dev: hook extensions into service event bus

This commit is contained in:
KernelDeimos
2024-11-01 17:42:12 -04:00
parent 58f34b948a
commit 84989367a7
7 changed files with 46 additions and 8 deletions
+4 -2
View File
@@ -1,7 +1,7 @@
const { AdvancedBase } = require("@heyputer/putility");
const EmitterFeature = require("@heyputer/putility/src/features/EmitterFeature");
const { Context } = require("./util/context");
const { ExtensionService, ExtensionServiceState } = require("./ExtensionService");
const { ExtensionServiceState } = require("./ExtensionService");
class Extension extends AdvancedBase {
static FEATURES = [
@@ -56,7 +56,9 @@ class Extension extends AdvancedBase {
return;
}
this.service = new ExtensionServiceState();
this.service = new ExtensionServiceState({
extension: this,
});
}
}
+15 -1
View File
@@ -7,6 +7,8 @@ class ExtensionServiceState extends AdvancedBase {
constructor (...a) {
super(...a);
this.extension = a[0].extension;
this.endpoints_ = [];
}
register_route_handler_ (path, handler, options = {}) {
@@ -44,11 +46,23 @@ class ExtensionServiceState extends AdvancedBase {
*/
class ExtensionService extends BaseService {
_construct () {
this.extension = null;
this.endpoints_ = [];
}
async _init (args) {
this.state = args.state;
// Propagate all events not from extensions to `core.`
const svc_event = this.services.get('event');
svc_event.on_all((key, data, meta = {}) => {
meta.from_outside_of_extension = true;
this.state.extension.emit(`core.${key}`, data, meta);
});
this.state.extension.on_all((key, data, meta) => {
if ( meta.from_outside_of_extension ) return;
svc_event.emit(key, data, meta);
});
}
['__on_install.routes'] (_, { app }) {
+1 -1
View File
@@ -74,7 +74,7 @@ router.post('/save_account', auth, express.json(), async (req, res, next)=>{
const svc_cleanEmail = req.services.get('clean-email')
const clean_email = svc_cleanEmail.clean(req.body.email);
if ( ! svc_cleanEmail.validate(clean_email) ) {
if ( ! await svc_cleanEmail.validate(clean_email) ) {
return res.status(400).send('This email domain is not allowed.');
}
+1 -1
View File
@@ -147,7 +147,7 @@ module.exports = eggspress(['/signup'], {
const svc_cleanEmail = req.services.get('clean-email');
const clean_email = svc_cleanEmail.clean(req.body.email);
if ( ! svc_cleanEmail.validate(clean_email) ) {
if ( ! await svc_cleanEmail.validate(clean_email) ) {
return res.status(400).send('This email domain is not allowed');
}
@@ -49,7 +49,7 @@ module.exports = {
const svc_cleanEmail = req.services.get('clean-email');
const clean_email = svc_cleanEmail.clean(new_email);
if ( ! svc_cleanEmail.validate(clean_email) ) {
if ( ! await svc_cleanEmail.validate(clean_email) ) {
throw APIError.create('email_not_allowed', undefined, {
email: clean_email,
});
@@ -101,7 +101,7 @@ class CleanEmailService extends BaseService {
return eml.local + '@' + eml.domain;
}
validate (email) {
async validate (email) {
email = this.clean(email);
const config = this.global_config;
@@ -112,6 +112,12 @@ class CleanEmailService extends BaseService {
}
}
}
const svc_event = this.services.get('event');
const event = { allow: true, email };
await svc_event.emit('email.validate', event);
if ( ! event.allow ) return false;
return true;
}
+17 -1
View File
@@ -15,6 +15,7 @@ module.exports = ({ decorators }) => ({
// install the internal state
const state = instance._.emitterFeature = {};
state.listeners_ = {};
state.global_listeners_ = [];
state.callbackDecorators = decorators || [];
instance.emit = async (key, data, meta) => {
@@ -22,6 +23,17 @@ module.exports = ({ decorators }) => ({
const parts = key.split('.');
const promises = [];
for ( let i = 0 ; i < state.global_listeners_.length ; i++ ) {
let callback = state.global_listeners_[i];
for ( const decorator of state.callbackDecorators ) {
callback = decorator(callback);
}
promises.push(callback(key, data,
{ ...meta, key }));
}
for ( let i = 0; i < parts.length; i++ ) {
const part = i === parts.length - 1
? parts.join('.')
@@ -42,7 +54,7 @@ module.exports = ({ decorators }) => ({
}));
}
}
return await Promise.all(promises);
}
@@ -63,6 +75,10 @@ module.exports = ({ decorators }) => ({
return det;
}
instance.on_all = (callback) => {
state.global_listeners_.push(callback);
};
}
});