mirror of
https://github.com/HeyPuter/puter.git
synced 2025-01-23 06:00:21 +08:00
refactor: move WebServerService and socketio to module
This commit is contained in:
parent
3887ce05da
commit
10f6e5458e
@ -28,6 +28,7 @@ const { Context } = require("./src/util/context.js");
|
||||
const { TestDriversModule } = require("./src/modules/test-drivers/TestDriversModule.js");
|
||||
const { PuterAIModule } = require("./src/modules/puterai/PuterAIModule.js");
|
||||
const { BroadcastModule } = require("./src/modules/broadcast/BroadcastModule.js");
|
||||
const { WebModule } = require("./src/modules/web/WebModule.js");
|
||||
|
||||
|
||||
module.exports = {
|
||||
@ -42,9 +43,15 @@ module.exports = {
|
||||
Context,
|
||||
|
||||
Kernel,
|
||||
|
||||
EssentialModules: [
|
||||
CoreModule,
|
||||
WebModule,
|
||||
],
|
||||
|
||||
// Pre-built modules
|
||||
CoreModule,
|
||||
WebModule,
|
||||
DatabaseModule,
|
||||
PuterDriversModule,
|
||||
LocalDiskStorageModule,
|
||||
|
@ -129,7 +129,6 @@ const install = async ({ services, app, useapi, modapi }) => {
|
||||
const { ConfigurableCountingService } = require('./services/ConfigurableCountingService');
|
||||
const { FSLockService } = require('./services/fs/FSLockService');
|
||||
const { StrategizedService } = require('./services/StrategizedService');
|
||||
const WebServerService = require('./services/WebServerService');
|
||||
const FilesystemAPIService = require('./services/FilesystemAPIService');
|
||||
const ServeGUIService = require('./services/ServeGUIService');
|
||||
const PuterAPIService = require('./services/PuterAPIService');
|
||||
@ -143,7 +142,6 @@ const install = async ({ services, app, useapi, modapi }) => {
|
||||
services.registerService('server-health', ServerHealthService);
|
||||
services.registerService('log-service', LogService);
|
||||
services.registerService('commands', CommandService);
|
||||
services.registerService('web-server', WebServerService, { app });
|
||||
services.registerService('__api-filesystem', FilesystemAPIService);
|
||||
services.registerService('__api', PuterAPIService);
|
||||
services.registerService('__gui', ServeGUIService);
|
||||
@ -354,6 +352,9 @@ const install = async ({ services, app, useapi, modapi }) => {
|
||||
|
||||
const { UserService } = require('./services/UserService');
|
||||
services.registerService('user', UserService);
|
||||
|
||||
const { WSPushService } = require('./services/WSPushService');
|
||||
services.registerService('__event-push-ws', WSPushService);
|
||||
}
|
||||
|
||||
const install_legacy = async ({ services }) => {
|
||||
@ -361,7 +362,6 @@ const install_legacy = async ({ services }) => {
|
||||
// const { FilesystemService } = require('./filesystem/FilesystemService');
|
||||
const PerformanceMonitor = require('./monitor/PerformanceMonitor');
|
||||
const { OperationTraceService } = require('./services/OperationTraceService');
|
||||
const { WSPushService } = require('./services/WSPushService');
|
||||
const { ClientOperationService } = require('./services/ClientOperationService');
|
||||
const { EngPortalService } = require('./services/EngPortalService');
|
||||
const { AppInformationService } = require('./services/AppInformationService');
|
||||
@ -371,7 +371,6 @@ const install_legacy = async ({ services }) => {
|
||||
services.registerService('process-event', ProcessEventService);
|
||||
// services.registerService('filesystem', FilesystemService);
|
||||
services.registerService('operationTrace', OperationTraceService);
|
||||
services.registerService('__event-push-ws', WSPushService);
|
||||
services.registerService('file-cache', FileCacheService);
|
||||
services.registerService('client-operation', ClientOperationService);
|
||||
services.registerService('app-information', AppInformationService);
|
||||
|
@ -44,7 +44,6 @@ class FilesystemService extends BaseService {
|
||||
static MODULES = {
|
||||
_path: require('path'),
|
||||
uuidv4: require('uuid').v4,
|
||||
socketio: require('../socketio.js'),
|
||||
config: require('../config.js'),
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,6 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
|
||||
static MODULES = {
|
||||
_path: require('path'),
|
||||
socketio: require('../../socketio.js'),
|
||||
}
|
||||
|
||||
static PROPERTIES = {
|
||||
@ -258,7 +257,7 @@ class HLMkdir extends HLFilesystemOperation {
|
||||
|
||||
async _run () {
|
||||
const { context, values } = this;
|
||||
const { _path, socketio } = this.modules;
|
||||
const { _path } = this.modules;
|
||||
const fs = context.get('services').get('filesystem');
|
||||
|
||||
if ( ! is_valid_path(values.path, {
|
||||
|
@ -116,7 +116,6 @@ class HLWrite extends HLFilesystemOperation {
|
||||
|
||||
static MODULES = {
|
||||
_path: require('path'),
|
||||
socketio: require('../../socketio.js'),
|
||||
mime: require('mime-types'),
|
||||
}
|
||||
|
||||
|
51
src/backend/src/modules/web/SocketioService.js
Normal file
51
src/backend/src/modules/web/SocketioService.js
Normal file
@ -0,0 +1,51 @@
|
||||
const BaseService = require('../../services/BaseService');
|
||||
|
||||
class SocketioService extends BaseService {
|
||||
static MODULES = {
|
||||
socketio: require('socket.io'),
|
||||
};
|
||||
|
||||
['__on_install.socketio'] (_, { server }) {
|
||||
const require = this.require;
|
||||
|
||||
const socketio = require('socket.io');
|
||||
/**
|
||||
* @type {import('socket.io').Server}
|
||||
*/
|
||||
this.io = socketio(server, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async send (socket_specifiers, key, data) {
|
||||
const svc_getUser = this.services.get('get-user');
|
||||
|
||||
if ( ! Array.isArray(socket_specifiers) ) {
|
||||
socket_specifiers = [socket_specifiers];
|
||||
}
|
||||
|
||||
for ( const socket_specifier of socket_specifiers ) {
|
||||
if ( socket_specifier.room ) {
|
||||
this.io.to(socket_specifier.room).emit(key, data);
|
||||
} else if ( socket_specifier.socket ) {
|
||||
const io = this.io.sockets.sockets.get(socket_specifier.socket)
|
||||
if ( ! io ) continue;
|
||||
io.emit(key, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
has (socket_specifier) {
|
||||
if ( socket_specifier.room ) {
|
||||
const room = this.io.sockets.adapter.rooms.get(socket_specifier.room);
|
||||
return (!!room) && room.size > 0;
|
||||
}
|
||||
if ( socket_specifier.socket ) {
|
||||
return this.io.sockets.sockets.has(socket_specifier.socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SocketioService;
|
17
src/backend/src/modules/web/WebModule.js
Normal file
17
src/backend/src/modules/web/WebModule.js
Normal file
@ -0,0 +1,17 @@
|
||||
const { AdvancedBase } = require("@heyputer/putility");
|
||||
|
||||
class WebModule extends AdvancedBase {
|
||||
async install (context) {
|
||||
const services = context.get('services');
|
||||
|
||||
const SocketioService = require("./SocketioService");
|
||||
services.registerService('socketio', SocketioService);
|
||||
|
||||
const WebServerService = require("./WebServerService");
|
||||
services.registerService('web-server', WebServerService);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
WebModule,
|
||||
};
|
@ -18,18 +18,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
const express = require('express');
|
||||
const eggspress = require("../api/eggspress");
|
||||
const { Context, ContextExpressMiddleware } = require("../util/context");
|
||||
const BaseService = require("./BaseService");
|
||||
const eggspress = require("../../api/eggspress.js");
|
||||
const { Context, ContextExpressMiddleware } = require("../../util/context.js");
|
||||
const BaseService = require("../../services/BaseService.js");
|
||||
|
||||
const config = require('../config');
|
||||
const config = require('../../config.js');
|
||||
const https = require('https')
|
||||
var http = require('http');
|
||||
const fs = require('fs');
|
||||
const auth = require('../middleware/auth');
|
||||
const { osclink } = require('../util/strutil');
|
||||
const { surrounding_box, es_import_promise } = require('../fun/dev-console-ui-utils');
|
||||
const auth = require('../../middleware/auth.js');
|
||||
const { osclink } = require('../../util/strutil.js');
|
||||
const { surrounding_box, es_import_promise } = require('../../fun/dev-console-ui-utils.js');
|
||||
|
||||
const relative_require = require;
|
||||
|
||||
/**
|
||||
* This class, WebServerService, is responsible for starting and managing the Puter web server.
|
||||
@ -103,9 +104,9 @@ class WebServerService extends BaseService {
|
||||
// error handling middleware goes last, as per the
|
||||
// expressjs documentation:
|
||||
// https://expressjs.com/en/guide/error-handling.html
|
||||
this.app.use(require('../api/api_error_handler'));
|
||||
this.app.use(require('../../api/api_error_handler.js'));
|
||||
|
||||
const { jwt_auth } = require('../helpers');
|
||||
const { jwt_auth } = require('../../helpers.js');
|
||||
|
||||
config.http_port = process.env.PORT ?? config.http_port;
|
||||
|
||||
@ -224,7 +225,11 @@ class WebServerService extends BaseService {
|
||||
// server.keepAliveTimeout = 1000 * 60 * 60 * 2; // 2 hours
|
||||
|
||||
// Socket.io server instance
|
||||
const socketio = require('../socketio.js').init(server);
|
||||
// const socketio = require('../../socketio.js').init(server);
|
||||
|
||||
// TODO: ^ Replace above line with the following code:
|
||||
await this.services.emit('install.socketio', { server });
|
||||
const socketio = this.services.get('socketio').io;
|
||||
|
||||
// Socket.io middleware for authentication
|
||||
socketio.use(async (socket, next) => {
|
||||
@ -305,13 +310,13 @@ class WebServerService extends BaseService {
|
||||
|
||||
|
||||
const require = this.require;
|
||||
|
||||
|
||||
const config = this.global_config;
|
||||
new ContextExpressMiddleware({
|
||||
parent: globalThis.root_context.sub({
|
||||
puter_environment: Context.create({
|
||||
env: config.env,
|
||||
version: require('../../package.json').version,
|
||||
version: relative_require('../../../package.json').version,
|
||||
}),
|
||||
}, 'mw')
|
||||
}).install(app);
|
||||
@ -580,6 +585,8 @@ class WebServerService extends BaseService {
|
||||
app.options('/*', (_, res) => {
|
||||
return res.sendStatus(200);
|
||||
});
|
||||
|
||||
console.log('WEB SERVER INIT DONE');
|
||||
}
|
||||
|
||||
_register_commands (commands) {
|
||||
@ -611,7 +618,7 @@ class WebServerService extends BaseService {
|
||||
// comment above line 497
|
||||
print_puter_logo_() {
|
||||
if ( this.global_config.env !== 'dev' ) return;
|
||||
const logos = require('../fun/logos.js');
|
||||
const logos = require('../../fun/logos.js');
|
||||
let last_logo = undefined;
|
||||
for ( const logo of logos ) {
|
||||
if ( logo.sz <= (process.stdout.columns ?? 0) ) {
|
@ -289,10 +289,8 @@ router.all('*', async function(req, res, next) {
|
||||
invalidate_cached_user(user);
|
||||
|
||||
// send realtime success msg to client
|
||||
let socketio = require('../socketio.js').getio();
|
||||
if(socketio){
|
||||
socketio.to(user.id).emit('user.email_confirmed', {})
|
||||
}
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: user.id }, 'user.email_confirmed', {});
|
||||
|
||||
// return results
|
||||
h += `<p style="text-align:center; color:green;">Your email has been successfully confirmed.</p>`;
|
||||
|
@ -83,10 +83,8 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', {
|
||||
});
|
||||
|
||||
invalidate_cached_user_by_id(user_id);
|
||||
let socketio = require('../socketio.js').getio();
|
||||
if(socketio){
|
||||
socketio.to(user_id).emit('user.email_changed', {})
|
||||
}
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: user_id }, 'user.email_changed', {});
|
||||
|
||||
const h = `<p style="text-align:center; color:green;">Your email has been successfully confirmed.</p>`;
|
||||
return res.send(h);
|
||||
|
@ -87,14 +87,14 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{
|
||||
|
||||
// Send realtime success msg to client
|
||||
if(req.body.code === req.user.email_confirm_code){
|
||||
let socketio = require('../socketio.js').getio();
|
||||
if(socketio){
|
||||
socketio.to(req.user.id).emit('user.email_confirmed', {original_client_socket_id: req.body.original_client_socket_id})
|
||||
}
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: req.user.id }, 'user.email_confirmed', {
|
||||
original_client_socket_id: req.body.original_client_socket_id
|
||||
});
|
||||
}
|
||||
|
||||
// return results
|
||||
return res.send(res_obj)
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
module.exports = router
|
||||
|
@ -48,8 +48,6 @@ module.exports = eggspress('/delete', {
|
||||
else if(paths.length === 0)
|
||||
return res.status(400).send('paths cannot be empty')
|
||||
|
||||
const socketio = require('../../socketio.js').getio();
|
||||
|
||||
// try to delete each path in the array one by one (if glob, resolve first)
|
||||
// TODO: remove this pseudo-batch
|
||||
for(let j=0; j < paths.length; j++){
|
||||
@ -67,9 +65,11 @@ module.exports = eggspress('/delete', {
|
||||
});
|
||||
|
||||
// send realtime success msg to client
|
||||
if(socketio){
|
||||
socketio.to(req.user.id).emit('item.removed', {path: item_path, descendants_only: descendants_only})
|
||||
}
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: req.user.id }, 'item.removed', {
|
||||
path: item_path,
|
||||
descendants_only: descendants_only,
|
||||
});
|
||||
}
|
||||
|
||||
res.send({});
|
||||
|
@ -174,10 +174,8 @@ module.exports = eggspress('/rename', {
|
||||
};
|
||||
|
||||
// send realtime success msg to client
|
||||
let socketio = require('../../socketio.js').getio();
|
||||
if(socketio){
|
||||
socketio.to(req.user.id).emit('item.renamed', return_obj)
|
||||
}
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: req.user.id }, 'item.renamed', return_obj);
|
||||
|
||||
return res.send(return_obj);
|
||||
});
|
||||
|
@ -90,8 +90,8 @@ router.post('/rao', auth, express.json(), async (req, res, next)=>{
|
||||
}
|
||||
|
||||
// Update clients
|
||||
const socketio = require('../socketio.js').getio();
|
||||
socketio.to(req.user.id).emit('app.opened', {
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: req.user.id }, 'app.opened', {
|
||||
uuid: opened_app.uid,
|
||||
uid: opened_app.uid,
|
||||
name: opened_app.name,
|
||||
|
@ -457,10 +457,8 @@ module.exports = eggspress('/writeFile', {
|
||||
};
|
||||
|
||||
// send realtime success msg to client
|
||||
let socketio = require('../socketio.js').getio();
|
||||
if(socketio){
|
||||
socketio.to(fsentry.user_id).emit('item.renamed', return_obj)
|
||||
}
|
||||
const svc_socketio = req.services.get('socketio');
|
||||
svc_socketio.send({ room: req.user.id }, 'item.renamed', return_obj);
|
||||
|
||||
return res.send(return_obj);
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ const { AdvancedBase } = require("@heyputer/putility");
|
||||
*/
|
||||
class EngPortalService extends AdvancedBase {
|
||||
static MODULES = {
|
||||
socketio: require('../socketio.js'),
|
||||
uuidv4: require('uuid').v4,
|
||||
};
|
||||
|
||||
|
@ -17,17 +17,10 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
const { AdvancedBase } = require("@heyputer/putility");
|
||||
|
||||
class WSPushService extends AdvancedBase {
|
||||
static MODULES = {
|
||||
socketio: require('../socketio.js'),
|
||||
}
|
||||
|
||||
constructor ({ services }) {
|
||||
super();
|
||||
this.log = services.get('log-service').create('WSPushService');
|
||||
this.svc_event = services.get('event');
|
||||
const BaseService = require("./BaseService");
|
||||
class WSPushService extends BaseService {
|
||||
async _init () {
|
||||
this.svc_event = this.services.get('event');
|
||||
|
||||
this.svc_event.on('fs.create.*', this._on_fs_create.bind(this));
|
||||
this.svc_event.on('fs.write.*', this._on_fs_update.bind(this));
|
||||
@ -50,7 +43,6 @@ class WSPushService extends AdvancedBase {
|
||||
*/
|
||||
async _on_fs_create (key, data) {
|
||||
const { node, context } = data;
|
||||
const { socketio } = this.modules;
|
||||
|
||||
const metadata = {
|
||||
from_new_service: true,
|
||||
@ -111,7 +103,6 @@ class WSPushService extends AdvancedBase {
|
||||
*/
|
||||
async _on_fs_update (key, data) {
|
||||
const { node, context } = data;
|
||||
const { socketio } = this.modules;
|
||||
|
||||
const metadata = {
|
||||
from_new_service: true,
|
||||
@ -177,7 +168,6 @@ class WSPushService extends AdvancedBase {
|
||||
*/
|
||||
async _on_fs_move (key, data) {
|
||||
const { moved, old_path, context } = data;
|
||||
const { socketio } = this.modules;
|
||||
|
||||
const metadata = {
|
||||
from_new_service: true,
|
||||
@ -235,7 +225,6 @@ class WSPushService extends AdvancedBase {
|
||||
*/
|
||||
async _on_fs_pending (key, data) {
|
||||
const { fsentry, context } = data;
|
||||
const { socketio } = this.modules;
|
||||
|
||||
const metadata = {
|
||||
from_new_service: true,
|
||||
@ -292,7 +281,6 @@ class WSPushService extends AdvancedBase {
|
||||
*/
|
||||
async _on_upload_progress (key, data) {
|
||||
this.log.info('got upload progress event');
|
||||
const { socketio } = this.modules;
|
||||
const { upload_tracker, context, meta } = data;
|
||||
|
||||
const metadata = {
|
||||
@ -320,25 +308,23 @@ class WSPushService extends AdvancedBase {
|
||||
}
|
||||
|
||||
this.log.info('socket id: ' + socket_id);
|
||||
|
||||
const io = socketio.getio()
|
||||
.sockets.sockets
|
||||
.get(socket_id);
|
||||
|
||||
// socket disconnected; that's allowed
|
||||
if ( ! io ) return;
|
||||
|
||||
const svc_socketio = context.get('services').get('socketio');
|
||||
if ( ! svc_socketio.has({ socket: socket_id }) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ws_event_name = metadata.call_it_download
|
||||
? 'download.progress' : 'upload.progress' ;
|
||||
|
||||
upload_tracker.sub(delta => {
|
||||
this.log.info('emitting progress event');
|
||||
io.emit(ws_event_name, {
|
||||
svc_socketio.send({ socket: socket_id }, ws_event_name, {
|
||||
...metadata,
|
||||
total: upload_tracker.total_,
|
||||
loaded: upload_tracker.progress_,
|
||||
loaded_diff: delta,
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@ -357,16 +343,13 @@ class WSPushService extends AdvancedBase {
|
||||
async _on_outer_gui (key, { user_id_list, response }, meta) {
|
||||
key = key.slice('outer.gui.'.length);
|
||||
|
||||
const { socketio } = this.modules;
|
||||
|
||||
const io = socketio.getio();
|
||||
const svc_socketio = this.services.get('socketio');
|
||||
|
||||
for ( const user_id of user_id_list ) {
|
||||
const room = io.sockets.adapter.rooms.get(user_id);
|
||||
if ( ! room || room.size <= 0 ) {
|
||||
if ( ! svc_socketio.has({ room: user_id }) ) {
|
||||
continue;
|
||||
}
|
||||
io.to(user_id).emit(key, response);
|
||||
svc_socketio.send({ room: user_id }, key, response);
|
||||
this.svc_event.emit(`sent-to-user.${key}`, {
|
||||
user_id,
|
||||
response,
|
||||
|
@ -25,11 +25,6 @@ const { UserActorType } = require("../auth/Actor");
|
||||
const { Endpoint } = require("../../util/expressutil");
|
||||
const APIError = require("../../api/APIError.js");
|
||||
|
||||
/**
|
||||
* This service registers endpoints that are protected by password authentication,
|
||||
* excluding login. These endpoints are typically for actions that affect
|
||||
* security settings on the user's account.
|
||||
*/
|
||||
/**
|
||||
* @class UserProtectedEndpointsService
|
||||
* @extends BaseService
|
||||
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
let io;
|
||||
module.exports = {
|
||||
init: function(server) {
|
||||
// start socket.io server and cache io value
|
||||
io = require('socket.io')(server, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
});
|
||||
// io.origins('*:*');
|
||||
return io;
|
||||
},
|
||||
getio: function() {
|
||||
// return previously cached value
|
||||
if (!io) {
|
||||
throw new Error("must call .init(server) before you can call .getio()");
|
||||
}
|
||||
return io;
|
||||
}
|
||||
}
|
@ -80,7 +80,7 @@ if ( ! import.meta.filename ) {
|
||||
const main = async () => {
|
||||
const {
|
||||
Kernel,
|
||||
CoreModule,
|
||||
EssentialModules,
|
||||
DatabaseModule,
|
||||
LocalDiskStorageModule,
|
||||
SelfHostedModule,
|
||||
@ -92,7 +92,9 @@ const main = async () => {
|
||||
const k = new Kernel({
|
||||
entry_path: import.meta.filename
|
||||
});
|
||||
k.add_module(new CoreModule());
|
||||
for ( const mod of EssentialModules ) {
|
||||
k.add_module(new mod());
|
||||
}
|
||||
k.add_module(new DatabaseModule());
|
||||
k.add_module(new LocalDiskStorageModule());
|
||||
k.add_module(new SelfHostedModule());
|
||||
|
Loading…
Reference in New Issue
Block a user