Merge pull request #115 from vatesfr/abhamonr-logger-module
Logger is implemented.
This commit is contained in:
commit
aa81e72e45
@ -61,6 +61,8 @@
|
|||||||
"julien-f-source-map-support": "0.0.0",
|
"julien-f-source-map-support": "0.0.0",
|
||||||
"julien-f-unzip": "^0.2.1",
|
"julien-f-unzip": "^0.2.1",
|
||||||
"kindof": "^2.0.0",
|
"kindof": "^2.0.0",
|
||||||
|
"level": "^1.3.0",
|
||||||
|
"level-sublevel": "^6.5.2",
|
||||||
"lodash.assign": "^3.0.0",
|
"lodash.assign": "^3.0.0",
|
||||||
"lodash.bind": "^3.0.0",
|
"lodash.bind": "^3.0.0",
|
||||||
"lodash.difference": "^3.2.0",
|
"lodash.difference": "^3.2.0",
|
||||||
|
@ -109,3 +109,9 @@ redis:
|
|||||||
#
|
#
|
||||||
# Default: tcp://localhost:6379
|
# Default: tcp://localhost:6379
|
||||||
#uri: ''
|
#uri: ''
|
||||||
|
|
||||||
|
# Directory containing the database of XO.
|
||||||
|
# Currently used for logs.
|
||||||
|
#
|
||||||
|
# Default: '/var/lib/xo-server/data'
|
||||||
|
#datadir: '/var/lib/xo-server/data'
|
||||||
|
@ -10,6 +10,7 @@ export * as docker from './docker'
|
|||||||
export * as group from './group'
|
export * as group from './group'
|
||||||
export * as host from './host'
|
export * as host from './host'
|
||||||
export * as job from './job'
|
export * as job from './job'
|
||||||
|
export * as log from './log'
|
||||||
export * as message from './message'
|
export * as message from './message'
|
||||||
export * as pbd from './pbd'
|
export * as pbd from './pbd'
|
||||||
export * as pif from './pif'
|
export * as pif from './pif'
|
||||||
|
18
src/api/log.js
Normal file
18
src/api/log.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export async function get ({namespace}) {
|
||||||
|
const logger = this.getLogger(namespace)
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const logs = {}
|
||||||
|
|
||||||
|
logger.createReadStream()
|
||||||
|
.on('data', (data) => {
|
||||||
|
logs[data.key] = data.value
|
||||||
|
})
|
||||||
|
.on('end', () => {
|
||||||
|
resolve(logs)
|
||||||
|
})
|
||||||
|
.on('error', reject)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get.description = 'returns logs list for one namespace'
|
@ -65,7 +65,8 @@ const DEFAULTS = {
|
|||||||
{ port: 80 }
|
{ port: 80 }
|
||||||
],
|
],
|
||||||
mounts: {}
|
mounts: {}
|
||||||
}
|
},
|
||||||
|
datadir: '/var/lib/xo-server/data'
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEPRECATED_ENTRIES = [
|
const DEPRECATED_ENTRIES = [
|
||||||
@ -573,11 +574,7 @@ export default async function main (args) {
|
|||||||
// Create the main object which will connects to Xen servers and
|
// Create the main object which will connects to Xen servers and
|
||||||
// manages all the models.
|
// manages all the models.
|
||||||
const xo = new Xo()
|
const xo = new Xo()
|
||||||
await xo.start({
|
await xo.start(config)
|
||||||
redis: {
|
|
||||||
uri: config.redis && config.redis.uri
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Loads default authentication providers.
|
// Loads default authentication providers.
|
||||||
registerPasswordAuthenticationProvider(xo)
|
registerPasswordAuthenticationProvider(xo)
|
||||||
|
@ -24,6 +24,24 @@ export const productParams = (...args) => {
|
|||||||
return product
|
return product
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function _computeCrossProduct (items, productCb, extractValueMap = {}) {
|
||||||
|
const upstreamValues = []
|
||||||
|
const itemsCopy = items.slice()
|
||||||
|
const item = itemsCopy.pop()
|
||||||
|
const values = extractValueMap[item.type] && extractValueMap[item.type](item) || item
|
||||||
|
forEach(values, value => {
|
||||||
|
if (itemsCopy.length) {
|
||||||
|
let downstreamValues = _computeCrossProduct(itemsCopy, productCb, extractValueMap)
|
||||||
|
forEach(downstreamValues, downstreamValue => {
|
||||||
|
upstreamValues.push(productCb(value, downstreamValue))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
upstreamValues.push(value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return upstreamValues
|
||||||
|
}
|
||||||
|
|
||||||
export default class JobExecutor {
|
export default class JobExecutor {
|
||||||
constructor (xo, api) {
|
constructor (xo, api) {
|
||||||
this.xo = xo
|
this.xo = xo
|
||||||
@ -31,46 +49,83 @@ export default class JobExecutor {
|
|||||||
this._extractValueCb = {
|
this._extractValueCb = {
|
||||||
'set': items => items.values
|
'set': items => items.values
|
||||||
}
|
}
|
||||||
|
this._logger = this.xo.getLogger('jobs')
|
||||||
}
|
}
|
||||||
|
|
||||||
exec (job) {
|
async exec (job) {
|
||||||
if (job.type === 'call') {
|
const runJobId = this._logger.notice(`Starting execution of ${job.id}.`, {
|
||||||
this._execCall(job.userId, job.method, job.paramsVector)
|
event: 'job.start',
|
||||||
} else {
|
userId: job.userId,
|
||||||
throw new UnsupportedJobType(job)
|
jobId: job.id,
|
||||||
}
|
key: job.key
|
||||||
}
|
|
||||||
|
|
||||||
_execCall (userId, method, paramsVector) {
|
|
||||||
let paramsFlatVector
|
|
||||||
if (paramsVector.type === 'crossProduct') {
|
|
||||||
paramsFlatVector = this._computeCrossProduct(paramsVector.items, productParams, this._extractValueCb)
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedVectorType(paramsVector)
|
|
||||||
}
|
|
||||||
const connection = this.xo.createUserConnection()
|
|
||||||
connection.set('user_id', userId)
|
|
||||||
forEach(paramsFlatVector, params => {
|
|
||||||
this.api.call(connection, method, { ...params })
|
|
||||||
})
|
})
|
||||||
connection.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeCrossProduct (items, productCb, extractValueMap = {}) {
|
try {
|
||||||
const upstreamValues = []
|
if (job.type === 'call') {
|
||||||
const itemsCopy = items.slice()
|
await this._execCall(job, runJobId)
|
||||||
const item = itemsCopy.pop()
|
|
||||||
const values = extractValueMap[item.type] && extractValueMap[item.type](item) || item
|
|
||||||
forEach(values, value => {
|
|
||||||
if (itemsCopy.length) {
|
|
||||||
let downstreamValues = this._computeCrossProduct(itemsCopy, productCb, extractValueMap)
|
|
||||||
forEach(downstreamValues, downstreamValue => {
|
|
||||||
upstreamValues.push(productCb(value, downstreamValue))
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
upstreamValues.push(value)
|
throw new UnsupportedJobType(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._logger.notice(`Execution terminated for ${job.id}.`, {
|
||||||
|
event: 'job.end',
|
||||||
|
runJobId
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.error(`The execution of ${job.id} has failed.`, {
|
||||||
|
event: 'job.end',
|
||||||
|
runJobId,
|
||||||
|
error: e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _execCall (job, runJobId) {
|
||||||
|
let paramsFlatVector
|
||||||
|
|
||||||
|
if (job.paramsVector.type === 'crossProduct') {
|
||||||
|
paramsFlatVector = _computeCrossProduct(job.paramsVector.items, productParams, this._extractValueCb)
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedVectorType(job.paramsVector)
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = this.xo.createUserConnection()
|
||||||
|
const promises = []
|
||||||
|
|
||||||
|
connection.set('user_id', job.userId)
|
||||||
|
|
||||||
|
forEach(paramsFlatVector, params => {
|
||||||
|
const runCallId = this._logger.notice(`Starting ${job.method} call. (${job.id})`, {
|
||||||
|
event: 'jobCall.start',
|
||||||
|
runJobId,
|
||||||
|
method: job.method,
|
||||||
|
params
|
||||||
|
})
|
||||||
|
|
||||||
|
promises.push(
|
||||||
|
this.api.call(connection, job.method, assign({}, params)).then(
|
||||||
|
value => {
|
||||||
|
this._logger.notice(`Call ${job.method} (${runCallId}) is a success. (${job.id})`, {
|
||||||
|
event: 'jobCall.end',
|
||||||
|
runJobId,
|
||||||
|
runCallId,
|
||||||
|
returnedValue: value
|
||||||
|
})
|
||||||
|
},
|
||||||
|
reason => {
|
||||||
|
this._logger.notice(`Call ${job.method} (${runCallId}) has failed. (${job.id})`, {
|
||||||
|
event: 'jobCall.end',
|
||||||
|
runJobId,
|
||||||
|
runCallId,
|
||||||
|
error: reason
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
return upstreamValues
|
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import {expect} from 'chai'
|
|||||||
import leche from 'leche'
|
import leche from 'leche'
|
||||||
|
|
||||||
import {productParams} from './job-executor'
|
import {productParams} from './job-executor'
|
||||||
import JobExecutor from './job-executor'
|
import {_computeCrossProduct} from './job-executor'
|
||||||
|
|
||||||
describe('productParams', function () {
|
describe('productParams', function () {
|
||||||
leche.withData({
|
leche.withData({
|
||||||
@ -36,8 +36,7 @@ describe('productParams', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('JobExecutor._computeCrossProduct', function () {
|
describe('_computeCrossProduct', function () {
|
||||||
const jobExecutor = new JobExecutor({})
|
|
||||||
// Gives the sum of all args
|
// Gives the sum of all args
|
||||||
const addTest = (...args) => args.reduce((prev, curr) => prev + curr, 0)
|
const addTest = (...args) => args.reduce((prev, curr) => prev + curr, 0)
|
||||||
// Gives the product of all args
|
// Gives the product of all args
|
||||||
@ -64,7 +63,7 @@ describe('JobExecutor._computeCrossProduct', function () {
|
|||||||
]
|
]
|
||||||
}, function (product, items, cb) {
|
}, function (product, items, cb) {
|
||||||
it('Crosses sets of values with a crossProduct callback', function () {
|
it('Crosses sets of values with a crossProduct callback', function () {
|
||||||
expect(jobExecutor._computeCrossProduct(items, cb)).to.have.members(product)
|
expect(_computeCrossProduct(items, cb)).to.have.members(product)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
53
src/loggers/leveldb.js
Normal file
53
src/loggers/leveldb.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// See: https://en.wikipedia.org/wiki/Syslog#Severity_level
|
||||||
|
const LEVELS = [
|
||||||
|
'emergency',
|
||||||
|
'alert',
|
||||||
|
'critical',
|
||||||
|
'error',
|
||||||
|
'warning',
|
||||||
|
'notice',
|
||||||
|
'informational',
|
||||||
|
'debug'
|
||||||
|
]
|
||||||
|
|
||||||
|
let lastDate = 0
|
||||||
|
let lastId = 0
|
||||||
|
|
||||||
|
function generateUniqueKey (date) {
|
||||||
|
lastId = (date === lastDate) ? (lastId + 1) : 0
|
||||||
|
lastDate = date
|
||||||
|
|
||||||
|
return `${lastDate}:${lastId}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LevelDbLogger {
|
||||||
|
constructor (db) {
|
||||||
|
this._db = db
|
||||||
|
}
|
||||||
|
|
||||||
|
_add (level, message, data) {
|
||||||
|
const log = {
|
||||||
|
level,
|
||||||
|
message,
|
||||||
|
data,
|
||||||
|
time: Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = generateUniqueKey(log.time)
|
||||||
|
this._db.put(key, log)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
createReadStream () {
|
||||||
|
return this._db.createReadStream()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create high level log methods.
|
||||||
|
for (const level of LEVELS) {
|
||||||
|
Object.defineProperty(LevelDbLogger.prototype, level, {
|
||||||
|
value (message, data) {
|
||||||
|
return this._add(level, message, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
31
src/schemas/log.js
Normal file
31
src/schemas/log.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export default {
|
||||||
|
$schema: 'http://json-schema.org/draft-04/schema#',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'unique identifier for this log'
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'timestamp (in miliseconds) of this log'
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'human readable (short) description of this log'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
oneOf: [
|
||||||
|
{ '$ref': 'log/jobStart.js' },
|
||||||
|
{ '$ref': 'log/jobEnd.js' },
|
||||||
|
{ '$ref': 'log/jobCallStart.js' },
|
||||||
|
{ '$ref': 'log/jobCallEnd.js' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
'time',
|
||||||
|
'message'
|
||||||
|
]
|
||||||
|
}
|
33
src/schemas/log/jobCallEnd.js
Normal file
33
src/schemas/log/jobCallEnd.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
export default {
|
||||||
|
$schema: 'http://json-schema.org/draft-04/schema#',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
event: {
|
||||||
|
enum: ['jobCall.end']
|
||||||
|
},
|
||||||
|
runJobId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'instance id of this job'
|
||||||
|
},
|
||||||
|
runCallId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'instance id of this call'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: 'object',
|
||||||
|
description: 'describe one failure, exists if the call has failed'
|
||||||
|
},
|
||||||
|
returnedValue: {
|
||||||
|
description: 'call\'s result, exists if the call is a success'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'event',
|
||||||
|
'runJobId',
|
||||||
|
'runCallId'
|
||||||
|
],
|
||||||
|
oneOf: [
|
||||||
|
{ required: ['error'] },
|
||||||
|
{ required: ['returnedValue'] }
|
||||||
|
]
|
||||||
|
}
|
27
src/schemas/log/jobCallStart.js
Normal file
27
src/schemas/log/jobCallStart.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
export default {
|
||||||
|
$schema: 'http://json-schema.org/draft-04/schema#',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
event: {
|
||||||
|
enum: ['jobCall.start']
|
||||||
|
},
|
||||||
|
runJobId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'instance id of this job'
|
||||||
|
},
|
||||||
|
method: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'method linked to this call'
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
type: 'object',
|
||||||
|
description: 'params of the called method'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'event',
|
||||||
|
'runJobId',
|
||||||
|
'method',
|
||||||
|
'params'
|
||||||
|
]
|
||||||
|
}
|
21
src/schemas/log/jobEnd.js
Normal file
21
src/schemas/log/jobEnd.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export default {
|
||||||
|
$schema: 'http://json-schema.org/draft-04/schema#',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
event: {
|
||||||
|
enum: ['job.end']
|
||||||
|
},
|
||||||
|
runJobId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'instance id of this job'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: 'object',
|
||||||
|
description: 'describe one failure, exists if no call has been made'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'event',
|
||||||
|
'runJobId'
|
||||||
|
]
|
||||||
|
}
|
26
src/schemas/log/jobStart.js
Normal file
26
src/schemas/log/jobStart.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export default {
|
||||||
|
$schema: 'http://json-schema.org/draft-04/schema#',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
event: {
|
||||||
|
enum: ['job.start']
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'user who executes this job'
|
||||||
|
},
|
||||||
|
jobId: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'identifier of this job'
|
||||||
|
},
|
||||||
|
key: {
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'event',
|
||||||
|
'userId',
|
||||||
|
'jobId',
|
||||||
|
'key'
|
||||||
|
]
|
||||||
|
}
|
@ -122,6 +122,32 @@ describe('generateToken()', () => {
|
|||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('pSettle()', () => {
|
||||||
|
it('makes an array of PromiseInspection', async () => {
|
||||||
|
const [
|
||||||
|
status1,
|
||||||
|
status2
|
||||||
|
] = await pSettle([
|
||||||
|
Promise.resolve(42),
|
||||||
|
Promise.reject('fatality')
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(status1.isRejected()).to.equal(false)
|
||||||
|
expect(status2.isRejected()).to.equal(true)
|
||||||
|
|
||||||
|
expect(status1.isFulfilled()).to.equal(true)
|
||||||
|
expect(status2.isFulfilled()).to.equal(false)
|
||||||
|
|
||||||
|
expect(status1.value()).to.equal(42)
|
||||||
|
expect(::status2.value).to.throw()
|
||||||
|
|
||||||
|
expect(::status1.reason).to.throw()
|
||||||
|
expect(status2.reason()).to.equal('fatality')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
describe('parseSize()', function () {
|
describe('parseSize()', function () {
|
||||||
it('parses a human size', function () {
|
it('parses a human size', function () {
|
||||||
expect(parseSize('1G')).to.equal(1e9)
|
expect(parseSize('1G')).to.equal(1e9)
|
||||||
|
26
src/xo.js
26
src/xo.js
@ -8,8 +8,10 @@ import fs from 'fs-promise'
|
|||||||
import includes from 'lodash.includes'
|
import includes from 'lodash.includes'
|
||||||
import isFunction from 'lodash.isfunction'
|
import isFunction from 'lodash.isfunction'
|
||||||
import isString from 'lodash.isstring'
|
import isString from 'lodash.isstring'
|
||||||
|
import levelup from 'level'
|
||||||
import sortBy from 'lodash.sortby'
|
import sortBy from 'lodash.sortby'
|
||||||
import startsWith from 'lodash.startswith'
|
import startsWith from 'lodash.startswith'
|
||||||
|
import sublevel from 'level-sublevel'
|
||||||
import XoCollection from 'xo-collection'
|
import XoCollection from 'xo-collection'
|
||||||
import XoUniqueIndex from 'xo-collection/unique-index'
|
import XoUniqueIndex from 'xo-collection/unique-index'
|
||||||
import {createClient as createRedisClient} from 'redis'
|
import {createClient as createRedisClient} from 'redis'
|
||||||
@ -22,6 +24,7 @@ import {
|
|||||||
import * as xapiObjectsToXo from './xapi-objects-to-xo'
|
import * as xapiObjectsToXo from './xapi-objects-to-xo'
|
||||||
import checkAuthorization from './acl'
|
import checkAuthorization from './acl'
|
||||||
import Connection from './connection'
|
import Connection from './connection'
|
||||||
|
import LevelDbLogger from './loggers/leveldb'
|
||||||
import Xapi from './xapi'
|
import Xapi from './xapi'
|
||||||
import XapiStats from './xapi-stats'
|
import XapiStats from './xapi-stats'
|
||||||
import {Acls} from './models/acl'
|
import {Acls} from './models/acl'
|
||||||
@ -130,9 +133,10 @@ export default class Xo extends EventEmitter {
|
|||||||
this._nextConId = 0
|
this._nextConId = 0
|
||||||
this._connections = createRawObject()
|
this._connections = createRawObject()
|
||||||
|
|
||||||
this._authenticationProviders = new Set()
|
|
||||||
this._authenticationFailures = createRawObject()
|
this._authenticationFailures = createRawObject()
|
||||||
|
this._authenticationProviders = new Set()
|
||||||
this._httpRequestWatchers = createRawObject()
|
this._httpRequestWatchers = createRawObject()
|
||||||
|
this._leveldb = null // Initialized in start().
|
||||||
this._plugins = createRawObject()
|
this._plugins = createRawObject()
|
||||||
|
|
||||||
this._watchObjects()
|
this._watchObjects()
|
||||||
@ -141,6 +145,14 @@ export default class Xo extends EventEmitter {
|
|||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
async start (config) {
|
async start (config) {
|
||||||
|
await fs.mkdirp(config.datadir)
|
||||||
|
|
||||||
|
this._leveldb = sublevel(levelup(`${config.datadir}/leveldb`, {
|
||||||
|
valueEncoding: 'json'
|
||||||
|
}))
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
// Connects to Redis.
|
// Connects to Redis.
|
||||||
const redis = createRedisClient(config.redis && config.redis.uri)
|
const redis = createRedisClient(config.redis && config.redis.uri)
|
||||||
|
|
||||||
@ -189,6 +201,8 @@ export default class Xo extends EventEmitter {
|
|||||||
indexes: ['enabled']
|
indexes: ['enabled']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
// Proxies tokens/users related events to XO and removes tokens
|
// Proxies tokens/users related events to XO and removes tokens
|
||||||
// when their related user is removed.
|
// when their related user is removed.
|
||||||
this._tokens.on('remove', ids => {
|
this._tokens.on('remove', ids => {
|
||||||
@ -206,6 +220,8 @@ export default class Xo extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
// Connects to existing servers.
|
// Connects to existing servers.
|
||||||
const servers = await this._servers.get()
|
const servers = await this._servers.get()
|
||||||
for (let server of servers) {
|
for (let server of servers) {
|
||||||
@ -220,6 +236,14 @@ export default class Xo extends EventEmitter {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
getLogger (identifier) {
|
||||||
|
return new LevelDbLogger(
|
||||||
|
this._leveldb.sublevel('logs').sublevel(identifier)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
async _getAclsForUser (userId) {
|
async _getAclsForUser (userId) {
|
||||||
const subjects = (await this.getUser(userId)).groups.concat(userId)
|
const subjects = (await this.getUser(userId)).groups.concat(userId)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user