mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
UBERF-6870: Speedup server broadcast of derived transactions (#5553)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
356dcc005a
commit
747bf3c8ba
@ -128,18 +128,6 @@ dependencies:
|
||||
'@rush-temp/core':
|
||||
specifier: file:./projects/core.tgz
|
||||
version: file:projects/core.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/dev-account':
|
||||
specifier: file:./projects/dev-account.tgz
|
||||
version: file:projects/dev-account.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/dev-client-resources':
|
||||
specifier: file:./projects/dev-client-resources.tgz
|
||||
version: file:projects/dev-client-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/dev-server':
|
||||
specifier: file:./projects/dev-server.tgz
|
||||
version: file:projects/dev-server.tgz(@types/node@20.11.19)(esbuild@0.20.1)
|
||||
'@rush-temp/dev-storage':
|
||||
specifier: file:./projects/dev-storage.tgz
|
||||
version: file:projects/dev-storage.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
'@rush-temp/devmodel':
|
||||
specifier: file:./projects/devmodel.tgz
|
||||
version: file:projects/devmodel.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2)
|
||||
@ -18326,133 +18314,6 @@ packages:
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/dev-account.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-LWWFUvgYWEbSKEbgl0DW088ikIIbxd94B+J5g5qGsBZUnVs2EfYKIOHZ6IkY3RcaqnLEYlwml6JHS2BuaPWh+A==, tarball: file:projects/dev-account.tgz}
|
||||
id: file:projects/dev-account.tgz
|
||||
name: '@rush-temp/dev-account'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 29.5.12
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
prettier: 3.2.5
|
||||
simplytyped: 3.3.0(typescript@5.3.3)
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/dev-client-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-cGChKmk9nSzZ32ne0g+PFZ2wCnZQN2UYQ/6Sf475WKMOU5n6vFcnTWjgPoDjNhGDN9Eqb/N42dGE/9FrFm5ypg==, tarball: file:projects/dev-client-resources.tgz}
|
||||
id: file:projects/dev-client-resources.tgz
|
||||
name: '@rush-temp/dev-client-resources'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 29.5.12
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
prettier: 3.2.5
|
||||
prettier-plugin-svelte: 3.2.1(prettier@3.2.5)(svelte@4.2.11)
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/dev-server.tgz(@types/node@20.11.19)(esbuild@0.20.1):
|
||||
resolution: {integrity: sha512-ejFT8uh0XsPvXdz1nxvESgUii09Eo5kTjqSiR5tnm7Xijo9nUAS8NCELlQ5CXdgh0ho2DUZWsLBAKx158E+YUQ==, tarball: file:projects/dev-server.tgz}
|
||||
id: file:projects/dev-server.tgz
|
||||
name: '@rush-temp/dev-server'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 29.5.12
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
jwt-simple: 0.5.6
|
||||
prettier: 3.2.5
|
||||
prettier-plugin-svelte: 3.2.1(prettier@3.2.5)(svelte@4.2.11)
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
ts-node: 10.9.2(@types/node@20.11.19)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@swc/core'
|
||||
- '@swc/wasm'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/dev-storage.tgz(@types/node@20.11.19)(esbuild@0.20.1)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-cgVla92iBIDPB+2c/z+YMbTFaONzy46pEas/QIYS8j6pNBGEIm8JjXwVy/ThSW+6wpi9vmwlUWOQe1ILsUdNXA==, tarball: file:projects/dev-storage.tgz}
|
||||
id: file:projects/dev-storage.tgz
|
||||
name: '@rush-temp/dev-storage'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 29.5.12
|
||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3)
|
||||
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint: 8.56.0
|
||||
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3)
|
||||
eslint-plugin-import: 2.29.1(eslint@8.56.0)
|
||||
eslint-plugin-n: 15.7.0(eslint@8.56.0)
|
||||
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
|
||||
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2)
|
||||
prettier: 3.2.5
|
||||
prettier-plugin-svelte: 3.2.1(prettier@3.2.5)(svelte@4.2.11)
|
||||
ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3)
|
||||
typescript: 5.3.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@jest/types'
|
||||
- '@types/node'
|
||||
- babel-jest
|
||||
- babel-plugin-macros
|
||||
- esbuild
|
||||
- node-notifier
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: false
|
||||
|
||||
file:projects/devmodel-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2):
|
||||
resolution: {integrity: sha512-NDdNczJE2bG7cuAqbD38xHMKXFndVeF3z0tvfBKVs6sVWauXThe448YkAMVY6NxEIczGqAqmyPHK0IHbuvEqgg==, tarball: file:projects/devmodel-resources.tgz}
|
||||
id: file:projects/devmodel-resources.tgz
|
||||
@ -21282,7 +21143,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/prod.tgz(bufferutil@4.0.8)(sass@1.71.1)(ts-node@10.9.2)(utf-8-validate@6.0.3):
|
||||
resolution: {integrity: sha512-/CKLzPjaTfkDNjT0evklXES1ISDy11ikLCJKFuyI4OQ6nfbt84wTqkO80Egr9IZScuNA0M0MEeJP+01pO2LNdA==, tarball: file:projects/prod.tgz}
|
||||
resolution: {integrity: sha512-ApNm3LLGsu8aU/ySQbpHVWR+td2eUUeCzgjnkwdw83E4QZ9mFj8I9hTN0z4gC32PAOFdxRt6P0J8vA78WBNfGw==, tarball: file:projects/prod.tgz}
|
||||
id: file:projects/prod.tgz
|
||||
name: '@rush-temp/prod'
|
||||
version: 0.0.0
|
||||
@ -24360,7 +24221,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/tool.tgz(bufferutil@4.0.8)(utf-8-validate@6.0.3):
|
||||
resolution: {integrity: sha512-aCu871KUBezC10ng0g9MwVF4UdeqlKVlMvLH4r0eBFvZx/XkEPiP++bL5dDuYo9o4cU2bhj+7uTzLCePUQVDZQ==, tarball: file:projects/tool.tgz}
|
||||
resolution: {integrity: sha512-mudcpqzHDkcN8NfVsWXUj+rtgp9QfGvIsmYSFEjvU9yzw+WIZJ3eqnU72/Vbhn1WgtMEKLweb3oqEtS9tmGAog==, tarball: file:projects/tool.tgz}
|
||||
id: file:projects/tool.tgz
|
||||
name: '@rush-temp/tool'
|
||||
version: 0.0.0
|
||||
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
@ -1,94 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-account",
|
||||
"entries": [
|
||||
{
|
||||
"version": "0.6.7",
|
||||
"tag": "@hcengineering/dev-account_v0.6.7",
|
||||
"date": "Mon, 09 Aug 2021 08:00:44 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "fix"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.6",
|
||||
"tag": "@hcengineering/dev-account_v0.6.6",
|
||||
"date": "Sun, 08 Aug 2021 12:00:07 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Change"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.5",
|
||||
"tag": "@hcengineering/dev-account_v0.6.5",
|
||||
"date": "Sun, 08 Aug 2021 11:43:36 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Update"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.4",
|
||||
"tag": "@hcengineering/dev-account_v0.6.4",
|
||||
"date": "Sun, 08 Aug 2021 11:38:34 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Update"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.3",
|
||||
"tag": "@hcengineering/dev-account_v0.6.3",
|
||||
"date": "Sun, 08 Aug 2021 10:21:31 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Lint"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.2",
|
||||
"tag": "@hcengineering/dev-account_v0.6.2",
|
||||
"date": "Sun, 08 Aug 2021 10:14:57 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Initial"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.0` to `~0.6.4`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.1",
|
||||
"tag": "@hcengineering/dev-account_v0.6.1",
|
||||
"date": "Sun, 08 Aug 2021 09:33:36 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Initial implementation"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
# Change Log - @hcengineering/dev-account
|
||||
|
||||
This log was last generated on Mon, 09 Aug 2021 08:00:44 GMT and should not be manually modified.
|
||||
|
||||
## 0.6.7
|
||||
Mon, 09 Aug 2021 08:00:44 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- fix
|
||||
|
||||
## 0.6.6
|
||||
Sun, 08 Aug 2021 12:00:07 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Change
|
||||
|
||||
## 0.6.5
|
||||
Sun, 08 Aug 2021 11:43:36 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Update
|
||||
|
||||
## 0.6.4
|
||||
Sun, 08 Aug 2021 11:38:34 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Update
|
||||
|
||||
## 0.6.3
|
||||
Sun, 08 Aug 2021 10:21:31 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Lint
|
||||
|
||||
## 0.6.2
|
||||
Sun, 08 Aug 2021 10:14:57 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Initial
|
||||
|
||||
## 0.6.1
|
||||
Sun, 08 Aug 2021 09:33:36 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Initial implementation
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-account",
|
||||
"version": "0.6.7",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.54.0",
|
||||
"simplytyped": "^3.3.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"@types/jest": "^29.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/platform": "^0.6.9",
|
||||
"@hcengineering/core": "^0.6.28",
|
||||
"@hcengineering/server-token": "^0.6.7"
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import platform, { Severity, Status } from '@hcengineering/platform'
|
||||
|
||||
import { getWorkspaceId } from '@hcengineering/core'
|
||||
import { generateToken } from '@hcengineering/server-token'
|
||||
|
||||
function login (endpoint: string, email: string, password: string, workspace: string): any {
|
||||
if (email !== 'rosamund@hc.engineering' && email !== 'elon@hc.engineering') {
|
||||
return { error: new Status(Severity.ERROR, platform.status.Unauthorized, {}) }
|
||||
}
|
||||
|
||||
if (password !== '1111') {
|
||||
return { error: new Status(Severity.ERROR, platform.status.Unauthorized, {}) }
|
||||
}
|
||||
|
||||
if (workspace !== 'ws1' && workspace !== 'ws2') {
|
||||
return { error: new Status(Severity.ERROR, platform.status.Unauthorized, {}) }
|
||||
}
|
||||
|
||||
const token = generateToken(email, getWorkspaceId(workspace))
|
||||
return { result: { token, endpoint } }
|
||||
}
|
||||
|
||||
export function handleRequest (req: any, serverEndpoint: string): any {
|
||||
if (req.method === 'login') {
|
||||
return login(serverEndpoint, req.params[0], req.params[1], req.params[2])
|
||||
}
|
||||
|
||||
return { error: new Status(Severity.ERROR, platform.status.BadRequest, {}) }
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { handleRequest } from './account'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function handle (req: string | null | undefined, serverEndpoint: string): { statusCode: number, body: string } {
|
||||
if (req === null || req === undefined) return { statusCode: 401, body: 'unauthorized' }
|
||||
const resp = handleRequest(JSON.parse(req), serverEndpoint)
|
||||
if (resp.error !== undefined) {
|
||||
return { statusCode: 401, body: '' }
|
||||
}
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify(resp)
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-client-resources",
|
||||
"entries": [
|
||||
{
|
||||
"version": "0.6.1",
|
||||
"tag": "@hcengineering/dev-client-resources_v0.6.1",
|
||||
"date": "Wed, 11 Aug 2021 09:37:04 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Server support for workspaces"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.8` to `~0.6.10`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/dev-storage\" from `~0.6.3` to `~0.6.6`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.0",
|
||||
"tag": "@hcengineering/dev-client-resources_v0.6.0",
|
||||
"date": "Sun, 08 Aug 2021 10:14:57 GMT",
|
||||
"comments": {
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.3` to `~0.6.4`"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
# Change Log - @hcengineering/dev-client-resources
|
||||
|
||||
This log was last generated on Wed, 11 Aug 2021 09:37:04 GMT and should not be manually modified.
|
||||
|
||||
## 0.6.1
|
||||
Wed, 11 Aug 2021 09:37:04 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Server support for workspaces
|
||||
|
||||
## 0.6.0
|
||||
Sun, 08 Aug 2021 10:14:57 GMT
|
||||
|
||||
_Initial release_
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-client-resources",
|
||||
"version": "0.6.1",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.54.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"@types/jest": "^29.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/platform": "^0.6.9",
|
||||
"@hcengineering/core": "^0.6.28",
|
||||
"@hcengineering/client": "^0.6.14",
|
||||
"@hcengineering/dev-storage": "^0.6.6",
|
||||
"@hcengineering/server-core": "^0.6.1",
|
||||
"@hcengineering/model-all": "^0.6.0",
|
||||
"@hcengineering/devmodel": "^0.6.0",
|
||||
"@hcengineering/rpc": "^0.6.1"
|
||||
}
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, {
|
||||
Account,
|
||||
Class,
|
||||
ClientConnection,
|
||||
Doc,
|
||||
DocChunk,
|
||||
DocumentQuery,
|
||||
Domain,
|
||||
DOMAIN_TX,
|
||||
FindOptions,
|
||||
FindResult,
|
||||
getWorkspaceId,
|
||||
MeasureDoneOperation,
|
||||
MeasureMetricsContext,
|
||||
Ref,
|
||||
SearchOptions,
|
||||
SearchQuery,
|
||||
SearchResult,
|
||||
ServerStorage,
|
||||
Timestamp,
|
||||
Tx,
|
||||
TxHandler,
|
||||
TxResult
|
||||
} from '@hcengineering/core'
|
||||
import { createInMemoryTxAdapter } from '@hcengineering/dev-storage'
|
||||
import devmodel from '@hcengineering/devmodel'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import { protoDeserialize, protoSerialize } from '@hcengineering/rpc'
|
||||
import {
|
||||
ContentTextAdapter,
|
||||
createInMemoryAdapter,
|
||||
createServerStorage,
|
||||
DbConfiguration,
|
||||
DummyFullTextAdapter,
|
||||
FullTextAdapter
|
||||
} from '@hcengineering/server-core'
|
||||
|
||||
class ServerStorageWrapper implements ClientConnection {
|
||||
measureCtx = new MeasureMetricsContext('client', {})
|
||||
constructor (
|
||||
private readonly storage: ServerStorage,
|
||||
private readonly handler: TxHandler
|
||||
) {}
|
||||
|
||||
findAll<T extends Doc>(
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
options?: FindOptions<T>
|
||||
): Promise<FindResult<T>> {
|
||||
const [c, q, o] = protoDeserialize(protoSerialize([_class, query, options], false), false)
|
||||
return this.storage.findAll(this.measureCtx, c, q, o)
|
||||
}
|
||||
|
||||
async searchFulltext (query: SearchQuery, options: SearchOptions): Promise<SearchResult> {
|
||||
return { docs: [] }
|
||||
}
|
||||
|
||||
async loadModel (lastModelTx: Timestamp): Promise<Tx[]> {
|
||||
return await this.storage.findAll(this.measureCtx, core.class.Tx, {
|
||||
space: core.space.Model,
|
||||
modifiedOn: { $gt: lastModelTx }
|
||||
})
|
||||
}
|
||||
|
||||
async getAccount (): Promise<Account> {
|
||||
return (await this.storage.findAll(this.measureCtx, core.class.Account, {}))[0]
|
||||
}
|
||||
|
||||
async tx (tx: Tx): Promise<TxResult> {
|
||||
const _tx = protoDeserialize(protoSerialize(tx, false), false)
|
||||
const [result, derived] = await this.storage.tx(this.measureCtx, _tx)
|
||||
for (const tx of derived) {
|
||||
this.handler(tx)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async close (): Promise<void> {}
|
||||
|
||||
async loadChunk (domain: Domain, idx?: number): Promise<DocChunk> {
|
||||
return { idx: -1, docs: [], finished: true }
|
||||
}
|
||||
|
||||
async closeChunk (idx: number): Promise<void> {}
|
||||
|
||||
async loadDocs (domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
|
||||
return []
|
||||
}
|
||||
|
||||
async upload (domain: Domain, docs: Doc[]): Promise<void> {}
|
||||
|
||||
async clean (domain: Domain, docs: Ref<Doc>[]): Promise<void> {}
|
||||
|
||||
async measure (operationName: string): Promise<MeasureDoneOperation> {
|
||||
return async () => ({ time: 0, serverTime: 0 })
|
||||
}
|
||||
|
||||
async sendForceClose (): Promise<void> {}
|
||||
}
|
||||
|
||||
async function createNullFullTextAdapter (): Promise<FullTextAdapter> {
|
||||
return new DummyFullTextAdapter()
|
||||
}
|
||||
async function createNullContentTextAdapter (): Promise<ContentTextAdapter> {
|
||||
return {
|
||||
async content (name: string, type: string, doc) {
|
||||
return ''
|
||||
},
|
||||
metrics () {
|
||||
return new MeasureMetricsContext('', {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function connect (handler: (tx: Tx) => void): Promise<ClientConnection> {
|
||||
const conf: DbConfiguration = {
|
||||
domains: {
|
||||
[DOMAIN_TX]: 'InMemoryTx'
|
||||
},
|
||||
defaultAdapter: 'InMemory',
|
||||
adapters: {
|
||||
InMemoryTx: {
|
||||
factory: createInMemoryTxAdapter,
|
||||
url: ''
|
||||
},
|
||||
InMemory: {
|
||||
factory: createInMemoryAdapter,
|
||||
url: ''
|
||||
}
|
||||
},
|
||||
metrics: new MeasureMetricsContext('', {}),
|
||||
fulltextAdapter: {
|
||||
factory: createNullFullTextAdapter,
|
||||
url: '',
|
||||
stages: () => []
|
||||
},
|
||||
contentAdapters: {
|
||||
default: {
|
||||
factory: createNullContentTextAdapter,
|
||||
contentType: '',
|
||||
url: ''
|
||||
}
|
||||
},
|
||||
serviceAdapters: {},
|
||||
defaultContentAdapter: 'default',
|
||||
workspace: { ...getWorkspaceId(''), workspaceUrl: '', workspaceName: '' }
|
||||
}
|
||||
const ctx = new MeasureMetricsContext('client', {})
|
||||
const serverStorage = await createServerStorage(ctx, conf, {
|
||||
upgrade: false
|
||||
})
|
||||
setMetadata(devmodel.metadata.DevModel, serverStorage)
|
||||
return new ServerStorageWrapper(serverStorage, handler)
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
//
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import clientPlugin from '@hcengineering/client'
|
||||
import core, { AccountClient, createClient, groupByArray, MigrationState } from '@hcengineering/core'
|
||||
import { migrateOperations } from '@hcengineering/model-all'
|
||||
import { getMetadata, getResource } from '@hcengineering/platform'
|
||||
import { connect } from './connection'
|
||||
|
||||
let client: AccountClient
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => {
|
||||
return {
|
||||
function: {
|
||||
GetClient: async (): Promise<AccountClient> => {
|
||||
if (client === undefined) {
|
||||
client = await createClient(connect)
|
||||
|
||||
const states = await client.findAll<MigrationState>(core.class.MigrationState, {})
|
||||
const migrateState = new Map(
|
||||
Array.from(groupByArray(states, (it) => it.plugin).entries()).map((it) => [
|
||||
it[0],
|
||||
new Set(it[1].map((q) => q.state))
|
||||
])
|
||||
)
|
||||
;(client as any).migrateState = migrateState
|
||||
for (const op of migrateOperations) {
|
||||
console.log('Migrate', op[0])
|
||||
await op[1].upgrade(client as any, {
|
||||
log (msg, data) {
|
||||
console.log(msg, data)
|
||||
},
|
||||
error (msg, data) {
|
||||
console.error(msg, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// Check if we had dev hook for client.
|
||||
const hook = getMetadata(clientPlugin.metadata.ClientHook)
|
||||
if (hook !== undefined) {
|
||||
const hookProc = await getResource(hook)
|
||||
client = await hookProc(client)
|
||||
}
|
||||
return client
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
version: '3.5'
|
||||
|
||||
services:
|
||||
etcd:
|
||||
container_name: milvus-etcd
|
||||
image: quay.io/coreos/etcd:v3.5.0
|
||||
environment:
|
||||
- ETCD_AUTO_COMPACTION_MODE=revision
|
||||
- ETCD_AUTO_COMPACTION_RETENTION=1000
|
||||
- ETCD_QUOTA_BACKEND_BYTES=4294967296
|
||||
- ETCD_SNAPSHOT_COUNT=50000
|
||||
volumes:
|
||||
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
|
||||
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
|
||||
|
||||
minio:
|
||||
container_name: milvus-minio
|
||||
image: minio/minio:RELEASE.2022-03-17T06-34-49Z
|
||||
environment:
|
||||
MINIO_ACCESS_KEY: minioadmin
|
||||
MINIO_SECRET_KEY: minioadmin
|
||||
ports:
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
|
||||
command: minio server /minio_data --console-address ":9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
|
||||
standalone:
|
||||
container_name: milvus-standalone
|
||||
image: milvusdb/milvus:v2.2.2
|
||||
command: ["milvus", "run", "standalone"]
|
||||
environment:
|
||||
ETCD_ENDPOINTS: etcd:2379
|
||||
MINIO_ADDRESS: minio:9000
|
||||
volumes:
|
||||
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
|
||||
ports:
|
||||
- "19530:19530"
|
||||
- "9091:9091"
|
||||
depends_on:
|
||||
- "etcd"
|
||||
- "minio"
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: milvus
|
@ -58,7 +58,6 @@
|
||||
"@hcengineering/login-assets": "^0.6.0",
|
||||
"@hcengineering/login-resources": "^0.6.2",
|
||||
"@hcengineering/client": "^0.6.14",
|
||||
"@hcengineering/dev-client-resources": "^0.6.1",
|
||||
"@hcengineering/workbench": "^0.6.9",
|
||||
"@hcengineering/workbench-resources": "^0.6.1",
|
||||
"@hcengineering/view": "^0.6.9",
|
||||
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
@ -1,184 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-server",
|
||||
"entries": [
|
||||
{
|
||||
"version": "0.6.10",
|
||||
"tag": "@hcengineering/dev-server_v0.6.10",
|
||||
"date": "Sat, 14 Aug 2021 09:13:32 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "ping"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.9",
|
||||
"tag": "@hcengineering/dev-server_v0.6.9",
|
||||
"date": "Wed, 11 Aug 2021 10:10:44 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "server ping"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.8",
|
||||
"tag": "@hcengineering/dev-server_v0.6.8",
|
||||
"date": "Wed, 11 Aug 2021 09:37:04 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Server support for workspaces"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/dev-storage\" from `~0.6.3` to `~0.6.6`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/server-ws\" from `~0.6.6` to `~0.6.8`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.8` to `~0.6.10`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.6",
|
||||
"tag": "@hcengineering/dev-server_v0.6.6",
|
||||
"date": "Sun, 08 Aug 2021 21:05:26 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Fix server connection"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/server-ws\" from `~0.6.4` to `~0.6.5`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.7` to `~0.6.8`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.5",
|
||||
"tag": "@hcengineering/dev-server_v0.6.5",
|
||||
"date": "Wed, 04 Aug 2021 21:18:44 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "fix"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/dev-storage\" from `~0.6.2` to `~0.6.3`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/server-ws\" from `~0.6.3` to `~0.6.4`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.6` to `~0.6.7`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.2` to `~0.6.3`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.4",
|
||||
"tag": "@hcengineering/dev-server_v0.6.4",
|
||||
"date": "Wed, 04 Aug 2021 21:00:14 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "npmignore"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/dev-storage\" from `~0.6.1` to `~0.6.2`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/server-ws\" from `~0.6.2` to `~0.6.3`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.5` to `~0.6.6`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.3",
|
||||
"tag": "@hcengineering/dev-server_v0.6.3",
|
||||
"date": "Wed, 04 Aug 2021 20:48:46 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Logging"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/server-ws\" from `~0.6.1` to `~0.6.2`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.1` to `~0.6.2`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.2",
|
||||
"tag": "@hcengineering/dev-server_v0.6.2",
|
||||
"date": "Wed, 04 Aug 2021 20:26:15 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Export start function as defauilt"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.4` to `~0.6.5`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.1",
|
||||
"tag": "@hcengineering/dev-server_v0.6.1",
|
||||
"date": "Wed, 04 Aug 2021 17:38:30 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Minor changes for publish"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/dev-storage\" from `~0.6.0` to `~0.6.1`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/server-ws\" from `~0.6.0` to `~0.6.1`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.0` to `~0.6.1`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.0` to `~0.6.1`"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
# Change Log - @hcengineering/dev-server
|
||||
|
||||
This log was last generated on Sat, 14 Aug 2021 09:13:32 GMT and should not be manually modified.
|
||||
|
||||
## 0.6.10
|
||||
Sat, 14 Aug 2021 09:13:32 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- ping
|
||||
|
||||
## 0.6.9
|
||||
Wed, 11 Aug 2021 10:10:44 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- server ping
|
||||
|
||||
## 0.6.8
|
||||
Wed, 11 Aug 2021 09:37:04 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Server support for workspaces
|
||||
|
||||
## 0.6.6
|
||||
Sun, 08 Aug 2021 21:05:26 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Fix server connection
|
||||
|
||||
## 0.6.5
|
||||
Wed, 04 Aug 2021 21:18:44 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- fix
|
||||
|
||||
## 0.6.4
|
||||
Wed, 04 Aug 2021 21:00:14 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- npmignore
|
||||
|
||||
## 0.6.3
|
||||
Wed, 04 Aug 2021 20:48:46 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Logging
|
||||
|
||||
## 0.6.2
|
||||
Wed, 04 Aug 2021 20:26:15 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Export start function as defauilt
|
||||
|
||||
## 0.6.1
|
||||
Wed, 04 Aug 2021 17:38:30 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Minor changes for publish
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-server",
|
||||
"version": "0.6.10",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"start": "ts-node src/__start.ts",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.54.0",
|
||||
"ts-node": "^10.8.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"@types/jest": "^29.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/dev-storage": "^0.6.6",
|
||||
"@hcengineering/server-ws": "^0.6.11",
|
||||
"@hcengineering/core": "^0.6.28",
|
||||
"@hcengineering/platform": "^0.6.9",
|
||||
"jwt-simple": "^0.5.6",
|
||||
"@hcengineering/server-core": "^0.6.1"
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { start } from '.'
|
||||
|
||||
import { encode } from 'jwt-simple'
|
||||
|
||||
const token = encode({ email: 'rosamund@hc.engineering', workspace: 'trx40' }, 'secret')
|
||||
console.log(token)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
start(3333)
|
@ -1,17 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021, 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
export { start } from './server'
|
@ -1,88 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { DOMAIN_TX, MeasureMetricsContext } from '@hcengineering/core'
|
||||
import { createInMemoryTxAdapter } from '@hcengineering/dev-storage'
|
||||
import {
|
||||
ContentTextAdapter,
|
||||
createInMemoryAdapter,
|
||||
createPipeline,
|
||||
DbConfiguration,
|
||||
DummyFullTextAdapter,
|
||||
FullTextAdapter
|
||||
} from '@hcengineering/server-core'
|
||||
import { ClientSession, startHttpServer, start as startJsonRpc } from '@hcengineering/server-ws'
|
||||
|
||||
async function createNullFullTextAdapter (): Promise<FullTextAdapter> {
|
||||
return new DummyFullTextAdapter()
|
||||
}
|
||||
async function createNullContentTextAdapter (): Promise<ContentTextAdapter> {
|
||||
return {
|
||||
async content (name: string, type: string, doc) {
|
||||
return ''
|
||||
},
|
||||
metrics: () => new MeasureMetricsContext('', {})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function start (port: number, host?: string): Promise<void> {
|
||||
const ctx = new MeasureMetricsContext('server', {})
|
||||
startJsonRpc(ctx, {
|
||||
pipelineFactory: (ctx, workspaceId) => {
|
||||
const conf: DbConfiguration = {
|
||||
domains: {
|
||||
[DOMAIN_TX]: 'InMemoryTx'
|
||||
},
|
||||
defaultAdapter: 'InMemory',
|
||||
adapters: {
|
||||
InMemoryTx: {
|
||||
factory: createInMemoryTxAdapter,
|
||||
url: ''
|
||||
},
|
||||
InMemory: {
|
||||
factory: createInMemoryAdapter,
|
||||
url: ''
|
||||
}
|
||||
},
|
||||
fulltextAdapter: {
|
||||
factory: createNullFullTextAdapter,
|
||||
url: '',
|
||||
stages: () => []
|
||||
},
|
||||
metrics: new MeasureMetricsContext('', {}),
|
||||
contentAdapters: {
|
||||
default: {
|
||||
factory: createNullContentTextAdapter,
|
||||
contentType: '',
|
||||
url: ''
|
||||
}
|
||||
},
|
||||
serviceAdapters: {},
|
||||
defaultContentAdapter: 'default',
|
||||
workspace: workspaceId
|
||||
}
|
||||
return createPipeline(ctx, conf, [], false, () => {})
|
||||
},
|
||||
sessionFactory: (token, pipeline, broadcast) => new ClientSession(broadcast, token, pipeline),
|
||||
port,
|
||||
productId: '',
|
||||
serverFactory: startHttpServer,
|
||||
accountsUrl: ''
|
||||
})
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
@ -1,79 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-storage",
|
||||
"entries": [
|
||||
{
|
||||
"version": "0.6.6",
|
||||
"tag": "@hcengineering/dev-storage_v0.6.6",
|
||||
"date": "Wed, 11 Aug 2021 09:37:04 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Server support for workspaces"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.8` to `~0.6.10`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.3",
|
||||
"tag": "@hcengineering/dev-storage_v0.6.3",
|
||||
"date": "Wed, 04 Aug 2021 21:18:44 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "fix"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.6` to `~0.6.7`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.2` to `~0.6.3`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.2",
|
||||
"tag": "@hcengineering/dev-storage_v0.6.2",
|
||||
"date": "Wed, 04 Aug 2021 21:00:14 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "npmignore"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.5` to `~0.6.6`"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "0.6.1",
|
||||
"tag": "@hcengineering/dev-storage_v0.6.1",
|
||||
"date": "Wed, 04 Aug 2021 17:38:30 GMT",
|
||||
"comments": {
|
||||
"patch": [
|
||||
{
|
||||
"comment": "Minor changes for publish"
|
||||
}
|
||||
],
|
||||
"dependency": [
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/core\" from `~0.6.0` to `~0.6.1`"
|
||||
},
|
||||
{
|
||||
"comment": "Updating dependency \"@hcengineering/platform\" from `~0.6.0` to `~0.6.1`"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
# Change Log - @hcengineering/dev-storage
|
||||
|
||||
This log was last generated on Wed, 11 Aug 2021 09:37:04 GMT and should not be manually modified.
|
||||
|
||||
## 0.6.6
|
||||
Wed, 11 Aug 2021 09:37:04 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Server support for workspaces
|
||||
|
||||
## 0.6.3
|
||||
Wed, 04 Aug 2021 21:18:44 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- fix
|
||||
|
||||
## 0.6.2
|
||||
Wed, 04 Aug 2021 21:00:14 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- npmignore
|
||||
|
||||
## 0.6.1
|
||||
Wed, 04 Aug 2021 17:38:30 GMT
|
||||
|
||||
### Patches
|
||||
|
||||
- Minor changes for publish
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "@hcengineering/dev-storage",
|
||||
"version": "0.6.6",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.54.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"@types/jest": "^29.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/core": "^0.6.28",
|
||||
"@hcengineering/platform": "^0.6.9",
|
||||
"@hcengineering/server-core": "^0.6.1",
|
||||
"@hcengineering/model-all": "^0.6.0"
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { TxFactory } from '@hcengineering/core'
|
||||
import { createStorage } from '../storage'
|
||||
|
||||
describe('client', () => {
|
||||
it('should create storage', async () => {
|
||||
const storage = await createStorage()
|
||||
const txes = await storage.findAll(core.class.Tx, {})
|
||||
expect(txes.length).toBe(64)
|
||||
})
|
||||
|
||||
it('should create space', async () => {
|
||||
const storage = await createStorage()
|
||||
const factory = new TxFactory(core.account.System)
|
||||
const tx = factory.createTxCreateDoc(core.class.Space, core.space.Model, {
|
||||
name: 'xxx',
|
||||
description: 'desc',
|
||||
private: false,
|
||||
members: []
|
||||
})
|
||||
await storage.tx(tx)
|
||||
const txes = await storage.findAll(core.class.Space, { name: 'xxx' })
|
||||
expect(txes.length).toBe(1)
|
||||
})
|
||||
})
|
@ -1,17 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021, 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
export * from './storage'
|
@ -1,72 +0,0 @@
|
||||
//
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type {
|
||||
Class,
|
||||
Doc,
|
||||
DocumentQuery,
|
||||
FindOptions,
|
||||
FindResult,
|
||||
MeasureContext,
|
||||
Ref,
|
||||
Tx,
|
||||
TxResult,
|
||||
WorkspaceId
|
||||
} from '@hcengineering/core'
|
||||
import { Hierarchy, TxDb } from '@hcengineering/core'
|
||||
import builder from '@hcengineering/model-all'
|
||||
import { DummyDbAdapter, TxAdapter } from '@hcengineering/server-core'
|
||||
|
||||
class InMemoryTxAdapter extends DummyDbAdapter implements TxAdapter {
|
||||
private readonly txdb: TxDb
|
||||
|
||||
constructor (hierarchy: Hierarchy) {
|
||||
super()
|
||||
this.txdb = new TxDb(hierarchy)
|
||||
}
|
||||
|
||||
async findAll<T extends Doc>(
|
||||
ctx: MeasureContext,
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
options?: FindOptions<T>
|
||||
): Promise<FindResult<T>> {
|
||||
return await this.txdb.findAll(_class, query, options)
|
||||
}
|
||||
|
||||
async tx (ctx: MeasureContext, ...tx: Tx[]): Promise<TxResult[]> {
|
||||
const r: TxResult[] = []
|
||||
for (const t of tx) {
|
||||
r.push(await this.txdb.tx(t))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
async getModel (): Promise<Tx[]> {
|
||||
return builder().getTxes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function createInMemoryTxAdapter (
|
||||
ctx: MeasureContext,
|
||||
hierarchy: Hierarchy,
|
||||
url: string,
|
||||
workspace: WorkspaceId
|
||||
): Promise<TxAdapter> {
|
||||
return new InMemoryTxAdapter(hierarchy)
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
@ -61,7 +61,6 @@
|
||||
"@hcengineering/client-resources": "^0.6.23",
|
||||
"@hcengineering/contact": "^0.6.20",
|
||||
"@hcengineering/core": "^0.6.28",
|
||||
"@hcengineering/dev-storage": "^0.6.6",
|
||||
"@hcengineering/elastic": "^0.6.0",
|
||||
"@hcengineering/lead": "^0.6.0",
|
||||
"@hcengineering/minio": "^0.6.0",
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { LoadModelResponse } from '.'
|
||||
import type { Class, Doc, Domain, Ref, Timestamp } from './classes'
|
||||
import { Hierarchy } from './hierarchy'
|
||||
import { MeasureContext } from './measurements'
|
||||
import { MeasureContext, type FullParamsType, type ParamsType } from './measurements'
|
||||
import { ModelDb } from './memdb'
|
||||
import type {
|
||||
DocumentQuery,
|
||||
@ -45,6 +45,22 @@ export interface StorageIterator {
|
||||
close: (ctx: MeasureContext) => Promise<void>
|
||||
}
|
||||
|
||||
export interface SessionOperationContext {
|
||||
ctx: MeasureContext
|
||||
// A parts of derived data to deal with after operation will be complete
|
||||
derived: {
|
||||
derived: Tx[]
|
||||
target?: string[]
|
||||
}[]
|
||||
|
||||
with: <T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
op: (ctx: SessionOperationContext) => T | Promise<T>,
|
||||
fullParams?: FullParamsType
|
||||
) => Promise<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -78,8 +94,8 @@ export interface ServerStorage extends LowLevelStorage {
|
||||
}
|
||||
) => Promise<FindResult<T>>
|
||||
searchFulltext: (ctx: MeasureContext, query: SearchQuery, options: SearchOptions) => Promise<SearchResult>
|
||||
tx: (ctx: MeasureContext, tx: Tx) => Promise<[TxResult, Tx[]]>
|
||||
apply: (ctx: MeasureContext, tx: Tx[], broadcast: boolean) => Promise<TxResult>
|
||||
tx: (ctx: SessionOperationContext, tx: Tx) => Promise<TxResult>
|
||||
apply: (ctx: SessionOperationContext, tx: Tx[], broadcast: boolean) => Promise<TxResult>
|
||||
close: () => Promise<void>
|
||||
loadModel: (last: Timestamp, hash?: string) => Promise<Tx[] | LoadModelResponse>
|
||||
}
|
||||
|
@ -142,7 +142,6 @@ export interface TxApplyIf extends Tx {
|
||||
|
||||
export interface TxApplyResult {
|
||||
success: boolean
|
||||
derived: Tx[] // Some derived transactions to handle.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,7 +36,6 @@ import core, {
|
||||
Timestamp,
|
||||
Tx,
|
||||
TxApplyIf,
|
||||
TxApplyResult,
|
||||
TxHandler,
|
||||
TxResult,
|
||||
TxWorkspaceEvent,
|
||||
@ -442,8 +441,7 @@ class Connection implements ClientConnection {
|
||||
params: [],
|
||||
id: -1,
|
||||
binary: useBinary,
|
||||
compression: useCompression,
|
||||
broadcast: true
|
||||
compression: useCompression
|
||||
}
|
||||
this.websocket?.send(serialize(helloRequest, false))
|
||||
}
|
||||
@ -623,20 +621,7 @@ class Connection implements ClientConnection {
|
||||
return (await this.findAll(core.class.Tx, { _id: (tx as TxApplyIf).txes[0]._id }, { limit: 1 })).length === 0
|
||||
}
|
||||
return (await this.findAll(core.class.Tx, { _id: tx._id }, { limit: 1 })).length === 0
|
||||
},
|
||||
handleResult:
|
||||
tx._class === core.class.TxApplyIf
|
||||
? async (result) => {
|
||||
if (tx._class === core.class.TxApplyIf) {
|
||||
// We need to check extra broadcast's and perform them before
|
||||
const r = result as TxApplyResult
|
||||
const dr = r?.derived ?? []
|
||||
if (dr.length > 0) {
|
||||
this.handler(...dr)
|
||||
}
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,6 @@ import { serverViewId } from '@hcengineering/server-view'
|
||||
import {
|
||||
ClientSession,
|
||||
start as startJsonRpc,
|
||||
type BroadcastCall,
|
||||
type PipelineFactory,
|
||||
type ServerFactory,
|
||||
type Session
|
||||
@ -373,11 +372,11 @@ export function start (
|
||||
return createPipeline(ctx, conf, middlewares, upgrade, broadcast)
|
||||
}
|
||||
|
||||
const sessionFactory = (token: Token, pipeline: Pipeline, broadcast: BroadcastCall): Session => {
|
||||
const sessionFactory = (token: Token, pipeline: Pipeline): Session => {
|
||||
if (token.extra?.mode === 'backup') {
|
||||
return new BackupClientSession(broadcast, token, pipeline)
|
||||
return new BackupClientSession(token, pipeline)
|
||||
}
|
||||
return new ClientSession(broadcast, token, pipeline)
|
||||
return new ClientSession(token, pipeline)
|
||||
}
|
||||
|
||||
return startJsonRpc(getMetricsContext(), {
|
||||
|
@ -51,7 +51,6 @@
|
||||
"@hcengineering/login-assets": "^0.6.0",
|
||||
"@hcengineering/login-resources": "^0.6.2",
|
||||
"@hcengineering/client": "^0.6.6",
|
||||
"@hcengineering/dev-client-resources": "^0.6.1",
|
||||
"@hcengineering/workbench": "^0.6.2",
|
||||
"@hcengineering/workbench-resources": "^0.6.1",
|
||||
"@hcengineering/view": "^0.6.2",
|
||||
|
25
rush.json
25
rush.json
@ -481,16 +481,6 @@
|
||||
"projectFolder": "server/uws",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/dev-storage",
|
||||
"projectFolder": "dev/storage",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/dev-server",
|
||||
"projectFolder": "dev/server",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/theme",
|
||||
"projectFolder": "packages/theme",
|
||||
@ -516,11 +506,6 @@
|
||||
"projectFolder": "dev/prod",
|
||||
"shouldPublish": false
|
||||
},
|
||||
// {
|
||||
// "packageName": "@hcengineering/prod-tracker",
|
||||
// "projectFolder": "products/tracker",
|
||||
// "shouldPublish": false
|
||||
// },
|
||||
{
|
||||
"packageName": "@hcengineering/server-core",
|
||||
"projectFolder": "server/core",
|
||||
@ -661,11 +646,6 @@
|
||||
"projectFolder": "plugins/task-resources",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/dev-client-resources",
|
||||
"projectFolder": "dev/client-resources",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/model-workbench",
|
||||
"projectFolder": "models/workbench",
|
||||
@ -741,11 +721,6 @@
|
||||
"projectFolder": "models/server-core",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/dev-account",
|
||||
"projectFolder": "dev/account",
|
||||
"shouldPublish": false
|
||||
},
|
||||
{
|
||||
"packageName": "@hcengineering/server-attachment",
|
||||
"projectFolder": "server-plugins/attachment",
|
||||
|
@ -35,7 +35,6 @@ import { type DbConfiguration } from './configuration'
|
||||
import { createServerStorage } from './server'
|
||||
import {
|
||||
type BroadcastFunc,
|
||||
type HandledBroadcastFunc,
|
||||
type Middleware,
|
||||
type MiddlewareCreator,
|
||||
type Pipeline,
|
||||
@ -52,30 +51,16 @@ export async function createPipeline (
|
||||
upgrade: boolean,
|
||||
broadcast: BroadcastFunc
|
||||
): Promise<Pipeline> {
|
||||
let broadcastHook: HandledBroadcastFunc = (): Tx[] => {
|
||||
return []
|
||||
}
|
||||
const storage = await ctx.with(
|
||||
'create-server-storage',
|
||||
{},
|
||||
async (ctx) =>
|
||||
await createServerStorage(ctx, conf, {
|
||||
upgrade,
|
||||
broadcast: (tx: Tx[], targets?: string[]) => {
|
||||
const sendTx = broadcastHook?.(tx, targets) ?? tx
|
||||
broadcast(sendTx, targets)
|
||||
}
|
||||
broadcast
|
||||
})
|
||||
)
|
||||
const pipelineResult = await PipelineImpl.create(
|
||||
ctx.newChild('pipeline-operations', {}),
|
||||
storage,
|
||||
constructors,
|
||||
broadcast
|
||||
)
|
||||
broadcastHook = (tx, targets) => {
|
||||
return pipelineResult.handleBroadcast(tx, targets)
|
||||
}
|
||||
const pipelineResult = await PipelineImpl.create(ctx.newChild('pipeline-operations', {}), storage, constructors)
|
||||
return pipelineResult
|
||||
}
|
||||
|
||||
@ -86,30 +71,21 @@ class PipelineImpl implements Pipeline {
|
||||
this.modelDb = storage.modelDb
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.head?.handleBroadcast(tx, targets) ?? tx
|
||||
}
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
storage: ServerStorage,
|
||||
constructors: MiddlewareCreator[],
|
||||
broadcast: BroadcastFunc
|
||||
constructors: MiddlewareCreator[]
|
||||
): Promise<PipelineImpl> {
|
||||
const pipeline = new PipelineImpl(storage)
|
||||
pipeline.head = await pipeline.buildChain(ctx, constructors, broadcast)
|
||||
pipeline.head = await pipeline.buildChain(ctx, constructors)
|
||||
return pipeline
|
||||
}
|
||||
|
||||
private async buildChain (
|
||||
ctx: MeasureContext,
|
||||
constructors: MiddlewareCreator[],
|
||||
broadcast: BroadcastFunc
|
||||
): Promise<Middleware | undefined> {
|
||||
private async buildChain (ctx: MeasureContext, constructors: MiddlewareCreator[]): Promise<Middleware | undefined> {
|
||||
let current: Middleware | undefined
|
||||
for (let index = constructors.length - 1; index >= 0; index--) {
|
||||
const element = constructors[index]
|
||||
current = await ctx.with('build chain', {}, async (ctx) => await element(ctx, broadcast, this.storage, current))
|
||||
current = await ctx.with('build chain', {}, async (ctx) => await element(ctx, this.storage, current))
|
||||
}
|
||||
return current
|
||||
}
|
||||
@ -122,19 +98,18 @@ class PipelineImpl implements Pipeline {
|
||||
): Promise<FindResult<T>> {
|
||||
return this.head !== undefined
|
||||
? await this.head.findAll(ctx, _class, query, options)
|
||||
: await this.storage.findAll(ctx, _class, query, options)
|
||||
: await this.storage.findAll(ctx.ctx, _class, query, options)
|
||||
}
|
||||
|
||||
async searchFulltext (ctx: SessionContext, query: SearchQuery, options: SearchOptions): Promise<SearchResult> {
|
||||
return this.head !== undefined
|
||||
? await this.head.searchFulltext(ctx, query, options)
|
||||
: await this.storage.searchFulltext(ctx, query, options)
|
||||
: await this.storage.searchFulltext(ctx.ctx, query, options)
|
||||
}
|
||||
|
||||
async tx (ctx: SessionContext, tx: Tx): Promise<[TxResult, Tx[], string[] | undefined]> {
|
||||
async tx (ctx: SessionContext, tx: Tx): Promise<TxResult> {
|
||||
if (this.head === undefined) {
|
||||
const res = await this.storage.tx(ctx, tx)
|
||||
return [...res, undefined]
|
||||
return await this.storage.tx(ctx, tx)
|
||||
} else {
|
||||
return await this.head.tx(ctx, tx)
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ export async function createServerStorage (
|
||||
space: core.space.DerivedTx,
|
||||
params: evt
|
||||
}
|
||||
options.broadcast?.([tx])
|
||||
options.broadcast([tx])
|
||||
}
|
||||
)
|
||||
return new FullTextIndex(
|
||||
|
@ -15,15 +15,19 @@
|
||||
//
|
||||
|
||||
import core, {
|
||||
type Account,
|
||||
type AttachedDoc,
|
||||
type Class,
|
||||
ClassifierKind,
|
||||
type Client,
|
||||
type Collection,
|
||||
DOMAIN_MODEL,
|
||||
DOMAIN_TRANSIENT,
|
||||
DOMAIN_TX,
|
||||
TxFactory,
|
||||
TxProcessor,
|
||||
cutObjectArray,
|
||||
toFindResult,
|
||||
type Account,
|
||||
type AttachedDoc,
|
||||
type Class,
|
||||
type Client,
|
||||
type Collection,
|
||||
type Doc,
|
||||
type DocumentQuery,
|
||||
type DocumentUpdate,
|
||||
@ -40,22 +44,19 @@ import core, {
|
||||
type SearchQuery,
|
||||
type SearchResult,
|
||||
type ServerStorage,
|
||||
type SessionOperationContext,
|
||||
type StorageIterator,
|
||||
type Timestamp,
|
||||
type Tx,
|
||||
type TxApplyIf,
|
||||
type TxCUD,
|
||||
type TxCollectionCUD,
|
||||
TxFactory,
|
||||
TxProcessor,
|
||||
type TxRemoveDoc,
|
||||
type TxResult,
|
||||
type TxUpdateDoc,
|
||||
type WorkspaceIdWithUrl,
|
||||
cutObjectArray,
|
||||
toFindResult
|
||||
type WorkspaceIdWithUrl
|
||||
} from '@hcengineering/core'
|
||||
import { type Metadata, getResource } from '@hcengineering/platform'
|
||||
import { getResource, type Metadata } from '@hcengineering/platform'
|
||||
import { LiveQuery as LQ } from '@hcengineering/query'
|
||||
import crypto from 'node:crypto'
|
||||
import { type DbAdapter } from '../adapter'
|
||||
@ -555,7 +556,7 @@ export class TServerStorage implements ServerStorage {
|
||||
}
|
||||
|
||||
private async processDerived (
|
||||
ctx: MeasureContext,
|
||||
ctx: SessionOperationContext,
|
||||
txes: Tx[],
|
||||
triggerFx: Effects,
|
||||
findAll: ServerStorage['findAll'],
|
||||
@ -570,11 +571,13 @@ export class TServerStorage implements ServerStorage {
|
||||
): Promise<FindResult<T>> =>
|
||||
findAll(mctx, clazz, query, options)
|
||||
|
||||
const removed = await ctx.with('process-remove', {}, (ctx) => this.processRemove(ctx, txes, findAll, removedMap))
|
||||
const collections = await ctx.with('process-collection', {}, (ctx) =>
|
||||
this.processCollection(ctx, txes, findAll, removedMap)
|
||||
const removed = await ctx.with('process-remove', {}, (ctx) =>
|
||||
this.processRemove(ctx.ctx, txes, findAll, removedMap)
|
||||
)
|
||||
const moves = await ctx.with('process-move', {}, (ctx) => this.processMove(ctx, txes, findAll))
|
||||
const collections = await ctx.with('process-collection', {}, (ctx) =>
|
||||
this.processCollection(ctx.ctx, txes, findAll, removedMap)
|
||||
)
|
||||
const moves = await ctx.with('process-move', {}, (ctx) => this.processMove(ctx.ctx, txes, findAll))
|
||||
|
||||
const triggerControl: Omit<TriggerControl, 'txFactory' | 'ctx' | 'result'> = {
|
||||
removedMap,
|
||||
@ -594,7 +597,7 @@ export class TServerStorage implements ServerStorage {
|
||||
serviceFx: (f) => {
|
||||
triggerFx.fx(() => f(this.serviceAdaptersManager))
|
||||
},
|
||||
findAll: fAll(ctx),
|
||||
findAll: fAll(ctx.ctx),
|
||||
findAllCtx: findAll,
|
||||
modelDb: this.modelDb,
|
||||
hierarchy: this.hierarchy,
|
||||
@ -614,8 +617,8 @@ export class TServerStorage implements ServerStorage {
|
||||
result.push(
|
||||
...(await this.triggers.apply(ctx, txes, {
|
||||
...triggerControl,
|
||||
ctx,
|
||||
findAll: fAll(ctx),
|
||||
ctx: ctx.ctx,
|
||||
findAll: fAll(ctx.ctx),
|
||||
result
|
||||
}))
|
||||
)
|
||||
@ -629,14 +632,14 @@ export class TServerStorage implements ServerStorage {
|
||||
|
||||
private async processDerivedTxes (
|
||||
derived: Tx[],
|
||||
ctx: MeasureContext,
|
||||
ctx: SessionOperationContext,
|
||||
triggerFx: Effects,
|
||||
findAll: ServerStorage['findAll'],
|
||||
removedMap: Map<Ref<Doc>, Doc>
|
||||
): Promise<Tx[]> {
|
||||
derived.sort((a, b) => a.modifiedOn - b.modifiedOn)
|
||||
|
||||
await ctx.with('derived-route-tx', {}, (ctx) => this.routeTx(ctx, removedMap, ...derived))
|
||||
await ctx.with('derived-route-tx', {}, (ctx) => this.routeTx(ctx.ctx, removedMap, ...derived))
|
||||
|
||||
const nestedTxes: Tx[] = []
|
||||
if (derived.length > 0) {
|
||||
@ -692,17 +695,8 @@ export class TServerStorage implements ServerStorage {
|
||||
return { passed, onEnd }
|
||||
}
|
||||
|
||||
async apply (ctx: MeasureContext, txes: Tx[], broadcast: boolean, target?: string[]): Promise<TxResult[]> {
|
||||
const result = await this.processTxes(ctx, txes)
|
||||
let derived: Tx[] = []
|
||||
|
||||
derived = result[1]
|
||||
|
||||
if (broadcast) {
|
||||
this.options?.broadcast?.([...txes, ...derived], target)
|
||||
}
|
||||
|
||||
return result[0]
|
||||
async apply (ctx: SessionOperationContext, txes: Tx[], broadcast: boolean, target?: string[]): Promise<TxResult> {
|
||||
return await this.processTxes(ctx, txes, broadcast, target)
|
||||
}
|
||||
|
||||
fillTxes (txes: Tx[], txToStore: Tx[], modelTx: Tx[], txToProcess: Tx[], applyTxes: Tx[]): void {
|
||||
@ -727,7 +721,12 @@ export class TServerStorage implements ServerStorage {
|
||||
}
|
||||
}
|
||||
|
||||
async processTxes (ctx: MeasureContext, txes: Tx[]): Promise<[TxResult[], Tx[]]> {
|
||||
async processTxes (
|
||||
ctx: SessionOperationContext,
|
||||
txes: Tx[],
|
||||
broadcast: boolean,
|
||||
target?: string[]
|
||||
): Promise<TxResult> {
|
||||
// store tx
|
||||
const _findAll: ServerStorage['findAll'] = async <T extends Doc>(
|
||||
ctx: MeasureContext,
|
||||
@ -745,14 +744,14 @@ export class TServerStorage implements ServerStorage {
|
||||
const removedMap = new Map<Ref<Doc>, Doc>()
|
||||
const onEnds: (() => void)[] = []
|
||||
const result: TxResult[] = []
|
||||
let derived: Tx[] = []
|
||||
const derived: Tx[] = [...txes].filter((it) => it._class !== core.class.TxApplyIf)
|
||||
|
||||
try {
|
||||
this.fillTxes(txes, txToStore, modelTx, txToProcess, applyTxes)
|
||||
for (const tx of applyTxes) {
|
||||
const applyIf = tx as TxApplyIf
|
||||
// Wait for scope promise if found
|
||||
const passed = await this.verifyApplyIf(ctx, applyIf, _findAll)
|
||||
const passed = await this.verifyApplyIf(ctx.ctx, applyIf, _findAll)
|
||||
onEnds.push(passed.onEnd)
|
||||
if (passed.passed) {
|
||||
result.push({
|
||||
@ -760,7 +759,7 @@ export class TServerStorage implements ServerStorage {
|
||||
success: true
|
||||
})
|
||||
this.fillTxes(applyIf.txes, txToStore, modelTx, txToProcess, applyTxes)
|
||||
derived = [...applyIf.txes]
|
||||
derived.push(...applyIf.txes)
|
||||
} else {
|
||||
result.push({
|
||||
derived: [],
|
||||
@ -776,35 +775,37 @@ export class TServerStorage implements ServerStorage {
|
||||
await this.triggers.tx(tx)
|
||||
await this.modelDb.tx(tx)
|
||||
}
|
||||
await ctx.with('domain-tx', {}, async (ctx) => await this.getAdapter(DOMAIN_TX).tx(ctx, ...txToStore))
|
||||
result.push(...(await ctx.with('apply', {}, (ctx) => this.routeTx(ctx, removedMap, ...txToProcess))))
|
||||
await ctx.with('domain-tx', {}, async (ctx) => await this.getAdapter(DOMAIN_TX).tx(ctx.ctx, ...txToStore))
|
||||
result.push(...(await ctx.with('apply', {}, (ctx) => this.routeTx(ctx.ctx, removedMap, ...txToProcess))))
|
||||
|
||||
// invoke triggers and store derived objects
|
||||
derived = derived.concat(await this.processDerived(ctx, txToProcess, triggerFx, _findAll, removedMap))
|
||||
derived.push(...(await this.processDerived(ctx, txToProcess, triggerFx, _findAll, removedMap)))
|
||||
|
||||
// index object
|
||||
await ctx.with('fulltext-tx', {}, async (ctx) => {
|
||||
await this.fulltext.tx(ctx, [...txToProcess, ...derived])
|
||||
await this.fulltext.tx(ctx.ctx, [...txToProcess, ...derived])
|
||||
})
|
||||
|
||||
for (const fx of triggerFx.effects) {
|
||||
await fx()
|
||||
}
|
||||
} catch (err: any) {
|
||||
ctx.error('error process tx', { error: err })
|
||||
ctx.ctx.error('error process tx', { error: err })
|
||||
throw err
|
||||
} finally {
|
||||
onEnds.forEach((p) => {
|
||||
p()
|
||||
})
|
||||
}
|
||||
return [result, derived]
|
||||
if (derived.length > 0 && broadcast) {
|
||||
ctx.derived.push({ derived, target })
|
||||
}
|
||||
return result[0]
|
||||
}
|
||||
|
||||
async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> {
|
||||
async tx (ctx: SessionOperationContext, tx: Tx): Promise<TxResult> {
|
||||
return await ctx.with('client-tx', { _class: tx._class }, async (ctx) => {
|
||||
const result = await this.processTxes(ctx, [tx])
|
||||
return [result[0][0], result[1]]
|
||||
return await this.processTxes(ctx, [tx], true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -15,22 +15,22 @@
|
||||
//
|
||||
|
||||
import core, {
|
||||
TxFactory,
|
||||
matchQuery,
|
||||
type AttachedDoc,
|
||||
type Class,
|
||||
type Doc,
|
||||
type DocumentQuery,
|
||||
type Hierarchy,
|
||||
type MeasureContext,
|
||||
type Obj,
|
||||
type Ref,
|
||||
type SessionOperationContext,
|
||||
type Tx,
|
||||
type TxCollectionCUD,
|
||||
type TxCreateDoc,
|
||||
TxFactory,
|
||||
matchQuery
|
||||
type TxCreateDoc
|
||||
} from '@hcengineering/core'
|
||||
|
||||
import { type Resource, getResource } from '@hcengineering/platform'
|
||||
import { getResource, type Resource } from '@hcengineering/platform'
|
||||
import type { Trigger, TriggerControl, TriggerFunc } from './types'
|
||||
|
||||
import serverCore from './plugin'
|
||||
@ -58,7 +58,7 @@ export class Triggers {
|
||||
}
|
||||
}
|
||||
|
||||
async apply (ctx: MeasureContext, tx: Tx[], ctrl: Omit<TriggerControl, 'txFactory'>): Promise<Tx[]> {
|
||||
async apply (ctx: SessionOperationContext, tx: Tx[], ctrl: Omit<TriggerControl, 'txFactory'>): Promise<Tx[]> {
|
||||
const result: Tx[] = []
|
||||
for (const [query, trigger, resource] of this.triggers) {
|
||||
let matches = tx
|
||||
@ -73,9 +73,9 @@ export class Triggers {
|
||||
result.push(
|
||||
...(await trigger(tx, {
|
||||
...ctrl,
|
||||
ctx,
|
||||
ctx: ctx.ctx,
|
||||
txFactory: new TxFactory(tx.modifiedBy, true),
|
||||
findAll: async (clazz, query, options) => await ctrl.findAllCtx(ctx, clazz, query, options),
|
||||
findAll: async (clazz, query, options) => await ctrl.findAllCtx(ctx.ctx, clazz, query, options),
|
||||
apply: async (tx, broadcast, target) => {
|
||||
return await ctrl.applyCtx(ctx, tx, broadcast, target)
|
||||
},
|
||||
|
@ -14,6 +14,7 @@
|
||||
//
|
||||
|
||||
import {
|
||||
MeasureMetricsContext,
|
||||
type Account,
|
||||
type Class,
|
||||
type Doc,
|
||||
@ -23,7 +24,6 @@ import {
|
||||
type Hierarchy,
|
||||
type LowLevelStorage,
|
||||
type MeasureContext,
|
||||
MeasureMetricsContext,
|
||||
type ModelDb,
|
||||
type Obj,
|
||||
type Ref,
|
||||
@ -31,6 +31,7 @@ import {
|
||||
type SearchQuery,
|
||||
type SearchResult,
|
||||
type ServerStorage,
|
||||
type SessionOperationContext,
|
||||
type Space,
|
||||
type Storage,
|
||||
type Timestamp,
|
||||
@ -48,7 +49,7 @@ import { type StorageAdapter } from './storage'
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SessionContext extends MeasureContext {
|
||||
export interface SessionContext extends SessionOperationContext {
|
||||
userEmail: string
|
||||
sessionId: string
|
||||
admin?: boolean
|
||||
@ -66,8 +67,6 @@ export interface Middleware {
|
||||
options?: FindOptions<T>
|
||||
) => Promise<FindResult<T>>
|
||||
searchFulltext: (ctx: SessionContext, query: SearchQuery, options: SearchOptions) => Promise<SearchResult>
|
||||
|
||||
handleBroadcast: (tx: Tx[], targets?: string[]) => Tx[]
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,17 +81,12 @@ export type HandledBroadcastFunc = (tx: Tx[], targets?: string[]) => Tx[]
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type MiddlewareCreator = (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
) => Promise<Middleware>
|
||||
export type MiddlewareCreator = (ctx: MeasureContext, storage: ServerStorage, next?: Middleware) => Promise<Middleware>
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type TxMiddlewareResult = [TxResult, Tx[], string[] | undefined]
|
||||
export type TxMiddlewareResult = TxResult
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -107,7 +101,7 @@ export interface Pipeline extends LowLevelStorage {
|
||||
options?: FindOptions<T>
|
||||
) => Promise<FindResult<T>>
|
||||
searchFulltext: (ctx: SessionContext, query: SearchQuery, options: SearchOptions) => Promise<SearchResult>
|
||||
tx: (ctx: SessionContext, tx: Tx) => Promise<[TxResult, Tx[], string[] | undefined]>
|
||||
tx: (ctx: SessionContext, tx: Tx) => Promise<TxResult>
|
||||
close: () => Promise<void>
|
||||
}
|
||||
|
||||
@ -137,7 +131,7 @@ export interface TriggerControl {
|
||||
serviceFx: (f: (adapter: ServiceAdaptersManager) => Promise<void>) => void
|
||||
// Bulk operations in case trigger require some
|
||||
apply: (tx: Tx[], broadcast: boolean, target?: string[]) => Promise<TxResult>
|
||||
applyCtx: (ctx: MeasureContext, tx: Tx[], broadcast: boolean, target?: string[]) => Promise<TxResult>
|
||||
applyCtx: (ctx: SessionOperationContext, tx: Tx[], broadcast: boolean, target?: string[]) => Promise<TxResult>
|
||||
|
||||
// Will create a live query if missing and return values immediately if already asked.
|
||||
queryFind: <T extends Doc>(
|
||||
@ -411,7 +405,7 @@ export interface ServerStorageOptions {
|
||||
// Indexing is not required to be started for upgrade mode.
|
||||
upgrade: boolean
|
||||
|
||||
broadcast?: BroadcastFunc
|
||||
broadcast: BroadcastFunc
|
||||
}
|
||||
|
||||
export interface ServiceAdapter {
|
||||
|
@ -54,15 +54,7 @@ export abstract class BaseMiddleware {
|
||||
if (this.next !== undefined) {
|
||||
return await this.next.tx(ctx, tx)
|
||||
}
|
||||
const res = await this.storage.tx(ctx, tx)
|
||||
return [res[0], res[1], undefined]
|
||||
}
|
||||
|
||||
provideHandleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
if (this.next !== undefined) {
|
||||
return this.next.handleBroadcast(tx, targets)
|
||||
}
|
||||
return tx
|
||||
return await this.storage.tx(ctx, tx)
|
||||
}
|
||||
|
||||
protected async provideFindAll<T extends Doc>(
|
||||
@ -74,7 +66,7 @@ export abstract class BaseMiddleware {
|
||||
if (this.next !== undefined) {
|
||||
return await this.next.findAll(ctx, _class, query, options)
|
||||
}
|
||||
return await this.storage.findAll(ctx, _class, query, options)
|
||||
return await this.storage.findAll(ctx.ctx, _class, query, options)
|
||||
}
|
||||
|
||||
protected async provideSearchFulltext (
|
||||
@ -85,6 +77,6 @@ export abstract class BaseMiddleware {
|
||||
if (this.next !== undefined) {
|
||||
return await this.next.searchFulltext(ctx, query, options)
|
||||
}
|
||||
return await this.storage.searchFulltext(ctx, query, options)
|
||||
return await this.storage.searchFulltext(ctx.ctx, query, options)
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import core, {
|
||||
TxCUD
|
||||
} from '@hcengineering/core'
|
||||
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { BaseMiddleware } from './base'
|
||||
|
||||
const configurationAccountEmail = '#configurator@hc.engineering'
|
||||
@ -45,7 +45,6 @@ export class ConfigurationMiddleware extends BaseMiddleware implements Middlewar
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<ConfigurationMiddleware> {
|
||||
@ -68,10 +67,6 @@ export class ConfigurationMiddleware extends BaseMiddleware implements Middlewar
|
||||
return await this.provideTx(ctx, tx)
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
}
|
||||
|
||||
override async findAll<T extends Doc>(
|
||||
ctx: SessionContext,
|
||||
_class: Ref<Class<T>>,
|
||||
|
@ -26,7 +26,7 @@ import {
|
||||
clone,
|
||||
toFindResult
|
||||
} from '@hcengineering/core'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { BaseMiddleware } from './base'
|
||||
|
||||
/**
|
||||
@ -37,12 +37,7 @@ export class LookupMiddleware extends BaseMiddleware implements Middleware {
|
||||
super(storage, next)
|
||||
}
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<LookupMiddleware> {
|
||||
static async create (ctx: MeasureContext, storage: ServerStorage, next?: Middleware): Promise<LookupMiddleware> {
|
||||
return new LookupMiddleware(storage, next)
|
||||
}
|
||||
|
||||
@ -50,10 +45,6 @@ export class LookupMiddleware extends BaseMiddleware implements Middleware {
|
||||
return await this.provideTx(ctx, tx)
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
}
|
||||
|
||||
override async findAll<T extends Doc>(
|
||||
ctx: SessionContext,
|
||||
_class: Ref<Class<T>>,
|
||||
|
@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { MeasureContext, ServerStorage, Tx, systemAccountEmail, TxCollectionCUD } from '@hcengineering/core'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import core, { MeasureContext, ServerStorage, Tx, TxCollectionCUD, systemAccountEmail } from '@hcengineering/core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { BaseMiddleware } from './base'
|
||||
|
||||
/**
|
||||
@ -25,19 +25,10 @@ export class ModifiedMiddleware extends BaseMiddleware implements Middleware {
|
||||
super(storage, next)
|
||||
}
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<ModifiedMiddleware> {
|
||||
static async create (ctx: MeasureContext, storage: ServerStorage, next?: Middleware): Promise<ModifiedMiddleware> {
|
||||
return new ModifiedMiddleware(storage, next)
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
}
|
||||
|
||||
async tx (ctx: SessionContext, tx: Tx): Promise<TxMiddlewareResult> {
|
||||
if (tx.modifiedBy !== core.account.System && ctx.userEmail !== systemAccountEmail) {
|
||||
tx.modifiedOn = Date.now()
|
||||
|
@ -30,7 +30,7 @@ import core, {
|
||||
systemAccountEmail
|
||||
} from '@hcengineering/core'
|
||||
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { DOMAIN_PREFERENCE } from '@hcengineering/server-preference'
|
||||
import { BaseMiddleware } from './base'
|
||||
import { getUser, mergeTargets } from './utils'
|
||||
@ -45,12 +45,7 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
|
||||
super(storage, next)
|
||||
}
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<PrivateMiddleware> {
|
||||
static async create (ctx: MeasureContext, storage: ServerStorage, next?: Middleware): Promise<PrivateMiddleware> {
|
||||
return new PrivateMiddleware(storage, next)
|
||||
}
|
||||
|
||||
@ -72,11 +67,11 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
|
||||
}
|
||||
}
|
||||
const res = await this.provideTx(ctx, tx)
|
||||
return [res[0], res[1], mergeTargets(target, res[2])]
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
// Add target to all broadcasts
|
||||
ctx.derived.forEach((it) => {
|
||||
it.target = mergeTargets(target, it.target)
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
override async findAll<T extends Doc>(
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
ServerStorage,
|
||||
Tx
|
||||
} from '@hcengineering/core'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { BaseMiddleware } from './base'
|
||||
|
||||
import { deepEqual } from 'fast-equals'
|
||||
@ -47,12 +47,7 @@ export class QueryJoinMiddleware extends BaseMiddleware implements Middleware {
|
||||
super(storage, next)
|
||||
}
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<QueryJoinMiddleware> {
|
||||
static async create (ctx: MeasureContext, storage: ServerStorage, next?: Middleware): Promise<QueryJoinMiddleware> {
|
||||
return new QueryJoinMiddleware(storage, next)
|
||||
}
|
||||
|
||||
@ -60,10 +55,6 @@ export class QueryJoinMiddleware extends BaseMiddleware implements Middleware {
|
||||
return await this.provideTx(ctx, tx)
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
}
|
||||
|
||||
override async findAll<T extends Doc>(
|
||||
ctx: SessionContext,
|
||||
_class: Ref<Class<T>>,
|
||||
|
@ -37,7 +37,7 @@ import core, {
|
||||
TypedSpace
|
||||
} from '@hcengineering/core'
|
||||
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
|
||||
import { BaseMiddleware } from './base'
|
||||
import { getUser } from './utils'
|
||||
@ -54,7 +54,6 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<SpacePermissionsMiddleware> {
|
||||
@ -317,16 +316,14 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle
|
||||
await this.processPermissionsUpdatesFromTx(ctx, tx)
|
||||
await this.checkPermissions(ctx, tx)
|
||||
const res = await this.provideTx(ctx, tx)
|
||||
for (const tx of res[1]) {
|
||||
await this.processPermissionsUpdatesFromTx(ctx, tx)
|
||||
for (const txd of ctx.derived) {
|
||||
for (const tx of txd.derived) {
|
||||
await this.processPermissionsUpdatesFromTx(ctx, tx)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
}
|
||||
|
||||
protected async checkPermissions (ctx: SessionContext, tx: Tx): Promise<void> {
|
||||
if (tx._class === core.class.TxApplyIf) {
|
||||
const applyTx = tx as TxApplyIf
|
||||
|
@ -45,7 +45,7 @@ import core, {
|
||||
systemAccountEmail
|
||||
} from '@hcengineering/core'
|
||||
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
|
||||
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { BaseMiddleware } from './base'
|
||||
import { getUser, isOwner, isSystem, mergeTargets } from './utils'
|
||||
|
||||
@ -74,21 +74,16 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
core.space.Tx
|
||||
]
|
||||
|
||||
private constructor (
|
||||
private readonly broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
) {
|
||||
private constructor (storage: ServerStorage, next?: Middleware) {
|
||||
super(storage, next)
|
||||
}
|
||||
|
||||
static async create (
|
||||
ctx: MeasureContext,
|
||||
broadcast: BroadcastFunc,
|
||||
storage: ServerStorage,
|
||||
next?: Middleware
|
||||
): Promise<SpaceSecurityMiddleware> {
|
||||
const res = new SpaceSecurityMiddleware(broadcast, storage, next)
|
||||
const res = new SpaceSecurityMiddleware(storage, next)
|
||||
res.spaceMeasureCtx = ctx.newChild('space chain', {})
|
||||
res.spaceSecurityInit = res.init(res.spaceMeasureCtx)
|
||||
return res
|
||||
@ -180,6 +175,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
}
|
||||
|
||||
private async pushMembersHandle (
|
||||
ctx: SessionContext,
|
||||
addedMembers: Ref<Account> | Position<Ref<Account>>,
|
||||
space: Ref<Space>
|
||||
): Promise<void> {
|
||||
@ -187,14 +183,15 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
for (const member of addedMembers.$each) {
|
||||
this.addMemberSpace(member, space)
|
||||
}
|
||||
await this.brodcastEvent(addedMembers.$each, space)
|
||||
await this.brodcastEvent(ctx, addedMembers.$each, space)
|
||||
} else {
|
||||
this.addMemberSpace(addedMembers, space)
|
||||
await this.brodcastEvent([addedMembers], space)
|
||||
await this.brodcastEvent(ctx, [addedMembers], space)
|
||||
}
|
||||
}
|
||||
|
||||
private async pullMembersHandle (
|
||||
ctx: SessionContext,
|
||||
removedMembers: Partial<Ref<Account>> | PullArray<Ref<Account>>,
|
||||
space: Ref<Space>
|
||||
): Promise<void> {
|
||||
@ -204,15 +201,15 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
for (const member of $in) {
|
||||
this.removeMemberSpace(member, space)
|
||||
}
|
||||
await this.brodcastEvent($in, space)
|
||||
await this.brodcastEvent(ctx, $in, space)
|
||||
}
|
||||
} else {
|
||||
this.removeMemberSpace(removedMembers, space)
|
||||
await this.brodcastEvent([removedMembers], space)
|
||||
await this.brodcastEvent(ctx, [removedMembers], space)
|
||||
}
|
||||
}
|
||||
|
||||
private async syncMembers (members: Ref<Account>[], space: SpaceWithMembers): Promise<void> {
|
||||
private async syncMembers (ctx: SessionContext, members: Ref<Account>[], space: SpaceWithMembers): Promise<void> {
|
||||
const oldMembers = new Set(space.members)
|
||||
const newMembers = new Set(members)
|
||||
const changed: Ref<Account>[] = []
|
||||
@ -229,11 +226,11 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
}
|
||||
}
|
||||
if (changed.length > 0) {
|
||||
await this.brodcastEvent(changed, space._id)
|
||||
await this.brodcastEvent(ctx, changed, space._id)
|
||||
}
|
||||
}
|
||||
|
||||
private async brodcastEvent (users: Ref<Account>[], space?: Ref<Space>): Promise<void> {
|
||||
private async brodcastEvent (ctx: SessionContext, users: Ref<Account>[], space?: Ref<Space>): Promise<void> {
|
||||
const targets = await this.getTargets(users)
|
||||
const tx: TxWorkspaceEvent = {
|
||||
_class: core.class.TxWorkspaceEvent,
|
||||
@ -245,12 +242,16 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
space: core.space.DerivedTx,
|
||||
params: null
|
||||
}
|
||||
this.broadcast([tx], targets)
|
||||
ctx.derived.push({
|
||||
derived: [tx],
|
||||
target: targets
|
||||
})
|
||||
}
|
||||
|
||||
private async broadcastNonMembers (space: SpaceWithMembers): Promise<void> {
|
||||
private async broadcastNonMembers (ctx: SessionContext, space: SpaceWithMembers): Promise<void> {
|
||||
const users = await this.storage.modelDb.findAll(core.class.Account, { _id: { $nin: space?.members } })
|
||||
await this.brodcastEvent(
|
||||
ctx,
|
||||
users.map((p) => p._id),
|
||||
space._id
|
||||
)
|
||||
@ -268,23 +269,23 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
if (updateDoc.operations.private) {
|
||||
this.privateSpaces.add(updateDoc.objectId)
|
||||
this.publicSpaces.delete(updateDoc.objectId)
|
||||
await this.broadcastNonMembers(space)
|
||||
await this.broadcastNonMembers(ctx, space)
|
||||
} else if (!updateDoc.operations.private) {
|
||||
this.privateSpaces.delete(updateDoc.objectId)
|
||||
this.publicSpaces.add(updateDoc.objectId)
|
||||
await this.broadcastNonMembers(space)
|
||||
await this.broadcastNonMembers(ctx, space)
|
||||
}
|
||||
}
|
||||
|
||||
if (updateDoc.operations.members !== undefined) {
|
||||
await this.syncMembers(updateDoc.operations.members, space)
|
||||
await this.syncMembers(ctx, updateDoc.operations.members, space)
|
||||
}
|
||||
if (updateDoc.operations.$push?.members !== undefined) {
|
||||
await this.pushMembersHandle(updateDoc.operations.$push.members, space._id)
|
||||
await this.pushMembersHandle(ctx, updateDoc.operations.$push.members, space._id)
|
||||
}
|
||||
|
||||
if (updateDoc.operations.$pull?.members !== undefined) {
|
||||
await this.pullMembersHandle(updateDoc.operations.$pull.members, space._id)
|
||||
await this.pullMembersHandle(ctx, updateDoc.operations.$pull.members, space._id)
|
||||
}
|
||||
const updatedSpace = TxProcessor.updateDoc2Doc(space as any, updateDoc)
|
||||
this.spacesMap.set(updateDoc.objectId, updatedSpace)
|
||||
@ -380,9 +381,9 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
}
|
||||
await this.processTxSpaceDomain(tx as TxCUD<Doc>)
|
||||
if (h.isDerived(cudTx.objectClass, core.class.Account) && cudTx._class === core.class.TxUpdateDoc) {
|
||||
const ctx = cudTx as TxUpdateDoc<Account>
|
||||
if (ctx.operations.role !== undefined) {
|
||||
await this.brodcastEvent([ctx.objectId])
|
||||
const cud = cudTx as TxUpdateDoc<Account>
|
||||
if (cud.operations.role !== undefined) {
|
||||
await this.brodcastEvent(ctx, [cud.objectId])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -397,23 +398,25 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
await this.processTx(ctx, tx)
|
||||
const targets = await this.getTxTargets(ctx, tx)
|
||||
const res = await this.provideTx(ctx, tx)
|
||||
for (const tx of res[1]) {
|
||||
await this.processTx(ctx, tx)
|
||||
for (const txd of ctx.derived) {
|
||||
for (const tx of txd.derived) {
|
||||
await this.processTx(ctx, tx)
|
||||
}
|
||||
}
|
||||
return [res[0], res[1], mergeTargets(targets, res[2])]
|
||||
}
|
||||
ctx.derived.forEach((it) => {
|
||||
it.target = mergeTargets(targets, it.target)
|
||||
})
|
||||
|
||||
handleBroadcast (tx: Tx[], targets?: string[]): Tx[] {
|
||||
const process = async (): Promise<void> => {
|
||||
await this.waitInit()
|
||||
for (const t of tx) {
|
||||
await this.waitInit()
|
||||
for (const tt of ctx.derived) {
|
||||
for (const t of tt.derived) {
|
||||
if (this.storage.hierarchy.isDerived(t._class, core.class.TxCUD)) {
|
||||
await this.processTxSpaceDomain(t as TxCUD<Doc>)
|
||||
}
|
||||
}
|
||||
}
|
||||
void process()
|
||||
return this.provideHandleBroadcast(tx, targets)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
private getAllAllowedSpaces (account: Account, isData: boolean): Ref<Space>[] {
|
||||
|
@ -32,7 +32,10 @@ import core, {
|
||||
SortingOrder,
|
||||
type Space,
|
||||
TxOperations,
|
||||
type WorkspaceId
|
||||
type WorkspaceId,
|
||||
type SessionOperationContext,
|
||||
type ParamsType,
|
||||
type FullParamsType
|
||||
} from '@hcengineering/core'
|
||||
import {
|
||||
type ContentTextAdapter,
|
||||
@ -169,11 +172,26 @@ describe('mongo operations', () => {
|
||||
storageFactory: () => createNullStorageFactory()
|
||||
}
|
||||
const ctx = new MeasureMetricsContext('client', {})
|
||||
const serverStorage = await createServerStorage(ctx, conf, { upgrade: false })
|
||||
const serverStorage = await createServerStorage(ctx, conf, {
|
||||
upgrade: false,
|
||||
broadcast: () => {}
|
||||
})
|
||||
const soCtx: SessionOperationContext = {
|
||||
ctx,
|
||||
derived: [],
|
||||
with: async <T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
op: (ctx: SessionOperationContext) => T | Promise<T>,
|
||||
fullParams?: FullParamsType
|
||||
): Promise<T> => {
|
||||
return await op(soCtx)
|
||||
}
|
||||
}
|
||||
client = await createClient(async (handler) => {
|
||||
const st: ClientConnection = {
|
||||
findAll: async (_class, query, options) => await serverStorage.findAll(ctx, _class, query, options),
|
||||
tx: async (tx) => (await serverStorage.tx(ctx, tx))[0],
|
||||
tx: async (tx) => await serverStorage.tx(soCtx, tx),
|
||||
searchFulltext: async () => ({ docs: [] }),
|
||||
close: async () => {},
|
||||
loadChunk: async (domain): Promise<DocChunk> => await Promise.reject(new Error('unsupported')),
|
||||
@ -197,7 +215,7 @@ describe('mongo operations', () => {
|
||||
})
|
||||
|
||||
it('check add', async () => {
|
||||
jest.setTimeout(50000)
|
||||
jest.setTimeout(500000)
|
||||
for (let i = 0; i < 50; i++) {
|
||||
await operations.createDoc(taskPlugin.class.Task, '' as Ref<Space>, {
|
||||
name: `my-task-${i}`,
|
||||
|
@ -40,7 +40,6 @@ export interface Request<P extends any[]> {
|
||||
export interface HelloRequest extends Request<any[]> {
|
||||
binary?: boolean
|
||||
compression?: boolean
|
||||
broadcast?: boolean
|
||||
}
|
||||
/**
|
||||
* @public
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Doc, DocChunk, DocInfo, Domain, MeasureContext, Ref, StorageIterator } from '@hcengineering/core'
|
||||
import { estimateDocSize, Pipeline } from '@hcengineering/server-core'
|
||||
import { Doc, DocInfo, Domain, Ref, StorageIterator } from '@hcengineering/core'
|
||||
import { Pipeline, estimateDocSize } from '@hcengineering/server-core'
|
||||
import { Token } from '@hcengineering/server-token'
|
||||
import { BroadcastCall, ClientSession, Session } from '@hcengineering/server-ws'
|
||||
import { ClientSession, Session, type ClientSessionCtx } from '@hcengineering/server-ws'
|
||||
|
||||
const chunkSize = 2 * 1024 * 1024
|
||||
|
||||
@ -19,9 +19,9 @@ export interface ChunkInfo {
|
||||
* @public
|
||||
*/
|
||||
export interface BackupSession extends Session {
|
||||
loadChunk: (ctx: MeasureContext, domain: Domain, idx?: number) => Promise<DocChunk>
|
||||
closeChunk: (ctx: MeasureContext, idx: number) => Promise<void>
|
||||
loadDocs: (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]) => Promise<Doc[]>
|
||||
loadChunk: (ctx: ClientSessionCtx, domain: Domain, idx?: number) => Promise<void>
|
||||
closeChunk: (ctx: ClientSessionCtx, idx: number) => Promise<void>
|
||||
loadDocs: (ctx: ClientSessionCtx, domain: Domain, docs: Ref<Doc>[]) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,19 +29,18 @@ export interface BackupSession extends Session {
|
||||
*/
|
||||
export class BackupClientSession extends ClientSession implements BackupSession {
|
||||
constructor (
|
||||
protected readonly broadcast: BroadcastCall,
|
||||
protected readonly token: Token,
|
||||
protected readonly _pipeline: Pipeline
|
||||
) {
|
||||
super(broadcast, token, _pipeline)
|
||||
super(token, _pipeline)
|
||||
}
|
||||
|
||||
idIndex = 0
|
||||
chunkInfo = new Map<number, ChunkInfo>()
|
||||
|
||||
async loadChunk (ctx: MeasureContext, domain: Domain, idx?: number): Promise<DocChunk> {
|
||||
async loadChunk (_ctx: ClientSessionCtx, domain: Domain, idx?: number): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
return await ctx.with('load-chunk', { domain }, async (ctx) => {
|
||||
await _ctx.ctx.with('load-chunk', { domain }, async (ctx) => {
|
||||
idx = idx ?? this.idIndex++
|
||||
let chunk: ChunkInfo | undefined = this.chunkInfo.get(idx)
|
||||
if (chunk !== undefined) {
|
||||
@ -71,37 +70,40 @@ export class BackupClientSession extends ClientSession implements BackupSession
|
||||
docs.push(doc)
|
||||
}
|
||||
|
||||
return {
|
||||
await _ctx.sendResponse({
|
||||
idx,
|
||||
docs,
|
||||
finished: chunk.finished
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async closeChunk (ctx: MeasureContext, idx: number): Promise<void> {
|
||||
async closeChunk (ctx: ClientSessionCtx, idx: number): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
await ctx.with('close-chunk', {}, async () => {
|
||||
await ctx.ctx.with('close-chunk', {}, async () => {
|
||||
const chunk = this.chunkInfo.get(idx)
|
||||
this.chunkInfo.delete(idx)
|
||||
if (chunk != null) {
|
||||
await chunk.iterator.close(ctx)
|
||||
await chunk.iterator.close(ctx.ctx)
|
||||
}
|
||||
await ctx.sendResponse({})
|
||||
})
|
||||
}
|
||||
|
||||
async loadDocs (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
|
||||
async loadDocs (ctx: ClientSessionCtx, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
return await this._pipeline.storage.load(ctx, domain, docs)
|
||||
await ctx.sendResponse(await this._pipeline.storage.load(ctx.ctx, domain, docs))
|
||||
}
|
||||
|
||||
async upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
|
||||
async upload (ctx: ClientSessionCtx, domain: Domain, docs: Doc[]): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
await this._pipeline.storage.upload(ctx, domain, docs)
|
||||
await this._pipeline.storage.upload(ctx.ctx, domain, docs)
|
||||
await ctx.sendResponse({})
|
||||
}
|
||||
|
||||
async clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
||||
async clean (ctx: ClientSessionCtx, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
await this._pipeline.storage.clean(ctx, domain, docs)
|
||||
await this._pipeline.storage.clean(ctx.ctx, domain, docs)
|
||||
await ctx.sendResponse({})
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ describe('server', () => {
|
||||
return { docs: [] }
|
||||
}
|
||||
}),
|
||||
sessionFactory: (token, pipeline, broadcast) => new ClientSession(broadcast, token, pipeline),
|
||||
sessionFactory: (token, pipeline) => new ClientSession(token, pipeline),
|
||||
port: 3335,
|
||||
productId: '',
|
||||
serverFactory: startHttpServer,
|
||||
@ -182,7 +182,7 @@ describe('server', () => {
|
||||
return { docs: [] }
|
||||
}
|
||||
}),
|
||||
sessionFactory: (token, pipeline, broadcast) => new ClientSession(broadcast, token, pipeline),
|
||||
sessionFactory: (token, pipeline) => new ClientSession(token, pipeline),
|
||||
port: 3336,
|
||||
productId: '',
|
||||
serverFactory: startHttpServer,
|
||||
|
@ -19,6 +19,7 @@ import core, {
|
||||
TxProcessor,
|
||||
WorkspaceEvent,
|
||||
generateId,
|
||||
toIdMap,
|
||||
type Account,
|
||||
type BulkUpdateEvent,
|
||||
type Class,
|
||||
@ -26,23 +27,47 @@ import core, {
|
||||
type DocumentQuery,
|
||||
type FindOptions,
|
||||
type FindResult,
|
||||
type LoadModelResponse,
|
||||
type FullParamsType,
|
||||
type MeasureContext,
|
||||
type ParamsType,
|
||||
type Ref,
|
||||
type SearchOptions,
|
||||
type SearchQuery,
|
||||
type SearchResult,
|
||||
type SessionOperationContext,
|
||||
type Timestamp,
|
||||
type Tx,
|
||||
type TxApplyIf,
|
||||
type TxApplyResult,
|
||||
type TxCUD,
|
||||
type TxResult,
|
||||
type TxWorkspaceEvent
|
||||
} from '@hcengineering/core'
|
||||
import { type Pipeline, type SessionContext } from '@hcengineering/server-core'
|
||||
import { type Token } from '@hcengineering/server-token'
|
||||
import { type BroadcastCall, type Session, type SessionRequest, type StatisticsElement } from './types'
|
||||
import { type ClientSessionCtx, type Session, type SessionRequest, type StatisticsElement } from './types'
|
||||
|
||||
class SessionContextImpl implements SessionContext {
|
||||
constructor (
|
||||
readonly ctx: MeasureContext,
|
||||
readonly userEmail: string,
|
||||
readonly sessionId: string,
|
||||
readonly admin: boolean | undefined,
|
||||
readonly derived: SessionContext['derived']
|
||||
) {}
|
||||
|
||||
with<T>(
|
||||
name: string,
|
||||
params: ParamsType,
|
||||
op: (ctx: SessionOperationContext) => 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)),
|
||||
fullParams
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -52,7 +77,6 @@ export class ClientSession implements Session {
|
||||
requests = new Map<string, SessionRequest>()
|
||||
binaryMode: boolean = false
|
||||
useCompression: boolean = true
|
||||
useBroadcast: boolean = false
|
||||
sessionId = ''
|
||||
lastRequest = Date.now()
|
||||
|
||||
@ -62,7 +86,6 @@ export class ClientSession implements Session {
|
||||
measures: { id: string, message: string, time: 0 }[] = []
|
||||
|
||||
constructor (
|
||||
protected readonly broadcast: BroadcastCall,
|
||||
protected readonly token: Token,
|
||||
protected readonly _pipeline: Pipeline
|
||||
) {}
|
||||
@ -83,17 +106,22 @@ export class ClientSession implements Session {
|
||||
return this._pipeline
|
||||
}
|
||||
|
||||
async ping (): Promise<string> {
|
||||
async ping (ctx: ClientSessionCtx): Promise<void> {
|
||||
// console.log('ping')
|
||||
this.lastRequest = Date.now()
|
||||
return 'pong!'
|
||||
await ctx.sendResponse('pong!')
|
||||
}
|
||||
|
||||
async loadModel (ctx: MeasureContext, lastModelTx: Timestamp, hash?: string): Promise<Tx[] | LoadModelResponse> {
|
||||
return await ctx.with('load-model', {}, async () => await this._pipeline.storage.loadModel(lastModelTx, hash))
|
||||
async loadModel (ctx: ClientSessionCtx, lastModelTx: Timestamp, hash?: string): Promise<void> {
|
||||
const result = await ctx.ctx.with(
|
||||
'load-model',
|
||||
{},
|
||||
async () => await this._pipeline.storage.loadModel(lastModelTx, hash)
|
||||
)
|
||||
await ctx.sendResponse(result)
|
||||
}
|
||||
|
||||
async getAccount (ctx: MeasureContext): Promise<Account> {
|
||||
async getAccount (ctx: ClientSessionCtx): Promise<void> {
|
||||
const account = await this._pipeline.modelDb.findAll(core.class.Account, { email: this.token.email })
|
||||
if (account.length === 0 && this.token.extra?.admin === 'true') {
|
||||
const systemAccount = await this._pipeline.modelDb.findAll(core.class.Account, {
|
||||
@ -112,20 +140,24 @@ export class ClientSession implements Session {
|
||||
},
|
||||
this.token.email as Ref<Account>
|
||||
)
|
||||
const context = ctx as SessionContext
|
||||
context.userEmail = this.token.email
|
||||
context.admin = this.token.extra?.admin === 'true'
|
||||
const context = new SessionContextImpl(
|
||||
ctx.ctx,
|
||||
this.token.email,
|
||||
this.sessionId,
|
||||
this.token.extra?.admin === 'true',
|
||||
[]
|
||||
)
|
||||
await this._pipeline.tx(context, createTx)
|
||||
const acc = TxProcessor.createDoc2Doc(createTx)
|
||||
return acc
|
||||
await ctx.sendResponse(acc)
|
||||
} else {
|
||||
return systemAccount[0]
|
||||
await ctx.sendResponse(systemAccount[0])
|
||||
}
|
||||
}
|
||||
return account[0]
|
||||
await ctx.sendResponse(account[0])
|
||||
}
|
||||
|
||||
async findAll<T extends Doc>(
|
||||
async findAllRaw<T extends Doc>(
|
||||
ctx: MeasureContext,
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
@ -134,89 +166,162 @@ export class ClientSession implements Session {
|
||||
this.lastRequest = Date.now()
|
||||
this.total.find++
|
||||
this.current.find++
|
||||
const context = ctx as SessionContext
|
||||
context.userEmail = this.token.email
|
||||
context.admin = this.token.extra?.admin === 'true'
|
||||
const context = new SessionContextImpl(
|
||||
ctx,
|
||||
this.token.email,
|
||||
this.sessionId,
|
||||
this.token.extra?.admin === 'true',
|
||||
[]
|
||||
)
|
||||
return await this._pipeline.findAll(context, _class, query, options)
|
||||
}
|
||||
|
||||
async searchFulltext (ctx: MeasureContext, query: SearchQuery, options: SearchOptions): Promise<SearchResult> {
|
||||
this.lastRequest = Date.now()
|
||||
const context = ctx as SessionContext
|
||||
context.userEmail = this.token.email
|
||||
context.admin = this.token.extra?.admin === 'true'
|
||||
return await this._pipeline.searchFulltext(context, query, options)
|
||||
async findAll<T extends Doc>(
|
||||
ctx: ClientSessionCtx,
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
options?: FindOptions<T>
|
||||
): Promise<void> {
|
||||
await ctx.sendResponse(await this.findAllRaw(ctx.ctx, _class, query, options))
|
||||
}
|
||||
|
||||
async tx (ctx: MeasureContext, tx: Tx): Promise<TxResult> {
|
||||
async searchFulltext (ctx: ClientSessionCtx, query: SearchQuery, options: SearchOptions): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
const context = new SessionContextImpl(
|
||||
ctx.ctx,
|
||||
this.token.email,
|
||||
this.sessionId,
|
||||
this.token.extra?.admin === 'true',
|
||||
[]
|
||||
)
|
||||
await ctx.sendResponse(await this._pipeline.searchFulltext(context, query, options))
|
||||
}
|
||||
|
||||
async txRaw (ctx: MeasureContext, tx: Tx): Promise<void> {
|
||||
// Just do Tx and do not send anything
|
||||
await this.tx({ ctx, sendResponse: async () => {}, send: async () => {}, sendError: async () => {} }, tx)
|
||||
}
|
||||
|
||||
async tx (ctx: ClientSessionCtx, tx: Tx): Promise<void> {
|
||||
this.lastRequest = Date.now()
|
||||
this.total.tx++
|
||||
this.current.tx++
|
||||
const context = ctx as SessionContext
|
||||
context.userEmail = this.token.email
|
||||
context.admin = this.token.extra?.admin === 'true'
|
||||
const [result, derived, target] = await this._pipeline.tx(context, tx)
|
||||
const context = new SessionContextImpl(
|
||||
ctx.ctx,
|
||||
this.token.email,
|
||||
this.sessionId,
|
||||
this.token.extra?.admin === 'true',
|
||||
[]
|
||||
)
|
||||
|
||||
let shouldBroadcast = true
|
||||
const result = await this._pipeline.tx(context, tx)
|
||||
|
||||
if (tx._class === core.class.TxApplyIf) {
|
||||
const apply = tx as TxApplyIf
|
||||
shouldBroadcast = apply.notify ?? true
|
||||
// Send result immideately
|
||||
await ctx.sendResponse(result)
|
||||
|
||||
// We need to combine all derived data and check if we need to send it
|
||||
|
||||
// Combine targets by sender
|
||||
|
||||
const toSendTarget = new Map<string, Tx[]>()
|
||||
|
||||
const getTxes = (key: string): Tx[] => {
|
||||
let txes = toSendTarget.get(key)
|
||||
if (txes === undefined) {
|
||||
txes = []
|
||||
toSendTarget.set(key, txes)
|
||||
}
|
||||
return txes
|
||||
}
|
||||
|
||||
if (tx._class !== core.class.TxApplyIf) {
|
||||
this.broadcast(null, this.token.workspace, { result: tx }, target)
|
||||
}
|
||||
if (shouldBroadcast) {
|
||||
if (this.useBroadcast) {
|
||||
if (derived.length > 250) {
|
||||
const classes = new Set<Ref<Class<Doc>>>()
|
||||
for (const dtx of derived) {
|
||||
if (this._pipeline.storage.hierarchy.isDerived(dtx._class, core.class.TxCUD)) {
|
||||
classes.add((dtx as TxCUD<Doc>).objectClass)
|
||||
}
|
||||
const etx = TxProcessor.extractTx(dtx)
|
||||
if (this._pipeline.storage.hierarchy.isDerived(etx._class, core.class.TxCUD)) {
|
||||
classes.add((etx as TxCUD<Doc>).objectClass)
|
||||
}
|
||||
}
|
||||
console.log('Broadcasting bulk', derived.length)
|
||||
const bevent = this.createBroadcastEvent(Array.from(classes))
|
||||
if (tx._class === core.class.TxApplyIf) {
|
||||
;(result as TxApplyResult).derived.push(bevent)
|
||||
}
|
||||
this.broadcast(null, this.token.workspace, { result: bevent }, target)
|
||||
} else {
|
||||
if (tx._class === core.class.TxApplyIf) {
|
||||
;(result as TxApplyResult).derived.push(...derived)
|
||||
}
|
||||
// Let's send after our response will go out
|
||||
setImmediate(() => {
|
||||
while (derived.length > 0) {
|
||||
const part = derived.splice(0, 250)
|
||||
console.log('Broadcasting part', part.length, derived.length)
|
||||
this.broadcast(null, this.token.workspace, { result: part }, target)
|
||||
}
|
||||
})
|
||||
// Put current user as send target
|
||||
toSendTarget.set(this.getUser(), [])
|
||||
for (const txd of context.derived) {
|
||||
if (txd.target === undefined) {
|
||||
getTxes('').push(...txd.derived)
|
||||
|
||||
// Also add to all other targeted sends
|
||||
for (const v of toSendTarget.values()) {
|
||||
v.push(...txd.derived)
|
||||
}
|
||||
} else {
|
||||
// Let's send after our response will go out
|
||||
setImmediate(() => {
|
||||
while (derived.length > 0) {
|
||||
const part = derived.splice(0, 250)
|
||||
this.broadcast(null, this.token.workspace, { result: part }, target)
|
||||
}
|
||||
})
|
||||
for (const t of txd.target) {
|
||||
getTxes(t).push(...txd.derived)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tx._class === core.class.TxApplyIf) {
|
||||
const apply = tx as TxApplyIf
|
||||
|
||||
if (apply.extraNotify !== undefined && apply.extraNotify.length > 0) {
|
||||
;(result as TxApplyResult).derived.push(this.createBroadcastEvent(apply.extraNotify))
|
||||
const handleSend = async (derived: Tx[], target?: string, exclude?: string[]): Promise<void> => {
|
||||
if (derived.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (derived.length > 10000) {
|
||||
await this.sendWithPart(derived, ctx, target, exclude)
|
||||
} else {
|
||||
// Let's send after our response will go out
|
||||
console.log('Broadcasting', derived.length, derived.length)
|
||||
await ctx.send(derived, target, exclude)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
const toSendAll = toSendTarget.get('') ?? []
|
||||
toSendTarget.delete('')
|
||||
|
||||
// Send original Txes first.
|
||||
if (tx._class === core.class.TxApplyIf && (result as TxApplyResult).success) {
|
||||
const txMap = toIdMap((tx as TxApplyIf).txes as Tx[])
|
||||
|
||||
for (const [k, derived] of toSendTarget.entries()) {
|
||||
// good, we could send apply transactions first.
|
||||
const part1 = derived.filter((it) => txMap.has(it._id))
|
||||
await ctx.send(part1, k, undefined)
|
||||
|
||||
toSendTarget.set(
|
||||
k,
|
||||
derived.filter((it) => !txMap.has(it._id))
|
||||
)
|
||||
}
|
||||
}
|
||||
if (tx._class !== core.class.TxApplyIf) {
|
||||
for (const [k, derived] of toSendTarget.entries()) {
|
||||
// good, we could send apply transactions first.
|
||||
const part1 = derived.filter((it) => it._id === tx._id)
|
||||
await ctx.send(part1, k, undefined)
|
||||
|
||||
toSendTarget.set(
|
||||
k,
|
||||
derived.filter((it) => it._id !== tx._id)
|
||||
)
|
||||
}
|
||||
}
|
||||
// Then send targeted and all other
|
||||
for (const [k, v] of toSendTarget.entries()) {
|
||||
void handleSend(v, k)
|
||||
}
|
||||
// Send all other except us.
|
||||
void handleSend(toSendAll, undefined, Array.from(toSendTarget.keys()))
|
||||
}
|
||||
|
||||
private async sendWithPart (
|
||||
derived: Tx[],
|
||||
ctx: ClientSessionCtx,
|
||||
target: string | undefined,
|
||||
exclude: string[] | undefined
|
||||
): Promise<void> {
|
||||
const classes = new Set<Ref<Class<Doc>>>()
|
||||
for (const dtx of derived) {
|
||||
if (this._pipeline.storage.hierarchy.isDerived(dtx._class, core.class.TxCUD)) {
|
||||
classes.add((dtx as TxCUD<Doc>).objectClass)
|
||||
}
|
||||
const etx = TxProcessor.extractTx(dtx)
|
||||
if (this._pipeline.storage.hierarchy.isDerived(etx._class, core.class.TxCUD)) {
|
||||
classes.add((etx as TxCUD<Doc>).objectClass)
|
||||
}
|
||||
}
|
||||
console.log('Broadcasting compact bulk', derived.length)
|
||||
const bevent = this.createBroadcastEvent(Array.from(classes))
|
||||
await ctx.send([bevent], target, exclude)
|
||||
}
|
||||
|
||||
private createBroadcastEvent (classes: Ref<Class<Doc>>[]): TxWorkspaceEvent<BulkUpdateEvent> {
|
||||
|
@ -18,6 +18,7 @@ import core, {
|
||||
TxFactory,
|
||||
WorkspaceEvent,
|
||||
generateId,
|
||||
getWorkspaceId,
|
||||
systemAccountEmail,
|
||||
toWorkspaceString,
|
||||
versionToString,
|
||||
@ -28,14 +29,14 @@ import core, {
|
||||
type TxWorkspaceEvent,
|
||||
type WorkspaceId
|
||||
} from '@hcengineering/core'
|
||||
import { unknownError } from '@hcengineering/platform'
|
||||
import { unknownError, type Status } from '@hcengineering/platform'
|
||||
import { type HelloRequest, type HelloResponse, type Request, type Response } from '@hcengineering/rpc'
|
||||
import type { Pipeline, SessionContext } from '@hcengineering/server-core'
|
||||
import type { Pipeline } from '@hcengineering/server-core'
|
||||
import { type Token } from '@hcengineering/server-token'
|
||||
|
||||
import {
|
||||
LOGGING_ENABLED,
|
||||
type BroadcastCall,
|
||||
type ClientSessionCtx,
|
||||
type ConnectionSocket,
|
||||
type PipelineFactory,
|
||||
type ServerFactory,
|
||||
@ -67,10 +68,6 @@ function timeoutPromise (time: number): { promise: Promise<void>, cancelHandle:
|
||||
}
|
||||
}
|
||||
|
||||
function onNextTick (op: () => void): void {
|
||||
setImmediate(op)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -95,7 +92,7 @@ class TSessionManager implements SessionManager {
|
||||
|
||||
constructor (
|
||||
readonly ctx: MeasureContext,
|
||||
readonly sessionFactory: (token: Token, pipeline: Pipeline, broadcast: BroadcastCall) => Session,
|
||||
readonly sessionFactory: (token: Token, pipeline: Pipeline) => Session,
|
||||
readonly timeouts: Timeouts
|
||||
) {
|
||||
this.checkInterval = setInterval(() => {
|
||||
@ -175,7 +172,7 @@ class TSessionManager implements SessionManager {
|
||||
this.ctx.warn('session hang, closing...', { wsId, user: s[1].session.getUser() })
|
||||
|
||||
// Force close workspace if only one client and it hang.
|
||||
void this.close(s[1].socket, wsId)
|
||||
void this.close(this.ctx, s[1].socket, wsId)
|
||||
continue
|
||||
}
|
||||
if (diff > 20000 && diff < 60000 && this.ticks % 10 === 0) {
|
||||
@ -218,7 +215,7 @@ class TSessionManager implements SessionManager {
|
||||
}
|
||||
|
||||
createSession (token: Token, pipeline: Pipeline): Session {
|
||||
return this.sessionFactory(token, pipeline, this.broadcast.bind(this))
|
||||
return this.sessionFactory(token, pipeline)
|
||||
}
|
||||
|
||||
@withContext('get-workspace-info')
|
||||
@ -449,7 +446,7 @@ class TSessionManager implements SessionManager {
|
||||
function send (): void {
|
||||
for (const session of sessions) {
|
||||
try {
|
||||
sendResponse(ctx, session.session, session.socket, { result: tx })
|
||||
void sendResponse(ctx, session.session, session.socket, { result: tx })
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
ctx.error('error during send', { error: err })
|
||||
@ -459,7 +456,52 @@ class TSessionManager implements SessionManager {
|
||||
}
|
||||
if (sessions.length > 0) {
|
||||
// We need to send broadcast after our client response so put it after all IO
|
||||
onNextTick(send)
|
||||
send()
|
||||
} else {
|
||||
ctx.end()
|
||||
}
|
||||
}
|
||||
|
||||
broadcast (
|
||||
from: Session | null,
|
||||
workspaceId: WorkspaceId,
|
||||
resp: Tx[],
|
||||
target: string | undefined,
|
||||
exclude?: string[]
|
||||
): void {
|
||||
const workspace = this.workspaces.get(toWorkspaceString(workspaceId))
|
||||
if (workspace === undefined) {
|
||||
this.ctx.error('internal: cannot find sessions', {
|
||||
workspaceId: workspaceId.name,
|
||||
target,
|
||||
userId: from?.getUser() ?? '$unknown'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (workspace?.upgrade ?? false) {
|
||||
return
|
||||
}
|
||||
if (LOGGING_ENABLED) {
|
||||
this.ctx.info('server broadcasting to clients...', {
|
||||
workspace: workspaceId.name,
|
||||
count: workspace.sessions.size
|
||||
})
|
||||
}
|
||||
|
||||
const sessions = [...workspace.sessions.values()]
|
||||
const ctx = this.ctx.newChild('📭 broadcast', {})
|
||||
function send (): void {
|
||||
for (const sessionRef of sessions) {
|
||||
const tt = sessionRef.session.getUser()
|
||||
if ((target === undefined && !(exclude ?? []).includes(tt)) || (target?.includes(tt) ?? false)) {
|
||||
void sendResponse(ctx, sessionRef.session, sessionRef.socket, { result: resp })
|
||||
}
|
||||
}
|
||||
ctx.end()
|
||||
}
|
||||
if (sessions.length > 0) {
|
||||
// We need to send broadcast after our client response so put it after all IO
|
||||
send()
|
||||
} else {
|
||||
ctx.end()
|
||||
}
|
||||
@ -521,28 +563,37 @@ class TSessionManager implements SessionManager {
|
||||
)
|
||||
)[0]
|
||||
if (user === undefined) return
|
||||
const status = (await session.findAll(ctx, core.class.UserStatus, { user: user._id }, { limit: 1 }))[0]
|
||||
const status = (await session.findAllRaw(ctx, core.class.UserStatus, { user: user._id }, { limit: 1 }))[0]
|
||||
const txFactory = new TxFactory(user._id, true)
|
||||
if (status === undefined) {
|
||||
const tx = txFactory.createTxCreateDoc(core.class.UserStatus, core.space.Space, {
|
||||
online,
|
||||
user: user._id
|
||||
})
|
||||
await session.tx(ctx, tx)
|
||||
await session.txRaw(ctx, tx)
|
||||
} else if (status.online !== online) {
|
||||
const tx = txFactory.createTxUpdateDoc(status._class, status.space, status._id, {
|
||||
online
|
||||
})
|
||||
await session.tx(ctx, tx)
|
||||
await session.txRaw(ctx, tx)
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async close (ws: ConnectionSocket, wsid: string): Promise<void> {
|
||||
async close (ctx: MeasureContext, ws: ConnectionSocket, wsid: string): Promise<void> {
|
||||
const workspace = this.workspaces.get(wsid)
|
||||
|
||||
const sessionRef = this.sessions.get(ws.id)
|
||||
if (sessionRef !== undefined) {
|
||||
ctx.info('bye happen', {
|
||||
workspace: workspace?.workspaceName,
|
||||
user: sessionRef.session.getUser(),
|
||||
binary: sessionRef.session.binaryMode,
|
||||
compression: sessionRef.session.useCompression,
|
||||
totalTime: Date.now() - sessionRef.session.createTime,
|
||||
workspaceUsers: workspace?.sessions?.size,
|
||||
totalUsers: this.sessions.size
|
||||
})
|
||||
this.sessions.delete(ws.id)
|
||||
if (workspace !== undefined) {
|
||||
workspace.sessions.delete(sessionRef.session.sessionId)
|
||||
@ -705,57 +756,16 @@ class TSessionManager implements SessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
broadcast (from: Session | null, workspaceId: WorkspaceId, resp: Response<any>, target?: string[]): void {
|
||||
const workspace = this.workspaces.get(toWorkspaceString(workspaceId))
|
||||
if (workspace === undefined) {
|
||||
this.ctx.error('internal: cannot find sessions', {
|
||||
workspaceId: workspaceId.name,
|
||||
target,
|
||||
userId: from?.getUser() ?? '$unknown'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (workspace?.upgrade ?? false) {
|
||||
return
|
||||
}
|
||||
if (LOGGING_ENABLED) {
|
||||
this.ctx.info('server broadcasting to clients...', {
|
||||
workspace: workspaceId.name,
|
||||
count: workspace.sessions.size
|
||||
})
|
||||
}
|
||||
|
||||
const sessions = [...workspace.sessions.values()]
|
||||
const ctx = this.ctx.newChild('📭 broadcast', {})
|
||||
function send (): void {
|
||||
for (const sessionRef of sessions) {
|
||||
if (sessionRef !== undefined && sessionRef.session.sessionId !== from?.sessionId) {
|
||||
if (target === undefined || target.includes(sessionRef.session.getUser())) {
|
||||
sendResponse(ctx, sessionRef.session, sessionRef.socket, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.end()
|
||||
}
|
||||
if (sessions.length > 0) {
|
||||
// We need to send broadcast after our client response so put it after all IO
|
||||
onNextTick(send)
|
||||
} else {
|
||||
ctx.end()
|
||||
}
|
||||
}
|
||||
|
||||
async handleRequest<S extends Session>(
|
||||
handleRequest<S extends Session>(
|
||||
requestCtx: MeasureContext,
|
||||
service: S,
|
||||
ws: ConnectionSocket,
|
||||
request: Request<any>,
|
||||
workspace: string
|
||||
): Promise<Response<any> | undefined> {
|
||||
): void {
|
||||
const userCtx = requestCtx.newChild('📞 client', {
|
||||
workspace: '🧲 ' + workspace
|
||||
}) as SessionContext
|
||||
userCtx.sessionId = service.sessionInstanceId ?? ''
|
||||
})
|
||||
|
||||
// Calculate total number of clients
|
||||
const reqId = generateId()
|
||||
@ -763,7 +773,7 @@ class TSessionManager implements SessionManager {
|
||||
const st = Date.now()
|
||||
try {
|
||||
const backupMode = 'loadChunk' in service
|
||||
return await userCtx.with(`🧭 ${backupMode ? 'handleBackup' : 'handleRequest'}`, {}, async (ctx) => {
|
||||
void userCtx.with(`🧭 ${backupMode ? 'handleBackup' : 'handleRequest'}`, {}, async (ctx) => {
|
||||
if (request.time != null) {
|
||||
const delta = Date.now() - request.time
|
||||
userCtx.measure('receive msg', delta)
|
||||
@ -790,7 +800,6 @@ class TSessionManager implements SessionManager {
|
||||
const hello = request as HelloRequest
|
||||
service.binaryMode = hello.binary ?? false
|
||||
service.useCompression = hello.compression ?? false
|
||||
service.useBroadcast = hello.broadcast ?? false
|
||||
|
||||
if (LOGGING_ENABLED) {
|
||||
ctx.info('hello happen', {
|
||||
@ -818,8 +827,36 @@ class TSessionManager implements SessionManager {
|
||||
await ws.send(ctx, helloResponse, false, false)
|
||||
return
|
||||
}
|
||||
const opContext = (ctx: MeasureContext): ClientSessionCtx => ({
|
||||
sendResponse: async (msg) => {
|
||||
await sendResponse(ctx, service, ws, {
|
||||
id: request.id,
|
||||
result: msg,
|
||||
time: Date.now() - st,
|
||||
bfst: Date.now(),
|
||||
queue: service.requests.size
|
||||
})
|
||||
userCtx.end()
|
||||
},
|
||||
ctx,
|
||||
send: async (msg, target, exclude) => {
|
||||
this.broadcast(service, getWorkspaceId(workspace), msg, target, exclude)
|
||||
},
|
||||
sendError: async (msg, error: Status) => {
|
||||
await sendResponse(ctx, service, ws, {
|
||||
id: request.id,
|
||||
result: msg,
|
||||
error,
|
||||
time: Date.now() - st,
|
||||
bfst: Date.now(),
|
||||
queue: service.requests.size
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (request.method === 'measure' || request.method === 'measure-done') {
|
||||
return await this.handleMeasure<S>(service, request, ctx, ws)
|
||||
await this.handleMeasure<S>(service, request, opContext(ctx))
|
||||
return
|
||||
}
|
||||
service.requests.set(reqId, {
|
||||
id: reqId,
|
||||
@ -835,28 +872,24 @@ class TSessionManager implements SessionManager {
|
||||
try {
|
||||
const params = [...request.params]
|
||||
|
||||
const result =
|
||||
service.measureCtx?.ctx !== undefined
|
||||
? await f.apply(service, [service.measureCtx?.ctx, ...params])
|
||||
: await ctx.with('🧨 process', {}, async (callTx) => f.apply(service, [callTx, ...params]))
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
result,
|
||||
time: Date.now() - st,
|
||||
bfst: Date.now(),
|
||||
queue: service.requests.size
|
||||
}
|
||||
service.measureCtx?.ctx !== undefined
|
||||
? await f.apply(service, [opContext(service.measureCtx?.ctx), ...params])
|
||||
: await ctx.with('🧨 process', {}, async (callTx) => f.apply(service, [opContext(callTx), ...params]))
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
if (LOGGING_ENABLED) {
|
||||
this.ctx.error('error handle request', { error: err, request })
|
||||
}
|
||||
return {
|
||||
id: request.id,
|
||||
error: unknownError(err),
|
||||
result: JSON.parse(JSON.stringify(err?.stack))
|
||||
}
|
||||
await ws.send(
|
||||
ctx,
|
||||
{
|
||||
id: request.id,
|
||||
error: unknownError(err),
|
||||
result: JSON.parse(JSON.stringify(err?.stack))
|
||||
},
|
||||
service.binaryMode,
|
||||
service.useCompression
|
||||
)
|
||||
}
|
||||
})
|
||||
} finally {
|
||||
@ -868,12 +901,11 @@ class TSessionManager implements SessionManager {
|
||||
private async handleMeasure<S extends Session>(
|
||||
service: S,
|
||||
request: Request<any[]>,
|
||||
ctx: MeasureContext,
|
||||
ws: ConnectionSocket
|
||||
): Promise<Response<any> | undefined> {
|
||||
ctx: ClientSessionCtx
|
||||
): Promise<void> {
|
||||
let serverTime = 0
|
||||
if (request.method === 'measure') {
|
||||
service.measureCtx = { ctx: ctx.newChild('📶 ' + request.params[0], {}), time: Date.now() }
|
||||
service.measureCtx = { ctx: ctx.ctx.newChild('📶 ' + request.params[0], {}), time: Date.now() }
|
||||
} else {
|
||||
if (service.measureCtx !== undefined) {
|
||||
serverTime = Date.now() - service.measureCtx.time
|
||||
@ -881,17 +913,13 @@ class TSessionManager implements SessionManager {
|
||||
}
|
||||
}
|
||||
try {
|
||||
return { id: request.id, result: request.method === 'measure' ? 'started' : serverTime }
|
||||
await ctx.sendResponse(request.method === 'measure' ? 'started' : serverTime)
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
if (LOGGING_ENABLED) {
|
||||
ctx.error('error handle measure', { error: err, request })
|
||||
}
|
||||
return {
|
||||
id: request.id,
|
||||
error: unknownError(err),
|
||||
result: JSON.parse(JSON.stringify(err?.stack))
|
||||
ctx.ctx.error('error handle measure', { error: err, request })
|
||||
}
|
||||
await ctx.sendError(JSON.parse(JSON.stringify(err?.stack)), unknownError(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -904,7 +932,7 @@ export function start (
|
||||
opt: {
|
||||
port: number
|
||||
pipelineFactory: PipelineFactory
|
||||
sessionFactory: (token: Token, pipeline: Pipeline, broadcast: BroadcastCall) => Session
|
||||
sessionFactory: (token: Token, pipeline: Pipeline) => Session
|
||||
productId: string
|
||||
serverFactory: ServerFactory
|
||||
enableCompression?: boolean
|
||||
@ -917,7 +945,9 @@ export function start (
|
||||
})
|
||||
return opt.serverFactory(
|
||||
sessions,
|
||||
(rctx, service, ws, msg, workspace) => sessions.handleRequest(rctx, service, ws, msg, workspace),
|
||||
(rctx, service, ws, msg, workspace) => {
|
||||
sessions.handleRequest(rctx, service, ws, msg, workspace)
|
||||
},
|
||||
ctx,
|
||||
opt.pipelineFactory,
|
||||
opt.port,
|
||||
|
@ -255,7 +255,7 @@ export function startHttpServer (
|
||||
doSessionOp(webSocketData, (s) => {
|
||||
if (!(s.session.workspaceClosed ?? false)) {
|
||||
// remove session after 1seconds, give a time to reconnect.
|
||||
void sessions.close(cs, toWorkspaceString(token.workspace))
|
||||
void sessions.close(ctx, cs, toWorkspaceString(token.workspace))
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -352,7 +352,7 @@ function createWebsocketClientSocket (
|
||||
}
|
||||
const smsg = serialize(msg, binary)
|
||||
|
||||
while (ws.bufferedAmount > 128 && ws.readyState === ws.OPEN) {
|
||||
while (ws.bufferedAmount > 16 * 1024 && ws.readyState === ws.OPEN) {
|
||||
await new Promise<void>((resolve) => {
|
||||
setImmediate(resolve)
|
||||
})
|
||||
|
@ -177,7 +177,11 @@ export function startUWebsocketServer (
|
||||
doSessionOp(data, (s) => {
|
||||
if (!(s.session.workspaceClosed ?? false)) {
|
||||
// remove session after 1seconds, give a time to reconnect.
|
||||
void sessions.close(data.connectionSocket as ConnectionSocket, toWorkspaceString(data.payload.workspace))
|
||||
void sessions.close(
|
||||
ctx,
|
||||
data.connectionSocket as ConnectionSocket,
|
||||
toWorkspaceString(data.payload.workspace)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
type MeasureContext,
|
||||
type Ref,
|
||||
type Tx,
|
||||
type TxResult,
|
||||
type WorkspaceId,
|
||||
type WorkspaceIdWithUrl
|
||||
} from '@hcengineering/core'
|
||||
@ -31,6 +30,17 @@ export interface StatisticsElement {
|
||||
find: number
|
||||
tx: number
|
||||
}
|
||||
|
||||
export interface ClientSessionCtx {
|
||||
ctx: MeasureContext
|
||||
sendResponse: (msg: any) => Promise<void>
|
||||
sendError: (msg: any, error: any) => Promise<void>
|
||||
|
||||
// target === undefined, send to all except exclude
|
||||
// target !== undefined, send to selected target only, exclude is not used.
|
||||
send: (msg: Tx[], target?: string, exclude?: string[]) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -38,14 +48,21 @@ export interface Session {
|
||||
createTime: number
|
||||
getUser: () => string
|
||||
pipeline: () => Pipeline
|
||||
ping: () => Promise<string>
|
||||
ping: (ctx: ClientSessionCtx) => Promise<void>
|
||||
findAll: <T extends Doc>(
|
||||
ctx: ClientSessionCtx,
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
options?: FindOptions<T>
|
||||
) => Promise<void>
|
||||
findAllRaw: <T extends Doc>(
|
||||
ctx: MeasureContext,
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
options?: FindOptions<T>
|
||||
) => Promise<FindResult<T>>
|
||||
tx: (ctx: MeasureContext, tx: Tx) => Promise<TxResult>
|
||||
tx: (ctx: ClientSessionCtx, tx: Tx) => Promise<void>
|
||||
txRaw: (ctx: MeasureContext, tx: Tx) => Promise<void>
|
||||
|
||||
// Session restore information
|
||||
sessionId: string
|
||||
@ -56,8 +73,6 @@ export interface Session {
|
||||
|
||||
binaryMode: boolean
|
||||
useCompression: boolean
|
||||
useBroadcast: boolean
|
||||
|
||||
total: StatisticsElement
|
||||
current: StatisticsElement
|
||||
mins5: StatisticsElement
|
||||
@ -71,16 +86,6 @@ export interface Session {
|
||||
getMode: () => string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type BroadcastCall = (
|
||||
from: Session | null,
|
||||
workspaceId: WorkspaceId,
|
||||
resp: Response<any>,
|
||||
target?: string[]
|
||||
) => void
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -161,7 +166,7 @@ export interface SessionManager {
|
||||
|
||||
broadcastAll: (workspace: Workspace, tx: Tx[], targets?: string[]) => void
|
||||
|
||||
close: (ws: ConnectionSocket, workspaceId: string) => Promise<void>
|
||||
close: (ctx: MeasureContext, ws: ConnectionSocket, workspaceId: string) => Promise<void>
|
||||
|
||||
closeAll: (
|
||||
wsId: string,
|
||||
@ -175,8 +180,6 @@ export interface SessionManager {
|
||||
|
||||
closeWorkspaces: (ctx: MeasureContext) => Promise<void>
|
||||
|
||||
broadcast: (from: Session | null, workspaceId: WorkspaceId, resp: Response<any>, target?: string[]) => void
|
||||
|
||||
scheduleMaintenance: (timeMinutes: number) => void
|
||||
}
|
||||
|
||||
@ -189,8 +192,7 @@ export type HandleRequestFunction = <S extends Session>(
|
||||
ws: ConnectionSocket,
|
||||
msg: Request<any>,
|
||||
workspaceId: string
|
||||
) => Promise<Response<any> | undefined>
|
||||
|
||||
) => void
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -35,25 +35,21 @@ export function processRequest (
|
||||
handleRequest: HandleRequestFunction
|
||||
): void {
|
||||
const request = readRequest(buff, session.binaryMode)
|
||||
void handleRequest(context, session, cs, request, workspaceId).then((resp) => {
|
||||
if (resp !== undefined) {
|
||||
void handleSend(context, cs, resp, 32 * 1024, session.binaryMode, session.useCompression)
|
||||
}
|
||||
})
|
||||
handleRequest(context, session, cs, request, workspaceId)
|
||||
}
|
||||
|
||||
export function sendResponse (
|
||||
export async function sendResponse (
|
||||
ctx: MeasureContext,
|
||||
session: Session,
|
||||
socket: ConnectionSocket,
|
||||
resp: Response<any>
|
||||
): void {
|
||||
void handleSend(ctx, socket, resp, 32 * 1024, session.binaryMode, session.useCompression)
|
||||
): Promise<void> {
|
||||
await handleSend(ctx, socket, resp, 32 * 1024, session.binaryMode, session.useCompression)
|
||||
}
|
||||
|
||||
function waitNextTick (): Promise<void> | undefined {
|
||||
return new Promise<void>((resolve) => {
|
||||
setImmediate(resolve)
|
||||
setTimeout(resolve)
|
||||
})
|
||||
}
|
||||
export async function handleSend (
|
||||
|
Loading…
Reference in New Issue
Block a user