Files
tankwar_proj/content-security-service/index.js
T
jakciehan d263c7bf48 Merge feature/add_skin into master: resolve all conflicts
- GameGlobal.js: keep upstream SERVER_URL with /ws suffix
- en.js/zh.js: merge both settings.nickname and settings.profile keys
- SettingsScene.js: keep both nickname row and profile button
- server/index.js: merge express app + content security proxy with
  noServer WebSocket mode and path validation
- Add .gitignore for node_modules and .codebuddy
2026-05-12 07:05:20 +08:00

141 lines
5.0 KiB
JavaScript

/**
* Content Security Microservice - Standalone Entry Point
*
* Independent content security service for UGC moderation.
* Shared by multiple mini-games via game_id tenant isolation.
*
* API Endpoints:
* POST /api/content/check-text - Text content security check
* POST /api/content/check-image - Image content security check
* GET /api/content/sensitive-words - Get sensitive word list
* GET /api/user/mute-status - Check if a user is muted
* GET /api/user/violation-summary - Get violation summary
* POST /api/content/report - Submit a content report
* GET /api/health - Health check
* GET /api/metrics - Service metrics
*/
const express = require('express');
const http = require('http');
const WechatTokenManager = require('./services/wechatTokenManager');
const AuditLogger = require('./services/auditLogger');
const { createContentSecurityRouter } = require('./services/contentSecurityRoutes');
const ViolationService = require('./services/violationService');
const ReportService = require('./services/reportService');
// ============================================================
// Configuration
// ============================================================
const PORT = process.env.PORT || 3000;
const HOST = process.env.HOST || '0.0.0.0';
const DEFAULT_GAME_ID = process.env.DEFAULT_GAME_ID || 'tankwar';
// ============================================================
// Express App
// ============================================================
const app = express();
// Parse JSON bodies
app.use(express.json({ limit: '2mb' }));
// Request logging middleware
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
const game_id = req.headers['x-game-id'] || req.body?.game_id || DEFAULT_GAME_ID;
console.log(`[HTTP] ${req.method} ${req.url} ${res.statusCode} ${duration}ms game_id=${game_id}`);
});
next();
});
// ============================================================
// Health Check
// ============================================================
app.get('/api/health', (req, res) => {
res.json({
status: 'ok',
service: 'content-security',
version: '1.0.0',
timestamp: Date.now(),
tokenManagerAvailable: tokenManager ? tokenManager.isAvailable() : false,
});
});
// ============================================================
// Metrics Endpoint
// ============================================================
app.get('/api/metrics', (req, res) => {
res.json({
uptime: process.uptime(),
memory: process.memoryUsage(),
tokenManagerAvailable: tokenManager ? tokenManager.isAvailable() : false,
activeViolations: violationService ? violationService._records.size : 0,
activeMutes: violationService ? violationService._mutes.size : 0,
activeReports: reportService ? reportService._reports.size : 0,
timestamp: Date.now(),
});
});
// ============================================================
// Initialize Services
// ============================================================
const auditLogger = new AuditLogger();
const tokenManager = new WechatTokenManager();
const violationService = new ViolationService({ logger: auditLogger });
const reportService = new ReportService({ logger: auditLogger, violationService });
// Mount content security routes
const contentSecurityRouter = createContentSecurityRouter({
tokenManager,
logger: auditLogger,
violationService,
reportService,
});
app.use('/api/content', contentSecurityRouter);
// ============================================================
// Start Server
// ============================================================
const server = http.createServer(app);
server.listen(PORT, HOST, async () => {
console.log(`[Content Security Service] Running on ${HOST}:${PORT}`);
console.log(`[Content Security Service] Default game_id: ${DEFAULT_GAME_ID}`);
console.log(`[Content Security Service] API URL: http://${HOST}:${PORT}`);
// Initialize token manager
const success = await tokenManager.init();
if (success) {
console.log('[Content Security Service] WeChat token manager initialized successfully');
} else {
console.warn('[Content Security Service] WeChat token manager unavailable (token fetch failed)');
console.warn('[Content Security Service] Content checks will be rejected until token is obtained');
}
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('[Content Security Service] SIGTERM received, shutting down gracefully...');
tokenManager.destroy();
auditLogger.destroy();
violationService.destroy();
server.close(() => {
console.log('[Content Security Service] Server closed');
process.exit(0);
});
});
process.on('SIGINT', () => {
console.log('[Content Security Service] SIGINT received, shutting down gracefully...');
tokenManager.destroy();
auditLogger.destroy();
violationService.destroy();
server.close(() => {
console.log('[Content Security Service] Server closed');
process.exit(0);
});
});
module.exports = { app, server };