mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-25 14:41:08 +00:00
refactoring
This commit is contained in:
parent
c958c26257
commit
80ad6aa8d6
5 changed files with 99 additions and 86 deletions
87
src/api.rs
87
src/api.rs
|
@ -1,10 +1,9 @@
|
||||||
use crate::database::DatabaseHandle;
|
use crate::database::{DatabaseHandle, DbConflict};
|
||||||
use crate::error::{Error, MyResult};
|
use crate::error::MyResult;
|
||||||
use crate::federation::activities::create_article::CreateArticle;
|
use crate::federation::activities::create_article::CreateArticle;
|
||||||
use crate::federation::activities::update_local_article::UpdateLocalArticle;
|
use crate::federation::activities::submit_article_update;
|
||||||
use crate::federation::activities::update_remote_article::UpdateRemoteArticle;
|
|
||||||
use crate::federation::objects::article::DbArticle;
|
use crate::federation::objects::article::DbArticle;
|
||||||
use crate::federation::objects::edit::{DbEdit, EditVersion};
|
use crate::federation::objects::edit::EditVersion;
|
||||||
use crate::federation::objects::instance::DbInstance;
|
use crate::federation::objects::instance::DbInstance;
|
||||||
use crate::utils::generate_article_version;
|
use crate::utils::generate_article_version;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
|
@ -14,7 +13,7 @@ use axum::extract::Query;
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::{Form, Json, Router};
|
use axum::{Form, Json, Router};
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
use diffy::{apply, create_patch, merge, Patch};
|
use diffy::create_patch;
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -85,54 +84,6 @@ pub struct ApiConflict {
|
||||||
pub previous_version: EditVersion,
|
pub previous_version: EditVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct DbConflict {
|
|
||||||
pub id: i32,
|
|
||||||
pub diff: String,
|
|
||||||
pub article_id: ObjectId<DbArticle>,
|
|
||||||
pub previous_version: EditVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DbConflict {
|
|
||||||
pub async fn to_api_conflict(
|
|
||||||
&self,
|
|
||||||
data: &Data<DatabaseHandle>,
|
|
||||||
) -> MyResult<Option<ApiConflict>> {
|
|
||||||
let original_article = {
|
|
||||||
let mut lock = data.articles.lock().unwrap();
|
|
||||||
let article = lock.get_mut(self.article_id.inner()).unwrap();
|
|
||||||
article.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
// create common ancestor version
|
|
||||||
let ancestor = generate_article_version(&original_article.edits, &self.previous_version)?;
|
|
||||||
|
|
||||||
let patch = Patch::from_str(&self.diff)?;
|
|
||||||
// apply self.diff to ancestor to get `ours`
|
|
||||||
let ours = apply(&ancestor, &patch)?;
|
|
||||||
match merge(&ancestor, &ours, &original_article.text) {
|
|
||||||
Ok(new_text) => {
|
|
||||||
// patch applies cleanly so we are done
|
|
||||||
// federate the change
|
|
||||||
submit_article_update(data, new_text, &original_article).await?;
|
|
||||||
// remove conflict from db
|
|
||||||
let mut lock = data.conflicts.lock().unwrap();
|
|
||||||
lock.retain(|c| c.id != self.id);
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
Err(three_way_merge) => {
|
|
||||||
// there is a merge conflict, user needs to do three-way-merge
|
|
||||||
Ok(Some(ApiConflict {
|
|
||||||
id: self.id,
|
|
||||||
three_way_merge,
|
|
||||||
article_id: original_article.ap_id.clone(),
|
|
||||||
previous_version: original_article.latest_version,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn edit_article(
|
async fn edit_article(
|
||||||
data: Data<DatabaseHandle>,
|
data: Data<DatabaseHandle>,
|
||||||
|
@ -177,34 +128,6 @@ async fn edit_article(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn submit_article_update(
|
|
||||||
data: &Data<DatabaseHandle>,
|
|
||||||
new_text: String,
|
|
||||||
original_article: &DbArticle,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let edit = DbEdit::new(original_article, &new_text)?;
|
|
||||||
if original_article.local {
|
|
||||||
let updated_article = {
|
|
||||||
let mut lock = data.articles.lock().unwrap();
|
|
||||||
let article = lock.get_mut(original_article.ap_id.inner()).unwrap();
|
|
||||||
article.text = new_text;
|
|
||||||
article.latest_version = edit.version.clone();
|
|
||||||
article.edits.push(edit.clone());
|
|
||||||
article.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
UpdateLocalArticle::send(updated_article, vec![], data).await?;
|
|
||||||
} else {
|
|
||||||
UpdateRemoteArticle::send(
|
|
||||||
edit,
|
|
||||||
original_article.instance.dereference(data).await?,
|
|
||||||
data,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
#[derive(Deserialize, Serialize, Clone)]
|
||||||
pub struct GetArticleData {
|
pub struct GetArticleData {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
use crate::api::DbConflict;
|
use crate::api::ApiConflict;
|
||||||
|
use crate::error::MyResult;
|
||||||
|
use crate::federation::activities::submit_article_update;
|
||||||
use crate::federation::objects::article::DbArticle;
|
use crate::federation::objects::article::DbArticle;
|
||||||
|
use crate::federation::objects::edit::EditVersion;
|
||||||
use crate::federation::objects::instance::DbInstance;
|
use crate::federation::objects::instance::DbInstance;
|
||||||
|
use crate::utils::generate_article_version;
|
||||||
|
use activitypub_federation::config::Data;
|
||||||
|
use activitypub_federation::fetch::object_id::ObjectId;
|
||||||
|
use diffy::{apply, merge, Patch};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -20,3 +26,51 @@ impl Database {
|
||||||
lock.iter().find(|i| i.1.local).unwrap().1.clone()
|
lock.iter().find(|i| i.1.local).unwrap().1.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DbConflict {
|
||||||
|
pub id: i32,
|
||||||
|
pub diff: String,
|
||||||
|
pub article_id: ObjectId<DbArticle>,
|
||||||
|
pub previous_version: EditVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbConflict {
|
||||||
|
pub async fn to_api_conflict(
|
||||||
|
&self,
|
||||||
|
data: &Data<DatabaseHandle>,
|
||||||
|
) -> MyResult<Option<ApiConflict>> {
|
||||||
|
let original_article = {
|
||||||
|
let mut lock = data.articles.lock().unwrap();
|
||||||
|
let article = lock.get_mut(self.article_id.inner()).unwrap();
|
||||||
|
article.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// create common ancestor version
|
||||||
|
let ancestor = generate_article_version(&original_article.edits, &self.previous_version)?;
|
||||||
|
|
||||||
|
let patch = Patch::from_str(&self.diff)?;
|
||||||
|
// apply self.diff to ancestor to get `ours`
|
||||||
|
let ours = apply(&ancestor, &patch)?;
|
||||||
|
match merge(&ancestor, &ours, &original_article.text) {
|
||||||
|
Ok(new_text) => {
|
||||||
|
// patch applies cleanly so we are done
|
||||||
|
// federate the change
|
||||||
|
submit_article_update(data, new_text, &original_article).await?;
|
||||||
|
// remove conflict from db
|
||||||
|
let mut lock = data.conflicts.lock().unwrap();
|
||||||
|
lock.retain(|c| c.id != self.id);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Err(three_way_merge) => {
|
||||||
|
// there is a merge conflict, user needs to do three-way-merge
|
||||||
|
Ok(Some(ApiConflict {
|
||||||
|
id: self.id,
|
||||||
|
three_way_merge,
|
||||||
|
article_id: original_article.ap_id.clone(),
|
||||||
|
previous_version: original_article.latest_version,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,42 @@
|
||||||
|
use crate::database::DatabaseHandle;
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::federation::activities::update_local_article::UpdateLocalArticle;
|
||||||
|
use crate::federation::activities::update_remote_article::UpdateRemoteArticle;
|
||||||
|
use crate::federation::objects::article::DbArticle;
|
||||||
|
use crate::federation::objects::edit::DbEdit;
|
||||||
|
use activitypub_federation::config::Data;
|
||||||
|
|
||||||
pub mod accept;
|
pub mod accept;
|
||||||
pub mod create_article;
|
pub mod create_article;
|
||||||
pub mod follow;
|
pub mod follow;
|
||||||
pub mod reject;
|
pub mod reject;
|
||||||
pub mod update_local_article;
|
pub mod update_local_article;
|
||||||
pub mod update_remote_article;
|
pub mod update_remote_article;
|
||||||
|
|
||||||
|
pub async fn submit_article_update(
|
||||||
|
data: &Data<DatabaseHandle>,
|
||||||
|
new_text: String,
|
||||||
|
original_article: &DbArticle,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let edit = DbEdit::new(original_article, &new_text)?;
|
||||||
|
if original_article.local {
|
||||||
|
let updated_article = {
|
||||||
|
let mut lock = data.articles.lock().unwrap();
|
||||||
|
let article = lock.get_mut(original_article.ap_id.inner()).unwrap();
|
||||||
|
article.text = new_text;
|
||||||
|
article.latest_version = edit.version.clone();
|
||||||
|
article.edits.push(edit.clone());
|
||||||
|
article.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdateLocalArticle::send(updated_article, vec![], data).await?;
|
||||||
|
} else {
|
||||||
|
UpdateRemoteArticle::send(
|
||||||
|
edit,
|
||||||
|
original_article.instance.dereference(data).await?,
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use activitypub_federation::{
|
||||||
};
|
};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
use crate::api::DbConflict;
|
use crate::database::DbConflict;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::net::ToSocketAddrs;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
mod database;
|
pub mod database;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod federation;
|
pub mod federation;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
Loading…
Reference in a new issue