Make cursor broadcast configurable
This commit is contained in:
parent
e37399dc29
commit
b60cb0104b
6 changed files with 107 additions and 45 deletions
66
backend/Cargo.lock
generated
66
backend/Cargo.lock
generated
|
|
@ -51,7 +51,7 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap 2.7.0",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -71,7 +71,7 @@ dependencies = [
|
||||||
"aide",
|
"aide",
|
||||||
"axum",
|
"axum",
|
||||||
"axum_typed_multipart",
|
"axum_typed_multipart",
|
||||||
"indexmap",
|
"indexmap 2.7.0",
|
||||||
"schemars",
|
"schemars",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -662,6 +662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -966,6 +967,12 @@ version = "0.31.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
|
|
@ -983,7 +990,7 @@ version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1298,6 +1305,17 @@ dependencies = [
|
||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
|
|
@ -1305,7 +1323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2068,7 +2086,7 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
"indexmap",
|
"indexmap 2.7.0",
|
||||||
"schemars_derive",
|
"schemars_derive",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -2177,13 +2195,43 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.7.0",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.9.34+deprecated"
|
version = "0.9.34+deprecated"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.7.0",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -2329,9 +2377,9 @@ dependencies = [
|
||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hashbrown",
|
"hashbrown 0.15.2",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"indexmap",
|
"indexmap 2.7.0",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -2581,6 +2629,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_with",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"sync_lib",
|
"sync_lib",
|
||||||
|
|
@ -2722,6 +2771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
|
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
|
"itoa",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,27 @@
|
||||||
database:
|
database:
|
||||||
databases_directory_path: databases
|
databases_directory_path: databases
|
||||||
max_connections_per_vault: 12
|
max_connections_per_vault: 12
|
||||||
|
cursor_timeout_seconds: 60
|
||||||
|
cursor_broadcast_interval_seconds: 1
|
||||||
server:
|
server:
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 3000
|
port: 3000
|
||||||
max_body_size_mb: 512
|
max_body_size_mb: 512
|
||||||
max_clients_per_vault: 256
|
max_clients_per_vault: 256
|
||||||
response_timeout_seconds: 60
|
response_timeout_seconds: 60
|
||||||
|
|
||||||
users:
|
users:
|
||||||
user_configs:
|
user_configs:
|
||||||
- name: admin
|
- name: admin
|
||||||
token: test-token-change-me
|
token: test-token-change-me
|
||||||
vault_access:
|
vault_access:
|
||||||
type: allow_access_to_all
|
type: allow_access_to_all
|
||||||
|
- name: other-admin
|
||||||
- name: other-admin
|
token: test-token-change-me2
|
||||||
token: test-token-change-me2
|
vault_access:
|
||||||
vault_access:
|
type: allow_access_to_all
|
||||||
type: allow_access_to_all
|
- name: test
|
||||||
|
token: other-test-token
|
||||||
- name: test
|
vault_access:
|
||||||
token: other-test-token
|
type: allow_list
|
||||||
vault_access:
|
allowed:
|
||||||
type: allow_list
|
- default
|
||||||
allowed:
|
|
||||||
- default
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ serde_json = "1.0.140"
|
||||||
clap-verbosity-flag = "3.0.3"
|
clap-verbosity-flag = "3.0.3"
|
||||||
bimap = "0.6.3"
|
bimap = "0.6.3"
|
||||||
ts-rs = { version = "10.1", features = ["uuid-impl", "chrono-impl"] }
|
ts-rs = { version = "10.1", features = ["uuid-impl", "chrono-impl"] }
|
||||||
|
serde_with = "3.12.0"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use chrono::TimeDelta;
|
|
||||||
use sqlx::types::chrono::Utc;
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|
@ -10,15 +8,13 @@ use super::{
|
||||||
websocket::{
|
websocket::{
|
||||||
broadcasts::Broadcasts,
|
broadcasts::Broadcasts,
|
||||||
models::{
|
models::{
|
||||||
ClientCursors, CursorPositionFromServer, WebSocketServerMessage,
|
ClientCursors, CursorPositionFromServer, CursorSpan, WebSocketServerMessage,
|
||||||
WebSocketServerMessageWithOrigin,
|
WebSocketServerMessageWithOrigin,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::config::database_config::DatabaseConfig;
|
use crate::config::database_config::DatabaseConfig;
|
||||||
|
|
||||||
const BACKGROUND_TASK_INTERVAL: Duration = Duration::from_secs(1);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cursors {
|
pub struct Cursors {
|
||||||
config: DatabaseConfig,
|
config: DatabaseConfig,
|
||||||
|
|
@ -39,7 +35,7 @@ impl Cursors {
|
||||||
&self,
|
&self,
|
||||||
vault_id: VaultId,
|
vault_id: VaultId,
|
||||||
device_id: &DeviceId,
|
device_id: &DeviceId,
|
||||||
document_to_cursors: HashMap<String, Vec<usize>>,
|
document_to_cursors: HashMap<String, Vec<CursorSpan>>,
|
||||||
) {
|
) {
|
||||||
let mut vault_to_cursors = self.vault_to_cursors.lock().await;
|
let mut vault_to_cursors = self.vault_to_cursors.lock().await;
|
||||||
|
|
||||||
|
|
@ -76,7 +72,7 @@ impl Cursors {
|
||||||
loop {
|
loop {
|
||||||
self.remove_expired_cursors().await;
|
self.remove_expired_cursors().await;
|
||||||
self.broadcast_cursors().await;
|
self.broadcast_cursors().await;
|
||||||
tokio::time::sleep(BACKGROUND_TASK_INTERVAL).await;
|
tokio::time::sleep(self.config.cursor_broadcast_interval).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,16 +105,16 @@ impl Cursors {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct ClientCursorsWithTimeToLive {
|
struct ClientCursorsWithTimeToLive {
|
||||||
client_cursors: ClientCursors,
|
client_cursors: ClientCursors,
|
||||||
last_updated: chrono::DateTime<Utc>,
|
last_updated: std::time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientCursorsWithTimeToLive {
|
impl ClientCursorsWithTimeToLive {
|
||||||
fn new(client_cursors: ClientCursors) -> Self {
|
fn new(client_cursors: ClientCursors) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client_cursors,
|
client_cursors,
|
||||||
last_updated: Utc::now(),
|
last_updated: std::time::Instant::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_expired(&self, ttl: TimeDelta) -> bool { Utc::now() - self.last_updated > ttl }
|
pub fn is_expired(&self, ttl: Duration) -> bool { self.last_updated.elapsed() > ttl }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
use chrono::TimeDelta;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::serde_as;
|
||||||
|
|
||||||
use crate::consts::{
|
use crate::consts::{
|
||||||
DEFAULT_CURSOR_TIMEOUT, DEFAULT_DATABASES_DIRECTORY_PATH, DEFAULT_MAX_CONNECTIONS_PER_VAULT,
|
DEFAULT_CURSOR_BROADCAST_INTERVAL, DEFAULT_CURSOR_TIMEOUT, DEFAULT_DATABASES_DIRECTORY_PATH,
|
||||||
|
DEFAULT_MAX_CONNECTIONS_PER_VAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct DatabaseConfig {
|
pub struct DatabaseConfig {
|
||||||
#[serde(default = "default_databases_directory_path")]
|
#[serde(default = "default_databases_directory_path")]
|
||||||
|
|
@ -16,8 +18,16 @@ pub struct DatabaseConfig {
|
||||||
#[serde(default = "default_max_connections_per_vault")]
|
#[serde(default = "default_max_connections_per_vault")]
|
||||||
pub max_connections_per_vault: u32,
|
pub max_connections_per_vault: u32,
|
||||||
|
|
||||||
#[serde(default = "default_cursor_timeout")]
|
#[serde(default = "default_cursor_timeout", rename = "cursor_timeout_seconds")]
|
||||||
pub cursor_timeout: TimeDelta,
|
#[serde_as(as = "serde_with::DurationSeconds<u64>")]
|
||||||
|
pub cursor_timeout: Duration,
|
||||||
|
|
||||||
|
#[serde(
|
||||||
|
default = "default_cursor_broadcast_interval",
|
||||||
|
rename = "cursor_broadcast_interval_seconds"
|
||||||
|
)]
|
||||||
|
#[serde_as(as = "serde_with::DurationSeconds<u64>")]
|
||||||
|
pub cursor_broadcast_interval: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_databases_directory_path() -> PathBuf {
|
fn default_databases_directory_path() -> PathBuf {
|
||||||
|
|
@ -30,17 +40,23 @@ fn default_max_connections_per_vault() -> u32 {
|
||||||
DEFAULT_MAX_CONNECTIONS_PER_VAULT
|
DEFAULT_MAX_CONNECTIONS_PER_VAULT
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_cursor_timeout() -> TimeDelta {
|
fn default_cursor_timeout() -> Duration {
|
||||||
debug!("Using default cursor timeout: {DEFAULT_CURSOR_TIMEOUT}");
|
debug!("Using default cursor timeout: {DEFAULT_CURSOR_TIMEOUT:?}");
|
||||||
DEFAULT_CURSOR_TIMEOUT
|
DEFAULT_CURSOR_TIMEOUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_cursor_broadcast_interval() -> Duration {
|
||||||
|
debug!("Using default cursor broadcast interval: {DEFAULT_CURSOR_BROADCAST_INTERVAL:?}");
|
||||||
|
DEFAULT_CURSOR_BROADCAST_INTERVAL
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for DatabaseConfig {
|
impl Default for DatabaseConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
databases_directory_path: default_databases_directory_path(),
|
databases_directory_path: default_databases_directory_path(),
|
||||||
max_connections_per_vault: default_max_connections_per_vault(),
|
max_connections_per_vault: default_max_connections_per_vault(),
|
||||||
cursor_timeout: default_cursor_timeout(),
|
cursor_timeout: default_cursor_timeout(),
|
||||||
|
cursor_broadcast_interval: default_cursor_broadcast_interval(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use chrono::TimeDelta;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub const DEFAULT_CONFIG_PATH: &str = "config.yml";
|
pub const DEFAULT_CONFIG_PATH: &str = "config.yml";
|
||||||
|
|
||||||
pub const DEFAULT_DATABASES_DIRECTORY_PATH: &str = "databases";
|
pub const DEFAULT_DATABASES_DIRECTORY_PATH: &str = "databases";
|
||||||
pub const DEFAULT_MAX_CONNECTIONS_PER_VAULT: u32 = 12;
|
pub const DEFAULT_MAX_CONNECTIONS_PER_VAULT: u32 = 12;
|
||||||
pub const DEFAULT_CURSOR_TIMEOUT: TimeDelta = TimeDelta::seconds(60);
|
pub const DEFAULT_CURSOR_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
pub const DEFAULT_CURSOR_BROADCAST_INTERVAL: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
pub const DEFAULT_HOST: &str = "127.0.0.1";
|
pub const DEFAULT_HOST: &str = "127.0.0.1";
|
||||||
pub const DEFAULT_PORT: u16 = 3000;
|
pub const DEFAULT_PORT: u16 = 3000;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue