@wandelbots/nova-js
Version:
Official JS client for the Wandelbots API
127 lines (114 loc) • 3.93 kB
text/typescript
import type { MotionGroupState } from "@wandelbots/nova-api/v2"
import type { AxiosResponse, InternalAxiosRequestConfig } from "axios"
import { AxiosError } from "axios"
import * as pathToRegexp from "path-to-regexp"
import type { AutoReconnectingWebsocket } from "../AutoReconnectingWebsocket.ts"
import { getCurrentRobotControllerState } from "./getCurrentRobotControllerState.ts"
import { getMotionGroupDescription } from "./getMotionGroupDescription.ts"
import { getMotionGroupKinematicModel } from "./getMotionGroupKinematicModel.ts"
import { getRobotController } from "./getRobotController.ts"
import { listCoordinateSystems } from "./listCoordinateSystems.ts"
import { listRobotControllers } from "./listRobotControllers.ts"
/**
* Ultra-simplified mock Nova server for testing stuff
*/
export class MockNovaInstance {
readonly connections: AutoReconnectingWebsocket[] = []
async handleAPIRequest(
config: InternalAxiosRequestConfig,
): Promise<AxiosResponse> {
const apiHandlers = [
listRobotControllers,
getRobotController,
getMotionGroupDescription,
getCurrentRobotControllerState,
listCoordinateSystems,
getMotionGroupKinematicModel,
]
const method = config.method?.toUpperCase() || "GET"
if (!config.url) {
throw new Error("No url sent with request")
}
const path = config.url.split("?")[0] ?? config.url
for (const handler of apiHandlers) {
const match = pathToRegexp.match(handler.path)(path)
if (method === handler.method && match) {
const json = handler.handle()
return {
status: 200,
statusText: "Success",
data: JSON.stringify(json),
headers: {},
config,
request: {
responseURL: config.url,
},
}
}
}
throw new AxiosError(
`No mock handler matched this request: ${method} ${path}`,
"404",
config,
)
}
// Please note: Only very basic websocket mocking is done here, needs to be extended as needed
handleWebsocketConnection(socket: AutoReconnectingWebsocket) {
this.connections.push(socket)
setTimeout(() => {
socket.dispatchEvent(new Event("open"))
console.log("Websocket connection opened from", socket.url)
if (socket.url.includes("/state-stream")) {
socket.dispatchEvent(
new MessageEvent("message", {
data: JSON.stringify(defaultMotionState),
}),
)
}
if (socket.url.includes("/execution/jogging")) {
socket.dispatchEvent(
new MessageEvent("message", {
data: JSON.stringify({
result: {
message: "string",
kind: "INITIALIZE_RECEIVED",
},
}),
}),
)
}
}, 10)
}
handleWebsocketMessage(socket: AutoReconnectingWebsocket, message: string) {
console.log(`Received message on ${socket.url}`, message)
}
}
const defaultMotionState = {
result: {
motion_group: "0@universalrobots-ur5e",
controller: "universalrobots-ur5e",
timestamp: new Date().toISOString(),
sequence_number: 1,
joint_position: [
1.1699999570846558, -1.5700000524520874, 1.3600000143051147,
1.0299999713897705, 1.2899999618530273, 1.2799999713897705,
],
joint_limit_reached: {
limit_reached: [false, false, false, false, false, false],
},
standstill: false,
flange_pose: {
position: [1.3300010259703043, -409.2680714682808, 531.0203477065281],
orientation: [
1.7564919306270736, -1.7542521568325058, 0.7326972590614671,
],
},
tcp_pose: {
position: [1.3300010259703043, -409.2680714682808, 531.0203477065281],
orientation: [
1.7564919306270736, -1.7542521568325058, 0.7326972590614671,
],
},
description_revision: 0,
} satisfies MotionGroupState,
}