mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
build an in-memory sync server implementation
This commit is contained in:
parent
2457d8bc43
commit
2dae271851
3 changed files with 117 additions and 37 deletions
|
@ -1,6 +1,6 @@
|
|||
use actix_web::{App, HttpServer};
|
||||
use api::ServerState;
|
||||
use server::{NullSyncServer, SyncServer};
|
||||
use server::{InMemorySyncServer, SyncServer};
|
||||
|
||||
mod api;
|
||||
mod server;
|
||||
|
@ -9,7 +9,7 @@ mod server;
|
|||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let server_box: Box<dyn SyncServer> = Box::new(NullSyncServer::new());
|
||||
let server_box: Box<dyn SyncServer> = Box::new(InMemorySyncServer::new());
|
||||
let server_state = ServerState::new(server_box);
|
||||
|
||||
HttpServer::new(move || {
|
||||
|
|
108
sync-server/src/server/inmemory.rs
Normal file
108
sync-server/src/server/inmemory.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use super::{
|
||||
AddVersionResult, ClientId, GetVersionResult, HistorySegment, SyncServer, VersionId,
|
||||
NO_VERSION_ID,
|
||||
};
|
||||
use failure::Fallible;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Mutex, RwLock};
|
||||
use taskchampion::Uuid;
|
||||
|
||||
/// An in-memory server backend that can be useful for testing.
|
||||
pub(crate) struct InMemorySyncServer {
|
||||
clients: RwLock<HashMap<ClientId, Mutex<Client>>>,
|
||||
}
|
||||
|
||||
struct Version {
|
||||
version_id: VersionId,
|
||||
history_segment: HistorySegment,
|
||||
}
|
||||
|
||||
struct Client {
|
||||
latest_version_id: VersionId,
|
||||
// NOTE: indexed by parent_version_id!
|
||||
versions: HashMap<VersionId, Version>,
|
||||
}
|
||||
|
||||
impl InMemorySyncServer {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
clients: RwLock::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncServer for InMemorySyncServer {
|
||||
fn get_child_version(
|
||||
&self,
|
||||
client_id: ClientId,
|
||||
parent_version_id: VersionId,
|
||||
) -> Fallible<Option<GetVersionResult>> {
|
||||
let clients = self.clients.read().expect("poisoned lock");
|
||||
if let Some(client) = clients.get(&client_id) {
|
||||
let client = client.lock().expect("poisoned lock");
|
||||
if let Some(version) = client.versions.get(&parent_version_id) {
|
||||
return Ok(Some(GetVersionResult {
|
||||
version_id: version.version_id,
|
||||
parent_version_id,
|
||||
history_segment: version.history_segment.clone(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn add_version(
|
||||
&self,
|
||||
client_id: ClientId,
|
||||
parent_version_id: VersionId,
|
||||
history_segment: HistorySegment,
|
||||
) -> Fallible<AddVersionResult> {
|
||||
let mut clients = self.clients.write().expect("poisoned lock");
|
||||
if let Some(client) = clients.get_mut(&client_id) {
|
||||
let mut client = client.lock().expect("poisoned lock");
|
||||
if client.latest_version_id != NO_VERSION_ID {
|
||||
if parent_version_id != client.latest_version_id {
|
||||
return Ok(AddVersionResult::ExpectedParentVersion(
|
||||
client.latest_version_id,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// invent a new ID for this version
|
||||
let version_id = Uuid::new_v4();
|
||||
|
||||
client.versions.insert(
|
||||
parent_version_id,
|
||||
Version {
|
||||
version_id,
|
||||
history_segment,
|
||||
},
|
||||
);
|
||||
client.latest_version_id = version_id;
|
||||
|
||||
Ok(AddVersionResult::Ok(version_id))
|
||||
} else {
|
||||
// new client, so insert a client with just this new version
|
||||
|
||||
let latest_version_id = Uuid::new_v4();
|
||||
let mut versions = HashMap::new();
|
||||
versions.insert(
|
||||
parent_version_id,
|
||||
Version {
|
||||
version_id: latest_version_id,
|
||||
history_segment,
|
||||
},
|
||||
);
|
||||
|
||||
clients.insert(
|
||||
client_id,
|
||||
Mutex::new(Client {
|
||||
latest_version_id,
|
||||
versions,
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(AddVersionResult::Ok(latest_version_id))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
use failure::Fallible;
|
||||
use taskchampion::Uuid;
|
||||
|
||||
mod inmemory;
|
||||
|
||||
pub(crate) use inmemory::InMemorySyncServer;
|
||||
|
||||
/// The distinguished value for "no version"
|
||||
pub const NO_VERSION_ID: VersionId = Uuid::nil();
|
||||
|
||||
pub(crate) type HistorySegment = Vec<u8>;
|
||||
pub(crate) type ClientId = Uuid;
|
||||
pub(crate) type VersionId = Uuid;
|
||||
|
@ -33,38 +40,3 @@ pub(crate) trait SyncServer: Sync + Send {
|
|||
history_segment: HistorySegment,
|
||||
) -> Fallible<AddVersionResult>;
|
||||
}
|
||||
|
||||
// TODO: temporary
|
||||
/// A "null" sync server's implementation; HTTP API methods call through to methods on a single
|
||||
/// instance of this type.
|
||||
pub(crate) struct NullSyncServer {}
|
||||
|
||||
impl NullSyncServer {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncServer for NullSyncServer {
|
||||
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(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn add_version(
|
||||
&self,
|
||||
_client_id: ClientId,
|
||||
_parent_version_id: VersionId,
|
||||
_history_segment: HistorySegment,
|
||||
) -> Fallible<AddVersionResult> {
|
||||
//Ok(AddVersionResult::Ok(Uuid::new_v4()))
|
||||
Ok(AddVersionResult::ExpectedParentVersion(Uuid::new_v4()))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue