mirror of https://github.com/requarks/wiki
parent
6ce29bdb77
commit
e1ebaf5b31
@ -1,118 +0,0 @@
|
|||||||
const _ = require('lodash')
|
|
||||||
const dotize = require('dotize')
|
|
||||||
const i18nMW = require('i18next-express-middleware')
|
|
||||||
const i18next = require('i18next')
|
|
||||||
const Promise = require('bluebird')
|
|
||||||
const fs = require('fs-extra')
|
|
||||||
const path = require('path')
|
|
||||||
const yaml = require('js-yaml')
|
|
||||||
|
|
||||||
/* global WIKI */
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
engine: null,
|
|
||||||
namespaces: [],
|
|
||||||
init() {
|
|
||||||
this.namespaces = WIKI.data.localeNamespaces
|
|
||||||
this.engine = i18next
|
|
||||||
this.engine.init({
|
|
||||||
load: 'languageOnly',
|
|
||||||
ns: this.namespaces,
|
|
||||||
defaultNS: 'common',
|
|
||||||
saveMissing: false,
|
|
||||||
lng: WIKI.config.lang.code,
|
|
||||||
fallbackLng: 'en'
|
|
||||||
})
|
|
||||||
|
|
||||||
// Load current language + namespaces
|
|
||||||
this.refreshNamespaces(true)
|
|
||||||
|
|
||||||
return this
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Attach i18n middleware for Express
|
|
||||||
*
|
|
||||||
* @param {Object} app Express Instance
|
|
||||||
*/
|
|
||||||
attachMiddleware (app) {
|
|
||||||
app.use(i18nMW.handle(this.engine))
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Get all entries for a specific locale and namespace
|
|
||||||
*
|
|
||||||
* @param {String} locale Locale code
|
|
||||||
* @param {String} namespace Namespace
|
|
||||||
*/
|
|
||||||
async getByNamespace(locale, namespace) {
|
|
||||||
if (this.engine.hasResourceBundle(locale, namespace)) {
|
|
||||||
let data = this.engine.getResourceBundle(locale, namespace)
|
|
||||||
return _.map(dotize.convert(data), (value, key) => {
|
|
||||||
return {
|
|
||||||
key,
|
|
||||||
value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid locale or namespace')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Load entries from the DB for a single locale
|
|
||||||
*
|
|
||||||
* @param {String} locale Locale code
|
|
||||||
* @param {*} opts Additional options
|
|
||||||
*/
|
|
||||||
async loadLocale(locale, opts = { silent: false }) {
|
|
||||||
const res = await WIKI.models.locales.query().findOne('code', locale)
|
|
||||||
if (res) {
|
|
||||||
if (_.isPlainObject(res.strings)) {
|
|
||||||
_.forOwn(res.strings, (data, ns) => {
|
|
||||||
this.namespaces.push(ns)
|
|
||||||
this.engine.addResourceBundle(locale, ns, data, true, true)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (!opts.silent) {
|
|
||||||
throw new Error('No such locale in local store.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// -> Load dev locale files if present
|
|
||||||
if (WIKI.IS_DEBUG) {
|
|
||||||
try {
|
|
||||||
const devEntriesRaw = await fs.readFile(path.join(WIKI.SERVERPATH, `locales/${locale}.yml`), 'utf8')
|
|
||||||
if (devEntriesRaw) {
|
|
||||||
const devEntries = yaml.safeLoad(devEntriesRaw)
|
|
||||||
_.forOwn(devEntries, (data, ns) => {
|
|
||||||
this.namespaces.push(ns)
|
|
||||||
this.engine.addResourceBundle(locale, ns, data, true, true)
|
|
||||||
})
|
|
||||||
WIKI.logger.info(`Loaded dev locales from ${locale}.yml`)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Reload all namespaces for all active locales from the DB
|
|
||||||
*
|
|
||||||
* @param {Boolean} silent No error on fail
|
|
||||||
*/
|
|
||||||
async refreshNamespaces (silent = false) {
|
|
||||||
await this.loadLocale(WIKI.config.lang.code, { silent })
|
|
||||||
if (WIKI.config.lang.namespacing) {
|
|
||||||
for (let ns of WIKI.config.lang.namespaces) {
|
|
||||||
await this.loadLocale(ns, { silent })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Set the active locale
|
|
||||||
*
|
|
||||||
* @param {String} locale Locale code
|
|
||||||
*/
|
|
||||||
async setCurrentLocale(locale) {
|
|
||||||
await Promise.fromCallback(cb => {
|
|
||||||
return this.engine.changeLanguage(locale, cb)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +1,60 @@
|
|||||||
const PgBoss = require('pg-boss')
|
const PgBoss = require('pg-boss')
|
||||||
|
const { DynamicThreadPool } = require('poolifier')
|
||||||
|
const os = require('node:os')
|
||||||
|
|
||||||
/* global WIKI */
|
/* global WIKI */
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
pool: null,
|
||||||
scheduler: null,
|
scheduler: null,
|
||||||
jobs: [],
|
async init () {
|
||||||
init () {
|
|
||||||
WIKI.logger.info('Initializing Scheduler...')
|
WIKI.logger.info('Initializing Scheduler...')
|
||||||
this.scheduler = new PgBoss({
|
this.scheduler = new PgBoss({
|
||||||
...WIKI.models.knex.client.connectionSettings,
|
db: {
|
||||||
|
close: () => Promise.resolve('ok'),
|
||||||
|
executeSql: async (text, values) => {
|
||||||
|
try {
|
||||||
|
const resource = await WIKI.models.knex.client.pool.acquire().promise
|
||||||
|
const res = await resource.query(text, values)
|
||||||
|
WIKI.models.knex.client.pool.release(resource)
|
||||||
|
return res
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.error('Failed to acquire DB connection during scheduler query execution.')
|
||||||
|
WIKI.logger.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ...WIKI.models.knex.client.connectionSettings,
|
||||||
application_name: 'Wiki.js Scheduler',
|
application_name: 'Wiki.js Scheduler',
|
||||||
schema: WIKI.config.db.schemas.scheduler,
|
schema: WIKI.config.db.schemas.scheduler,
|
||||||
uuid: 'v4'
|
uuid: 'v4'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const maxWorkers = WIKI.config.workers === 'auto' ? os.cpus().length : WIKI.config.workers
|
||||||
|
WIKI.logger.info(`Initializing Worker Pool (Max ${maxWorkers})...`)
|
||||||
|
this.pool = new DynamicThreadPool(1, maxWorkers, './server/worker.js', {
|
||||||
|
errorHandler: (err) => WIKI.logger.warn(err),
|
||||||
|
exitHandler: () => WIKI.logger.debug('A worker has gone offline.'),
|
||||||
|
onlineHandler: () => WIKI.logger.debug('New worker is online.')
|
||||||
|
})
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
async start () {
|
async start () {
|
||||||
WIKI.logger.info('Starting Scheduler...')
|
WIKI.logger.info('Starting Scheduler...')
|
||||||
await this.scheduler.start()
|
await this.scheduler.start()
|
||||||
|
this.scheduler.work('*', async job => {
|
||||||
|
return this.pool.execute({
|
||||||
|
id: job.id,
|
||||||
|
name: job.name,
|
||||||
|
data: job.data
|
||||||
|
})
|
||||||
|
})
|
||||||
WIKI.logger.info('Scheduler: [ STARTED ]')
|
WIKI.logger.info('Scheduler: [ STARTED ]')
|
||||||
},
|
},
|
||||||
async stop () {
|
async stop () {
|
||||||
WIKI.logger.info('Stopping Scheduler...')
|
WIKI.logger.info('Stopping Scheduler...')
|
||||||
await this.scheduler.stop()
|
await this.scheduler.stop()
|
||||||
|
await this.pool.destroy()
|
||||||
WIKI.logger.info('Scheduler: [ STOPPED ]')
|
WIKI.logger.info('Scheduler: [ STOPPED ]')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
const { ThreadWorker } = require('poolifier')
|
||||||
|
|
||||||
|
module.exports = new ThreadWorker(async (job) => {
|
||||||
|
return { ok: true }
|
||||||
|
}, { async: true })
|
Loading…
Reference in new issue