wxmxqq

BaccPaste

Jan 26th, 2026
97
0
Never
4
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.51 KB | None | 0 0
  1. @keyframes spin{
  2. to{transform:rotate(360deg)}
  3. //! Eventually consistent server-side logic for Rustpad.
  4.  
  5. use std::collections::HashMap;
  6. use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
  7.  
  8. use anyhow::{bail, Context, Result};
  9. use futures::prelude::*;
  10. use log::{info, warn};
  11. use operational_transform::OperationSeq;
  12. use parking_lot::{RwLock, RwLockUpgradableReadGuard};
  13. use serde::{Deserialize, Serialize};
  14. use tokio::sync::{broadcast, Notify};
  15. use warp::ws::{Message, WebSocket};
  16.  
  17. use crate::{database::PersistedDocument, ot::transform_index};
  18.  
  19. /// The main object representing a collaborative session.
  20. pub struct Rustpad {
  21. /// State modified by critical sections of the code.
  22. state: RwLock<State>,
  23. /// Incremented to obtain unique user IDs.
  24. count: AtomicU64,
  25. /// Used to notify clients of new text operations.
  26. notify: Notify,
  27. /// Used to inform all clients of metadata updates.
  28. update: broadcast::Sender<ServerMsg>,
  29. /// Set to true when the document is destroyed.
  30. killed: AtomicBool,
  31. }
  32.  
  33. /// Shared state involving multiple users, protected by a lock.
  34. #[derive(Default)]
  35. struct State {
  36. operations: Vec<UserOperation>,
  37. text: String,
  38. language: Option<String>,
  39. users: HashMap<u64, UserInfo>,
  40. cursors: HashMap<u64, CursorData>,
  41. }
  42.  
  43. #[derive(Clone, Debug, Serialize, Deserialize)]
  44. struct UserOperation {
  45. id: u64,
  46. operation: OperationSeq,
  47. }
  48.  
  49. #[derive(Clone, Debug, Serialize, Deserialize)]
  50. struct UserInfo {
  51. name: String,
  52. hue: u32,
  53. }
  54.  
  55. #[derive(Clone, Debug, Serialize, Deserialize)]
  56. struct CursorData {
  57. cursors: Vec<u32>,
  58. selections: Vec<(u32, u32)>,
  59. }
  60.  
  61. /// A message received from the client over WebSocket.
  62. #[derive(Clone, Debug, Serialize, Deserialize)]
  63. enum ClientMsg {
  64. /// Represents a sequence of local edits from the user.
  65. Edit {
  66. revision: usize,
  67. operation: OperationSeq,
  68. },
  69. /// Sets the language of the editor.
  70. SetLanguage(String),
  71. /// Sets the user's current information.
  72. ClientInfo(UserInfo),
  73. /// Sets the user's cursor and selection positions.
  74. CursorData(CursorData),
  75. }
  76.  
  77. /// A message sent to the client over WebSocket.
  78. #[derive(Clone, Debug, Serialize, Deserialize)]
  79. enum ServerMsg {
  80. /// Informs the client of their unique socket ID.
  81. Identity(u64),
  82. /// Broadcasts text operations to all clients.
  83. History {
  84. start: usize,
  85. operations: Vec<UserOperation>,
  86. },
  87. /// Broadcasts the current language, last writer wins.
  88. Language(String),
  89. /// Broadcasts a user's information, or `None` on disconnect.
  90. UserInfo { id: u64, info: Option<UserInfo> },
  91. /// Broadcasts a user's cursor position.
  92. UserCursor { id: u64, data: CursorData },
  93. }
  94.  
  95. impl From<ServerMsg> for Message {
  96. fn from(msg: ServerMsg) -> Self {
  97. let serialized = serde_json::to_string(&msg).expect("failed serialize");
  98. Message::text(serialized)
  99. }
  100. }
  101.  
  102. impl Default for Rustpad {
  103. fn default() -> Self {
  104. let (tx, _) = broadcast::channel(16);
  105. Self {
  106. state: Default::default(),
  107. count: Default::default(),
  108. notify: Default::default(),
  109. update: tx,
  110. killed: AtomicBool::new(false),
  111. }
  112. }
  113. }
  114.  
  115. impl From<PersistedDocument> for Rustpad {
  116. fn from(document: PersistedDocument) -> Self {
  117. let mut operation = OperationSeq::default();
  118. operation.insert(&document.text);
  119.  
  120. let rustpad = Self::default();
  121. {
  122. let mut state = rustpad.state.write();
  123. state.text = document.text;
  124. state.language = document.language;
  125. state.operations.push(UserOperation {
  126. id: u64::MAX,
  127. operation,
  128. })
  129. }
  130. rustpad
  131. }
  132. }
  133.  
  134. impl Rustpad {
  135. /// Handle a connection from a WebSocket.
  136. pub async fn on_connection(&self, socket: WebSocket) {
  137. let id = self.count.fetch_add(1, Ordering::Relaxed);
  138. info!("connection! id = {}", id);
  139. if let Err(e) = self.handle_connection(id, socket).await {
  140. warn!("connection terminated early: {}", e);
  141. }
  142. info!("disconnection, id = {}", id);
  143. self.state.write().users.remove(&id);
  144. self.state.write().cursors.remove(&id);
  145. self.update
  146. .send(ServerMsg::UserInfo { id, info: None })
  147. .ok();
  148. }
  149.  
  150. /// Returns a snapshot of the latest text.
  151. pub fn text(&self) -> String {
  152. let state = self.state.read();
  153. state.text.clone()
  154. }
  155.  
  156. /// Returns a snapshot of the current document for persistence.
  157. pub fn snapshot(&self) -> PersistedDocument {
  158. let state = self.state.read();
  159. PersistedDocument {
  160. text: state.text.clone(),
  161. language: state.language.clone(),
  162. }
  163. }
  164.  
  165. /// Returns the current revision.
  166. pub fn revision(&self) -> usize {
  167. let state = self.state.read();
  168. state.operations.len()
  169. }
  170.  
  171. /// Kill this object immediately, dropping all current connections.
  172. pub fn kill(&self) {
  173. self.killed.store(true, Ordering::Relaxed);
  174. self.notify.notify_waiters();
  175. }
  176.  
  177. /// Returns if this Rustpad object has been killed.
  178. pub fn killed(&self) -> bool {
  179. self.killed.load(Ordering::Relaxed)
  180. }
  181.  
  182. async fn handle_connection(&self, id: u64, mut socket: WebSocket) -> Result<()> {
  183. let mut update_rx = self.update.subscribe();
  184.  
  185. let mut revision: usize = self.send_initial(id, &mut socket).await?;
  186.  
  187. loop {
  188. // In order to avoid the "lost wakeup" problem, we first request a
  189. // notification, **then** check the current state for new revisions.
  190. // This is the same approach that `tokio::sync::watch` takes.
  191. let notified = self.notify.notified();
  192. if self.killed() {
  193. break;
  194. }
  195. if self.revision() > revision {
  196. revision = self.send_history(revision, &mut socket).await?
  197. }
  198.  
  199. tokio::select! {
  200. _ = notified => {}
  201. update = update_rx.recv() => {
  202. socket.send(update?.into()).await?;
  203. }
  204. result = socket.next() => {
  205. match result {
  206. None => break,
  207. Some(message) => {
  208. self.handle_message(id, message?).await?;
  209. }
  210. }
  211. }
  212. }
  213. }
  214.  
  215. Ok(())
  216. }
  217.  
  218. async fn send_initial(&self, id: u64, socket: &mut WebSocket) -> Result<usize> {
  219. socket.send(ServerMsg::Identity(id).into()).await?;
  220. let mut messages = Vec::new();
  221. let revision = {
  222. let state = self.state.read();
  223. if !state.operations.is_empty() {
  224. messages.push(ServerMsg::History {
  225. start: 0,
  226. operations: state.operations.clone(),
  227. });
  228. }
  229. if let Some(language) = &state.language {
  230. messages.push(ServerMsg::Language(language.clone()));
  231. }
  232. for (&id, info) in &state.users {
  233. messages.push(ServerMsg::UserInfo {
  234. id,
  235. info: Some(info.clone()),
  236. });
  237. }
  238. for (&id, data) in &state.cursors {
  239. messages.push(ServerMsg::UserCursor {
  240. id,
  241. data: data.clone(),
  242. });
  243. }
  244. state.operations.len()
  245. };
  246. for msg in messages {
  247. socket.send(msg.into()).await?;
  248. }
  249. Ok(revision)
  250. }
  251.  
  252. async fn send_history(&self, start: usize, socket: &mut WebSocket) -> Result<usize> {
  253. let operations = {
  254. let state = self.state.read();
  255. let len = state.operations.len();
  256. if start < len {
  257. state.operations[start..].to_owned()
  258. } else {
  259. Vec::new()
  260. }
  261. };
  262. let num_ops = operations.len();
  263. if num_ops > 0 {
  264. let msg = ServerMsg::History { start, operations };
  265. socket.send(msg.into()).await?;
  266. }
  267. Ok(start + num_ops)
  268. }
  269.  
  270. async fn handle_message(&self, id: u64, message: Message) -> Result<()> {
  271. let msg: ClientMsg = match message.to_str() {
  272. Ok(text) => serde_json::from_str(text).context("failed to deserialize message")?,
  273. Err(()) => return Ok(()), // Ignore non-text messages
  274. };
  275. match msg {
  276. ClientMsg::Edit {
  277. revision,
  278. operation,
  279. } => {
  280. self.apply_edit(id, revision, operation)
  281. .context("invalid edit operation")?;
  282. self.notify.notify_waiters();
  283. }
  284. ClientMsg::SetLanguage(language) => {
  285. self.state.write().language = Some(language.clone());
  286. self.update.send(ServerMsg::Language(language)).ok();
  287. }
  288. ClientMsg::ClientInfo(info) => {
  289. self.state.write().users.insert(id, info.clone());
  290. let msg = ServerMsg::UserInfo {
  291. id,
  292. info: Some(info),
  293. };
  294. self.update.send(msg).ok();
  295. }
  296. ClientMsg::CursorData(data) => {
  297. self.state.write().cursors.insert(id, data.clone());
  298. let msg = ServerMsg::UserCursor { id, data };
  299. self.update.send(msg).ok();
  300. }
  301. }
  302. Ok(())
  303. }
  304.  
  305. fn apply_edit(&self, id: u64, revision: usize, mut operation: OperationSeq) -> Result<()> {
  306. info!(
  307. "edit: id = {}, revision = {}, base_len = {}, target_len = {}",
  308. id,
  309. revision,
  310. operation.base_len(),
  311. operation.target_len()
  312. );
  313. let state = self.state.upgradable_read();
  314. let len = state.operations.len();
  315. if revision > len {
  316. bail!("got revision {}, but current is {}", revision, len);
  317. }
  318. for history_op in &state.operations[revision..] {
  319. operation = operation.transform(&history_op.operation)?.0;
  320. }
  321. if operation.target_len() > 256 * 1024 {
  322. bail!(
  323. "target length {} is greater than 256 KiB maximum",
  324. operation.target_len()
  325. );
  326. }
  327. let new_text = operation.apply(&state.text)?;
  328. let mut state = RwLockUpgradableReadGuard::upgrade(state);
  329. for (_, data) in state.cursors.iter_mut() {
  330. for cursor in data.cursors.iter_mut() {
  331. *cursor = transform_index(&operation, *cursor);
  332. }
  333. for (start, end) in data.selections.iter_mut() {
  334. *start = transform_index(&operation, *start);
  335. *end = transform_index(&operation, *end);
  336. }
  337. }
  338. state.operations.push(UserOperation { id, operation });
  339. state.text = new_text;
  340. Ok(())
  341. }
  342. }
  343. START "" C:\docs\mypath\common\aod.pyw %1
  344.  
  345. <script src="https://pastebin.com/embed_js/a2hFnzi5?theme=dark"></script>
  346.  
  347. //! Eventually consistent server-side logic for Rustpad.
  348.  
  349. use std::collections::HashMap;
  350. use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
  351.  
  352. use anyhow::{bail, Context, Result};
  353. use futures::prelude::*;
  354. use log::{info, warn};
  355. use operational_transform::OperationSeq;
  356. use parking_lot::{RwLock, RwLockUpgradableReadGuard};
  357. use serde::{Deserialize, Serialize};
  358. use tokio::sync::{broadcast, Notify};
  359. use warp::ws::{Message, WebSocket};
  360.  
  361. use crate::{database::PersistedDocument, ot::transform_index};
  362.  
  363. /// The main object representing a collaborative session.
  364. pub struct Rustpad {
  365. /// State modified by critical sections of the code.
  366. state: RwLock<State>,
  367. /// Incremented to obtain unique user IDs.
  368. count: AtomicU64,
  369. /// Used to notify clients of new text operations.
  370. notify: Notify,
  371. /// Used to inform all clients of metadata updates.
  372. update: broadcast::Sender<ServerMsg>,
  373. /// Set to true when the document is destroyed.
  374. killed: AtomicBool,
  375. }
  376.  
  377. /// Shared state involving multiple users, protected by a lock.
  378. #[derive(Default)]
  379. struct State {
  380. operations: Vec<UserOperation>,
  381. text: String,
  382. language: Option<String>,
  383. users: HashMap<u64, UserInfo>,
  384. cursors: HashMap<u64, CursorData>,
  385. }
  386.  
  387. #[derive(Clone, Debug, Serialize, Deserialize)]
  388. struct UserOperation {
  389. id: u64,
  390. operation: OperationSeq,
  391. }
  392.  
  393. #[derive(Clone, Debug, Serialize, Deserialize)]
  394. struct UserInfo {
  395. name: String,
  396. hue: u32,
  397. }
  398.  
  399. #[derive(Clone, Debug, Serialize, Deserialize)]
  400. struct CursorData {
  401. cursors: Vec<u32>,
  402. selections: Vec<(u32, u32)>,
  403. }
  404.  
  405. /// A message received from the client over WebSocket.
  406. #[derive(Clone, Debug, Serialize, Deserialize)]
  407. enum ClientMsg {
  408. /// Represents a sequence of local edits from the user.
  409. Edit {
  410. revision: usize,
  411. operation: OperationSeq,
  412. },
  413. /// Sets the language of the editor.
  414. SetLanguage(String),
  415. /// Sets the user's current information.
  416. ClientInfo(UserInfo),
  417. /// Sets the user's cursor and selection positions.
  418. CursorData(CursorData),
  419. }
  420.  
  421. /// A message sent to the client over WebSocket.
  422. #[derive(Clone, Debug, Serialize, Deserialize)]
  423. enum ServerMsg {
  424. /// Informs the client of their unique socket ID.
  425. Identity(u64),
  426. /// Broadcasts text operations to all clients.
  427. History {
  428. start: usize,
  429. operations: Vec<UserOperation>,
  430. },
  431. /// Broadcasts the current language, last writer wins.
  432. Language(String),
  433. /// Broadcasts a user's information, or `None` on disconnect.
  434. UserInfo { id: u64, info: Option<UserInfo> },
  435. /// Broadcasts a user's cursor position.
  436. UserCursor { id: u64, data: CursorData },
  437. }
  438.  
  439. impl From<ServerMsg> for Message {
  440. fn from(msg: ServerMsg) -> Self {
  441. let serialized = serde_json::to_string(&msg).expect("failed serialize");
  442. Message::text(serialized)
  443. }
  444. }
  445.  
  446. impl Default for Rustpad {
  447. fn default() -> Self {
  448. let (tx, _) = broadcast::channel(16);
  449. Self {
  450. state: Default::default(),
  451. count: Default::default(),
  452. notify: Default::default(),
  453. update: tx,
  454. killed: AtomicBool::new(false),
  455. }
  456. }
  457. }
  458.  
  459. impl From<PersistedDocument> for Rustpad {
  460. fn from(document: PersistedDocument) -> Self {
  461. let mut operation = OperationSeq::default();
  462. operation.insert(&document.text);
  463.  
  464. let rustpad = Self::default();
  465. {
  466. let mut state = rustpad.state.write();
  467. state.text = document.text;
  468. state.language = document.language;
  469. state.operations.push(UserOperation {
  470. id: u64::MAX,
  471. operation,
  472. })
  473. }
  474. rustpad
  475. }
  476. }
  477.  
  478. impl Rustpad {
  479. /// Handle a connection from a WebSocket.
  480. pub async fn on_connection(&self, socket: WebSocket) {
  481. let id = self.count.fetch_add(1, Ordering::Relaxed);
  482. info!("connection! id = {}", id);
  483. if let Err(e) = self.handle_connection(id, socket).await {
  484. warn!("connection terminated early: {}", e);
  485. }
  486. info!("disconnection, id = {}", id);
  487. self.state.write().users.remove(&id);
  488. self.state.write().cursors.remove(&id);
  489. self.update
  490. .send(ServerMsg::UserInfo { id, info: None })
  491. .ok();
  492. }
  493.  
  494. /// Returns a snapshot of the latest text.
  495. pub fn text(&self) -> String {
  496. let state = self.state.read();
  497. state.text.clone()
  498. }
  499.  
  500. /// Returns a snapshot of the current document for persistence.
  501. pub fn snapshot(&self) -> PersistedDocument {
  502. let state = self.state.read();
  503. PersistedDocument {
  504. text: state.text.clone(),
  505. language: state.language.clone(),
  506. }
  507. }
  508.  
  509. /// Returns the current revision.
  510. pub fn revision(&self) -> usize {
  511. let state = self.state.read();
  512. state.operations.len()
  513. }
  514.  
  515. /// Kill this object immediately, dropping all current connections.
  516. pub fn kill(&self) {
  517. self.killed.store(true, Ordering::Relaxed);
  518. self.notify.notify_waiters();
  519. }
  520.  
  521. /// Returns if this Rustpad object has been killed.
  522. pub fn killed(&self) -> bool {
  523. self.killed.load(Ordering::Relaxed)
  524. }
  525.  
  526. async fn handle_connection(&self, id: u64, mut socket: WebSocket) -> Result<()> {
  527. let mut update_rx = self.update.subscribe();
  528.  
  529. let mut revision: usize = self.send_initial(id, &mut socket).await?;
  530.  
  531. loop {
  532. // In order to avoid the "lost wakeup" problem, we first request a
  533. // notification, **then** check the current state for new revisions.
  534. // This is the same approach that `tokio::sync::watch` takes.
  535. let notified = self.notify.notified();
  536. if self.killed() {
  537. break;
  538. }
  539. if self.revision() > revision {
  540. revision = self.send_history(revision, &mut socket).await?
  541. }
  542.  
  543. tokio::select! {
  544. _ = notified => {}
  545. update = update_rx.recv() => {
  546. socket.send(update?.into()).await?;
  547. }
  548. result = socket.next() => {
  549. match result {
  550. None => break,
  551. Some(message) => {
  552. self.handle_message(id, message?).await?;
  553. }
  554. }
  555. }
  556. }
  557. }
  558.  
  559. Ok(())
  560. }
  561.  
  562. async fn send_initial(&self, id: u64, socket: &mut WebSocket) -> Result<usize> {
  563. socket.send(ServerMsg::Identity(id).into()).await?;
  564. let mut messages = Vec::new();
  565. let revision = {
  566. let state = self.state.read();
  567. if !state.operations.is_empty() {
  568. messages.push(ServerMsg::History {
  569. start: 0,
  570. operations: state.operations.clone(),
  571. });
  572. }
  573. if let Some(language) = &state.language {
  574. messages.push(ServerMsg::Language(language.clone()));
  575. }
  576. for (&id, info) in &state.users {
  577. messages.push(ServerMsg::UserInfo {
  578. id,
  579. info: Some(info.clone()),
  580. });
  581. }
  582. for (&id, data) in &state.cursors {
  583. messages.push(ServerMsg::UserCursor {
  584. id,
  585. data: data.clone(),
  586. });
  587. }
  588. state.operations.len()
  589. };
  590. for msg in messages {
  591. socket.send(msg.into()).await?;
  592. }
  593. Ok(revision)
  594. }
  595.  
  596. async fn send_history(&self, start: usize, socket: &mut WebSocket) -> Result<usize> {
  597. let operations = {
  598. let state = self.state.read();
  599. let len = state.operations.len();
  600. if start < len {
  601. state.operations[start..].to_owned()
  602. } else {
  603. Vec::new()
  604. }
  605. };
  606. let num_ops = operations.len();
  607. if num_ops > 0 {
  608. let msg = ServerMsg::History { start, operations };
  609. socket.send(msg.into()).await?;
  610. }
  611. Ok(start + num_ops)
  612. }
  613.  
  614. async fn handle_message(&self, id: u64, message: Message) -> Result<()> {
  615. let msg: ClientMsg = match message.to_str() {
  616. Ok(text) => serde_json::from_str(text).context("failed to deserialize message")?,
  617. Err(()) => return Ok(()), // Ignore non-text messages
  618. };
  619. match msg {
  620. ClientMsg::Edit {
  621. revision,
  622. operation,
  623. } => {
  624. self.apply_edit(id, revision, operation)
  625. .context("invalid edit operation")?;
  626. self.notify.notify_waiters();
  627. }
  628. ClientMsg::SetLanguage(language) => {
  629. self.state.write().language = Some(language.clone());
  630. self.update.send(ServerMsg::Language(language)).ok();
  631. }
  632. ClientMsg::ClientInfo(info) => {
  633. self.state.write().users.insert(id, info.clone());
  634. let msg = ServerMsg::UserInfo {
  635. id,
  636. info: Some(info),
  637. };
  638. self.update.send(msg).ok();
  639. }
  640. ClientMsg::CursorData(data) => {
  641. self.state.write().cursors.insert(id, data.clone());
  642. let msg = ServerMsg::UserCursor { id, data };
  643. self.update.send(msg).ok();
  644. }
  645. }
  646. Ok(())
  647. }
  648.  
  649. fn apply_edit(&self, id: u64, revision: usize, mut operation: OperationSeq) -> Result<()> {
  650. info!(
  651. "edit: id = {}, revision = {}, base_len = {}, target_len = {}",
  652. id,
  653. revision,
  654. operation.base_len(),
  655. operation.target_len()
  656. );
  657. let state = self.state.upgradable_read();
  658. let len = state.operations.len();
  659. if revision > len {
  660. bail!("got revision {}, but current is {}", revision, len);
  661. }
  662. for history_op in &state.operations[revision..] {
  663. operation = operation.transform(&history_op.operation)?.0;
  664. }
  665. if operation.target_len() > 256 * 1024 {
  666. bail!(
  667. "target length {} is greater than 256 KiB maximum",
  668. operation.target_len()
  669. );
  670. }
  671. let new_text = operation.apply(&state.text)?;
  672. let mut state = RwLockUpgradableReadGuard::upgrade(state);
  673. for (_, data) in state.cursors.iter_mut() {
  674. for cursor in data.cursors.iter_mut() {
  675. *cursor = transform_index(&operation, *cursor);
  676. }
  677. for (start, end) in data.selections.iter_mut() {
  678. *start = transform_index(&operation, *start);
  679. *end = transform_index(&operation, *end);
  680. }
  681. }
  682. state.operations.push(UserOperation { id, operation });
  683. state.text = new_text;
  684. Ok(())
  685. }
  686. }
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment