mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-20 23:32:14 +00:00
UBERF-8547 Do not update collaborative doc in platform when content not changed (#7115)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
parent
aa4eaeae84
commit
afa485deb1
@ -14,7 +14,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { DocumentId } from '@hcengineering/collaborator-client'
|
import { DocumentId } from '@hcengineering/collaborator-client'
|
||||||
import { MeasureContext } from '@hcengineering/core'
|
import { type Markup, MeasureContext } from '@hcengineering/core'
|
||||||
import {
|
import {
|
||||||
Document,
|
Document,
|
||||||
Extension,
|
Extension,
|
||||||
@ -37,19 +37,35 @@ export interface StorageConfiguration {
|
|||||||
transformer: Transformer
|
transformer: Transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DocumentName = string
|
||||||
|
|
||||||
|
type ConnectionId = string
|
||||||
|
|
||||||
|
interface DocumentUpdates {
|
||||||
|
context: Context
|
||||||
|
collaborators: Set<ConnectionId>
|
||||||
|
}
|
||||||
|
|
||||||
export class StorageExtension implements Extension {
|
export class StorageExtension implements Extension {
|
||||||
private readonly configuration: StorageConfiguration
|
private readonly configuration: StorageConfiguration
|
||||||
private readonly collaborators = new Map<string, Set<string>>()
|
private readonly updates = new Map<DocumentName, DocumentUpdates>()
|
||||||
private readonly markups = new Map<string, Record<string, string>>()
|
private readonly markups = new Map<DocumentName, Record<Markup, Markup>>()
|
||||||
|
|
||||||
constructor (configuration: StorageConfiguration) {
|
constructor (configuration: StorageConfiguration) {
|
||||||
this.configuration = configuration
|
this.configuration = configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
async onChange ({ context, documentName }: withContext<onChangePayload>): Promise<any> {
|
async onChange ({ context, documentName }: withContext<onChangePayload>): Promise<any> {
|
||||||
const collaborators = this.collaborators.get(documentName) ?? new Set()
|
const { connectionId } = context
|
||||||
collaborators.add(context.connectionId)
|
|
||||||
this.collaborators.set(documentName, collaborators)
|
const updates = this.updates.get(documentName)
|
||||||
|
if (updates === undefined) {
|
||||||
|
const collaborators = new Set([connectionId])
|
||||||
|
this.updates.set(documentName, { context, collaborators })
|
||||||
|
} else {
|
||||||
|
updates.context = context
|
||||||
|
updates.collaborators.add(connectionId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onLoadDocument ({ context, documentName }: withContext<onLoadDocumentPayload>): Promise<any> {
|
async onLoadDocument ({ context, documentName }: withContext<onLoadDocumentPayload>): Promise<any> {
|
||||||
@ -59,7 +75,7 @@ export class StorageExtension implements Extension {
|
|||||||
return await this.loadDocument(documentName, context)
|
return await this.loadDocument(documentName, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
async afterLoadDocument ({ context, documentName, document }: withContext<afterLoadDocumentPayload>): Promise<any> {
|
async afterLoadDocument ({ documentName, document }: withContext<afterLoadDocumentPayload>): Promise<any> {
|
||||||
// remember the markup for the document
|
// remember the markup for the document
|
||||||
this.markups.set(documentName, this.configuration.transformer.fromYdoc(document))
|
this.markups.set(documentName, this.configuration.transformer.fromYdoc(document))
|
||||||
}
|
}
|
||||||
@ -70,14 +86,14 @@ export class StorageExtension implements Extension {
|
|||||||
|
|
||||||
ctx.info('store document', { documentName, connectionId })
|
ctx.info('store document', { documentName, connectionId })
|
||||||
|
|
||||||
const collaborators = this.collaborators.get(documentName)
|
const updates = this.updates.get(documentName)
|
||||||
if (collaborators === undefined || collaborators.size === 0) {
|
if (updates === undefined || updates.collaborators.size === 0) {
|
||||||
ctx.info('no changes for document', { documentName, connectionId })
|
ctx.info('no changes for document', { documentName, connectionId })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collaborators.delete(documentName)
|
this.updates.delete(documentName)
|
||||||
await this.storeDocument(documentName, document, context)
|
await this.storeDocument(documentName, document, updates.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
async onConnect ({ context, documentName, instance }: withContext<onConnectPayload>): Promise<any> {
|
async onConnect ({ context, documentName, instance }: withContext<onConnectPayload>): Promise<any> {
|
||||||
@ -93,19 +109,19 @@ export class StorageExtension implements Extension {
|
|||||||
const params = { documentName, connectionId, connections: document.getConnectionsCount() }
|
const params = { documentName, connectionId, connections: document.getConnectionsCount() }
|
||||||
ctx.info('disconnect from document', params)
|
ctx.info('disconnect from document', params)
|
||||||
|
|
||||||
const collaborators = this.collaborators.get(documentName)
|
const updates = this.updates.get(documentName)
|
||||||
if (collaborators === undefined || !collaborators.has(connectionId)) {
|
if (updates === undefined || updates.collaborators.size === 0) {
|
||||||
ctx.info('no changes for document', { documentName, connectionId })
|
ctx.info('no changes for document', { documentName, connectionId })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collaborators.delete(documentName)
|
this.updates.delete(documentName)
|
||||||
await this.storeDocument(documentName, document, context)
|
await this.storeDocument(documentName, document, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
async afterUnloadDocument ({ documentName }: afterUnloadDocumentPayload): Promise<any> {
|
async afterUnloadDocument ({ documentName }: afterUnloadDocumentPayload): Promise<any> {
|
||||||
this.configuration.ctx.info('unload document', { documentName })
|
this.configuration.ctx.info('unload document', { documentName })
|
||||||
this.collaborators.delete(documentName)
|
this.updates.delete(documentName)
|
||||||
this.markups.delete(documentName)
|
this.markups.delete(documentName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ export async function updateContent (
|
|||||||
fragment.delete(0, fragment.length)
|
fragment.delete(0, fragment.length)
|
||||||
applyUpdate(document, update)
|
applyUpdate(document, update)
|
||||||
})
|
})
|
||||||
})
|
}, connection)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -34,6 +34,7 @@ import { Doc as YDoc } from 'yjs'
|
|||||||
import { Context } from '../context'
|
import { Context } from '../context'
|
||||||
|
|
||||||
import { CollabStorageAdapter } from './adapter'
|
import { CollabStorageAdapter } from './adapter'
|
||||||
|
import { areEqualMarkups } from '@hcengineering/text'
|
||||||
|
|
||||||
export class PlatformStorageAdapter implements CollabStorageAdapter {
|
export class PlatformStorageAdapter implements CollabStorageAdapter {
|
||||||
constructor (private readonly storage: StorageAdapter) {}
|
constructor (private readonly storage: StorageAdapter) {}
|
||||||
@ -156,6 +157,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { objectClass, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
|
const { objectClass, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
|
||||||
|
|
||||||
|
const currMarkup = markup.curr[objectAttr]
|
||||||
|
const prevMarkup = markup.prev[objectAttr]
|
||||||
|
|
||||||
|
if (areEqualMarkups(currMarkup, prevMarkup)) {
|
||||||
|
ctx.info('markup not changed, skip platform update', { documentName })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const attribute = client.getHierarchy().findAttribute(objectClass, objectAttr)
|
const attribute = client.getHierarchy().findAttribute(objectClass, objectAttr)
|
||||||
if (attribute === undefined) {
|
if (attribute === undefined) {
|
||||||
ctx.warn('attribute not found', { documentName, objectClass, objectAttr })
|
ctx.warn('attribute not found', { documentName, objectClass, objectAttr })
|
||||||
@ -192,8 +201,8 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
|
|||||||
attributeUpdates: {
|
attributeUpdates: {
|
||||||
attrKey: objectAttr,
|
attrKey: objectAttr,
|
||||||
attrClass: core.class.TypeMarkup,
|
attrClass: core.class.TypeMarkup,
|
||||||
prevValue: markup.prev[objectAttr],
|
prevValue: prevMarkup,
|
||||||
set: [markup.curr[objectAttr]],
|
set: [currMarkup],
|
||||||
added: [],
|
added: [],
|
||||||
removed: [],
|
removed: [],
|
||||||
isMixin: hierarchy.isMixin(objectClass)
|
isMixin: hierarchy.isMixin(objectClass)
|
||||||
|
Loading…
Reference in New Issue
Block a user