1- import { OperationSource , type EBoard , type ElementService , type ModelChangeEvent , type ModelService } from "@e-board/board-core" ;
1+ import { type EBoard , type ElementService , type ModelChangeEvent , type ModelService } from "@e-board/board-core" ;
22import { WebSocketProvider , MsgType } from '@e-board/board-websocket' ;
3+ import { operationManager } from "./operation/transform" ;
34const WS_URL = 'ws://localhost:3010/collaboration' ; // TODO: 这个配置应该放到app初始化时作为配置传入
45
56class BoardCollaboration {
@@ -9,110 +10,64 @@ class BoardCollaboration {
910 private disposeList : ( ( ) => void ) [ ] = [ ] ;
1011 private currentUserid = `user-${ Math . floor ( Math . random ( ) * 1000 ) } ` ;
1112 constructor ( private board : EBoard ) {
12-
1313 this . modelService = board . getService ( 'modelService' )
1414 this . elementService = this . board . getService ( 'elementService' )
15-
1615 this . init ( )
1716 }
1817
1918 private init = ( ) => {
2019 this . websocketProvider = new WebSocketProvider ( ) ;
20+ this . initRemoteConnection ( ) ;
21+ this . initLocalSubscription ( ) ;
22+ }
23+
24+ private initRemoteConnection = ( ) => {
2125 try {
22- this . websocketProvider . connect ( WS_URL ) ;
23- this . websocketProvider . onMessage ( ( data ) => {
24- console
26+ this . websocketProvider ?. connect ( WS_URL ) ;
27+ this . websocketProvider ?. onMessage ( ( data ) => {
2528 if ( data . type === MsgType . OPERATION ) {
2629 if ( data . senderId === this . currentUserid ) return ; // 忽略自己发送的消息
27- const operation = JSON . parse ( data . data )
28- // 外存模型转内存模型
29- if ( operation . operation === 'create' ) {
30- const element = this . elementService . getElement ( operation . model . type ) ;
31- if ( ! element ) throw new Error ( `Unregistered element type: ${ operation . model . type } ` ) ;
32- const saveInfoService = this . board . getService ( 'saveInfoService' )
33- saveInfoService . importSaveInfo ( operation . model , OperationSource . REMOTE )
34- } else if ( operation . operation === 'update' ) {
35- const modelId = operation . modelId ;
36- // 获取type
37- const model = this . modelService . getModelById ( modelId ) ;
38- const type = model ?. type ;
39- if ( ! type ) throw new Error ( 'Operation missing type' ) ;
40- const element = this . elementService . getElement ( type ) ;
41- if ( ! element ) throw new Error ( `Unregistered element type: ${ type } ` ) ;
42- this . modelService . updateModel ( model . id , operation . updates , OperationSource . REMOTE )
43- } else if ( operation . operation === 'delete' ) {
44-
45- operation . data . deletedModels . forEach ( ( m : any ) => {
46- const element = this . elementService . getElement ( m . type ) ;
47- if ( ! element ) throw new Error ( `Unregistered element type: ${ m . type } ` ) ;
48- const model = element . saveInfoProvider . importSaveInfo ( m )
49- this . modelService . deleteModel ( model . id , OperationSource . REMOTE )
50- } )
30+ const operationData = JSON . parse ( data . data )
31+ const handler = operationManager . getHandler ( operationData . operation ) ;
32+ if ( handler ) {
33+ handler . handleRemote ( {
34+ data : operationData ,
35+ board : this . board ,
36+ modelService : this . modelService ,
37+ elementService : this . elementService
38+ } ) ;
5139 } else {
52- throw new Error ( `Unsupported operation type: ${ operation . operation } ` ) ;
40+ throw new Error ( `Unsupported operation type: ${ operationData . operation } ` ) ;
5341 }
5442 }
55-
5643 } )
5744 } catch ( err ) {
5845 console . error ( 'WebSocket 连接失败:' , err ) ;
5946 }
47+ }
6048
61-
49+ private initLocalSubscription = ( ) => {
6250 const { dispose } = this . modelService . onModelOperation (
6351 ( operation : ModelChangeEvent ) => {
64-
65- const body : any = {
66- type : MsgType . OPERATION ,
67- id : `msg-${ Date . now ( ) } ` ,
68- senderId : this . currentUserid ,
69- timestamp : Date . now ( )
70- }
7152 if ( operation . operationSource === 'remote' ) return ; // 忽略远程操作,防止循环广播
7253
73- // 内存模型转外存模型
74- if ( operation . type === 'create' ) {
75-
76- const type = operation . model ?. type
77- if ( ! type ) throw new Error ( 'Operation missing type' ) ;
78- const element = this . elementService . getElement ( type ) ;
79- if ( ! element ) throw new Error ( `Unregistered element type: ${ type } ` ) ;
80-
81-
82-
83- body . data = JSON . stringify ( { operation : 'create' , model : element . saveInfoProvider . parse ( operation . model ) } )
84- } else if ( operation . type === 'update' ) {
85- const modelId = operation . modelId ;
86- // 获取type
87- const model = this . modelService . getModelById ( modelId ) ;
88- const type = model ?. type ;
89- if ( ! type ) throw new Error ( 'Operation missing type' ) ;
90- const element = this . elementService . getElement ( type ) ;
91- if ( ! element ) throw new Error ( `Unregistered element type: ${ type } ` ) ;
92-
93- body . data = JSON . stringify ( {
94- operation : 'update' ,
95- updates : element . saveInfoProvider . parse ( operation . updates ) ,
96- previousState : element . saveInfoProvider . parse ( operation . previousState ) ,
97- modelId : operation . modelId
98- } )
99- } else if ( operation . type === 'delete' ) {
100- body . data = JSON . stringify ( {
101- operation : 'delete' ,
102- deletedModels : Array . from ( operation . deletedModels ?. values ( ) || [ ] ) . map ( m => {
103- const type = m ?. type ;
104- if ( ! type ) throw new Error ( 'Operation missing type' ) ;
105- const element = this . elementService . getElement ( type ) ;
106- if ( ! element ) throw new Error ( `Unregistered element type: ${ type } ` ) ;
107- return element . saveInfoProvider . parse ( m ) ;
108- } ) ,
109- modelId : operation . modelId
110- } )
111- } else {
112- throw new Error ( `Unsupported operation type: ${ operation . type } ` ) ;
54+ const handler = operationManager . getHandler ( operation . type ) ;
55+ if ( handler ) {
56+ const payload = handler . handleLocal ( {
57+ operation,
58+ board : this . board ,
59+ modelService : this . modelService ,
60+ elementService : this . elementService
61+ } ) ;
62+ const body : any = {
63+ type : MsgType . OPERATION ,
64+ id : `msg-${ Date . now ( ) } ` ,
65+ senderId : this . currentUserid ,
66+ timestamp : Date . now ( ) ,
67+ data : JSON . stringify ( payload )
68+ }
69+ this . websocketProvider ?. send ( body )
11370 }
114- this . websocketProvider ?. send ( body )
115- console . log ( 'Received operation:' , operation ) ;
11671 }
11772 )
11873 this . disposeList . push ( dispose ) ;
0 commit comments