inspection-host-computer/server/index.js
2026-06-29 17:33:18 +08:00

269 lines
6.1 KiB
JavaScript

// server/index.js
import express from 'express'
import cors from 'cors'
import grpc from '@grpc/grpc-js'
import protoLoader from '@grpc/proto-loader'
import path from 'path';
import { fileURLToPath } from 'url';
import 'dotenv/config';
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const app = express()
app.use(express.static(path.join(__dirname, '../dist')));
app.use(cors())
app.use(express.json())
// ========== 加载 Proto ==========
const PROTO_ROOT = path.resolve(__dirname, './proto') // 指向 server/proto/
const PROTO_ENTRY = path.join(PROTO_ROOT, 'cmvr/api/agv_service.proto')
const packageDefinition = protoLoader.loadSync(
PROTO_ENTRY,
{
includeDirs: [PROTO_ROOT , path.join(PROTO_ROOT, 'cmvr/api')], // 关键:让加载器从 PROTO_ROOT 查找 import
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
)
const cmvrProto = grpc.loadPackageDefinition(packageDefinition).cmvr.api
const createGrpcClient = (address) => {
const grpcClient = new cmvrProto.AgvService(
address,
grpc.credentials.createInsecure()
)
return grpcClient
}
// 获取机器人当前地图名称
app.post('/api/agv/getCurrentMapName', async (req, res) => {
const request = {
header: {
device_id: req.body.device_id || 'agv_src1100'
}
};
const grpcClient = createGrpcClient(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 = createGrpcClient(req.body.ip)
const request = {
header: {
device_id: req.body.device_id || '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.device_id || 'agv_src1100'
}
};
const grpcClient = createGrpcClient(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 = createGrpcClient(req.body.ip)
const request = {
header: {
device_id: req.body.device_id || '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 = createGrpcClient(req.body.ip)
const request = {
header: {
device_id: req.body.device_id || '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服务端错误' })
}
})
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}`)
})