成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實(shí)現(xiàn)一個(gè)多人協(xié)作在線文檔有哪些技術(shù)難點(diǎn)?

網(wǎng)絡(luò)
用于多人協(xié)同編輯 Autodesk Maya 文檔OT算法維持一致性的基本思路是根據(jù)先前執(zhí)行的并發(fā)操作的影響將編輯操作轉(zhuǎn)換為新形式,以便轉(zhuǎn)換后的操作可以實(shí)現(xiàn)正確的效果,并確保復(fù)制的文檔相同。

 這是一篇鴿了很久的回答,正巧 Cloud Studio 也實(shí)現(xiàn)了多人協(xié)作代碼編輯,技術(shù)原理上來說是差不多的,這里把之前我的一篇博客發(fā)上來吧。協(xié)同編輯基本實(shí)現(xiàn)思路有兩種,分別是 CRDT(Conflict-Free Replicated Data Types) 和 OT(Operational-Transformation)。

CRDT

CRDT即無沖突可復(fù)制數(shù)據(jù)類型,看上去很難理解(其實(shí)我也不怎么理解),這是一些分布式系統(tǒng)中適應(yīng)于不同場(chǎng)景且可以保持最終一致性的數(shù)據(jù)結(jié)構(gòu)的統(tǒng)稱。也就是說CRDT本身只是一個(gè)概念,應(yīng)用于協(xié)作編輯中需要自行實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu),比如GitHub團(tuán)隊(duì)開源的。

ATOM的實(shí)時(shí)協(xié)作功能就是基于這個(gè)庫(kù)來實(shí)現(xiàn)的,數(shù)據(jù)傳輸采用WebRTC,只有在最初的邀請(qǐng)/加入階段依賴GitHub的服務(wù)器外,所有的傳輸都是點(diǎn)對(duì)點(diǎn)的(peer-to-peer),同時(shí)以確保隱私,所有數(shù)據(jù)都是加密的。

OTO

perational-Transformation 或者叫操作轉(zhuǎn)換,是指對(duì)文檔編輯以及同時(shí)編輯沖突解決的一類技術(shù),不僅僅是一個(gè)算法。與CRDT不同的是,OT算法全程依賴于服務(wù)器來保持最終一致性。成本而言,CRDT優(yōu)于OT,但因CRDT的實(shí)現(xiàn)復(fù)雜性(沒學(xué)會(huì)),本文主要介紹基于OT算法的實(shí)時(shí)協(xié)同編輯。OT算法不僅可用于純文本操作,同時(shí)還支持一些更為復(fù)雜的場(chǎng)景:

  • 協(xié)同圖形編輯

支持實(shí)時(shí)協(xié)作的多媒體編輯器,可以讓多個(gè)用戶在同一 Adobe Flash 中同時(shí)編輯同一文檔

  • 協(xié)同HTML/XML以及富文本編輯

基于網(wǎng)絡(luò)的實(shí)時(shí)協(xié)作編輯器

  • 協(xié)同電子表格、Word文檔等
  • 計(jì)算機(jī)輔助設(shè)計(jì)(Maya)

用于多人協(xié)同編輯 Autodesk Maya 文檔OT算法維持一致性的基本思路是根據(jù)先前執(zhí)行的并發(fā)操作的影響將編輯操作轉(zhuǎn)換為新形式,以便轉(zhuǎn)換后的操作可以實(shí)現(xiàn)正確的效果,并確保復(fù)制的文檔相同。事實(shí)上,并不是在多人同時(shí)編輯相鄰字符時(shí)才必須要使用OT,OT的適用性與并發(fā)操作的字符/對(duì)象數(shù)量無關(guān),無論這些目標(biāo)對(duì)象是否相互重疊,無論這些字符相鄰遠(yuǎn)近,OT都會(huì)針對(duì)具有位置依賴關(guān)系的對(duì)象進(jìn)行并發(fā)控制。

OT將文檔變更表示為三類操作(Operational)

  1. Insert 插入
  2. Retain 保留
  3. Delete 刪除

例如對(duì)于一個(gè)原始內(nèi)容為“abc”的文檔,假設(shè)用戶O1在文檔位置0處插入一個(gè)字符“x”,表示為`Insert[0,"x"]`,用戶O2在文檔位置2處刪除一個(gè)字符,表示為`Delete[2,1]`(或者Delete[2,'c']),這將產(chǎn)生一個(gè)并發(fā)操作。在OT的控制下,本地操作會(huì)如期執(zhí)行,遠(yuǎn)端服務(wù)器收到兩個(gè)操作后會(huì)進(jìn)行轉(zhuǎn)換`Transformation`,具體過程如下

  1. 用戶O1首先執(zhí)行插入操作,文檔內(nèi)容變?yōu)?ldquo;xabc”。然后O2的操作到達(dá)且被轉(zhuǎn)換為`O2' = T(O2,O1) = Delete[3,1]`,產(chǎn)生了一個(gè)新的操作,此時(shí)位置增加了1,因?yàn)镺1插入了一個(gè)字符。然后在文檔“xabc”執(zhí)行O2',此時(shí)文檔內(nèi)容變?yōu)?ldquo;xab”,即“c”被正確的刪除。(如果不進(jìn)行轉(zhuǎn)換,會(huì)錯(cuò)誤的刪除“b”)。
  2. 用戶O2首先執(zhí)行刪除操作,文檔內(nèi)容變?yōu)?ldquo;ab”,然后O1的操作到達(dá)且被轉(zhuǎn)換為`O1' = T(O1, o2) = Insert[0,"x"]`,也產(chǎn)生了一個(gè)新的操作,由于先前執(zhí)行的O2與O1互不影響,轉(zhuǎn)換后的O1'與O1相同,文檔內(nèi)容變?yōu)?ldquo;xab”。

這里忽略了光標(biāo)操作,實(shí)際上多用戶實(shí)時(shí)編輯時(shí),應(yīng)用在編輯器上,并不會(huì)真正的去移動(dòng)光標(biāo),只會(huì)在相應(yīng)的位置插入一個(gè)fake cursor。Monaco-Editor 與 ot.js我們使用ot.js來實(shí)現(xiàn)Monaco-Editor的協(xié)同編輯。ot.js包含客戶端與服務(wù)端的實(shí)現(xiàn),在客戶端,它將編輯操作轉(zhuǎn)換為一系列的operation。

  1. // 對(duì)于文檔“Operational Transformation” 
  2. const operation = new ot.Operation() 
  3.   .retain(11) // 前11個(gè)字符保留 
  4.   .insert("color"); // 插入字符 
  5. // 這將使文檔變更為 "Operationalcolor" 
  6.  
  7. // “abc” 
  8. const deleteOperation = new ot.Operation() 
  9.   .retain(2) // 
  10.   .delete(1) 
  11.   .insert("x"// axc 

同時(shí)operation也是可組合的,比如將兩個(gè)操作組合為一個(gè)操作

  1. const operation0 = new ot.Operation() 
  2.   .retain(13) 
  3.   .insert(" hello"); 
  4. const operation1 = new ot.Operation() 
  5.   .delete("misaka "
  6.   .retain(13); 
  7.  
  8. const str0 = "misaka mikoto"
  9.  
  10. const str1 = operation0.apply(str0); // "misaka mikoto hello" 
  11. const str2a = operation1.apply(str1); // "mikoto hello" 
  12.  
  13. // 組合 
  14. const combinedOperation = operation0.compose(operation1); 
  15. const str2b = combinedOperation.apply(str0); // "mikoto dolor" 

應(yīng)用到Monaco中,我們需要監(jiān)聽編輯器的onChange事件以及光標(biāo)相關(guān)操作事件(selectionChange,cursorChange,blur等)。在文本內(nèi)容修改的事件中,將每次修改產(chǎn)生的`changes`轉(zhuǎn)換為一個(gè)或多個(gè)操作,也叫`operation`。光標(biāo)的操作很好處理,轉(zhuǎn)換成一個(gè)`Retain`操作即可。

  1.  const editor = monaco.editor.create(container, { 
  2.   language: 'php'
  3.   glyphMargin: true
  4.   lightbulb: { 
  5.     enabled: true
  6.   }, 
  7.   theme: 'vs-dark'
  8. }); 
  9.  
  10. editor.onDidChangeModelContent((e) => { 
  11.   const { changes } = e; 
  12.   let docLength = this.editor.getModel().getValueLength(); // 文檔長(zhǎng)度 
  13.   let operation = new TextOperation().retain(docLength); // 初始化一個(gè)operation,并保留文檔原始內(nèi)容 
  14.   for (let i = changes.length - 1; i >= 0; i--) { 
  15.       const change = changes[i]; 
  16.       const restLength = docLength - change.rangeOffset - change.text.length; // 文檔 
  17.       operation = new TextOperation() 
  18.         .retain(change.rangeOffset) // 保留光標(biāo)位置前的所有字符 
  19.         .delete(change.rangeLength) // 刪除N個(gè)字符(如為0這個(gè)操作無效) 
  20.         .insert(change.text) // 插入字符 
  21.         .retain(restLength) // 保留剩余字符 
  22.         .compose(operation); // 與初始o(jì)peration組合為一個(gè)操作 
  23. }); 

這段代碼首先創(chuàng)建了一個(gè)編輯器實(shí)例,監(jiān)聽了`onDidChangeModelContent`事件,遍歷changes數(shù)組,change.rangeOffset代表產(chǎn)生操作時(shí)的光標(biāo)位置,change.rangeLength代表刪除的字符長(zhǎng)度(為0即沒有刪除操作),restLength是根據(jù)文檔最終長(zhǎng)度 - 光標(biāo)位置 - 插入字符長(zhǎng)度得出,用于在文檔中間位置插入字符時(shí)保留剩余字符的操作。

但同時(shí)我們也要考慮到撤銷/重做,ot.js中對(duì)撤銷/重做的處理是每次編輯操作都需要產(chǎn)生對(duì)應(yīng)的`逆操作`,并存入撤銷/重做棧,在上面代碼的循環(huán)體中,我們還需要添加一個(gè)名為`inverse`的操作。

  1. let inverse = new TextOperation().retain(docLength); 
  2.  
  3. // 獲取刪除的字符,實(shí)現(xiàn)略 
  4. const removed = getRemovedText(change, this.documentBeforeChanged); 
  5.   inverse = inverse.compose( 
  6.     new TextOperation() 
  7.       .retain(change.rangeOffset) // 與編輯相同 
  8.       .delete(change.text.length) // 插入變?yōu)閯h除 
  9.       .insert(removed) // 刪除變?yōu)椴迦?/span> 
  10.       .retain(restLength); // 同樣保留剩余字符 

這樣就產(chǎn)生了一個(gè)編輯操作和一個(gè)用于撤銷的逆操作,編輯操作會(huì)發(fā)送到服務(wù)端進(jìn)行轉(zhuǎn)換同時(shí)再發(fā)送到給其他客戶端,逆操作保存在本地用于實(shí)現(xiàn)撤銷。

撤銷/重做的思路很簡(jiǎn)單,因?yàn)椴徽撊绾味紩?huì)對(duì)編輯器產(chǎn)成一個(gè)change事件,并且實(shí)時(shí)編輯的狀態(tài)下,兩個(gè)用戶的撤銷/重做棧需要互相獨(dú)立,也就是說A的操作不能進(jìn)入B的撤銷棧,因而在B執(zhí)行撤銷的時(shí)候只能對(duì)自己先前的操作產(chǎn)生影響,不能撤銷A的編輯,所以我們需要實(shí)現(xiàn)一個(gè)自定義的撤銷函數(shù)來覆蓋編輯器自帶的撤銷功能。

我們需要覆蓋默認(rèn)的撤銷

  1. this.editor.addAction({ 
  2.   id: 'cuctom_undo'
  3.   label: 'undo'
  4.   keybindings: [ 
  5.     monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_Z 
  6.   ], 
  7.   run: () => { 
  8.     this._undoFn() 
  9.   } 
  10. }) 

這里_undoFn的實(shí)現(xiàn)不再贅述,實(shí)際就是將先前change事件中產(chǎn)生的逆操作保存在一個(gè)自定義的undoManager中,每次執(zhí)行撤銷就undoStack.pop()拿出最近一次的操作并應(yīng)用在本地,同時(shí)發(fā)送給協(xié)作者,因?yàn)閡ndoManager中并未保存協(xié)作者的逆操作,所以執(zhí)行撤銷不會(huì)影響協(xié)作者的操作。

ot.js還包含了服務(wù)端的實(shí)現(xiàn),只需要將ot.js的服務(wù)端代碼運(yùn)行在nodejs中,同時(shí)搭建一個(gè)簡(jiǎn)單的websocket服務(wù)器即可。

  1. const EditorSocketIOServer = require('ot.js/socketio-server.js'); 
  2. const server = new EditorSocketIOServer("", [], 1); 
  3.  
  4. io.on('connection'function(socket) { 
  5.   server.addClient(socket); 
  6. }); 

服務(wù)端接收到每個(gè)協(xié)作者的operation并進(jìn)行轉(zhuǎn)換后下發(fā)到其他協(xié)作者客戶端,轉(zhuǎn)換操作實(shí)際是調(diào)用一個(gè)`transform`函數(shù),可以戳這里transform查看,實(shí)際上這個(gè)函數(shù)也正是OT技術(shù)的核心,由于時(shí)間有限,所以不再詳細(xì)解讀這個(gè)函數(shù)的源碼(逃隨著 Cloud Studio 的架構(gòu)升級(jí)和改進(jìn),我們正在準(zhǔn)備拋棄 OT 轉(zhuǎn)向 CRDT,所以等全部實(shí)現(xiàn)完成再來分享。

 

責(zé)任編輯:梁菲 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2021-09-15 14:53:35

在線文檔多人協(xié)作

2011-11-30 16:37:58

sync

2021-08-30 17:35:17

開發(fā)在線文檔多人協(xié)作

2022-06-16 15:54:32

前端

2016-10-18 20:50:00

android鎖屏App

2021-03-28 17:21:15

Git分支策略

2018-09-18 14:03:57

OpenStack知識(shí)難點(diǎn)

2019-03-21 09:12:06

CryptPad開源編輯器

2011-11-30 16:08:14

YC新銳Stypi

2011-11-30 15:57:18

2011-11-30 16:06:16

20個(gè)實(shí)用的在線協(xié)作

2022-03-04 09:02:01

StoryBoard工具git

2023-06-28 15:49:35

2025-01-20 00:35:00

vitestvite組件

2024-05-06 08:34:17

GolangGo程序

2024-03-14 09:07:05

刷數(shù)任務(wù)維度后端

2012-06-12 09:51:43

在線思維

2023-10-11 07:52:09

遍歷方式Java

2023-01-03 12:30:25

架構(gòu)CPUGPU
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美日韩一区在线观看 | 亚洲www啪成人一区二区麻豆 | 天天玩夜夜操 | 精品久久久精品 | 欧美日韩中文字幕在线播放 | 国产精品www | 精品久久久久久亚洲综合网 | 国产精品不卡 | 91精品国产91久久久久青草 | 国产免费视频 | 91麻豆精品国产91久久久久久 | 范冰冰一级做a爰片久久毛片 | 国产高清久久久 | 欧美日韩理论 | 中文字幕在线看第二 | h视频在线免费 | 一区二区三区精品在线 | 自拍偷拍亚洲视频 | 亚洲一区二区精品视频 | 国产精品视频一二三区 | av特级毛片 | 天天激情综合 | 免费的色网站 | 香蕉婷婷 | 91精品国产91久久久久青草 | 一级黄色淫片 | 18gay男同69亚洲网站 | 亚洲中午字幕 | 欧美视频免费在线 | 成人免费视频观看视频 | 欧美一级黑人aaaaaaa做受 | 91精品国产一区二区三区动漫 | 成人精品国产一区二区4080 | 亚洲69p | 亚洲国产成人精品一区二区 | 精品成人在线观看 | 国产精品久久久久久久久久免费看 | 五月婷婷 六月丁香 | 一区二区av| 成人亚洲 | 黄色网毛片 |