@gitpod/gitpod-protocol 0.1.5-se-workspace-for-teams.18 → 0.1.5-se-workspaceid.9

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 (235) hide show
  1. package/data/gitpod-schema.json +9 -2
  2. package/lib/accounting-protocol.d.ts +0 -1
  3. package/lib/accounting-protocol.d.ts.map +1 -1
  4. package/lib/accounting-protocol.js +10 -11
  5. package/lib/accounting-protocol.js.map +1 -1
  6. package/lib/admin-protocol.d.ts +8 -2
  7. package/lib/admin-protocol.d.ts.map +1 -1
  8. package/lib/admin-protocol.js +2 -13
  9. package/lib/admin-protocol.js.map +1 -1
  10. package/lib/analytics.d.ts +1 -0
  11. package/lib/analytics.d.ts.map +1 -1
  12. package/lib/context-url.js +4 -4
  13. package/lib/context-url.js.map +1 -1
  14. package/lib/context-url.spec.js +45 -48
  15. package/lib/context-url.spec.js.map +1 -1
  16. package/lib/email-protocol.js +4 -4
  17. package/lib/email-protocol.js.map +1 -1
  18. package/lib/encryption/container-module.js +4 -4
  19. package/lib/encryption/container-module.js.map +1 -1
  20. package/lib/encryption/encryption-engine.js +19 -20
  21. package/lib/encryption/encryption-engine.js.map +1 -1
  22. package/lib/encryption/encryption-engine.spec.js +29 -36
  23. package/lib/encryption/encryption-engine.spec.js.map +1 -1
  24. package/lib/encryption/encryption-service.js +29 -43
  25. package/lib/encryption/encryption-service.js.map +1 -1
  26. package/lib/encryption/key-provider.js +25 -30
  27. package/lib/encryption/key-provider.js.map +1 -1
  28. package/lib/env.d.ts +0 -1
  29. package/lib/env.d.ts.map +1 -1
  30. package/lib/env.js +12 -14
  31. package/lib/env.js.map +1 -1
  32. package/lib/gitpod-file-parser.js +25 -41
  33. package/lib/gitpod-file-parser.js.map +1 -1
  34. package/lib/gitpod-file-parser.spec.js +116 -116
  35. package/lib/gitpod-file-parser.spec.js.map +1 -1
  36. package/lib/gitpod-service.d.ts +24 -9
  37. package/lib/gitpod-service.d.ts.map +1 -1
  38. package/lib/gitpod-service.js +149 -295
  39. package/lib/gitpod-service.js.map +1 -1
  40. package/lib/ide-protocol.d.ts +81 -0
  41. package/lib/ide-protocol.d.ts.map +1 -0
  42. package/lib/ide-protocol.js +8 -0
  43. package/lib/ide-protocol.js.map +1 -0
  44. package/lib/index.d.ts +2 -0
  45. package/lib/index.d.ts.map +1 -1
  46. package/lib/index.js +2 -0
  47. package/lib/index.js.map +1 -1
  48. package/lib/messaging/browser/connection.d.ts +3 -3
  49. package/lib/messaging/browser/connection.d.ts.map +1 -1
  50. package/lib/messaging/browser/connection.js +172 -35
  51. package/lib/messaging/browser/connection.js.map +1 -1
  52. package/lib/messaging/browser/window-connection.js +35 -55
  53. package/lib/messaging/browser/window-connection.js.map +1 -1
  54. package/lib/messaging/client-call-metrics.js +17 -18
  55. package/lib/messaging/client-call-metrics.js.map +1 -1
  56. package/lib/messaging/connection-error-handler.js +11 -23
  57. package/lib/messaging/connection-error-handler.js.map +1 -1
  58. package/lib/messaging/error.d.ts +1 -1
  59. package/lib/messaging/error.d.ts.map +1 -1
  60. package/lib/messaging/error.js +2 -2
  61. package/lib/messaging/error.js.map +1 -1
  62. package/lib/messaging/handler.d.ts +10 -0
  63. package/lib/messaging/handler.d.ts.map +1 -1
  64. package/lib/messaging/node/connection.d.ts +0 -10
  65. package/lib/messaging/node/connection.d.ts.map +1 -1
  66. package/lib/messaging/node/connection.js +11 -49
  67. package/lib/messaging/node/connection.js.map +1 -1
  68. package/lib/messaging/proxy-factory.d.ts +2 -0
  69. package/lib/messaging/proxy-factory.d.ts.map +1 -1
  70. package/lib/messaging/proxy-factory.js +73 -160
  71. package/lib/messaging/proxy-factory.js.map +1 -1
  72. package/lib/oss-allowlist.d.ts +14 -0
  73. package/lib/oss-allowlist.d.ts.map +1 -0
  74. package/lib/oss-allowlist.js +8 -0
  75. package/lib/oss-allowlist.js.map +1 -0
  76. package/lib/permission.d.ts +1 -2
  77. package/lib/permission.d.ts.map +1 -1
  78. package/lib/permission.js +12 -13
  79. package/lib/permission.js.map +1 -1
  80. package/lib/plans.d.ts +1 -1
  81. package/lib/plans.d.ts.map +1 -1
  82. package/lib/plans.js +38 -57
  83. package/lib/plans.js.map +1 -1
  84. package/lib/protocol.d.ts +11 -7
  85. package/lib/protocol.d.ts.map +1 -1
  86. package/lib/protocol.js +44 -114
  87. package/lib/protocol.js.map +1 -1
  88. package/lib/snapshot-url.d.ts +14 -0
  89. package/lib/snapshot-url.d.ts.map +1 -0
  90. package/lib/snapshot-url.js +26 -0
  91. package/lib/snapshot-url.js.map +1 -0
  92. package/lib/snapshot-url.spec.d.ts +7 -0
  93. package/lib/snapshot-url.spec.d.ts.map +1 -0
  94. package/lib/snapshot-url.spec.js +41 -0
  95. package/lib/snapshot-url.spec.js.map +1 -0
  96. package/lib/team-subscription-protocol.js +13 -13
  97. package/lib/team-subscription-protocol.js.map +1 -1
  98. package/lib/teams-projects-protocol.d.ts +11 -1
  99. package/lib/teams-projects-protocol.d.ts.map +1 -1
  100. package/lib/teams-projects-protocol.js +4 -15
  101. package/lib/teams-projects-protocol.js.map +1 -1
  102. package/lib/util/analytics.js +25 -32
  103. package/lib/util/analytics.js.map +1 -1
  104. package/lib/util/async-iterator.js +55 -133
  105. package/lib/util/async-iterator.js.map +1 -1
  106. package/lib/util/cancelable.js +17 -59
  107. package/lib/util/cancelable.js.map +1 -1
  108. package/lib/util/date-time.js +8 -8
  109. package/lib/util/date-time.js.map +1 -1
  110. package/lib/util/deferred.js +10 -12
  111. package/lib/util/deferred.js.map +1 -1
  112. package/lib/util/disposable.js +26 -39
  113. package/lib/util/disposable.js.map +1 -1
  114. package/lib/util/event.js +58 -74
  115. package/lib/util/event.js.map +1 -1
  116. package/lib/util/garbage-collected-cache.d.ts +1 -0
  117. package/lib/util/garbage-collected-cache.d.ts.map +1 -1
  118. package/lib/util/garbage-collected-cache.js +26 -46
  119. package/lib/util/garbage-collected-cache.js.map +1 -1
  120. package/lib/util/generate-workspace-id.d.ts +1 -1
  121. package/lib/util/generate-workspace-id.d.ts.map +1 -1
  122. package/lib/util/generate-workspace-id.js +28 -68
  123. package/lib/util/generate-workspace-id.js.map +1 -1
  124. package/lib/util/generate-workspace-id.spec.js +56 -78
  125. package/lib/util/generate-workspace-id.spec.js.map +1 -1
  126. package/lib/util/gitpod-cookie.d.ts +20 -0
  127. package/lib/util/gitpod-cookie.d.ts.map +1 -0
  128. package/lib/util/gitpod-cookie.js +44 -0
  129. package/lib/util/gitpod-cookie.js.map +1 -0
  130. package/lib/util/gitpod-host-url.d.ts +1 -0
  131. package/lib/util/gitpod-host-url.d.ts.map +1 -1
  132. package/lib/util/gitpod-host-url.js +96 -103
  133. package/lib/util/gitpod-host-url.js.map +1 -1
  134. package/lib/util/gitpod-host-url.spec.js +87 -135
  135. package/lib/util/gitpod-host-url.spec.js.map +1 -1
  136. package/lib/util/grpc.js +3 -3
  137. package/lib/util/grpc.js.map +1 -1
  138. package/lib/util/jaeger-client-types.d.ts +68 -0
  139. package/lib/util/jaeger-client-types.d.ts.map +1 -0
  140. package/lib/util/jaeger-client-types.js +8 -0
  141. package/lib/util/jaeger-client-types.js.map +1 -0
  142. package/lib/util/logging.d.ts +32 -32
  143. package/lib/util/logging.d.ts.map +1 -1
  144. package/lib/util/logging.js +51 -125
  145. package/lib/util/logging.js.map +1 -1
  146. package/lib/util/make-link.js +2 -2
  147. package/lib/util/make-link.js.map +1 -1
  148. package/lib/util/parse-workspace-id.d.ts +10 -0
  149. package/lib/util/parse-workspace-id.d.ts.map +1 -1
  150. package/lib/util/parse-workspace-id.js +31 -7
  151. package/lib/util/parse-workspace-id.js.map +1 -1
  152. package/lib/util/parse-workspace-id.spec.d.ts +4 -0
  153. package/lib/util/parse-workspace-id.spec.d.ts.map +1 -1
  154. package/lib/util/parse-workspace-id.spec.js +123 -84
  155. package/lib/util/parse-workspace-id.spec.js.map +1 -1
  156. package/lib/util/queue.js +16 -55
  157. package/lib/util/queue.js.map +1 -1
  158. package/lib/util/queue.spec.js +144 -288
  159. package/lib/util/queue.spec.js.map +1 -1
  160. package/lib/util/repeat.d.ts +15 -0
  161. package/lib/util/repeat.d.ts.map +1 -0
  162. package/lib/util/repeat.js +55 -0
  163. package/lib/util/repeat.js.map +1 -0
  164. package/lib/util/safe-promise.js +9 -12
  165. package/lib/util/safe-promise.js.map +1 -1
  166. package/lib/util/semaphore.js +15 -46
  167. package/lib/util/semaphore.js.map +1 -1
  168. package/lib/util/skip-if.js +6 -6
  169. package/lib/util/skip-if.js.map +1 -1
  170. package/lib/util/timeutil.js +16 -16
  171. package/lib/util/timeutil.js.map +1 -1
  172. package/lib/util/timeutil.spec.js +21 -24
  173. package/lib/util/timeutil.spec.js.map +1 -1
  174. package/lib/util/tracing.d.ts +50 -5
  175. package/lib/util/tracing.d.ts.map +1 -1
  176. package/lib/util/tracing.js +171 -63
  177. package/lib/util/tracing.js.map +1 -1
  178. package/lib/util/tracing.spec.d.ts +7 -0
  179. package/lib/util/tracing.spec.d.ts.map +1 -0
  180. package/lib/util/tracing.spec.js +121 -0
  181. package/lib/util/tracing.spec.js.map +1 -0
  182. package/lib/util/workspace-port-authentication.js +2 -2
  183. package/lib/util/workspace-port-authentication.js.map +1 -1
  184. package/lib/workspace-cluster.d.ts +11 -1
  185. package/lib/workspace-cluster.d.ts.map +1 -1
  186. package/lib/workspace-cluster.js +3 -3
  187. package/lib/workspace-cluster.js.map +1 -1
  188. package/lib/workspace-instance.d.ts +4 -2
  189. package/lib/workspace-instance.d.ts.map +1 -1
  190. package/lib/wsready.js +1 -1
  191. package/package.json +22 -13
  192. package/pkg-yarn.lock +12 -7
  193. package/provenance-bundle.jsonl +2 -0
  194. package/src/accounting-protocol.ts +1 -3
  195. package/src/admin-protocol.ts +9 -3
  196. package/src/analytics.ts +2 -0
  197. package/src/email-protocol.ts +1 -1
  198. package/src/env.ts +0 -1
  199. package/src/gitpod-service.ts +27 -14
  200. package/src/ide-protocol.ts +92 -0
  201. package/src/index.ts +2 -0
  202. package/src/messaging/browser/connection.ts +176 -10
  203. package/src/messaging/error.ts +2 -2
  204. package/src/messaging/handler.ts +12 -0
  205. package/src/messaging/node/connection.ts +1 -45
  206. package/src/messaging/proxy-factory.ts +10 -4
  207. package/src/oss-allowlist.ts +15 -0
  208. package/src/permission.ts +0 -1
  209. package/src/protocol.ts +13 -8
  210. package/src/snapshot-url.spec.ts +25 -0
  211. package/src/snapshot-url.ts +27 -0
  212. package/src/team-subscription-protocol.ts +1 -1
  213. package/src/teams-projects-protocol.ts +14 -2
  214. package/src/util/garbage-collected-cache.ts +7 -1
  215. package/src/util/generate-workspace-id.spec.ts +16 -0
  216. package/src/util/generate-workspace-id.ts +19 -2
  217. package/src/util/gitpod-cookie.ts +39 -0
  218. package/src/util/gitpod-host-url.ts +12 -8
  219. package/src/util/grpc.ts +3 -3
  220. package/src/util/jaeger-client-types.ts +102 -0
  221. package/src/util/logging.ts +36 -41
  222. package/src/util/parse-workspace-id.spec.ts +21 -1
  223. package/src/util/parse-workspace-id.ts +32 -6
  224. package/src/util/repeat.ts +45 -0
  225. package/src/util/tracing.spec.ts +83 -0
  226. package/src/util/tracing.ts +157 -18
  227. package/src/workspace-cluster.ts +8 -1
  228. package/src/workspace-instance.ts +12 -6
  229. package/src/wsready.ts +1 -1
  230. package/lib/util/repeater.d.ts +0 -22
  231. package/lib/util/repeater.d.ts.map +0 -1
  232. package/lib/util/repeater.js +0 -118
  233. package/lib/util/repeater.js.map +0 -1
  234. package/src/util/jaeger-client.d.ts +0 -105
  235. package/src/util/repeater.ts +0 -49
@@ -5,10 +5,13 @@
5
5
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
6
  */
7
7
 
8
- import { listen as doListen, Logger, ConsoleLogger } from "vscode-ws-jsonrpc";
8
+ import { Logger, ConsoleLogger, toSocket, IWebSocket } from "vscode-ws-jsonrpc";
9
+ import { createMessageConnection } from "vscode-jsonrpc";
10
+ import { AbstractMessageWriter } from "vscode-jsonrpc/lib/messageWriter";
11
+ import { AbstractMessageReader } from "vscode-jsonrpc/lib/messageReader";
9
12
  import { JsonRpcProxyFactory, JsonRpcProxy } from "../proxy-factory";
10
- import { ConnectionHandler } from "../handler";
11
- import ReconnectingWebSocket from 'reconnecting-websocket';
13
+ import { ConnectionEventHandler, ConnectionHandler } from "../handler";
14
+ import ReconnectingWebSocket, { Event } from 'reconnecting-websocket';
12
15
 
13
16
  export interface WebSocketOptions {
14
17
  onerror?: (event: Event) => void;
@@ -29,7 +32,10 @@ export class WebSocketConnectionProvider {
29
32
  const startListening = (path: string) => {
30
33
  const socket = this.listen({
31
34
  path,
32
- onConnection: c => factory.listen(c)
35
+ onConnection: c => factory.listen(c),
36
+ }, {
37
+ onTransportDidClose: () => factory.fireConnectionClosed(),
38
+ onTransportDidOpen: () => factory.fireConnectionOpened(),
33
39
  },
34
40
  options
35
41
  );
@@ -49,7 +55,7 @@ export class WebSocketConnectionProvider {
49
55
  /**
50
56
  * Install a connection handler for the given path.
51
57
  */
52
- listen(handler: ConnectionHandler, options?: WebSocketOptions): WebSocket {
58
+ listen(handler: ConnectionHandler, eventHandler: ConnectionEventHandler, options?: WebSocketOptions): WebSocket {
53
59
  const url = handler.path;
54
60
  const webSocket = this.createWebSocket(url);
55
61
 
@@ -64,11 +70,12 @@ export class WebSocketConnectionProvider {
64
70
  logger.error(JSON.stringify(error));
65
71
  });
66
72
  }
67
- doListen({
68
- webSocket,
69
- onConnection: connection => handler.onConnection(connection),
70
- logger
71
- });
73
+ doListen(
74
+ webSocket as any as ReconnectingWebSocket,
75
+ handler,
76
+ eventHandler,
77
+ logger,
78
+ );
72
79
  return webSocket;
73
80
  }
74
81
 
@@ -91,3 +98,162 @@ export class WebSocketConnectionProvider {
91
98
  }
92
99
 
93
100
  }
101
+
102
+ // The following was extracted from vscode-ws-jsonrpc to make these changes:
103
+ // - switch from WebSocket to ReconnectingWebSocket
104
+ // - webSocket.onopen: making sure it's only ever called once so we're re-using MessageConnection
105
+ // - WebSocketMessageWriter: buffer and re-try messages instead of throwing an error immidiately
106
+ // - WebSocketMessageReader: don't close MessageConnection on 'socket.onclose'
107
+ function doListen(resocket: ReconnectingWebSocket, handler: ConnectionHandler, eventHandler: ConnectionEventHandler, logger: Logger) {
108
+ resocket.addEventListener("close", () => eventHandler.onTransportDidClose());
109
+
110
+ let alreadyOpened = false;
111
+ resocket.onopen = () => {
112
+ // trigerr "open" every time we re-open the underlying websocket
113
+ eventHandler.onTransportDidOpen();
114
+
115
+ // make sure we're only ever creating one MessageConnection, irregardless of how many times we have to re-open the underlying (reconnecting) websocket
116
+ if (alreadyOpened) {
117
+ return;
118
+ }
119
+ alreadyOpened = true;
120
+
121
+ const connection = createWebSocketConnection(resocket, logger);
122
+ handler.onConnection(connection);
123
+ };
124
+ }
125
+
126
+ function createWebSocketConnection(resocket: ReconnectingWebSocket, logger: Logger) {
127
+ const socket = toSocket(resocket as any);
128
+ const messageReader = new NonClosingWebSocketMessageReader(socket);
129
+ const messageWriter = new BufferingWebSocketMessageWriter(resocket, logger);
130
+ const connection = createMessageConnection(messageReader, messageWriter, logger);
131
+ connection.onClose(() => connection.dispose());
132
+ return connection;
133
+ }
134
+
135
+ /**
136
+ * This takes vscode-ws-jsonrpc/lib/socket/writer/WebSocketMessageWriter and adds a buffer
137
+ */
138
+ class BufferingWebSocketMessageWriter extends AbstractMessageWriter {
139
+ protected readonly socket: ReconnectingWebSocket;
140
+ protected readonly logger: Logger;
141
+ protected errorCount: number = 0;
142
+
143
+ protected buffer: any[] = [];
144
+
145
+ constructor(socket: ReconnectingWebSocket, logger: Logger) {
146
+ super();
147
+ this.socket = socket;
148
+ this.logger = logger;
149
+
150
+ socket.addEventListener("open", (event: Event) => this.flushBuffer());
151
+ }
152
+
153
+ write(msg: any) {
154
+ if (this.socket.readyState !== ReconnectingWebSocket.OPEN) {
155
+ this.bufferMsg(msg);
156
+ return;
157
+ }
158
+
159
+ try {
160
+ const content = JSON.stringify(msg);
161
+ this.socket.send(content);
162
+ } catch (e) {
163
+ this.errorCount++;
164
+ this.fireError(e, msg, this.errorCount);
165
+
166
+ this.bufferMsg(msg);
167
+ }
168
+ }
169
+
170
+ protected flushBuffer() {
171
+ if (this.buffer.length === 0) {
172
+ return
173
+ }
174
+
175
+ const buffer = [...this.buffer];
176
+ this.buffer = [];
177
+ for (const msg of buffer) {
178
+ this.write(msg);
179
+ }
180
+ //this.logger.info(`flushed buffer (${this.buffer.length})`)
181
+ }
182
+
183
+ protected bufferMsg(msg: any) {
184
+ this.buffer.push(msg);
185
+ //this.logger.info(`buffered message (${this.buffer.length})`);
186
+ }
187
+ }
188
+
189
+
190
+ /**
191
+ * This takes vscode-ws-jsonrpc/lib/socket/reader/WebSocketMessageReader and removes the "onClose -> fireClose" connection
192
+ */
193
+ class NonClosingWebSocketMessageReader extends AbstractMessageReader {
194
+ protected readonly socket: IWebSocket;
195
+ protected readonly events: any[] = [];
196
+ protected state: 'initial' | 'listening' | 'closed' = 'initial';
197
+ protected callback: (message: any) => void = () => {};
198
+
199
+ constructor(socket: IWebSocket) {
200
+ super();
201
+ this.socket = socket;
202
+ this.socket.onMessage(message => this.readMessage(message));
203
+ this.socket.onError(error => this.fireError(error));
204
+ this.socket.onClose((code, reason) => {
205
+ if (code !== 1000) {
206
+ const error = {
207
+ name: '' + code,
208
+ message: `Error during socket reconnect: code = ${code}, reason = ${reason}`
209
+ };
210
+ this.fireError(error);
211
+ }
212
+ // this.fireClose(); // <-- reason for this class to be copied over
213
+ });
214
+ }
215
+ listen(callback: (message: any) => void) {
216
+ if (this.state === 'initial') {
217
+ this.state = 'listening';
218
+ this.callback = callback;
219
+ while (this.events.length !== 0) {
220
+ const event = this.events.pop();
221
+ if (event.message) {
222
+ this.readMessage(event.message);
223
+ }
224
+ else if (event.error) {
225
+ this.fireError(event.error);
226
+ }
227
+ else {
228
+ this.fireClose();
229
+ }
230
+ }
231
+ }
232
+ }
233
+ readMessage(message: any) {
234
+ if (this.state === 'initial') {
235
+ this.events.splice(0, 0, { message });
236
+ }
237
+ else if (this.state === 'listening') {
238
+ const data = JSON.parse(message);
239
+ this.callback(data);
240
+ }
241
+ }
242
+ fireError(error: any) {
243
+ if (this.state === 'initial') {
244
+ this.events.splice(0, 0, { error });
245
+ }
246
+ else if (this.state === 'listening') {
247
+ super.fireError(error);
248
+ }
249
+ }
250
+ fireClose() {
251
+ if (this.state === 'initial') {
252
+ this.events.splice(0, 0, {});
253
+ }
254
+ else if (this.state === 'listening') {
255
+ super.fireClose();
256
+ }
257
+ this.state = 'closed';
258
+ }
259
+ }
@@ -76,6 +76,6 @@ export namespace ErrorCodes {
76
76
  // 620 Team Subscription Assignment Failed
77
77
  export const TEAM_SUBSCRIPTION_ASSIGNMENT_FAILED = 620;
78
78
 
79
- // 666 Not Implemented TODO IO-SPLIT remove
80
- export const NOT_IMPLEMENTED = 666;
79
+ // 630 Snapshot Error
80
+ export const SNAPSHOT_ERROR = 630;
81
81
  }
@@ -13,3 +13,15 @@ export interface ConnectionHandler {
13
13
  readonly path: string;
14
14
  onConnection(connection: MessageConnection, session?: object): void;
15
15
  }
16
+
17
+ export interface ConnectionEventHandler {
18
+ /**
19
+ * Called when the transport underpinning the connection got closed
20
+ */
21
+ onTransportDidClose(): void;
22
+
23
+ /**
24
+ * Called when the transport underpinning the connection is (re-)opened
25
+ */
26
+ onTransportDidOpen(): void;
27
+ }
@@ -7,58 +7,14 @@
7
7
 
8
8
  import * as ws from "ws";
9
9
  import * as http from "http";
10
- import * as https from "https";
11
- import * as url from "url";
12
10
  import * as net from "net";
13
- import { MessageConnection } from "vscode-jsonrpc";
14
- import { createWebSocketConnection, IWebSocket } from "vscode-ws-jsonrpc";
11
+ import { IWebSocket } from "vscode-ws-jsonrpc";
15
12
  import { log } from '../../util/logging';
16
13
 
17
- export interface IServerOptions {
18
- readonly server: http.Server | https.Server;
19
- readonly path?: string;
20
- matches?(request: http.IncomingMessage): boolean;
21
- }
22
-
23
- export function createServerWebSocketConnection(options: IServerOptions, onConnect: (connection: MessageConnection) => void): void {
24
- openJsonRpcSocket(options, socket => {
25
- onConnect(createWebSocketConnection(socket, console));
26
- });
27
- }
28
-
29
- export function openJsonRpcSocket(options: IServerOptions, onOpen: (socket: IWebSocket) => void): void {
30
- openSocket(options, socket => {
31
- const webSocket = toIWebSocket(socket);
32
- onOpen(webSocket);
33
- });
34
- }
35
-
36
14
  export interface OnOpen {
37
15
  (webSocket: ws, request: http.IncomingMessage, socket: net.Socket, head: Buffer): void;
38
16
  }
39
17
 
40
- export function openSocket(options: IServerOptions, onOpen: OnOpen): void {
41
- const wss = new ws.Server({
42
- noServer: true,
43
- perMessageDeflate: {
44
- // don't compress if a message is less than 256kb
45
- threshold: 256 * 1024
46
- }
47
- });
48
- options.server.on('upgrade', (request: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
49
- const pathname = request.url ? url.parse(request.url).pathname : undefined;
50
- if (options.path && pathname === options.path || options.matches && options.matches(request)) {
51
- wss.handleUpgrade(request, socket, head, webSocket => {
52
- if (webSocket.readyState === webSocket.OPEN) {
53
- onOpen(webSocket, request, socket, head);
54
- } else {
55
- webSocket.on('open', () => onOpen(webSocket, request, socket, head));
56
- }
57
- });
58
- }
59
- });
60
- }
61
-
62
18
  export function toIWebSocket(webSocket: ws) {
63
19
  let sendsAfterOpen = 0;
64
20
  return <IWebSocket>{
@@ -105,13 +105,19 @@ export class JsonRpcProxyFactory<T extends object> implements ProxyHandler<T> {
105
105
  this.connectionPromiseResolve = resolve
106
106
  );
107
107
  this.connectionPromise.then(connection => {
108
- connection.onClose(() =>
109
- this.onDidCloseConnectionEmitter.fire(undefined)
110
- );
111
- this.onDidOpenConnectionEmitter.fire(undefined);
108
+ connection.onClose(() => this.fireConnectionClosed());
109
+ this.fireConnectionOpened();
112
110
  });
113
111
  }
114
112
 
113
+ fireConnectionClosed() {
114
+ this.onDidCloseConnectionEmitter.fire(undefined)
115
+ }
116
+
117
+ fireConnectionOpened() {
118
+ this.onDidOpenConnectionEmitter.fire(undefined);
119
+ }
120
+
115
121
  /**
116
122
  * Connect a MessageConnection to the factory.
117
123
  *
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2021 Gitpod GmbH. All rights reserved.
3
+ * Licensed under the GNU Affero General Public License (AGPL).
4
+ * See License-AGPL.txt in the project root for license information.
5
+ */
6
+
7
+ export interface OssAllowList {
8
+ /**
9
+ * A string that identifies a GitHub/GitLab/Bitbucket identity of the form "<host>/<profilename>"
10
+ * E.g., "github.com/geropl"
11
+ */
12
+ identity: string,
13
+
14
+ deleted?: boolean,
15
+ }
package/src/permission.ts CHANGED
@@ -16,7 +16,6 @@ export const Permissions = {
16
16
  "admin-api": undefined,
17
17
  "ide-settings": undefined,
18
18
  "new-workspace-cluster": undefined,
19
- "teams-and-projects": undefined,
20
19
  };
21
20
  export type PermissionName = keyof (typeof Permissions);
22
21
  export const Roles = {"devops": undefined, "viewer": undefined, "admin": undefined };
package/src/protocol.ts CHANGED
@@ -114,6 +114,8 @@ export interface EmailNotificationSettings {
114
114
 
115
115
  export type IDESettings = {
116
116
  defaultIde?: string
117
+ useDesktopIde?: boolean
118
+ defaultDesktopIde?: string
117
119
  }
118
120
 
119
121
  export interface UserPlatform {
@@ -135,14 +137,6 @@ export interface UserPlatform {
135
137
  }
136
138
 
137
139
  export interface UserFeatureSettings {
138
- /**
139
- * This field is used as marker to grant users a free trial for using private repositories,
140
- * independent of any subscription or Chargebee.
141
- * - it is set when the user uses their first private repo
142
- * - whether the trial is expired or not is juged by the UserService
143
- */
144
- privateRepoTrialStartDate?: string;
145
-
146
140
  /**
147
141
  * Permanent feature flags are added to each and every workspace instance
148
142
  * this user starts.
@@ -378,11 +372,16 @@ export interface PendingGithubEvent {
378
372
  export interface Snapshot {
379
373
  id: string;
380
374
  creationTime: string;
375
+ availableTime?: string;
381
376
  originalWorkspaceId: string;
382
377
  bucketId: string;
383
378
  layoutData?: string;
379
+ state: SnapshotState;
380
+ message?: string;
384
381
  }
385
382
 
383
+ export type SnapshotState = 'pending' | 'available' | 'error';
384
+
386
385
  export interface LayoutData {
387
386
  workspaceId: string;
388
387
  lastUpdatedTime: string;
@@ -559,6 +558,9 @@ export interface WorkspaceConfig {
559
558
  github?: GithubAppConfig;
560
559
  vscode?: VSCodeConfig;
561
560
 
561
+ /** deprecated. Enabled by default **/
562
+ experimentalNetwork?: boolean;
563
+
562
564
  /**
563
565
  * Where the config object originates from.
564
566
  *
@@ -682,6 +684,8 @@ export interface PortConfig {
682
684
  port: number;
683
685
  onOpen?: PortOnOpen;
684
686
  visibility?: PortVisibility;
687
+ description?: string;
688
+ name?: string;
685
689
  }
686
690
  export namespace PortConfig {
687
691
  export function is(config: any): config is PortConfig {
@@ -769,6 +773,7 @@ export namespace ExternalImageConfigFile {
769
773
 
770
774
  export interface WorkspaceContext {
771
775
  title: string;
776
+ /** This contains the URL portion of the contextURL (which might contain other modifiers as well). It's optional because it's not set for older workspaces. */
772
777
  normalizedContextURL?: string;
773
778
  forceCreateNewWorkspace?: boolean;
774
779
  forceImageBuild?: boolean;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Copyright (c) 2020 Gitpod GmbH. All rights reserved.
3
+ * Licensed under the GNU Affero General Public License (AGPL).
4
+ * See License-AGPL.txt in the project root for license information.
5
+ */
6
+
7
+ import { suite, test } from "mocha-typescript"
8
+ import * as chai from "chai"
9
+ import { SnapshotUrl } from ".";
10
+
11
+ const expect = chai.expect
12
+
13
+ @suite class TestSnapshotUrlParser {
14
+
15
+ @test public testPositive() {
16
+ const actual = SnapshotUrl.parse("workspaces/c362d434-6faa-4ce0-9ad4-91b4a87c4abe/3f0556f7-4afa-11e9-98d5-52f8983b9279.tar@gitpod-prodcopy-user-e1e28f18-0354-4a5d-b6b4-8879a2ff73fd");
17
+
18
+ expect(actual).to.deep.equal(<SnapshotUrl>{
19
+ bucketId: "gitpod-prodcopy-user-e1e28f18-0354-4a5d-b6b4-8879a2ff73fd",
20
+ filename: "3f0556f7-4afa-11e9-98d5-52f8983b9279.tar",
21
+ fullPath: "workspaces/c362d434-6faa-4ce0-9ad4-91b4a87c4abe/3f0556f7-4afa-11e9-98d5-52f8983b9279.tar",
22
+ });
23
+ }
24
+ }
25
+ module.exports = new TestSnapshotUrlParser() // Only to circumvent no usage warning :-/
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright (c) 2021 Gitpod GmbH. All rights reserved.
3
+ * Licensed under the GNU Affero General Public License (AGPL).
4
+ * See License-AGPL.txt in the project root for license information.
5
+ */
6
+
7
+ export interface SnapshotUrl {
8
+ bucketId: string;
9
+ fullPath: string;
10
+ filename: string;
11
+ }
12
+ export namespace SnapshotUrl {
13
+ export function parse(url: string): SnapshotUrl {
14
+ const parts = url.split("@");
15
+ if (parts.length !== 2) {
16
+ throw new Error(`cannot parse snapshot URL: ${url}`);
17
+ }
18
+ const [fullPath, bucketId] = parts;
19
+
20
+ const pathParts = fullPath.split("/");
21
+ if (pathParts.length < 1) {
22
+ throw new Error(`cannot parse snapshot URL: ${url}`);
23
+ }
24
+ const filename = pathParts[pathParts.length - 1];
25
+ return { bucketId, fullPath, filename };
26
+ }
27
+ }
@@ -4,7 +4,7 @@
4
4
  * See License-AGPL.txt in the project root for license information.
5
5
  */
6
6
 
7
- import uuidv4 = require("uuid/v4");
7
+ import { v4 as uuidv4 } from 'uuid';
8
8
  import { Subscription } from "./accounting-protocol";
9
9
 
10
10
  export interface TeamSubscription {
@@ -5,20 +5,27 @@
5
5
  */
6
6
 
7
7
  import { PrebuiltWorkspaceState } from "./protocol";
8
- import uuidv4 = require("uuid/v4");
8
+ import { v4 as uuidv4 } from 'uuid';
9
+ import { DeepPartial } from "./util/deep-partial";
9
10
 
10
11
  export interface ProjectConfig {
11
12
  '.gitpod.yml': string;
12
13
  }
13
14
 
15
+ export interface ProjectSettings {
16
+ useIncrementalPrebuilds?: boolean;
17
+ }
18
+
14
19
  export interface Project {
15
20
  id: string;
16
21
  name: string;
22
+ slug?: string;
17
23
  cloneUrl: string;
18
24
  teamId?: string;
19
25
  userId?: string;
20
26
  appInstallationId: string;
21
27
  config?: ProjectConfig;
28
+ settings?: ProjectSettings;
22
29
  creationTime: string;
23
30
  /** This is a flag that triggers the HARD DELETION of this entity */
24
31
  deleted?: boolean;
@@ -54,14 +61,18 @@ export namespace Project {
54
61
  }
55
62
  }
56
63
 
64
+ export type PartialProject = DeepPartial<Project> & Pick<Project, 'id'>;
65
+
57
66
  export interface PrebuildWithStatus {
58
67
  info: PrebuildInfo;
59
68
  status: PrebuiltWorkspaceState;
69
+ error?: string;
60
70
  }
61
71
 
62
72
  export interface PrebuildInfo {
63
73
  id: string;
64
74
  buildWorkspaceId: string;
75
+ basedOnPrebuildId?: string;
65
76
 
66
77
  teamId?: string;
67
78
  userId?: string;
@@ -91,9 +102,9 @@ export namespace PrebuildInfo {
91
102
  }
92
103
 
93
104
  export interface StartPrebuildResult {
105
+ prebuildId: string;
94
106
  wsid: string;
95
107
  done: boolean;
96
- didFinish?: boolean;
97
108
  }
98
109
 
99
110
  export interface Team {
@@ -101,6 +112,7 @@ export interface Team {
101
112
  name: string;
102
113
  slug: string;
103
114
  creationTime: string;
115
+ markedDeleted?: boolean;
104
116
  /** This is a flag that triggers the HARD DELETION of this entity */
105
117
  deleted?: boolean;
106
118
  }
@@ -4,6 +4,8 @@
4
4
  * See License-AGPL.txt in the project root for license information.
5
5
  */
6
6
 
7
+ import { repeat } from "./repeat";
8
+
7
9
 
8
10
  interface CacheEntry<T> {
9
11
  key: string;
@@ -41,8 +43,12 @@ export class GarbageCollectedCache<T> {
41
43
  return entry.value;
42
44
  }
43
45
 
46
+ public delete(key: string) {
47
+ this.store.delete(key);
48
+ }
49
+
44
50
  protected regularlyCollectGarbage() {
45
- setInterval(() => this.collectGarbage(), this.gcIntervalSeconds * 1000);
51
+ repeat(() => this.collectGarbage(), this.gcIntervalSeconds * 1000);
46
52
  }
47
53
 
48
54
  protected collectGarbage() {
@@ -27,5 +27,21 @@ const expect = chai.expect
27
27
  expect(longestName.length <= 36, `"${longestName}" is longer than 36 chars (${longestName.length})`).to.be.true;
28
28
  }
29
29
 
30
+ @test public async testCustomName() {
31
+ const data = [
32
+ ['foo','bar','foo-bar-'],
33
+ ['f','bar','.{2,16}-bar-'],
34
+ ['gitpod-io','gitpod','gitpodio-gitpod-'],
35
+ ['this is rather long and has some "§$"% special chars','also here pretty long and needs abbreviation','thisisratherlon-alsohere-'],
36
+ ['breatheco-de', 'python-flask-api-tutorial', 'breathecode-pythonflaska-'],
37
+ ]
38
+ for (const d of data) {
39
+ const id = await generateWorkspaceID(d[0], d[1]);
40
+ expect(id).match(new RegExp("^"+d[2]));
41
+ expect(new GitpodHostUrl().withWorkspacePrefix(id, "eu").workspaceId).to.equal(id);
42
+ expect(id.length <= 36, `"${id}" is longer than 36 chars (${id.length})`).to.be.true;
43
+ }
44
+ }
45
+
30
46
  }
31
47
  module.exports = new TestGenerateWorkspaceId()
@@ -5,8 +5,25 @@
5
5
  */
6
6
  import randomNumber = require("random-number-csprng");
7
7
 
8
- export async function generateWorkspaceID(): Promise<string> {
9
- return (await random(colors))+'-'+(await random(animals))+'-'+(await random(characters, 8));
8
+ export async function generateWorkspaceID(firstSegment?: string, secondSegment?: string): Promise<string> {
9
+ const firstSeg = clean(firstSegment) || await random(colors);
10
+ const secSeg = clean(secondSegment, Math.min(15, 23 - firstSeg.length)) || await random(animals);
11
+ return firstSeg+'-'+secSeg+'-'+(await random(characters, 11));
12
+ }
13
+
14
+ function clean(segment: string | undefined, maxChars: number = 15) {
15
+ if (!segment) {
16
+ return undefined;
17
+ }
18
+ let result = '';
19
+ for (let i =0; i < segment.length; i++) {
20
+ if (characters.indexOf(segment[i]) !== -1) {
21
+ result += segment[i];
22
+ }
23
+ }
24
+ if (result.length >= 2) {
25
+ return result.substring(0, maxChars);
26
+ }
10
27
  }
11
28
 
12
29
  async function random(array: string[], length: number = 1): Promise<string> {
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) 2021 Gitpod GmbH. All rights reserved.
3
+ * Licensed under the GNU Affero General Public License (AGPL).
4
+ * See License-AGPL.txt in the project root for license information.
5
+ */
6
+ import * as cookie from 'cookie';
7
+
8
+
9
+ /**
10
+ * This cookie indicates whether the connected client is a Gitpod user (= "has logged in within the last year") or not.
11
+ * This is used by "gitpod.io" and "www.gitpod.io" to display different content/buttons.
12
+ */
13
+ export const NAME = "gitpod-user";
14
+ export const VALUE = "true";
15
+
16
+ /**
17
+ * @param domain The domain the Gitpod installation is installed onto
18
+ * @returns
19
+ */
20
+ export function options(domain: string): cookie.CookieSerializeOptions {
21
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
22
+ return {
23
+ path: "/", // make sure we send the cookie to all sub-pages
24
+ httpOnly: false,
25
+ secure: false,
26
+ maxAge: 60 * 60 * 24 * 365, // 1 year
27
+ sameSite: "lax", // default: true. "Lax" needed to ensure we see cookies from users that neavigate to gitpod.io from external sites
28
+ domain: `.${domain}`, // explicilty include subdomains to not only cover "gitpod.io", but also "www.gitpod.io" or workspaces
29
+ };
30
+ };
31
+
32
+ export function generateCookie(domain: string): string {
33
+ return cookie.serialize(NAME, VALUE, options(domain));
34
+ };
35
+
36
+ export function isPresent(cookies: string): boolean {
37
+ // needs to match the old (gitpod-user=loggedIn) and new (gitpod-user=true) values to ensure a smooth transition during rollout.
38
+ return !!cookies.match(`${NAME}=`);
39
+ };