mirror of
https://github.com/hcengineering/platform.git
synced 2025-03-26 01:40:50 +00:00
204 lines
4.8 KiB
TypeScript
204 lines
4.8 KiB
TypeScript
import core, {
|
|
WorkspaceEvent,
|
|
generateId,
|
|
getTypeOf,
|
|
type BulkUpdateEvent,
|
|
type Class,
|
|
type Doc,
|
|
type FullParamsType,
|
|
type MeasureContext,
|
|
type ParamsType,
|
|
type Ref,
|
|
type TxWorkspaceEvent,
|
|
type WorkspaceIdWithUrl,
|
|
type Branding,
|
|
type BrandingMap
|
|
} from '@hcengineering/core'
|
|
import { type Hash } from 'crypto'
|
|
import fs from 'fs'
|
|
import type { SessionContext } from './types'
|
|
|
|
/**
|
|
* Return some estimation for object size
|
|
*/
|
|
export function estimateDocSize (_obj: any): number {
|
|
let result = 0
|
|
const toProcess = [_obj]
|
|
while (toProcess.length > 0) {
|
|
const obj = toProcess.shift()
|
|
if (typeof obj === 'undefined') {
|
|
continue
|
|
}
|
|
if (typeof obj === 'function') {
|
|
continue
|
|
}
|
|
for (const key in obj) {
|
|
// include prototype properties
|
|
const value = obj[key]
|
|
const type = getTypeOf(value)
|
|
result += key.length
|
|
|
|
switch (type) {
|
|
case 'Array':
|
|
result += 4
|
|
toProcess.push(value)
|
|
break
|
|
case 'Object':
|
|
toProcess.push(value)
|
|
break
|
|
case 'Date':
|
|
result += 24 // Some value
|
|
break
|
|
case 'string':
|
|
result += (value as string).length
|
|
break
|
|
case 'number':
|
|
result += 8
|
|
break
|
|
case 'boolean':
|
|
result += 1
|
|
break
|
|
case 'symbol':
|
|
result += (value as symbol).toString().length
|
|
break
|
|
case 'bigint':
|
|
result += (value as bigint).toString().length
|
|
break
|
|
case 'undefined':
|
|
result += 1
|
|
break
|
|
case 'null':
|
|
result += 1
|
|
break
|
|
default:
|
|
result += value.toString().length
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
/**
|
|
* Return some estimation for object size
|
|
*/
|
|
export function updateHashForDoc (hash: Hash, _obj: any): void {
|
|
const toProcess = [_obj]
|
|
while (toProcess.length > 0) {
|
|
const obj = toProcess.shift()
|
|
if (typeof obj === 'undefined') {
|
|
continue
|
|
}
|
|
if (typeof obj === 'function') {
|
|
continue
|
|
}
|
|
for (const key in obj) {
|
|
// include prototype properties
|
|
const value = obj[key]
|
|
const type = getTypeOf(value)
|
|
hash.update(key)
|
|
|
|
switch (type) {
|
|
case 'Array':
|
|
toProcess.push(value)
|
|
break
|
|
case 'Object':
|
|
toProcess.push(value)
|
|
break
|
|
case 'Date':
|
|
hash.update(value.toString())
|
|
break
|
|
case 'string':
|
|
hash.update(value)
|
|
break
|
|
case 'number':
|
|
hash.update((value as number).toString(16))
|
|
break
|
|
case 'boolean':
|
|
hash.update((value as boolean) ? '1' : '0')
|
|
break
|
|
case 'symbol':
|
|
hash.update((value as symbol).toString())
|
|
break
|
|
case 'bigint':
|
|
hash.update((value as bigint).toString())
|
|
break
|
|
case 'undefined':
|
|
hash.update('und')
|
|
break
|
|
case 'null':
|
|
hash.update('null')
|
|
break
|
|
default:
|
|
hash.update(value.toString())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export class SessionContextImpl implements SessionContext {
|
|
constructor (
|
|
readonly ctx: MeasureContext,
|
|
readonly userEmail: string,
|
|
readonly sessionId: string,
|
|
readonly admin: boolean | undefined,
|
|
readonly derived: SessionContext['derived'],
|
|
readonly workspace: WorkspaceIdWithUrl,
|
|
readonly branding: Branding | null,
|
|
readonly isAsyncContext: boolean
|
|
) {}
|
|
|
|
with<T>(
|
|
name: string,
|
|
params: ParamsType,
|
|
op: (ctx: SessionContext) => T | Promise<T>,
|
|
fullParams?: FullParamsType
|
|
): Promise<T> {
|
|
return this.ctx.with(
|
|
name,
|
|
params,
|
|
async (ctx) =>
|
|
await op(
|
|
new SessionContextImpl(
|
|
ctx,
|
|
this.userEmail,
|
|
this.sessionId,
|
|
this.admin,
|
|
this.derived,
|
|
this.workspace,
|
|
this.branding,
|
|
this.isAsyncContext
|
|
)
|
|
),
|
|
fullParams
|
|
)
|
|
}
|
|
}
|
|
|
|
export function createBroadcastEvent (classes: Ref<Class<Doc>>[]): TxWorkspaceEvent<BulkUpdateEvent> {
|
|
return {
|
|
_class: core.class.TxWorkspaceEvent,
|
|
_id: generateId(),
|
|
event: WorkspaceEvent.BulkUpdate,
|
|
params: {
|
|
_class: classes
|
|
},
|
|
modifiedBy: core.account.System,
|
|
modifiedOn: Date.now(),
|
|
objectSpace: core.space.DerivedTx,
|
|
space: core.space.DerivedTx
|
|
}
|
|
}
|
|
|
|
export function loadBrandingMap (brandingPath?: string): BrandingMap {
|
|
let brandings: BrandingMap = {}
|
|
if (brandingPath !== undefined && brandingPath !== '') {
|
|
brandings = JSON.parse(fs.readFileSync(brandingPath, 'utf8'))
|
|
|
|
for (const [host, value] of Object.entries(brandings)) {
|
|
const protocol = value.protocol ?? 'https'
|
|
value.front = `${protocol}://${host}/`
|
|
}
|
|
}
|
|
|
|
return brandings
|
|
}
|