|
5 | 5 | import {Observable, Subject} from 'rxjs';
|
6 | 6 | import {map} from 'rxjs/operators';
|
7 | 7 | import {fromBinary, toBinary} from '@bufbuild/protobuf';
|
| 8 | +import type {Message} from '@bufbuild/protobuf'; |
| 9 | +import type {GenMessage} from '@bufbuild/protobuf/codegenv1'; |
8 | 10 | import * as varint from 'varint';
|
9 | 11 |
|
10 | 12 | import {compilerError} from './utils';
|
11 |
| -import { |
12 |
| - InboundMessage, |
13 |
| - InboundMessageSchema, |
14 |
| - OutboundMessage, |
15 |
| - OutboundMessageSchema, |
16 |
| -} from './vendor/embedded_sass_pb'; |
| 13 | +import * as proto from './vendor/embedded_sass_pb'; |
17 | 14 |
|
18 | 15 | /**
|
19 |
| - * Encodes InboundMessages into protocol buffers and decodes protocol buffers |
20 |
| - * into OutboundMessages. |
| 16 | + * Encodes OutType into protocol buffers and decodes protocol buffers |
| 17 | + * into InType. |
21 | 18 | */
|
22 |
| -export class MessageTransformer { |
| 19 | +class MessageTransformer<InType extends Message, OutType extends Message> { |
23 | 20 | // The decoded messages are written to this Subject. It is publicly exposed
|
24 | 21 | // as a readonly Observable.
|
25 |
| - private readonly outboundMessagesInternal$ = new Subject< |
26 |
| - [number, OutboundMessage] |
27 |
| - >(); |
| 22 | + private readonly messagesInternal$ = new Subject<[number, InType]>(); |
28 | 23 |
|
29 | 24 | /**
|
30 |
| - * The OutboundMessages, decoded from protocol buffers. If this fails to |
| 25 | + * The InType messages, decoded from protocol buffers. If this fails to |
31 | 26 | * decode a message, it will emit an error.
|
32 | 27 | */
|
33 |
| - readonly outboundMessages$ = this.outboundMessagesInternal$.pipe(); |
| 28 | + readonly messages$ = this.messagesInternal$.pipe(); |
34 | 29 |
|
35 | 30 | constructor(
|
36 |
| - private readonly outboundProtobufs$: Observable<Uint8Array>, |
37 |
| - private readonly writeInboundProtobuf: (buffer: Uint8Array) => void |
| 31 | + private readonly InTypeSchema: GenMessage<InType>, |
| 32 | + private readonly OutTypeSchema: GenMessage<OutType>, |
| 33 | + private readonly protobufs$: Observable<Uint8Array>, |
| 34 | + private readonly writeProtobuf: (buffer: Uint8Array) => void |
38 | 35 | ) {
|
39 |
| - this.outboundProtobufs$ |
40 |
| - .pipe(map(decode)) |
41 |
| - .subscribe(this.outboundMessagesInternal$); |
| 36 | + this.protobufs$ |
| 37 | + .pipe(map(buffer => this.decode(buffer))) |
| 38 | + .subscribe(this.messagesInternal$); |
42 | 39 | }
|
43 | 40 |
|
44 | 41 | /**
|
45 |
| - * Converts the inbound `compilationId` and `message` to a protocol buffer. |
| 42 | + * Converts the `compilationId` and OutType `message` to a protocol buffer. |
46 | 43 | */
|
47 |
| - writeInboundMessage([compilationId, message]: [ |
48 |
| - number, |
49 |
| - InboundMessage, |
50 |
| - ]): void { |
| 44 | + writeMessage([compilationId, message]: [number, OutType]): void { |
51 | 45 | const compilationIdLength = varint.encodingLength(compilationId);
|
52 |
| - const encodedMessage = toBinary(InboundMessageSchema, message); |
| 46 | + const encodedMessage = toBinary(this.OutTypeSchema, message); |
53 | 47 | const buffer = new Uint8Array(compilationIdLength + encodedMessage.length);
|
54 | 48 | varint.encode(compilationId, buffer);
|
55 | 49 | buffer.set(encodedMessage, compilationIdLength);
|
56 | 50 |
|
57 | 51 | try {
|
58 |
| - this.writeInboundProtobuf(buffer); |
| 52 | + this.writeProtobuf(buffer); |
59 | 53 | } catch (error) {
|
60 |
| - this.outboundMessagesInternal$.error(error); |
| 54 | + this.messagesInternal$.error(error); |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + // Decodes a protobuf `buffer` into a compilation ID and an InType message, |
| 59 | + // ensuring that all mandatory message fields are populated. Throws if `buffer` |
| 60 | + // cannot be decoded into a valid message, or if the message itself contains a |
| 61 | + // Protocol Error. |
| 62 | + private decode(buffer: Uint8Array): [number, InType] { |
| 63 | + let compilationId: number; |
| 64 | + try { |
| 65 | + compilationId = varint.decode(buffer); |
| 66 | + } catch (error) { |
| 67 | + throw compilerError(`Invalid compilation ID varint: ${error}`); |
| 68 | + } |
| 69 | + |
| 70 | + try { |
| 71 | + return [ |
| 72 | + compilationId, |
| 73 | + fromBinary( |
| 74 | + this.InTypeSchema, |
| 75 | + new Uint8Array(buffer.buffer, varint.decode.bytes) |
| 76 | + ), |
| 77 | + ]; |
| 78 | + } catch (error) { |
| 79 | + throw compilerError(`Invalid protobuf: ${error}`); |
61 | 80 | }
|
62 | 81 | }
|
63 | 82 | }
|
64 | 83 |
|
65 |
| -// Decodes a protobuf `buffer` into a compilation ID and an OutboundMessage, |
66 |
| -// ensuring that all mandatory message fields are populated. Throws if `buffer` |
67 |
| -// cannot be decoded into a valid message, or if the message itself contains a |
68 |
| -// Protocol Error. |
69 |
| -function decode(buffer: Uint8Array): [number, OutboundMessage] { |
70 |
| - let compilationId: number; |
71 |
| - try { |
72 |
| - compilationId = varint.decode(buffer); |
73 |
| - } catch (error) { |
74 |
| - throw compilerError(`Invalid compilation ID varint: ${error}`); |
| 84 | +/** |
| 85 | + * Encodes InboundMessage into protocol buffers and decodes protocol buffers |
| 86 | + * into OutboundMessage. |
| 87 | + */ |
| 88 | +export class HostMessageTransformer extends MessageTransformer< |
| 89 | + proto.OutboundMessage, |
| 90 | + proto.InboundMessage |
| 91 | +> { |
| 92 | + constructor( |
| 93 | + protobufs$: Observable<Uint8Array>, |
| 94 | + writeProtobuf: (buffer: Uint8Array) => void |
| 95 | + ) { |
| 96 | + super( |
| 97 | + proto.OutboundMessageSchema, |
| 98 | + proto.InboundMessageSchema, |
| 99 | + protobufs$, |
| 100 | + writeProtobuf |
| 101 | + ); |
75 | 102 | }
|
| 103 | +} |
76 | 104 |
|
77 |
| - try { |
78 |
| - return [ |
79 |
| - compilationId, |
80 |
| - fromBinary( |
81 |
| - OutboundMessageSchema, |
82 |
| - new Uint8Array(buffer.buffer, varint.decode.bytes) |
83 |
| - ), |
84 |
| - ]; |
85 |
| - } catch (error) { |
86 |
| - throw compilerError(`Invalid protobuf: ${error}`); |
| 105 | +/** |
| 106 | + * Encodes OutboundMessage into protocol buffers and decodes protocol buffers |
| 107 | + * into InboundMessage. |
| 108 | + */ |
| 109 | +export class CompilerMessageTransformer extends MessageTransformer< |
| 110 | + proto.InboundMessage, |
| 111 | + proto.OutboundMessage |
| 112 | +> { |
| 113 | + constructor( |
| 114 | + protobufs$: Observable<Uint8Array>, |
| 115 | + writeProtobuf: (buffer: Uint8Array) => void |
| 116 | + ) { |
| 117 | + super( |
| 118 | + proto.InboundMessageSchema, |
| 119 | + proto.OutboundMessageSchema, |
| 120 | + protobufs$, |
| 121 | + writeProtobuf |
| 122 | + ); |
87 | 123 | }
|
88 | 124 | }
|
0 commit comments