Skip to content

Commit 688aae3

Browse files
authored
Merge in pre connect-es rpc/js (#365)
1 parent 9cb36cb commit 688aae3

17 files changed

+1606
-32
lines changed

package-lock.json

Lines changed: 4 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
},
4747
"homepage": "https://github.com/viamrobotics/viam-typescript-sdk#readme",
4848
"dependencies": {
49-
"@viamrobotics/rpc": "^0.2.6",
5049
"exponential-backoff": "^3.1.1"
5150
},
5251
"devDependencies": {

src/app/viam-transport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { grpc } from '@improbable-eng/grpc-web';
2-
import { dialDirect } from '@viamrobotics/rpc';
2+
import { dialDirect } from '../rpc';
33

44
import {
55
AuthenticateRequest,

src/robot/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* eslint-disable max-classes-per-file */
22
import { grpc } from '@improbable-eng/grpc-web';
3-
import { dialDirect, dialWebRTC, type DialOptions } from '@viamrobotics/rpc';
43
import { backOff } from 'exponential-backoff';
54
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
65
import { isCredential, type Credentials } from '../app/viam-transport';
@@ -32,6 +31,7 @@ import { SensorsServiceClient } from '../gen/service/sensors/v1/sensors_pb_servi
3231
import { SLAMServiceClient } from '../gen/service/slam/v1/slam_pb_service';
3332
import { VisionServiceClient } from '../gen/service/vision/v1/vision_pb_service';
3433
import { ViamResponseStream } from '../responses';
34+
import { dialDirect, dialWebRTC, type DialOptions } from '../rpc';
3535
import { MetadataTransport, encodeResourceName, promisify } from '../utils';
3636
import GRPCConnectionManager from './grpc-connection-manager';
3737
import type { Robot, RobotStatusStream } from './robot';

src/robot/session-manager.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// @vitest-environment happy-dom
22

3-
import { beforeEach, describe, expect, it, vi } from 'vitest';
4-
import { ConnectionClosedError } from '@viamrobotics/rpc';
5-
import { FakeTransportBuilder } from '@improbable-eng/grpc-web-fake-transport';
63
import { grpc } from '@improbable-eng/grpc-web';
4+
import { FakeTransportBuilder } from '@improbable-eng/grpc-web-fake-transport';
5+
import { beforeEach, describe, expect, it, vi } from 'vitest';
76
import { RobotServiceClient } from '../gen/robot/v1/robot_pb_service';
7+
import { ConnectionClosedError } from '../rpc';
88
vi.mock('../gen/robot/v1/robot_pb_service');
99

1010
import SessionManager from './session-manager';

src/robot/session-manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { ConnectionClosedError } from '@viamrobotics/rpc';
21
import { grpc } from '@improbable-eng/grpc-web';
2+
import robotApi from '../gen/robot/v1/robot_pb';
33
import {
44
RobotServiceClient,
55
type ServiceError,
66
} from '../gen/robot/v1/robot_pb_service';
7-
import robotApi from '../gen/robot/v1/robot_pb';
7+
import { ConnectionClosedError } from '../rpc';
88
import SessionTransport from './session-transport';
99

1010
const timeoutBlob = new Blob(

src/robot/session-transport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { GRPCError } from '@viamrobotics/rpc';
21
import { grpc } from '@improbable-eng/grpc-web';
2+
import { GRPCError } from '../rpc';
33
import type SessionManager from './session-manager';
44

55
export default class SessionTransport implements grpc.Transport {

src/rpc/base-channel.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import type { ProtobufMessage } from '@improbable-eng/grpc-web/dist/typings/message';
2+
import { ConnectionClosedError } from './connection-closed-error';
3+
4+
export class BaseChannel {
5+
public readonly ready: Promise<unknown>;
6+
7+
private readonly peerConn: RTCPeerConnection;
8+
private readonly dataChannel: RTCDataChannel;
9+
private pResolve: ((value: unknown) => void) | undefined;
10+
private pReject: ((reason?: unknown) => void) | undefined;
11+
12+
private closed = false;
13+
private closedReason: Error | undefined;
14+
15+
protected maxDataChannelSize = 65_535;
16+
17+
constructor(peerConn: RTCPeerConnection, dataChannel: RTCDataChannel) {
18+
this.peerConn = peerConn;
19+
this.dataChannel = dataChannel;
20+
21+
this.ready = new Promise<unknown>((resolve, reject) => {
22+
this.pResolve = resolve;
23+
this.pReject = reject;
24+
});
25+
26+
dataChannel.addEventListener('open', () => this.onChannelOpen());
27+
dataChannel.addEventListener('close', () => this.onChannelClose());
28+
dataChannel.addEventListener('error', (ev) => {
29+
this.onChannelError(ev);
30+
});
31+
32+
peerConn.addEventListener('iceconnectionstatechange', () => {
33+
const state = peerConn.iceConnectionState;
34+
if (
35+
!(state === 'failed' || state === 'disconnected' || state === 'closed')
36+
) {
37+
return;
38+
}
39+
this.pReject?.(new Error(`ICE connection failed with state: ${state}`));
40+
});
41+
}
42+
43+
public close() {
44+
this.closeWithReason(undefined);
45+
}
46+
47+
public isClosed() {
48+
return this.closed;
49+
}
50+
51+
public isClosedReason() {
52+
return this.closedReason;
53+
}
54+
55+
protected closeWithReason(err?: Error) {
56+
if (this.closed) {
57+
return;
58+
}
59+
this.closed = true;
60+
this.closedReason = err;
61+
this.pReject?.(err);
62+
this.peerConn.close();
63+
}
64+
65+
private onChannelOpen() {
66+
this.pResolve?.(undefined);
67+
}
68+
69+
private onChannelClose() {
70+
this.closeWithReason(new ConnectionClosedError('data channel closed'));
71+
}
72+
73+
private onChannelError(ev: any) {
74+
console.error('channel error', ev);
75+
this.closeWithReason(new Error(ev));
76+
}
77+
78+
protected write(msg: ProtobufMessage) {
79+
this.dataChannel.send(msg.serializeBinary());
80+
}
81+
}

src/rpc/base-stream.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { grpc } from '@improbable-eng/grpc-web';
2+
import type { PacketMessage, Stream } from '../gen/proto/rpc/webrtc/v1/grpc_pb';
3+
4+
// MaxMessageSize (2^25) is the maximum size a gRPC message can be.
5+
const MaxMessageSize = 33_554_432;
6+
7+
export class BaseStream {
8+
protected readonly stream: Stream;
9+
private readonly onDone: (id: number) => void;
10+
protected readonly opts: grpc.TransportOptions;
11+
protected closed = false;
12+
private readonly packetBuf: Uint8Array[] = [];
13+
private packetBufSize = 0;
14+
private err: Error | undefined;
15+
16+
constructor(
17+
stream: Stream,
18+
onDone: (id: number) => void,
19+
opts: grpc.TransportOptions
20+
) {
21+
this.stream = stream;
22+
this.onDone = onDone;
23+
this.opts = opts;
24+
}
25+
26+
public closeWithRecvError(err?: Error) {
27+
if (this.closed) {
28+
return;
29+
}
30+
this.closed = true;
31+
this.err = err;
32+
this.onDone(this.stream.getId());
33+
// pretty sure passing the error does nothing.
34+
this.opts.onEnd(this.err);
35+
}
36+
37+
protected processPacketMessage(msg: PacketMessage): Uint8Array | undefined {
38+
const data = msg.getData_asU8();
39+
if (data.length + this.packetBufSize > MaxMessageSize) {
40+
this.packetBuf.length = 0;
41+
this.packetBufSize = 0;
42+
console.error(
43+
`message size larger than max ${MaxMessageSize}; discarding`
44+
);
45+
return undefined;
46+
}
47+
this.packetBuf.push(data);
48+
this.packetBufSize += data.length;
49+
if (msg.getEom()) {
50+
const pktData = new Uint8Array(this.packetBufSize);
51+
let position = 0;
52+
for (const partialData of this.packetBuf) {
53+
pktData.set(partialData, position);
54+
position += partialData.length;
55+
}
56+
this.packetBuf.length = 0;
57+
this.packetBufSize = 0;
58+
return pktData;
59+
}
60+
return undefined;
61+
}
62+
}

0 commit comments

Comments
 (0)