mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 14:03:42 +00:00
dev: add get() and post() to extension API
This commit is contained in:
parent
d1ebbbe3c7
commit
3f6900f26b
7
mods/mods_available/example/main.js
Normal file
7
mods/mods_available/example/main.js
Normal file
@ -0,0 +1,7 @@
|
||||
extension.get('/example-mod-get', (req, res) => {
|
||||
res.send('Hello World!');
|
||||
});
|
||||
|
||||
extension.on('install', ({ services }) => {
|
||||
console.log('install was called');
|
||||
})
|
12
mods/mods_available/example/package.json
Normal file
12
mods/mods_available/example/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "example-puter-extension",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "AGPL-3.0-only"
|
||||
}
|
@ -1,6 +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");
|
||||
|
||||
class Extension extends AdvancedBase {
|
||||
static FEATURES = [
|
||||
@ -12,6 +13,51 @@ class Extension extends AdvancedBase {
|
||||
]
|
||||
}),
|
||||
];
|
||||
|
||||
constructor (...a) {
|
||||
super(...a);
|
||||
this.service = null;
|
||||
}
|
||||
|
||||
get (path, handler, options) {
|
||||
// this extension will have a default service
|
||||
this.ensure_service_();
|
||||
|
||||
// handler and options may be flipped
|
||||
if ( typeof handler === 'object' ) {
|
||||
[handler, options] = [options, handler];
|
||||
}
|
||||
if ( ! options ) options = {};
|
||||
|
||||
this.service.register_route_handler_(path, handler, {
|
||||
...options,
|
||||
methods: ['GET'],
|
||||
});
|
||||
}
|
||||
|
||||
post (path, handler, options) {
|
||||
// this extension will have a default service
|
||||
this.ensure_service_();
|
||||
|
||||
// handler and options may be flipped
|
||||
if ( typeof handler === 'object' ) {
|
||||
[handler, options] = [options, handler];
|
||||
}
|
||||
if ( ! options ) options = {};
|
||||
|
||||
this.service.register_route_handler_(path, handler, {
|
||||
...options,
|
||||
methods: ['POST'],
|
||||
});
|
||||
}
|
||||
|
||||
ensure_service_ () {
|
||||
if ( this.service ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.service = new ExtensionServiceState();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -1,10 +1,18 @@
|
||||
const { AdvancedBase } = require("@heyputer/putility");
|
||||
const uuid = require('uuid');
|
||||
const { ExtensionService } = require("./ExtensionService");
|
||||
|
||||
class ExtensionModule extends AdvancedBase {
|
||||
async install (context) {
|
||||
const services = context.get('services');
|
||||
|
||||
this.extension.emit('install', { context, services })
|
||||
|
||||
if ( this.extension.service ) {
|
||||
services.registerService(uuid.v4(), ExtensionService, {
|
||||
state: this.extension.service,
|
||||
}); // uuid for now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
64
src/backend/src/ExtensionService.js
Normal file
64
src/backend/src/ExtensionService.js
Normal file
@ -0,0 +1,64 @@
|
||||
const { AdvancedBase } = require("@heyputer/putility");
|
||||
const BaseService = require("./services/BaseService");
|
||||
const { Endpoint } = require("./util/expressutil");
|
||||
|
||||
class ExtensionServiceState extends AdvancedBase {
|
||||
constructor (...a) {
|
||||
super(...a);
|
||||
|
||||
this.endpoints_ = [];
|
||||
}
|
||||
register_route_handler_ (path, handler, options = {}) {
|
||||
// handler and options may be flipped
|
||||
if ( typeof handler === 'object' ) {
|
||||
[handler, options] = [options, handler];
|
||||
}
|
||||
|
||||
const mw = options.mw ?? [];
|
||||
|
||||
// TODO: option for auth middleware is harcoded here, but eventually
|
||||
// all exposed middlewares should be registered under the simpele names
|
||||
// used in this options object (probably; still not 100% decided on that)
|
||||
if ( options.auth ) {
|
||||
const auth_conf = typeof options.auth === 'object' ?
|
||||
options.auth : {};
|
||||
mw.push(configurable_auth(auth_conf));
|
||||
}
|
||||
|
||||
const endpoint = Endpoint({
|
||||
methods: options.methods ?? ['GET'],
|
||||
mw,
|
||||
route: path,
|
||||
handler: handler,
|
||||
});
|
||||
|
||||
this.endpoints_.push(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A service that does absolutely nothing by default, but its behavior can be
|
||||
* extended by adding route handlers and event listeners. This is used to
|
||||
* provide a default service for extensions.
|
||||
*/
|
||||
class ExtensionService extends BaseService {
|
||||
_construct () {
|
||||
this.extension = null;
|
||||
this.endpoints_ = [];
|
||||
}
|
||||
async _init (args) {
|
||||
this.state = args.state;
|
||||
}
|
||||
|
||||
['__on_install.routes'] (_, { app }) {
|
||||
for ( const endpoint of this.state.endpoints_ ) {
|
||||
endpoint.attach(app);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ExtensionService,
|
||||
ExtensionServiceState,
|
||||
};
|
Loading…
Reference in New Issue
Block a user