Add WIP aedifex db

aedifex-rework
kts of kettek (yan) 2021-08-14 13:48:04 -07:00
parent 966715319b
commit 809fa78d35
12 changed files with 308 additions and 95 deletions

View File

@ -78,6 +78,7 @@ try {
console.log('...ok')
plugins.push(plugin)
} catch(err) {
console.error(err)
if (err.code === 'MODULE_NOT_FOUND') {
console.error('plugin', plugin_path, 'is not a valid module')
} else {

View File

@ -0,0 +1,44 @@
class AedifexError extends Error {
constructor(message) {
super(message)
this.name = 'AedifexError'
}
}
class UnhandledTypeError extends AedifexError {
constructor(received) {
super(`unhandled aedifex type "${received}"`)
this.name = 'UnhandleTypeError'
}
}
class IncorrectTypeError extends AedifexError {
constructor(expected, received) {
super(`expected "${expected}", received "${received}"`)
this.name = 'IncorrectTypeError'
}
}
class IncorrectPropertyError extends AedifexError {
constructor(field, expected, received) {
super(`expected property "${field}" to be "${expected}", received type "${received}"`)
this.name = 'IncorrectPropertyError'
}
}
class MismatchedVersionError extends AedifexError {
constructor(expected, received) {
super(`expected version "${expected}", received "${received}"`)
this.name = 'MismatchedVersionError'
}
}
module.exports = {
AedifexError,
UnhandledTypeError,
IncorrectTypeError,
IncorrectPropertyError,
MismatchedVersionError,
}

View File

@ -0,0 +1,22 @@
const semver = require('semver')
const { IncorrectTypeError, IncorrectPropertyError, MismatchedVersionError } = require('./errors.js')
function readGear(collection, v) {
if (v.type !== 'hord-gear') {
throw new IncorrectTypeError('hord-gear', v.type)
}
if (!Array.isArray(v.gear)) {
throw new IncorrectPropertyError('gear', typeof [], typeof v.gear)
}
if (!v.version || !semver.satisfies(v.version, '1.x')) {
throw new MismatchedVersionError('1.x', v.version)
}
for (let g of v.gear) {
collection.insert(g)
}
}
module.exports = {
readGear,
}

View File

@ -0,0 +1,63 @@
const path = require('path')
const chokidar = require('chokidar')
const YAML = require('yaml')
const fs = require('fs')
const loki = require('lokijs')
const { readSpecimens } = require('./specimen.js')
const { readGear } = require('./gear.js')
const { UnhandledTypeError } = require('./errors.js')
const refresh = async (plugin, app, db_dir) => {
let files = await fs.promises.readdir(path.join(db_dir))
let db = new loki('Hord')
let specimens = db.getCollection('specimens') || db.addCollection('specimens', {indices: ['family', 'name']})
let gear = db.getCollection('gear') || db.addCollection('gear', {indices: ['type', 'name']})
for (let file of files) {
if (path.extname(file) === '.aedifex' || path.extname(file) === '.aed') {
plugin.log(`parsing aedifex file: "${path.join(db_dir, file)}"`)
let o = YAML.parse(await fs.promises.readFile(path.join(db_dir, file), { encoding: 'utf8' }))
try {
switch(o.type) {
case 'hord-specimens':
readSpecimens(specimens, o)
break;
case 'hord-gear':
readGear(gear, o)
break;
default:
throw new UnhandledTypeError(o.type)
break;
}
} catch(err) {
plugin.error(err)
}
}
}
app.live = {
...app.live,
db: db,
}
}
module.exports = {
priority: 1,
load: async (plugin, app) => {
// Load up our DB.
const db_dir = path.resolve(path.join(app.config.srd, 'db'))
await refresh(plugin, app, db_dir)
const watcher = chokidar.watch(db_dir, {persistent: true})
watcher.on('change', p => {
refresh(plugin, app, db_dir)
})
plugin.log('watching', db_dir)
app.express.use(require('./route.js')(plugin, app))
},
}

View File

@ -1,5 +1,5 @@
{
"name": "srd-gear-router",
"name": "srd-aedifex-router",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
@ -9,11 +9,13 @@
"license": "GPL-3.0",
"dependencies": {
"chokidar": "^3.5.1",
"lokijs": "^1.5.12",
"markdown-it": "^12.0.6",
"markdown-it-anchor": "^7.1.0",
"markdown-it-attrs": "^4.0.0",
"markdown-it-title": "^3.0.0",
"memory-cache": "^0.2.0",
"semver": "^7.3.5",
"yaml": "^1.10.2"
}
},
@ -162,6 +164,22 @@
"uc.micro": "^1.0.1"
}
},
"node_modules/lokijs": {
"version": "1.5.12",
"resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.12.tgz",
"integrity": "sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q=="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/markdown-it": {
"version": "12.0.6",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.0.6.tgz",
@ -241,6 +259,20 @@
"node": ">=8.10.0"
}
},
"node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -257,6 +289,11 @@
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
@ -370,6 +407,19 @@
"uc.micro": "^1.0.1"
}
},
"lokijs": {
"version": "1.5.12",
"resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.12.tgz",
"integrity": "sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"markdown-it": {
"version": "12.0.6",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.0.6.tgz",
@ -427,6 +477,14 @@
"picomatch": "^2.2.1"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -440,6 +498,11 @@
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",

View File

@ -1,5 +1,5 @@
{
"name": "srd-gear-router",
"name": "srd-aedifex-router",
"version": "1.0.0",
"description": "",
"main": "index.js",
@ -11,11 +11,13 @@
"license": "GPL-3.0",
"dependencies": {
"chokidar": "^3.5.1",
"lokijs": "^1.5.12",
"markdown-it": "^12.0.6",
"markdown-it-anchor": "^7.1.0",
"markdown-it-attrs": "^4.0.0",
"markdown-it-title": "^3.0.0",
"memory-cache": "^0.2.0",
"semver": "^7.3.5",
"yaml": "^1.10.2"
}
}

View File

@ -0,0 +1,56 @@
const router = require('express').Router()
const fs = require('fs')
const path = require('path')
module.exports = (plugin, app) => {
router.get(['/db/:collection', '/db/:collection/:type', '/db/:collection/:type/:name'], async function(req, res) {
let collection = app.live.db.getCollection(req.params.collection)
let results = []
let error = ''
let errorCode = 0
if (!collection) {
// TODO: 404 - collection missing
} else {
if (req.params.name) {
results = collection.find({type: req.params.type, name: req.params.name})
if (results.length === 0) {
error = `No such entry "${req.params.name}"`
errorCode = 404
}
} else if (req.params.type) {
results = collection.find({type: req.params.type})
if (results.length === 0) {
error = `No such collection type "${req.params.type}"`
errorCode = 404
}
} else {
results = collection.find({})
if (results.length === 0) {
error = `Collection empty`
errorCode = 404
}
}
}
//console.log(results, error, errorCode)
let content
if (errorCode > 0) {
content = error
} else {
content = app.dot.tables({...req.params, results, type: req.params.type, name: req.params.name, collection: req.params.collection})
}
res.render('index', {
content,
menu: app.live.menu,
title: 'gear',
www_name: app.live.conf.www_name,
www_copyright: app.live.conf.www_copyright,
scripts: ['/js/gear.js'],
})
})
plugin.log('added aedifex route')
return router
}

View File

@ -0,0 +1,22 @@
const semver = require('semver')
const { IncorrectTypeError, IncorrectPropertyError, MismatchedVersionError } = require('./errors.js')
function readSpecimens(collection, v) {
if (v.type !== 'hord-specimens') {
throw new IncorrectTypeError('hord-specimens', v.type)
}
if (!Array.isArray(v.specimens)) {
throw new IncorrectPropertyError('specimens', typeof [], typeof v.specimens)
}
if (!v.version || !semver.satisfies(v.version, '1.x')) {
throw new MismatchedVersionError('1.x', v.version)
}
for (let s of v.specimens) {
collection.insert(s)
}
}
module.exports = {
readSpecimens,
}

View File

@ -1,47 +0,0 @@
const path = require('path')
const chokidar = require('chokidar')
const YAML = require('yaml')
const fs = require('fs')
const refresh = async (app, db_dir) => {
const gear_path = path.join(db_dir, 'gear.yaml')
let gear = {}
YAML.parse(await fs.promises.readFile(gear_path, { encoding: 'utf8' })).forEach((v,i) => {
let type = 'untyped'
if (v.type) {
type = v.type+'s'
}
if (!gear[type]) {
gear[type] = []
}
gear[type].push(v)
})
app.live = {
...app.live,
db: {
...app.live.db,
gear: gear,
},
}
}
module.exports = {
priority: 1,
load: async (plugin, app) => {
// Load up our DB.
const db_dir = path.resolve(path.join(app.config.srd, 'db'))
await refresh(app, db_dir)
const watcher = chokidar.watch(db_dir, {persistent: true})
watcher.on('change', p => {
refresh(app, db_dir)
})
plugin.log('watching', db_dir)
app.express.use(require('./route.js')(plugin, app))
},
}

View File

@ -1,32 +0,0 @@
const router = require('express').Router()
const fs = require('fs')
const path = require('path')
module.exports = (plugin, app) => {
// gear, gear/type, gear/type/name
router.get(['/gear', '/gear/:type', '/gear/:type/:name'], async function(req, res) {
let entry = null
if (req.params.name) {
if (!app.live.db.gear[req.params.type]) {
// TODO: 404 - no such gear type
} else {
entry = app.live.db.gear[req.params.type].find(v=>v.name===req.params.name)
if (!entry) {
// TODO: 404 - no such gear by name
}
}
}
res.render('index', {
content: app.dot.tables({...req.params, db: app.live.db.gear, entry: entry}),
menu: app.live.menu,
title: 'gear',
www_name: app.live.conf.www_name,
www_copyright: app.live.conf.www_copyright,
scripts: ['/js/gear.js'],
})
})
plugin.log('added gear route')
return router
}

View File

@ -11,6 +11,7 @@
"dependencies": {
"markdown-it": "^12.0.6",
"markdown-it-anchor": "^7.1.0",
"markdown-it-attrs": "^4.0.0",
"markdown-it-title": "^3.0.0",
"memory-cache": "^0.2.0"
}
@ -59,6 +60,17 @@
"markdown-it": "*"
}
},
"node_modules/markdown-it-attrs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.0.0.tgz",
"integrity": "sha512-uLjtdCmhhmL3BuZsReYkFxk74qKjj5ahe34teBpOCJ4hYZZl7/ftLyXWLowngC2moRkbLEvKwN/7TMwbhbHE/A==",
"engines": {
"node": ">=6"
},
"peerDependencies": {
"markdown-it": ">= 9.0.0 < 13.0.0"
}
},
"node_modules/markdown-it-title": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-title/-/markdown-it-title-3.0.0.tgz",
@ -117,6 +129,12 @@
"integrity": "sha512-loQggrwsIkkP7TOrESvmYkV2ikbQNNKhHcWyqC7/C2CmfHl1tkUizJJU8C5aGgg7J6oXVQJx17gk7i47tNn/lQ==",
"requires": {}
},
"markdown-it-attrs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.0.0.tgz",
"integrity": "sha512-uLjtdCmhhmL3BuZsReYkFxk74qKjj5ahe34teBpOCJ4hYZZl7/ftLyXWLowngC2moRkbLEvKwN/7TMwbhbHE/A==",
"requires": {}
},
"markdown-it-title": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-title/-/markdown-it-title-3.0.0.tgz",

View File

@ -1,6 +1,6 @@
{{##def.weapons_table_entry:item:
<tr data-json='{{=JSON.stringify(item)}}'>
<td><a href="/gear/weapons/{{=item.name||''}}"</a>{{=item.name || ''}}</td>
<td><a href="/gear/weapon/{{=item.name||''}}"</a>{{=item.name || ''}}</td>
<td>{{=item.attack || ''}}</td>
<td>{{=item.damage || ''}}</td>
<td>{{=item.damagetype || ''}}</td>
@ -79,9 +79,20 @@
</dl>
#}}
{{? it.entry }}
{{#def.entry:it.entry || ''}}
{{?? !it.type }}
{{? it.results }}
{{#def.entry:it.results[0] || ''}}
<h2>got results</h2>
{{?? !it.name }}
{{? it.type === "weapon"}}
<h1>Weapons</h1>
{{#def.weapons_table:it.results || ''}}
{{?? it.type === "consumable"}}
<h1>Consumables</h1>
{{#def.consumables_table:it.results || ''}}
{{?? true }}
Bad type
{{?}}
{{?? true }}
<h1>Gear</h1>
{{? it.db.weapons }}
<h2><a href="gear/weapons">Weapons</a></h2>
@ -92,14 +103,4 @@
<h2><a href="gear/consumables">Consumables</a></h2>
{{#def.consumables_table:it.db.consumables || ''}}
{{?}}
{{?? true }}
{{? it.type === "weapons"}}
<h1>Weapons</h1>
{{#def.weapons_table:it.db.weapons || ''}}
{{?? it.type === "consumables"}}
<h1>Consumables</h1>
{{#def.consumables_table:it.db.consumables || ''}}
{{?? true }}
Bad type
{{?}}
{{?}}