feat(proto): add separate client/user-agent gRPC services

This commit is contained in:
hdbg
2026-02-10 19:01:09 +01:00
parent 5b27c78bfc
commit 8dd0276185
21 changed files with 1073 additions and 94 deletions

View File

@@ -2,5 +2,6 @@
name = "arbiter-client"
version = "0.1.0"
edition = "2024"
repository = "https://git.markettakers.org/MarketTakers/arbiter"
[dependencies]

View File

@@ -2,6 +2,7 @@
name = "arbiter-proto"
version = "0.1.0"
edition = "2024"
repository = "https://git.markettakers.org/MarketTakers/arbiter"
[dependencies]
tonic.workspace = true
@@ -10,6 +11,8 @@ bytes = "1.11.1"
prost-derive = "0.14.3"
prost-types = { version = "0.14.3", features = ["chrono"] }
tonic-prost = "0.14.3"
rkyv = "0.8.15"
[build-dependencies]
prost-build = "0.14.3"

View File

@@ -4,4 +4,4 @@ pub mod proto {
pub mod auth {
tonic::include_proto!("arbiter.auth");
}
}
}

View File

@@ -2,10 +2,19 @@
name = "arbiter-server"
version = "0.1.0"
edition = "2024"
repository = "https://git.markettakers.org/MarketTakers/arbiter"
[dependencies]
diesel = { version = "2.3.6", features = ["sqlite", "uuid", "time", "chrono", "serde_json"] }
diesel-async = { version = "0.7.4", features = ["sqlite", "tokio", "migrations", "pool", "deadpool"] }
ed25519.workspace = true
ed25519-dalek.workspace = true
arbiter-proto.path = "../arbiter-proto"
tracing.workspace = true
tonic.workspace = true
tokio.workspace = true
tokio.workspace = true
rustls.workspace = true
smlang.workspace = true
miette.workspace = true
thiserror.workspace = true
diesel_migrations = { version = "2.3.1", features = ["sqlite"] }

View File

@@ -2,7 +2,7 @@
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/schema.rs"
file = "src/db/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
[migrations_directory]

View File

@@ -1 +1,29 @@
-- Your SQL goes here
-- This is a singleton
create table if not exists arbiter_settings (
root_key_enc blob, -- if null, means wasn't bootstrapped yet
cert_key blob not null,
cert blob not null
) STRICT;
create table if not exists key_identity(
id integer primary key,
name text not null,
public_key text not null,
created_at integer not null default (unixepoch('now')),
updated_at integer not null default (unixepoch('now'))
) STRICT;
create table if not exists useragent_client (
id integer primary key,
key_identity_id integer not null references key_identity(id) on delete cascade,
created_at integer not null default (unixepoch('now')),
updated_at integer not null default (unixepoch('now'))
) STRICT;
create table if not exists program_client(
id integer primary key,
key_identity_id integer not null references key_identity(id) on delete cascade,
created_at integer not null default (unixepoch('now')),
updated_at integer not null default (unixepoch('now'))
) STRICT;

View File

@@ -0,0 +1,83 @@
use diesel::{Connection as _, SqliteConnection, connection::SimpleConnection as _};
use diesel_async::sync_connection_wrapper::SyncConnectionWrapper;
use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations};
use miette::Diagnostic;
use thiserror::Error;
pub mod models;
pub mod schema;
pub type Database = SyncConnectionWrapper<SqliteConnection>;
static ARBITER_HOME: &'static str = ".arbiter";
static DB_FILE: &'static str = "db.sqlite";
const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
#[derive(Error, Diagnostic, Debug)]
pub enum DatabaseSetupError {
#[error("Failed to determine home directory")]
#[diagnostic(code(arbiter::db::home_dir_error))]
HomeDir(Option<std::io::Error>),
#[error(transparent)]
#[diagnostic(code(arbiter::db::connection_error))]
Connection(diesel::ConnectionError),
#[error(transparent)]
#[diagnostic(code(arbiter::db::concurrency_error))]
ConcurrencySetup(diesel::result::Error),
#[error(transparent)]
#[diagnostic(code(arbiter::db::migration_error))]
Migration(Box<dyn std::error::Error + Send + Sync>),
}
fn database_path() -> Result<std::path::PathBuf, DatabaseSetupError> {
let home_dir = std::env::home_dir().ok_or_else(|| DatabaseSetupError::HomeDir(None))?;
let arbiter_home = home_dir.join(ARBITER_HOME);
let db_path = arbiter_home.join(DB_FILE);
std::fs::create_dir_all(arbiter_home)
.map_err(|err| DatabaseSetupError::HomeDir(Some(err)))?;
Ok(db_path)
}
fn setup_concurrency(conn: &mut SqliteConnection) -> Result<(), diesel::result::Error> {
// see https://fractaledmind.github.io/2023/09/07/enhancing-rails-sqlite-fine-tuning/
// sleep if the database is busy, this corresponds to up to 2 seconds sleeping time.
conn.batch_execute("PRAGMA busy_timeout = 2000;")?;
// better write-concurrency
conn.batch_execute("PRAGMA journal_mode = WAL;")?;
// fsync only in critical moments
conn.batch_execute("PRAGMA synchronous = NORMAL;")?;
// write WAL changes back every 1000 pages, for an in average 1MB WAL file.
// May affect readers if number is increased
conn.batch_execute("PRAGMA wal_autocheckpoint = 1000;")?;
// free some space by truncating possibly massive WAL files from the last run
conn.batch_execute("PRAGMA wal_checkpoint(TRUNCATE);")?;
Ok(())
}
#[tracing::instrument]
pub fn connect() -> Result<Database, DatabaseSetupError> {
let database_url = format!(
"{}?mode=rwc",
database_path()?
.to_str()
.ok_or_else(|| DatabaseSetupError::HomeDir(None))?
);
let mut conn =
SqliteConnection::establish(&database_url).map_err(DatabaseSetupError::Connection)?;
setup_concurrency(&mut conn).map_err(DatabaseSetupError::ConcurrencySetup)?;
conn.run_pending_migrations(MIGRATIONS)
.map_err(DatabaseSetupError::Migration)?;
Ok(SyncConnectionWrapper::new(conn))
}

View File

@@ -0,0 +1,48 @@
// @generated automatically by Diesel CLI.
diesel::table! {
arbiter_settings (rowid) {
rowid -> Integer,
root_key_enc -> Nullable<Binary>,
cert_key -> Binary,
cert -> Binary,
}
}
diesel::table! {
key_identity (id) {
id -> Nullable<Integer>,
name -> Text,
public_key -> Text,
created_at -> Integer,
updated_at -> Integer,
}
}
diesel::table! {
program_client (id) {
id -> Nullable<Integer>,
key_identity_id -> Integer,
created_at -> Integer,
updated_at -> Integer,
}
}
diesel::table! {
useragent_client (id) {
id -> Nullable<Integer>,
key_identity_id -> Integer,
created_at -> Integer,
updated_at -> Integer,
}
}
diesel::joinable!(program_client -> key_identity (key_identity_id));
diesel::joinable!(useragent_client -> key_identity (key_identity_id));
diesel::allow_tables_to_appear_in_same_query!(
arbiter_settings,
key_identity,
program_client,
useragent_client,
);

View File

@@ -1,5 +1,5 @@
mod db;
#[tokio::main]
pub async fn main() {
}
pub struct Server {
pub db: db::Database,
}

View File

@@ -0,0 +1,6 @@
[package]
name = "arbiter-useragent"
version = "0.1.0"
edition = "2024"
[dependencies]

View File

@@ -0,0 +1,14 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}