@@ -75,62 +75,7 @@ export class YjsService
7575 // 노드를 클릭해 페이지를 열었을 때만 해당 페이지 값을 가져와서 초기 데이터로 세팅해줍니다.
7676 if ( customDoc . name ?. startsWith ( 'document-' ) ) {
7777 const pageId = parseInt ( customDoc . name . split ( '-' ) [ 1 ] ) ;
78-
79- // 초기 세팅할 page content
80- let pageContent : JSON ;
81- try {
82- const findPage = await this . pageService . findPageById ( pageId ) ;
83- pageContent = JSON . parse ( JSON . stringify ( findPage . content ) ) ;
84- } catch ( exception ) {
85- // 에러 스택 출력
86- this . logger . error ( exception . stack ) ;
87-
88- // 만약 존재하지 않는 페이지에 접근한다면 비어있는 content를 전달한다.
89- if ( exception instanceof PageNotFoundException ) {
90- pageContent = JSON . parse ( '{}' ) ;
91- return ;
92- }
93-
94- throw exception ;
95- }
96-
97- // content가 비어있다면 내부 구조가 novel editor schema를 따르지 않기 때문에 오류가 납니다.
98- // content가 존재할 때만 넣어줍니다.
99- // const pageContent = JSON.parse(JSON.stringify(findPage.content));
100- // const novelEditorContent = {
101- // type: 'doc',
102- // content: pageContent,
103- // };
104-
105- if ( Object . keys ( pageContent ) . length > 0 ) {
106- this . transformText ( pageContent ) ;
107- // this.logger.error(this.transformText(pageContent));
108- this . initializePageContent ( pageContent , editorDoc ) ;
109- }
110- // JSON.parse(findPage.content).length > 0 &&
111-
112- // 페이지 내용 변경 사항을 감지해서 데이터베이스에 갱신합니다.
113- editorDoc . observeDeep ( ( ) => {
114- const document = editorDoc . doc as CustomDoc ;
115- const pageId = parseInt ( document . name . split ( '-' ) [ 1 ] ) ;
116-
117- this . redisService . setField (
118- `page:${ pageId . toString ( ) } ` ,
119- 'content' ,
120- JSON . stringify ( yXmlFragmentToProsemirrorJSON ( editorDoc ) ) ,
121-
122- ) ;
123-
124- // this.redisService.setField(
125- // pageId.toString(),
126- // 'content',
127- // JSON.stringify(yXmlFragmentToProsemirrorJSON(editorDoc)),
128- // );
129- // this.redisService.get(pageId.toString()).then((data) => {
130- // console.log(data);
131- // });
132- } ) ;
133- return ;
78+ this . initializePage ( pageId , editorDoc ) ;
13479 }
13580
13681 // 만약 페이지가 아닌 모든 노드들을 볼 수 있는 document라면 node, edge 초기 데이터를 세팅해줍니다.
@@ -142,96 +87,147 @@ export class YjsService
14287 return ;
14388 }
14489
145- // const workspaceId = customDoc.name.split('-')[2];
146- // console.log('======', workspaceId);
14790 const workspaceId = 'main' ;
148- const nodes = await this . nodeService . findNodesByWorkspace ( workspaceId ) ;
149- const edges = await this . edgeService . findEdgesByWorkspace ( workspaceId ) ;
150- const nodesMap = doc . getMap ( 'nodes' ) ;
151- const title = doc . getMap ( 'title' ) ;
152- const emoji = doc . getMap ( 'emoji' ) ;
153- const edgesMap = doc . getMap ( 'edges' ) ;
154-
155- this . initializeYNodeMap ( nodes , nodesMap , title , emoji ) ;
156- this . initializeYEdgeMap ( edges , edgesMap ) ;
157-
158- // title의 변경 사항을 감지한다.
159- title . observeDeep ( async ( event ) => {
160- // path가 존재할 때만 페이지 갱신
161-
162- event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] &&
163- this . redisService . setField (
164- `page:${ event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] } ` ,
165- 'title' ,
166- event [ 0 ] . target . toString ( ) ,
91+ this . initializeWorkspace ( workspaceId , doc ) ;
92+ } ) ;
93+ }
16794
168- ) ;
169- // this.redisService.setField(
170- // event[0].path.toString().split('_')[1],
171- // 'title',
172- // event[0].target.toString(),
173- // );
174- } ) ;
175- emoji . observeDeep ( ( event ) => {
176- // path가 존재할 때만 페이지 갱신
177- event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] &&
178- this . pageService . updatePage (
179- parseInt ( event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] ) ,
180- {
181- emoji : event [ 0 ] . target . toString ( ) ,
182- } ,
183- ) ;
184- } ) ;
185- // node의 변경 사항을 감지한다.
186- nodesMap . observe ( async ( event ) => {
187- for ( const [ key , change ] of event . changes . keys ) {
188- if ( change . action === 'update' ) {
189- const node : any = nodesMap . get ( key ) ;
190- if ( node . type !== 'note' ) {
191- continue ;
192- }
193-
194- // node.data는 페이지에 대한 정보
195- const { title, id } = node . data ;
196- const { x, y } = node . position ;
197- const isHolding = node . isHolding ;
198- if ( ! isHolding ) {
199- // TODO : node의 경우 key 값을 page id가 아닌 node id로 변경
200- const findPage = await this . pageService . findPageById ( id ) ;
201- await this . nodeService . updateNode ( findPage . node . id , {
202- title,
203- x,
204- y,
205- } ) ;
206- }
95+ // yXmlFragment에 content를 넣어준다.
96+ private async initializePage ( pageId : number , editorDoc : Y . XmlFragment ) {
97+ // 초기 세팅할 page content
98+ let pageContent : JSON ;
99+ try {
100+ const findPage = await this . pageService . findPageById ( pageId ) ;
101+ pageContent = JSON . parse ( JSON . stringify ( findPage . content ) ) ;
102+ } catch ( exception ) {
103+ // 에러 스택 출력
104+ this . logger . error ( exception . stack ) ;
105+
106+ // 만약 존재하지 않는 페이지에 접근한다면 비어있는 content를 전달한다.
107+ if ( exception instanceof PageNotFoundException ) {
108+ pageContent = JSON . parse ( '{}' ) ;
109+ return ;
110+ }
111+
112+ throw exception ;
113+ }
114+
115+ // content가 비어있다면 내부 구조가 novel editor schema를 따르지 않기 때문에 오류가 납니다.
116+ // content가 존재할 때만 넣어줍니다.
117+ if ( Object . keys ( pageContent ) . length > 0 ) {
118+ this . transformText ( pageContent ) ;
119+ // this.logger.error(this.transformText(pageContent));
120+ prosemirrorJSONToYXmlFragment ( novelEditorSchema , pageContent , editorDoc ) ;
121+ }
122+
123+ // 페이지 내용 변경 사항을 감지해서 데이터베이스에 갱신합니다.
124+ editorDoc . observeDeep ( ( ) => {
125+ const document = editorDoc . doc as CustomDoc ;
126+ const pageId = parseInt ( document . name . split ( '-' ) [ 1 ] ) ;
127+
128+ this . redisService . setField (
129+ `page:${ pageId . toString ( ) } ` ,
130+ 'content' ,
131+ JSON . stringify ( yXmlFragmentToProsemirrorJSON ( editorDoc ) ) ,
132+ ) ;
133+ } ) ;
134+ return ;
135+ }
136+
137+ handleConnection ( ) {
138+ this . logger . log ( '접속' ) ;
139+ }
140+
141+ handleDisconnect ( ) {
142+ this . logger . log ( '접속 해제' ) ;
143+ }
144+
145+
146+ /**
147+ * initialize 관련 메소드
148+ */
149+ private async initializeWorkspace ( workspaceId : string , doc : Y . Doc ) {
150+ // const workspaceId = customDoc.name.split('-')[2];
151+ // console.log('======', workspaceId);
152+ const nodes = await this . nodeService . findNodesByWorkspace ( workspaceId ) ;
153+ const edges = await this . edgeService . findEdgesByWorkspace ( workspaceId ) ;
154+ const nodesMap = doc . getMap ( 'nodes' ) ;
155+ const title = doc . getMap ( 'title' ) ;
156+ const emoji = doc . getMap ( 'emoji' ) ;
157+ const edgesMap = doc . getMap ( 'edges' ) ;
158+
159+ this . initializeYNodeMap ( nodes , nodesMap , title , emoji ) ;
160+ this . initializeYEdgeMap ( edges , edgesMap ) ;
161+
162+ // title의 변경 사항을 감지한다.
163+ title . observeDeep ( async ( event ) => {
164+ // path가 존재할 때만 페이지 갱신
165+
166+ event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] &&
167+ this . redisService . setField (
168+ `page:${ event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] } ` ,
169+ 'title' ,
170+ event [ 0 ] . target . toString ( ) ,
171+ ) ;
172+ } ) ;
173+ emoji . observeDeep ( ( event ) => {
174+ // path가 존재할 때만 페이지 갱신
175+ event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] &&
176+ this . pageService . updatePage (
177+ parseInt ( event [ 0 ] . path . toString ( ) . split ( '_' ) [ 1 ] ) ,
178+ {
179+ emoji : event [ 0 ] . target . toString ( ) ,
180+ } ,
181+ ) ;
182+ } ) ;
183+ // node의 변경 사항을 감지한다.
184+ nodesMap . observe ( async ( event ) => {
185+ for ( const [ key , change ] of event . changes . keys ) {
186+ if ( change . action === 'update' ) {
187+ const node : any = nodesMap . get ( key ) ;
188+ if ( node . type !== 'note' ) {
189+ continue ;
190+ }
191+
192+ // node.data는 페이지에 대한 정보
193+ const { title, id } = node . data ;
194+ const { x, y } = node . position ;
195+ const isHolding = node . isHolding ;
196+ if ( ! isHolding ) {
197+ // TODO : node의 경우 key 값을 page id가 아닌 node id로 변경
198+ const findPage = await this . pageService . findPageById ( id ) ;
199+ await this . nodeService . updateNode ( findPage . node . id , {
200+ title,
201+ x,
202+ y,
203+ } ) ;
207204 }
208205 }
209- } ) ;
206+ }
207+ } ) ;
210208
211- // edge의 변경 사항을 감지한다.
212- edgesMap . observe ( async ( event ) => {
213- for ( const [ key , change ] of event . changes . keys ) {
214- if ( change . action === 'add' ) {
215- const edge = edgesMap . get ( key ) as YMapEdge ;
216- const findEdge = await this . edgeService . findEdgeByFromNodeAndToNode (
217- parseInt ( edge . source ) ,
218- parseInt ( edge . target ) ,
219- ) ;
220- // 연결된 노드가 없을 때만 edge 생성
221- if ( ! findEdge ) {
222- await this . edgeService . createEdge ( {
223- fromNode : parseInt ( edge . source ) ,
224- toNode : parseInt ( edge . target ) ,
225- } ) ;
226- }
209+ // edge의 변경 사항을 감지한다.
210+ edgesMap . observe ( async ( event ) => {
211+ for ( const [ key , change ] of event . changes . keys ) {
212+ if ( change . action === 'add' ) {
213+ const edge = edgesMap . get ( key ) as YMapEdge ;
214+ const findEdge = await this . edgeService . findEdgeByFromNodeAndToNode (
215+ parseInt ( edge . source ) ,
216+ parseInt ( edge . target ) ,
217+ ) ;
218+ // 연결된 노드가 없을 때만 edge 생성
219+ if ( ! findEdge ) {
220+ await this . edgeService . createEdge ( {
221+ fromNode : parseInt ( edge . source ) ,
222+ toNode : parseInt ( edge . target ) ,
223+ } ) ;
227224 }
228225 }
229- } ) ;
226+ }
230227 } ) ;
231228 }
232-
233229 // YMap에 노드 정보를 넣어준다.
234- initializeYNodeMap (
230+ private initializeYNodeMap (
235231 nodes : Node [ ] ,
236232 yNodeMap : Y . Map < unknown > ,
237233 yTitleMap : Y . Map < unknown > ,
@@ -279,7 +275,7 @@ export class YjsService
279275 }
280276
281277 // yMap에 edge 정보를 넣어준다.
282- initializeYEdgeMap ( edges : Edge [ ] , yMap : Y . Map < unknown > ) : void {
278+ private initializeYEdgeMap ( edges : Edge [ ] , yMap : Y . Map < unknown > ) : void {
283279 edges . forEach ( ( edge ) => {
284280 const edgeId = edge . id . toString ( ) ; // id를 string으로 변환
285281
@@ -294,18 +290,23 @@ export class YjsService
294290 } ) ;
295291 }
296292
297- // yXmlFragment에 content를 넣어준다.
298- initializePageContent ( content : JSON , yXmlFragment : Y . XmlFragment ) {
299- prosemirrorJSONToYXmlFragment ( novelEditorSchema , content , yXmlFragment ) ;
293+ /**
294+ * event listener 관련
295+ */
296+ private observeTitle ( ) {
297+
300298 }
301299
302- handleConnection ( ) {
303- this . logger . log ( '접속' ) ;
300+ private observeEmoji ( ) {
301+
302+ }
303+ private observeContent ( ) {
304+
304305 }
305306
306307 // editor에서 paragraph 내부 text 노드의 text 값의 빈 문자열을 제거한다.
307308 // text 값이 빈 문자열이면 empty text nodes are not allowed 에러가 발생합니다.
308- transformText ( doc : any ) {
309+ private transformText ( doc : any ) {
309310 doc . content . forEach ( ( paragraph ) => {
310311 if ( paragraph . type === 'paragraph' && Array . isArray ( paragraph . content ) ) {
311312 paragraph . content . forEach ( ( textNode ) => {
@@ -316,7 +317,4 @@ export class YjsService
316317 }
317318 } ) ;
318319 }
319- handleDisconnect ( ) {
320- this . logger . log ( '접속 해제' ) ;
321- }
322320}
0 commit comments