Compare commits
1 Commits
improveFor
...
xo-server-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abb65325b5 |
8
@xen-orchestra/multi-counter/index.js
Normal file
8
@xen-orchestra/multi-counter/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
const handler = {
|
||||||
|
get(target, property) {
|
||||||
|
const value = target[property]
|
||||||
|
return value !== undefined ? value : 0
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const create = () => new Proxy({ __proto__: null }, handler)
|
||||||
14
@xen-orchestra/multi-counter/package.json
Normal file
14
@xen-orchestra/multi-counter/package.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "@xen-orchestra/multi-counter",
|
||||||
|
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/@xen-orchestra/multi-counter",
|
||||||
|
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||||
|
"repository": {
|
||||||
|
"directory": "@xen-orchestra/multi-counter",
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"postversion": "npm publish"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
"make-error": "^1",
|
"make-error": "^1",
|
||||||
"micromatch": "^3.1.4",
|
"micromatch": "^3.1.4",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
|
"mnemonist": "^0.27.2",
|
||||||
"moment-timezone": "^0.5.14",
|
"moment-timezone": "^0.5.14",
|
||||||
"ms": "^2.1.1",
|
"ms": "^2.1.1",
|
||||||
"multikey-hash": "^1.0.4",
|
"multikey-hash": "^1.0.4",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as MultiCounter from '@xen-orchestra/multi-counter'
|
||||||
import aclResolver from 'xo-acl-resolver'
|
import aclResolver from 'xo-acl-resolver'
|
||||||
import { forEach, includes, map } from 'lodash'
|
import { forEach, includes, map } from 'lodash'
|
||||||
|
|
||||||
@@ -6,9 +7,11 @@ import { Acls } from '../models/acl'
|
|||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
|
// TODO add cache per user
|
||||||
export default class {
|
export default class {
|
||||||
constructor(xo) {
|
constructor(xo) {
|
||||||
this._xo = xo
|
this._xo = xo
|
||||||
|
this._cacheByObjectByUser = { __proto__: null }
|
||||||
|
|
||||||
const aclsDb = (this._acls = new Acls({
|
const aclsDb = (this._acls = new Acls({
|
||||||
connection: xo._redis,
|
connection: xo._redis,
|
||||||
@@ -16,6 +19,20 @@ export default class {
|
|||||||
indexes: ['subject', 'object'],
|
indexes: ['subject', 'object'],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const nSessionsByUser = MultiCounter.create()
|
||||||
|
xo.on('session.open', session => {
|
||||||
|
const userId = session.get('user_id')
|
||||||
|
if (nSessionsByUser[userId]++ === 0) {
|
||||||
|
this._cacheByObjectByUser[userId] = { __proto__: null }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
xo.on('session.close', session => {
|
||||||
|
const userId = session.get('user_id')
|
||||||
|
if (--nSessionsByUser[userId] === 0) {
|
||||||
|
delete this._cacheByObjectByUser[userId]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
xo.on('start', () => {
|
xo.on('start', () => {
|
||||||
xo.addConfigManager(
|
xo.addConfigManager(
|
||||||
'acls',
|
'acls',
|
||||||
|
|||||||
75
packages/xo-server/src/xo-mixins/subscriptions.js
Normal file
75
packages/xo-server/src/xo-mixins/subscriptions.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import BloomFilter from 'mnemonist/bloom-filter'
|
||||||
|
import forOwn from 'lodash/forOwn'
|
||||||
|
import iteratee from 'lodash/iteratee'
|
||||||
|
|
||||||
|
const BLOOM_FILTER_CAPACITY = 50
|
||||||
|
|
||||||
|
export default class Subscriptions {
|
||||||
|
constructor(app) {
|
||||||
|
this._app = app
|
||||||
|
|
||||||
|
this._permCacheByUser = { __proto__: null }
|
||||||
|
this._objCacheBySession = { __proto__: null }
|
||||||
|
this._predicatesBySession = { __proto__: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
async subscribe(sessionId, userId, filter) {
|
||||||
|
const predicatesBySession = this._predicatesBySession
|
||||||
|
const predicates =
|
||||||
|
predicatesBySession[sessionId] ??
|
||||||
|
(predicatesBySession[sessionId] = { __proto__: null })
|
||||||
|
|
||||||
|
const subscriptionId = Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.slice(2)
|
||||||
|
const predicate = iteratee(filter)
|
||||||
|
predicates[subscriptionId] = predicate
|
||||||
|
|
||||||
|
const objCacheBySession = this._objCacheBySession
|
||||||
|
const objCache =
|
||||||
|
objCacheBySession[sessionId] ??
|
||||||
|
(objCacheBySession[sessionId] = { __proto__: null })
|
||||||
|
|
||||||
|
const objects = this.getObjects()
|
||||||
|
const ids = Object.keys(objects)
|
||||||
|
await Promise.all(
|
||||||
|
ids.map(async id => {
|
||||||
|
if (!(await this.hasPermissions(userId, [[id, 'view']]))) {
|
||||||
|
// user cannot see this object
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache =
|
||||||
|
objCache[id] ??
|
||||||
|
(objCache[id] = new BloomFilter(BLOOM_FILTER_CAPACITY))
|
||||||
|
cache.add(subscriptionId)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return subscriptionId
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe(sessionId, userId, subscriptionId) {
|
||||||
|
const predicates = this._predicatesBySession[sessionId]
|
||||||
|
if (predicates === undefined || !(subscriptionId in predicates)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete predicates[subscriptionId]
|
||||||
|
|
||||||
|
const objCache = this._objCacheBySession[sessionId]
|
||||||
|
forOwn(objCache, (cache, id) => {
|
||||||
|
if (!cache.test(subscriptionId)) {
|
||||||
|
// not handled by this subscription
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const object = this.getObject(id)
|
||||||
|
cache = objCache[id] = new BloomFilter(BLOOM_FILTER_CAPACITY)
|
||||||
|
forOwn(predicates, (predicate, subscriptionId) => {
|
||||||
|
if (predicate(object)) {
|
||||||
|
cache.add(subscriptionId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
12
yarn.lock
12
yarn.lock
@@ -9408,6 +9408,13 @@ mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimist "0.0.8"
|
minimist "0.0.8"
|
||||||
|
|
||||||
|
mnemonist@^0.27.2:
|
||||||
|
version "0.27.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.27.2.tgz#c56a8ad5345b9089604a1aa0af8610480717e40a"
|
||||||
|
integrity sha512-dJOzzaEZtSR23m8e/kTg0SNvV9WdDeYwRFQwT/6yb79z2rwXnd6L2xZkUBuArmBOug7xoKfImk/In1TC/Ry8lg==
|
||||||
|
dependencies:
|
||||||
|
obliterator "^1.5.0"
|
||||||
|
|
||||||
modular-css-core@^12.1.3:
|
modular-css-core@^12.1.3:
|
||||||
version "12.1.3"
|
version "12.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/modular-css-core/-/modular-css-core-12.1.3.tgz#801fbe5e7412ba897b40a1982a9b99134ffe4990"
|
resolved "https://registry.yarnpkg.com/modular-css-core/-/modular-css-core-12.1.3.tgz#801fbe5e7412ba897b40a1982a9b99134ffe4990"
|
||||||
@@ -10122,6 +10129,11 @@ object.values@^1.0.4, object.values@^1.1.0:
|
|||||||
function-bind "^1.1.1"
|
function-bind "^1.1.1"
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
|
|
||||||
|
obliterator@^1.5.0:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.5.0.tgz#f3535e5be192473ef59efb2d30396738f7c645c6"
|
||||||
|
integrity sha512-dENe0UviDf8/auXn0bIBKwCcUr49khvSBWDLlszv/ZB2qz1VxWDmkNKFqO2nfmve7hQb/QIDY7+rc7K3LdJimQ==
|
||||||
|
|
||||||
on-finished@~2.3.0:
|
on-finished@~2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||||
|
|||||||
Reference in New Issue
Block a user