Add option to not create new clients
This commit is contained in:
parent
1ed97d6b83
commit
ed9d885bed
@ -52,14 +52,22 @@ pub(crate) async fn service(
|
||||
let mut txn = server_state.storage.txn().map_err(failure_to_ise)?;
|
||||
|
||||
// get, or create, the client
|
||||
let client = match txn.get_client(client_id).map_err(failure_to_ise)? {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
txn.new_client(client_id, NIL_VERSION_ID)
|
||||
.map_err(failure_to_ise)?;
|
||||
txn.get_client(client_id).map_err(failure_to_ise)?.unwrap()
|
||||
}
|
||||
};
|
||||
let client;
|
||||
if server_state.config.create_client_on_request {
|
||||
client = match txn.get_client(client_id).map_err(failure_to_ise)? {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
txn.new_client(client_id, NIL_VERSION_ID)
|
||||
.map_err(failure_to_ise)?;
|
||||
txn.get_client(client_id).map_err(failure_to_ise)?.unwrap()
|
||||
}
|
||||
};
|
||||
} else {
|
||||
client = txn
|
||||
.get_client(client_id)
|
||||
.map_err(failure_to_ise)?
|
||||
.ok_or_else(|| error::ErrorNotFound("no such client"))?;
|
||||
}
|
||||
|
||||
add_snapshot(
|
||||
txn,
|
||||
|
@ -60,14 +60,22 @@ pub(crate) async fn service(
|
||||
let mut txn = server_state.storage.txn().map_err(failure_to_ise)?;
|
||||
|
||||
// get, or create, the client
|
||||
let client = match txn.get_client(client_id).map_err(failure_to_ise)? {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
txn.new_client(client_id, NIL_VERSION_ID)
|
||||
.map_err(failure_to_ise)?;
|
||||
txn.get_client(client_id).map_err(failure_to_ise)?.unwrap()
|
||||
}
|
||||
};
|
||||
let client;
|
||||
if server_state.config.create_client_on_request {
|
||||
client = match txn.get_client(client_id).map_err(failure_to_ise)? {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
txn.new_client(client_id, NIL_VERSION_ID)
|
||||
.map_err(failure_to_ise)?;
|
||||
txn.get_client(client_id).map_err(failure_to_ise)?.unwrap()
|
||||
}
|
||||
};
|
||||
} else {
|
||||
client = txn
|
||||
.get_client(client_id)
|
||||
.map_err(failure_to_ise)?
|
||||
.ok_or_else(|| error::ErrorNotFound("no such client"))?;
|
||||
}
|
||||
|
||||
let (result, snap_urgency) = add_version(
|
||||
txn,
|
||||
|
@ -2,59 +2,102 @@
|
||||
|
||||
use actix_web::{middleware::Logger, App, HttpServer};
|
||||
use clap::{arg, builder::ValueParser, value_parser, Command};
|
||||
use uuid::Uuid;
|
||||
use std::ffi::OsString;
|
||||
use taskchampion_sync_server::storage::SqliteStorage;
|
||||
use std::path::{Path, PathBuf};
|
||||
use taskchampion_sync_server::storage::{SqliteStorage, Storage};
|
||||
use taskchampion_sync_server::{Server, ServerConfig};
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
let defaults = ServerConfig::default();
|
||||
let default_snapshot_versions = defaults.snapshot_versions.to_string();
|
||||
let default_snapshot_days = defaults.snapshot_days.to_string();
|
||||
|
||||
let config_arg = arg!(-c --config <PATH> "Config file")
|
||||
.default_value(PathBuf::from(&defaults.data_dir).join("config").to_string_lossy().to_string());
|
||||
|
||||
let matches = Command::new("taskchampion-sync-server")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("Server for TaskChampion")
|
||||
.arg(
|
||||
arg!(-p --port <PORT> "Port on which to serve")
|
||||
.help("Port on which to serve")
|
||||
.value_parser(value_parser!(usize))
|
||||
.default_value("8080"),
|
||||
)
|
||||
.arg(&config_arg)
|
||||
.arg(
|
||||
arg!(-d --"data-dir" <DIR> "Directory in which to store data")
|
||||
.value_parser(ValueParser::os_string())
|
||||
.default_value("/var/lib/taskchampion-sync-server"),
|
||||
.default_value(&defaults.data_dir),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("clients")
|
||||
.subcommand(Command::new("list"))
|
||||
.subcommand(Command::new("add").arg(arg!(<CLIENT_ID>)))
|
||||
.subcommand(Command::new("remove").arg(arg!(<CLIENT_ID>)))
|
||||
)
|
||||
.arg(
|
||||
arg!(-p --port <PORT> "Port on which to serve")
|
||||
.value_parser(value_parser!(u16))
|
||||
.default_value(defaults.port.to_string()),
|
||||
)
|
||||
.arg(
|
||||
arg!(--"snapshot-versions" <NUM> "Target number of versions between snapshots")
|
||||
.value_parser(value_parser!(u32))
|
||||
.default_value(default_snapshot_versions),
|
||||
.default_value(defaults.snapshot_versions.to_string()),
|
||||
)
|
||||
.arg(
|
||||
arg!(--"snapshot-days" <NUM> "Target number of days between snapshots")
|
||||
.value_parser(value_parser!(i64))
|
||||
.default_value(default_snapshot_days),
|
||||
.default_value(defaults.snapshot_days.to_string()),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let data_dir: &OsString = matches.get_one("data-dir").unwrap();
|
||||
let port: usize = *matches.get_one("port").unwrap();
|
||||
let snapshot_versions: u32 = *matches.get_one("snapshot-versions").unwrap();
|
||||
let snapshot_days: i64 = *matches.get_one("snapshot-days").unwrap();
|
||||
// TODO: let config_path: &String = matches.get_one("config").unwrap();
|
||||
|
||||
let config = ServerConfig::from_args(snapshot_days, snapshot_versions)?;
|
||||
let server = Server::new(config, Box::new(SqliteStorage::new(data_dir)?));
|
||||
let storage = SqliteStorage::new(data_dir)?;
|
||||
|
||||
match matches.subcommand() {
|
||||
Some(("clients", sub_matches)) => {
|
||||
|
||||
match sub_matches.subcommand() {
|
||||
Some(("add", sub_matches)) => {
|
||||
let client_id = sub_matches.get_one::<String>("CLIENT_ID").unwrap();
|
||||
let client_id = Uuid::parse_str(client_id)?;
|
||||
let mut t = storage.txn()?;
|
||||
t.new_client(client_id, Uuid::nil())?
|
||||
},
|
||||
Some(("remove", _sub_matches)) => {
|
||||
todo!()
|
||||
},
|
||||
_ => {
|
||||
let mut t = storage.txn()?;
|
||||
for client in t.list_clients()? {
|
||||
print!("{client}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let port: u16 = *matches.get_one("port").unwrap();
|
||||
let snapshot_versions: u32 = *matches.get_one("snapshot-versions").unwrap();
|
||||
let snapshot_days: i64 = *matches.get_one("snapshot-days").unwrap();
|
||||
|
||||
let data_dir_owned = data_dir.to_string_lossy().into();
|
||||
let mut config = ServerConfig::from_args(snapshot_days, snapshot_versions, port, data_dir_owned)?;
|
||||
config.create_client_on_request = false;
|
||||
|
||||
let server = Server::new(config, Box::new(storage));
|
||||
|
||||
log::warn!("Serving on port {}", port);
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.configure(|cfg| server.config(cfg))
|
||||
})
|
||||
.bind(format!("0.0.0.0:{}", port))?
|
||||
.run()
|
||||
.await?;
|
||||
},
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
log::warn!("Serving on port {}", port);
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.configure(|cfg| server.config(cfg))
|
||||
})
|
||||
.bind(format!("0.0.0.0:{}", port))?
|
||||
.run()
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,12 @@ pub struct ServerConfig {
|
||||
|
||||
/// Target number of versions between snapshots.
|
||||
pub snapshot_versions: u32,
|
||||
|
||||
pub port: u16,
|
||||
|
||||
pub data_dir: String,
|
||||
|
||||
pub create_client_on_request: bool,
|
||||
}
|
||||
|
||||
impl Default for ServerConfig {
|
||||
@ -31,15 +37,21 @@ impl Default for ServerConfig {
|
||||
ServerConfig {
|
||||
snapshot_days: 14,
|
||||
snapshot_versions: 100,
|
||||
port: 8080,
|
||||
data_dir: String::from("/var/lib/taskchampion-sync-server"),
|
||||
create_client_on_request: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
pub fn from_args(snapshot_days: i64, snapshot_versions: u32) -> anyhow::Result<ServerConfig> {
|
||||
pub fn from_args(snapshot_days: i64, snapshot_versions: u32, port: u16, data_dir: String) -> anyhow::Result<ServerConfig> {
|
||||
Ok(ServerConfig {
|
||||
snapshot_days,
|
||||
snapshot_versions,
|
||||
port,
|
||||
data_dir,
|
||||
create_client_on_request: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,10 @@ impl<'a> StorageTxn for InnerTxn<'a> {
|
||||
Ok(self.0.clients.get(&client_id).cloned())
|
||||
}
|
||||
|
||||
fn list_clients(&mut self) -> anyhow::Result<Vec<Uuid>> {
|
||||
Ok(self.0.clients.keys().map(|key| key.clone()).collect())
|
||||
}
|
||||
|
||||
fn new_client(&mut self, client_id: Uuid, latest_version_id: Uuid) -> anyhow::Result<()> {
|
||||
if self.0.clients.get(&client_id).is_some() {
|
||||
return Err(anyhow::anyhow!("Client {} already exists", client_id));
|
||||
|
@ -41,6 +41,9 @@ pub trait StorageTxn {
|
||||
/// Get information about the given client
|
||||
fn get_client(&mut self, client_id: Uuid) -> anyhow::Result<Option<Client>>;
|
||||
|
||||
/// Get information about the given client
|
||||
fn list_clients(&mut self) -> anyhow::Result<Vec<Uuid>>;
|
||||
|
||||
/// Create a new client with the given latest_version_id
|
||||
fn new_client(&mut self, client_id: Uuid, latest_version_id: Uuid) -> anyhow::Result<()>;
|
||||
|
||||
|
@ -166,6 +166,22 @@ impl StorageTxn for Txn {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn list_clients(&mut self) -> anyhow::Result<Vec<Uuid>> {
|
||||
let t = self.get_txn()?;
|
||||
|
||||
let mut stmt = t.prepare("SELECT client_id FROM clients")?;
|
||||
let rows = stmt
|
||||
.query_map([], |r| r.get::<usize, StoredUuid>(0))
|
||||
.context("Error getting clients")?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for client_id_result in rows {
|
||||
result.push(client_id_result?.0);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn new_client(&mut self, client_id: Uuid, latest_version_id: Uuid) -> anyhow::Result<()> {
|
||||
let t = self.get_txn()?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user