Add runner ci (test)
This commit is contained in:
Binary file not shown.
BIN
server/data/metoyou.sqlite_old
Normal file
BIN
server/data/metoyou.sqlite_old
Normal file
Binary file not shown.
@@ -3,7 +3,9 @@
|
||||
"version": "1.0.0",
|
||||
"description": "Signaling server for MetoYou P2P chat application",
|
||||
"main": "dist/index.js",
|
||||
"bin": "dist/index.js",
|
||||
"scripts": {
|
||||
"prebuild": "node ../tools/sync-server-build-version.js",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "ts-node-dev --respawn src/index.ts"
|
||||
@@ -27,5 +29,13 @@
|
||||
"@types/ws": "^8.5.8",
|
||||
"ts-node-dev": "^2.0.0",
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"pkg": {
|
||||
"assets": [
|
||||
"node_modules/ansis/**/*"
|
||||
],
|
||||
"scripts": [
|
||||
"dist/**/*.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { resolveRuntimePath } from '../runtime-paths';
|
||||
|
||||
export interface ServerVariablesConfig {
|
||||
klipyApiKey: string;
|
||||
releaseManifestUrl: string;
|
||||
}
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const DATA_DIR = resolveRuntimePath('data');
|
||||
const VARIABLES_FILE = path.join(DATA_DIR, 'variables.json');
|
||||
|
||||
function normalizeKlipyApiKey(value: unknown): string {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDataSource } from '../db';
|
||||
import { getDataSource } from '../db/database';
|
||||
import {
|
||||
CommandType,
|
||||
QueryType,
|
||||
|
||||
@@ -6,12 +6,27 @@ import {
|
||||
ServerEntity,
|
||||
JoinRequestEntity
|
||||
} from '../entities';
|
||||
import { serverMigrations } from '../migrations';
|
||||
import { findExistingPath, resolveRuntimePath } from '../runtime-paths';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const DATA_DIR = resolveRuntimePath('data');
|
||||
const DB_FILE = path.join(DATA_DIR, 'metoyou.sqlite');
|
||||
|
||||
let applicationDataSource: DataSource | undefined;
|
||||
|
||||
function resolveSqlJsConfig(): { locateFile: (file: string) => string } {
|
||||
return {
|
||||
locateFile: (file) => {
|
||||
const bundledBinaryPath = path.join(__dirname, '..', '..', 'node_modules', 'sql.js', 'dist', file);
|
||||
|
||||
return findExistingPath(
|
||||
resolveRuntimePath(file),
|
||||
bundledBinaryPath
|
||||
) ?? bundledBinaryPath;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getDataSource(): DataSource {
|
||||
if (!applicationDataSource?.isInitialized) {
|
||||
throw new Error('DataSource not initialised');
|
||||
@@ -29,22 +44,34 @@ export async function initDatabase(): Promise<void> {
|
||||
if (fs.existsSync(DB_FILE))
|
||||
database = fs.readFileSync(DB_FILE);
|
||||
|
||||
applicationDataSource = new DataSource({
|
||||
type: 'sqljs',
|
||||
database,
|
||||
entities: [
|
||||
AuthUserEntity,
|
||||
ServerEntity,
|
||||
JoinRequestEntity
|
||||
],
|
||||
migrations: [path.join(__dirname, '..', 'migrations', '*.js'), path.join(__dirname, '..', 'migrations', '*.ts')],
|
||||
synchronize: false,
|
||||
logging: false,
|
||||
autoSave: true,
|
||||
location: DB_FILE
|
||||
});
|
||||
try {
|
||||
applicationDataSource = new DataSource({
|
||||
type: 'sqljs',
|
||||
database,
|
||||
entities: [
|
||||
AuthUserEntity,
|
||||
ServerEntity,
|
||||
JoinRequestEntity
|
||||
],
|
||||
migrations: serverMigrations,
|
||||
synchronize: false,
|
||||
logging: false,
|
||||
autoSave: true,
|
||||
location: DB_FILE,
|
||||
sqlJsConfig: resolveSqlJsConfig()
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[DB] Failed to configure the sql.js data source', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
await applicationDataSource.initialize();
|
||||
} catch (error) {
|
||||
console.error('[DB] Failed to initialise the sql.js data source', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
await applicationDataSource.initialize();
|
||||
console.log('[DB] Connection initialised at:', DB_FILE);
|
||||
|
||||
await applicationDataSource.runMigrations();
|
||||
|
||||
1
server/src/generated/build-version.ts
Normal file
1
server/src/generated/build-version.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const SERVER_BUILD_VERSION = "1.0.0";
|
||||
@@ -4,11 +4,15 @@ import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { createServer as createHttpServer } from 'http';
|
||||
import { createServer as createHttpsServer } from 'https';
|
||||
import {
|
||||
resolveCertificateDirectory,
|
||||
resolveEnvFilePath
|
||||
} from './runtime-paths';
|
||||
|
||||
// Load .env from project root (one level up from server/)
|
||||
dotenv.config({ path: path.resolve(__dirname, '..', '..', '.env') });
|
||||
dotenv.config({ path: resolveEnvFilePath() });
|
||||
|
||||
import { initDatabase } from './db';
|
||||
import { initDatabase } from './db/database';
|
||||
import { deleteStaleJoinRequests } from './cqrs';
|
||||
import { createApp } from './app';
|
||||
import {
|
||||
@@ -23,7 +27,7 @@ const PORT = process.env.PORT || 3001;
|
||||
|
||||
function buildServer(app: ReturnType<typeof createApp>) {
|
||||
if (USE_SSL) {
|
||||
const certDir = path.resolve(__dirname, '..', '..', '.certs');
|
||||
const certDir = resolveCertificateDirectory();
|
||||
const certFile = path.join(certDir, 'localhost.crt');
|
||||
const keyFile = path.join(certDir, 'localhost.key');
|
||||
|
||||
|
||||
3
server/src/migrations/index.ts
Normal file
3
server/src/migrations/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { InitialSchema1000000000000 } from './1000000000000-InitialSchema';
|
||||
|
||||
export const serverMigrations = [InitialSchema1000000000000];
|
||||
@@ -1,24 +1,15 @@
|
||||
import { Router } from 'express';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { getAllPublicServers } from '../cqrs';
|
||||
import { getReleaseManifestUrl } from '../config/variables';
|
||||
import { SERVER_BUILD_VERSION } from '../generated/build-version';
|
||||
import { connectedUsers } from '../websocket/state';
|
||||
|
||||
const router = Router();
|
||||
|
||||
function getServerProjectVersion(): string {
|
||||
try {
|
||||
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
||||
const rawContents = fs.readFileSync(packageJsonPath, 'utf8');
|
||||
const parsed = JSON.parse(rawContents) as { version?: unknown };
|
||||
|
||||
return typeof parsed.version === 'string' && parsed.version.trim().length > 0
|
||||
? parsed.version.trim()
|
||||
: '0.0.0';
|
||||
} catch {
|
||||
return '0.0.0';
|
||||
}
|
||||
return typeof process.env.METOYOU_SERVER_VERSION === 'string' && process.env.METOYOU_SERVER_VERSION.trim().length > 0
|
||||
? process.env.METOYOU_SERVER_VERSION.trim()
|
||||
: SERVER_BUILD_VERSION;
|
||||
}
|
||||
|
||||
router.get('/health', async (_req, res) => {
|
||||
|
||||
58
server/src/runtime-paths.ts
Normal file
58
server/src/runtime-paths.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
type PackagedProcess = NodeJS.Process & { pkg?: unknown };
|
||||
|
||||
function uniquePaths(paths: string[]): string[] {
|
||||
return [...new Set(paths.map((candidate) => path.resolve(candidate)))];
|
||||
}
|
||||
|
||||
export function isPackagedRuntime(): boolean {
|
||||
return Boolean((process as PackagedProcess).pkg);
|
||||
}
|
||||
|
||||
export function getRuntimeBaseDir(): string {
|
||||
return isPackagedRuntime()
|
||||
? path.dirname(process.execPath)
|
||||
: process.cwd();
|
||||
}
|
||||
|
||||
export function resolveRuntimePath(...segments: string[]): string {
|
||||
return path.join(getRuntimeBaseDir(), ...segments);
|
||||
}
|
||||
|
||||
export function resolveProjectRootPath(...segments: string[]): string {
|
||||
return path.resolve(__dirname, '..', '..', ...segments);
|
||||
}
|
||||
|
||||
export function findExistingPath(...candidates: string[]): string | null {
|
||||
for (const candidate of uniquePaths(candidates)) {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resolveEnvFilePath(): string {
|
||||
if (isPackagedRuntime()) {
|
||||
return resolveRuntimePath('.env');
|
||||
}
|
||||
|
||||
return findExistingPath(
|
||||
resolveRuntimePath('.env'),
|
||||
resolveProjectRootPath('.env')
|
||||
) ?? resolveProjectRootPath('.env');
|
||||
}
|
||||
|
||||
export function resolveCertificateDirectory(): string {
|
||||
if (isPackagedRuntime()) {
|
||||
return resolveRuntimePath('.certs');
|
||||
}
|
||||
|
||||
return findExistingPath(
|
||||
resolveRuntimePath('.certs'),
|
||||
resolveProjectRootPath('.certs')
|
||||
) ?? resolveRuntimePath('.certs');
|
||||
}
|
||||
Reference in New Issue
Block a user