You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
3.8 KiB

#!/usr/bin/env node
/**
* 开发环境启动脚本
* 同时启动前端和链下服务
*/
const { spawn } = require('child_process')
const path = require('path')
const fs = require('fs')
// 颜色输出
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
yellow: '\x1b[33m',
red: '\x1b[31m',
blue: '\x1b[34m',
cyan: '\x1b[36m'
}
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`)
}
// 检查链下服务配置
function checkServicesConfig() {
const servicesEnvPath = path.join(__dirname, 'services', '.env')
const servicesEnvExamplePath = path.join(__dirname, 'services', '.env.example')
if (!fs.existsSync(servicesEnvPath)) {
log('⚠️ 未找到 services/.env 文件', 'yellow')
if (fs.existsSync(servicesEnvExamplePath)) {
log(' 请复制 services/.env.example 为 services/.env 并配置', 'yellow')
} else {
log(' 请创建 services/.env 文件,配置以下内容:', 'yellow')
log(' - RPC_URL: 区块链RPC地址', 'yellow')
log(' - PRIVATE_KEY: 管理员私钥', 'yellow')
log(' - CONTRACT_ADDRESS: CampusRatingV2合约地址', 'yellow')
log(' - MAIN_CONTRACT_ADDRESS: CampusRating主合约地址', 'yellow')
}
log(' 链下服务将不会启动,但前端仍可正常运行', 'yellow')
return false
}
// 检查必要的环境变量
const envContent = fs.readFileSync(servicesEnvPath, 'utf-8')
if (!envContent.includes('PRIVATE_KEY=') || envContent.match(/PRIVATE_KEY=\s*$/)) {
log('⚠️ services/.env 中未配置 PRIVATE_KEY', 'yellow')
log(' 链下服务将不会启动,但前端仍可正常运行', 'yellow')
return false
}
return true
}
// 启动前端
function startFrontend() {
log('\n🚀 启动前端应用...', 'cyan')
const frontend = spawn('npm', ['run', 'dev'], {
cwd: path.join(__dirname, 'app'),
stdio: 'inherit',
shell: true
})
frontend.on('error', (error) => {
log(`❌ 前端启动失败: ${error.message}`, 'red')
})
return frontend
}
// 启动链下服务
function startServices() {
log('\n🔧 启动链下服务...', 'cyan')
const services = spawn('npm', ['run', 'dev:all'], {
cwd: path.join(__dirname, 'services'),
stdio: 'inherit',
shell: true
})
services.on('error', (error) => {
log(`⚠️ 链下服务启动失败: ${error.message}`, 'yellow')
log(' 前端仍可正常运行', 'yellow')
})
return services
}
// 主函数
function main() {
log('\n' + '='.repeat(50), 'bright')
log(' 校园评分系统 - 开发环境启动', 'bright')
log('='.repeat(50) + '\n', 'bright')
// 检查链下服务配置
const hasServicesConfig = checkServicesConfig()
// 启动前端(必须)
const frontend = startFrontend()
// 启动链下服务(可选)
let services = null
if (hasServicesConfig) {
services = startServices()
}
// 处理退出信号
process.on('SIGINT', () => {
log('\n\n🛑 正在关闭服务...', 'yellow')
if (frontend) frontend.kill()
if (services) services.kill()
process.exit(0)
})
process.on('SIGTERM', () => {
log('\n\n🛑 正在关闭服务...', 'yellow')
if (frontend) frontend.kill()
if (services) services.kill()
process.exit(0)
})
// 监听进程退出
frontend.on('exit', (code) => {
if (code !== 0 && code !== null) {
log(`\n❌ 前端进程异常退出,代码: ${code}`, 'red')
}
if (services) services.kill()
process.exit(code || 0)
})
if (services) {
services.on('exit', (code) => {
if (code !== 0 && code !== null) {
log(`\n⚠️ 链下服务进程异常退出,代码: ${code}`, 'yellow')
log(' 前端仍可正常运行', 'yellow')
}
})
}
}
main()