mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
refactor sync server into modules
This commit is contained in:
parent
d0bfbbb7f0
commit
087333a227
9 changed files with 1504 additions and 102 deletions
1388
Cargo.lock
generated
1388
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -7,3 +7,8 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
actix-web = "3.3.0"
|
||||
failure = "0.1.8"
|
||||
serde = "1.0.117"
|
||||
serde_json = "1.0.59"
|
||||
taskchampion = { path = "../taskchampion" }
|
||||
|
|
25
sync-server/src/api/add_version.rs
Normal file
25
sync-server/src/api/add_version.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::server::SyncServer;
|
||||
use crate::types::{ClientId, HistorySegment, VersionId};
|
||||
use actix_web::{error, http::StatusCode, post, web, HttpResponse, Responder, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Request body to add_version
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) struct AddVersionRequest {
|
||||
// TODO: temporary!
|
||||
#[serde(default)]
|
||||
history_segment: HistorySegment,
|
||||
}
|
||||
|
||||
#[post("/client/{client_id}/add-version/{parent_version_id}")]
|
||||
pub(crate) async fn service(
|
||||
data: web::Data<Arc<SyncServer>>,
|
||||
web::Path((client_id, parent_version_id)): web::Path<(ClientId, VersionId)>,
|
||||
body: web::Json<AddVersionRequest>,
|
||||
) -> Result<impl Responder> {
|
||||
let result = data
|
||||
.add_version(client_id, parent_version_id, &body.history_segment)
|
||||
.map_err(|e| error::InternalError::new(e, StatusCode::INTERNAL_SERVER_ERROR))?;
|
||||
Ok(HttpResponse::Ok().json(result))
|
||||
}
|
19
sync-server/src/api/get_child_version.rs
Normal file
19
sync-server/src/api/get_child_version.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use crate::server::SyncServer;
|
||||
use crate::types::{ClientId, VersionId};
|
||||
use actix_web::{error, get, http::StatusCode, web, HttpResponse, Result};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[get("/client/{client_id}/get-child-version/{parent_version_id}")]
|
||||
pub(crate) async fn service(
|
||||
data: web::Data<Arc<SyncServer>>,
|
||||
web::Path((client_id, parent_version_id)): web::Path<(ClientId, VersionId)>,
|
||||
) -> Result<HttpResponse> {
|
||||
let result = data
|
||||
.get_child_version(client_id, parent_version_id)
|
||||
.map_err(|e| error::InternalError::new(e, StatusCode::INTERNAL_SERVER_ERROR))?;
|
||||
if let Some(result) = result {
|
||||
Ok(HttpResponse::Ok().json(result))
|
||||
} else {
|
||||
Err(error::ErrorNotFound("no such version"))
|
||||
}
|
||||
}
|
2
sync-server/src/api/mod.rs
Normal file
2
sync-server/src/api/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub(crate) mod add_version;
|
||||
pub(crate) mod get_child_version;
|
|
@ -1,86 +0,0 @@
|
|||
#![allow(clippy::new_without_default)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
type Blob = Vec<u8>;
|
||||
|
||||
struct User {
|
||||
// versions, indexed at v-1
|
||||
versions: Vec<Blob>,
|
||||
snapshots: HashMap<u64, Blob>,
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
users: HashMap<String, User>,
|
||||
}
|
||||
|
||||
pub enum VersionAdd {
|
||||
// OK, version added
|
||||
Ok,
|
||||
// Rejected, must be based on the the given version
|
||||
ExpectedVersion(u64),
|
||||
}
|
||||
|
||||
impl User {
|
||||
fn new() -> User {
|
||||
User {
|
||||
versions: vec![],
|
||||
snapshots: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_versions(&self, since_version: u64) -> Vec<Blob> {
|
||||
let last_version = self.versions.len();
|
||||
if last_version == since_version as usize {
|
||||
return vec![];
|
||||
}
|
||||
self.versions[since_version as usize..last_version].to_vec()
|
||||
}
|
||||
|
||||
fn add_version(&mut self, version: u64, blob: Blob) -> VersionAdd {
|
||||
// of by one here: client wants to send version 1 first
|
||||
let expected_version = self.versions.len() as u64 + 1;
|
||||
if version != expected_version {
|
||||
return VersionAdd::ExpectedVersion(expected_version);
|
||||
}
|
||||
self.versions.push(blob);
|
||||
|
||||
VersionAdd::Ok
|
||||
}
|
||||
|
||||
fn add_snapshot(&mut self, version: u64, blob: Blob) {
|
||||
self.snapshots.insert(version, blob);
|
||||
}
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new() -> Server {
|
||||
Server {
|
||||
users: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_user_mut(&mut self, username: &str) -> &mut User {
|
||||
self.users
|
||||
.entry(username.to_string())
|
||||
.or_insert_with(User::new)
|
||||
}
|
||||
|
||||
/// Get a vector of all versions after `since_version`
|
||||
pub fn get_versions(&self, username: &str, since_version: u64) -> Vec<Blob> {
|
||||
self.users
|
||||
.get(username)
|
||||
.map(|user| user.get_versions(since_version))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Add a new version. If the given version number is incorrect, this responds with the
|
||||
/// appropriate version and expects the caller to try again.
|
||||
pub fn add_version(&mut self, username: &str, version: u64, blob: Blob) -> VersionAdd {
|
||||
self.get_user_mut(username).add_version(version, blob)
|
||||
}
|
||||
|
||||
pub fn add_snapshot(&mut self, username: &str, version: u64, blob: Blob) {
|
||||
self.get_user_mut(username).add_snapshot(version, blob);
|
||||
}
|
||||
}
|
24
sync-server/src/main.rs
Normal file
24
sync-server/src/main.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use actix_web::{App, HttpServer};
|
||||
use server::SyncServer;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod api;
|
||||
mod server;
|
||||
mod types;
|
||||
|
||||
// TODO: use hawk to sign requests
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let sync_server = Arc::new(SyncServer::new());
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.data(sync_server.clone())
|
||||
.service(api::get_child_version::service)
|
||||
.service(api::add_version::service)
|
||||
})
|
||||
.bind("127.0.0.1:8080")?
|
||||
.run()
|
||||
.await
|
||||
}
|
34
sync-server/src/server.rs
Normal file
34
sync-server/src/server.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use crate::types::{AddVersionResult, ClientId, GetVersionResult, HistorySegment, VersionId};
|
||||
use failure::Fallible;
|
||||
use taskchampion::Uuid;
|
||||
|
||||
/// The sync server's implementation; HTTP API method call through to methods on a single
|
||||
/// instance of this type.
|
||||
pub(crate) struct SyncServer {}
|
||||
|
||||
impl SyncServer {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub(crate) fn get_child_version(
|
||||
&self,
|
||||
_client_id: ClientId,
|
||||
parent_version_id: VersionId,
|
||||
) -> Fallible<Option<GetVersionResult>> {
|
||||
Ok(Some(GetVersionResult {
|
||||
version_id: Uuid::new_v4(),
|
||||
parent_version_id,
|
||||
history_segment: b"abcd".to_vec(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn add_version(
|
||||
&self,
|
||||
_client_id: ClientId,
|
||||
_parent_version_id: VersionId,
|
||||
_history_segment: &HistorySegment,
|
||||
) -> Fallible<AddVersionResult> {
|
||||
Ok(AddVersionResult::Ok(Uuid::new_v4()))
|
||||
}
|
||||
}
|
23
sync-server/src/types.rs
Normal file
23
sync-server/src/types.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use taskchampion::Uuid;
|
||||
|
||||
pub(crate) type HistorySegment = Vec<u8>;
|
||||
pub(crate) type ClientId = Uuid;
|
||||
pub(crate) type VersionId = Uuid;
|
||||
|
||||
/// Response to get_child_version
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) struct GetVersionResult {
|
||||
pub(crate) version_id: Uuid,
|
||||
pub(crate) parent_version_id: Uuid,
|
||||
pub(crate) history_segment: HistorySegment,
|
||||
}
|
||||
|
||||
/// Response to add_version
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) enum AddVersionResult {
|
||||
/// OK, version added with the given ID
|
||||
Ok(VersionId),
|
||||
/// Rejected; expected a version with the given parent version
|
||||
ExpectedParentVersion(VersionId),
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue