GOCollab
September 20, 2005
9月15号的The GNOME Journal上有了这篇,GOCollab — Peer to Peer Document Collaboration ,介绍了P2P和文档共享写作的结合--很酷--不光有新意,而且有解决实际问题的现实意义。
按我的传统,尽量介绍,胡乱评论。
在程序员中间,使用版本控制系统完成代码共享,合并与管理是很普遍的事情了,checkout,merge,checkin,update 都是熟悉的动作。
不过在其他领域,文档共享,或者协同写作,同样有很大的需求,却鲜有高效而且简单的解决方法。
目前大量使用的方法之一是利用track change,Microsoft Office 和 OpenSource 世界的AbiWord都支持这个功能,它可以记录每个作者输入,修改或者删除的内容。如果多人都要修改一份文档,可以先在各自的副本上工作,然后根据大家的track change一一合并--从本质上讲,这和程序员用的方法一样,不过恼火的是,纯文本的源代码是可以非常方便地由程序进行比较和合并的,文档就不行了,这个比较合并的活儿让人来干就辛苦了。
下一个版本的 GNOME Office 打算解决这个难题的方法是--GOCollab。GOCollab 将把Abiword/Gnumeric 已有的变更管理系统与类似 Gnutella/eMule 文件共享的 P2P 网络融合。这意味着一份文档无论有多少个作者,没有任何一个人需要一个中央服务器放置基准版本,没有任何一个人需要检查他人的改动并手工合并--来自所有人的修改都能自动合并。
基本使用
现在的GNOME Office 包括 AbiWord, Gnumeric 和GNOME-db(在整合和打品牌上,觉得GNMOE Office落后Koffice不少)。
在开始工作前,选择一个参与者的机器放置基准版本。未来的GOCollab 可能会提供这样的界面(尽管最终界面还没有确定):文件 菜单下的 ‘Offer Collaboration’ 和 ‘Join Collaboration’。显然,拥有基准版本的参与者选择Offer Collaboration即可。这时,可以认为这个参与者的机器就是collaboration server ,它允许其他人参与并开始在这份文档上协同写作。
其他参与者的操作当然就是从 文件 菜单下选择 Join Collaboration 了,好了,现在的问题是,如何找到提供者的机器。
目前有两种方法可以寻找和加入一台协作服务器:
1.直接指定IP/主机名。这是个传统方法。
2.用libHowl 搜索已提供的协作服务。LibHowl 允许通过Zeroconf multicast DNS service discovery浏览或发布服务。在VPN或可信赖IP域内,这个方法也可用。
一旦新参与者期望加入,提供基准版本的参与者可以选择接受或者拒绝加入者的请求。
双发(并且以后扩展到多方)连接建立以后,协作服务器将把基准版本压缩为gzip的XML文件传递给客户端(AbiWord是.zabw,Gnumeric是.gnumeric )。一个新的远程文档视图会被创建,用户可以开始各自编辑了。当然,这个“远程”实际是“本地”的。在每个参与者的电脑上,Nautilus 都会显示这个文件,你可以打开,保存它,没什么特别。真正特别的是,参与者相互都看得到其他人的修改,在大家的电脑上,他们各自的文档总是一样的--什么,你在说多人同时修改同一处的问题仍然无法避免?年轻人不要着急,看到后面就知道了。
任何加入协作的一方可以再允许其他人加入,协作可以无限扩充。
实现
Abiword 和 Gnumeric 在创建文档的时候都提供了一种叫做Model-View-Controller (MVC) paradigm的技术。
Model – View – Controller 模式是组织原始内容的一种方法。Model 是软件对内容(也就是文档)的内部表示,View 负责内部表示如何被呈现,Controller 负责管理 Model 的改变(听上去有一点熟悉,对不对?;-P )--当然,每个软件对MVC的实现都可能不同。
Abiword通过ChangeRecord 对象记录对Model的改变。一系列的ChangeRecords 记录了用户对文档的修改。Gnumeric 也类似,不过把改变叫做Cmd--我承认,这个名字也够烂的。我们可以说,Abiword 和 Gnumeric 在内部,就像一个变更管理系统一样工作。换句话说,两个软件都不直接对文档“内容”动手动脚,他们只是知道如何“操作”这个文档--他们看不到类似“我爱你”这样的文档内容,他们眼里只有类似“在第一行第一列输入‘我’,右移一字符,输入‘爱’,右移一字符,输入‘你’”这样一个操作序列。用户通过菜单,工具栏,快捷键施加的所有操作都是这样记录下来的,而有了这个操作序列,AbiWord和Gnumeric就可以随意地生成文档了。
人类当然接受不了这样的模式,我们只能,也必须面向最终的“内容”。所以,一个叫做 Listener 的东西就被attach 到了每个Model上。他们把ChangeRecords转换为磁盘上的物理文件--或者在屏幕上显示出来的可见内容。无论何时,用户的命令引起的一连串台前幕后的动作都是:创建对应的ChangeRecord,应用解释该变更,建立文档的新版本,在显示器上显示,或者在磁盘上存储。
好了,大道理也说完了,很明显,现在需要的,就是对 ChangeRecord 或者 Cmd 作出一点改变--一个堪称 我的一小步,人类的一大步 的改变 -- 将变更通过网络发送到其他参与协作的电脑上。接受者抓住网络上传来的的 ChangeRecord/Cmd ,将其应用到自己操作的文档的对应位置上即可。
实际上AbiWord 里已经有类似的东西了--translators ,它就是用来接受ChangeRecord 然后应用到文档的--猜猜是什么应用?
……剪贴板。显然,粘贴的时候,是translators接受了输入,然后在当前位置应用了这些改变。好了,各位,从这个实例我们看到什么呢?第一,剪贴板中不是纯内容型的数据,仍然是ChangeRecord式的动作列表;第二,搭好架构真TMD的重要啊。欢迎各位将其他心得留言,谢谢。
总结一下,新的GOCollab 将提供两个主要功能:一方面提供 Listener 和 Translator 向网络发送或者从网络接受包;另一方面,提供一个P2P网络传输这些包,构建协作环境。
一个诡异但是不能回避的问题是:如何应对网络延迟。多个参与者之间的文档可能因为不确定的网络延迟而变得不同步。比如,这样的问题--也就是你在前面提到的多人同时修改同一处的问题--Bob在文档最后加了一个字,这个动作生成了一个ChangeRecord,并且通过网络向协作者Jane传递,然而由于网络延迟,这个动作需要一段较长的时间;与此同时,Jane也在文档最后输入了一个字,同样地,生成了自己的ChangeRecord--显然,这会发生冲突(咳,就是本质意义上和OS讨论的竞争条件类似嘛……)。
解决方法,不好意思,非常简单,每个ChangeRecord(当然他们都包含了位置信息)都会获得一个不断增长的唯一ID。一篇文档其实就要由编号为1,2,3,4,5等等的ChangeRecord组成。通过传递包含了位置信息的ChangeRecord及其标号,Jane的AbiWord就可以知道Bob在
同样的地方做了修改,这是一个--冲突。
那么,最终结果?显示内容目前会是:把Bob的输入会放到Jane的输入之后,让Jane知晓Bob修改--软件并不能解决人引入的冲突,它能明显的标识和记录冲突,在显示地标注冲突之后,Jane和Bob可以商量以谁的修改为准(或者共同商议一个新修改),这样的动作,因为冲突自动管理和显示而简单得多了--这就相当于自动合并。
展望
GOCollab 引入了一种新的互连和写作方法。文档变更能自动向网络上的连接协作者发送。
目前,GOCollab 已经作为AbiWord的一个spec和基本插件存在。用于传输包的网络代码可以其他软件复用。冲突管理算法已经有一个Python原型。下一个稳定版本的AbiWord 和 Gnumeric 将随着GNOME-2.12 的发布而发布。
努力,奋斗。
Tags: BabyBus