@momo2555/koppeliajs 0.0.91
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/README.md +110 -0
- package/dist/components/DynamicCursor.svelte +0 -0
- package/dist/components/DynamicCursor.svelte.d.ts +26 -0
- package/dist/components/DynamicTextField.svelte +0 -0
- package/dist/components/DynamicTextField.svelte.d.ts +26 -0
- package/dist/components/GrowableElement.svelte +62 -0
- package/dist/components/GrowableElement.svelte.d.ts +29 -0
- package/dist/components/KBase.svelte +8 -0
- package/dist/components/KBase.svelte.d.ts +22 -0
- package/dist/components/KButton.svelte +0 -0
- package/dist/components/KButton.svelte.d.ts +26 -0
- package/dist/components/Koppelia.svelte +11 -0
- package/dist/components/Koppelia.svelte.d.ts +20 -0
- package/dist/components/ResizableText.svelte +0 -0
- package/dist/components/ResizableText.svelte.d.ts +26 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/dist/scripts/console.d.ts +75 -0
- package/dist/scripts/console.js +180 -0
- package/dist/scripts/device.d.ts +49 -0
- package/dist/scripts/device.js +123 -0
- package/dist/scripts/game.d.ts +5 -0
- package/dist/scripts/game.js +8 -0
- package/dist/scripts/koppelia.d.ts +70 -0
- package/dist/scripts/koppelia.js +196 -0
- package/dist/scripts/koppeliaWebsocket.d.ts +77 -0
- package/dist/scripts/koppeliaWebsocket.js +159 -0
- package/dist/scripts/message.d.ts +116 -0
- package/dist/scripts/message.js +178 -0
- package/dist/scripts/play.d.ts +49 -0
- package/dist/scripts/play.js +107 -0
- package/dist/scripts/stage.d.ts +12 -0
- package/dist/scripts/stage.js +38 -0
- package/dist/scripts/state.d.ts +36 -0
- package/dist/scripts/state.js +82 -0
- package/dist/scripts/utils.d.ts +1 -0
- package/dist/scripts/utils.js +5 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/koppeliaServerApi.d.ts +7 -0
- package/dist/server/koppeliaServerApi.js +97 -0
- package/dist/stores/routeStore.d.ts +2 -0
- package/dist/stores/routeStore.js +21 -0
- package/dist/stores/stateStore.d.ts +1 -0
- package/dist/stores/stateStore.js +7 -0
- package/package.json +64 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Console } from './console.js';
|
|
2
|
+
/**
|
|
3
|
+
* This class reprensts a device
|
|
4
|
+
*/
|
|
5
|
+
type Color = {
|
|
6
|
+
r: number;
|
|
7
|
+
g: number;
|
|
8
|
+
b: number;
|
|
9
|
+
};
|
|
10
|
+
export declare class Device {
|
|
11
|
+
private _address;
|
|
12
|
+
private _color;
|
|
13
|
+
private _name;
|
|
14
|
+
private _console;
|
|
15
|
+
private _attachedEvents;
|
|
16
|
+
constructor(console: Console, address?: string);
|
|
17
|
+
set color(color: Color);
|
|
18
|
+
get color(): Color;
|
|
19
|
+
ping(): void;
|
|
20
|
+
onEvent(eventName: string, callback: () => void): void;
|
|
21
|
+
onZPosition(callback: (z: number) => void): void;
|
|
22
|
+
onVerticalDetector(callback: (vertical: boolean) => void): void;
|
|
23
|
+
private _attachEvent;
|
|
24
|
+
private _enableModule;
|
|
25
|
+
setColor(color: Color): void;
|
|
26
|
+
/**
|
|
27
|
+
* Vibrate the device (use the motor vibrator)
|
|
28
|
+
* @param time
|
|
29
|
+
* @param blink
|
|
30
|
+
* @param blinkOff
|
|
31
|
+
* @param blinkCount
|
|
32
|
+
*/
|
|
33
|
+
vibrate(time: number, blink?: boolean, blinkOff?: number, blinkCount?: number): void;
|
|
34
|
+
/**
|
|
35
|
+
* Convert this device object to a json object
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
toObject(): {
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* set the device object from a json object
|
|
43
|
+
* @param object
|
|
44
|
+
*/
|
|
45
|
+
fromObject(object: {
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
}): void;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Console } from './console.js';
|
|
2
|
+
import { Message, MessageType, PeerType } from './message.js';
|
|
3
|
+
export class Device {
|
|
4
|
+
_address;
|
|
5
|
+
_color;
|
|
6
|
+
_name;
|
|
7
|
+
_console;
|
|
8
|
+
_attachedEvents;
|
|
9
|
+
constructor(console, address = "") {
|
|
10
|
+
this._address = address;
|
|
11
|
+
this._color = { r: 0, g: 0, b: 0 };
|
|
12
|
+
this._name = "";
|
|
13
|
+
this._console = console;
|
|
14
|
+
this._attachedEvents = [];
|
|
15
|
+
}
|
|
16
|
+
set color(color) {
|
|
17
|
+
this._color = color;
|
|
18
|
+
// TODO : send a request to change the color
|
|
19
|
+
}
|
|
20
|
+
get color() {
|
|
21
|
+
return this._color;
|
|
22
|
+
}
|
|
23
|
+
ping() {
|
|
24
|
+
}
|
|
25
|
+
onEvent(eventName, callback) {
|
|
26
|
+
this._attachEvent(eventName);
|
|
27
|
+
this._console.onDeviceEvent(callback);
|
|
28
|
+
}
|
|
29
|
+
onZPosition(callback) {
|
|
30
|
+
this._enableModule("zPos");
|
|
31
|
+
this._attachEvent("zPosition");
|
|
32
|
+
this._console.onRequest((request, params, form, address) => {
|
|
33
|
+
if (request == "zPosition" && address == this._address) {
|
|
34
|
+
callback(params.value);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
onVerticalDetector(callback) {
|
|
39
|
+
this._enableModule("vDetct");
|
|
40
|
+
this._attachEvent("verticalDetector");
|
|
41
|
+
this._console.onRequest((request, params, form, address) => {
|
|
42
|
+
if (request == "verticalDetector" && address == this._address) {
|
|
43
|
+
callback(params.value);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
_attachEvent(event) {
|
|
48
|
+
if (!(event in this._attachedEvents)) {
|
|
49
|
+
let request = new Message();
|
|
50
|
+
request.addParam("event", event);
|
|
51
|
+
request.setDestination(PeerType.DEVICE, this._address);
|
|
52
|
+
request.setRequest("attachEvent");
|
|
53
|
+
this._console.sendMessage(request);
|
|
54
|
+
this._attachedEvents.push(event);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
_enableModule(moduleNmae) {
|
|
58
|
+
let request = new Message();
|
|
59
|
+
request.addParam("module", moduleNmae);
|
|
60
|
+
request.setDestination(PeerType.DEVICE, this._address);
|
|
61
|
+
request.setRequest("enableModule");
|
|
62
|
+
this._console.sendMessage(request);
|
|
63
|
+
}
|
|
64
|
+
setColor(color) {
|
|
65
|
+
console.log("Set Color");
|
|
66
|
+
this._color = color;
|
|
67
|
+
let request = new Message();
|
|
68
|
+
request.addParam("color", color);
|
|
69
|
+
request.setDestination(PeerType.DEVICE, this._address);
|
|
70
|
+
request.setRequest("setColor");
|
|
71
|
+
console.log("Set Color request", request);
|
|
72
|
+
this._console.sendMessage(request);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Vibrate the device (use the motor vibrator)
|
|
76
|
+
* @param time
|
|
77
|
+
* @param blink
|
|
78
|
+
* @param blinkOff
|
|
79
|
+
* @param blinkCount
|
|
80
|
+
*/
|
|
81
|
+
vibrate(time, blink = false, blinkOff = 0, blinkCount = 0) {
|
|
82
|
+
let vibration = {
|
|
83
|
+
v: time,
|
|
84
|
+
toff: 0,
|
|
85
|
+
c: 1
|
|
86
|
+
};
|
|
87
|
+
if (blink) {
|
|
88
|
+
vibration.toff = blinkOff;
|
|
89
|
+
vibration.c = blinkCount;
|
|
90
|
+
}
|
|
91
|
+
let request = new Message();
|
|
92
|
+
request.addParam("vibration", vibration);
|
|
93
|
+
request.setDestination(PeerType.DEVICE, this._address);
|
|
94
|
+
request.setRequest("vibrate");
|
|
95
|
+
this._console.sendMessage(request);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Convert this device object to a json object
|
|
99
|
+
* @returns
|
|
100
|
+
*/
|
|
101
|
+
toObject() {
|
|
102
|
+
return {
|
|
103
|
+
"address": this._address,
|
|
104
|
+
"color": this._color,
|
|
105
|
+
"name": this._name
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* set the device object from a json object
|
|
110
|
+
* @param object
|
|
111
|
+
*/
|
|
112
|
+
fromObject(object) {
|
|
113
|
+
if (object.address !== undefined) {
|
|
114
|
+
this._address = object.address;
|
|
115
|
+
}
|
|
116
|
+
if (object.color !== undefined) {
|
|
117
|
+
this._color = object.color;
|
|
118
|
+
}
|
|
119
|
+
if (object.name !== undefined) {
|
|
120
|
+
this._name = object.name;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type Writable } from "svelte/store";
|
|
2
|
+
import { type AnyState } from "./state.js";
|
|
3
|
+
import { Device } from "./device.js";
|
|
4
|
+
import { Play } from "./play.js";
|
|
5
|
+
export declare class Koppelia {
|
|
6
|
+
private _console;
|
|
7
|
+
private _state;
|
|
8
|
+
private _stage;
|
|
9
|
+
private static _instance;
|
|
10
|
+
constructor();
|
|
11
|
+
static get instance(): Koppelia;
|
|
12
|
+
get state(): Writable<AnyState>;
|
|
13
|
+
updateState(stateUpdate: AnyState): void;
|
|
14
|
+
setState(newState: AnyState): void;
|
|
15
|
+
get ready(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Add a callback that will be called when the connection to the console is entirely ready
|
|
18
|
+
*
|
|
19
|
+
* @param callback
|
|
20
|
+
*/
|
|
21
|
+
onReady(callback: () => void): void;
|
|
22
|
+
/**
|
|
23
|
+
* Init the default state of the game and the list of all stages
|
|
24
|
+
*
|
|
25
|
+
* @param defaultState Default state that be initialized
|
|
26
|
+
* @param stages List of all stages
|
|
27
|
+
*/
|
|
28
|
+
init(defaultState: AnyState, stages: string[]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Go to a stage, the stage must be in the stage list
|
|
31
|
+
* If the stage list is empty the console will return an error
|
|
32
|
+
* @param stageName
|
|
33
|
+
*/
|
|
34
|
+
goto(stageName: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get the list of devices in a callback
|
|
37
|
+
* @param callback
|
|
38
|
+
*/
|
|
39
|
+
getDevices(): Promise<Device[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the game ID of the current game
|
|
42
|
+
* @returns the game id as a string
|
|
43
|
+
*/
|
|
44
|
+
getGameId(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Get the list of plays
|
|
47
|
+
* @param count limit of plays to get
|
|
48
|
+
* @param index index from which to start fetching the plays
|
|
49
|
+
* @param orderBy order by date or name
|
|
50
|
+
* @returns the List of plays an array of objects of type Play
|
|
51
|
+
*/
|
|
52
|
+
getPlays(count?: number, index?: number, orderBy?: string): Promise<Play[]>;
|
|
53
|
+
/**
|
|
54
|
+
* This function enables the difficulty cursor, to change the difficulty in live when playing from Koppeli'App
|
|
55
|
+
* @param callback : callback to call when difficulty changes
|
|
56
|
+
*/
|
|
57
|
+
enableDifficultyCursor(callback: (difficulty: number) => void): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param id
|
|
61
|
+
* @param onGrowChange
|
|
62
|
+
*/
|
|
63
|
+
registerNewGrowableElement(id: string, onGrowChange: (grown: boolean) => void): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
* @param id
|
|
67
|
+
* @param grown
|
|
68
|
+
*/
|
|
69
|
+
updateGrowableElement(id: string, grown: boolean): Promise<void>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { get } from "svelte/store";
|
|
2
|
+
import { routeType } from "../stores/routeStore.js";
|
|
3
|
+
import { Console } from "./console.js";
|
|
4
|
+
import { State } from "./state.js";
|
|
5
|
+
import { Message, PeerType } from "./message.js";
|
|
6
|
+
import { Stage } from "./stage.js";
|
|
7
|
+
import { Device } from "./device.js";
|
|
8
|
+
import { Play } from "./play.js";
|
|
9
|
+
import { PUBLIC_GAME_ID } from '$env/static/public';
|
|
10
|
+
export class Koppelia {
|
|
11
|
+
_console;
|
|
12
|
+
_state;
|
|
13
|
+
_stage;
|
|
14
|
+
static _instance;
|
|
15
|
+
constructor() {
|
|
16
|
+
this._console = new Console();
|
|
17
|
+
this._console.onReady(() => {
|
|
18
|
+
let type = get(routeType);
|
|
19
|
+
if (type == "controller") {
|
|
20
|
+
console.log("identify controller");
|
|
21
|
+
this._console.identify(PeerType.CONTROLLER);
|
|
22
|
+
}
|
|
23
|
+
else if (type == "monitor") {
|
|
24
|
+
console.log("identify monitor");
|
|
25
|
+
this._console.identify(PeerType.MONITOR);
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
console.log("Cannot identifiy type ", type);
|
|
29
|
+
});
|
|
30
|
+
this._state = new State(this._console, {
|
|
31
|
+
hey: "coucou"
|
|
32
|
+
});
|
|
33
|
+
this._stage = new Stage(this._console);
|
|
34
|
+
}
|
|
35
|
+
static get instance() {
|
|
36
|
+
if (!Koppelia._instance) {
|
|
37
|
+
Koppelia._instance = new Koppelia();
|
|
38
|
+
}
|
|
39
|
+
return Koppelia._instance;
|
|
40
|
+
}
|
|
41
|
+
get state() {
|
|
42
|
+
return this._state.state;
|
|
43
|
+
}
|
|
44
|
+
updateState(stateUpdate) {
|
|
45
|
+
this._state.updateState(stateUpdate);
|
|
46
|
+
}
|
|
47
|
+
setState(newState) {
|
|
48
|
+
this._state.setState(newState);
|
|
49
|
+
}
|
|
50
|
+
get ready() {
|
|
51
|
+
return this._console.ready;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Add a callback that will be called when the connection to the console is entirely ready
|
|
55
|
+
*
|
|
56
|
+
* @param callback
|
|
57
|
+
*/
|
|
58
|
+
onReady(callback) {
|
|
59
|
+
this._console.onReady(callback);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Init the default state of the game and the list of all stages
|
|
63
|
+
*
|
|
64
|
+
* @param defaultState Default state that be initialized
|
|
65
|
+
* @param stages List of all stages
|
|
66
|
+
*/
|
|
67
|
+
init(defaultState, stages) {
|
|
68
|
+
this._console.onReady(() => {
|
|
69
|
+
let type = get(routeType);
|
|
70
|
+
if (type == "controller") {
|
|
71
|
+
this._state.setState(defaultState); // set the state
|
|
72
|
+
this._stage.initStages(stages); // init the list of stages
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Go to a stage, the stage must be in the stage list
|
|
78
|
+
* If the stage list is empty the console will return an error
|
|
79
|
+
* @param stageName
|
|
80
|
+
*/
|
|
81
|
+
goto(stageName) {
|
|
82
|
+
this._stage.goto(stageName);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the list of devices in a callback
|
|
86
|
+
* @param callback
|
|
87
|
+
*/
|
|
88
|
+
async getDevices() {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
// create the message to request the devices
|
|
91
|
+
let getDevicesRequest = new Message();
|
|
92
|
+
getDevicesRequest.setRequest("getDevices");
|
|
93
|
+
getDevicesRequest.setDestination(PeerType.MASTER, "");
|
|
94
|
+
// send the message to the console
|
|
95
|
+
this._console.sendMessage(getDevicesRequest, (response) => {
|
|
96
|
+
// convert the response to al list of device objects
|
|
97
|
+
let devices_raw = response.getParam("devices", []);
|
|
98
|
+
let devices = [];
|
|
99
|
+
for (let device_raw of devices_raw) {
|
|
100
|
+
let device = new Device(this._console);
|
|
101
|
+
device.fromObject(device_raw);
|
|
102
|
+
devices.push(device);
|
|
103
|
+
}
|
|
104
|
+
resolve(devices);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get the game ID of the current game
|
|
110
|
+
* @returns the game id as a string
|
|
111
|
+
*/
|
|
112
|
+
getGameId() {
|
|
113
|
+
return PUBLIC_GAME_ID;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the list of plays
|
|
117
|
+
* @param count limit of plays to get
|
|
118
|
+
* @param index index from which to start fetching the plays
|
|
119
|
+
* @param orderBy order by date or name
|
|
120
|
+
* @returns the List of plays an array of objects of type Play
|
|
121
|
+
*/
|
|
122
|
+
async getPlays(count = 10, index = 0, orderBy = "date") {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
let getPlaysRequest = new Message();
|
|
125
|
+
getPlaysRequest.setRequest("getPlaysList");
|
|
126
|
+
getPlaysRequest.addParam("gameId", this.getGameId());
|
|
127
|
+
getPlaysRequest.addParam("count", count);
|
|
128
|
+
getPlaysRequest.addParam("index", index);
|
|
129
|
+
getPlaysRequest.addParam("orderBy", orderBy);
|
|
130
|
+
getPlaysRequest.setDestination(PeerType.MASTER, "");
|
|
131
|
+
this._console.sendMessage(getPlaysRequest, (response) => {
|
|
132
|
+
let playsRawList = response.getParam("plays", {});
|
|
133
|
+
let plays = [];
|
|
134
|
+
for (let playId in playsRawList) {
|
|
135
|
+
plays.push(new Play(this._console, playId, playsRawList[playId]));
|
|
136
|
+
}
|
|
137
|
+
resolve(plays);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* This function enables the difficulty cursor, to change the difficulty in live when playing from Koppeli'App
|
|
143
|
+
* @param callback : callback to call when difficulty changes
|
|
144
|
+
*/
|
|
145
|
+
async enableDifficultyCursor(callback) {
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
*
|
|
149
|
+
* @param id
|
|
150
|
+
* @param onGrowChange
|
|
151
|
+
*/
|
|
152
|
+
async registerNewGrowableElement(id, onGrowChange) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
// create the message to request the devices
|
|
155
|
+
if (get(routeType) == "controller") {
|
|
156
|
+
let addGrowableElRequest = new Message();
|
|
157
|
+
addGrowableElRequest.setRequest("addGrowableElement");
|
|
158
|
+
addGrowableElRequest.addParam("id", id);
|
|
159
|
+
addGrowableElRequest.setDestination(PeerType.MASTER, "");
|
|
160
|
+
// send the message to the console (only the controller sends the )
|
|
161
|
+
this._console.sendMessage(addGrowableElRequest, (response) => {
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
this._console.onRequest((req, params) => {
|
|
165
|
+
if (req == "gowableElementNotification") {
|
|
166
|
+
if (params.id !== undefined && params.id == id) {
|
|
167
|
+
let grown = false;
|
|
168
|
+
if (params.grown != undefined)
|
|
169
|
+
grown = params.grown;
|
|
170
|
+
onGrowChange(grown);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
resolve();
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
*
|
|
179
|
+
* @param id
|
|
180
|
+
* @param grown
|
|
181
|
+
*/
|
|
182
|
+
async updateGrowableElement(id, grown) {
|
|
183
|
+
return new Promise((resolve, reject) => {
|
|
184
|
+
// create the message to request the devices
|
|
185
|
+
let addGrowableElRequest = new Message();
|
|
186
|
+
addGrowableElRequest.setRequest("updateGrowableElement");
|
|
187
|
+
addGrowableElRequest.addParam("id", id);
|
|
188
|
+
addGrowableElRequest.addParam("grown", grown);
|
|
189
|
+
addGrowableElRequest.setDestination(PeerType.MASTER, "");
|
|
190
|
+
// send the message to the console
|
|
191
|
+
this._console.sendMessage(addGrowableElRequest, (response) => {
|
|
192
|
+
resolve();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Message } from "./message.js";
|
|
2
|
+
export type Callback = (response: Message) => void;
|
|
3
|
+
type OnGoingRequest = {
|
|
4
|
+
requestId: string;
|
|
5
|
+
callback?: Callback;
|
|
6
|
+
};
|
|
7
|
+
export declare class KoppeliaWebsocket {
|
|
8
|
+
socket?: WebSocket;
|
|
9
|
+
onGoingRequests: OnGoingRequest[];
|
|
10
|
+
timeout: number;
|
|
11
|
+
receiveCallbacks: Callback[];
|
|
12
|
+
openCallback?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Constructor of the Koppelia websocket class
|
|
15
|
+
* @param websocketUrl
|
|
16
|
+
* @param timeout
|
|
17
|
+
*/
|
|
18
|
+
constructor(websocketUrl: string, timeout?: number);
|
|
19
|
+
/**
|
|
20
|
+
* Send a new request: Add a request Id to the request and add it to the ongoing requests
|
|
21
|
+
* Add an interval to timeout when there is no response after a certain amount of time
|
|
22
|
+
* @param data
|
|
23
|
+
* @param callback
|
|
24
|
+
*/
|
|
25
|
+
send(data: Message, callback?: Callback): void;
|
|
26
|
+
/**
|
|
27
|
+
* Add a receive callback
|
|
28
|
+
* @param callback
|
|
29
|
+
*/
|
|
30
|
+
onReceive(callback: Callback): void;
|
|
31
|
+
/**
|
|
32
|
+
* Define a callback for the websocket open event
|
|
33
|
+
* @param callback
|
|
34
|
+
*/
|
|
35
|
+
onOpen(callback: () => void): void;
|
|
36
|
+
/**
|
|
37
|
+
* Generate a new request Id
|
|
38
|
+
* @returns (string): a nex resuest id
|
|
39
|
+
*/
|
|
40
|
+
private _generateRequestId;
|
|
41
|
+
/**
|
|
42
|
+
* Handle a websocket response
|
|
43
|
+
* - Execute a callback of a reception if a request was send before (by checking ongoing request)
|
|
44
|
+
* - Execute a callbacj for a genral reception response
|
|
45
|
+
* @param data
|
|
46
|
+
* @returns
|
|
47
|
+
*/
|
|
48
|
+
private _handleWebsocketResponse;
|
|
49
|
+
/**
|
|
50
|
+
* Init all websocker events
|
|
51
|
+
*/
|
|
52
|
+
private _setupEvents;
|
|
53
|
+
/**
|
|
54
|
+
* Timeout the request if there is no response
|
|
55
|
+
* To timout the response, the function simply delete the id from on going request list
|
|
56
|
+
* @param requestId Id of the request
|
|
57
|
+
*/
|
|
58
|
+
private _getRequestIndex;
|
|
59
|
+
/**
|
|
60
|
+
* Delete the request from the list of onGoing Requests
|
|
61
|
+
* @param requestId
|
|
62
|
+
*/
|
|
63
|
+
private _deleteRequest;
|
|
64
|
+
/**
|
|
65
|
+
* get the Ongoing the request and get theh callback
|
|
66
|
+
* @param requestId
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
private _getOnGoingRequest;
|
|
70
|
+
/**
|
|
71
|
+
* Add a new request to ongoing requests
|
|
72
|
+
* @param requestId
|
|
73
|
+
* @param callback
|
|
74
|
+
*/
|
|
75
|
+
private _addNewRequest;
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Message } from "./message.js";
|
|
2
|
+
const DEFAULT_WS_TIMEOUT = 4000;
|
|
3
|
+
export class KoppeliaWebsocket {
|
|
4
|
+
socket = undefined;
|
|
5
|
+
onGoingRequests;
|
|
6
|
+
timeout;
|
|
7
|
+
receiveCallbacks;
|
|
8
|
+
openCallback;
|
|
9
|
+
/* ------ PUBLIC ------ */
|
|
10
|
+
/**
|
|
11
|
+
* Constructor of the Koppelia websocket class
|
|
12
|
+
* @param websocketUrl
|
|
13
|
+
* @param timeout
|
|
14
|
+
*/
|
|
15
|
+
constructor(websocketUrl, timeout = DEFAULT_WS_TIMEOUT) {
|
|
16
|
+
if (!import.meta.env.SSR) {
|
|
17
|
+
this.socket = new WebSocket(websocketUrl);
|
|
18
|
+
console.log("Open new Koppelia websocket connection successfully with url ", websocketUrl);
|
|
19
|
+
this._setupEvents();
|
|
20
|
+
}
|
|
21
|
+
else
|
|
22
|
+
console.log("Koppelia websocket not accessible during server rendering");
|
|
23
|
+
this.onGoingRequests = [];
|
|
24
|
+
this.timeout = timeout;
|
|
25
|
+
this.receiveCallbacks = [];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Send a new request: Add a request Id to the request and add it to the ongoing requests
|
|
29
|
+
* Add an interval to timeout when there is no response after a certain amount of time
|
|
30
|
+
* @param data
|
|
31
|
+
* @param callback
|
|
32
|
+
*/
|
|
33
|
+
send(data, callback) {
|
|
34
|
+
if (this.socket === undefined) {
|
|
35
|
+
console.log("KoppeliaWebsocket::send(): Koppelia websocket client was not instancieated");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Create a request id
|
|
39
|
+
data.generateRequestId();
|
|
40
|
+
this._addNewRequest(data.getRequestId(), callback);
|
|
41
|
+
// Send the request
|
|
42
|
+
const serializedMessage = JSON.stringify(data.toObject());
|
|
43
|
+
console.log("sending message", serializedMessage);
|
|
44
|
+
console.log(this.socket);
|
|
45
|
+
this.socket.send(serializedMessage);
|
|
46
|
+
// set a timeout
|
|
47
|
+
window.setTimeout(() => this._deleteRequest(data.getRequestId()), this.timeout);
|
|
48
|
+
;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Add a receive callback
|
|
52
|
+
* @param callback
|
|
53
|
+
*/
|
|
54
|
+
onReceive(callback) {
|
|
55
|
+
this.receiveCallbacks.push(callback);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Define a callback for the websocket open event
|
|
59
|
+
* @param callback
|
|
60
|
+
*/
|
|
61
|
+
onOpen(callback) {
|
|
62
|
+
this.openCallback = callback;
|
|
63
|
+
}
|
|
64
|
+
/* ------ PRIVATE ------ */
|
|
65
|
+
/**
|
|
66
|
+
* Generate a new request Id
|
|
67
|
+
* @returns (string): a nex resuest id
|
|
68
|
+
*/
|
|
69
|
+
_generateRequestId() {
|
|
70
|
+
return crypto.randomUUID();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Handle a websocket response
|
|
74
|
+
* - Execute a callback of a reception if a request was send before (by checking ongoing request)
|
|
75
|
+
* - Execute a callbacj for a genral reception response
|
|
76
|
+
* @param data
|
|
77
|
+
* @returns
|
|
78
|
+
*/
|
|
79
|
+
_handleWebsocketResponse(data) {
|
|
80
|
+
if (data === undefined) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
let message = new Message();
|
|
84
|
+
message.parse(data);
|
|
85
|
+
if (message.getRequestId() !== undefined) {
|
|
86
|
+
// There is a request id, check if it's a response
|
|
87
|
+
let onGoing = this._getOnGoingRequest(message.getRequestId());
|
|
88
|
+
if (onGoing) {
|
|
89
|
+
// check if the callback exists
|
|
90
|
+
if (onGoing.callback)
|
|
91
|
+
onGoing.callback(message);
|
|
92
|
+
// otherwise do not execute callback and delete the request from ongoing
|
|
93
|
+
this._deleteRequest(message.getRequestId());
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (let callback of this.receiveCallbacks) {
|
|
98
|
+
callback(message);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Init all websocker events
|
|
103
|
+
*/
|
|
104
|
+
_setupEvents() {
|
|
105
|
+
if (this.socket === undefined) {
|
|
106
|
+
console.log("KoppeliaWebsocket::_setupEvents(): Koppelia websocket client was not instancieated");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// handle web socker opening
|
|
110
|
+
this.socket.addEventListener('open', (e) => {
|
|
111
|
+
if (this.openCallback)
|
|
112
|
+
this.openCallback();
|
|
113
|
+
});
|
|
114
|
+
// handle web socket reception
|
|
115
|
+
this.socket.addEventListener('message', (e) => {
|
|
116
|
+
let data = JSON.parse(e.data);
|
|
117
|
+
this._handleWebsocketResponse(data);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Timeout the request if there is no response
|
|
122
|
+
* To timout the response, the function simply delete the id from on going request list
|
|
123
|
+
* @param requestId Id of the request
|
|
124
|
+
*/
|
|
125
|
+
_getRequestIndex(requestId) {
|
|
126
|
+
return this.onGoingRequests.findIndex((element) => {
|
|
127
|
+
if (!element) {
|
|
128
|
+
return false; // Skip empty slots
|
|
129
|
+
}
|
|
130
|
+
return element.requestId === requestId;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Delete the request from the list of onGoing Requests
|
|
135
|
+
* @param requestId
|
|
136
|
+
*/
|
|
137
|
+
_deleteRequest(requestId) {
|
|
138
|
+
this.onGoingRequests = this.onGoingRequests.filter((element) => element.requestId !== requestId);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* get the Ongoing the request and get theh callback
|
|
142
|
+
* @param requestId
|
|
143
|
+
* @returns
|
|
144
|
+
*/
|
|
145
|
+
_getOnGoingRequest(requestId) {
|
|
146
|
+
let requestIndex = this._getRequestIndex(requestId);
|
|
147
|
+
if (requestIndex < 0)
|
|
148
|
+
return undefined;
|
|
149
|
+
return this.onGoingRequests[requestIndex];
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Add a new request to ongoing requests
|
|
153
|
+
* @param requestId
|
|
154
|
+
* @param callback
|
|
155
|
+
*/
|
|
156
|
+
_addNewRequest(requestId, callback) {
|
|
157
|
+
this.onGoingRequests.push({ requestId: requestId, callback: callback });
|
|
158
|
+
}
|
|
159
|
+
}
|