@unitn-asa/deliveroo-js-sdk 1.2.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.
@@ -0,0 +1,432 @@
1
+
2
+ /**
3
+ * @typedef {import("../types/IOAgent.js").IOAgent} IOAgent
4
+ * @typedef {import("../types/IOParcel.js").IOParcel} IOParcel
5
+ * @typedef {import("../types/IOConfig.js").IOConfig} IOConfig
6
+ */
7
+
8
+
9
+
10
+ /**
11
+ * @typedef {{
12
+ * 'agents': () => IOAgent[],
13
+ * 'agents/:id': () => IOAgent,
14
+ * 'configs': () => IOConfig,
15
+ * 'levels': () => IOConfig[],
16
+ * 'level': () => IOConfig,
17
+ * 'maps': () => any[],
18
+ * 'map': () => any,
19
+ * 'npcs': () => any[],
20
+ * 'npc': () => any,
21
+ * 'parcels': () => IOParcel[],
22
+ * 'parcel': () => IOParcel,
23
+ * }} IODeliveroojsGETRoutes
24
+ */
25
+
26
+ /**
27
+ * @typedef {{
28
+ * 'agents': (body: IOAgent) => IOAgent,
29
+ * 'levels': (body: IOConfig) => IOConfig,
30
+ * 'maps': (body: any) => IOConfig,
31
+ * 'npcs': (body: any) => {},
32
+ * 'parcels': (body: IOParcel) => IOParcel,
33
+ * }} IODeliveroojsPOSTRoutes
34
+ */
35
+
36
+ /**
37
+ * @typedef {{
38
+ * 'agents': () => IOAgent[],
39
+ * 'agents/:id': () => IOAgent,
40
+ * 'npcs': () => any[],
41
+ * 'npc': (id: string) => any,
42
+ * 'parcels': () => IOParcel[],
43
+ * 'parcel': (id: string) => IOParcel,
44
+ * }} IODeliveroojsDELETERoutes
45
+ */
46
+
47
+
48
+
49
+ /**
50
+ * @class
51
+ */
52
+ export class DjsRestClient {
53
+
54
+
55
+
56
+ /** @type {string} */
57
+ #HOST = 'http://localhost:8080';
58
+ /** @type {string} */
59
+ get HOST() { return this.#HOST }
60
+
61
+
62
+
63
+ /**
64
+ * Initialize HOST for API calls.
65
+ * @param {string} HOST
66
+ */
67
+ constructor( HOST ) {
68
+ this.#HOST = HOST;
69
+ console.log("DjsRestClient (API RESTful Client) initialized with HOST:", this.HOST);
70
+ }
71
+
72
+
73
+
74
+ /**
75
+ * @template { keyof IODeliveroojsGETRoutes } K
76
+ * @param { K } resource
77
+ * @param { string } token
78
+ * @returns {Promise<ReturnType<IODeliveroojsGETRoutes[K][]>>}
79
+ */
80
+ async getAll ( resource, token ) {
81
+
82
+ return new Promise( (resolve, reject) => {
83
+
84
+ const url = this.HOST+'/api/'+resource;
85
+
86
+ console.log( 'GET', url );
87
+
88
+ fetch(url, {
89
+ method: 'GET',
90
+ headers: {
91
+ 'Content-Type': 'application/json',
92
+ 'x-token': token
93
+ }
94
+ })
95
+
96
+ .then( JSON.stringify )
97
+
98
+ .then( body => resolve( /** @type {any} */ (body)) )
99
+
100
+ .catch(error => {
101
+ console.error('An error occurred:', error);
102
+ reject('Error getting config');
103
+ });
104
+
105
+ } );
106
+ }
107
+
108
+
109
+
110
+ /**
111
+ * @template { keyof IODeliveroojsGETRoutes } K
112
+ * @param { K } resource
113
+ * @param { string } id
114
+ * @param { string } token
115
+ * @returns {Promise<ReturnType<IODeliveroojsGETRoutes[K]>>}
116
+ */
117
+ async get ( resource, id, token ) {
118
+
119
+ return new Promise( (resolve, reject) => {
120
+
121
+ // replace placeholder ':id' with value of id in string resource
122
+ const url = this.HOST+'/api/'+resource.replace( ':id', id );
123
+
124
+ console.log( 'GET', url );
125
+
126
+ fetch(url, {
127
+ method: 'GET',
128
+ headers: {
129
+ 'Content-Type': 'application/json',
130
+ 'x-token': token
131
+ }
132
+ })
133
+
134
+ .then( JSON.stringify )
135
+
136
+ .then( body => resolve( /** @type {any} */ (body)) )
137
+
138
+ .catch(error => {
139
+ console.error('An error occurred:', error);
140
+ reject('Error getting config');
141
+ });
142
+
143
+ } );
144
+
145
+ }
146
+
147
+
148
+
149
+ /**
150
+ * @template { keyof IODeliveroojsPOSTRoutes } K
151
+ * @param { K } resource
152
+ * @param { string } token
153
+ * @param { Parameters<IODeliveroojsPOSTRoutes[K]>[0] } body
154
+ * @returns {Promise<ReturnType<IODeliveroojsPOSTRoutes[K]>>}
155
+ */
156
+ async post ( resource, token, body ) {
157
+
158
+ return new Promise( (resolve, reject) => {
159
+
160
+ const url = this.HOST+'/api/'+resource;
161
+
162
+ console.log( 'POST', url, body );
163
+
164
+ fetch(url, {
165
+ method: 'POST',
166
+ headers: {
167
+ 'Content-Type': 'application/json',
168
+ 'x-token': token
169
+ },
170
+ body: JSON.stringify( body )
171
+ })
172
+
173
+ .then( JSON.stringify )
174
+
175
+ .then( body => resolve( /** @type {any} */ (body)) )
176
+
177
+ .catch(error => {
178
+ console.error('An error occurred:', error);
179
+ reject('Error getting config');
180
+ });
181
+
182
+ } );
183
+
184
+ }
185
+
186
+
187
+
188
+ async getToken(name, team, password) {
189
+ return new Promise((resolve, reject) => {
190
+
191
+ console.log("Name fetch: ", name + " team fetch: ", team);
192
+
193
+ fetch(this.HOST+'/api/tokens', {
194
+ method: 'POST',
195
+ headers: {
196
+ 'Content-Type': 'application/json',
197
+ 'name': name,
198
+ 'team': team,
199
+ 'password': password
200
+ }
201
+ })
202
+ .then(response => {
203
+ if (response.ok) {
204
+ return response.json();
205
+ }
206
+ throw new Error(`Error generating token, Status code: ${response.status}`);
207
+ })
208
+ .then(data => {
209
+ console.log("token ottenuto: " + data.token.slice(-30));
210
+ resolve(data);
211
+ })
212
+ .catch(error => {
213
+ console.error('An error occurred:', error);
214
+ reject('No tokens available at the moment');
215
+ });
216
+ });
217
+ }
218
+
219
+
220
+
221
+ async getConfig ( token ) {
222
+ return new Promise((resolve, reject) => {
223
+ fetch(this.HOST+'/api/configs', {
224
+ method: 'GET',
225
+ headers: {
226
+ 'Content-Type': 'application/json',
227
+ 'x-token': token
228
+ }
229
+ })
230
+ .then( JSON.stringify )
231
+ .catch(error => {
232
+ console.error('An error occurred:', error);
233
+ reject('Error getting config');
234
+ });
235
+ });
236
+ }
237
+
238
+
239
+
240
+ /**
241
+ *
242
+ * @param {string} token
243
+ * @param {{}} config
244
+ * @returns
245
+ */
246
+ async patchConfig ( token, config ) {
247
+
248
+ console.log( "Patching config: ", config );
249
+
250
+ return new Promise((resolve, reject) => {
251
+ fetch(this.HOST+'/api/configs', {
252
+ method: 'PATCH',
253
+ headers: {
254
+ 'Content-Type': 'application/json',
255
+ 'x-token': token
256
+ },
257
+ body: JSON.stringify(config)
258
+ })
259
+ // parsing response
260
+ .then( JSON.stringify )
261
+ // .then( response => {
262
+ // console.log("config patched: " + response);
263
+ // for ( let [key,value] of Object.entries(response) ) {
264
+ // settings[key] = value;
265
+ // }
266
+ // resolve(settings);
267
+ // })
268
+ .catch(error => {
269
+ console.error('An error occurred:', error);
270
+ reject('Error patching config');
271
+ });
272
+ });
273
+ }
274
+
275
+
276
+
277
+ /**
278
+ * @param {string} token
279
+ * @param {string} id
280
+ * @returns
281
+ */
282
+ async deleteAgent ( token, id ) {
283
+ return new Promise((resolve, reject) => {
284
+ fetch(this.HOST+'/api/agents/'+id, {
285
+ method: 'DELETE',
286
+ headers: {
287
+ 'Content-Type': 'application/json',
288
+ 'x-token': token
289
+ }
290
+ })
291
+ .then(response => {
292
+ if (response.ok) {
293
+ return response.json();
294
+ }
295
+ throw new Error(`Error deleting agent, Status code: ${response.status}`);
296
+ })
297
+ .then(data => {
298
+ console.log("agent deleted: " + data);
299
+ resolve(data);
300
+ })
301
+ .catch(error => {
302
+ console.error('An error occurred:', error);
303
+ reject('Error deleting agent');
304
+ });
305
+ });
306
+ }
307
+
308
+
309
+
310
+ /**
311
+ * @param {string} token
312
+ * @param {string} id
313
+ * @param {{score?:number, penalty?:number}} agent
314
+ * @returns
315
+ */
316
+ async patchAgent ( token, id, agent ) {
317
+ return new Promise((resolve, reject) => {
318
+ fetch(this.HOST+'/api/agents/'+id, {
319
+ method: 'PATCH',
320
+ headers: {
321
+ 'Content-Type': 'application/json',
322
+ 'x-token': token
323
+ },
324
+ body: JSON.stringify(agent)
325
+ })
326
+ .then(response => {
327
+ if (response.ok) {
328
+ return response.json();
329
+ }
330
+ throw new Error(`Error patching agent, Status code: ${response.status}`);
331
+ })
332
+ .then(data => {
333
+ console.log("agent patched: " + data);
334
+ resolve(data);
335
+ })
336
+ .catch(error => {
337
+ console.warn('An error occurred:', error);
338
+ reject('Error patching agent');
339
+ });
340
+ });
341
+ }
342
+
343
+
344
+
345
+ /**
346
+ *
347
+ * @param {string} token
348
+ * @param {string} id
349
+ * @returns
350
+ */
351
+ async deleteParcel( token, id ) {
352
+ return new Promise((resolve, reject) => {
353
+ fetch(this.HOST+'/api/parcels/'+id, {
354
+ method: 'DELETE',
355
+ headers: {
356
+ 'Content-Type': 'application/json',
357
+ 'x-token': token
358
+ }
359
+ })
360
+ .then(response => {
361
+ if (response.ok) {
362
+ return response.json();
363
+ }
364
+ throw new Error(`Error deleting parcel, Status code: ${response.status}`);
365
+ })
366
+ .then(data => {
367
+ console.log("parcel deleted: " + data);
368
+ resolve(data);
369
+ })
370
+ .catch(error => {
371
+ console.warn('An error occurred:', error);
372
+ reject('Error deleting parcel');
373
+ });
374
+ });
375
+ }
376
+
377
+
378
+
379
+ /**
380
+ * Delete all parcels from the grid.
381
+ * @param {*} token
382
+ */
383
+ async deleteAllParcels( token ) {
384
+ return new Promise((resolve, reject) => {
385
+ fetch(this.HOST+'/api/parcels', {
386
+ method: 'DELETE',
387
+ headers: {
388
+ 'Content-Type': 'application/json',
389
+ 'x-token': token
390
+ }
391
+ })
392
+ .then(response => {
393
+ if (response.ok) {
394
+ return response.json();
395
+ }
396
+ else {
397
+ throw new Error(`Error deleting all parcels, Status code: ${response.status}`);
398
+ }
399
+ })
400
+ .then(data => {
401
+ console.log("all parcels deleted: " + data);
402
+ resolve(data);
403
+ })
404
+ .catch(error => {
405
+ console.warn('An error occurred:', error);
406
+ reject('Error deleting all parcels');
407
+ });
408
+ });
409
+ }
410
+
411
+
412
+
413
+ }
414
+
415
+
416
+
417
+ // Example usage:
418
+ //
419
+ // const api = new DeliveroojsRestClient('http://localhost:8080');
420
+ // api.get('agents', '', 'some-token').then( agents => console.log( agents ) );
421
+ // api.get('agents/:id', 'some-id', 'some-token').then( agent => console.log( agent ) );
422
+ // api.post('agents', 'some-token', {
423
+ // id: 'agent-123',
424
+ // name: 'Agent 123',
425
+ // teamId: 'team-1',
426
+ // teamName: 'Team 1',
427
+ // score: 0,
428
+ // penalty: 0,
429
+ // x: 0,
430
+ // y: 0
431
+ // } )
432
+ // .then( agent => console.log( agent ) );
@@ -0,0 +1,51 @@
1
+ import { io } from "socket.io-client";
2
+ import { default as argsparser } from "args-parser";
3
+ import { DjsClientSocket } from "./DjsClientSocket.js";
4
+
5
+
6
+
7
+ /**
8
+ * Takes the following arguments from console:
9
+ * token or name
10
+ * e.g:
11
+ * $ node index.js -token=... -name=marco
12
+ * $ npm start -- -token=... -name=marco
13
+ */
14
+ const args = argsparser(process? process?.argv : []);
15
+
16
+
17
+
18
+ /**
19
+ * @returns { DjsClientSocket }
20
+ */
21
+ export function connect ( host, token = args['token'], name = args['name'], autoconnect = true ) {
22
+
23
+ let opts = {
24
+ autoConnect: false,
25
+ withCredentials: false,
26
+ // extraHeaders: { 'x-token': TOKEN || token }
27
+ // query: { name: NAME }
28
+ // path: '/'
29
+ };
30
+ if ( token && token != '' )
31
+ opts.extraHeaders = { 'x-token': token }
32
+ else if ( name && name != '' )
33
+ opts.query = { name: name }
34
+
35
+ const enhancedClientSocket = DjsClientSocket.enhance( io( host, opts ) );
36
+
37
+ if ( autoconnect )
38
+ enhancedClientSocket.connect();
39
+
40
+ console.log( `Connecting to ${host} as ${ token ? 'token '+ (token).substring(0,5)+'...' : name ? 'name '+name : 'guest' }` );
41
+
42
+ return enhancedClientSocket;
43
+
44
+ }
45
+
46
+
47
+
48
+ // Example usage:
49
+ //
50
+ // const socket = connect( 'http://localhost:8080', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjczZDZkOSIsIm5hbWUiOiJub21lX21vbHRvX2x1bmdvXzEiLCJ0ZWFtSWQiOiIyNDc0ZDkiLCJ0ZWFtTmFtZSI6Im5vbWVfdGVhbV9tb2x0b19sdW5nbyIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzQ4MzUxOTM3fQ.rhEHyAoaQhqVqhEJ5bqyu3UdcvJWK5RLWKJxkBDAX_0', true );
51
+ // socket.emitMove( 'up' );
@@ -0,0 +1,21 @@
1
+
2
+ /**
3
+ * @typedef {import("../types/IOConfig.js").IOConfig} IOConfig
4
+ * @typedef {import("../types/IOGameOptions.js").IOGameOptions} IOGameOptions
5
+ *
6
+ * @typedef {import("../types/IOClockEvent.js").IOClockEvent} IOClockEvent
7
+ *
8
+ * @typedef {import("../types/IOAgent.js").IOAgent} IOAgent
9
+ * @typedef {import("../types/IOParcel.js").IOParcel} IOParcel
10
+ * @typedef {import("../types/IOTile.js").IOTile} IOTile
11
+ *
12
+ * @typedef {import("../types/IOIdentity.js").IOIdentity} IOIdentity
13
+ * @typedef {import("../types/IOInfo.js").IOInfo} IOInfo
14
+ * @typedef {import("../types/IOSensing.js").IOSensing} IOSensing
15
+ *
16
+ * @typedef {import("../types/IOSocketEvents.js").IOClientEvents} IOClientEvents
17
+ * @typedef {import("../types/IOSocketEvents.js").IOServerEvents} IOServerEvents
18
+ */
19
+
20
+ export { DjsClientSocket } from './DjsClientSocket.js';
21
+ export { DjsRestClient } from './DjsRestClient.js';
@@ -0,0 +1,136 @@
1
+ import { Server } from 'socket.io';
2
+ import { DjsServerSocket } from './DjsServerSocket.js';
3
+
4
+ /**
5
+ * @typedef {import("../types/IOAgent.js").IOAgent} IOAgent
6
+ * @typedef {import("../types/IOParcel.js").IOParcel} IOParcel
7
+ * @typedef {import("../types/IOTile.js").IOTile} IOTile
8
+ * @typedef {import("../types/IOConfig.js").IOConfig} IOConfig
9
+ * @typedef {import("../types/IOInfo.js").IOInfo} IOInfo
10
+ *
11
+ * @typedef {import("../types/IOSocketEvents.js").IOSensing} IOSensing
12
+ * @typedef {import("../types/IOSocketEvents.js").IOClientEvents} IOClientEvents on the client side these are to be emitted with .emit
13
+ * @typedef {import("../types/IOSocketEvents.js").IOServerEvents} IOServerEvents on the client side these are to be listened with .on
14
+ */
15
+
16
+ /**
17
+ * @class
18
+ * @extends { Server<IOClientEvents, IOServerEvents> }
19
+ */
20
+ export class DjsServer extends Server {
21
+
22
+ /**
23
+ * Broadcast config to all connected clients
24
+ * @param { IOConfig } config
25
+ */
26
+ broadcastConfig(config) {
27
+ this.emit('config', config);
28
+ }
29
+
30
+ /**
31
+ * Broadcast map to all connected clients
32
+ * @param { number } width
33
+ * @param { number } height
34
+ * @param { IOTile[] } tiles
35
+ */
36
+ broadcastMap(width, height, tiles) {
37
+ this.emit('map', width, height, tiles);
38
+ }
39
+
40
+ /**
41
+ * Broadcast a tile update to all connected clients
42
+ * @param { IOTile } tile
43
+ * @param { IOInfo } info
44
+ */
45
+ broadcastTile({ x, y, type }, info) {
46
+ this.emit('tile', { x, y, type }, info);
47
+ }
48
+
49
+ /**
50
+ * Broadcast controller status (agent connected/disconnected) to all clients
51
+ * @param { 'connected' | 'disconnected' } status
52
+ * @param { Parameters<IOServerEvents['controller']>[1] } agent
53
+ */
54
+ broadcastController(status, { id, name, teamId, teamName, score }) {
55
+ this.emit('controller', status, { id, name, teamId, teamName, score });
56
+ }
57
+
58
+ /**
59
+ * Broadcast a message to all connected clients
60
+ * @param { string } fromId
61
+ * @param { string } fromName
62
+ * @param { any } msg
63
+ */
64
+ broadcastMessage(fromId, fromName, msg) {
65
+ this.emit('msg', fromId, fromName, msg);
66
+ }
67
+
68
+ /**
69
+ * Broadcast a log message to all connected clients
70
+ * @param { 'server' | { socket:string, id:string, name:string } } src - 'server' or client
71
+ * @param { IOInfo } info
72
+ * @param { ...any } message
73
+ */
74
+ broadcastLog(src, info, ...message) {
75
+ this.emit('log', src, info, ...message);
76
+ }
77
+
78
+ // /**
79
+ // * Get all sockets in a room
80
+ // * @param { string } roomName
81
+ // * @returns { Promise<import('./DjsServerSocket.js').DjsServerSocket[]> }
82
+ // */
83
+ // async fetchSocketsInRoom(roomName) {
84
+ // const sockets = await this.in(roomName).fetchSockets();
85
+ // return sockets.forEach(s => DjsServerSocket.enhance(s));
86
+ // }
87
+
88
+ // /**
89
+ // * Count sockets in a room
90
+ // * @param { string } roomName
91
+ // * @returns { Promise<number> }
92
+ // */
93
+ // async countSocketsInRoom(roomName) {
94
+ // const sockets = await this.fetchSocketsInRoom(roomName);
95
+ // return sockets.length;
96
+ // }
97
+
98
+ // /**
99
+ // * Emit to all sockets in a specific room
100
+ // * @param { string } roomName
101
+ // * @param { string } event
102
+ // * @param { ...any } args
103
+ // */
104
+ // emitToRoom(roomName, event, ...args) {
105
+ // this.to(roomName).emit(event, ...args);
106
+ // }
107
+
108
+ /**
109
+ * Enhance a Socket.io Server into a DjsServer
110
+ * @param { Server } server
111
+ * @returns { DjsServer }
112
+ */
113
+ static enhance(server) {
114
+ /**
115
+ * Mixin function to copy methods from a class prototype to an object
116
+ */
117
+ function applyMixin(target, MixinClass) {
118
+ let proto = MixinClass.prototype;
119
+
120
+ const descriptors = Object.getOwnPropertyDescriptors(proto);
121
+ delete descriptors.constructor;
122
+
123
+ Object.defineProperties(target, descriptors);
124
+
125
+ return target;
126
+ }
127
+ applyMixin(server, DjsServer);
128
+
129
+ /**
130
+ * Original server enhanced with DjsServer methods
131
+ * @type { DjsServer }
132
+ */
133
+ // @ts-ignore
134
+ return server;
135
+ }
136
+ }