@agentscope/studio
Version:
AgentScope Studio is a powerful local monitoring and visualization tool designed to provide real-time insights into your system's performance and behavior.
212 lines (211 loc) • 10 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const trpcExpress = __importStar(require("@trpc/server/adapters/express"));
const express_1 = __importDefault(require("express"));
const http_1 = require("http");
const opener_1 = __importDefault(require("opener"));
const path_1 = __importDefault(require("path"));
const portfinder_1 = __importDefault(require("portfinder"));
const config_1 = require("../../shared/src/config");
const banner_1 = require("../../shared/src/utils/banner");
const terminal_1 = require("../../shared/src/utils/terminal");
const database_1 = require("./database");
const grpc_server_1 = require("./otel/grpc-server");
const router_1 = __importDefault(require("./otel/router"));
const router_2 = require("./trpc/router");
const socket_1 = require("./trpc/socket");
function initializeServer() {
return __awaiter(this, void 0, void 0, function* () {
try {
// Initialize the configuration
const configManager = config_1.ConfigManager.getInstance();
const config = configManager.getConfig();
portfinder_1.default.basePort = config.port;
portfinder_1.default.highestPort = portfinder_1.default.basePort + 2000;
// Handle HTTP port
const availableHttpPort = yield portfinder_1.default.getPortPromise();
if (availableHttpPort !== config.port) {
console.log(`HTTP port ${config.port} is already in use.`);
// Check if running in interactive environment
const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
let useNewPort;
if (isInteractive) {
useNewPort = yield (0, terminal_1.promptUser)(`Would you like to start the HTTP server on port ${availableHttpPort} instead? (y/n): `);
}
else {
// Non-interactive mode: automatically use available port
console.log(`Automatically using available HTTP port ${availableHttpPort} (non-interactive mode)`);
useNewPort = true;
}
if (useNewPort) {
yield configManager.setPort(availableHttpPort);
console.log(`HTTP server will start on port ${availableHttpPort}`);
}
else {
console.log('Exiting...');
process.exit(1);
}
}
// Handle gRPC port
portfinder_1.default.basePort = config.otelGrpcPort;
portfinder_1.default.highestPort = portfinder_1.default.basePort + 2000;
const availableGrpcPort = yield portfinder_1.default.getPortPromise();
if (availableGrpcPort !== config.otelGrpcPort) {
console.log(`[OTEL gRPC] port ${config.otelGrpcPort} is already in use.`);
// Check if running in interactive environment
const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
let useNewPort;
if (isInteractive) {
useNewPort = yield (0, terminal_1.promptUser)(`Would you like to start the OTEL gRPC server on port ${availableGrpcPort} instead? (y/n): `);
}
else {
// Non-interactive mode: automatically use available port
console.log(`Automatically using available OTEL gRPC port ${availableGrpcPort} (non-interactive mode)`);
useNewPort = true;
}
if (useNewPort) {
yield configManager.setOtelGrpcPort(availableGrpcPort);
console.log(`OTEL gRPC server will start on port ${availableGrpcPort}`);
}
else {
console.log('Exiting...');
process.exit(1);
}
}
// Create APP instance
const app = (0, express_1.default)();
const httpServer = (0, http_1.createServer)(app);
// Initialize the database
yield (0, database_1.initializeDatabase)(config.database);
// Set TRPC router
app.use('/trpc', trpcExpress.createExpressMiddleware({
router: router_2.appRouter,
}));
app.use('/v1', express_1.default.raw({
type: [
'application/x-protobuf',
'application/vnd.google.protobuf',
'application/protobuf',
'application/octet-stream',
'application/json',
],
limit: '10mb',
}), router_1.default);
// Initialize SocketManager
socket_1.SocketManager.init(httpServer);
// Initialize and start OTEL gRPC server on a separate port
const actualGrpcPort = configManager.getConfig().otelGrpcPort;
const otelGrpcServer = new grpc_server_1.OtelGrpcServer();
try {
yield otelGrpcServer.start(actualGrpcPort);
}
catch (error) {
console.warn(`Failed to start OTEL gRPC server on port ${actualGrpcPort}, ` +
'traces will be received via HTTP endpoint /v1/traces:', error instanceof Error ? error.message : error);
}
// Serve static files in development mode
if (process.env.NODE_ENV === 'production') {
const publicPath = path_1.default.join(__dirname, '../../public');
app.use(express_1.default.static(publicPath));
app.use((req, res, next) => {
if (!req.path.startsWith('/trpc')) {
res.sendFile(path_1.default.join(publicPath, 'index.html'), {
dotfiles: 'allow',
});
}
else {
next();
}
});
}
httpServer.listen(configManager.getConfig().port, () => {
const actualPort = configManager.getConfig().port;
const config = configManager.getConfig();
const mode = (process.env.NODE_ENV || 'production');
// Display startup banner
(0, banner_1.displayBanner)(config_1.APP_INFO.name.replace('-', '\n'), config_1.APP_INFO.version, actualPort, actualGrpcPort, config.database.database, mode);
if (process.env.NODE_ENV === 'production') {
(0, opener_1.default)(`http://localhost:${actualPort}/home`);
}
});
return { httpServer, otelGrpcServer };
}
catch (error) {
console.error('Error initializing server:', error);
console.error('Error stack:', error.stack);
throw error;
}
});
}
// Set up the server and start listening
initializeServer()
.then(({ httpServer, otelGrpcServer }) => {
// Handle graceful shutdown
const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
console.debug('Closing Socket.IO connections');
socket_1.SocketManager.close();
console.debug('Stopping gRPC server');
try {
yield otelGrpcServer.stop();
}
catch (error) {
console.error('Error stopping gRPC server:', error);
otelGrpcServer.forceShutdown();
}
console.debug('Closing HTTP server');
httpServer.close(() => {
console.debug('HTTP server closed');
process.exit(0);
});
});
process.on('SIGTERM', cleanup);
process.on('SIGINT', cleanup);
})
.catch(() => {
process.exit(1);
});