Move extension storage to SurrealDB schema modules
- Split storage repositories into per-domain modules - Add SurrealDB schema definitions and route handlers - Update phone docs for new persistent table layout
This commit is contained in:
parent
4532e7b73d
commit
06c634c642
@ -8,13 +8,12 @@ Server State
|
||||
|
||||
Phone contacts, messages, and emails are owned by the server extension. SQF phone stores act as bridge objects for CBA events and UI sync only.
|
||||
|
||||
Persistent Redis keys:
|
||||
Persistent SurrealDB tables:
|
||||
|
||||
- `phone:{uid}:contacts`: set of contact actor UIDs
|
||||
- `phone:message:{messageId}`: hash containing message record fields
|
||||
- `phone:{uid}:messages`: list of message IDs visible to the user
|
||||
- `phone:{uid}:thread:{otherUid}`: list of message IDs for a conversation
|
||||
- `phone:{uid}:message_read`: hash of message ID to per-user read state
|
||||
- `phone:email:{emailId}`: hash containing email record fields
|
||||
- `phone:{uid}:emails`: list of email IDs visible to the user
|
||||
- `phone:{uid}:email_read`: hash of email ID to per-user read state
|
||||
- `phone_user`: owner row for an initialized phone profile.
|
||||
- `phone_contact`: per-owner contact rows keyed by owner UID and contact UID.
|
||||
- `phone_message`: shared message records.
|
||||
- `phone_message_index`: per-owner message visibility and read state.
|
||||
- `phone_email`: shared email records.
|
||||
- `phone_email_index`: per-owner email visibility and read state.
|
||||
- `phone_sequence`: global sequence state for generated message and email IDs.
|
||||
|
||||
@ -23,6 +23,7 @@ mod log;
|
||||
pub mod org;
|
||||
pub mod phone;
|
||||
pub mod redis;
|
||||
pub mod schema;
|
||||
pub mod storage;
|
||||
pub mod store;
|
||||
pub mod surreal;
|
||||
|
||||
15
arma/server/extension/src/schema/actor.surql
Normal file
15
arma/server/extension/src/schema/actor.surql
Normal file
@ -0,0 +1,15 @@
|
||||
DEFINE TABLE IF NOT EXISTS actor SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON actor TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS name ON actor TYPE option<string>;
|
||||
DEFINE FIELD IF NOT EXISTS loadout ON actor TYPE any;
|
||||
DEFINE FIELD IF NOT EXISTS position ON actor TYPE option<array>;
|
||||
DEFINE FIELD IF NOT EXISTS direction ON actor TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS stance ON actor TYPE option<string>;
|
||||
DEFINE FIELD IF NOT EXISTS email ON actor TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS phone_number ON actor TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS state ON actor TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS holster ON actor TYPE bool;
|
||||
DEFINE FIELD IF NOT EXISTS rank ON actor TYPE option<string>;
|
||||
DEFINE FIELD IF NOT EXISTS organization ON actor TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON actor TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS actor_uid ON actor COLUMNS uid UNIQUE;
|
||||
17
arma/server/extension/src/schema/bank.surql
Normal file
17
arma/server/extension/src/schema/bank.surql
Normal file
@ -0,0 +1,17 @@
|
||||
DEFINE TABLE IF NOT EXISTS bank SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON bank TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS name ON bank TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS bank ON bank TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS cash ON bank TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS earnings ON bank TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS pin ON bank TYPE int;
|
||||
DEFINE FIELD OVERWRITE updated_at ON bank TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS bank_uid ON bank COLUMNS uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS bank_transaction SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON bank_transaction TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS ordinal ON bank_transaction TYPE int;
|
||||
DEFINE FIELD IF NOT EXISTS message ON bank_transaction TYPE string;
|
||||
DEFINE FIELD OVERWRITE created_at ON bank_transaction TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS bank_transaction_owner ON bank_transaction COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS bank_transaction_unique ON bank_transaction COLUMNS uid, ordinal UNIQUE;
|
||||
29
arma/server/extension/src/schema/garage.surql
Normal file
29
arma/server/extension/src/schema/garage.surql
Normal file
@ -0,0 +1,29 @@
|
||||
DEFINE TABLE IF NOT EXISTS garage SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON garage TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON garage TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS garage_uid ON garage COLUMNS uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS garage_vehicle SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON garage_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS plate ON garage_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON garage_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS fuel ON garage_vehicle TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS damage ON garage_vehicle TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS hit_points ON garage_vehicle TYPE object;
|
||||
DEFINE FIELD OVERWRITE updated_at ON garage_vehicle TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS garage_vehicle_owner ON garage_vehicle COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS garage_vehicle_unique ON garage_vehicle COLUMNS uid, plate UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS owned_garage SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON owned_garage TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON owned_garage TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS owned_garage_uid ON owned_garage COLUMNS uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS garage_unlock SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON garage_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON garage_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON garage_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS source ON garage_unlock TYPE option<string>;
|
||||
DEFINE FIELD OVERWRITE unlocked_at ON garage_unlock TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS garage_unlock_owner ON garage_unlock COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS garage_unlock_unique ON garage_unlock COLUMNS uid, category, classname UNIQUE;
|
||||
27
arma/server/extension/src/schema/locker.surql
Normal file
27
arma/server/extension/src/schema/locker.surql
Normal file
@ -0,0 +1,27 @@
|
||||
DEFINE TABLE IF NOT EXISTS locker SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON locker TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON locker TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS locker_uid ON locker COLUMNS uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS locker_item SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON locker_item TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON locker_item TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON locker_item TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS amount ON locker_item TYPE int;
|
||||
DEFINE FIELD OVERWRITE updated_at ON locker_item TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS locker_item_owner ON locker_item COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS locker_item_unique ON locker_item COLUMNS uid, classname UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS owned_locker SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON owned_locker TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON owned_locker TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS owned_locker_uid ON owned_locker COLUMNS uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS locker_unlock SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON locker_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON locker_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON locker_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS source ON locker_unlock TYPE option<string>;
|
||||
DEFINE FIELD OVERWRITE unlocked_at ON locker_unlock TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS locker_unlock_owner ON locker_unlock COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS locker_unlock_unique ON locker_unlock COLUMNS uid, category, classname UNIQUE;
|
||||
48
arma/server/extension/src/schema/mod.rs
Normal file
48
arma/server/extension/src/schema/mod.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::log;
|
||||
use crate::surreal::SurrealDb;
|
||||
|
||||
const SCHEMAS: &[(&str, &str)] = &[
|
||||
("actor", include_str!("actor.surql")),
|
||||
("bank", include_str!("bank.surql")),
|
||||
("org", include_str!("org.surql")),
|
||||
("locker", include_str!("locker.surql")),
|
||||
("garage", include_str!("garage.surql")),
|
||||
("phone", include_str!("phone.surql")),
|
||||
];
|
||||
|
||||
pub async fn apply_all(db: &SurrealDb) -> Result<(), String> {
|
||||
for (name, schema) in SCHEMAS {
|
||||
for statement in schema_statements(schema) {
|
||||
db.query(statement)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
format!(
|
||||
"SurrealDB {} schema bootstrap failed for statement '{}': {}",
|
||||
name, statement, error
|
||||
)
|
||||
})?
|
||||
.check()
|
||||
.map_err(|error| {
|
||||
format!(
|
||||
"SurrealDB {} schema bootstrap failed for statement '{}': {}",
|
||||
name, statement, error
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
log::log(
|
||||
"surreal",
|
||||
"DEBUG",
|
||||
&format!("Applied SurrealDB {} schema", name),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn schema_statements(schema: &'static str) -> impl Iterator<Item = &'static str> {
|
||||
schema
|
||||
.split(';')
|
||||
.map(str::trim)
|
||||
.filter(|statement| !statement.is_empty())
|
||||
}
|
||||
51
arma/server/extension/src/schema/org.surql
Normal file
51
arma/server/extension/src/schema/org.surql
Normal file
@ -0,0 +1,51 @@
|
||||
DEFINE TABLE IF NOT EXISTS org SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS org_id ON org TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS owner ON org TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS name ON org TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS funds ON org TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS reputation ON org TYPE int;
|
||||
DEFINE FIELD OVERWRITE updated_at ON org TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS org_org_id ON org COLUMNS org_id UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS org_member SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS org_id ON org_member TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS member_uid ON org_member TYPE string;
|
||||
DEFINE FIELD OVERWRITE joined_at ON org_member TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS org_member_org ON org_member COLUMNS org_id;
|
||||
DEFINE INDEX IF NOT EXISTS org_member_unique ON org_member COLUMNS org_id, member_uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS org_credit_line SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS org_id ON org_credit_line TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON org_credit_line TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS name ON org_credit_line TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS approved_amount ON org_credit_line TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS available_amount ON org_credit_line TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS outstanding_principal ON org_credit_line TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS interest_rate ON org_credit_line TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS amount_due ON org_credit_line TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS amount ON org_credit_line TYPE number;
|
||||
DEFINE FIELD OVERWRITE updated_at ON org_credit_line TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS org_credit_line_org ON org_credit_line COLUMNS org_id;
|
||||
DEFINE INDEX IF NOT EXISTS org_credit_line_unique ON org_credit_line COLUMNS org_id, uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS org_asset SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS org_id ON org_asset TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON org_asset TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON org_asset TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS asset_type ON org_asset TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS quantity ON org_asset TYPE int;
|
||||
DEFINE FIELD OVERWRITE updated_at ON org_asset TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS org_asset_org ON org_asset COLUMNS org_id;
|
||||
DEFINE INDEX IF NOT EXISTS org_asset_unique ON org_asset COLUMNS org_id, category, classname UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS org_fleet_vehicle SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS org_id ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS fleet_key ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS name ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS fleet_type ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS status ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS damage ON org_fleet_vehicle TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON org_fleet_vehicle TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS org_fleet_vehicle_org ON org_fleet_vehicle COLUMNS org_id;
|
||||
DEFINE INDEX IF NOT EXISTS org_fleet_vehicle_unique ON org_fleet_vehicle COLUMNS org_id, fleet_key UNIQUE;
|
||||
53
arma/server/extension/src/schema/phone.surql
Normal file
53
arma/server/extension/src/schema/phone.surql
Normal file
@ -0,0 +1,53 @@
|
||||
DEFINE TABLE IF NOT EXISTS phone_user SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_user TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON phone_user TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_user_uid ON phone_user COLUMNS uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS phone_contact SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_contact TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS contact_uid ON phone_contact TYPE string;
|
||||
DEFINE FIELD OVERWRITE created_at ON phone_contact TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_contact_owner ON phone_contact COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS phone_contact_unique ON phone_contact COLUMNS uid, contact_uid UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS phone_message SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS message_id ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS from_uid ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS to_uid ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS message ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS timestamp ON phone_message TYPE number;
|
||||
DEFINE FIELD OVERWRITE created_at ON phone_message TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_message_id ON phone_message COLUMNS message_id UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS phone_message_index SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_message_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS message_id ON phone_message_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS is_read ON phone_message_index TYPE bool;
|
||||
DEFINE FIELD OVERWRITE updated_at ON phone_message_index TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_index_owner ON phone_message_index COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_index_message ON phone_message_index COLUMNS message_id;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_index_unique ON phone_message_index COLUMNS uid, message_id UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS phone_email SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS email_id ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS from_uid ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS to_uid ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS subject ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS body ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS timestamp ON phone_email TYPE number;
|
||||
DEFINE FIELD OVERWRITE created_at ON phone_email TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_email_id ON phone_email COLUMNS email_id UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS phone_email_index SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_email_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS email_id ON phone_email_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS is_read ON phone_email_index TYPE bool;
|
||||
DEFINE FIELD OVERWRITE updated_at ON phone_email_index TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_index_owner ON phone_email_index COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_index_email ON phone_email_index COLUMNS email_id;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_index_unique ON phone_email_index COLUMNS uid, email_id UNIQUE;
|
||||
|
||||
DEFINE TABLE IF NOT EXISTS phone_sequence SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS sequence_id ON phone_sequence TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS value ON phone_sequence TYPE int;
|
||||
DEFINE INDEX IF NOT EXISTS phone_sequence_id ON phone_sequence COLUMNS sequence_id UNIQUE;
|
||||
File diff suppressed because it is too large
Load Diff
135
arma/server/extension/src/storage/actor.rs
Normal file
135
arma/server/extension/src/storage/actor.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use super::common::*;
|
||||
use super::*;
|
||||
|
||||
pub enum ActorStorageRepository {
|
||||
Redis(RedisActorRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealActorRepository),
|
||||
}
|
||||
|
||||
impl ActorStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealActorRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisActorRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActorRepository for ActorStorageRepository {
|
||||
fn create(&self, actor: &Actor) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(actor),
|
||||
Self::Surreal(repository) => repository.create(actor),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_by_id(&self, id: &str) -> Result<Option<Actor>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get_by_id(id),
|
||||
Self::Surreal(repository) => repository.get_by_id(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, actor: &Actor) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(actor),
|
||||
Self::Surreal(repository) => repository.update(actor),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(id),
|
||||
Self::Surreal(repository) => repository.delete(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(id),
|
||||
Self::Surreal(repository) => repository.exists(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealActorRepository;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct ActorRecord {
|
||||
uid: String,
|
||||
name: Option<String>,
|
||||
loadout: serde_json::Value,
|
||||
position: Option<Vec<f64>>,
|
||||
direction: f64,
|
||||
stance: Option<String>,
|
||||
email: String,
|
||||
phone_number: String,
|
||||
state: String,
|
||||
holster: bool,
|
||||
rank: Option<String>,
|
||||
organization: String,
|
||||
}
|
||||
|
||||
impl ActorRecord {
|
||||
fn into_actor(self) -> Actor {
|
||||
Actor {
|
||||
uid: self.uid,
|
||||
name: self.name,
|
||||
loadout: self.loadout,
|
||||
position: self.position,
|
||||
direction: self.direction,
|
||||
stance: self.stance,
|
||||
email: self.email,
|
||||
phone_number: self.phone_number,
|
||||
state: self.state,
|
||||
holster: self.holster,
|
||||
rank: self.rank,
|
||||
organization: self.organization,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Actor> for ActorRecord {
|
||||
fn from(actor: &Actor) -> Self {
|
||||
Self {
|
||||
uid: actor.uid.clone(),
|
||||
name: actor.name.clone(),
|
||||
loadout: actor.loadout.clone(),
|
||||
position: actor.position.clone(),
|
||||
direction: actor.direction,
|
||||
stance: actor.stance.clone(),
|
||||
email: actor.email.clone(),
|
||||
phone_number: actor.phone_number.clone(),
|
||||
state: actor.state.clone(),
|
||||
holster: actor.holster,
|
||||
rank: actor.rank.clone(),
|
||||
organization: actor.organization.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActorRepository for SurrealActorRepository {
|
||||
fn create(&self, actor: &Actor) -> Result<(), String> {
|
||||
self.update(actor)
|
||||
}
|
||||
|
||||
fn get_by_id(&self, id: &str) -> Result<Option<Actor>, String> {
|
||||
surreal_select::<ActorRecord>("actor", id, "actor")
|
||||
.map(|record| record.map(ActorRecord::into_actor))
|
||||
}
|
||||
|
||||
fn update(&self, actor: &Actor) -> Result<(), String> {
|
||||
let record = ActorRecord::from(actor);
|
||||
surreal_upsert("actor", actor.uid.as_str(), "actor", &record)
|
||||
}
|
||||
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
surreal_delete::<ActorRecord>("actor", id, "actor")
|
||||
}
|
||||
|
||||
fn exists(&self, id: &str) -> Result<bool, String> {
|
||||
self.get_by_id(id).map(|actor| actor.is_some())
|
||||
}
|
||||
}
|
||||
165
arma/server/extension/src/storage/bank.rs
Normal file
165
arma/server/extension/src/storage/bank.rs
Normal file
@ -0,0 +1,165 @@
|
||||
use super::common::*;
|
||||
use super::*;
|
||||
|
||||
pub enum BankStorageRepository {
|
||||
Redis(RedisBankRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealBankRepository),
|
||||
}
|
||||
|
||||
impl BankStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealBankRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisBankRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BankRepository for BankStorageRepository {
|
||||
fn create(&self, bank: &Bank) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(bank),
|
||||
Self::Surreal(repository) => repository.create(bank),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_by_id(&self, id: &str) -> Result<Option<Bank>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get_by_id(id),
|
||||
Self::Surreal(repository) => repository.get_by_id(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, bank: &Bank) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(bank),
|
||||
Self::Surreal(repository) => repository.update(bank),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(id),
|
||||
Self::Surreal(repository) => repository.delete(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(id),
|
||||
Self::Surreal(repository) => repository.exists(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealBankRepository;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct BankAccountRecord {
|
||||
uid: String,
|
||||
name: String,
|
||||
bank: f64,
|
||||
cash: f64,
|
||||
earnings: f64,
|
||||
pin: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct BankTransactionRecord {
|
||||
uid: String,
|
||||
ordinal: u64,
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl BankAccountRecord {
|
||||
fn into_bank(self, transactions: Vec<String>) -> Bank {
|
||||
Bank {
|
||||
uid: self.uid,
|
||||
name: self.name,
|
||||
bank: self.bank,
|
||||
cash: self.cash,
|
||||
earnings: self.earnings,
|
||||
pin: self.pin,
|
||||
transactions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Bank> for BankAccountRecord {
|
||||
fn from(bank: &Bank) -> Self {
|
||||
Self {
|
||||
uid: bank.uid.clone(),
|
||||
name: bank.name.clone(),
|
||||
bank: bank.bank,
|
||||
cash: bank.cash,
|
||||
earnings: bank.earnings,
|
||||
pin: bank.pin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bank_transaction_id(uid: &str, ordinal: usize) -> String {
|
||||
format!("{}:{}", uid, ordinal)
|
||||
}
|
||||
|
||||
fn bank_transactions_from_records(mut records: Vec<BankTransactionRecord>) -> Vec<String> {
|
||||
records.sort_by_key(|record| record.ordinal);
|
||||
records
|
||||
.into_iter()
|
||||
.map(|record| record.message)
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
impl BankRepository for SurrealBankRepository {
|
||||
fn create(&self, bank: &Bank) -> Result<(), String> {
|
||||
self.update(bank)
|
||||
}
|
||||
|
||||
fn get_by_id(&self, id: &str) -> Result<Option<Bank>, String> {
|
||||
let Some(record) = surreal_select::<BankAccountRecord>("bank", id, "bank")? else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let transaction_records = surreal_select_by_uid::<BankTransactionRecord>(
|
||||
"bank_transaction",
|
||||
"bank transactions",
|
||||
id,
|
||||
)?;
|
||||
let transactions = bank_transactions_from_records(transaction_records);
|
||||
|
||||
Ok(Some(record.into_bank(transactions)))
|
||||
}
|
||||
|
||||
fn update(&self, bank: &Bank) -> Result<(), String> {
|
||||
let account = BankAccountRecord::from(bank);
|
||||
surreal_upsert("bank", bank.uid.as_str(), "bank", &account)?;
|
||||
surreal_delete_by_uid("bank_transaction", "bank transactions", &bank.uid)?;
|
||||
|
||||
for (ordinal, message) in bank.transactions.iter().enumerate() {
|
||||
let record = BankTransactionRecord {
|
||||
uid: bank.uid.clone(),
|
||||
ordinal: ordinal as u64,
|
||||
message: message.clone(),
|
||||
};
|
||||
surreal_upsert(
|
||||
"bank_transaction",
|
||||
&bank_transaction_id(&bank.uid, ordinal),
|
||||
"bank transaction",
|
||||
&record,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
surreal_delete_by_uid("bank_transaction", "bank transactions", id)?;
|
||||
surreal_delete::<BankAccountRecord>("bank", id, "bank")
|
||||
}
|
||||
|
||||
fn exists(&self, id: &str) -> Result<bool, String> {
|
||||
self.get_by_id(id).map(|bank| bank.is_some())
|
||||
}
|
||||
}
|
||||
132
arma/server/extension/src/storage/common.rs
Normal file
132
arma/server/extension/src/storage/common.rs
Normal file
@ -0,0 +1,132 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) fn surreal_select<T>(
|
||||
table: &'static str,
|
||||
id: &str,
|
||||
label: &str,
|
||||
) -> Result<Option<T>, String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let id = id.to_string();
|
||||
RUNTIME.block_on(async move {
|
||||
surreal::client()
|
||||
.await?
|
||||
.select((table, id.as_str()))
|
||||
.await
|
||||
.map_err(|error| format!("SurrealDB {} select failed: {}", label, error))
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn surreal_select_all<T>(table: &'static str, label: &str) -> Result<Vec<T>, String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
RUNTIME.block_on(async move {
|
||||
surreal::client()
|
||||
.await?
|
||||
.select(table)
|
||||
.await
|
||||
.map_err(|error| format!("SurrealDB {} select all failed: {}", label, error))
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn surreal_upsert<T>(
|
||||
table: &'static str,
|
||||
id: &str,
|
||||
label: &str,
|
||||
record: &T,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
T: Serialize + DeserializeOwned,
|
||||
{
|
||||
let id = id.to_string();
|
||||
let record = serde_json::to_value(record)
|
||||
.map_err(|error| format!("SurrealDB {} serialize failed: {}", label, error))?;
|
||||
RUNTIME.block_on(async move {
|
||||
let _: Option<T> = surreal::client()
|
||||
.await?
|
||||
.upsert((table, id.as_str()))
|
||||
.content(record)
|
||||
.await
|
||||
.map_err(|error| format!("SurrealDB {} upsert failed: {}", label, error))?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn surreal_delete<T>(table: &'static str, id: &str, label: &str) -> Result<(), String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let id = id.to_string();
|
||||
RUNTIME.block_on(async move {
|
||||
let _: Option<T> = surreal::client()
|
||||
.await?
|
||||
.delete((table, id.as_str()))
|
||||
.await
|
||||
.map_err(|error| format!("SurrealDB {} delete failed: {}", label, error))?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn surreal_select_by_uid<T>(
|
||||
table: &'static str,
|
||||
label: &str,
|
||||
uid: &str,
|
||||
) -> Result<Vec<T>, String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
surreal_select_by_field(table, label, "uid", uid)
|
||||
}
|
||||
|
||||
pub(super) fn surreal_select_by_field<T>(
|
||||
table: &'static str,
|
||||
label: &str,
|
||||
field: &'static str,
|
||||
value: &str,
|
||||
) -> Result<Vec<T>, String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let value = value.to_string();
|
||||
RUNTIME.block_on(async move {
|
||||
let mut response = surreal::client()
|
||||
.await?
|
||||
.query(format!("SELECT * FROM {} WHERE {} = $value", table, field))
|
||||
.bind(("value", value))
|
||||
.await
|
||||
.map_err(|error| format!("SurrealDB {} select by field failed: {}", label, error))?;
|
||||
response
|
||||
.take(0)
|
||||
.map_err(|error| format!("SurrealDB {} select by field failed: {}", label, error))
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn surreal_delete_by_uid(
|
||||
table: &'static str,
|
||||
label: &str,
|
||||
uid: &str,
|
||||
) -> Result<(), String> {
|
||||
surreal_delete_by_field(table, label, "uid", uid)
|
||||
}
|
||||
|
||||
pub(super) fn surreal_delete_by_field(
|
||||
table: &'static str,
|
||||
label: &str,
|
||||
field: &'static str,
|
||||
value: &str,
|
||||
) -> Result<(), String> {
|
||||
let value = value.to_string();
|
||||
RUNTIME.block_on(async move {
|
||||
surreal::client()
|
||||
.await?
|
||||
.query(format!("DELETE {} WHERE {} = $value", table, field))
|
||||
.bind(("value", value))
|
||||
.await
|
||||
.map_err(|error| format!("SurrealDB {} delete by field failed: {}", label, error))?
|
||||
.check()
|
||||
.map_err(|error| format!("SurrealDB {} delete by field failed: {}", label, error))?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
339
arma/server/extension/src/storage/garage.rs
Normal file
339
arma/server/extension/src/storage/garage.rs
Normal file
@ -0,0 +1,339 @@
|
||||
use super::common::*;
|
||||
use super::*;
|
||||
|
||||
pub enum GarageStorageRepository {
|
||||
Redis(RedisGarageRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealGarageRepository),
|
||||
}
|
||||
|
||||
impl GarageStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealGarageRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisGarageRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GarageRepository for GarageStorageRepository {
|
||||
fn create(&self, uid: &str, garage: &Garage) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(uid, garage),
|
||||
Self::Surreal(repository) => repository.create(uid, garage),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, garage: &Garage) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(uid, garage),
|
||||
Self::Surreal(repository) => repository.update(uid, garage),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str) -> Result<Option<Garage>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get(uid),
|
||||
Self::Surreal(repository) => repository.get(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(uid),
|
||||
Self::Surreal(repository) => repository.delete(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(uid),
|
||||
Self::Surreal(repository) => repository.exists(uid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealGarageRepository;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct GarageOwnerRecord {
|
||||
uid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct GarageVehicleRecord {
|
||||
uid: String,
|
||||
plate: String,
|
||||
classname: String,
|
||||
fuel: f64,
|
||||
damage: f64,
|
||||
hit_points: HitPoints,
|
||||
}
|
||||
|
||||
fn garage_vehicle_id(uid: &str, plate: &str) -> String {
|
||||
format!("{}:{}", uid, plate)
|
||||
}
|
||||
|
||||
fn garage_from_vehicle_records(records: Vec<GarageVehicleRecord>) -> Garage {
|
||||
let vehicles = records
|
||||
.into_iter()
|
||||
.map(|record| {
|
||||
let vehicle = Vehicle {
|
||||
plate: record.plate.clone(),
|
||||
classname: record.classname,
|
||||
fuel: record.fuel,
|
||||
damage: record.damage,
|
||||
hit_points: record.hit_points,
|
||||
};
|
||||
(record.plate, vehicle)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Garage { vehicles }
|
||||
}
|
||||
|
||||
impl GarageRepository for SurrealGarageRepository {
|
||||
fn create(&self, uid: &str, garage: &Garage) -> Result<(), String> {
|
||||
self.update(uid, garage)
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, garage: &Garage) -> Result<(), String> {
|
||||
let owner = GarageOwnerRecord {
|
||||
uid: uid.to_string(),
|
||||
};
|
||||
surreal_upsert("garage", uid, "garage owner", &owner)?;
|
||||
surreal_delete_by_uid("garage_vehicle", "garage vehicles", uid)?;
|
||||
|
||||
for (plate_key, vehicle) in &garage.vehicles {
|
||||
let plate = if vehicle.plate.trim().is_empty() {
|
||||
plate_key.clone()
|
||||
} else {
|
||||
vehicle.plate.clone()
|
||||
};
|
||||
let record = GarageVehicleRecord {
|
||||
uid: uid.to_string(),
|
||||
plate: plate.clone(),
|
||||
classname: vehicle.classname.clone(),
|
||||
fuel: vehicle.fuel,
|
||||
damage: vehicle.damage,
|
||||
hit_points: vehicle.hit_points.clone(),
|
||||
};
|
||||
surreal_upsert(
|
||||
"garage_vehicle",
|
||||
&garage_vehicle_id(uid, &plate),
|
||||
"garage vehicle",
|
||||
&record,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str) -> Result<Option<Garage>, String> {
|
||||
if surreal_select::<GarageOwnerRecord>("garage", uid, "garage owner")?.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let vehicle_records =
|
||||
surreal_select_by_uid::<GarageVehicleRecord>("garage_vehicle", "garage vehicles", uid)?;
|
||||
Ok(Some(garage_from_vehicle_records(vehicle_records)))
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
surreal_delete_by_uid("garage_vehicle", "garage vehicles", uid)?;
|
||||
surreal_delete::<GarageOwnerRecord>("garage", uid, "garage owner")
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
surreal_select::<GarageOwnerRecord>("garage", uid, "garage owner")
|
||||
.map(|garage| garage.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum VGarageStorageRepository {
|
||||
Redis(RedisVGarageRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealVGarageRepository),
|
||||
}
|
||||
|
||||
impl VGarageStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealVGarageRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisVGarageRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VGarageRepository for VGarageStorageRepository {
|
||||
fn create(&self, uid: &str, garage: &VGarage) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(uid, garage),
|
||||
Self::Surreal(repository) => repository.create(uid, garage),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, garage: &VGarage) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(uid, garage),
|
||||
Self::Surreal(repository) => repository.update(uid, garage),
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch(&self, uid: &str) -> Result<Option<VGarage>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.fetch(uid),
|
||||
Self::Surreal(repository) => repository.fetch(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str, field: &str) -> Result<Vec<String>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get(uid, field),
|
||||
Self::Surreal(repository) => repository.get(uid, field),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(uid),
|
||||
Self::Surreal(repository) => repository.delete(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(uid),
|
||||
Self::Surreal(repository) => repository.exists(uid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealVGarageRepository;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct VGarageOwnerRecord {
|
||||
uid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct GarageUnlockRecord {
|
||||
uid: String,
|
||||
category: String,
|
||||
classname: String,
|
||||
source: Option<String>,
|
||||
}
|
||||
|
||||
fn garage_unlock_id(uid: &str, category: &str, classname: &str) -> String {
|
||||
format!("{}:{}:{}", uid, category, classname)
|
||||
}
|
||||
|
||||
fn push_garage_unlock(garage: &mut VGarage, category: &str, classname: String) {
|
||||
let target = match category {
|
||||
"cars" => &mut garage.cars,
|
||||
"armor" => &mut garage.armor,
|
||||
"helis" => &mut garage.helis,
|
||||
"planes" => &mut garage.planes,
|
||||
"naval" => &mut garage.naval,
|
||||
"other" => &mut garage.other,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if !target.contains(&classname) {
|
||||
target.push(classname);
|
||||
}
|
||||
}
|
||||
|
||||
fn vgarage_from_unlock_records(records: Vec<GarageUnlockRecord>) -> VGarage {
|
||||
let mut garage = VGarage {
|
||||
cars: Vec::new(),
|
||||
armor: Vec::new(),
|
||||
helis: Vec::new(),
|
||||
planes: Vec::new(),
|
||||
naval: Vec::new(),
|
||||
other: Vec::new(),
|
||||
};
|
||||
|
||||
for record in records {
|
||||
push_garage_unlock(&mut garage, &record.category, record.classname);
|
||||
}
|
||||
|
||||
garage
|
||||
}
|
||||
|
||||
fn upsert_garage_unlocks(uid: &str, category: &str, classnames: &[String]) -> Result<(), String> {
|
||||
for classname in classnames {
|
||||
let record = GarageUnlockRecord {
|
||||
uid: uid.to_string(),
|
||||
category: category.to_string(),
|
||||
classname: classname.clone(),
|
||||
source: None,
|
||||
};
|
||||
surreal_upsert(
|
||||
"garage_unlock",
|
||||
&garage_unlock_id(uid, category, classname),
|
||||
"garage unlock",
|
||||
&record,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl VGarageRepository for SurrealVGarageRepository {
|
||||
fn create(&self, uid: &str, garage: &VGarage) -> Result<(), String> {
|
||||
self.update(uid, garage)
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, garage: &VGarage) -> Result<(), String> {
|
||||
let owner = VGarageOwnerRecord {
|
||||
uid: uid.to_string(),
|
||||
};
|
||||
surreal_upsert("owned_garage", uid, "virtual garage owner", &owner)?;
|
||||
surreal_delete_by_uid("garage_unlock", "garage unlocks", uid)?;
|
||||
upsert_garage_unlocks(uid, "cars", &garage.cars)?;
|
||||
upsert_garage_unlocks(uid, "armor", &garage.armor)?;
|
||||
upsert_garage_unlocks(uid, "helis", &garage.helis)?;
|
||||
upsert_garage_unlocks(uid, "planes", &garage.planes)?;
|
||||
upsert_garage_unlocks(uid, "naval", &garage.naval)?;
|
||||
upsert_garage_unlocks(uid, "other", &garage.other)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch(&self, uid: &str) -> Result<Option<VGarage>, String> {
|
||||
if surreal_select::<VGarageOwnerRecord>("owned_garage", uid, "virtual garage owner")?
|
||||
.is_none()
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let unlock_records =
|
||||
surreal_select_by_uid::<GarageUnlockRecord>("garage_unlock", "garage unlocks", uid)?;
|
||||
Ok(Some(vgarage_from_unlock_records(unlock_records)))
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str, field: &str) -> Result<Vec<String>, String> {
|
||||
let garage = self.fetch(uid)?.unwrap_or_else(VGarage::new);
|
||||
match field {
|
||||
"cars" => Ok(garage.cars),
|
||||
"armor" => Ok(garage.armor),
|
||||
"helis" => Ok(garage.helis),
|
||||
"planes" => Ok(garage.planes),
|
||||
"naval" => Ok(garage.naval),
|
||||
"other" => Ok(garage.other),
|
||||
_ => Err(format!("Unknown virtual garage field '{}'", field)),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
surreal_delete_by_uid("garage_unlock", "garage unlocks", uid)?;
|
||||
surreal_delete::<VGarageOwnerRecord>("owned_garage", uid, "virtual garage owner")
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
surreal_select::<VGarageOwnerRecord>("owned_garage", uid, "virtual garage owner")
|
||||
.map(|garage| garage.is_some())
|
||||
}
|
||||
}
|
||||
320
arma/server/extension/src/storage/locker.rs
Normal file
320
arma/server/extension/src/storage/locker.rs
Normal file
@ -0,0 +1,320 @@
|
||||
use super::common::*;
|
||||
use super::*;
|
||||
|
||||
pub enum LockerStorageRepository {
|
||||
Redis(RedisLockerRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealLockerRepository),
|
||||
}
|
||||
|
||||
impl LockerStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealLockerRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisLockerRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LockerRepository for LockerStorageRepository {
|
||||
fn create(&self, uid: &str, locker: &Locker) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(uid, locker),
|
||||
Self::Surreal(repository) => repository.create(uid, locker),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, locker: &Locker) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(uid, locker),
|
||||
Self::Surreal(repository) => repository.update(uid, locker),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str) -> Result<Option<Locker>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get(uid),
|
||||
Self::Surreal(repository) => repository.get(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(uid),
|
||||
Self::Surreal(repository) => repository.delete(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(uid),
|
||||
Self::Surreal(repository) => repository.exists(uid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealLockerRepository;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct LockerOwnerRecord {
|
||||
uid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct LockerItemRecord {
|
||||
uid: String,
|
||||
category: String,
|
||||
classname: String,
|
||||
amount: u32,
|
||||
}
|
||||
|
||||
fn locker_item_id(uid: &str, classname: &str) -> String {
|
||||
format!("{}:{}", uid, classname)
|
||||
}
|
||||
|
||||
fn locker_from_item_records(records: Vec<LockerItemRecord>) -> Locker {
|
||||
let items = records
|
||||
.into_iter()
|
||||
.map(|record| {
|
||||
let item = Item {
|
||||
category: record.category,
|
||||
classname: record.classname.clone(),
|
||||
amount: record.amount,
|
||||
};
|
||||
(record.classname, item)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Locker { items }
|
||||
}
|
||||
|
||||
impl LockerRepository for SurrealLockerRepository {
|
||||
fn create(&self, uid: &str, locker: &Locker) -> Result<(), String> {
|
||||
self.update(uid, locker)
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, locker: &Locker) -> Result<(), String> {
|
||||
let owner = LockerOwnerRecord {
|
||||
uid: uid.to_string(),
|
||||
};
|
||||
surreal_upsert("locker", uid, "locker owner", &owner)?;
|
||||
surreal_delete_by_uid("locker_item", "locker items", uid)?;
|
||||
|
||||
for item in locker.items.values() {
|
||||
let record = LockerItemRecord {
|
||||
uid: uid.to_string(),
|
||||
category: item.category.clone(),
|
||||
classname: item.classname.clone(),
|
||||
amount: item.amount,
|
||||
};
|
||||
surreal_upsert(
|
||||
"locker_item",
|
||||
&locker_item_id(uid, &item.classname),
|
||||
"locker item",
|
||||
&record,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str) -> Result<Option<Locker>, String> {
|
||||
if surreal_select::<LockerOwnerRecord>("locker", uid, "locker owner")?.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let item_records =
|
||||
surreal_select_by_uid::<LockerItemRecord>("locker_item", "locker items", uid)?;
|
||||
Ok(Some(locker_from_item_records(item_records)))
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
surreal_delete_by_uid("locker_item", "locker items", uid)?;
|
||||
surreal_delete::<LockerOwnerRecord>("locker", uid, "locker owner")
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
surreal_select::<LockerOwnerRecord>("locker", uid, "locker owner")
|
||||
.map(|locker| locker.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum VLockerStorageRepository {
|
||||
Redis(RedisVLockerRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealVLockerRepository),
|
||||
}
|
||||
|
||||
impl VLockerStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealVLockerRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisVLockerRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VLockerRepository for VLockerStorageRepository {
|
||||
fn create(&self, uid: &str, locker: &VLocker) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(uid, locker),
|
||||
Self::Surreal(repository) => repository.create(uid, locker),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, locker: &VLocker) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(uid, locker),
|
||||
Self::Surreal(repository) => repository.update(uid, locker),
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch(&self, uid: &str) -> Result<Option<VLocker>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.fetch(uid),
|
||||
Self::Surreal(repository) => repository.fetch(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str, field: &str) -> Result<Vec<String>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get(uid, field),
|
||||
Self::Surreal(repository) => repository.get(uid, field),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(uid),
|
||||
Self::Surreal(repository) => repository.delete(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(uid),
|
||||
Self::Surreal(repository) => repository.exists(uid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealVLockerRepository;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct VLockerOwnerRecord {
|
||||
uid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct LockerUnlockRecord {
|
||||
uid: String,
|
||||
category: String,
|
||||
classname: String,
|
||||
source: Option<String>,
|
||||
}
|
||||
|
||||
fn locker_unlock_id(uid: &str, category: &str, classname: &str) -> String {
|
||||
format!("{}:{}:{}", uid, category, classname)
|
||||
}
|
||||
|
||||
fn push_locker_unlock(locker: &mut VLocker, category: &str, classname: String) {
|
||||
let target = match category {
|
||||
"items" => &mut locker.items,
|
||||
"weapons" => &mut locker.weapons,
|
||||
"magazines" => &mut locker.magazines,
|
||||
"backpacks" => &mut locker.backpacks,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if !target.contains(&classname) {
|
||||
target.push(classname);
|
||||
}
|
||||
}
|
||||
|
||||
fn vlocker_from_unlock_records(records: Vec<LockerUnlockRecord>) -> VLocker {
|
||||
let mut locker = VLocker {
|
||||
items: Vec::new(),
|
||||
weapons: Vec::new(),
|
||||
magazines: Vec::new(),
|
||||
backpacks: Vec::new(),
|
||||
};
|
||||
|
||||
for record in records {
|
||||
push_locker_unlock(&mut locker, &record.category, record.classname);
|
||||
}
|
||||
|
||||
locker
|
||||
}
|
||||
|
||||
fn upsert_locker_unlocks(uid: &str, category: &str, classnames: &[String]) -> Result<(), String> {
|
||||
for classname in classnames {
|
||||
let record = LockerUnlockRecord {
|
||||
uid: uid.to_string(),
|
||||
category: category.to_string(),
|
||||
classname: classname.clone(),
|
||||
source: None,
|
||||
};
|
||||
surreal_upsert(
|
||||
"locker_unlock",
|
||||
&locker_unlock_id(uid, category, classname),
|
||||
"locker unlock",
|
||||
&record,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl VLockerRepository for SurrealVLockerRepository {
|
||||
fn create(&self, uid: &str, locker: &VLocker) -> Result<(), String> {
|
||||
self.update(uid, locker)
|
||||
}
|
||||
|
||||
fn update(&self, uid: &str, locker: &VLocker) -> Result<(), String> {
|
||||
let owner = VLockerOwnerRecord {
|
||||
uid: uid.to_string(),
|
||||
};
|
||||
surreal_upsert("owned_locker", uid, "virtual locker owner", &owner)?;
|
||||
surreal_delete_by_uid("locker_unlock", "locker unlocks", uid)?;
|
||||
upsert_locker_unlocks(uid, "items", &locker.items)?;
|
||||
upsert_locker_unlocks(uid, "weapons", &locker.weapons)?;
|
||||
upsert_locker_unlocks(uid, "magazines", &locker.magazines)?;
|
||||
upsert_locker_unlocks(uid, "backpacks", &locker.backpacks)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch(&self, uid: &str) -> Result<Option<VLocker>, String> {
|
||||
if surreal_select::<VLockerOwnerRecord>("owned_locker", uid, "virtual locker owner")?
|
||||
.is_none()
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let unlock_records =
|
||||
surreal_select_by_uid::<LockerUnlockRecord>("locker_unlock", "locker unlocks", uid)?;
|
||||
Ok(Some(vlocker_from_unlock_records(unlock_records)))
|
||||
}
|
||||
|
||||
fn get(&self, uid: &str, field: &str) -> Result<Vec<String>, String> {
|
||||
let locker = self.fetch(uid)?.unwrap_or_else(VLocker::new);
|
||||
match field {
|
||||
"items" => Ok(locker.items),
|
||||
"weapons" => Ok(locker.weapons),
|
||||
"magazines" => Ok(locker.magazines),
|
||||
"backpacks" => Ok(locker.backpacks),
|
||||
_ => Err(format!("Unknown virtual locker field '{}'", field)),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, uid: &str) -> Result<(), String> {
|
||||
surreal_delete_by_uid("locker_unlock", "locker unlocks", uid)?;
|
||||
surreal_delete::<VLockerOwnerRecord>("owned_locker", uid, "virtual locker owner")
|
||||
}
|
||||
|
||||
fn exists(&self, uid: &str) -> Result<bool, String> {
|
||||
surreal_select::<VLockerOwnerRecord>("owned_locker", uid, "virtual locker owner")
|
||||
.map(|locker| locker.is_some())
|
||||
}
|
||||
}
|
||||
501
arma/server/extension/src/storage/org.rs
Normal file
501
arma/server/extension/src/storage/org.rs
Normal file
@ -0,0 +1,501 @@
|
||||
use super::common::*;
|
||||
use super::*;
|
||||
|
||||
pub enum OrgStorageRepository {
|
||||
Redis(RedisOrgRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealOrgRepository),
|
||||
}
|
||||
|
||||
impl OrgStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealOrgRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisOrgRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OrgRepository for OrgStorageRepository {
|
||||
fn create(&self, org: &Org) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.create(org),
|
||||
Self::Surreal(repository) => repository.create(org),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_by_id(&self, id: &str) -> Result<Option<Org>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get_by_id(id),
|
||||
Self::Surreal(repository) => repository.get_by_id(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, org: &Org) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update(org),
|
||||
Self::Surreal(repository) => repository.update(org),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete(id),
|
||||
Self::Surreal(repository) => repository.delete(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(&self, id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.exists(id),
|
||||
Self::Surreal(repository) => repository.exists(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_member(&self, org_id: &str, member_uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.add_member(org_id, member_uid),
|
||||
Self::Surreal(repository) => repository.add_member(org_id, member_uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_members(&self, org_id: &str) -> Result<Vec<MemberSummary>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get_members(org_id),
|
||||
Self::Surreal(repository) => repository.get_members(org_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_member(&self, org_id: &str, member_uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.remove_member(org_id, member_uid),
|
||||
Self::Surreal(repository) => repository.remove_member(org_id, member_uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_assets(
|
||||
&self,
|
||||
org_id: &str,
|
||||
) -> Result<HashMap<String, HashMap<String, OrgAssetEntry>>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get_assets(org_id),
|
||||
Self::Surreal(repository) => repository.get_assets(org_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_assets(
|
||||
&self,
|
||||
org_id: &str,
|
||||
assets: &HashMap<String, HashMap<String, OrgAssetEntry>>,
|
||||
) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update_assets(org_id, assets),
|
||||
Self::Surreal(repository) => repository.update_assets(org_id, assets),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fleet(&self, org_id: &str) -> Result<HashMap<String, OrgFleetEntry>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.get_fleet(org_id),
|
||||
Self::Surreal(repository) => repository.get_fleet(org_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_fleet(
|
||||
&self,
|
||||
org_id: &str,
|
||||
fleet: &HashMap<String, OrgFleetEntry>,
|
||||
) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.update_fleet(org_id, fleet),
|
||||
Self::Surreal(repository) => repository.update_fleet(org_id, fleet),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
struct SurrealOrgRecord {
|
||||
#[serde(default)]
|
||||
org_id: String,
|
||||
#[serde(default)]
|
||||
owner: String,
|
||||
#[serde(default)]
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
funds: f64,
|
||||
#[serde(default)]
|
||||
reputation: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct OrgMemberRow {
|
||||
org_id: String,
|
||||
member_uid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct OrgCreditLineRow {
|
||||
org_id: String,
|
||||
uid: String,
|
||||
name: String,
|
||||
approved_amount: f64,
|
||||
available_amount: f64,
|
||||
outstanding_principal: f64,
|
||||
interest_rate: f64,
|
||||
amount_due: f64,
|
||||
amount: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct OrgAssetRow {
|
||||
org_id: String,
|
||||
category: String,
|
||||
classname: String,
|
||||
asset_type: String,
|
||||
quantity: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct OrgFleetRow {
|
||||
org_id: String,
|
||||
fleet_key: String,
|
||||
classname: String,
|
||||
name: String,
|
||||
fleet_type: String,
|
||||
status: String,
|
||||
damage: String,
|
||||
}
|
||||
|
||||
impl SurrealOrgRecord {
|
||||
fn into_org(self, fallback_id: &str, credit_lines: HashMap<String, CreditLineSummary>) -> Org {
|
||||
let id = if self.org_id.trim().is_empty() {
|
||||
fallback_id.to_string()
|
||||
} else {
|
||||
self.org_id
|
||||
};
|
||||
|
||||
let mut org = Org {
|
||||
id,
|
||||
owner: self.owner,
|
||||
name: self.name,
|
||||
funds: self.funds,
|
||||
reputation: self.reputation,
|
||||
credit_lines,
|
||||
};
|
||||
org.normalize_credit_lines();
|
||||
org
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Org> for SurrealOrgRecord {
|
||||
fn from(org: &Org) -> Self {
|
||||
Self {
|
||||
org_id: org.id.clone(),
|
||||
owner: org.owner.clone(),
|
||||
name: org.name.clone(),
|
||||
funds: org.funds,
|
||||
reputation: org.reputation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SurrealOrgRepository;
|
||||
|
||||
fn org_member_id(org_id: &str, member_uid: &str) -> String {
|
||||
format!("{}:{}", org_id, member_uid)
|
||||
}
|
||||
|
||||
fn org_credit_line_id(org_id: &str, uid: &str) -> String {
|
||||
format!("{}:{}", org_id, uid)
|
||||
}
|
||||
|
||||
fn org_asset_id(org_id: &str, category: &str, classname: &str) -> String {
|
||||
format!("{}:{}:{}", org_id, category, classname)
|
||||
}
|
||||
|
||||
fn org_fleet_id(org_id: &str, fleet_key: &str) -> String {
|
||||
format!("{}:{}", org_id, fleet_key)
|
||||
}
|
||||
|
||||
fn org_credit_lines_from_rows(rows: Vec<OrgCreditLineRow>) -> HashMap<String, CreditLineSummary> {
|
||||
rows.into_iter()
|
||||
.map(|row| {
|
||||
let mut credit_line = CreditLineSummary {
|
||||
uid: row.uid.clone(),
|
||||
name: row.name,
|
||||
approved_amount: row.approved_amount,
|
||||
available_amount: row.available_amount,
|
||||
outstanding_principal: row.outstanding_principal,
|
||||
interest_rate: row.interest_rate,
|
||||
amount_due: row.amount_due,
|
||||
amount: row.amount,
|
||||
};
|
||||
credit_line.normalize();
|
||||
(row.uid, credit_line)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn org_member_uids(org_id: &str) -> Result<Vec<String>, String> {
|
||||
let rows =
|
||||
surreal_select_by_field::<OrgMemberRow>("org_member", "org members", "org_id", org_id)?;
|
||||
let mut uids = rows
|
||||
.into_iter()
|
||||
.map(|row| row.member_uid)
|
||||
.filter(|uid| !uid.trim().is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
uids.sort();
|
||||
uids.dedup();
|
||||
Ok(uids)
|
||||
}
|
||||
|
||||
fn upsert_org_member(org_id: &str, member_uid: &str) -> Result<(), String> {
|
||||
let row = OrgMemberRow {
|
||||
org_id: org_id.to_string(),
|
||||
member_uid: member_uid.to_string(),
|
||||
};
|
||||
surreal_upsert(
|
||||
"org_member",
|
||||
&org_member_id(org_id, member_uid),
|
||||
"org member",
|
||||
&row,
|
||||
)
|
||||
}
|
||||
|
||||
fn org_assets_from_rows(rows: Vec<OrgAssetRow>) -> HashMap<String, HashMap<String, OrgAssetEntry>> {
|
||||
let mut assets = HashMap::new();
|
||||
for row in rows {
|
||||
let category_assets = assets
|
||||
.entry(row.category.clone())
|
||||
.or_insert_with(HashMap::new);
|
||||
category_assets.insert(
|
||||
row.classname.clone(),
|
||||
OrgAssetEntry {
|
||||
classname: row.classname,
|
||||
asset_type: row.asset_type,
|
||||
quantity: row.quantity,
|
||||
},
|
||||
);
|
||||
}
|
||||
assets
|
||||
}
|
||||
|
||||
fn org_fleet_from_rows(rows: Vec<OrgFleetRow>) -> HashMap<String, OrgFleetEntry> {
|
||||
rows.into_iter()
|
||||
.map(|row| {
|
||||
(
|
||||
row.fleet_key,
|
||||
OrgFleetEntry {
|
||||
classname: row.classname,
|
||||
name: row.name,
|
||||
fleet_type: row.fleet_type,
|
||||
status: row.status,
|
||||
damage: row.damage,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl OrgRepository for SurrealOrgRepository {
|
||||
fn create(&self, org: &Org) -> Result<(), String> {
|
||||
self.update(org)
|
||||
}
|
||||
|
||||
fn get_by_id(&self, id: &str) -> Result<Option<Org>, String> {
|
||||
let Some(record) = surreal_select::<SurrealOrgRecord>("org", id, "org")? else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let credit_line_rows = surreal_select_by_field::<OrgCreditLineRow>(
|
||||
"org_credit_line",
|
||||
"org credit lines",
|
||||
"org_id",
|
||||
id,
|
||||
)?;
|
||||
let credit_lines = org_credit_lines_from_rows(credit_line_rows);
|
||||
|
||||
Ok(Some(record.into_org(id, credit_lines)))
|
||||
}
|
||||
|
||||
fn update(&self, org: &Org) -> Result<(), String> {
|
||||
let record = SurrealOrgRecord::from(org);
|
||||
surreal_upsert("org", org.id.as_str(), "org", &record)?;
|
||||
surreal_delete_by_field("org_credit_line", "org credit lines", "org_id", &org.id)?;
|
||||
|
||||
for (uid, credit_line) in &org.credit_lines {
|
||||
let resolved_uid = if credit_line.uid.trim().is_empty() {
|
||||
uid.clone()
|
||||
} else {
|
||||
credit_line.uid.clone()
|
||||
};
|
||||
let mut normalized = credit_line.clone();
|
||||
normalized.uid = resolved_uid.clone();
|
||||
normalized.normalize();
|
||||
let row = OrgCreditLineRow {
|
||||
org_id: org.id.clone(),
|
||||
uid: resolved_uid.clone(),
|
||||
name: normalized.name,
|
||||
approved_amount: normalized.approved_amount,
|
||||
available_amount: normalized.available_amount,
|
||||
outstanding_principal: normalized.outstanding_principal,
|
||||
interest_rate: normalized.interest_rate,
|
||||
amount_due: normalized.amount_due,
|
||||
amount: normalized.amount,
|
||||
};
|
||||
surreal_upsert(
|
||||
"org_credit_line",
|
||||
&org_credit_line_id(&org.id, &resolved_uid),
|
||||
"org credit line",
|
||||
&row,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete(&self, id: &str) -> Result<(), String> {
|
||||
surreal_delete::<SurrealOrgRecord>("org", id, "org")?;
|
||||
surreal_delete_by_field("org_member", "org members", "org_id", id)?;
|
||||
surreal_delete_by_field("org_credit_line", "org credit lines", "org_id", id)?;
|
||||
surreal_delete_by_field("org_asset", "org assets", "org_id", id)?;
|
||||
surreal_delete_by_field("org_fleet_vehicle", "org fleet", "org_id", id)
|
||||
}
|
||||
|
||||
fn exists(&self, id: &str) -> Result<bool, String> {
|
||||
self.get_by_id(id).map(|org| org.is_some())
|
||||
}
|
||||
|
||||
fn add_member(&self, org_id: &str, member_uid: &str) -> Result<(), String> {
|
||||
if !self.exists(org_id)? {
|
||||
return Err(format!("Organization {} does not exist", org_id));
|
||||
}
|
||||
|
||||
let mut member_uids = org_member_uids(org_id)?;
|
||||
if !member_uids.iter().any(|uid| uid == member_uid) {
|
||||
member_uids.push(member_uid.to_string());
|
||||
}
|
||||
surreal_delete_by_field("org_member", "org members", "org_id", org_id)?;
|
||||
for uid in member_uids {
|
||||
upsert_org_member(org_id, &uid)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_members(&self, org_id: &str) -> Result<Vec<MemberSummary>, String> {
|
||||
let member_uids = org_member_uids(org_id)?;
|
||||
let mut members = Vec::with_capacity(member_uids.len());
|
||||
let actor_repository = SurrealActorRepository;
|
||||
|
||||
for uid in member_uids {
|
||||
if uid.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = match actor_repository.get_by_id(&uid)? {
|
||||
Some(actor) => actor
|
||||
.name
|
||||
.filter(|name| !name.trim().is_empty())
|
||||
.unwrap_or_else(|| "Unknown".to_string()),
|
||||
None => "Unknown".to_string(),
|
||||
};
|
||||
|
||||
members.push(MemberSummary { uid, name });
|
||||
}
|
||||
|
||||
Ok(members)
|
||||
}
|
||||
|
||||
fn remove_member(&self, org_id: &str, member_uid: &str) -> Result<(), String> {
|
||||
let mut member_uids = org_member_uids(org_id)?;
|
||||
member_uids.retain(|uid| uid != member_uid);
|
||||
surreal_delete_by_field("org_member", "org members", "org_id", org_id)?;
|
||||
for uid in member_uids {
|
||||
upsert_org_member(org_id, &uid)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_assets(
|
||||
&self,
|
||||
org_id: &str,
|
||||
) -> Result<HashMap<String, HashMap<String, OrgAssetEntry>>, String> {
|
||||
let rows =
|
||||
surreal_select_by_field::<OrgAssetRow>("org_asset", "org assets", "org_id", org_id)?;
|
||||
Ok(org_assets_from_rows(rows))
|
||||
}
|
||||
|
||||
fn update_assets(
|
||||
&self,
|
||||
org_id: &str,
|
||||
assets: &HashMap<String, HashMap<String, OrgAssetEntry>>,
|
||||
) -> Result<(), String> {
|
||||
surreal_delete_by_field("org_asset", "org assets", "org_id", org_id)?;
|
||||
|
||||
for (category, category_assets) in assets {
|
||||
for (classname, asset) in category_assets {
|
||||
let row = OrgAssetRow {
|
||||
org_id: org_id.to_string(),
|
||||
category: category.clone(),
|
||||
classname: if asset.classname.trim().is_empty() {
|
||||
classname.clone()
|
||||
} else {
|
||||
asset.classname.clone()
|
||||
},
|
||||
asset_type: asset.asset_type.clone(),
|
||||
quantity: asset.quantity,
|
||||
};
|
||||
surreal_upsert(
|
||||
"org_asset",
|
||||
&org_asset_id(org_id, category, &row.classname),
|
||||
"org asset",
|
||||
&row,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_fleet(&self, org_id: &str) -> Result<HashMap<String, OrgFleetEntry>, String> {
|
||||
let rows = surreal_select_by_field::<OrgFleetRow>(
|
||||
"org_fleet_vehicle",
|
||||
"org fleet",
|
||||
"org_id",
|
||||
org_id,
|
||||
)?;
|
||||
if !rows.is_empty() {
|
||||
return Ok(org_fleet_from_rows(rows));
|
||||
}
|
||||
Ok(HashMap::new())
|
||||
}
|
||||
|
||||
fn update_fleet(
|
||||
&self,
|
||||
org_id: &str,
|
||||
fleet: &HashMap<String, OrgFleetEntry>,
|
||||
) -> Result<(), String> {
|
||||
surreal_delete_by_field("org_fleet_vehicle", "org fleet", "org_id", org_id)?;
|
||||
|
||||
for (fleet_key, entry) in fleet {
|
||||
let row = OrgFleetRow {
|
||||
org_id: org_id.to_string(),
|
||||
fleet_key: fleet_key.clone(),
|
||||
classname: entry.classname.clone(),
|
||||
name: entry.name.clone(),
|
||||
fleet_type: entry.fleet_type.clone(),
|
||||
status: entry.status.clone(),
|
||||
damage: entry.damage.clone(),
|
||||
};
|
||||
surreal_upsert(
|
||||
"org_fleet_vehicle",
|
||||
&org_fleet_id(org_id, fleet_key),
|
||||
"org fleet",
|
||||
&row,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
536
arma/server/extension/src/storage/phone.rs
Normal file
536
arma/server/extension/src/storage/phone.rs
Normal file
@ -0,0 +1,536 @@
|
||||
use super::common::*;
|
||||
use super::*;
|
||||
|
||||
pub enum PhoneStorageRepository {
|
||||
Redis(RedisPhoneRepository<ExtensionRedisClient>),
|
||||
Surreal(SurrealPhoneRepository),
|
||||
}
|
||||
|
||||
impl PhoneStorageRepository {
|
||||
pub fn configured() -> Self {
|
||||
match load().storage.backend {
|
||||
StorageBackend::Surreal => Self::Surreal(SurrealPhoneRepository),
|
||||
StorageBackend::Redis => {
|
||||
Self::Redis(RedisPhoneRepository::new(ExtensionRedisClient::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PhoneRepository for PhoneStorageRepository {
|
||||
fn init(&self, uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.init(uid),
|
||||
Self::Surreal(repository) => repository.init(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.add_contact(uid, contact_uid),
|
||||
Self::Surreal(repository) => repository.add_contact(uid, contact_uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.remove_contact(uid, contact_uid),
|
||||
Self::Surreal(repository) => repository.remove_contact(uid, contact_uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn list_contacts(&self, uid: &str) -> Result<Vec<String>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.list_contacts(uid),
|
||||
Self::Surreal(repository) => repository.list_contacts(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_phone(&self, uid: &str) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.remove_phone(uid),
|
||||
Self::Surreal(repository) => repository.remove_phone(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn append_message(&self, uid: &str, message: PhoneMessage) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.append_message(uid, message),
|
||||
Self::Surreal(repository) => repository.append_message(uid, message),
|
||||
}
|
||||
}
|
||||
|
||||
fn list_messages(&self, uid: &str) -> Result<Vec<PhoneMessage>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.list_messages(uid),
|
||||
Self::Surreal(repository) => repository.list_messages(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_message_read(&self, uid: &str, message_id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.mark_message_read(uid, message_id),
|
||||
Self::Surreal(repository) => repository.mark_message_read(uid, message_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_message(&self, uid: &str, message_id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete_message(uid, message_id),
|
||||
Self::Surreal(repository) => repository.delete_message(uid, message_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn append_email(&self, uid: &str, email: PhoneEmail) -> Result<(), String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.append_email(uid, email),
|
||||
Self::Surreal(repository) => repository.append_email(uid, email),
|
||||
}
|
||||
}
|
||||
|
||||
fn list_emails(&self, uid: &str) -> Result<Vec<PhoneEmail>, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.list_emails(uid),
|
||||
Self::Surreal(repository) => repository.list_emails(uid),
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_email_read(&self, uid: &str, email_id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.mark_email_read(uid, email_id),
|
||||
Self::Surreal(repository) => repository.mark_email_read(uid, email_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_email(&self, uid: &str, email_id: &str) -> Result<bool, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.delete_email(uid, email_id),
|
||||
Self::Surreal(repository) => repository.delete_email(uid, email_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_sequence(&self) -> Result<u64, String> {
|
||||
match self {
|
||||
Self::Redis(repository) => repository.next_sequence(),
|
||||
Self::Surreal(repository) => repository.next_sequence(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PhoneUserRecord {
|
||||
uid: String,
|
||||
}
|
||||
|
||||
impl PhoneUserRecord {
|
||||
fn new(uid: &str) -> Self {
|
||||
Self {
|
||||
uid: uid.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PhoneContactRecord {
|
||||
uid: String,
|
||||
contact_uid: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PhoneMessageIndexRecord {
|
||||
uid: String,
|
||||
message_id: String,
|
||||
is_read: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PhoneEmailIndexRecord {
|
||||
uid: String,
|
||||
email_id: String,
|
||||
is_read: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PhoneMessageRecord {
|
||||
message_id: String,
|
||||
from_uid: String,
|
||||
to_uid: String,
|
||||
message: String,
|
||||
timestamp: f64,
|
||||
}
|
||||
|
||||
impl PhoneMessageRecord {
|
||||
fn into_message(self, read: bool) -> PhoneMessage {
|
||||
PhoneMessage {
|
||||
id: self.message_id,
|
||||
from: self.from_uid,
|
||||
to: self.to_uid,
|
||||
message: self.message,
|
||||
timestamp: self.timestamp,
|
||||
read,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PhoneMessage> for PhoneMessageRecord {
|
||||
fn from(message: &PhoneMessage) -> Self {
|
||||
Self {
|
||||
message_id: message.id.clone(),
|
||||
from_uid: message.from.clone(),
|
||||
to_uid: message.to.clone(),
|
||||
message: message.message.clone(),
|
||||
timestamp: message.timestamp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PhoneEmailRecord {
|
||||
email_id: String,
|
||||
from_uid: String,
|
||||
to_uid: String,
|
||||
subject: String,
|
||||
body: String,
|
||||
timestamp: f64,
|
||||
}
|
||||
|
||||
impl PhoneEmailRecord {
|
||||
fn into_email(self, read: bool) -> PhoneEmail {
|
||||
PhoneEmail {
|
||||
id: self.email_id,
|
||||
from: self.from_uid,
|
||||
to: self.to_uid,
|
||||
subject: self.subject,
|
||||
body: self.body,
|
||||
timestamp: self.timestamp,
|
||||
read,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PhoneEmail> for PhoneEmailRecord {
|
||||
fn from(email: &PhoneEmail) -> Self {
|
||||
Self {
|
||||
email_id: email.id.clone(),
|
||||
from_uid: email.from.clone(),
|
||||
to_uid: email.to.clone(),
|
||||
subject: email.subject.clone(),
|
||||
body: email.body.clone(),
|
||||
timestamp: email.timestamp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
struct PhoneSequenceRecord {
|
||||
#[serde(default)]
|
||||
sequence_id: String,
|
||||
#[serde(default)]
|
||||
value: u64,
|
||||
}
|
||||
|
||||
pub struct SurrealPhoneRepository;
|
||||
|
||||
impl SurrealPhoneRepository {
|
||||
fn save_user(&self, uid: &str) -> Result<(), String> {
|
||||
let record = PhoneUserRecord::new(uid);
|
||||
surreal_upsert("phone_user", uid, "phone user", &record)
|
||||
}
|
||||
|
||||
fn message_is_referenced(&self, message_id: &str) -> Result<bool, String> {
|
||||
Ok(!surreal_select_by_field::<PhoneMessageIndexRecord>(
|
||||
"phone_message_index",
|
||||
"phone message indexes",
|
||||
"message_id",
|
||||
message_id,
|
||||
)?
|
||||
.is_empty())
|
||||
}
|
||||
|
||||
fn email_is_referenced(&self, email_id: &str) -> Result<bool, String> {
|
||||
Ok(!surreal_select_by_field::<PhoneEmailIndexRecord>(
|
||||
"phone_email_index",
|
||||
"phone email indexes",
|
||||
"email_id",
|
||||
email_id,
|
||||
)?
|
||||
.is_empty())
|
||||
}
|
||||
|
||||
fn cleanup_orphaned_records(&self) -> Result<(), String> {
|
||||
let referenced_messages = surreal_select_all::<PhoneMessageIndexRecord>(
|
||||
"phone_message_index",
|
||||
"phone message indexes",
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|record| record.message_id)
|
||||
.collect::<HashSet<_>>();
|
||||
let referenced_emails = surreal_select_all::<PhoneEmailIndexRecord>(
|
||||
"phone_email_index",
|
||||
"phone email indexes",
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|record| record.email_id)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
for record in surreal_select_all::<PhoneMessageRecord>("phone_message", "phone messages")? {
|
||||
let message_id = record.message_id.trim();
|
||||
if !message_id.is_empty() && !referenced_messages.contains(message_id) {
|
||||
surreal_delete::<PhoneMessageRecord>("phone_message", message_id, "phone message")?;
|
||||
}
|
||||
}
|
||||
|
||||
for record in surreal_select_all::<PhoneEmailRecord>("phone_email", "phone emails")? {
|
||||
let email_id = record.email_id.trim();
|
||||
if !email_id.is_empty() && !referenced_emails.contains(email_id) {
|
||||
surreal_delete::<PhoneEmailRecord>("phone_email", email_id, "phone email")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn contact_id(uid: &str, contact_uid: &str) -> String {
|
||||
format!("{}:{}", uid, contact_uid)
|
||||
}
|
||||
|
||||
fn message_index_id(uid: &str, message_id: &str) -> String {
|
||||
format!("{}:{}", uid, message_id)
|
||||
}
|
||||
|
||||
fn email_index_id(uid: &str, email_id: &str) -> String {
|
||||
format!("{}:{}", uid, email_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl PhoneRepository for SurrealPhoneRepository {
|
||||
fn init(&self, uid: &str) -> Result<(), String> {
|
||||
if surreal_select::<PhoneUserRecord>("phone_user", uid, "phone user")?.is_none() {
|
||||
self.save_user(uid)?;
|
||||
}
|
||||
self.cleanup_orphaned_records()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String> {
|
||||
self.save_user(uid)?;
|
||||
let record = PhoneContactRecord {
|
||||
uid: uid.to_string(),
|
||||
contact_uid: contact_uid.to_string(),
|
||||
};
|
||||
surreal_upsert(
|
||||
"phone_contact",
|
||||
&Self::contact_id(uid, contact_uid),
|
||||
"phone contact",
|
||||
&record,
|
||||
)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn remove_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String> {
|
||||
let id = Self::contact_id(uid, contact_uid);
|
||||
let exists =
|
||||
surreal_select::<PhoneContactRecord>("phone_contact", &id, "phone contact")?.is_some();
|
||||
if !exists {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
surreal_delete::<PhoneContactRecord>("phone_contact", &id, "phone contact")?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn list_contacts(&self, uid: &str) -> Result<Vec<String>, String> {
|
||||
let mut contacts =
|
||||
surreal_select_by_uid::<PhoneContactRecord>("phone_contact", "phone contacts", uid)?
|
||||
.into_iter()
|
||||
.map(|record| record.contact_uid)
|
||||
.collect::<Vec<_>>();
|
||||
contacts.sort();
|
||||
contacts.dedup();
|
||||
Ok(contacts)
|
||||
}
|
||||
|
||||
fn remove_phone(&self, uid: &str) -> Result<(), String> {
|
||||
surreal_delete_by_uid("phone_contact", "phone contacts", uid)?;
|
||||
surreal_delete_by_uid("phone_message_index", "phone message indexes", uid)?;
|
||||
surreal_delete_by_uid("phone_email_index", "phone email indexes", uid)?;
|
||||
surreal_delete::<PhoneUserRecord>("phone_user", uid, "phone user")?;
|
||||
self.cleanup_orphaned_records()
|
||||
}
|
||||
|
||||
fn append_message(&self, uid: &str, message: PhoneMessage) -> Result<(), String> {
|
||||
self.save_user(uid)?;
|
||||
|
||||
let record = PhoneMessageRecord::from(&message);
|
||||
surreal_upsert("phone_message", &message.id, "phone message", &record)?;
|
||||
let index = PhoneMessageIndexRecord {
|
||||
uid: uid.to_string(),
|
||||
message_id: message.id.clone(),
|
||||
is_read: message.from == uid,
|
||||
};
|
||||
surreal_upsert(
|
||||
"phone_message_index",
|
||||
&Self::message_index_id(uid, &message.id),
|
||||
"phone message index",
|
||||
&index,
|
||||
)
|
||||
}
|
||||
|
||||
fn list_messages(&self, uid: &str) -> Result<Vec<PhoneMessage>, String> {
|
||||
let indexes = surreal_select_by_uid::<PhoneMessageIndexRecord>(
|
||||
"phone_message_index",
|
||||
"phone message indexes",
|
||||
uid,
|
||||
)?;
|
||||
let mut messages = Vec::with_capacity(indexes.len());
|
||||
|
||||
for index in indexes {
|
||||
if index.message_id.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(record) = surreal_select::<PhoneMessageRecord>(
|
||||
"phone_message",
|
||||
&index.message_id,
|
||||
"phone message",
|
||||
)? {
|
||||
messages.push(record.into_message(index.is_read));
|
||||
}
|
||||
}
|
||||
|
||||
messages.sort_by(|left, right| {
|
||||
left.timestamp
|
||||
.partial_cmp(&right.timestamp)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
fn mark_message_read(&self, uid: &str, message_id: &str) -> Result<bool, String> {
|
||||
let id = Self::message_index_id(uid, message_id);
|
||||
let Some(mut index) = surreal_select::<PhoneMessageIndexRecord>(
|
||||
"phone_message_index",
|
||||
&id,
|
||||
"phone message index",
|
||||
)?
|
||||
else {
|
||||
return Ok(false);
|
||||
};
|
||||
|
||||
index.is_read = true;
|
||||
surreal_upsert("phone_message_index", &id, "phone message index", &index)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn delete_message(&self, uid: &str, message_id: &str) -> Result<bool, String> {
|
||||
let id = Self::message_index_id(uid, message_id);
|
||||
let exists = surreal_select::<PhoneMessageIndexRecord>(
|
||||
"phone_message_index",
|
||||
&id,
|
||||
"phone message index",
|
||||
)?
|
||||
.is_some();
|
||||
if !exists {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
surreal_delete::<PhoneMessageIndexRecord>(
|
||||
"phone_message_index",
|
||||
&id,
|
||||
"phone message index",
|
||||
)?;
|
||||
if !self.message_is_referenced(message_id)? {
|
||||
surreal_delete::<PhoneMessageRecord>("phone_message", message_id, "phone message")?;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn append_email(&self, uid: &str, email: PhoneEmail) -> Result<(), String> {
|
||||
self.save_user(uid)?;
|
||||
|
||||
let record = PhoneEmailRecord::from(&email);
|
||||
surreal_upsert("phone_email", &email.id, "phone email", &record)?;
|
||||
let index = PhoneEmailIndexRecord {
|
||||
uid: uid.to_string(),
|
||||
email_id: email.id.clone(),
|
||||
is_read: false,
|
||||
};
|
||||
surreal_upsert(
|
||||
"phone_email_index",
|
||||
&Self::email_index_id(uid, &email.id),
|
||||
"phone email index",
|
||||
&index,
|
||||
)
|
||||
}
|
||||
|
||||
fn list_emails(&self, uid: &str) -> Result<Vec<PhoneEmail>, String> {
|
||||
let indexes = surreal_select_by_uid::<PhoneEmailIndexRecord>(
|
||||
"phone_email_index",
|
||||
"phone email indexes",
|
||||
uid,
|
||||
)?;
|
||||
let mut emails = Vec::with_capacity(indexes.len());
|
||||
|
||||
for index in indexes {
|
||||
if index.email_id.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(record) =
|
||||
surreal_select::<PhoneEmailRecord>("phone_email", &index.email_id, "phone email")?
|
||||
{
|
||||
emails.push(record.into_email(index.is_read));
|
||||
}
|
||||
}
|
||||
|
||||
emails.sort_by(|left, right| {
|
||||
right
|
||||
.timestamp
|
||||
.partial_cmp(&left.timestamp)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
Ok(emails)
|
||||
}
|
||||
|
||||
fn mark_email_read(&self, uid: &str, email_id: &str) -> Result<bool, String> {
|
||||
let id = Self::email_index_id(uid, email_id);
|
||||
let Some(mut index) =
|
||||
surreal_select::<PhoneEmailIndexRecord>("phone_email_index", &id, "phone email index")?
|
||||
else {
|
||||
return Ok(false);
|
||||
};
|
||||
|
||||
index.is_read = true;
|
||||
surreal_upsert("phone_email_index", &id, "phone email index", &index)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn delete_email(&self, uid: &str, email_id: &str) -> Result<bool, String> {
|
||||
let id = Self::email_index_id(uid, email_id);
|
||||
let exists =
|
||||
surreal_select::<PhoneEmailIndexRecord>("phone_email_index", &id, "phone email index")?
|
||||
.is_some();
|
||||
if !exists {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
surreal_delete::<PhoneEmailIndexRecord>("phone_email_index", &id, "phone email index")?;
|
||||
if !self.email_is_referenced(email_id)? {
|
||||
surreal_delete::<PhoneEmailRecord>("phone_email", email_id, "phone email")?;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn next_sequence(&self) -> Result<u64, String> {
|
||||
let mut record =
|
||||
surreal_select::<PhoneSequenceRecord>("phone_sequence", "global", "phone sequence")?
|
||||
.unwrap_or_default();
|
||||
record.sequence_id = "global".to_string();
|
||||
record.value = record
|
||||
.value
|
||||
.checked_add(1)
|
||||
.ok_or_else(|| "Phone sequence overflowed.".to_string())?;
|
||||
surreal_upsert("phone_sequence", "global", "phone sequence", &record)?;
|
||||
Ok(record.value)
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ use tokio::time::{Duration, sleep, timeout};
|
||||
|
||||
use crate::log;
|
||||
use crate::redis::config::SurrealConfig;
|
||||
use crate::schema;
|
||||
|
||||
pub type SurrealDb = Surreal<Client>;
|
||||
|
||||
@ -120,6 +121,8 @@ async fn connect(config: SurrealConfig) -> Result<SurrealDb, String> {
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
|
||||
schema::apply_all(&db).await?;
|
||||
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
|
||||
@ -10,11 +10,12 @@ use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::{LazyLock, Mutex as StdMutex};
|
||||
|
||||
use crate::{actor, bank, cad, garage, locker, org, phone, v_garage, v_locker};
|
||||
mod routes;
|
||||
|
||||
use routes::route_command;
|
||||
|
||||
const CHUNK_PREFIX: &str = "FORGE_TRANSPORT_CHUNK:";
|
||||
const RESPONSE_CHUNK_SIZE: usize = 12_000;
|
||||
const UNSUPPORTED_ROUTE_PREFIX: &str = "Unsupported transport route";
|
||||
|
||||
static REQUEST_STORE: LazyLock<StdMutex<HashMap<String, String>>> =
|
||||
LazyLock::new(|| StdMutex::new(HashMap::new()));
|
||||
@ -143,903 +144,6 @@ fn parse_transport_argument_value(value: serde_json::Value) -> Result<Vec<String
|
||||
}
|
||||
}
|
||||
|
||||
fn route_command(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
match function_name {
|
||||
"actor:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::get_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:create" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(actor::create_actor(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"actor:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(actor::update_actor(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"actor:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::actor_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::delete_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::init_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::get_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:keys" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(actor::list_hot_actor_keys())
|
||||
}
|
||||
"actor:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(actor::override_hot_actor(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"actor:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::save_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::remove_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::get_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:create" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::create_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::update_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::bank_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::delete_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::init_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::get_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::override_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:patch" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::patch_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:charge_checkout" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::charge_checkout_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:deposit" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::deposit_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:withdraw" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::withdraw_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:deposit_earnings" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::deposit_earnings_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:transfer" => {
|
||||
expect_arg_count(function_name, &arguments, 4)?;
|
||||
Ok(bank::transfer_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
arguments[3].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:validate_pin" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::validate_pin_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::save_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::remove_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"org:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_org(arguments[0].clone()))
|
||||
}
|
||||
"org:create" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::create_org(arguments[0].clone(), arguments[1].clone()))
|
||||
}
|
||||
"org:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::update_org(arguments[0].clone(), arguments[1].clone()))
|
||||
}
|
||||
"org:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::org_exists(arguments[0].clone()))
|
||||
}
|
||||
"org:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::delete_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::init_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::override_hot_org(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:hot:ensure_member" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::ensure_hot_org_member(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:member_invites" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_hot_org_member_invites(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:register" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::register_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:invite_member" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::invite_hot_org_member(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:accept_invite" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::accept_hot_org_invite(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:decline_invite" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::decline_hot_org_invite(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:assign_credit_line" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::assign_credit_line_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:repay_credit_line" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::repay_credit_line_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:charge_checkout" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::charge_checkout_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:add_assets" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::add_assets_hot_org(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:hot:add_fleet" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::add_fleet_hot_org(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:hot:leave" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::leave_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:disband" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::disband_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::save_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::remove_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:assets:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_assets(arguments[0].clone()))
|
||||
}
|
||||
"org:assets:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::update_assets(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:fleet:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_fleet(arguments[0].clone()))
|
||||
}
|
||||
"org:fleet:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::update_fleet(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:members:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_members(arguments[0].clone()))
|
||||
}
|
||||
"org:members:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::add_member(arguments[0].clone(), arguments[1].clone()))
|
||||
}
|
||||
"org:members:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::remove_member(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"store:checkout" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(crate::store::checkout(arguments[0].clone()))
|
||||
}
|
||||
"garage:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::create_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::get_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::add_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::update_garage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:patch" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::patch_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::remove_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::delete_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::garage_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::init_hot_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::get_hot_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::override_hot_garage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::save_hot_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::remove_hot_garage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"garage:hot:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::add_hot_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:hot:remove_vehicle" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::remove_hot_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::create_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::get_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::add_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::update_locker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:patch" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::patch_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::remove_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::delete_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::locker_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::init_hot_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::get_hot_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::override_hot_locker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::save_hot_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::remove_hot_locker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::create_vgarage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::fetch_vgarage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_garage::get_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:add" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::add_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::remove_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::delete_vgarage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::vgarage_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::init_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::fetch_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_garage::get_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_garage::override_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::save_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::remove_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:add" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::add_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:remove_item" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::remove_hot_vgarage_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::create_vlocker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::fetch_vlocker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_locker::get_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:add" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_locker::add_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_locker::remove_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::delete_vlocker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::vlocker_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::init_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::fetch_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_locker::get_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_locker::override_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::save_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::remove_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"cad:activity:append" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::append_activity(arguments[0].clone()))
|
||||
}
|
||||
"cad:activity:recent" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::recent_activity(arguments[0].clone()))
|
||||
}
|
||||
"cad:assignments:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_assignments())
|
||||
}
|
||||
"cad:assignments:assign" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::assign_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:acknowledge" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::acknowledge_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:decline" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::decline_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_assignment(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_orders())
|
||||
}
|
||||
"cad:orders:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::create_order(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:create_from_context" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::create_order_from_context(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:close" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::close_order(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_order(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:orders:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_order(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_requests())
|
||||
}
|
||||
"cad:requests:submit" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::submit_request(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:submit_from_context" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::submit_request_from_context(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:close" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::close_request(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_request(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:requests:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_request(arguments[0].clone()))
|
||||
}
|
||||
"cad:profiles:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_profiles())
|
||||
}
|
||||
"cad:profiles:update_from_context" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::update_profile_from_context(arguments[0].clone()))
|
||||
}
|
||||
"cad:profiles:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_profile(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:profiles:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_profile(arguments[0].clone()))
|
||||
}
|
||||
"cad:groups:build" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::build_groups(arguments[0].clone()))
|
||||
}
|
||||
"cad:view:hydrate" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::hydrate_view(arguments[0].clone()))
|
||||
}
|
||||
"phone:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::init_phone(arguments[0].clone()))
|
||||
}
|
||||
"phone:contacts:list" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::list_contacts(arguments[0].clone()))
|
||||
}
|
||||
"phone:contacts:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::add_contact(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:contacts:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::remove_contact(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:list" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::list_messages(arguments[0].clone()))
|
||||
}
|
||||
"phone:messages:thread" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::message_thread(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:send" => {
|
||||
expect_arg_count(function_name, &arguments, 4)?;
|
||||
Ok(phone::send_message(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
arguments[3].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:mark_read" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::mark_message_read(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:emails:list" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::list_emails(arguments[0].clone()))
|
||||
}
|
||||
"phone:emails:send" => {
|
||||
expect_arg_count(function_name, &arguments, 5)?;
|
||||
Ok(phone::send_email(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
arguments[3].clone(),
|
||||
arguments[4].clone(),
|
||||
))
|
||||
}
|
||||
"phone:emails:mark_read" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::mark_email_read(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::remove_phone(arguments[0].clone()))
|
||||
}
|
||||
_ => Err(format!(
|
||||
"{UNSUPPORTED_ROUTE_PREFIX} for function '{function_name}'"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_arg_count(
|
||||
function_name: &str,
|
||||
arguments: &[String],
|
||||
expected_count: usize,
|
||||
) -> Result<(), String> {
|
||||
if arguments.len() == expected_count {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"Transport route '{}' expected {} arguments but received {}",
|
||||
function_name,
|
||||
expected_count,
|
||||
arguments.len()
|
||||
))
|
||||
}
|
||||
|
||||
fn chunk_response_if_needed(result: String) -> String {
|
||||
if result.len() <= RESPONSE_CHUNK_SIZE {
|
||||
return result;
|
||||
|
||||
74
arma/server/extension/src/transport/routes.rs
Normal file
74
arma/server/extension/src/transport/routes.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
mod actor;
|
||||
mod bank;
|
||||
mod cad;
|
||||
mod garage;
|
||||
mod locker;
|
||||
mod org;
|
||||
mod phone;
|
||||
mod store;
|
||||
mod v_garage;
|
||||
mod v_locker;
|
||||
|
||||
const UNSUPPORTED_ROUTE_PREFIX: &str = "Unsupported transport route";
|
||||
|
||||
pub(super) fn route_command(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
if function_name.starts_with("actor:") {
|
||||
return actor::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("bank:") {
|
||||
return bank::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("org:") {
|
||||
return org::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name == "store:checkout" {
|
||||
return store::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("garage:") {
|
||||
return garage::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("locker:") {
|
||||
return locker::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("owned:garage:") {
|
||||
return v_garage::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("owned:locker:") {
|
||||
return v_locker::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("cad:") {
|
||||
return cad::route(call_context, function_name, arguments);
|
||||
}
|
||||
if function_name.starts_with("phone:") {
|
||||
return phone::route(call_context, function_name, arguments);
|
||||
}
|
||||
|
||||
Err(unsupported_route(function_name))
|
||||
}
|
||||
|
||||
pub(super) fn expect_arg_count(
|
||||
function_name: &str,
|
||||
arguments: &[String],
|
||||
expected_count: usize,
|
||||
) -> Result<(), String> {
|
||||
if arguments.len() == expected_count {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"Transport route '{}' expected {} arguments but received {}",
|
||||
function_name,
|
||||
expected_count,
|
||||
arguments.len()
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn unsupported_route(function_name: &str) -> String {
|
||||
format!("{UNSUPPORTED_ROUTE_PREFIX} for function '{function_name}'")
|
||||
}
|
||||
72
arma/server/extension/src/transport/routes/actor.rs
Normal file
72
arma/server/extension/src/transport/routes/actor.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::actor;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"actor:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::get_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:create" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(actor::create_actor(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"actor:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(actor::update_actor(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"actor:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::actor_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::delete_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::init_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::get_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:keys" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(actor::list_hot_actor_keys())
|
||||
}
|
||||
"actor:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(actor::override_hot_actor(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"actor:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::save_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
"actor:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(actor::remove_hot_actor(call_context, arguments[0].clone()))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
131
arma/server/extension/src/transport/routes/bank.rs
Normal file
131
arma/server/extension/src/transport/routes/bank.rs
Normal file
@ -0,0 +1,131 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::bank;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"bank:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::get_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:create" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::create_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::update_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::bank_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::delete_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::init_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::get_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::override_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:patch" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(bank::patch_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:charge_checkout" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::charge_checkout_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:deposit" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::deposit_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:withdraw" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::withdraw_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:deposit_earnings" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::deposit_earnings_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:transfer" => {
|
||||
expect_arg_count(function_name, &arguments, 4)?;
|
||||
Ok(bank::transfer_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
arguments[3].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:validate_pin" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(bank::validate_pin_hot_bank(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"bank:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::save_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
"bank:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(bank::remove_hot_bank(call_context, arguments[0].clone()))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
141
arma/server/extension/src/transport/routes/cad.rs
Normal file
141
arma/server/extension/src/transport/routes/cad.rs
Normal file
@ -0,0 +1,141 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::cad;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"cad:activity:append" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::append_activity(arguments[0].clone()))
|
||||
}
|
||||
"cad:activity:recent" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::recent_activity(arguments[0].clone()))
|
||||
}
|
||||
"cad:assignments:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_assignments())
|
||||
}
|
||||
"cad:assignments:assign" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::assign_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:acknowledge" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::acknowledge_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:decline" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::decline_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_assignment(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:assignments:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_assignment(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_orders())
|
||||
}
|
||||
"cad:orders:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::create_order(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:create_from_context" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::create_order_from_context(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:close" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::close_order(arguments[0].clone()))
|
||||
}
|
||||
"cad:orders:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_order(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:orders:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_order(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_requests())
|
||||
}
|
||||
"cad:requests:submit" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::submit_request(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:submit_from_context" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::submit_request_from_context(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:close" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::close_request(arguments[0].clone()))
|
||||
}
|
||||
"cad:requests:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_request(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:requests:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_request(arguments[0].clone()))
|
||||
}
|
||||
"cad:profiles:list" => {
|
||||
expect_arg_count(function_name, &arguments, 0)?;
|
||||
Ok(cad::list_profiles())
|
||||
}
|
||||
"cad:profiles:update_from_context" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::update_profile_from_context(arguments[0].clone()))
|
||||
}
|
||||
"cad:profiles:upsert" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(cad::upsert_profile(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"cad:profiles:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::delete_profile(arguments[0].clone()))
|
||||
}
|
||||
"cad:groups:build" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::build_groups(arguments[0].clone()))
|
||||
}
|
||||
"cad:view:hydrate" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(cad::hydrate_view(arguments[0].clone()))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
107
arma/server/extension/src/transport/routes/garage.rs
Normal file
107
arma/server/extension/src/transport/routes/garage.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::garage;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"garage:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::create_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::get_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::add_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::update_garage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:patch" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::patch_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::remove_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::delete_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::garage_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::init_hot_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::get_hot_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::override_hot_garage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::save_hot_garage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"garage:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(garage::remove_hot_garage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"garage:hot:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::add_hot_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"garage:hot:remove_vehicle" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(garage::remove_hot_vehicle(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
91
arma/server/extension/src/transport/routes/locker.rs
Normal file
91
arma/server/extension/src/transport/routes/locker.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::locker;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"locker:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::create_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::get_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::add_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::update_locker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:patch" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::patch_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::remove_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::delete_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::locker_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::init_hot_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::get_hot_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(locker::override_hot_locker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"locker:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::save_hot_locker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"locker:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(locker::remove_hot_locker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
154
arma/server/extension/src/transport/routes/org.rs
Normal file
154
arma/server/extension/src/transport/routes/org.rs
Normal file
@ -0,0 +1,154 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::org;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"org:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_org(arguments[0].clone()))
|
||||
}
|
||||
"org:create" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::create_org(arguments[0].clone(), arguments[1].clone()))
|
||||
}
|
||||
"org:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::update_org(arguments[0].clone(), arguments[1].clone()))
|
||||
}
|
||||
"org:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::org_exists(arguments[0].clone()))
|
||||
}
|
||||
"org:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::delete_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::init_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::override_hot_org(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:hot:ensure_member" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::ensure_hot_org_member(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:member_invites" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_hot_org_member_invites(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:register" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::register_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:invite_member" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::invite_hot_org_member(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:accept_invite" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::accept_hot_org_invite(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:decline_invite" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::decline_hot_org_invite(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:assign_credit_line" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::assign_credit_line_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:repay_credit_line" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::repay_credit_line_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:charge_checkout" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::charge_checkout_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:add_assets" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::add_assets_hot_org(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:hot:add_fleet" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::add_fleet_hot_org(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:hot:leave" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::leave_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:disband" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::disband_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::save_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::remove_hot_org(arguments[0].clone()))
|
||||
}
|
||||
"org:assets:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_assets(arguments[0].clone()))
|
||||
}
|
||||
"org:assets:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::update_assets(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:fleet:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_fleet(arguments[0].clone()))
|
||||
}
|
||||
"org:fleet:update" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::update_fleet(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"org:members:get" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(org::get_members(arguments[0].clone()))
|
||||
}
|
||||
"org:members:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::add_member(arguments[0].clone(), arguments[1].clone()))
|
||||
}
|
||||
"org:members:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(org::remove_member(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
104
arma/server/extension/src/transport/routes/phone.rs
Normal file
104
arma/server/extension/src/transport/routes/phone.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::phone;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"phone:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::init_phone(arguments[0].clone()))
|
||||
}
|
||||
"phone:contacts:list" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::list_contacts(arguments[0].clone()))
|
||||
}
|
||||
"phone:contacts:add" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::add_contact(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:contacts:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::remove_contact(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:list" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::list_messages(arguments[0].clone()))
|
||||
}
|
||||
"phone:messages:thread" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::message_thread(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:send" => {
|
||||
expect_arg_count(function_name, &arguments, 4)?;
|
||||
Ok(phone::send_message(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
arguments[3].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:mark_read" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::mark_message_read(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:messages:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::delete_message(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:emails:list" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::list_emails(arguments[0].clone()))
|
||||
}
|
||||
"phone:emails:send" => {
|
||||
expect_arg_count(function_name, &arguments, 5)?;
|
||||
Ok(phone::send_email(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
arguments[3].clone(),
|
||||
arguments[4].clone(),
|
||||
))
|
||||
}
|
||||
"phone:emails:mark_read" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::mark_email_read(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:emails:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(phone::delete_email(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"phone:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(phone::remove_phone(arguments[0].clone()))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
18
arma/server/extension/src/transport/routes/store.rs
Normal file
18
arma/server/extension/src/transport/routes/store.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"store:checkout" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(crate::store::checkout(arguments[0].clone()))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
120
arma/server/extension/src/transport/routes/v_garage.rs
Normal file
120
arma/server/extension/src/transport/routes/v_garage.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::v_garage;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"owned:garage:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::create_vgarage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::fetch_vgarage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_garage::get_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:add" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::add_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::remove_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::delete_vgarage(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::vgarage_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:garage:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::init_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::fetch_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_garage::get_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_garage::override_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::save_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_garage::remove_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:add" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::add_hot_vgarage(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:garage:hot:remove_item" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_garage::remove_hot_vgarage_item(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
102
arma/server/extension/src/transport/routes/v_locker.rs
Normal file
102
arma/server/extension/src/transport/routes/v_locker.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use arma_rs::CallContext;
|
||||
|
||||
use super::expect_arg_count;
|
||||
use crate::v_locker;
|
||||
|
||||
pub(super) fn route(
|
||||
call_context: CallContext,
|
||||
function_name: &str,
|
||||
arguments: Vec<String>,
|
||||
) -> Result<String, String> {
|
||||
let _ = &call_context;
|
||||
|
||||
match function_name {
|
||||
"owned:locker:create" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::create_vlocker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::fetch_vlocker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_locker::get_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:add" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_locker::add_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 3)?;
|
||||
Ok(v_locker::remove_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
arguments[2].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:delete" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::delete_vlocker(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:exists" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::vlocker_exists(call_context, arguments[0].clone()))
|
||||
}
|
||||
"owned:locker:hot:init" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::init_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:fetch" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::fetch_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:get" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_locker::get_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:override" => {
|
||||
expect_arg_count(function_name, &arguments, 2)?;
|
||||
Ok(v_locker::override_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:save" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::save_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
"owned:locker:hot:remove" => {
|
||||
expect_arg_count(function_name, &arguments, 1)?;
|
||||
Ok(v_locker::remove_hot_vlocker(
|
||||
call_context,
|
||||
arguments[0].clone(),
|
||||
))
|
||||
}
|
||||
_ => Err(super::unsupported_route(function_name)),
|
||||
}
|
||||
}
|
||||
101
history.txt
Normal file
101
history.txt
Normal file
@ -0,0 +1,101 @@
|
||||
#V2
|
||||
DEFINE FIELD OVERWRITE updated_at ON org_fleet_vehicle TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS org_fleet_vehicle_org ON org_fleet_vehicle COLUMNS org_id;
|
||||
DEFINE INDEX IF NOT EXISTS org_fleet_vehicle_unique ON org_fleet_vehicle COLUMNS org_id, fleet_key UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS locker SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON locker TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON locker TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS locker_uid ON locker COLUMNS uid UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS locker_item SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON locker_item TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON locker_item TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON locker_item TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS amount ON locker_item TYPE int;
|
||||
DEFINE FIELD OVERWRITE updated_at ON locker_item TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS locker_item_owner ON locker_item COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS locker_item_unique ON locker_item COLUMNS uid, classname UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS owned_locker SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON owned_locker TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON owned_locker TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS owned_locker_uid ON owned_locker COLUMNS uid UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS locker_unlock SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON locker_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON locker_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON locker_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS source ON locker_unlock TYPE option<string>;
|
||||
DEFINE FIELD OVERWRITE unlocked_at ON locker_unlock TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS locker_unlock_owner ON locker_unlock COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS locker_unlock_unique ON locker_unlock COLUMNS uid, category, classname UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS garage SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON garage TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON garage TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS garage_uid ON garage COLUMNS uid UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS garage_vehicle SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON garage_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS plate ON garage_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON garage_vehicle TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS fuel ON garage_vehicle TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS damage ON garage_vehicle TYPE number;
|
||||
DEFINE FIELD IF NOT EXISTS hit_points ON garage_vehicle TYPE object;
|
||||
DEFINE FIELD OVERWRITE updated_at ON garage_vehicle TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS garage_vehicle_owner ON garage_vehicle COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS garage_vehicle_unique ON garage_vehicle COLUMNS uid, plate UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS owned_garage SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON owned_garage TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON owned_garage TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS owned_garage_uid ON owned_garage COLUMNS uid UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS garage_unlock SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON garage_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS category ON garage_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS classname ON garage_unlock TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS source ON garage_unlock TYPE option<string>;
|
||||
DEFINE FIELD OVERWRITE unlocked_at ON garage_unlock TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS garage_unlock_owner ON garage_unlock COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS garage_unlock_unique ON garage_unlock COLUMNS uid, category, classname UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_user SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_user TYPE string;
|
||||
DEFINE FIELD OVERWRITE updated_at ON phone_user TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_user_uid ON phone_user COLUMNS uid UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_contact SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_contact TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS contact_uid ON phone_contact TYPE string;
|
||||
DEFINE FIELD OVERWRITE created_at ON phone_contact TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_contact_owner ON phone_contact COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS phone_contact_unique ON phone_contact COLUMNS uid, contact_uid UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_message SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS message_id ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS from_uid ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS to_uid ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS message ON phone_message TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS timestamp ON phone_message TYPE number;
|
||||
DEFINE FIELD OVERWRITE created_at ON phone_message TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_message_id ON phone_message COLUMNS message_id UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_message_index SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_message_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS message_id ON phone_message_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS is_read ON phone_message_index TYPE bool;
|
||||
DEFINE FIELD OVERWRITE updated_at ON phone_message_index TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_index_owner ON phone_message_index COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_index_message ON phone_message_index COLUMNS message_id;
|
||||
DEFINE INDEX IF NOT EXISTS phone_message_index_unique ON phone_message_index COLUMNS uid, message_id UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_email SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS email_id ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS from_uid ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS to_uid ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS subject ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS body ON phone_email TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS timestamp ON phone_email TYPE number;
|
||||
DEFINE FIELD OVERWRITE created_at ON phone_email TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_email_id ON phone_email COLUMNS email_id UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_email_index SCHEMAFULL;
|
||||
DEFINE FIELD IF NOT EXISTS uid ON phone_email_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS email_id ON phone_email_index TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS is_read ON phone_email_index TYPE bool;
|
||||
DEFINE FIELD OVERWRITE updated_at ON phone_email_index TYPE option<datetime>;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_index_owner ON phone_email_index COLUMNS uid;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_index_email ON phone_email_index COLUMNS email_id;
|
||||
DEFINE INDEX IF NOT EXISTS phone_email_index_unique ON phone_email_index COLUMNS uid, email_id UNIQUE;
|
||||
DEFINE TABLE IF NOT EXISTS phone_sequence SCHEMALESS;
|
||||
DEFINE FIELD IF NOT EXISTS sequence_id ON phone_sequence TYPE string;
|
||||
DEFINE FIELD IF NOT EXISTS value ON phone_sequence TYPE int;
|
||||
DEFINE INDEX IF NOT EXISTS phone_sequence_id ON phone_sequence COLUMNS sequence_id UNIQUE;
|
||||
Loading…
x
Reference in New Issue
Block a user