2024-05-28 18:45:34 +02:00
|
|
|
import * as plugins from './plugins.js';
|
|
|
|
|
import * as paths from './paths.js';
|
|
|
|
|
import { Cloudly } from './classes.cloudly.js';
|
2024-05-30 22:49:39 +02:00
|
|
|
import { logger } from './logger.js';
|
2024-04-20 12:21:41 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* handles incoming requests from CI to deploy new versions of apps
|
|
|
|
|
*/
|
|
|
|
|
export class CloudlyServer {
|
|
|
|
|
/**
|
|
|
|
|
* a reference to the cloudly instance
|
|
|
|
|
*/
|
2024-06-13 09:36:02 +02:00
|
|
|
public cloudlyRef: Cloudly;
|
2026-05-08 13:56:20 +00:00
|
|
|
public additionalHandlers: plugins.typedserver.IRouteHandler[] = [];
|
2024-04-20 12:21:41 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* the smartexpress server handling the actual requests
|
|
|
|
|
*/
|
2026-05-08 13:56:20 +00:00
|
|
|
public typedServer!: plugins.typedserver.TypedServer;
|
|
|
|
|
public typedsocketServer!: plugins.typedsocket.TypedSocket;
|
2024-04-20 12:21:41 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* typedrouter
|
|
|
|
|
* @param cloudlyArg
|
|
|
|
|
*/
|
|
|
|
|
public typedrouter = new plugins.typedrequest.TypedRouter();
|
|
|
|
|
|
|
|
|
|
constructor(cloudlyArg: Cloudly) {
|
|
|
|
|
this.cloudlyRef = cloudlyArg;
|
|
|
|
|
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =========
|
|
|
|
|
// LIFECYCLE
|
|
|
|
|
// =========
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* init the reception instance
|
|
|
|
|
*/
|
|
|
|
|
public async start() {
|
2024-06-13 09:36:02 +02:00
|
|
|
logger.log('info', `cloudly domain is ${this.cloudlyRef.config.data.publicUrl}`);
|
2026-05-08 13:56:20 +00:00
|
|
|
let sslCert: plugins.smartacme.Cert | undefined;
|
2024-04-20 12:21:41 +02:00
|
|
|
|
|
|
|
|
if (this.cloudlyRef.config.data.sslMode === 'letsencrypt') {
|
2024-06-13 09:36:02 +02:00
|
|
|
logger.log('info', `Using letsencrypt for ssl mode. Trying to obtain a certificate...`);
|
|
|
|
|
logger.log('info', `This might take 10 minutes...`);
|
2024-04-20 12:21:41 +02:00
|
|
|
sslCert = await this.cloudlyRef.letsencryptConnector.getCertificateForDomain(
|
2026-05-08 13:56:20 +00:00
|
|
|
this.cloudlyRef.config.data.publicUrl!,
|
2024-04-20 12:21:41 +02:00
|
|
|
);
|
2024-06-13 09:36:02 +02:00
|
|
|
logger.log(
|
|
|
|
|
'success',
|
2024-10-27 19:50:39 +01:00
|
|
|
`Successfully obtained certificate for cloudly domain ${this.cloudlyRef.config.data.publicUrl}`,
|
2024-06-13 09:36:02 +02:00
|
|
|
);
|
2024-04-20 12:21:41 +02:00
|
|
|
} else if (this.cloudlyRef.config.data.sslMode === 'external') {
|
2024-06-13 09:36:02 +02:00
|
|
|
logger.log(
|
|
|
|
|
'info',
|
2024-10-27 19:50:39 +01:00
|
|
|
`Using external certificate for ssl mode, meaning cloudly is not in charge of ssl termination.`,
|
2024-06-13 09:36:02 +02:00
|
|
|
);
|
2024-04-20 12:21:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// server
|
|
|
|
|
this.typedServer = new plugins.typedserver.TypedServer({
|
|
|
|
|
cors: true,
|
|
|
|
|
forceSsl: false,
|
2024-06-13 09:36:02 +02:00
|
|
|
port: this.cloudlyRef.config.data.publicPort,
|
|
|
|
|
...(sslCert
|
|
|
|
|
? {
|
|
|
|
|
privateKey: sslCert.privateKey,
|
|
|
|
|
publicKey: sslCert.publicKey,
|
|
|
|
|
}
|
|
|
|
|
: {}),
|
2024-04-20 12:21:41 +02:00
|
|
|
injectReload: true,
|
|
|
|
|
serveDir: paths.distServeDir,
|
|
|
|
|
watch: true,
|
2026-05-08 13:56:20 +00:00
|
|
|
compression: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
algorithms: ['gzip'],
|
|
|
|
|
},
|
2024-04-20 12:21:41 +02:00
|
|
|
});
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedsocketServer = this.typedServer.typedsocket;
|
2024-04-20 12:21:41 +02:00
|
|
|
this.typedServer.typedrouter.addTypedRouter(this.typedrouter);
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedServer.addRoute(
|
2026-04-28 15:23:51 +00:00
|
|
|
'/v2',
|
2026-05-08 13:56:20 +00:00
|
|
|
'ALL',
|
|
|
|
|
async (ctx) => this.cloudlyRef.registryManager.handleHttpRequest(ctx),
|
2026-04-28 15:23:51 +00:00
|
|
|
);
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedServer.addRoute(
|
|
|
|
|
'/v2/*',
|
|
|
|
|
'ALL',
|
|
|
|
|
async (ctx) => this.cloudlyRef.registryManager.handleHttpRequest(ctx),
|
2026-04-28 15:23:51 +00:00
|
|
|
);
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedServer.addRoute(
|
2024-06-13 09:36:02 +02:00
|
|
|
'/curlfresh/:scriptname',
|
2026-05-08 13:56:20 +00:00
|
|
|
'ALL',
|
|
|
|
|
async (ctx) => this.cloudlyRef.nodeManager.curlfreshInstance.handleRequest(ctx),
|
2024-06-13 09:36:02 +02:00
|
|
|
);
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedServer.addRoute(
|
2026-05-07 15:53:16 +00:00
|
|
|
'/baseos/v1/nodes/register',
|
2026-05-08 13:56:20 +00:00
|
|
|
'POST',
|
|
|
|
|
async (ctx) => this.cloudlyRef.baseOsManager.handleRegisterHttpRequest(ctx),
|
2026-05-07 15:53:16 +00:00
|
|
|
);
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedServer.addRoute(
|
2026-05-07 15:53:16 +00:00
|
|
|
'/baseos/v1/nodes/heartbeat',
|
2026-05-08 13:56:20 +00:00
|
|
|
'POST',
|
|
|
|
|
async (ctx) => this.cloudlyRef.baseOsManager.handleHeartbeatHttpRequest(ctx),
|
2026-05-07 15:53:16 +00:00
|
|
|
);
|
2026-05-08 13:56:20 +00:00
|
|
|
this.typedServer.addRoute(
|
2026-05-07 17:44:31 +00:00
|
|
|
'/baseos/v1/images/:buildId/download',
|
2026-05-08 13:56:20 +00:00
|
|
|
'GET',
|
|
|
|
|
async (ctx) => this.cloudlyRef.baseOsManager.handleImageDownloadHttpRequest(ctx),
|
2026-05-07 17:44:31 +00:00
|
|
|
);
|
2024-04-20 12:21:41 +02:00
|
|
|
await this.typedServer.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* stop the reception instance
|
|
|
|
|
*/
|
|
|
|
|
public async stop() {
|
2026-05-08 13:56:20 +00:00
|
|
|
await this.typedServer?.stop();
|
2024-04-20 12:21:41 +02:00
|
|
|
}
|
|
|
|
|
}
|