Skip to content

Commit

Permalink
Merge pull request #380 from n0th1ng-else/server-router
Browse files Browse the repository at this point in the history
fix(server): Continue refactoring the server model
  • Loading branch information
n0th1ng-else authored Mar 29, 2024
2 parents 1c8ad2b + 3a837b2 commit fb9ff8c
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 79 deletions.
8 changes: 7 additions & 1 deletion src/memory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { Logger } from "../logger/index.js";

const logger = new Logger("memory");

export const SIZE_UNIT = 1024;

export const getMB = (mb: number): number => {
return SIZE_UNIT * SIZE_UNIT * mb;
};

export const printCurrentMemoryStat = (
limit?: number,
offset = 15,
Expand Down Expand Up @@ -52,6 +58,6 @@ const getMemoryUsageMb = (): NodeJS.MemoryUsage => {
};

const getMb = (stat: number): number => {
const mb = 1024 * 1024;
const mb = getMB(1);
return Math.ceil(stat / mb);
};
37 changes: 35 additions & 2 deletions src/server/bot-server-base.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,57 @@
import { UptimeDaemon } from "./uptime.js";
import { Logger } from "../logger/index.js";
import { sSuffix } from "../text/utils.js";
import type { BotServerModelBase, ServerStatCore } from "./types.js";
import type { TelegramBotModel } from "../telegram/bot.js";
import type { HttpsOptions } from "../../certs/index.js";

const logger = new Logger("server");

export class BotServerBase {
export abstract class BotServerBase<ServerType> implements BotServerModelBase {
protected readonly app: ServerType;
protected readonly uptimeDaemon: UptimeDaemon;
protected threadId = 0;
protected stat: ServerStatCore | null = null;
protected selfUrl = "";
protected bots: TelegramBotModel[] = [];
protected isIdle = true;
protected readonly isHttps: boolean;

constructor(
protected constructor(
protected readonly serverName: string,
protected readonly port: number,
protected readonly version: string,
protected readonly webhookDoNotWait: boolean,
protected readonly httpsOptions?: HttpsOptions,
) {
logger.info(`Initializing ${Logger.y(this.serverName)} bot server`);

this.isHttps = Boolean(httpsOptions);
this.uptimeDaemon = new UptimeDaemon(version);
this.app = this.getServerInstance();
}

public setThreadId(threadId: number): this {
this.threadId = threadId;
return this;
}

public setStat(stat: ServerStatCore): this {
this.stat = stat;
this.uptimeDaemon.setStat(stat);
return this;
}

public setSelfUrl(url: string): this {
this.selfUrl = url;
return this;
}

protected abstract getServerInstance(): ServerType;

protected setBots(bots: TelegramBotModel[]): this {
this.bots = bots;
logger.info(`Requested ${Logger.y(sSuffix("bot", bots.length))} to set up`);
return this;
}
}
61 changes: 22 additions & 39 deletions src/server/bot-server-new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,30 @@ import { sSuffix } from "../text/utils.js";
import { isFileExist, readFile } from "../files/index.js";
import { flattenPromise } from "../common/helpers.js";
import { TgUpdateSchema } from "../telegram/api/types.js";
import { getMB } from "../memory/index.js";
import {
type BotServerModel,
type HealthDto,
HealthModel,
type ServerStatCore,
type NotFoundDto,
HealthModel,
} from "./types.js";
import type { VoidPromise } from "../common/types.js";
import type { HttpsOptions } from "../../certs/index.js";
import type { TelegramBotModel } from "../telegram/bot.js";

const logger = new Logger("server");

export class BotServerNew extends BotServerBase implements BotServerModel {
private readonly app: FastifyInstance;
private readonly isHttps: boolean;

private stat: ServerStatCore | null = null;
private bots: TelegramBotModel[] = [];
private isIdle = true;
private selfUrl = "";

export class BotServerNew
extends BotServerBase<FastifyInstance>
implements BotServerModel
{
constructor(
port: number,
version: string,
private readonly webhookDoNotWait: boolean,
webhookDoNotWait: boolean,
httpsOptions?: HttpsOptions,
) {
super("Fastify", port, version);

this.isHttps = Boolean(httpsOptions);

const httpsOpts = this.isHttps
? {
https: httpsOptions,
}
: {};

this.app = fastify({
...httpsOpts,
bodyLimit: 1024 * 1024 * 100, // 100 MB
});
super("Fastify", port, version, webhookDoNotWait, httpsOptions);

initSentryNew();
trackAPIHandlersNew(this.app);
Expand Down Expand Up @@ -139,8 +121,7 @@ export class BotServerNew extends BotServerBase implements BotServerModel {
}

public setBots(bots: TelegramBotModel[] = []): this {
this.bots = bots;
logger.info(`Requested ${Logger.y(sSuffix("bot", bots.length))} to set up`);
super.setBots(bots);

bots.forEach((bot) => {
logger.warn(`Setting up a handler for ${Logger.y(bot.getPath())}`);
Expand Down Expand Up @@ -220,17 +201,6 @@ export class BotServerNew extends BotServerBase implements BotServerModel {
return this;
}

public setSelfUrl(url: string): this {
this.selfUrl = url;
return this;
}

public setStat(stat: ServerStatCore): this {
this.stat = stat;
this.uptimeDaemon.setStat(stat);
return this;
}

public start(): Promise<VoidPromise> {
logger.info(
`Starting ${Logger.y(sSuffix("http", this.isHttps))} ${this.selfUrl} server`,
Expand Down Expand Up @@ -337,4 +307,17 @@ export class BotServerNew extends BotServerBase implements BotServerModel {
return [400, status.getDto()];
}
}

protected getServerInstance(): FastifyInstance {
const httpsOpts = this.isHttps
? {
https: this.httpsOptions,
}
: {};

return fastify({
...httpsOpts,
bodyLimit: getMB(100), // 100 MB
});
}
}
47 changes: 18 additions & 29 deletions src/server/bot-server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createServer as createHttp } from "node:http";
import { createServer as createHttps } from "node:https";
import express, { type Response } from "express";
import express, { type Response, type Express } from "express";
import { Logger } from "../logger/index.js";
import { sSuffix } from "../text/utils.js";
import { BotServerBase } from "./bot-server-base.js";
Expand All @@ -12,44 +12,39 @@ import { initSentry, trackAPIHandlers } from "../monitoring/sentry.js";
import {
type BotServerModel,
type HealthDto,
HealthModel,
type ServerStatCore,
HealthModel,
} from "./types.js";
import type { TelegramBotModel } from "../telegram/bot.js";
import type { HttpsOptions } from "../../certs/index.js";
import type { VoidPromise } from "../common/types.js";

const logger = new Logger("server");

export class BotServer extends BotServerBase implements BotServerModel {
private readonly app = express();

private stat: ServerStatCore | null = null;
private bots: TelegramBotModel[] = [];
private isIdle = true;
private selfUrl = "";

export class BotServer
extends BotServerBase<Express>
implements BotServerModel
{
constructor(
port: number,
version: string,
private readonly webhookDoNotWait: boolean,
private readonly httpsOptions?: HttpsOptions,
webhookDoNotWait: boolean,
httpsOptions?: HttpsOptions,
) {
super("ExpressJS", port, version);
super("ExpressJS", port, version, webhookDoNotWait, httpsOptions);

initSentry(this.app);
trackAPIHandlers(this.app);
this.app.use(express.json());

this.app.use("/static", express.static("assets/v2"));

const statusHandler = (
res: Response<HealthDto>,
db: ServerStatCore | null,
): void => {
const isHttps = Boolean(this.httpsOptions);
const status = new HealthModel(
this.version,
isHttps,
this.isHttps,
this.threadId,
this.serverName,
);
Expand Down Expand Up @@ -98,15 +93,8 @@ export class BotServer extends BotServerBase implements BotServerModel {
});
}

public setStat(stat: ServerStatCore): this {
this.stat = stat;
this.uptimeDaemon.setStat(stat);
return this;
}

public setBots(bots: TelegramBotModel[] = []): this {
this.bots = bots;
logger.info(`Requested ${Logger.y(sSuffix("bot", bots.length))} to set up`);
super.setBots(bots);

bots.forEach((bot) => {
logger.warn(`Setting up a handler for ${Logger.y(bot.getPath())}`);
Expand Down Expand Up @@ -195,11 +183,6 @@ export class BotServer extends BotServerBase implements BotServerModel {
return this;
}

public setSelfUrl(url: string): this {
this.selfUrl = url;
return this;
}

public start(): Promise<VoidPromise> {
const isHttps = Boolean(this.httpsOptions);
logger.info(`Starting ${Logger.y(sSuffix("http", isHttps))} server`);
Expand Down Expand Up @@ -283,4 +266,10 @@ export class BotServer extends BotServerBase implements BotServerModel {
.then(flattenPromise);
});
}

protected getServerInstance(): Express {
const app = express();
app.use(express.json());
return app;
}
}
3 changes: 2 additions & 1 deletion src/server/static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
import Fastify, { type FastifyInstance } from "fastify";
import { httpsOptions } from "../../certs/index.js";
import { enableSSL } from "../env.js";
import { getMB } from "../memory/index.js";

export type FastifyStaticRoute<Body = void, Query = void, Reply = void> = {
Body: Body;
Expand All @@ -28,7 +29,7 @@ export const initStaticServer = (

const app = Fastify({
...httpsOpts,
bodyLimit: 1024 * 1024 * 100, // 100 MB
bodyLimit: getMB(100), // 100 MB
});

app.get("/", async (_, res) => {
Expand Down
10 changes: 7 additions & 3 deletions src/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ import type { getDb } from "../db/index.js";
export type ServerStatCore = ReturnType<typeof getDb>;

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export interface BotServerModel {
export interface BotServerModel extends BotServerModelBase {
start(): Promise<VoidPromise | VoidFunction>;
applyHostLocation(launchDelay?: number): Promise<void>;
triggerDaemon(
nextReplicaUrl: string,
lifecycleInterval: number,
timeoutMs: number,
): void;
setSelfUrl(url: string): this;
setBots(bots: TelegramBotModel[]): this;
setStat(stat: ServerStatCore): this;
}

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export interface BotServerModelBase {
setThreadId(threadId: number): this;
setStat(stat: ServerStatCore): this;
setSelfUrl(url: string): this;
}

export type NotFoundDto = {
Expand Down
5 changes: 3 additions & 2 deletions src/storage/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { resolve as resolvePath } from "node:path";
import { readdirSync, statSync } from "node:fs";
import { Logger } from "../logger/index.js";
import { getMB } from "../memory/index.js";

const logger = new Logger("storage");

export const printCurrentStorageUsage = (dir: string): Promise<void> => {
export const printCurrentStorageUsage = async (dir: string): Promise<void> => {
return Promise.resolve().then(() => {
try {
const folder = resolvePath(process.cwd(), dir);
Expand All @@ -15,7 +16,7 @@ export const printCurrentStorageUsage = (dir: string): Promise<void> => {
(sum, file) => sum + statSync(resolvePath(folder, file)).size,
0,
);
const cacheSizeMBytes = Math.ceil(cacheSizeBytes / (1024 * 1000));
const cacheSizeMBytes = Math.ceil(cacheSizeBytes / getMB(1));
const size =
cacheSizeMBytes < 1 ? "almost empty" : `[size=${cacheSizeMBytes}Mb]`;
const list = files.length ? `[files=${files.join(",")}]` : "no files";
Expand Down
5 changes: 3 additions & 2 deletions src/telegram/actions/donate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LabelId } from "../../text/types.js";
import { Logger } from "../../logger/index.js";
import { collectAnalytics } from "../../analytics/index.js";
import { BOT_LOGO, donationLevels } from "../../const.js";
import { SIZE_UNIT } from "../../memory/index.js";
import { toCurrency } from "../../text/utils.js";
import type { TgInlineKeyboardButton, TgMessage } from "../api/types.js";
import type { PaymentService } from "../../donate/types.js";
Expand Down Expand Up @@ -218,8 +219,8 @@ export class DonateAction extends GenericAction {
payload: getDonationDtoString(donationId, chatId, prefix.id),
photo: {
url: BOT_LOGO,
height: 1024,
width: 1024,
height: SIZE_UNIT,
width: SIZE_UNIT,
},
forumThreadId,
};
Expand Down

0 comments on commit fb9ff8c

Please sign in to comment.