@dronedeploy/rocos-js-sdk 4.4.3 → 4.4.5

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.
Files changed (58) hide show
  1. package/LICENSE +3 -0
  2. package/cjs/api/StreamRegister.d.ts +18 -3
  3. package/cjs/api/StreamRegister.js +71 -38
  4. package/cjs/api/atoms/StreamHeartbeat.js +2 -2
  5. package/cjs/api/streams/telemetry/TelemetryStreamAbstract.d.ts +8 -1
  6. package/cjs/api/streams/telemetry/TelemetryStreamAbstract.js +83 -40
  7. package/cjs/api/streams/webRTCSignalling/WebRTCSignallingStreamAbstract.js +1 -1
  8. package/cjs/constants/api.d.ts +3 -2
  9. package/cjs/constants/api.js +5 -4
  10. package/cjs/constants/identifier.d.ts +1 -0
  11. package/cjs/constants/identifier.js +2 -1
  12. package/cjs/helpers/getUniqueId.js +2 -1
  13. package/cjs/models/callsigns/CallsignsLookup.d.ts +4 -0
  14. package/cjs/models/callsigns/CallsignsLookup.js +19 -0
  15. package/cjs/models/gamepad/GamepadConfig.d.ts +26 -0
  16. package/cjs/models/gamepad/GamepadConfig.js +11 -1
  17. package/cjs/services/AssetStorageService.js +6 -1
  18. package/cjs/services/BaseServiceAbstract.js +1 -1
  19. package/cjs/services/BaseStreamService.d.ts +12 -1
  20. package/cjs/services/BaseStreamService.js +19 -30
  21. package/cjs/services/EnvironmentService.d.ts +4 -0
  22. package/cjs/services/EnvironmentService.js +5 -1
  23. package/cjs/services/MapService.d.ts +15 -3
  24. package/cjs/services/MapService.js +25 -13
  25. package/cjs/services/SearchService.js +1 -1
  26. package/cjs/services/TargetService.js +2 -2
  27. package/cjs/services/TelemetryService.d.ts +1 -1
  28. package/cjs/services/TelemetryService.js +29 -22
  29. package/cjs/services/WebRTCSignallingService.js +7 -9
  30. package/esm/api/StreamRegister.d.ts +18 -3
  31. package/esm/api/StreamRegister.js +71 -38
  32. package/esm/api/atoms/StreamHeartbeat.js +2 -2
  33. package/esm/api/streams/telemetry/TelemetryStreamAbstract.d.ts +8 -1
  34. package/esm/api/streams/telemetry/TelemetryStreamAbstract.js +84 -41
  35. package/esm/api/streams/webRTCSignalling/WebRTCSignallingStreamAbstract.js +2 -2
  36. package/esm/constants/api.d.ts +3 -2
  37. package/esm/constants/api.js +3 -2
  38. package/esm/constants/identifier.d.ts +1 -0
  39. package/esm/constants/identifier.js +1 -0
  40. package/esm/helpers/getUniqueId.js +2 -1
  41. package/esm/models/callsigns/CallsignsLookup.d.ts +4 -0
  42. package/esm/models/callsigns/CallsignsLookup.js +19 -0
  43. package/esm/models/gamepad/GamepadConfig.d.ts +26 -0
  44. package/esm/models/gamepad/GamepadConfig.js +10 -0
  45. package/esm/services/AssetStorageService.js +6 -1
  46. package/esm/services/BaseServiceAbstract.js +1 -1
  47. package/esm/services/BaseStreamService.d.ts +12 -1
  48. package/esm/services/BaseStreamService.js +19 -30
  49. package/esm/services/EnvironmentService.d.ts +4 -0
  50. package/esm/services/EnvironmentService.js +5 -1
  51. package/esm/services/MapService.d.ts +15 -3
  52. package/esm/services/MapService.js +26 -14
  53. package/esm/services/SearchService.js +2 -2
  54. package/esm/services/TargetService.js +3 -3
  55. package/esm/services/TelemetryService.d.ts +1 -1
  56. package/esm/services/TelemetryService.js +30 -23
  57. package/esm/services/WebRTCSignallingService.js +8 -10
  58. package/package.json +8 -1
@@ -36,10 +36,22 @@ export declare class MapService extends BaseServiceAbstract implements IBaseServ
36
36
  */
37
37
  listDeployedMaps(projectId: string, callsign: string): Promise<Map[]>;
38
38
  /**
39
- * Creates a new map by merging two existing maps
39
+ * Creates a new map by folding two existing maps together.
40
+ *
41
+ * `options.name` is the mapId of the new target map and must not already
42
+ * exist. `options.callsign` is accepted for signature compatibility and is
43
+ * not sent: the union target is a cloud map, and deploying it to a robot is
44
+ * {@link deploy}'s job.
45
+ *
46
+ * `options.description` needs a second request - the union endpoint takes no
47
+ * metadata. That request is best-effort: a failure is logged and swallowed,
48
+ * because the map itself already exists by then and retrying `merge` would
49
+ * conflict on `targetMapId`. Call {@link updateMetadata} directly to retry
50
+ * the description.
51
+ *
40
52
  * @param projectId Project ID
41
- * @param maps Array of two map IDs to merge
42
- * @param options Options to create the new map
53
+ * @param maps Array of two source map IDs to fold together
54
+ * @param options `name` for the new map, optional `description`
43
55
  */
44
56
  merge(projectId: string, maps: [string, string], options: {
45
57
  name: string;
@@ -1,4 +1,4 @@
1
- import { API_GRAPHS_MAPS_COPY_URL, API_GRAPHS_MAPS_DEPLOYED_URL, API_GRAPHS_MAPS_DEPLOY_URL, API_GRAPHS_MAPS_GEOJSON_URL, API_GRAPHS_MAPS_MERGE_URL, API_GRAPHS_MAPS_NEW_URL, API_GRAPHS_MAPS_URL, API_GRAPHS_MAP_CONTENT_URL, API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL, API_GRAPHS_MAP_EDGES_ADD_URL, API_GRAPHS_MAP_EDGE_URL, API_GRAPHS_MAP_ID_URL, API_GRAPHS_MAP_METADATA_URL, API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL, API_GRAPHS_MAP_NODES_ADD_URL, API_GRAPHS_MAP_NODE_URL, API_GRAPHS_MAP_PATHS_URL, API_GRAPHS_MAP_PATH_APPEND_TRANSFORMABLE_URL, API_GRAPHS_MAP_PATH_APPEND_URL, API_GRAPHS_MAP_PATH_URL, API_GRAPHS_OBSERVATIONS_URL, API_GRAPHS_OBSERVATION_KEYS_URL, API_GRAPHS_PANORAMA, API_GRAPHS_PANORAMAS_URL, API_GRAPHS_PANORAMA_OBSERVATIONS_URL, } from '../constants/api';
1
+ import { API_GRAPHS_MAPS_COPY_URL, API_GRAPHS_MAPS_DEPLOYED_URL, API_GRAPHS_MAPS_DEPLOY_URL, API_GRAPHS_MAPS_GEOJSON_URL, API_GRAPHS_MAPS_NEW_URL, API_GRAPHS_MAPS_UNION_URL, API_GRAPHS_MAPS_URL, API_GRAPHS_MAP_CONTENT_URL, API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL, API_GRAPHS_MAP_EDGES_ADD_URL, API_GRAPHS_MAP_EDGE_URL, API_GRAPHS_MAP_ID_URL, API_GRAPHS_MAP_METADATA_URL, API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL, API_GRAPHS_MAP_NODES_ADD_URL, API_GRAPHS_MAP_NODE_URL, API_GRAPHS_MAP_PATHS_URL, API_GRAPHS_MAP_PATH_APPEND_TRANSFORMABLE_URL, API_GRAPHS_MAP_PATH_APPEND_URL, API_GRAPHS_MAP_PATH_URL, API_GRAPHS_OBSERVATIONS_URL, API_GRAPHS_OBSERVATION_KEYS_URL, API_GRAPHS_PANORAMA, API_GRAPHS_PANORAMAS_URL, API_GRAPHS_PANORAMA_OBSERVATIONS_URL, } from '../constants/api';
2
2
  import { RocosError, errorCodes } from '../models';
3
3
  import { BaseServiceAbstract } from './BaseServiceAbstract';
4
4
  import { RocosLogger } from '../logger/RocosLogger';
@@ -52,26 +52,38 @@ export class MapService extends BaseServiceAbstract {
52
52
  return resp.maps;
53
53
  }
54
54
  /**
55
- * Creates a new map by merging two existing maps
55
+ * Creates a new map by folding two existing maps together.
56
+ *
57
+ * `options.name` is the mapId of the new target map and must not already
58
+ * exist. `options.callsign` is accepted for signature compatibility and is
59
+ * not sent: the union target is a cloud map, and deploying it to a robot is
60
+ * {@link deploy}'s job.
61
+ *
62
+ * `options.description` needs a second request - the union endpoint takes no
63
+ * metadata. That request is best-effort: a failure is logged and swallowed,
64
+ * because the map itself already exists by then and retrying `merge` would
65
+ * conflict on `targetMapId`. Call {@link updateMetadata} directly to retry
66
+ * the description.
67
+ *
56
68
  * @param projectId Project ID
57
- * @param maps Array of two map IDs to merge
58
- * @param options Options to create the new map
69
+ * @param maps Array of two source map IDs to fold together
70
+ * @param options `name` for the new map, optional `description`
59
71
  */
60
72
  async merge(projectId, maps, options) {
61
73
  if (maps.length !== 2)
62
74
  throw new Error('You must provide two maps to merge.');
63
- const payload = {
64
- projectID: projectId,
65
- mapIDLeft: maps[0],
66
- mapIDRight: maps[1],
67
- name: options.name,
68
- description: options.description,
69
- callsign: options.callsign,
70
- };
71
- return this.callPost(formatServiceUrl(API_GRAPHS_MAPS_MERGE_URL, {
75
+ await this.callPost(formatServiceUrl(API_GRAPHS_MAPS_UNION_URL, {
72
76
  url: this.config.url,
73
77
  projectId,
74
- }, this.config.insecure), payload, 'Failed to merge maps.');
78
+ }, this.config.insecure), { targetMapId: options.name, sources: [maps[0], maps[1]] }, 'Failed to merge maps.');
79
+ if (options.description) {
80
+ try {
81
+ await this.updateMetadata(projectId, options.name, { description: options.description });
82
+ }
83
+ catch (e) {
84
+ this.logger.error(`Map ${options.name} was created but its description could not be set.`, e);
85
+ }
86
+ }
75
87
  }
76
88
  /** Returns a map in its canonical form
77
89
  *
@@ -1,7 +1,7 @@
1
1
  import { SubscriberStatusEnum, } from '../models';
2
2
  import { Subject } from 'rxjs';
3
3
  import { BaseStreamService } from './BaseStreamService';
4
- import { IDENTIFIER_NAME_FILE_ACCESSOR } from '../constants/identifier';
4
+ import { IDENTIFIER_NAME_SEARCH } from '../constants/identifier';
5
5
  import { SearchStream } from '../api/streams/search/SearchStream';
6
6
  import { finalize } from 'rxjs/operators';
7
7
  export class SearchService extends BaseStreamService {
@@ -36,7 +36,7 @@ export class SearchService extends BaseStreamService {
36
36
  return stream.deleteProjectData(params);
37
37
  }
38
38
  async createStream() {
39
- const newStream = await this.createStreamFromConfig(IDENTIFIER_NAME_FILE_ACCESSOR, {
39
+ const newStream = await this.createStreamFromConfig(IDENTIFIER_NAME_SEARCH, {
40
40
  url: this.config.url,
41
41
  token: this.config.token,
42
42
  scope: 'default',
@@ -1,4 +1,4 @@
1
- import { API_GRAPHS_ASSETS_UPLOAD_URL, API_GRAPHS_ASSETS_URL, API_GRAPHS_TARGETS_URL, API_GRAPHS_TARGET_UPLOAD_URL, } from '../constants/api';
1
+ import { API_GRAPHS_ASSETS_UPLOAD_URL, API_GRAPHS_ASSETS_URL, API_GRAPHS_TARGETS_URL, API_GRAPHS_TARGET_MEDIA_URL, API_GRAPHS_TARGET_UPLOAD_URL, } from '../constants/api';
2
2
  import { RocosError, errorCodes } from '../models';
3
3
  import { BaseServiceAbstract } from './BaseServiceAbstract';
4
4
  import { RocosLogger } from '../logger/RocosLogger';
@@ -53,10 +53,10 @@ export class TargetService extends BaseServiceAbstract {
53
53
  });
54
54
  }
55
55
  async addMedia(projectId, targetId, media) {
56
- await this.callPost(formatServiceUrl(API_GRAPHS_TARGETS_URL, {
56
+ await this.callPut(formatServiceUrl(API_GRAPHS_TARGET_MEDIA_URL, {
57
57
  url: this.config.url,
58
58
  projectId,
59
- targetId,
59
+ targetId: encodeURIComponent(targetId),
60
60
  }, this.config.insecure), media, 'Failed to add media to a target');
61
61
  }
62
62
  }
@@ -46,6 +46,6 @@ export declare class TelemetryService extends BaseStreamService<ITelemetryStream
46
46
  monitorTelemetryWithTimeout(projectId: string, callsign: string, source: string, heartbeatTimeoutMs?: number, intervalMs?: number): Observable<TelemetryMonitorStatus>;
47
47
  protected initStream(stream: ITelemetryStream): Promise<void>;
48
48
  private buildScope;
49
- private createStream;
49
+ private buildStreamConfig;
50
50
  protected getStream(config: ITelemetryStreamConfig): ITelemetryStream;
51
51
  }
@@ -1,5 +1,5 @@
1
1
  import { BehaviorSubject, catchError, combineLatest, defer, distinctUntilChanged, from, interval, map, mergeAll, of, startWith, } from 'rxjs';
2
- import { CallsignStatus, CallsignsLookup, CallsignsLookupType, RocosError, SubscriberStatusEnum, TelemetryMonitorStatus, errorCodes, } from '../models';
2
+ import { CallsignStatus, CallsignsLookup, RocosError, SubscriberStatusEnum, TelemetryMonitorStatus, errorCodes, } from '../models';
3
3
  import { filter, finalize } from 'rxjs/operators';
4
4
  import { BaseStreamService } from './BaseStreamService';
5
5
  import { IDENTIFIER_NAME_TELEMETRY } from '../constants/identifier';
@@ -52,20 +52,33 @@ export class TelemetryService extends BaseStreamService {
52
52
  // scope is used as a key to generate unique streams
53
53
  // ideally there should be just one concurrent stream opened
54
54
  const scope = this.buildScope(params, callsignsLookup);
55
- const callsigns = callsignsLookup.lookupValue;
56
55
  const subscriptionParams = {
57
56
  uniqueId: getUniqueId(params.projectId, callsignsLookup, sources, scope),
58
- callsigns: callsignsLookup?.lookupType === CallsignsLookupType.List ? callsignsLookup.lookupValue : [],
57
+ callsigns: callsignsLookup.getCallsigns(),
59
58
  sources,
60
59
  };
61
60
  // `defer` acquires the stream only when subscribed; `finalize` releases it on unsubscribe, error
62
- // and complete — so acquire and release stay balanced on every path.
61
+ // and complete — so acquire and release stay balanced on every path. The registry refcount taken
62
+ // here keeps the stream alive until the finalize, so everything in between is race-free.
63
63
  return defer(() => {
64
- let acquired;
65
- const stream$ = this.createStream(params.projectId, callsignsLookup, sources, scope, (stream) => {
66
- acquired = stream;
64
+ const { stream, isNew, ready, release } = this.acquireStream(IDENTIFIER_NAME_TELEMETRY, this.buildStreamConfig(params.projectId, callsignsLookup, sources, scope));
65
+ try {
67
66
  stream.addSubscription(subscriptionParams);
68
- }).then((stream) => {
67
+ if (!isNew) {
68
+ stream.statusStream$.subscribe((msg) => {
69
+ this.streamStatusSubject$.next({
70
+ scope,
71
+ status: msg,
72
+ });
73
+ });
74
+ }
75
+ }
76
+ catch (e) {
77
+ // finalize below is not wired up yet, so a throw here must hand the refcount back itself.
78
+ release();
79
+ throw e;
80
+ }
81
+ const messages$ = ready.then(() => {
69
82
  if (!this.statusSubscription) {
70
83
  this.statusSubscription = stream.statusStream$.subscribe((msg) => {
71
84
  this.status = msg === SubscriberStatusEnum.STOPPED || msg === SubscriberStatusEnum.ALIVE;
@@ -74,9 +87,12 @@ export class TelemetryService extends BaseStreamService {
74
87
  }
75
88
  return from(stream.messageStream$);
76
89
  });
77
- return from(stream$).pipe(mergeAll(), filter((message) => {
78
- return callsigns.includes(message.callsign) && sources.includes(message.source);
79
- }), finalize(() => acquired?.removeSubscription(subscriptionParams, params.terminateReceiverGroupOnUnsubscribe)));
90
+ return from(messages$).pipe(mergeAll(), filter((message) => {
91
+ return callsignsLookup.includesCallsign(message.callsign) && sources.includes(message.source);
92
+ }), finalize(() => {
93
+ void stream.removeSubscription(subscriptionParams, params.terminateReceiverGroupOnUnsubscribe);
94
+ release();
95
+ }));
80
96
  });
81
97
  }
82
98
  /**
@@ -156,8 +172,8 @@ export class TelemetryService extends BaseStreamService {
156
172
  return `${params.projectId}-default-${flattenCallsignsLookup(callsignsLookup).join()}`;
157
173
  return `${params.projectId}-default`;
158
174
  }
159
- async createStream(projectId, callsignsLookup, sources, scope, onAcquire) {
160
- const newStream = await this.createStreamFromConfig(IDENTIFIER_NAME_TELEMETRY, {
175
+ buildStreamConfig(projectId, callsignsLookup, sources, scope) {
176
+ return {
161
177
  url: this.config.url,
162
178
  projectId,
163
179
  callsignsLookup,
@@ -169,16 +185,7 @@ export class TelemetryService extends BaseStreamService {
169
185
  insecure: this.config.insecure,
170
186
  transport: this.config.transport,
171
187
  fetch: this.config.fetch,
172
- }, onAcquire);
173
- if (!newStream.isNew) {
174
- newStream.stream.statusStream$.subscribe((msg) => {
175
- this.streamStatusSubject$.next({
176
- scope,
177
- status: msg,
178
- });
179
- });
180
- }
181
- return newStream.stream;
188
+ };
182
189
  }
183
190
  getStream(config) {
184
191
  if (config.transport === 'grpc-web') {
@@ -1,4 +1,4 @@
1
- import { IDENTIFIER_NAME_COMMAND } from '../constants/identifier';
1
+ import { IDENTIFIER_NAME_WEBRTC_SIGNALLING } from '../constants/identifier';
2
2
  import { RocosLogger } from '../logger/RocosLogger';
3
3
  import { RocosStore } from '../store/RocosStore';
4
4
  import { StreamRegister } from '../api/StreamRegister';
@@ -34,11 +34,9 @@ export class WebRTCSignallingService {
34
34
  }
35
35
  async createSignallingStream() {
36
36
  const scope = 'default';
37
- const identifier = StreamRegister.getIdentifier(IDENTIFIER_NAME_COMMAND, scope);
38
- const streamRegister = StreamRegister.getInstance();
39
- let stream = streamRegister.getStream(identifier);
40
- if (!stream) {
41
- stream = this.getStream({
37
+ const identifier = StreamRegister.getIdentifier(IDENTIFIER_NAME_WEBRTC_SIGNALLING, scope);
38
+ const { stream, ready } = StreamRegister.getInstance().acquireStream(identifier, () => {
39
+ const newStream = this.getStream({
42
40
  url: this.config.url,
43
41
  token: this.config.token,
44
42
  scope,
@@ -46,13 +44,13 @@ export class WebRTCSignallingService {
46
44
  port: this.config.port,
47
45
  insecure: this.config.insecure,
48
46
  });
49
- stream.statusStream$.subscribe((msg) => {
47
+ newStream.statusStream$.subscribe((msg) => {
50
48
  this.status = msg === SubscriberStatusEnum.STOPPED || msg === SubscriberStatusEnum.ALIVE;
51
49
  this.status$.next(msg);
52
50
  });
53
- streamRegister.addStream(stream);
54
- await this.initStream(stream);
55
- }
51
+ return newStream;
52
+ }, (newStream) => this.initStream(newStream));
53
+ await ready;
56
54
  return stream;
57
55
  }
58
56
  async initStream(stream) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dronedeploy/rocos-js-sdk",
3
- "version": "4.4.3",
3
+ "version": "4.4.5",
4
4
  "description": "Javascript SDK for rocos",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -28,12 +28,19 @@
28
28
  "@grpc/grpc-js": "^1.7.1",
29
29
  "@protobuf-ts/grpcweb-transport": "^2.9.1",
30
30
  "@protobuf-ts/runtime": "^2.9.1",
31
+ "@protobuf-ts/runtime-rpc": "^2.9.1",
31
32
  "acorn": "^8.11.3",
32
33
  "loglevel": "^1.7.1"
33
34
  },
34
35
  "peerDependencies": {
36
+ "@types/node": "*",
35
37
  "rxjs": "^6.6.6 || ^7.0.0"
36
38
  },
39
+ "peerDependenciesMeta": {
40
+ "@types/node": {
41
+ "optional": true
42
+ }
43
+ },
37
44
  "repository": {},
38
45
  "private": false
39
46
  }