Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor application places #1879

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
}
Expand Down
25 changes: 8 additions & 17 deletions lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
31 changes: 0 additions & 31 deletions lib/cache.js

This file was deleted.

4 changes: 2 additions & 2 deletions lib/cert.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
82 changes: 82 additions & 0 deletions lib/code.js
Original file line number Diff line number Diff line change
@@ -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 };
80 changes: 19 additions & 61 deletions lib/place.js
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions lib/schemas.js
Original file line number Diff line number Diff line change
@@ -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;
}

Expand Down
8 changes: 4 additions & 4 deletions lib/static.js
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
6 changes: 3 additions & 3 deletions test/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions test/bus.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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, {});
Expand Down
20 changes: 10 additions & 10 deletions test/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
});
Loading
Loading