mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Make the sync server client an optional feature (#3216)
* Make the sync server client an optional feature * fix comment, remove unnecessary allow(dead_code)
This commit is contained in:
parent
e95f95eb08
commit
b52248f146
11 changed files with 85 additions and 23 deletions
38
.github/workflows/rust-tests.yml
vendored
38
.github/workflows/rust-tests.yml
vendored
|
@ -1,5 +1,3 @@
|
|||
## Run the TaskChampion tests, using both the minimum supported rust version
|
||||
## and the latest stable Rust.
|
||||
|
||||
name: tests - rust
|
||||
|
||||
|
@ -11,6 +9,42 @@ on:
|
|||
types: [opened, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
## Run the `taskchampion` crate's tests with various combinations of features.
|
||||
features:
|
||||
strategy:
|
||||
matrix:
|
||||
features:
|
||||
- ""
|
||||
- "server-sync"
|
||||
|
||||
name: "taskchampion ${{ matrix.features == '' && 'with no features' || format('with features {0}', matrix.features) }}"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ubuntu-latest-stable-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
key: ubuntu-latest-stable-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: test
|
||||
run: cargo test -p taskchampion --no-default-features --features "${{ matrix.features }}"
|
||||
|
||||
## Run all TaskChampion crate tests, using both the minimum supported rust version
|
||||
## and the latest stable Rust.
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
|
|
|
@ -7,7 +7,7 @@ publish = false
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
taskchampion = { path = "../taskchampion" }
|
||||
taskchampion = { path = "../taskchampion", features = ["server-sync"] }
|
||||
taskchampion-lib = { path = "../lib" }
|
||||
taskchampion-sync-server = { path = "../sync-server" }
|
||||
|
||||
|
|
|
@ -10,6 +10,14 @@ readme = "../README.md"
|
|||
license = "MIT"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["server-sync" ]
|
||||
server-sync = ["crypto", "dep:ureq"]
|
||||
crypto = ["dep:ring"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
uuid.workspace = true
|
||||
serde.workspace = true
|
||||
|
@ -26,6 +34,9 @@ flate2.workspace = true
|
|||
byteorder.workspace = true
|
||||
ring.workspace = true
|
||||
|
||||
ureq.optional = true
|
||||
ring.optional = true
|
||||
|
||||
[dev-dependencies]
|
||||
proptest.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
|
|
@ -34,6 +34,7 @@ macro_rules! other_error {
|
|||
}
|
||||
};
|
||||
}
|
||||
#[cfg(feature = "server-sync")]
|
||||
other_error!(ureq::Error);
|
||||
other_error!(io::Error);
|
||||
other_error!(serde_json::Error);
|
||||
|
|
|
@ -34,6 +34,14 @@ Create a server with [`ServerConfig`](crate::ServerConfig).
|
|||
The [`server`](crate::server) module defines the interface a server must meet.
|
||||
Users can define their own server impelementations.
|
||||
|
||||
# Feature Flags
|
||||
|
||||
Support for some optional functionality is controlled by feature flags.
|
||||
|
||||
Sync server client support:
|
||||
|
||||
* `server-sync` - sync to the taskchampion-sync-server
|
||||
|
||||
# See Also
|
||||
|
||||
See the [TaskChampion Book](http://taskchampion.github.com/taskchampion)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use super::types::Server;
|
||||
use super::{LocalServer, RemoteServer};
|
||||
use crate::errors::Result;
|
||||
use crate::server::local::LocalServer;
|
||||
#[cfg(feature = "server-sync")]
|
||||
use crate::server::sync::SyncServer;
|
||||
use std::path::PathBuf;
|
||||
#[cfg(feature = "server-sync")]
|
||||
use uuid::Uuid;
|
||||
|
||||
/// The configuration for a replica's access to a sync server.
|
||||
|
@ -12,6 +15,7 @@ pub enum ServerConfig {
|
|||
server_dir: PathBuf,
|
||||
},
|
||||
/// A remote taskchampion-sync-server instance
|
||||
#[cfg(feature = "server-sync")]
|
||||
Remote {
|
||||
/// Sync server "origin"; a URL with schema and hostname but no path or trailing `/`
|
||||
origin: String,
|
||||
|
@ -30,11 +34,12 @@ impl ServerConfig {
|
|||
pub fn into_server(self) -> Result<Box<dyn Server>> {
|
||||
Ok(match self {
|
||||
ServerConfig::Local { server_dir } => Box::new(LocalServer::new(server_dir)?),
|
||||
#[cfg(feature = "server-sync")]
|
||||
ServerConfig::Remote {
|
||||
origin,
|
||||
client_id,
|
||||
encryption_secret,
|
||||
} => Box::new(RemoteServer::new(origin, client_id, encryption_secret)?),
|
||||
} => Box::new(SyncServer::new(origin, client_id, encryption_secret)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
/// document.
|
||||
use crate::errors::{Error, Result};
|
||||
use ring::{aead, digest, pbkdf2, rand, rand::SecureRandom};
|
||||
use std::io::Read;
|
||||
use uuid::Uuid;
|
||||
|
||||
const PBKDF2_ITERATIONS: u32 = 100000;
|
||||
|
@ -177,11 +176,13 @@ pub(super) struct Sealed {
|
|||
}
|
||||
|
||||
impl Sealed {
|
||||
#[cfg(feature = "server-sync")]
|
||||
pub(super) fn from_resp(
|
||||
resp: ureq::Response,
|
||||
version_id: Uuid,
|
||||
content_type: &str,
|
||||
) -> Result<Sealed> {
|
||||
use std::io::Read;
|
||||
if resp.header("Content-Type") == Some(content_type) {
|
||||
let mut reader = resp.into_reader();
|
||||
let mut payload = vec![];
|
||||
|
|
|
@ -12,15 +12,17 @@ However, users who wish to implement their own server interfaces can implement t
|
|||
pub(crate) mod test;
|
||||
|
||||
mod config;
|
||||
mod crypto;
|
||||
mod local;
|
||||
mod op;
|
||||
mod remote;
|
||||
mod types;
|
||||
|
||||
#[cfg(feature = "crypto")]
|
||||
mod crypto;
|
||||
|
||||
#[cfg(feature = "server-sync")]
|
||||
mod sync;
|
||||
|
||||
pub use config::ServerConfig;
|
||||
pub use local::LocalServer;
|
||||
pub use remote::RemoteServer;
|
||||
pub use types::*;
|
||||
|
||||
pub(crate) use op::SyncOp;
|
||||
|
|
|
@ -8,7 +8,7 @@ use uuid::Uuid;
|
|||
|
||||
use super::crypto::{Cryptor, Sealed, Secret, Unsealed};
|
||||
|
||||
pub struct RemoteServer {
|
||||
pub struct SyncServer {
|
||||
origin: String,
|
||||
client_id: Uuid,
|
||||
cryptor: Cryptor,
|
||||
|
@ -21,19 +21,14 @@ const HISTORY_SEGMENT_CONTENT_TYPE: &str = "application/vnd.taskchampion.history
|
|||
/// The content-type for snapshots (opaque blobs of bytes)
|
||||
const SNAPSHOT_CONTENT_TYPE: &str = "application/vnd.taskchampion.snapshot";
|
||||
|
||||
/// A RemoeServer communicates with a remote server over HTTP (such as with
|
||||
/// taskchampion-sync-server).
|
||||
impl RemoteServer {
|
||||
/// Construct a new RemoteServer. The `origin` is the sync server's protocol and hostname
|
||||
/// A SyncServer communicates with a sync server over HTTP.
|
||||
impl SyncServer {
|
||||
/// Construct a new SyncServer. The `origin` is the sync server's protocol and hostname
|
||||
/// without a trailing slash, such as `https://tcsync.example.com`. Pass a client_id to
|
||||
/// identify this client to the server. Multiple replicas synchronizing the same task history
|
||||
/// should use the same client_id.
|
||||
pub fn new(
|
||||
origin: String,
|
||||
client_id: Uuid,
|
||||
encryption_secret: Vec<u8>,
|
||||
) -> Result<RemoteServer> {
|
||||
Ok(RemoteServer {
|
||||
pub fn new(origin: String, client_id: Uuid, encryption_secret: Vec<u8>) -> Result<SyncServer> {
|
||||
Ok(SyncServer {
|
||||
origin,
|
||||
client_id,
|
||||
cryptor: Cryptor::new(client_id, &Secret(encryption_secret.to_vec()))?,
|
||||
|
@ -67,7 +62,7 @@ fn get_snapshot_urgency(resp: &ureq::Response) -> SnapshotUrgency {
|
|||
}
|
||||
}
|
||||
|
||||
impl Server for RemoteServer {
|
||||
impl Server for SyncServer {
|
||||
fn add_version(
|
||||
&mut self,
|
||||
parent_version_id: VersionId,
|
|
@ -1,7 +1,7 @@
|
|||
use crate::errors::Result;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Versions are referred to with sha2 hashes.
|
||||
/// Versions are referred to with UUIDs.
|
||||
pub type VersionId = Uuid;
|
||||
|
||||
/// The distinguished value for "no version"
|
||||
|
@ -52,6 +52,11 @@ pub enum GetVersionResult {
|
|||
/// A value implementing this trait can act as a server against which a replica can sync.
|
||||
pub trait Server {
|
||||
/// Add a new version.
|
||||
///
|
||||
/// This must ensure that the new version is the only version with the given
|
||||
/// `parent_version_id`, and that all versions form a single parent-child chain. Inductively,
|
||||
/// this means that if there are any versions on the server, then `parent_version_id` must be
|
||||
/// the only version that does not already have a child.
|
||||
fn add_version(
|
||||
&mut self,
|
||||
parent_version_id: VersionId,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue