mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +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 actix_web::{App, HttpServer};
|
||||||
use api::ServerState;
|
use api::ServerState;
|
||||||
use server::{NullSyncServer, SyncServer};
|
use server::{InMemorySyncServer, SyncServer};
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod server;
|
mod server;
|
||||||
|
@ -9,7 +9,7 @@ mod server;
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
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);
|
let server_state = ServerState::new(server_box);
|
||||||
|
|
||||||
HttpServer::new(move || {
|
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 failure::Fallible;
|
||||||
use taskchampion::Uuid;
|
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 HistorySegment = Vec<u8>;
|
||||||
pub(crate) type ClientId = Uuid;
|
pub(crate) type ClientId = Uuid;
|
||||||
pub(crate) type VersionId = Uuid;
|
pub(crate) type VersionId = Uuid;
|
||||||
|
@ -33,38 +40,3 @@ pub(crate) trait SyncServer: Sync + Send {
|
||||||
history_segment: HistorySegment,
|
history_segment: HistorySegment,
|
||||||
) -> Fallible<AddVersionResult>;
|
) -> 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