y-rb 0.4.5-x64-mingw-ucrt → 0.5.0-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,425 +0,0 @@
1
- use std::cell::RefCell;
2
- use std::collections::hash_map::Entry;
3
- use std::collections::HashMap;
4
- use std::rc::{Rc, Weak};
5
- use std::time::Instant;
6
- use thiserror::Error;
7
- use yrs::block::ClientID;
8
- use yrs::updates::decoder::{Decode, Decoder};
9
- use yrs::updates::encoder::{Encode, Encoder};
10
- use yrs::{Doc, SubscriptionId};
11
-
12
- const NULL_STR: &str = "null";
13
-
14
- /// The Awareness class implements a simple shared state protocol that can be used for non-persistent
15
- /// data like awareness information (cursor, username, status, ..). Each client can update its own
16
- /// local state and listen to state changes of remote clients.
17
- ///
18
- /// Each client is identified by a unique client id (something we borrow from `doc.clientID`).
19
- /// A client can override its own state by propagating a message with an increasing timestamp
20
- /// (`clock`). If such a message is received, it is applied if the known state of that client is
21
- /// older than the new state (`clock < new_clock`). If a client thinks that a remote client is
22
- /// offline, it may propagate a message with `{ clock, state: null, client }`. If such a message is
23
- /// received, and the known clock of that client equals the received clock, it will clean the state.
24
- ///
25
- /// Before a client disconnects, it should propagate a `null` state with an updated clock.
26
- pub struct Awareness {
27
- doc: Doc,
28
- states: HashMap<ClientID, String>,
29
- meta: HashMap<ClientID, MetaClientState>,
30
- on_update: Option<EventHandler<Event>>,
31
- }
32
-
33
- unsafe impl Send for Awareness {}
34
- unsafe impl Sync for Awareness {}
35
-
36
- impl Awareness {
37
- /// Creates a new instance of [Awareness] struct, which operates over a given document.
38
- /// Awareness instance has full ownership of that document. If necessary it can be accessed
39
- /// using either [Awareness::doc] or [Awareness::doc_mut] methods.
40
- pub fn new(doc: Doc) -> Self {
41
- Awareness {
42
- doc,
43
- on_update: None,
44
- states: HashMap::new(),
45
- meta: HashMap::new(),
46
- }
47
- }
48
-
49
- /// Returns a channel receiver for an incoming awareness events. This channel can be cloned.
50
- pub fn on_update<F>(&mut self, f: F) -> Subscription<Event>
51
- where
52
- F: Fn(&Awareness, &Event) + 'static,
53
- {
54
- let eh = self.on_update.get_or_insert_with(EventHandler::default);
55
- eh.subscribe(f)
56
- }
57
-
58
- /// Removes a receiver for incoming awareness events.
59
- pub fn remove_on_update(&mut self, subscription_id: u32) {
60
- if let Some(eh) = self.on_update.as_mut() {
61
- eh.unsubscribe(subscription_id);
62
- }
63
- }
64
-
65
- /// Returns a globally unique client ID of an underlying [Doc].
66
- pub fn client_id(&self) -> ClientID {
67
- self.doc.client_id()
68
- }
69
-
70
- /// Returns a state map of all of the clients tracked by current [Awareness] instance. Those
71
- /// states are identified by their corresponding [ClientID]s. The associated state is
72
- /// represented and replicated to other clients as a JSON string.
73
- pub fn clients(&self) -> &HashMap<ClientID, String> {
74
- &self.states
75
- }
76
-
77
- /// Returns a JSON string state representation of a current [Awareness] instance.
78
- pub fn local_state(&self) -> Option<&str> {
79
- Some(self.states.get(&self.doc.client_id())?.as_str())
80
- }
81
-
82
- /// Sets a current [Awareness] instance state to a corresponding JSON string. This state will
83
- /// be replicated to other clients as part of the [AwarenessUpdate] and it will trigger an event
84
- /// to be emitted if current instance was created using [Awareness::with_observer] method.
85
- ///
86
- pub fn set_local_state<S: Into<String>>(&mut self, json: S) {
87
- let client_id = self.doc.client_id();
88
- self.update_meta(client_id);
89
- let new: String = json.into();
90
- match self.states.entry(client_id) {
91
- Entry::Occupied(mut e) => {
92
- e.insert(new);
93
- if let Some(eh) = self.on_update.as_ref() {
94
- eh.trigger(self, &Event::new(vec![], vec![client_id], vec![]));
95
- }
96
- }
97
- Entry::Vacant(e) => {
98
- e.insert(new);
99
- if let Some(eh) = self.on_update.as_ref() {
100
- eh.trigger(self, &Event::new(vec![client_id], vec![], vec![]));
101
- }
102
- }
103
- }
104
- }
105
-
106
- /// Clears out a state of a given client, effectively marking it as disconnected.
107
- pub fn remove_state(&mut self, client_id: ClientID) {
108
- let prev_state = self.states.remove(&client_id);
109
- self.update_meta(client_id);
110
- if let Some(eh) = self.on_update.as_ref() {
111
- if prev_state.is_some() {
112
- eh.trigger(
113
- self,
114
- &Event::new(Vec::default(), Vec::default(), vec![client_id]),
115
- );
116
- }
117
- }
118
- }
119
-
120
- /// Clears out a state of a current client (see: [Awareness::client_id]),
121
- /// effectively marking it as disconnected.
122
- pub fn clean_local_state(&mut self) {
123
- let client_id = self.doc.client_id();
124
- self.remove_state(client_id);
125
- }
126
-
127
- fn update_meta(&mut self, client_id: ClientID) {
128
- match self.meta.entry(client_id) {
129
- Entry::Occupied(mut e) => {
130
- let clock = e.get().clock + 1;
131
- let meta = MetaClientState::new(clock, Instant::now());
132
- e.insert(meta);
133
- }
134
- Entry::Vacant(e) => {
135
- e.insert(MetaClientState::new(1, Instant::now()));
136
- }
137
- }
138
- }
139
-
140
- /// Returns a serializable update object which is representation of a current Awareness state.
141
- pub fn update(&self) -> Result<AwarenessUpdate, Error> {
142
- let clients = self.states.keys().cloned();
143
- self.update_with_clients(clients)
144
- }
145
-
146
- /// Returns a serializable update object which is representation of a current Awareness state.
147
- /// Unlike [Awareness::update], this method variant allows to prepare update only for a subset
148
- /// of known clients. These clients must all be known to a current [Awareness] instance,
149
- /// otherwise a [Error::ClientNotFound] error will be returned.
150
- pub fn update_with_clients<I: IntoIterator<Item = ClientID>>(
151
- &self,
152
- clients: I,
153
- ) -> Result<AwarenessUpdate, Error> {
154
- let mut res = HashMap::new();
155
- for client_id in clients {
156
- let clock = if let Some(meta) = self.meta.get(&client_id) {
157
- meta.clock
158
- } else {
159
- return Err(Error::ClientNotFound(client_id));
160
- };
161
- let json = if let Some(json) = self.states.get(&client_id) {
162
- json.clone()
163
- } else {
164
- String::from(NULL_STR)
165
- };
166
- res.insert(client_id, AwarenessUpdateEntry { clock, json });
167
- }
168
- Ok(AwarenessUpdate { clients: res })
169
- }
170
-
171
- /// Applies an update (incoming from remote channel or generated using [Awareness::update] /
172
- /// [Awareness::update_with_clients] methods) and modifies a state of a current instance.
173
- ///
174
- /// If current instance has an observer channel (see: [Awareness::with_observer]), applied
175
- /// changes will also be emitted as events.
176
- pub fn apply_update(&mut self, update: AwarenessUpdate) -> Result<(), Error> {
177
- let now = Instant::now();
178
-
179
- let mut added = Vec::new();
180
- let mut updated = Vec::new();
181
- let mut removed = Vec::new();
182
-
183
- for (client_id, entry) in update.clients {
184
- let mut clock = entry.clock;
185
- let is_null = entry.json.as_str() == NULL_STR;
186
- match self.meta.entry(client_id) {
187
- Entry::Occupied(mut e) => {
188
- let prev = e.get();
189
- let is_removed =
190
- prev.clock == clock && is_null && self.states.contains_key(&client_id);
191
- let is_new = prev.clock < clock;
192
- if is_new || is_removed {
193
- if is_null {
194
- // never let a remote client remove this local state
195
- if client_id == self.doc.client_id()
196
- && self.states.get(&client_id).is_some()
197
- {
198
- // remote client removed the local state. Do not remote state. Broadcast a message indicating
199
- // that this client still exists by increasing the clock
200
- clock += 1;
201
- } else {
202
- self.states.remove(&client_id);
203
- if self.on_update.is_some() {
204
- removed.push(client_id);
205
- }
206
- }
207
- } else {
208
- match self.states.entry(client_id) {
209
- Entry::Occupied(mut e) => {
210
- if self.on_update.is_some() {
211
- updated.push(client_id);
212
- }
213
- e.insert(entry.json);
214
- }
215
- Entry::Vacant(e) => {
216
- e.insert(entry.json);
217
- if self.on_update.is_some() {
218
- updated.push(client_id);
219
- }
220
- }
221
- }
222
- }
223
- e.insert(MetaClientState::new(clock, now));
224
- true
225
- } else {
226
- false
227
- }
228
- }
229
- Entry::Vacant(e) => {
230
- e.insert(MetaClientState::new(clock, now));
231
- self.states.insert(client_id, entry.json);
232
- if self.on_update.is_some() {
233
- added.push(client_id);
234
- }
235
- true
236
- }
237
- };
238
- }
239
-
240
- if let Some(eh) = self.on_update.as_ref() {
241
- if !added.is_empty() || !updated.is_empty() || !removed.is_empty() {
242
- eh.trigger(self, &Event::new(added, updated, removed));
243
- }
244
- }
245
-
246
- Ok(())
247
- }
248
- }
249
-
250
- impl Default for Awareness {
251
- fn default() -> Self {
252
- Awareness::new(Doc::new())
253
- }
254
- }
255
-
256
- #[allow(clippy::type_complexity)]
257
- struct EventHandler<T> {
258
- seq_nr: u32,
259
- subscribers: Rc<RefCell<HashMap<u32, Box<dyn Fn(&Awareness, &T)>>>>,
260
- }
261
-
262
- impl<T> EventHandler<T> {
263
- pub fn subscribe<F>(&mut self, f: F) -> Subscription<T>
264
- where
265
- F: Fn(&Awareness, &T) + 'static,
266
- {
267
- let subscription_id = self.seq_nr;
268
- self.seq_nr += 1;
269
- {
270
- let func = Box::new(f);
271
- let mut subs = self.subscribers.borrow_mut();
272
- subs.insert(subscription_id, func);
273
- }
274
- Subscription {
275
- subscription_id,
276
- subscribers: Rc::downgrade(&self.subscribers),
277
- }
278
- }
279
-
280
- pub fn unsubscribe(&mut self, subscription_id: u32) {
281
- let mut subs = self.subscribers.borrow_mut();
282
- subs.remove(&subscription_id);
283
- }
284
-
285
- pub fn trigger(&self, awareness: &Awareness, arg: &T) {
286
- let subs = self.subscribers.borrow();
287
- for func in subs.values() {
288
- func(awareness, arg);
289
- }
290
- }
291
- }
292
-
293
- impl<T> Default for EventHandler<T> {
294
- fn default() -> Self {
295
- EventHandler {
296
- seq_nr: 0,
297
- subscribers: Rc::new(RefCell::new(HashMap::new())),
298
- }
299
- }
300
- }
301
-
302
- /// Whenever a new callback is being registered, a [Subscription] is made. Whenever this
303
- /// subscription a registered callback is cancelled and will not be called any more.
304
- #[allow(clippy::type_complexity)]
305
- pub struct Subscription<T> {
306
- subscription_id: u32,
307
- subscribers: Weak<RefCell<HashMap<u32, Box<dyn Fn(&Awareness, &T)>>>>,
308
- }
309
-
310
- #[allow(clippy::from_over_into)]
311
- impl<T> Into<SubscriptionId> for Subscription<T> {
312
- fn into(self) -> SubscriptionId {
313
- let id = self.subscription_id;
314
- std::mem::forget(self);
315
- id
316
- }
317
- }
318
-
319
- impl<T> Drop for Subscription<T> {
320
- fn drop(&mut self) {
321
- if let Some(subs) = self.subscribers.upgrade() {
322
- let mut s = subs.borrow_mut();
323
- s.remove(&self.subscription_id);
324
- }
325
- }
326
- }
327
-
328
- /// A structure that represents an encodable state of an [Awareness] struct.
329
- #[derive(Debug, Eq, PartialEq)]
330
- pub struct AwarenessUpdate {
331
- clients: HashMap<ClientID, AwarenessUpdateEntry>,
332
- }
333
-
334
- impl Encode for AwarenessUpdate {
335
- fn encode<E: Encoder>(&self, encoder: &mut E) {
336
- encoder.write_var(self.clients.len());
337
- for (&client_id, e) in self.clients.iter() {
338
- encoder.write_var(client_id);
339
- encoder.write_var(e.clock);
340
- encoder.write_string(&e.json);
341
- }
342
- }
343
- }
344
-
345
- impl Decode for AwarenessUpdate {
346
- fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, lib0::error::Error> {
347
- let len: usize = decoder.read_var()?;
348
- let mut clients = HashMap::with_capacity(len);
349
- for _ in 0..len {
350
- let client_id: ClientID = decoder.read_var()?;
351
- let clock: u32 = decoder.read_var()?;
352
- let json = decoder.read_string()?.to_string();
353
- clients.insert(client_id, AwarenessUpdateEntry { clock, json });
354
- }
355
-
356
- Ok(AwarenessUpdate { clients })
357
- }
358
- }
359
-
360
- /// A single client entry of an [AwarenessUpdate]. It consists of logical clock and JSON client
361
- /// state represented as a string.
362
- #[derive(Debug, Eq, PartialEq)]
363
- pub struct AwarenessUpdateEntry {
364
- clock: u32,
365
- json: String,
366
- }
367
-
368
- /// Errors generated by an [Awareness] struct methods.
369
- #[derive(Error, Debug)]
370
- pub enum Error {
371
- /// Client ID was not found in [Awareness] metadata.
372
- #[error("client ID `{0}` not found")]
373
- ClientNotFound(ClientID),
374
- }
375
-
376
- #[derive(Debug, Clone, PartialEq, Eq)]
377
- struct MetaClientState {
378
- clock: u32,
379
- last_updated: Instant,
380
- }
381
-
382
- impl MetaClientState {
383
- fn new(clock: u32, last_updated: Instant) -> Self {
384
- MetaClientState {
385
- clock,
386
- last_updated,
387
- }
388
- }
389
- }
390
-
391
- /// Event type emitted by an [Awareness] struct.
392
- #[derive(Debug, Default, Clone, Eq, PartialEq)]
393
- pub struct Event {
394
- added: Vec<ClientID>,
395
- updated: Vec<ClientID>,
396
- removed: Vec<ClientID>,
397
- }
398
-
399
- impl Event {
400
- pub fn new(added: Vec<ClientID>, updated: Vec<ClientID>, removed: Vec<ClientID>) -> Self {
401
- Event {
402
- added,
403
- updated,
404
- removed,
405
- }
406
- }
407
-
408
- /// Collection of new clients that have been added to an [Awareness] struct, that was not known
409
- /// before. Actual client state can be accessed via `awareness.clients().get(client_id)`.
410
- pub fn added(&self) -> &[ClientID] {
411
- &self.added
412
- }
413
-
414
- /// Collection of new clients that have been updated within an [Awareness] struct since the last
415
- /// update. Actual client state can be accessed via `awareness.clients().get(client_id)`.
416
- pub fn updated(&self) -> &[ClientID] {
417
- &self.updated
418
- }
419
-
420
- /// Collection of new clients that have been removed from [Awareness] struct since the last
421
- /// update.
422
- pub fn removed(&self) -> &[ClientID] {
423
- &self.removed
424
- }
425
- }