// server/index.js import express from 'express' import cors from 'cors' import path from 'path'; import 'dotenv/config'; import { createAGVGrpcClient, createARMGrpcClient, __dirname } from './grpcClient.js'; const app = express() app.use(express.static(path.join(__dirname, '../dist'))); app.use(cors()) app.use(express.json()) // 获取机器人当前地图名称 app.post('/api/agv/getCurrentMapName', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'agv_src1100' } }; const grpcClient = createAGVGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.getMapStatus(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.status }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 获取机器人当前地图名称 app.post('/api/agv/getCurrentMap', async (req, res) => { const grpcClient = createAGVGrpcClient(req.body.ip) const request = { header: { device_id: req.body.deviceId || 'agv_src1100' }, data: { map_name: req.body.mapName } }; const resp = await new Promise((resolve, reject) => { grpcClient.RobotConfigDownloadMap(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.status }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 获取机器人状态 app.post('/api/agv/getRobotState', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'agv_src1100' } }; const grpcClient = createAGVGrpcClient(req.body.ip) const response = await new Promise((resolve, reject) => { grpcClient.GetRobotLocation(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.status }); } }) }) const resp = await new Promise((resolve, reject) => { grpcClient.GetBatteryStatus(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.status }); } }); }) if (response.code === 200 && resp.code ===200) { res.json({ code: 200, data: { x: response.data.x, y: response.data.y, angle: response.data.angle, confidence: response.data.confidence, batteryLevel: resp.data.battery_level, batteryTemp: resp.data.battery_temp, charging: resp.data.charging, voltage: resp.data.voltage } }) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 机器人运动控制 app.post('/api/agv/moveRobot', async (req, res) => { const grpcClient = createAGVGrpcClient(req.body.ip) const request = { header: { device_id: req.body.deviceId || 'agv_src1100' }, data: { vx: req.body.vx, vy: req.body.vy, w: req.body.w, duration: req.body.duration } }; const resp = await new Promise((resolve, reject) => { grpcClient.RobotMotionControl(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.status }); } }); }) if (resp.code === 200) { res.json({ code: 200, data: resp }) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 机器人停止运动 app.post('/api/agv/stopRobot', async (req, res) => { const grpcClient = createAGVGrpcClient(req.body.ip) const request = { header: { device_id: req.body.deviceId || 'agv_src1100' } }; const resp = await new Promise((resolve, reject) => { grpcClient.RobotControlStop(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.status }); } }); }) if (resp.code === 200) { res.json({ code: 200, data: resp }) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 获取机械臂末端位姿 app.post('/api/arm/getPose', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'huayan_arm' } }; const grpcClient = createARMGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.getPose(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.pose }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 获取机械臂节点状态 app.post('/api/arm/getJointState', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'huayan_arm' } }; const grpcClient = createARMGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.getJointState(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.state }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 机械臂关节运动 app.post('/api/arm/speedJ', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'huayan_arm' }, velocity: { velocity: req.body.velocities }, acceleration: req.body.acceleration, duration: req.body.duration }; const grpcClient = createARMGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.speedJ(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) app.post('/api/arm/speedL', async (req, res) => { const request = { header: { device_id: req.body.deviceId || 'huayan_arm' }, velocity: req.body.velocity, acceleration: req.body.acceleration, duration: req.body.duration }; const grpcClient = createARMGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.speedL(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) // 机械臂停止运动 app.post('/api/arm/stopMotion', async (req, res) => { const request = { // header: { device_id: req.body.deviceId || 'huayan_arm', // }, }; const grpcClient = createARMGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.stopMotion(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res.success }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) app.post('/api/arm/torqueOn', async (req, res) => { const request = { device_id: req.body.deviceId || 'huayan_arm', }; const grpcClient = createARMGrpcClient(req.body.ip) const resp = await new Promise((resolve, reject) => { grpcClient.torqueOn(request, (err, res) => { if (err) { resolve({ code: 500, data: `grpc服务端错误` }); } else { resolve({ code: 200, data: res }); } }); }) if (resp.code === 200) { res.json(resp) } else { res.status(500).json({ error: 'grpc服务端错误' }) } }) const isProd = process.env.NODE_ENV === 'production'; const PORT = process.env.VITE_SERVICE_PORT || 3000; // ============ 生产环境:托管 Vite 构建产物 ============ if (isProd) { const distPath = path.resolve(__dirname, '../dist'); // 托管静态文件 app.use(express.static(distPath)); // SPA 回退:所有非 API 请求返回 index.html app.get('/{*path}', (req, res) => { res.sendFile(path.resolve(distPath, 'index.html')); }); app.post('/{*path}', (req, res) => { res.sendFile(path.resolve(distPath, 'index.html')); }); } // ========== 启动 ========= app.listen(PORT, () => { console.log(`gRPC 桥接服务已启动: http://localhost:${PORT}`) })