chore: merge with main
This commit is contained in:
commit
4fd5086e85
|
|
@ -1274,6 +1274,7 @@ dependencies = [
|
||||||
"getrandom 0.2.12",
|
"getrandom 0.2.12",
|
||||||
"gotrue",
|
"gotrue",
|
||||||
"gotrue-entity",
|
"gotrue-entity",
|
||||||
|
"governor",
|
||||||
"mime",
|
"mime",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
|
|
@ -1719,6 +1720,19 @@ dependencies = [
|
||||||
"syn 2.0.48",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dashmap"
|
||||||
|
version = "5.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"hashbrown 0.14.3",
|
||||||
|
"lock_api",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot_core 0.9.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "data-encoding"
|
name = "data-encoding"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
@ -2171,6 +2185,12 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-timer"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
|
@ -2314,6 +2334,24 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "governor"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"dashmap",
|
||||||
|
"futures",
|
||||||
|
"futures-timer",
|
||||||
|
"no-std-compat",
|
||||||
|
"nonzero_ext",
|
||||||
|
"parking_lot 0.12.1",
|
||||||
|
"quanta 0.11.1",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.24"
|
version = "0.3.24"
|
||||||
|
|
@ -2963,6 +3001,15 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach2"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
@ -3116,7 +3163,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"quanta",
|
"quanta 0.12.2",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"skeptic",
|
"skeptic",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
|
@ -3176,6 +3223,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "no-std-compat"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
|
|
@ -3186,6 +3239,12 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonzero_ext"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "normpath"
|
name = "normpath"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|
@ -3942,6 +4001,22 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quanta"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"libc",
|
||||||
|
"mach2",
|
||||||
|
"once_cell",
|
||||||
|
"raw-cpuid 10.7.0",
|
||||||
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
"web-sys",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quanta"
|
name = "quanta"
|
||||||
version = "0.12.2"
|
version = "0.12.2"
|
||||||
|
|
@ -3951,7 +4026,7 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"raw-cpuid",
|
"raw-cpuid 11.0.1",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
|
@ -4053,6 +4128,15 @@ dependencies = [
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "raw-cpuid"
|
||||||
|
version = "10.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-cpuid"
|
name = "raw-cpuid"
|
||||||
version = "11.0.1"
|
version = "11.0.1"
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ pub fn localhost_client_with_device_id(device_id: &str) -> Client {
|
||||||
&LOCALHOST_GOTRUE,
|
&LOCALHOST_GOTRUE,
|
||||||
device_id,
|
device_id,
|
||||||
ClientConfiguration::default(),
|
ClientConfiguration::default(),
|
||||||
|
"test",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ serde.workspace = true
|
||||||
database-entity.workspace = true
|
database-entity.workspace = true
|
||||||
app-error = { workspace = true, features = ["tokio_error", "bincode_error"] }
|
app-error = { workspace = true, features = ["tokio_error", "bincode_error"] }
|
||||||
scraper = { version = "0.17.1", optional = true }
|
scraper = { version = "0.17.1", optional = true }
|
||||||
|
governor = { version = "0.6.0" }
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
tokio-retry = "0.3"
|
tokio-retry = "0.3"
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,6 @@ use url::Url;
|
||||||
use gotrue_entity::dto::SignUpResponse::{Authenticated, NotAuthenticated};
|
use gotrue_entity::dto::SignUpResponse::{Authenticated, NotAuthenticated};
|
||||||
use gotrue_entity::dto::{GotrueTokenResponse, UpdateGotrueUserParams, User};
|
use gotrue_entity::dto::{GotrueTokenResponse, UpdateGotrueUserParams, User};
|
||||||
|
|
||||||
/// The API version of the client.
|
|
||||||
/// 0.0.4
|
|
||||||
/// fix refresh token issue
|
|
||||||
pub const CLIENT_API_VERSION: &str = "0.0.5";
|
|
||||||
pub const X_COMPRESSION_TYPE: &str = "X-Compression-Type";
|
pub const X_COMPRESSION_TYPE: &str = "X-Compression-Type";
|
||||||
pub const X_COMPRESSION_BUFFER_SIZE: &str = "X-Compression-Buffer-Size";
|
pub const X_COMPRESSION_BUFFER_SIZE: &str = "X-Compression-Buffer-Size";
|
||||||
pub const X_COMPRESSION_TYPE_BROTLI: &str = "brotli";
|
pub const X_COMPRESSION_TYPE_BROTLI: &str = "brotli";
|
||||||
|
|
@ -110,6 +106,7 @@ pub struct Client {
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
ws_addr: String,
|
ws_addr: String,
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
|
pub client_id: String,
|
||||||
pub(crate) token: Arc<RwLock<ClientToken>>,
|
pub(crate) token: Arc<RwLock<ClientToken>>,
|
||||||
pub(crate) is_refreshing_token: Arc<AtomicBool>,
|
pub(crate) is_refreshing_token: Arc<AtomicBool>,
|
||||||
pub(crate) refresh_ret_txs: Arc<RwLock<Vec<RefreshTokenSender>>>,
|
pub(crate) refresh_ret_txs: Arc<RwLock<Vec<RefreshTokenSender>>>,
|
||||||
|
|
@ -134,6 +131,7 @@ impl Client {
|
||||||
gotrue_url: &str,
|
gotrue_url: &str,
|
||||||
device_id: &str,
|
device_id: &str,
|
||||||
config: ClientConfiguration,
|
config: ClientConfiguration,
|
||||||
|
client_id: &str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let reqwest_client = reqwest::Client::new();
|
let reqwest_client = reqwest::Client::new();
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -146,6 +144,7 @@ impl Client {
|
||||||
refresh_ret_txs: Default::default(),
|
refresh_ret_txs: Default::default(),
|
||||||
config,
|
config,
|
||||||
device_id: device_id.to_string(),
|
device_id: device_id.to_string(),
|
||||||
|
client_id: client_id.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1186,7 +1185,7 @@ impl Client {
|
||||||
let request_builder = self
|
let request_builder = self
|
||||||
.cloud_client
|
.cloud_client
|
||||||
.request(method, url)
|
.request(method, url)
|
||||||
.header("client-version", CLIENT_API_VERSION)
|
.header("client-version", self.client_id.clone())
|
||||||
.header("client-timestamp", ts_now.to_string())
|
.header("client-timestamp", ts_now.to_string())
|
||||||
.header("device_id", self.device_id.clone())
|
.header("device_id", self.device_id.clone())
|
||||||
.bearer_auth(access_token);
|
.bearer_auth(access_token);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
use futures_util::{SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt};
|
||||||
|
use governor::clock::DefaultClock;
|
||||||
|
use governor::middleware::NoOpMiddleware;
|
||||||
|
use governor::state::{InMemoryState, NotKeyed};
|
||||||
|
use governor::{Quota, RateLimiter};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use futures_util::FutureExt;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use tokio::sync::broadcast::{channel, Receiver, Sender};
|
use tokio::sync::broadcast::{channel, Receiver, Sender};
|
||||||
|
|
||||||
use crate::ws::{ConnectState, ConnectStateNotify, WSError, WebSocketChannel};
|
use crate::ws::{ConnectState, ConnectStateNotify, WSError, WebSocketChannel};
|
||||||
use crate::ServerFixIntervalPing;
|
use crate::ServerFixIntervalPing;
|
||||||
use crate::{platform_spawn, retry_connect};
|
use crate::{platform_spawn, retry_connect};
|
||||||
use realtime_entity::collab_msg::CollabMessage;
|
use realtime_entity::collab_msg::CollabMessage;
|
||||||
use realtime_entity::message::RealtimeMessage;
|
use realtime_entity::message::{RealtimeMessage, SystemMessage};
|
||||||
use realtime_entity::user::UserMessage;
|
use realtime_entity::user::UserMessage;
|
||||||
use tokio::sync::{oneshot, Mutex};
|
use tokio::sync::{oneshot, Mutex};
|
||||||
use tracing::{debug, error, info, trace, warn};
|
use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
@ -59,6 +65,8 @@ pub struct WSClient {
|
||||||
collab_channels: Arc<RwLock<ChannelByObjectId>>,
|
collab_channels: Arc<RwLock<ChannelByObjectId>>,
|
||||||
ping: Arc<Mutex<Option<ServerFixIntervalPing>>>,
|
ping: Arc<Mutex<Option<ServerFixIntervalPing>>>,
|
||||||
stop_tx: Mutex<Option<oneshot::Sender<()>>>,
|
stop_tx: Mutex<Option<oneshot::Sender<()>>>,
|
||||||
|
rate_limiter:
|
||||||
|
Arc<tokio::sync::RwLock<RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WSClient {
|
impl WSClient {
|
||||||
|
|
@ -72,6 +80,7 @@ impl WSClient {
|
||||||
let ping = Arc::new(Mutex::new(None));
|
let ping = Arc::new(Mutex::new(None));
|
||||||
let http_sender = Arc::new(http_sender);
|
let http_sender = Arc::new(http_sender);
|
||||||
let (user_channel, _) = channel(1);
|
let (user_channel, _) = channel(1);
|
||||||
|
let rate_limiter = gen_rate_limiter(10);
|
||||||
WSClient {
|
WSClient {
|
||||||
addr: Arc::new(parking_lot::Mutex::new(None)),
|
addr: Arc::new(parking_lot::Mutex::new(None)),
|
||||||
config,
|
config,
|
||||||
|
|
@ -82,6 +91,7 @@ impl WSClient {
|
||||||
collab_channels,
|
collab_channels,
|
||||||
ping,
|
ping,
|
||||||
stop_tx: Mutex::new(None),
|
stop_tx: Mutex::new(None),
|
||||||
|
rate_limiter: Arc::new(tokio::sync::RwLock::new(rate_limiter)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +155,7 @@ impl WSClient {
|
||||||
*self.ping.lock().await = Some(ping);
|
*self.ping.lock().await = Some(ping);
|
||||||
|
|
||||||
let user_message_tx = self.user_channel.as_ref().clone();
|
let user_message_tx = self.user_channel.as_ref().clone();
|
||||||
|
let rate_limiter = self.rate_limiter.clone();
|
||||||
// Receive messages from the websocket, and send them to the channels.
|
// Receive messages from the websocket, and send them to the channels.
|
||||||
platform_spawn(async move {
|
platform_spawn(async move {
|
||||||
while let Some(Ok(ws_msg)) = stream.next().await {
|
while let Some(Ok(ws_msg)) = stream.next().await {
|
||||||
|
|
@ -180,7 +191,14 @@ impl WSClient {
|
||||||
RealtimeMessage::User(user_message) => {
|
RealtimeMessage::User(user_message) => {
|
||||||
let _ = user_message_tx.send(user_message);
|
let _ = user_message_tx.send(user_message);
|
||||||
},
|
},
|
||||||
RealtimeMessage::ServerKickedOff => {},
|
RealtimeMessage::System(sys_message) => match sys_message {
|
||||||
|
SystemMessage::RateLimit(limit) => {
|
||||||
|
*rate_limiter.write().await = gen_rate_limiter(limit);
|
||||||
|
},
|
||||||
|
SystemMessage::KickOff => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -210,12 +228,15 @@ impl WSClient {
|
||||||
|
|
||||||
let mut rx = self.sender.subscribe();
|
let mut rx = self.sender.subscribe();
|
||||||
let weak_http_sender = Arc::downgrade(&self.http_sender);
|
let weak_http_sender = Arc::downgrade(&self.http_sender);
|
||||||
|
let rate_limiter = self.rate_limiter.clone();
|
||||||
let device_id = device_id.to_string();
|
let device_id = device_id.to_string();
|
||||||
platform_spawn(async move {
|
platform_spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = &mut stop_rx => break,
|
_ = &mut stop_rx => break,
|
||||||
Ok(msg) = rx.recv() => {
|
Ok(msg) = rx.recv() => {
|
||||||
|
rate_limiter.read().await.until_ready().fuse().await;
|
||||||
|
|
||||||
let len = msg.len();
|
let len = msg.len();
|
||||||
// The maximum size allowed for a WebSocket message is 65,536 bytes. If the message exceeds
|
// The maximum size allowed for a WebSocket message is 65,536 bytes. If the message exceeds
|
||||||
// 40,960 bytes (to avoid occupying the entire space), it should be sent over HTTP instead.
|
// 40,960 bytes (to avoid occupying the entire space), it should be sent over HTTP instead.
|
||||||
|
|
@ -307,3 +328,14 @@ impl WSClient {
|
||||||
self.state_notify.lock().set_state(state);
|
self.state_notify.lock().set_state(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gen_rate_limiter(
|
||||||
|
mut times_per_sec: u32,
|
||||||
|
) -> RateLimiter<NotKeyed, InMemoryState, DefaultClock, NoOpMiddleware> {
|
||||||
|
// make sure the rate limiter is not zero
|
||||||
|
if times_per_sec == 0 {
|
||||||
|
times_per_sec = 1;
|
||||||
|
}
|
||||||
|
let quota = Quota::per_second(NonZeroU32::new(times_per_sec).unwrap());
|
||||||
|
RateLimiter::direct(quota)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ use websocket::Message;
|
||||||
pub enum RealtimeMessage {
|
pub enum RealtimeMessage {
|
||||||
Collab(CollabMessage),
|
Collab(CollabMessage),
|
||||||
User(UserMessage),
|
User(UserMessage),
|
||||||
ServerKickedOff,
|
System(SystemMessage),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RealtimeMessage {
|
impl RealtimeMessage {
|
||||||
pub fn device_id(&self) -> Option<String> {
|
pub fn device_id(&self) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
RealtimeMessage::Collab(msg) => msg.device_id(),
|
RealtimeMessage::Collab(msg) => msg.device_id(),
|
||||||
RealtimeMessage::ServerKickedOff => None,
|
|
||||||
RealtimeMessage::User(_) => None,
|
RealtimeMessage::User(_) => None,
|
||||||
|
RealtimeMessage::System(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -30,8 +30,8 @@ impl Display for RealtimeMessage {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RealtimeMessage::Collab(msg) => f.write_fmt(format_args!("Collab:{}", msg.object_id())),
|
RealtimeMessage::Collab(msg) => f.write_fmt(format_args!("Collab:{}", msg.object_id())),
|
||||||
RealtimeMessage::ServerKickedOff => f.write_fmt(format_args!("ServerKickedOff")),
|
|
||||||
RealtimeMessage::User(_) => f.write_fmt(format_args!("User")),
|
RealtimeMessage::User(_) => f.write_fmt(format_args!("User")),
|
||||||
|
RealtimeMessage::System(_) => f.write_fmt(format_args!("System")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,3 +111,9 @@ impl From<RealtimeMessage> for Message {
|
||||||
Message::Binary(bytes)
|
Message::Binary(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum SystemMessage {
|
||||||
|
RateLimit(u32),
|
||||||
|
KickOff,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ where
|
||||||
match &msg {
|
match &msg {
|
||||||
RealtimeMessage::Collab(_) => ctx.binary(msg),
|
RealtimeMessage::Collab(_) => ctx.binary(msg),
|
||||||
RealtimeMessage::User(_) => ctx.binary(msg),
|
RealtimeMessage::User(_) => ctx.binary(msg),
|
||||||
RealtimeMessage::ServerKickedOff => ctx.stop(),
|
RealtimeMessage::System(_) => ctx.binary(msg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use crate::collaborate::permission::CollabAccessControl;
|
||||||
use crate::collaborate::retry::{CollabUserMessage, SubscribeGroupIfNeed};
|
use crate::collaborate::retry::{CollabUserMessage, SubscribeGroupIfNeed};
|
||||||
use crate::util::channel_ext::UnboundedSenderSink;
|
use crate::util::channel_ext::UnboundedSenderSink;
|
||||||
use database::collab::CollabStorage;
|
use database::collab::CollabStorage;
|
||||||
|
use realtime_entity::message::SystemMessage;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CollabServer<S, U, AC> {
|
pub struct CollabServer<S, U, AC> {
|
||||||
|
|
@ -509,7 +510,9 @@ impl CollabClientStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disconnect(&self) {
|
pub fn disconnect(&self) {
|
||||||
self.sink.do_send(RealtimeMessage::ServerKickedOff);
|
self
|
||||||
|
.sink
|
||||||
|
.do_send(RealtimeMessage::System(SystemMessage::KickOff));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue