@dronedeploy/rocos-js-sdk 3.0.0-alpha.8 → 3.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IRocosSDK.d.ts +3 -26
- package/RocosSDK.d.ts +6 -1
- package/RocosSDK.js +11 -1
- package/helpers/getURLSearchParams.d.ts +2 -0
- package/helpers/getURLSearchParams.js +9 -0
- package/helpers/getURLSearchParams.spec.d.ts +1 -0
- package/helpers/getURLSearchParams.spec.js +19 -0
- package/helpers/index.d.ts +2 -0
- package/helpers/index.js +2 -0
- package/helpers/websandbox/connection.d.ts +67 -0
- package/helpers/websandbox/connection.js +133 -0
- package/helpers/websandbox/frame/frame.d.ts +12 -0
- package/helpers/websandbox/frame/frame.js +22 -0
- package/helpers/websandbox/frame/frame.source.d.ts +2 -0
- package/helpers/websandbox/frame/frame.source.js +5 -0
- package/helpers/websandbox/frame/index.d.ts +2 -0
- package/helpers/websandbox/frame/index.js +2 -0
- package/helpers/websandbox/frame/worker/index.d.ts +2 -0
- package/helpers/websandbox/frame/worker/index.js +2 -0
- package/helpers/websandbox/frame/worker/manager.d.ts +13 -0
- package/helpers/websandbox/frame/worker/manager.js +60 -0
- package/helpers/websandbox/frame/worker/types.d.ts +11 -0
- package/helpers/websandbox/frame/worker/types.js +1 -0
- package/helpers/websandbox/frame/worker/worker.d.ts +1 -0
- package/helpers/websandbox/frame/worker/worker.js +74 -0
- package/helpers/websandbox/frame/worker/worker.source.d.ts +2 -0
- package/helpers/websandbox/frame/worker/worker.source.js +4 -0
- package/helpers/websandbox/index.d.ts +2 -0
- package/helpers/websandbox/index.js +2 -0
- package/helpers/websandbox/sandbox.d.ts +54 -0
- package/helpers/websandbox/sandbox.js +146 -0
- package/helpers/websandbox/types.d.ts +13 -0
- package/helpers/websandbox/types.js +1 -0
- package/models/RocosError.d.ts +1 -0
- package/models/RocosError.js +1 -0
- package/models/ServiceEnum.d.ts +2 -1
- package/models/ServiceEnum.js +1 -0
- package/node/RocosSDKNode.d.ts +6 -1
- package/node/RocosSDKNode.js +7 -0
- package/package.json +1 -1
- package/services/AssetStorageService.js +1 -1
- package/services/BaseServiceAbstract.d.ts +1 -1
- package/services/BaseServiceAbstract.js +2 -6
- package/services/EvaluatorService.d.ts +11 -0
- package/services/EvaluatorService.js +28 -0
- package/services/MapService.d.ts +2 -1
- package/services/MapService.js +5 -3
- package/services/TelemetryService.spec.js +2 -2
- package/services/index.d.ts +1 -0
- package/services/index.js +1 -0
package/IRocosSDK.d.ts
CHANGED
@@ -1,29 +1,5 @@
|
|
1
|
-
import { MapService, SpotProvisioningServiceNode } from './services';
|
2
|
-
import {
|
3
|
-
import { AuthService } from './services/AuthService';
|
4
|
-
import { CallerService } from './services/CallerService';
|
5
|
-
import { CommandService } from './services/CommandService';
|
6
|
-
import { ConfigGroupService } from './services/ConfigGroupService';
|
7
|
-
import { ControlService } from './services/ControlService';
|
8
|
-
import { DashboardService } from './services/DashboardService';
|
9
|
-
import { EventService } from './services/EventService';
|
10
|
-
import { FileAccessorService } from './services/FileAccessorService';
|
11
|
-
import { FunctionService } from './services/FunctionService';
|
12
|
-
import { IBaseService } from './models/IBaseService';
|
13
|
-
import { IDebugLevel } from './models/IDebugLevel';
|
14
|
-
import { IntegrationService } from './services/IntegrationService';
|
15
|
-
import { ProfileService } from './services/ProfileService';
|
16
|
-
import { ProjectService } from './services/ProjectService';
|
17
|
-
import { RobotService } from './services/RobotService';
|
18
|
-
import { SearchService } from './services/SearchService';
|
19
|
-
import { ServiceEnum } from './models/ServiceEnum';
|
20
|
-
import { SpotProvisioningService } from './services/SpotProvisioningService';
|
21
|
-
import { StreamService } from './services/StreamService';
|
22
|
-
import { TelemetryService } from './services/TelemetryService';
|
23
|
-
import { TimeSyncerService } from './services/TimeSyncerService';
|
24
|
-
import { UserService } from './services/UserService';
|
25
|
-
import { WebRTCSignallingService } from './services/WebRTCSignallingService';
|
26
|
-
import { WorkflowService } from './services/WorkflowService';
|
1
|
+
import { AssetStorageService, AuthService, CallerService, CommandService, ConfigGroupService, ControlService, DashboardService, EvaluatorService, EventService, FileAccessorService, FunctionService, IntegrationService, MapService, ProfileService, ProjectService, RobotService, SearchService, SpotProvisioningService, SpotProvisioningServiceNode, StreamService, TelemetryService, TimeSyncerService, UserService, WebRTCSignallingService, WorkflowService } from './services';
|
2
|
+
import { IBaseService, IDebugLevel, ServiceEnum } from './models';
|
27
3
|
export declare abstract class IRocosSDK {
|
28
4
|
abstract getService<T extends IBaseService>(name: ServiceEnum): T;
|
29
5
|
abstract getAuthService(): AuthService;
|
@@ -49,6 +25,7 @@ export declare abstract class IRocosSDK {
|
|
49
25
|
abstract getFileAccessorService(): FileAccessorService;
|
50
26
|
abstract getSpotProvisionerService(): SpotProvisioningService | SpotProvisioningServiceNode;
|
51
27
|
abstract getIntegrationService(): IntegrationService;
|
28
|
+
abstract getEvaluatorService(): EvaluatorService;
|
52
29
|
abstract cleanup(): Promise<boolean>;
|
53
30
|
abstract enableDebugMode(on: boolean): void;
|
54
31
|
abstract setDebugLevel(level: IDebugLevel): void;
|
package/RocosSDK.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AssetStorageService, AuthService, CallerService, CommandService, ConfigGroupService, ControlService, DashboardService, EventService, FileAccessorService, FunctionService, IntegrationService, MapService, ProfileService, ProjectService, RobotService, ScheduleService, SearchService, SpotProvisioningService, StreamService, TelemetryService, TimeSyncerService, UserService, WebRTCSignallingService, WorkflowService } from './services';
|
1
|
+
import { AssetStorageService, AuthService, CallerService, CommandService, ConfigGroupService, ControlService, DashboardService, EvaluatorService, EventService, FileAccessorService, FunctionService, IntegrationService, MapService, ProfileService, ProjectService, RobotService, ScheduleService, SearchService, SpotProvisioningService, StreamService, TelemetryService, TimeSyncerService, UserService, WebRTCSignallingService, WorkflowService } from './services';
|
2
2
|
import { IBaseService, IDebugLevel, IRocosSDKConfig, ServiceEnum } from './models';
|
3
3
|
import { IRocosSDK } from './IRocosSDK';
|
4
4
|
import { Logger } from 'loglevel';
|
@@ -120,6 +120,11 @@ export declare class RocosSDK implements IRocosSDK {
|
|
120
120
|
* @returns MapService
|
121
121
|
*/
|
122
122
|
getMapService(): MapService;
|
123
|
+
/**
|
124
|
+
* Gets the evaluator service
|
125
|
+
* @returns EvaluatorService
|
126
|
+
*/
|
127
|
+
getEvaluatorService(): EvaluatorService;
|
123
128
|
get platformTimeOffset(): number;
|
124
129
|
get platformTime(): number;
|
125
130
|
/**
|
package/RocosSDK.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AssetStorageService, AuthService, CallerService, CommandService, ConfigGroupService, ControlService, DashboardService, EventService, FileAccessorService, FunctionService, IntegrationService, MapService, PlatFormTimeService, ProfileService, ProjectService, RobotService, ScheduleService, SearchService, SpotProvisioningService, StreamService, TelemetryService, TimeSyncerService, UserService, WebRTCSignallingService, WorkflowService, } from './services';
|
1
|
+
import { AssetStorageService, AuthService, CallerService, CommandService, ConfigGroupService, ControlService, DashboardService, EvaluatorService, EventService, FileAccessorService, FunctionService, IntegrationService, MapService, PlatFormTimeService, ProfileService, ProjectService, RobotService, ScheduleService, SearchService, SpotProvisioningService, StreamService, TelemetryService, TimeSyncerService, UserService, WebRTCSignallingService, WorkflowService, } from './services';
|
2
2
|
import { ServiceEnum } from './models';
|
3
3
|
import { RocosLogger } from './logger/RocosLogger';
|
4
4
|
import { RocosStore } from './store/RocosStore';
|
@@ -97,6 +97,9 @@ export class RocosSDK {
|
|
97
97
|
case ServiceEnum.MAP:
|
98
98
|
this.services[name] = new MapService(this.config);
|
99
99
|
break;
|
100
|
+
case ServiceEnum.EVALUATOR:
|
101
|
+
this.services[name] = new EvaluatorService(this.config);
|
102
|
+
break;
|
100
103
|
}
|
101
104
|
}
|
102
105
|
this.logger.debug(`Found service ${name}.`);
|
@@ -252,6 +255,13 @@ export class RocosSDK {
|
|
252
255
|
getMapService() {
|
253
256
|
return this.getService(ServiceEnum.MAP);
|
254
257
|
}
|
258
|
+
/**
|
259
|
+
* Gets the evaluator service
|
260
|
+
* @returns EvaluatorService
|
261
|
+
*/
|
262
|
+
getEvaluatorService() {
|
263
|
+
return this.getService(ServiceEnum.EVALUATOR);
|
264
|
+
}
|
255
265
|
get platformTimeOffset() {
|
256
266
|
return PlatFormTimeService.getInstance(this.getTimeSyncerService())?.platformTimeOffset;
|
257
267
|
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
export const getURLSearchParams = (params) => {
|
2
|
+
if (params instanceof URLSearchParams)
|
3
|
+
return params;
|
4
|
+
const stringParams = Object.entries(params ?? {}).reduce((acc, [key, value]) => {
|
5
|
+
acc[key] = value.toString();
|
6
|
+
return acc;
|
7
|
+
}, {});
|
8
|
+
return new URLSearchParams(stringParams);
|
9
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { getURLSearchParams } from './getURLSearchParams';
|
2
|
+
describe('getURLSearchParams', () => {
|
3
|
+
it('Should return the original param if URLSearchParams', () => {
|
4
|
+
const param = new URLSearchParams();
|
5
|
+
const searchParam = getURLSearchParams(param);
|
6
|
+
expect(searchParam).toBe(param);
|
7
|
+
});
|
8
|
+
it('Should a new URLSearchParams ', () => {
|
9
|
+
const param = {
|
10
|
+
foo: 'bar',
|
11
|
+
bar: true,
|
12
|
+
foobar: 123,
|
13
|
+
};
|
14
|
+
const searchParam = getURLSearchParams(param);
|
15
|
+
expect(searchParam.get('foo')).toBe('bar');
|
16
|
+
expect(searchParam.get('bar')).toBe('true');
|
17
|
+
expect(searchParam.get('foobar')).toBe('123');
|
18
|
+
});
|
19
|
+
});
|
package/helpers/index.d.ts
CHANGED
package/helpers/index.js
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
import { APIDeclaration } from './types';
|
2
|
+
export interface ConnectionOptions {
|
3
|
+
allowedSenderOrigin?: string;
|
4
|
+
debugMode: boolean;
|
5
|
+
}
|
6
|
+
type ListenerCallback = (e: MessageEvent<Message>) => void;
|
7
|
+
declare enum MessageType {
|
8
|
+
RESPONSE = "response",
|
9
|
+
MESSAGE = "message"
|
10
|
+
}
|
11
|
+
interface BaseMessageData {
|
12
|
+
type: MessageType;
|
13
|
+
callId: string;
|
14
|
+
}
|
15
|
+
interface ResponseData extends BaseMessageData {
|
16
|
+
type: MessageType.RESPONSE;
|
17
|
+
success: boolean;
|
18
|
+
result: unknown;
|
19
|
+
}
|
20
|
+
interface MessageData extends BaseMessageData {
|
21
|
+
type: MessageType.MESSAGE;
|
22
|
+
methodName: string;
|
23
|
+
arguments: unknown[];
|
24
|
+
}
|
25
|
+
type Message = MessageData | ResponseData;
|
26
|
+
export default class Connection<Local extends APIDeclaration<Local>, Remote extends APIDeclaration<Remote>> {
|
27
|
+
private readonly name;
|
28
|
+
private incrementalID;
|
29
|
+
private readonly options;
|
30
|
+
private readonly postMessageInternal;
|
31
|
+
private callbacks;
|
32
|
+
private serviceMethods;
|
33
|
+
constructor(name: string, postMessage: typeof window.postMessage, methods: Local, registerOnMessageListener: (listener: ListenerCallback) => void, options?: Partial<ConnectionOptions>);
|
34
|
+
/** Call a remote method
|
35
|
+
*
|
36
|
+
* returns a promise that resolves when the remote responds
|
37
|
+
*
|
38
|
+
* @param name - name of remote method to call
|
39
|
+
* @param args - arguments to pass to remote method
|
40
|
+
*/
|
41
|
+
callRemoteMethod<Method extends keyof Remote>(name: Method, ...args: Parameters<Remote[Method]>): Promise<ReturnType<Remote[Method]>>;
|
42
|
+
private onMessageListener;
|
43
|
+
private callLocalMethod;
|
44
|
+
/** Respond to remote call
|
45
|
+
*
|
46
|
+
* @param id - remote call ID
|
47
|
+
* @param result - result to pass to calling function
|
48
|
+
* @param success - whether the call was successful
|
49
|
+
*/
|
50
|
+
private responseOtherSide;
|
51
|
+
/** Store a callback to be called when the remote responds
|
52
|
+
*
|
53
|
+
* @param success - callback to be called on success
|
54
|
+
* @param failure - callback to be called on failure
|
55
|
+
*/
|
56
|
+
private registerCallback;
|
57
|
+
/** Calls and deletes stored callback
|
58
|
+
*
|
59
|
+
* @param callId - ID of callback to call
|
60
|
+
* @param success - whether the call was successful
|
61
|
+
* @param result - result of remote call
|
62
|
+
*/
|
63
|
+
private popCallback;
|
64
|
+
private postMessage;
|
65
|
+
private log;
|
66
|
+
}
|
67
|
+
export {};
|
@@ -0,0 +1,133 @@
|
|
1
|
+
var MessageType;
|
2
|
+
(function (MessageType) {
|
3
|
+
MessageType["RESPONSE"] = "response";
|
4
|
+
MessageType["MESSAGE"] = "message";
|
5
|
+
})(MessageType || (MessageType = {}));
|
6
|
+
const defaultOptions = {
|
7
|
+
allowedSenderOrigin: undefined,
|
8
|
+
debugMode: false,
|
9
|
+
};
|
10
|
+
export default class Connection {
|
11
|
+
constructor(name, postMessage, methods, registerOnMessageListener, options = {}) {
|
12
|
+
this.callbacks = new Map();
|
13
|
+
this.serviceMethods = new Map();
|
14
|
+
this.name = name;
|
15
|
+
this.options = { ...defaultOptions, ...options };
|
16
|
+
this.log('Created connection w/ allowedOrigin:', this.options.allowedSenderOrigin);
|
17
|
+
this.serviceMethods = new Map(Object.entries(methods));
|
18
|
+
// Assign a random starting ID to this connection
|
19
|
+
const [id] = crypto.getRandomValues(new Uint32Array(1));
|
20
|
+
this.incrementalID = id;
|
21
|
+
this.postMessageInternal = postMessage;
|
22
|
+
registerOnMessageListener((e) => this.onMessageListener(e));
|
23
|
+
}
|
24
|
+
/** Call a remote method
|
25
|
+
*
|
26
|
+
* returns a promise that resolves when the remote responds
|
27
|
+
*
|
28
|
+
* @param name - name of remote method to call
|
29
|
+
* @param args - arguments to pass to remote method
|
30
|
+
*/
|
31
|
+
callRemoteMethod(name, ...args) {
|
32
|
+
this.log('Calling Remote Method', {
|
33
|
+
name,
|
34
|
+
args,
|
35
|
+
});
|
36
|
+
return new Promise((resolve, reject) => {
|
37
|
+
const id = this.registerCallback(resolve, reject);
|
38
|
+
this.postMessage({
|
39
|
+
callId: id,
|
40
|
+
type: MessageType.MESSAGE,
|
41
|
+
methodName: name,
|
42
|
+
arguments: args,
|
43
|
+
});
|
44
|
+
});
|
45
|
+
}
|
46
|
+
onMessageListener(e) {
|
47
|
+
this.log('Received message', e);
|
48
|
+
const { data } = e;
|
49
|
+
const { allowedSenderOrigin } = this.options;
|
50
|
+
if (allowedSenderOrigin && e.origin !== allowedSenderOrigin) {
|
51
|
+
console.warn(`Received message from invalid origin: ${e.origin}`);
|
52
|
+
}
|
53
|
+
switch (data.type) {
|
54
|
+
case MessageType.RESPONSE:
|
55
|
+
this.popCallback(data.callId, data.success, data.result);
|
56
|
+
return;
|
57
|
+
case MessageType.MESSAGE:
|
58
|
+
this.callLocalMethod(data.methodName, data.arguments)
|
59
|
+
.then((res) => this.responseOtherSide(data.callId, res))
|
60
|
+
.catch((err) => this.responseOtherSide(data.callId, err, false));
|
61
|
+
}
|
62
|
+
}
|
63
|
+
async callLocalMethod(methodName, args) {
|
64
|
+
this.log('calling local method', methodName, args);
|
65
|
+
const method = this.serviceMethods.get(methodName);
|
66
|
+
if (!method) {
|
67
|
+
throw new Error(`service method ${methodName} not found`);
|
68
|
+
}
|
69
|
+
return method(...args);
|
70
|
+
}
|
71
|
+
/** Respond to remote call
|
72
|
+
*
|
73
|
+
* @param id - remote call ID
|
74
|
+
* @param result - result to pass to calling function
|
75
|
+
* @param success - whether the call was successful
|
76
|
+
*/
|
77
|
+
responseOtherSide(id, result, success = true) {
|
78
|
+
this.log('responding to remote call', { id, result, success });
|
79
|
+
const doPost = (result) => {
|
80
|
+
this.postMessage({
|
81
|
+
callId: id,
|
82
|
+
type: MessageType.RESPONSE,
|
83
|
+
success,
|
84
|
+
result,
|
85
|
+
});
|
86
|
+
};
|
87
|
+
try {
|
88
|
+
doPost(result);
|
89
|
+
}
|
90
|
+
catch (err) {
|
91
|
+
if (err instanceof DOMException) {
|
92
|
+
doPost(JSON.parse(JSON.stringify(result)));
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
/** Store a callback to be called when the remote responds
|
97
|
+
*
|
98
|
+
* @param success - callback to be called on success
|
99
|
+
* @param failure - callback to be called on failure
|
100
|
+
*/
|
101
|
+
registerCallback(success, failure) {
|
102
|
+
const id = (++this.incrementalID).toString();
|
103
|
+
this.log('registering callback for id', id);
|
104
|
+
this.callbacks.set(id, { success, failure });
|
105
|
+
return id;
|
106
|
+
}
|
107
|
+
/** Calls and deletes stored callback
|
108
|
+
*
|
109
|
+
* @param callId - ID of callback to call
|
110
|
+
* @param success - whether the call was successful
|
111
|
+
* @param result - result of remote call
|
112
|
+
*/
|
113
|
+
popCallback(callId, success, result) {
|
114
|
+
this.log('calling callback for id', callId, { success, result });
|
115
|
+
const callbacks = this.callbacks.get(callId);
|
116
|
+
if (success) {
|
117
|
+
callbacks?.success(result);
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
callbacks?.failure(result);
|
121
|
+
}
|
122
|
+
this.callbacks.delete(callId);
|
123
|
+
}
|
124
|
+
postMessage(data, targetOrigin = '*') {
|
125
|
+
this.log('sending message', { data, targetOrigin });
|
126
|
+
this.postMessageInternal(data, targetOrigin);
|
127
|
+
}
|
128
|
+
log(...args) {
|
129
|
+
if (this.options.debugMode) {
|
130
|
+
console.debug(`[${this.name}]`, ...args);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Task } from '../types';
|
2
|
+
export interface FrameMethods {
|
3
|
+
startTask: (task: Task) => unknown;
|
4
|
+
}
|
5
|
+
declare class Frame {
|
6
|
+
private connection;
|
7
|
+
private workerManager;
|
8
|
+
constructor();
|
9
|
+
private runCode;
|
10
|
+
}
|
11
|
+
declare const frame: Frame;
|
12
|
+
export default frame;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// this file is bundled via webpack and included in the iframe source
|
2
|
+
import Connection from '../connection';
|
3
|
+
import WorkerManager from './worker';
|
4
|
+
class Frame {
|
5
|
+
constructor() {
|
6
|
+
const isDebugMode = !!window?.debugMode;
|
7
|
+
this.connection = new Connection('FRAME', window.parent.postMessage.bind(window.parent), {
|
8
|
+
startTask: this.runCode.bind(this),
|
9
|
+
}, (listener) => {
|
10
|
+
window.addEventListener('message', listener);
|
11
|
+
}, {
|
12
|
+
debugMode: isDebugMode,
|
13
|
+
});
|
14
|
+
void this.connection.callRemoteMethod('iframeInitialised');
|
15
|
+
this.workerManager = new WorkerManager();
|
16
|
+
}
|
17
|
+
async runCode(task) {
|
18
|
+
return this.workerManager.execute(task);
|
19
|
+
}
|
20
|
+
}
|
21
|
+
const frame = new Frame();
|
22
|
+
export default frame;
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// Auto-generated file
|
2
|
+
/* eslint-disable */
|
3
|
+
import __WORKER_SOURCE__ from './worker/worker.source';
|
4
|
+
const source = `(()=>{"use strict";var e={880:(e,t)=>{var s;Object.defineProperty(t,"__esModule",{value:!0}),function(e){e.RESPONSE="response",e.MESSAGE="message"}(s||(s={}));const r={allowedSenderOrigin:void 0,debugMode:!1};t.default=class{constructor(e,t,s,i,o={}){this.callbacks=new Map,this.serviceMethods=new Map,this.name=e,this.options={...r,...o},this.log("Created connection w/ allowedOrigin:",this.options.allowedSenderOrigin),this.serviceMethods=new Map(Object.entries(s));const[n]=crypto.getRandomValues(new Uint32Array(1));this.incrementalID=n,this.postMessageInternal=t,i((e=>this.onMessageListener(e)))}callRemoteMethod(e,...t){return this.log("Calling Remote Method",{name:e,args:t}),new Promise(((r,i)=>{const o=this.registerCallback(r,i);this.postMessage({callId:o,type:s.MESSAGE,methodName:e,arguments:t})}))}onMessageListener(e){this.log("Received message",e);const{data:t}=e,{allowedSenderOrigin:r}=this.options;switch(r&&e.origin!==r&&console.warn(\`Received message from invalid origin: \${e.origin}\`),t.type){case s.RESPONSE:return void this.popCallback(t.callId,t.success,t.result);case s.MESSAGE:this.callLocalMethod(t.methodName,t.arguments).then((e=>this.responseOtherSide(t.callId,e))).catch((e=>this.responseOtherSide(t.callId,e,!1)))}}async callLocalMethod(e,t){this.log("calling local method",e,t);const s=this.serviceMethods.get(e);if(!s)throw new Error(\`service method \${e} not found\`);return s(...t)}responseOtherSide(e,t,r=!0){this.log("responding to remote call",{id:e,result:t,success:r});const i=t=>{this.postMessage({callId:e,type:s.RESPONSE,success:r,result:t})};try{i(t)}catch(e){e instanceof DOMException&&i(JSON.parse(JSON.stringify(t)))}}registerCallback(e,t){const s=(++this.incrementalID).toString();return this.log("registering callback for id",s),this.callbacks.set(s,{success:e,failure:t}),s}popCallback(e,t,s){this.log("calling callback for id",e,{success:t,result:s});const r=this.callbacks.get(e);t?r?.success(s):r?.failure(s),this.callbacks.delete(e)}postMessage(e,t="*"){this.log("sending message",{data:e,targetOrigin:t}),this.postMessageInternal(e,t)}log(...e){this.options.debugMode&&console.debug(\`[\${this.name}]\`,...e)}}},306:function(e,t,s){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const i=r(s(880)),o=r(s(54)),n=new class{constructor(){const e=!!window?.debugMode;this.connection=new i.default("FRAME",window.parent.postMessage.bind(window.parent),{startTask:this.runCode.bind(this)},(e=>{window.addEventListener("message",e)}),{debugMode:e}),this.connection.callRemoteMethod("iframeInitialised"),this.workerManager=new o.default}async runCode(e){return this.workerManager.execute(e)}};t.default=n},54:function(e,t,s){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const i=r(s(420));t.default=i.default},420:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.default=class{constructor(){this.worker=this.createWorker()}async execute(e){const t={...e,contextVariable:e.contextVariable??"ctx"},s=this.runTask(t),r=this.timeout(e.timeout??1e3);return Promise.race([s,r]).finally((()=>{this.removeMessageListener()}))}terminate(){this.removeMessageListener(),this.worker.terminate(),this.worker=this.createWorker()}runTask(e){return new Promise(((t,s)=>{const r=r=>{const{data:i}=r;i.id===e.id&&(this.stopTimer(),i.success?t(i.result):s(i.result))};this.worker.addEventListener("message",r),this.removeMessageListener=()=>this.worker.removeEventListener("message",r),this.worker.postMessage(e)}))}timeout(e){return new Promise(((t,s)=>{this.timerId=window.setTimeout((()=>{this.terminate(),s(new Error("maximum execution time exceeded"))}),e)}))}stopTimer(){clearTimeout(this.timerId)}createWorker(){const e=URL.createObjectURL(new Blob(["${__WORKER_SOURCE__.replace(/(['`"$])/g, '\\$1')}"],{type:"application/javascript"}));return new Worker(e)}removeMessageListener(){}}}},t={};!function s(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r].call(o.exports,o,o.exports,s),o.exports}(306)})();`;
|
5
|
+
export default source;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Task } from '../../types';
|
2
|
+
export default class Manager {
|
3
|
+
private worker;
|
4
|
+
private timerId?;
|
5
|
+
constructor();
|
6
|
+
execute(task: Task): Promise<unknown>;
|
7
|
+
terminate(): void;
|
8
|
+
private runTask;
|
9
|
+
private timeout;
|
10
|
+
private stopTimer;
|
11
|
+
private createWorker;
|
12
|
+
private removeMessageListener;
|
13
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
// this token (__WORKER_SOURCE__) is replaced by webpack with the source of the worker
|
2
|
+
const WORKER_SOURCE = '__WORKER_SOURCE__';
|
3
|
+
export default class Manager {
|
4
|
+
constructor() {
|
5
|
+
this.worker = this.createWorker();
|
6
|
+
}
|
7
|
+
async execute(task) {
|
8
|
+
const workerTask = {
|
9
|
+
...task,
|
10
|
+
contextVariable: task.contextVariable ?? 'ctx',
|
11
|
+
};
|
12
|
+
const result = this.runTask(workerTask);
|
13
|
+
const timeout = this.timeout(task.timeout ?? 1000);
|
14
|
+
return Promise.race([result, timeout]).finally(() => {
|
15
|
+
this.removeMessageListener();
|
16
|
+
});
|
17
|
+
}
|
18
|
+
terminate() {
|
19
|
+
this.removeMessageListener();
|
20
|
+
this.worker.terminate();
|
21
|
+
this.worker = this.createWorker();
|
22
|
+
}
|
23
|
+
runTask(task) {
|
24
|
+
return new Promise((resolve, reject) => {
|
25
|
+
const listener = (event) => {
|
26
|
+
const { data } = event;
|
27
|
+
if (data.id === task.id) {
|
28
|
+
this.stopTimer();
|
29
|
+
if (data.success) {
|
30
|
+
resolve(data.result);
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
reject(data.result);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
};
|
37
|
+
this.worker.addEventListener('message', listener);
|
38
|
+
this.removeMessageListener = () => this.worker.removeEventListener('message', listener);
|
39
|
+
this.worker.postMessage(task);
|
40
|
+
});
|
41
|
+
}
|
42
|
+
timeout(timeoutMs) {
|
43
|
+
return new Promise((_, reject) => {
|
44
|
+
this.timerId = window.setTimeout(() => {
|
45
|
+
this.terminate();
|
46
|
+
reject(new Error('maximum execution time exceeded'));
|
47
|
+
}, timeoutMs);
|
48
|
+
});
|
49
|
+
}
|
50
|
+
stopTimer() {
|
51
|
+
clearTimeout(this.timerId);
|
52
|
+
}
|
53
|
+
createWorker() {
|
54
|
+
const blob = URL.createObjectURL(new Blob([WORKER_SOURCE], { type: 'application/javascript' }));
|
55
|
+
return new Worker(blob);
|
56
|
+
}
|
57
|
+
removeMessageListener() {
|
58
|
+
// replaced by constructor
|
59
|
+
}
|
60
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,74 @@
|
|
1
|
+
const WHITELIST = [
|
2
|
+
'TEMPORARY',
|
3
|
+
'PERSISTENT',
|
4
|
+
'console',
|
5
|
+
'self',
|
6
|
+
'onmessage',
|
7
|
+
'postMessage',
|
8
|
+
'global',
|
9
|
+
'allowed',
|
10
|
+
'Array',
|
11
|
+
'Boolean',
|
12
|
+
'Date',
|
13
|
+
'Function',
|
14
|
+
'Number',
|
15
|
+
'Object',
|
16
|
+
'RegExp',
|
17
|
+
'String',
|
18
|
+
'Error',
|
19
|
+
'EvalError',
|
20
|
+
'RangeError',
|
21
|
+
'ReferenceError',
|
22
|
+
'SyntaxError',
|
23
|
+
'TypeError',
|
24
|
+
'URIError',
|
25
|
+
'decodeURI',
|
26
|
+
'decodeURIComponent',
|
27
|
+
'encodeURI',
|
28
|
+
'encodeURIComponent',
|
29
|
+
'isFinite',
|
30
|
+
'isNaN',
|
31
|
+
'parseFloat',
|
32
|
+
'parseInt',
|
33
|
+
'Infinity',
|
34
|
+
'JSON',
|
35
|
+
'Math',
|
36
|
+
'NaN',
|
37
|
+
'undefined',
|
38
|
+
];
|
39
|
+
const windowProps = Object.getOwnPropertyNames(self);
|
40
|
+
const protoProps = Object.getOwnPropertyNames(self.__proto__);
|
41
|
+
const props = [...windowProps, ...protoProps];
|
42
|
+
props.forEach((prop) => {
|
43
|
+
if (!WHITELIST.includes(prop)) {
|
44
|
+
Object.defineProperty(self, prop, {
|
45
|
+
get: () => {
|
46
|
+
throw new Error(`Security Exception: cannot access ${prop}`);
|
47
|
+
},
|
48
|
+
set: () => {
|
49
|
+
throw new Error(`Security Exception: cannot set ${prop}`);
|
50
|
+
},
|
51
|
+
configurable: false,
|
52
|
+
});
|
53
|
+
}
|
54
|
+
});
|
55
|
+
// Parses and calls function string with args
|
56
|
+
onmessage = (event) => {
|
57
|
+
let result;
|
58
|
+
let success = true;
|
59
|
+
try {
|
60
|
+
const fn = Function(event.data.contextVariable, `"use strict";return (${event.data.code});`);
|
61
|
+
result = fn(event.data.context);
|
62
|
+
}
|
63
|
+
catch (e) {
|
64
|
+
result = e;
|
65
|
+
success = false;
|
66
|
+
}
|
67
|
+
const message = {
|
68
|
+
id: event.data.id,
|
69
|
+
result,
|
70
|
+
success,
|
71
|
+
};
|
72
|
+
postMessage(message);
|
73
|
+
};
|
74
|
+
export {};
|
@@ -0,0 +1,4 @@
|
|
1
|
+
// Auto-generated file
|
2
|
+
/* eslint-disable */
|
3
|
+
const source = `(()=>{"use strict";(()=>{const e=["TEMPORARY","PERSISTENT","console","self","onmessage","postMessage","global","allowed","Array","Boolean","Date","Function","Number","Object","RegExp","String","Error","EvalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","isFinite","isNaN","parseFloat","parseInt","Infinity","JSON","Math","NaN","undefined"];[...Object.getOwnPropertyNames(self),...Object.getOwnPropertyNames(self.__proto__)].forEach((r=>{e.includes(r)||Object.defineProperty(self,r,{get:()=>{throw new Error(\`Security Exception: cannot access \${r}\`)},set:()=>{throw new Error(\`Security Exception: cannot set \${r}\`)},configurable:!1})})),onmessage=e=>{let r,t=!0;try{r=Function(e.data.contextVariable,\`"use strict";return (\${e.data.code});\`)(e.data.context)}catch(e){r=e,t=!1}const o={id:e.data.id,result:r,success:t};postMessage(o)}})()})();`;
|
4
|
+
export default source;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
export interface SandboxOptions extends Required<RunCodeOptions> {
|
2
|
+
/** The selector or element to append the iframe to */
|
3
|
+
frameContainer: string | Element;
|
4
|
+
/** Whether to enable verbose logging */
|
5
|
+
debugMode: boolean;
|
6
|
+
}
|
7
|
+
export interface RunCodeOptions {
|
8
|
+
/** The name of the variable to use for the context object */
|
9
|
+
contextVariable?: string;
|
10
|
+
timeout?: {
|
11
|
+
/** The minimum time to wait for a task to complete
|
12
|
+
*
|
13
|
+
* The worker will attempt to kill the task after this time.
|
14
|
+
*/
|
15
|
+
minimumMs: number;
|
16
|
+
/** The maximum time to wait for a task to complete
|
17
|
+
*
|
18
|
+
* The sandbox will be destroyed and rebuilt after this time.
|
19
|
+
*/
|
20
|
+
maximumMs: number;
|
21
|
+
};
|
22
|
+
}
|
23
|
+
export declare const BaseOptions: SandboxOptions;
|
24
|
+
export interface SandboxMethods {
|
25
|
+
iframeInitialised: () => void;
|
26
|
+
}
|
27
|
+
/** A sandbox for running untrusted code in an iframe & embedded web worker.
|
28
|
+
*
|
29
|
+
* This is a wrapper around the iframe and web worker that provides a simple API for running code in the sandbox.
|
30
|
+
* It also provides a context object that can be used to pass data into the sandbox.
|
31
|
+
*/
|
32
|
+
export default class WebSandbox {
|
33
|
+
private readonly options;
|
34
|
+
private frame;
|
35
|
+
private connection?;
|
36
|
+
private initialised;
|
37
|
+
static new(options?: Partial<SandboxOptions>): Promise<WebSandbox>;
|
38
|
+
private constructor();
|
39
|
+
/** Runs code in the sandbox. Can be either a string or a function */
|
40
|
+
run<T = unknown>(code: string | (() => T), context?: unknown, options?: RunCodeOptions): Promise<T>;
|
41
|
+
/** Destroys the sandbox.
|
42
|
+
*
|
43
|
+
* This will remove the iframe from the DOM and remove the message listener.
|
44
|
+
*/
|
45
|
+
destroy(): void;
|
46
|
+
private initialise;
|
47
|
+
private validateOptions;
|
48
|
+
private destroyAndRebuild;
|
49
|
+
private removeMessageListener;
|
50
|
+
private runFunction;
|
51
|
+
private runCode;
|
52
|
+
private createFrame;
|
53
|
+
private prepareFrameContent;
|
54
|
+
}
|
@@ -0,0 +1,146 @@
|
|
1
|
+
import Connection from './connection';
|
2
|
+
import frameSource from './frame';
|
3
|
+
import { generateUUID } from '../generateUUID';
|
4
|
+
export const BaseOptions = {
|
5
|
+
frameContainer: 'body',
|
6
|
+
debugMode: false,
|
7
|
+
contextVariable: 'ctx',
|
8
|
+
timeout: {
|
9
|
+
minimumMs: 1000,
|
10
|
+
maximumMs: 1500,
|
11
|
+
},
|
12
|
+
};
|
13
|
+
/** A sandbox for running untrusted code in an iframe & embedded web worker.
|
14
|
+
*
|
15
|
+
* This is a wrapper around the iframe and web worker that provides a simple API for running code in the sandbox.
|
16
|
+
* It also provides a context object that can be used to pass data into the sandbox.
|
17
|
+
*/
|
18
|
+
export default class WebSandbox {
|
19
|
+
static async new(options = {}) {
|
20
|
+
const sandbox = new WebSandbox(options);
|
21
|
+
await sandbox.initialised;
|
22
|
+
return sandbox;
|
23
|
+
}
|
24
|
+
constructor(options) {
|
25
|
+
this.options = { ...BaseOptions, ...options };
|
26
|
+
this.frame = this.createFrame();
|
27
|
+
this.validateOptions(this.options);
|
28
|
+
this.initialised = this.initialise();
|
29
|
+
}
|
30
|
+
/** Runs code in the sandbox. Can be either a string or a function */
|
31
|
+
async run(code, context, options) {
|
32
|
+
if (typeof code === 'function') {
|
33
|
+
return this.runFunction(code, context);
|
34
|
+
}
|
35
|
+
return this.runCode(code, context, options);
|
36
|
+
}
|
37
|
+
/** Destroys the sandbox.
|
38
|
+
*
|
39
|
+
* This will remove the iframe from the DOM and remove the message listener.
|
40
|
+
*/
|
41
|
+
destroy() {
|
42
|
+
this.frame.remove();
|
43
|
+
this.removeMessageListener();
|
44
|
+
}
|
45
|
+
initialise() {
|
46
|
+
return new Promise((resolve) => {
|
47
|
+
this.connection = new Connection('SANDBOX', this.frame.contentWindow.postMessage.bind(this.frame.contentWindow), {
|
48
|
+
iframeInitialised: () => resolve(),
|
49
|
+
}, (listener) => {
|
50
|
+
const sourceCheckListener = (event) => {
|
51
|
+
if (event.source !== this.frame.contentWindow) {
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
return listener(event);
|
55
|
+
};
|
56
|
+
window.addEventListener('message', sourceCheckListener);
|
57
|
+
this.removeMessageListener = () => window.removeEventListener('message', sourceCheckListener);
|
58
|
+
}, { allowedSenderOrigin: 'null', debugMode: this.options.debugMode });
|
59
|
+
});
|
60
|
+
}
|
61
|
+
validateOptions(options) {
|
62
|
+
const minimumTimeout = options.timeout.minimumMs;
|
63
|
+
const maximumTimeout = options.timeout.maximumMs;
|
64
|
+
if (maximumTimeout < minimumTimeout) {
|
65
|
+
throw new Error(`maximum timeout (${maximumTimeout}ms) must be greater than or equal to minimum timeout (${minimumTimeout}ms)`);
|
66
|
+
}
|
67
|
+
if (minimumTimeout <= 0 || maximumTimeout <= 0) {
|
68
|
+
throw new Error('timeout values must be greater than 0');
|
69
|
+
}
|
70
|
+
if (maximumTimeout > 5000) {
|
71
|
+
throw new Error('maximum timeout must be less than or equal to 5000ms');
|
72
|
+
}
|
73
|
+
}
|
74
|
+
async destroyAndRebuild() {
|
75
|
+
this.destroy();
|
76
|
+
this.frame = this.createFrame();
|
77
|
+
await this.initialise();
|
78
|
+
}
|
79
|
+
removeMessageListener() {
|
80
|
+
// replaced by constructor
|
81
|
+
}
|
82
|
+
async runFunction(fn, context, options) {
|
83
|
+
return this.runCode(`(${fn.toString()})()`, context, options);
|
84
|
+
}
|
85
|
+
async runCode(code, context, options) {
|
86
|
+
if (!this.connection) {
|
87
|
+
throw new Error('sandbox not initialised');
|
88
|
+
}
|
89
|
+
this.validateOptions({
|
90
|
+
...this.options,
|
91
|
+
...options,
|
92
|
+
});
|
93
|
+
let timerId;
|
94
|
+
const timeout = new Promise((_, reject) => {
|
95
|
+
timerId = setTimeout(() => {
|
96
|
+
this.destroyAndRebuild().finally(() => reject(new Error('sandbox timed out')));
|
97
|
+
}, options?.timeout?.maximumMs ?? this.options.timeout.maximumMs);
|
98
|
+
});
|
99
|
+
const taskId = generateUUID();
|
100
|
+
const task = await this.connection.callRemoteMethod('startTask', {
|
101
|
+
id: taskId,
|
102
|
+
code,
|
103
|
+
context,
|
104
|
+
timeout: this.options.timeout.minimumMs,
|
105
|
+
contextVariable: options?.contextVariable ?? this.options.contextVariable,
|
106
|
+
});
|
107
|
+
return Promise.race([task, timeout]).finally(() => {
|
108
|
+
clearTimeout(timerId);
|
109
|
+
});
|
110
|
+
}
|
111
|
+
createFrame() {
|
112
|
+
const containerSelector = this.options.frameContainer;
|
113
|
+
const container = typeof containerSelector === 'string' ? document.querySelector(containerSelector) : containerSelector;
|
114
|
+
if (!container) {
|
115
|
+
throw new Error('unable to find container for sandbox');
|
116
|
+
}
|
117
|
+
const iframe = document.createElement('iframe');
|
118
|
+
if (iframe.sandbox) {
|
119
|
+
iframe.sandbox.add('allow-scripts');
|
120
|
+
}
|
121
|
+
else {
|
122
|
+
iframe.setAttribute('sandbox', 'allow-scripts');
|
123
|
+
}
|
124
|
+
iframe.srcdoc = this.prepareFrameContent();
|
125
|
+
iframe.style.display = 'none';
|
126
|
+
container.appendChild(iframe);
|
127
|
+
return iframe;
|
128
|
+
}
|
129
|
+
prepareFrameContent() {
|
130
|
+
let script = frameSource;
|
131
|
+
if (this.options.debugMode) {
|
132
|
+
script = `window.debugMode=true;${script}`;
|
133
|
+
}
|
134
|
+
return `
|
135
|
+
<!DOCTYPE html>
|
136
|
+
<html>
|
137
|
+
<head>
|
138
|
+
<meta charset="UTF-8">
|
139
|
+
<script>
|
140
|
+
${script}
|
141
|
+
</script>
|
142
|
+
</head>
|
143
|
+
</html>
|
144
|
+
`;
|
145
|
+
}
|
146
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
type APIMethod = (...args: any[]) => unknown;
|
2
|
+
export type API = Map<string, APIMethod>;
|
3
|
+
export type APIDeclaration<T> = {
|
4
|
+
[K in keyof T]: T[K] extends APIMethod ? T[K] : never;
|
5
|
+
};
|
6
|
+
export interface Task {
|
7
|
+
id: string;
|
8
|
+
code: string;
|
9
|
+
context?: unknown;
|
10
|
+
timeout: number;
|
11
|
+
contextVariable?: string;
|
12
|
+
}
|
13
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/models/RocosError.d.ts
CHANGED
package/models/RocosError.js
CHANGED
@@ -22,6 +22,7 @@ export const errorCodes = {
|
|
22
22
|
SCHEDULE_SERVICE_ERROR: 'SCHEDULE_SERVICE_ERROR',
|
23
23
|
INTEGRATIONS_SERVICE_ERROR: 'INTEGRATIONS_SERVICE_ERROR',
|
24
24
|
MAPS_SERVICE_ERROR: 'MAPS_SERVICE_ERROR',
|
25
|
+
EVALUATOR_SERVICE_ERROR: 'EVALUATOR_SERVICE_ERROR',
|
25
26
|
};
|
26
27
|
export class RocosError extends Error {
|
27
28
|
constructor(err, code, statusCode) {
|
package/models/ServiceEnum.d.ts
CHANGED
package/models/ServiceEnum.js
CHANGED
package/node/RocosSDKNode.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ScheduleService } from '../services';
|
1
|
+
import { EvaluatorService, ScheduleService } from '../services';
|
2
2
|
import { CallerServiceNode } from '../services/CallerServiceNode';
|
3
3
|
import { CommandServiceNode } from '../services/CommandServiceNode';
|
4
4
|
import { ControlServiceNode } from '../services/ControlServiceNode';
|
@@ -39,4 +39,9 @@ export declare class RocosSDKNode extends RocosSDK {
|
|
39
39
|
* @returns FileAccessorServiceNode
|
40
40
|
*/
|
41
41
|
getFileAccessorService(): FileAccessorServiceNode;
|
42
|
+
/**
|
43
|
+
* Gets the evaluator service
|
44
|
+
* @returns EvaluatorServiceNode
|
45
|
+
*/
|
46
|
+
getEvaluatorService(): EvaluatorService;
|
42
47
|
}
|
package/node/RocosSDKNode.js
CHANGED
@@ -140,4 +140,11 @@ export class RocosSDKNode extends RocosSDK {
|
|
140
140
|
getFileAccessorService() {
|
141
141
|
return this.getService(ServiceEnum.FILE_ACCESSOR);
|
142
142
|
}
|
143
|
+
/**
|
144
|
+
* Gets the evaluator service
|
145
|
+
* @returns EvaluatorServiceNode
|
146
|
+
*/
|
147
|
+
getEvaluatorService() {
|
148
|
+
throw new Error('Evaluator service is not supported in NodeJS');
|
149
|
+
}
|
143
150
|
}
|
package/package.json
CHANGED
@@ -110,7 +110,7 @@ export class AssetStorageService extends BaseServiceAbstract {
|
|
110
110
|
*/
|
111
111
|
async listMissionAssets(projectId, assetIdList) {
|
112
112
|
const searchParams = new URLSearchParams();
|
113
|
-
assetIdList.forEach((assetId) => searchParams.append('
|
113
|
+
assetIdList.forEach((assetId) => searchParams.append('assetID', assetId));
|
114
114
|
return this.callGet(formatServiceUrl(API_PROJECT_MISSION_ASSETS_PATH_URL, { url: this.config.url, projectId }, this.config.insecure), `Failed to get asset for ${projectId}, assetIdList ${assetIdList}.`, searchParams);
|
115
115
|
}
|
116
116
|
/**
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { IRocosSDKConfig, RocosError } from '../models';
|
2
|
+
import { QueryParams } from '../helpers';
|
2
3
|
import { Logger } from 'loglevel';
|
3
|
-
type QueryParams = Record<string, string | number | boolean> | URLSearchParams;
|
4
4
|
type ResponseType = 'json' | 'blob' | 'stream' | 'text' | 'raw';
|
5
5
|
interface RequestConfig {
|
6
6
|
/**
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { RocosError } from '../models';
|
2
|
+
import { getURLSearchParams } from '../helpers';
|
2
3
|
import { RocosStore } from '../store/RocosStore';
|
3
4
|
class HttpError extends Error {
|
4
5
|
constructor(response) {
|
@@ -26,12 +27,7 @@ export class BaseServiceAbstract {
|
|
26
27
|
async call(url, method, options) {
|
27
28
|
const { errorMessage, config, payload, params } = options;
|
28
29
|
try {
|
29
|
-
|
30
|
-
const stringParams = Object.entries(params ?? {}).reduce((acc, [key, value]) => {
|
31
|
-
acc[key] = value.toString();
|
32
|
-
return acc;
|
33
|
-
}, {});
|
34
|
-
const formattedUrl = params ? `${url}?${new URLSearchParams(stringParams)}` : url;
|
30
|
+
const formattedUrl = params ? `${url}?${getURLSearchParams(params)}` : url;
|
35
31
|
const defaultHeaders = {};
|
36
32
|
if (!config?.public) {
|
37
33
|
const token = await RocosStore.getSDKInstance(this.config).getAuthService().getToken();
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { IBaseService, IRocosSDKConfig, RocosError } from '../models';
|
2
|
+
import { BaseServiceAbstract } from './BaseServiceAbstract';
|
3
|
+
import { RunCodeOptions } from '../helpers/websandbox/sandbox';
|
4
|
+
export declare class EvaluatorService extends BaseServiceAbstract implements IBaseService {
|
5
|
+
private readonly sandbox;
|
6
|
+
constructor(config: IRocosSDKConfig);
|
7
|
+
protected getError(e: Error): RocosError;
|
8
|
+
getStatus(): boolean;
|
9
|
+
teardown(): Promise<void>;
|
10
|
+
execute<T = unknown>(code: string | (() => T), context?: unknown, options?: RunCodeOptions): Promise<T>;
|
11
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { RocosError, errorCodes } from '../models';
|
2
|
+
import { BaseServiceAbstract } from './BaseServiceAbstract';
|
3
|
+
import { RocosLogger } from '../logger/RocosLogger';
|
4
|
+
import { WebSandbox } from '../helpers';
|
5
|
+
export class EvaluatorService extends BaseServiceAbstract {
|
6
|
+
constructor(config) {
|
7
|
+
super(config);
|
8
|
+
this.logger = RocosLogger.getInstance(`EvaluatorService(${this.config.url})`);
|
9
|
+
this.sandbox = WebSandbox.new().catch((e) => {
|
10
|
+
this.logger.error('Failed to create WebSandbox', e);
|
11
|
+
throw e;
|
12
|
+
});
|
13
|
+
}
|
14
|
+
getError(e) {
|
15
|
+
return new RocosError(e, errorCodes.EVALUATOR_SERVICE_ERROR);
|
16
|
+
}
|
17
|
+
getStatus() {
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
async teardown() {
|
21
|
+
const sandbox = await this.sandbox;
|
22
|
+
sandbox.destroy();
|
23
|
+
}
|
24
|
+
async execute(code, context, options) {
|
25
|
+
const sandbox = await this.sandbox;
|
26
|
+
return sandbox.run(code, context, options);
|
27
|
+
}
|
28
|
+
}
|
package/services/MapService.d.ts
CHANGED
@@ -102,6 +102,7 @@ export declare class MapService extends BaseServiceAbstract implements IBaseServ
|
|
102
102
|
*
|
103
103
|
* @param projectId Project ID
|
104
104
|
* @param mapId Map ID
|
105
|
+
* @param frameId Frame ID (optional)
|
105
106
|
*/
|
106
|
-
getGeoJSON(projectId: string, mapId: string): Promise<unknown>;
|
107
|
+
getGeoJSON(projectId: string, mapId: string, frameId?: string): Promise<unknown>;
|
107
108
|
}
|
package/services/MapService.js
CHANGED
@@ -138,12 +138,14 @@ export class MapService extends BaseServiceAbstract {
|
|
138
138
|
*
|
139
139
|
* @param projectId Project ID
|
140
140
|
* @param mapId Map ID
|
141
|
+
* @param frameId Frame ID (optional)
|
141
142
|
*/
|
142
|
-
async getGeoJSON(projectId, mapId) {
|
143
|
-
|
143
|
+
async getGeoJSON(projectId, mapId, frameId) {
|
144
|
+
const params = {
|
144
145
|
url: this.config.url,
|
145
146
|
projectId,
|
146
147
|
mapId,
|
147
|
-
}
|
148
|
+
};
|
149
|
+
return this.callGet(formatServiceUrl(API_MAPS_GEOJSON_URL, params, this.config.insecure), 'Failed to get map GeoJSON.', frameId ? { frameID: frameId } : undefined);
|
148
150
|
}
|
149
151
|
}
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import { TelemetryService } from './TelemetryService';
|
2
|
-
import { delay, from, lastValueFrom, NEVER, take, throwError } from 'rxjs';
|
3
1
|
import { CallsignStatus } from '../models';
|
2
|
+
import { NEVER, delay, from, lastValueFrom, take, throwError } from 'rxjs';
|
3
|
+
import { TelemetryService } from './TelemetryService';
|
4
4
|
describe('TelemetryService', () => {
|
5
5
|
describe('getRobotStatusChanges', () => {
|
6
6
|
it('should emit unknown to begin with', async () => {
|
package/services/index.d.ts
CHANGED
package/services/index.js
CHANGED