diff --git a/lib/api.js b/lib/api.js index bb2fedd4..b28c5d69 100644 --- a/lib/api.js +++ b/lib/api.js @@ -2,11 +2,11 @@ const { node, npm, metarhia } = require('./deps.js'); const { Procedure } = require('./procedure.js'); -const { Cache } = require('./cache.js'); +const { Place } = require('./place.js'); -class Api extends Cache { - constructor(place, application) { - super(place, application); +class Api extends Place { + constructor(name, application) { + super(name, application); this.collection = {}; this.signatures = {}; } diff --git a/lib/application.js b/lib/application.js index c7ff5eee..f0d7561b 100644 --- a/lib/application.js +++ b/lib/application.js @@ -4,7 +4,7 @@ const { node, npm, metarhia, wt } = require('./deps.js'); const { MessageChannel, parentPort, threadId, workerData } = wt; const { Error, DomainError } = metarhia.metautil; const { Api } = require('./api.js'); -const { Place } = require('./place.js'); +const { Code } = require('./code.js'); const { Static } = require('./static.js'); const { Cert } = require('./cert.js'); const { Schemas } = require('./schemas.js'); @@ -52,10 +52,10 @@ class Application extends node.events.EventEmitter { this.cert = new Cert('cert', this, { ext: ['pem', 'domains'] }); this.resources = new Static('resources', this); this.api = new Api('api', this); - this.lib = new Place('lib', this); - this.db = new Place('db', this); - this.bus = new Place('bus', this); - this.domain = new Place('domain', this); + this.lib = new Code('lib', this); + this.db = new Code('db', this); + this.bus = new Code('bus', this); + this.domain = new Code('domain', this); this.starts = []; this.config = null; @@ -111,22 +111,13 @@ class Application extends node.events.EventEmitter { async shutdown() { this.finalization = true; - await this.stopPlace('domain'); - await this.stopPlace('db'); - await this.stopPlace('lib'); + await this.domain.stop(); + await this.db.stop(); + await this.lib.stop(); if (this.server) await this.server.close(); if (this.logger) await this.logger.close(); } - async stopPlace(name) { - if (!this.sandbox) return; - const place = this.sandbox[name]; - for (const moduleName of Object.keys(place)) { - const module = place[moduleName]; - if (typeof module.stop === 'function') await this.execute(module.stop); - } - } - createSandbox() { const { config, console, resources, schemas } = this; const { server: { host, port, protocol } = {} } = this; diff --git a/lib/cache.js b/lib/cache.js deleted file mode 100644 index 6dc30a00..00000000 --- a/lib/cache.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -const { node, metarhia } = require('./deps.js'); - -class Cache { - constructor(place, application) { - this.place = place; - this.path = application.absolute(place); - this.application = application; - } - - async load(targetPath = this.path) { - await metarhia.metautil.ensureDirectory(this.path); - this.application.watcher.watch(targetPath); - try { - const files = await node.fsp.readdir(targetPath, { withFileTypes: true }); - for (const file of files) { - const { name } = file; - if (name.startsWith('.eslint')) continue; - const filePath = node.path.join(targetPath, name); - if (file.isDirectory()) await this.load(filePath); - else await this.change(filePath); - } - } catch (error) { - const console = this.application.console || global.console; - console.error(error.stack); - } - } -} - -module.exports = { Cache }; diff --git a/lib/cert.js b/lib/cert.js index c66136a8..6938c2ca 100644 --- a/lib/cert.js +++ b/lib/cert.js @@ -4,8 +4,8 @@ const { node, metarhia, wt } = require('./deps.js'); const { Static } = require('./static.js'); class Cert extends Static { - constructor(place, application, options = {}) { - super(place, application, options); + constructor(name, application, options = {}) { + super(name, application, options); this.domains = new Map(); } diff --git a/lib/code.js b/lib/code.js new file mode 100644 index 00000000..9fd4c066 --- /dev/null +++ b/lib/code.js @@ -0,0 +1,82 @@ +'use strict'; + +const { metarhia } = require('./deps.js'); +const { Place } = require('./place.js'); +const bus = require('./bus.js'); + +class Code extends Place { + constructor(name, application) { + super(name, application); + this.tree = {}; + } + + async stop() { + for (const moduleName of Object.keys(this.tree)) { + const module = this.tree[moduleName]; + if (typeof module.stop === 'function') { + await this.application.execute(module.stop); + } + } + } + + stopModule(name, module) { + const timeout = this.application.config.server.timeouts.watch; + setTimeout(() => { + if (this.tree[name] !== undefined) return; + this.application.execute(module.stop); + }, timeout); + } + + set(relPath, unit) { + const names = metarhia.metautil.parsePath(relPath); + let level = this.tree; + const last = names.length - 1; + for (let depth = 0; depth <= last; depth++) { + const name = names[depth]; + let next = level[name]; + if (depth === last) { + if (unit === null) { + if (name === 'stop') this.stopModule(names[0], level); + delete level[name]; + return; + } + next = unit; + unit.parent = level; + } + if (next === undefined) next = { parent: level }; + level[name] = next; + if (depth === 1 && name === 'start') { + if (unit.constructor.name === 'AsyncFunction') { + this.application.starts.push(unit); + } else { + const msg = `${relPath} expected to be async function`; + this.application.console.error(msg); + } + } + level = next; + } + } + + delete(filePath) { + const relPath = filePath.substring(this.path.length + 1); + this.set(relPath, null); + } + + async change(filePath) { + if (!filePath.endsWith('.js')) return; + const { application, path, name } = this; + const options = { context: application.sandbox, filename: filePath }; + try { + const { exports } = await metarhia.metavm.readScript(filePath, options); + const relPath = filePath.substring(path.length + 1); + const exp = name === 'bus' ? bus.prepare(exports, application) : exports; + this.set(relPath, exp); + } catch (error) { + if (error.code !== 'ENOENT') { + application.console.error(error.stack); + } + } + } +} + +module.exports = { Code }; diff --git a/lib/place.js b/lib/place.js index bb9fecc9..87ad89da 100644 --- a/lib/place.js +++ b/lib/place.js @@ -1,71 +1,29 @@ 'use strict'; -const { metarhia } = require('./deps.js'); -const { Cache } = require('./cache.js'); -const bus = require('./bus.js'); +const { node, metarhia } = require('./deps.js'); -class Place extends Cache { - constructor(place, application) { - super(place, application); - this.tree = {}; +class Place { + constructor(name, application) { + this.name = name; + this.path = application.absolute(name); + this.application = application; } - stop(name, method) { - const timeout = this.application.config.server.timeouts.watch; - setTimeout(() => { - if (this.tree[name] !== undefined) return; - this.application.execute(method); - }, timeout); - } - - set(relPath, unit) { - const names = metarhia.metautil.parsePath(relPath); - let level = this.tree; - const last = names.length - 1; - for (let depth = 0; depth <= last; depth++) { - const name = names[depth]; - let next = level[name]; - if (depth === last) { - if (unit === null) { - if (name === 'stop') this.stop(names[0], level.stop); - delete level[name]; - return; - } - next = unit; - unit.parent = level; - } - if (next === undefined) next = { parent: level }; - level[name] = next; - if (depth === 1 && name === 'start') { - if (unit.constructor.name === 'AsyncFunction') { - this.application.starts.push(unit); - } else { - const msg = `${relPath} expected to be async function`; - this.application.console.error(msg); - } - } - level = next; - } - } - - delete(filePath) { - const relPath = filePath.substring(this.path.length + 1); - this.set(relPath, null); - } - - async change(filePath) { - if (!filePath.endsWith('.js')) return; - const { application, path, place } = this; - const options = { context: application.sandbox, filename: filePath }; + async load(targetPath = this.path) { + await metarhia.metautil.ensureDirectory(this.path); + this.application.watcher.watch(targetPath); try { - const { exports } = await metarhia.metavm.readScript(filePath, options); - const relPath = filePath.substring(path.length + 1); - const exp = place === 'bus' ? bus.prepare(exports, application) : exports; - this.set(relPath, exp); - } catch (error) { - if (error.code !== 'ENOENT') { - application.console.error(error.stack); + const files = await node.fsp.readdir(targetPath, { withFileTypes: true }); + for (const file of files) { + const { name } = file; + if (name.startsWith('.eslint')) continue; + const filePath = node.path.join(targetPath, name); + if (file.isDirectory()) await this.load(filePath); + else await this.change(filePath); } + } catch (error) { + const console = this.application.console || global.console; + console.error(error.stack); } } } diff --git a/lib/schemas.js b/lib/schemas.js index c926dbe5..055e643a 100644 --- a/lib/schemas.js +++ b/lib/schemas.js @@ -1,11 +1,11 @@ 'use strict'; const { node, metarhia } = require('./deps.js'); -const { Cache } = require('./cache.js'); +const { Place } = require('./place.js'); -class Schemas extends Cache { - constructor(place, application) { - super(place, application); +class Schemas extends Place { + constructor(name, application) { + super(name, application); this.model = null; } diff --git a/lib/static.js b/lib/static.js index 4f64f8e1..a8371cf9 100644 --- a/lib/static.js +++ b/lib/static.js @@ -1,14 +1,14 @@ 'use strict'; const { node, metarhia } = require('./deps.js'); -const { Cache } = require('./cache.js'); +const { Place } = require('./place.js'); const WIN = process.platform === 'win32'; const MAX_FILE_SIZE = '10 mb'; -class Static extends Cache { - constructor(place, application, options = {}) { - super(place, application); +class Static extends Place { + constructor(name, application, options = {}) { + super(name, application); this.files = new Map(); this.ext = options.ext; this.maxFileSize = -1; diff --git a/test/application.js b/test/application.js index 4548af9f..441cb1ad 100644 --- a/test/application.js +++ b/test/application.js @@ -20,9 +20,9 @@ metatests.test('lib/application', (test) => { test.strictSame(application.cert.constructor.name, 'Cert'); test.strictSame(application.resources.constructor.name, 'Static'); test.strictSame(application.api.constructor.name, 'Api'); - test.strictSame(application.lib.constructor.name, 'Place'); - test.strictSame(application.db.constructor.name, 'Place'); - test.strictSame(application.bus.constructor.name, 'Place'); + test.strictSame(application.lib.constructor.name, 'Code'); + test.strictSame(application.db.constructor.name, 'Code'); + test.strictSame(application.bus.constructor.name, 'Code'); test.strictSame(application.starts, []); test.strictSame(application.config, null); test.strictSame(application.logger, null); diff --git a/test/bus.js b/test/bus.js index 08366d2a..a5b46c05 100644 --- a/test/bus.js +++ b/test/bus.js @@ -2,7 +2,7 @@ const path = require('node:path'); const metatests = require('metatests'); -const { Place } = require('../lib/place.js'); +const { Code } = require('../lib/code.js'); const root = process.cwd(); @@ -17,8 +17,8 @@ const application = { }; metatests.testAsync('lib/bus', async (test) => { - const bus = new Place('bus', application); - test.strictSame(bus.place, 'bus'); + const bus = new Code('bus', application); + test.strictSame(bus.name, 'bus'); test.strictSame(bus.path, path.join(root, 'test/bus')); test.strictSame(typeof bus.application, 'object'); test.strictSame(bus.tree, {}); diff --git a/test/cache.js b/test/cache.js index dfd28a43..7017203a 100644 --- a/test/cache.js +++ b/test/cache.js @@ -2,7 +2,7 @@ const path = require('node:path'); const metatests = require('metatests'); -const { Cache } = require('../lib/cache.js'); +const { Place } = require('../lib/place.js'); const root = process.cwd(); @@ -16,26 +16,26 @@ const application = { }, }; -metatests.testAsync('lib/cache', async (test) => { +metatests.testAsync('lib/place', async (test) => { test.plan(17); - test.strictSame(typeof Cache, 'function'); - test.strictSame(Cache.name, 'Cache'); + test.strictSame(typeof Place, 'function'); + test.strictSame(Place.name, 'Place'); - class EmptyCache extends Cache { + class EmptyPlace extends Place { constructor(place, application) { super(place, application); this.empty = true; } async change(filePath) { - test.strictSame(this.constructor.name, 'EmptyCache'); + test.strictSame(this.constructor.name, 'EmptyPlace'); test.strictSame(typeof filePath, 'string'); } } - const cache = new EmptyCache('cache', application); - await cache.load(); - test.strictSame(cache.place, 'cache'); - test.strictSame(cache.empty, true); + const place = new EmptyPlace('lib', application); + await place.load(); + test.strictSame(place.name, 'lib'); + test.strictSame(place.empty, true); }); diff --git a/test/code.js b/test/code.js new file mode 100644 index 00000000..66acf130 --- /dev/null +++ b/test/code.js @@ -0,0 +1,34 @@ +'use strict'; + +const path = require('node:path'); +const metatests = require('metatests'); +const { Code } = require('../lib/code.js'); + +const root = process.cwd(); + +const application = { + path: path.join(root, 'test'), + console, + starts: [], + watcher: { watch() {} }, + absolute(relative) { + return path.join(this.path, relative); + }, +}; + +metatests.testAsync('lib/code', async (test) => { + const code = new Code('lib', application); + test.strictSame(code.name, 'lib'); + test.strictSame(typeof code.path, 'string'); + test.strictSame(typeof code.application, 'object'); + test.strictSame(code.tree, {}); + await code.load(); + test.strictSame(Object.keys(code.tree), ['example', 'utils']); + test.strictSame(code.tree.example.parent, code.tree); + test.strictSame(typeof code.tree.example.add, 'object'); + test.strictSame(typeof code.tree.example.doSomething, 'function'); + test.strictSame(typeof code.tree.example.stop, 'function'); + test.strictSame(typeof code.tree.example.start, 'function'); + test.strictSame(code.tree.utils.UNITS.length, 9); + test.end(); +}); diff --git a/test/cache/.eslintrc.json b/test/lib/.eslintrc.json similarity index 100% rename from test/cache/.eslintrc.json rename to test/lib/.eslintrc.json diff --git a/test/cache/example/add.js b/test/lib/example/add.js similarity index 100% rename from test/cache/example/add.js rename to test/lib/example/add.js diff --git a/test/cache/example/cache.js b/test/lib/example/cache.js similarity index 100% rename from test/cache/example/cache.js rename to test/lib/example/cache.js diff --git a/test/cache/example/doSomething.js b/test/lib/example/doSomething.js similarity index 100% rename from test/cache/example/doSomething.js rename to test/lib/example/doSomething.js diff --git a/test/cache/example/start.js b/test/lib/example/start.js similarity index 100% rename from test/cache/example/start.js rename to test/lib/example/start.js diff --git a/test/cache/example/stop.js b/test/lib/example/stop.js similarity index 100% rename from test/cache/example/stop.js rename to test/lib/example/stop.js diff --git a/test/cache/example/storage/set.js b/test/lib/example/storage/set.js similarity index 100% rename from test/cache/example/storage/set.js rename to test/lib/example/storage/set.js diff --git a/test/cache/example/submodule1/method1.js b/test/lib/example/submodule1/method1.js similarity index 100% rename from test/cache/example/submodule1/method1.js rename to test/lib/example/submodule1/method1.js diff --git a/test/cache/example/submodule1/method2.js b/test/lib/example/submodule1/method2.js similarity index 100% rename from test/cache/example/submodule1/method2.js rename to test/lib/example/submodule1/method2.js diff --git a/test/cache/example/submodule2/method1.js b/test/lib/example/submodule2/method1.js similarity index 100% rename from test/cache/example/submodule2/method1.js rename to test/lib/example/submodule2/method1.js diff --git a/test/cache/example/submodule2/method2.js b/test/lib/example/submodule2/method2.js similarity index 100% rename from test/cache/example/submodule2/method2.js rename to test/lib/example/submodule2/method2.js diff --git a/test/cache/example/submodule2/nested1/method1.js b/test/lib/example/submodule2/nested1/method1.js similarity index 100% rename from test/cache/example/submodule2/nested1/method1.js rename to test/lib/example/submodule2/nested1/method1.js diff --git a/test/cache/example/submodule3/nested2/method1.js b/test/lib/example/submodule3/nested2/method1.js similarity index 100% rename from test/cache/example/submodule3/nested2/method1.js rename to test/lib/example/submodule3/nested2/method1.js diff --git a/test/cache/utils.js b/test/lib/utils.js similarity index 100% rename from test/cache/utils.js rename to test/lib/utils.js diff --git a/test/place.js b/test/place.js deleted file mode 100644 index 5f9c1a4d..00000000 --- a/test/place.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -const path = require('node:path'); -const metatests = require('metatests'); -const { Place } = require('../lib/place.js'); - -const root = process.cwd(); - -const application = { - path: path.join(root, 'test'), - console, - starts: [], - watcher: { watch() {} }, - absolute(relative) { - return path.join(this.path, relative); - }, -}; - -metatests.testAsync('lib/place', async (test) => { - const cache = new Place('cache', application); - test.strictSame(cache.place, 'cache'); - test.strictSame(typeof cache.path, 'string'); - test.strictSame(typeof cache.application, 'object'); - test.strictSame(cache.tree, {}); - await cache.load(); - test.strictSame(Object.keys(cache.tree), ['example', 'utils']); - test.strictSame(cache.tree.example.parent, cache.tree); - test.strictSame(typeof cache.tree.example.add, 'object'); - test.strictSame(typeof cache.tree.example.doSomething, 'function'); - test.strictSame(typeof cache.tree.example.stop, 'function'); - test.strictSame(typeof cache.tree.example.start, 'function'); - test.strictSame(cache.tree.utils.UNITS.length, 9); - test.end(); -}); diff --git a/test/static.js b/test/static.js index 218fdf99..1de12c69 100644 --- a/test/static.js +++ b/test/static.js @@ -15,7 +15,7 @@ const application = { }; metatests.testAsync('lib/static load', async (test) => { - const cache = new Static('cache', application); + const cache = new Static('lib', application); test.strictSame(cache.files instanceof Map, true); test.strictSame(cache.files.size, 0); test.strictSame(cache.ext, undefined); diff --git a/types/core.d.ts b/types/core.d.ts index 7a72ab97..6a8af033 100644 --- a/types/core.d.ts +++ b/types/core.d.ts @@ -18,7 +18,11 @@ export interface InvokeTarget { args: object; } -export interface Cache { +export interface Static { + get(name: string): unknown; +} + +export interface Schemas { get(name: string): unknown; } @@ -29,8 +33,8 @@ export interface Listener { export interface Application extends EventEmitter { worker: { id: string }; server: { host: string; port: number; protocol: string }; - resources: Cache; - schemas: Cache; + resources: Static; + schemas: Schemas; scheduler: Scheduler; introspect: () => Promise; invoke: (target: InvokeTarget) => Promise;