Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcf230ff

Browse files
committed
Unify WS implementations across VS Code
1 parent67f7268 commitcf230ff

File tree

10 files changed

+227
-225
lines changed

10 files changed

+227
-225
lines changed

‎src/agentMetadataHelper.ts‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import{Api}from"coder/site/src/api/api";
21
import{WorkspaceAgent}from"coder/site/src/api/typesGenerated";
3-
import{ProxyAgent}from"proxy-agent";
42
import*asvscodefrom"vscode";
53
import{
64
AgentMetadataEvent,
75
AgentMetadataEventSchemaArray,
86
errToStr,
97
}from"./api-helper";
10-
import{watchAgentMetadata}from"./websocket/ws-helper";
8+
import{CoderWebSocketClient}from"./websocket/webSocketClient";
119

1210
exporttypeAgentMetadataWatcher={
1311
onChange:vscode.EventEmitter<null>["event"];
@@ -22,10 +20,9 @@ export type AgentMetadataWatcher = {
2220
*/
2321
exportfunctioncreateAgentMetadataWatcher(
2422
agentId:WorkspaceAgent["id"],
25-
restClient:Api,
26-
httpAgent:ProxyAgent,
23+
webSocketClient:CoderWebSocketClient,
2724
):AgentMetadataWatcher{
28-
constsocket=watchAgentMetadata(restClient,httpAgent,agentId);
25+
constsocket=webSocketClient.watchAgentMetadata(agentId);
2926

3027
letdisposed=false;
3128
constonChange=newvscode.EventEmitter<null>();
@@ -42,7 +39,7 @@ export function createAgentMetadataWatcher(
4239
socket.addEventListener("message",(event)=>{
4340
try{
4441
constmetadata=AgentMetadataEventSchemaArray.parse(
45-
event.parsedMessage?.data,
42+
event.parsedMessage!.data,
4643
);
4744

4845
// Overwrite metadata if it changed.

‎src/api.ts‎

Lines changed: 38 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
import{AxiosInstance,InternalAxiosRequestConfig,isAxiosError}from"axios";
22
import{spawn}from"child_process";
33
import{Api}from"coder/site/src/api/api";
4-
import{
5-
ProvisionerJobLog,
6-
Workspace,
7-
}from"coder/site/src/api/typesGenerated";
4+
import{Workspace}from"coder/site/src/api/typesGenerated";
85
importfsfrom"fs/promises";
96
import{ProxyAgent}from"proxy-agent";
107
import*asvscodefrom"vscode";
11-
import*aswsfrom"ws";
128
import{errToStr}from"./api-helper";
139
import{CertificateError}from"./error";
1410
import{FeatureSet}from"./featureSet";
1511
import{getGlobalFlags}from"./globalFlags";
1612
import{getProxyForUrl}from"./proxy";
1713
import{Storage}from"./storage";
1814
import{expandPath}from"./util";
15+
import{CoderWebSocketClient}from"./websocket/webSocketClient";
1916

2017
exportconstcoderSessionTokenHeader="Coder-Session-Token";
2118

@@ -68,8 +65,12 @@ export async function createHttpAgent(): Promise<ProxyAgent> {
6865

6966
/**
7067
* Create an sdk instance using the provided URL and token and hook it up to
71-
* configuration.The token may be undefined if some other form of
68+
* configuration. The token may be undefined if some other form of
7269
* authentication is being used.
70+
*
71+
* Automatically configures logging interceptors that log:
72+
* - Requests and responses at the trace level
73+
* - Errors at the error level
7374
*/
7475
exportfunctionmakeCoderSdk(
7576
baseUrl:string,
@@ -128,14 +129,14 @@ function addLoggingInterceptors(
128129
){
129130
client.interceptors.request.use(
130131
(config)=>{
131-
constrequestId=crypto.randomUUID();
132+
constrequestId=crypto.randomUUID().replace(/-/g,"");
132133
(configasRequestConfigWithMetadata).metadata={
133134
requestId,
134135
startedAt:Date.now(),
135136
};
136137

137138
logger.trace(
138-
`Request${requestId}:${config.method?.toUpperCase()}${config.url}`,
139+
`req${requestId}:${config.method?.toUpperCase()}${config.url}`,
139140
config.data??"",
140141
);
141142

@@ -146,9 +147,9 @@ function addLoggingInterceptors(
146147
if(isAxiosError(error)){
147148
constmeta=(error.configasRequestConfigWithMetadata)?.metadata;
148149
constrequestId=meta?.requestId??"n/a";
149-
message=`Request${requestId} error`;
150+
message=`req${requestId} error`;
150151
}
151-
logger.warn(message,error);
152+
logger.error(message,error);
152153

153154
returnPromise.reject(error);
154155
},
@@ -161,7 +162,7 @@ function addLoggingInterceptors(
161162
constms=startedAt ?Date.now()-startedAt :undefined;
162163

163164
logger.trace(
164-
`Response${requestId??"n/a"}:${response.status}${
165+
`res${requestId??"n/a"}:${response.status}${
165166
ms!==undefined ?` in${ms}ms` :""
166167
}`,
167168
// { responseBody: response.data }, // TODO too noisy
@@ -177,9 +178,9 @@ function addLoggingInterceptors(
177178
constms=startedAt ?Date.now()-startedAt :undefined;
178179

179180
conststatus=error.response?.status??"unknown";
180-
message=`Response${requestId}:${status}${ms!==undefined ?` in${ms}ms` :""}`;
181+
message=`res${requestId}:${status}${ms!==undefined ?` in${ms}ms` :""}`;
181182
}
182-
logger.warn(message,error);
183+
logger.error(message,error);
183184

184185
returnPromise.reject(error);
185186
},
@@ -262,71 +263,44 @@ export async function startWorkspaceIfStoppedOrFailed(
262263
*/
263264
exportasyncfunctionwaitForBuild(
264265
restClient:Api,
266+
webSocketClient:CoderWebSocketClient,
265267
writeEmitter:vscode.EventEmitter<string>,
266268
workspace:Workspace,
267269
):Promise<Workspace>{
268-
constbaseUrlRaw=restClient.getAxiosInstance().defaults.baseURL;
269-
if(!baseUrlRaw){
270-
thrownewError("No base URL set on REST client");
271-
}
272-
273270
// This fetches the initial bunch of logs.
274271
constlogs=awaitrestClient.getWorkspaceBuildLogs(
275272
workspace.latest_build.id,
276273
);
277274
logs.forEach((log)=>writeEmitter.fire(log.output+"\r\n"));
278275

279-
// This follows the logs for new activity!
280-
// TODO: watchBuildLogsByBuildId exists, but it uses `location`.
281-
// Would be nice if we could use it here.
282-
letpath=`/api/v2/workspacebuilds/${workspace.latest_build.id}/logs?follow=true`;
283-
if(logs.length){
284-
path+=`&after=${logs[logs.length-1].id}`;
285-
}
286-
287-
constagent=awaitcreateHttpAgent();
288276
awaitnewPromise<void>((resolve,reject)=>{
289-
try{
290-
// TODO move to `ws-helper`
291-
constbaseUrl=newURL(baseUrlRaw);
292-
constproto=baseUrl.protocol==="https:" ?"wss:" :"ws:";
293-
constsocketUrlRaw=`${proto}//${baseUrl.host}${path}`;
294-
consttoken=restClient.getAxiosInstance().defaults.headers.common[
295-
coderSessionTokenHeader
296-
]asstring|undefined;
297-
constsocket=newws.WebSocket(newURL(socketUrlRaw),{
298-
agent:agent,
299-
followRedirects:true,
300-
headers:token
301-
?{
302-
[coderSessionTokenHeader]:token,
303-
}
304-
:undefined,
305-
});
306-
socket.binaryType="nodebuffer";
307-
socket.on("message",(data)=>{
308-
constbuf=dataasBuffer;
309-
constlog=JSON.parse(buf.toString())asProvisionerJobLog;
310-
writeEmitter.fire(log.output+"\r\n");
311-
});
312-
socket.on("error",(error)=>{
313-
reject(
314-
newError(
315-
`Failed to watch workspace build using${socketUrlRaw}:${errToStr(error,"no further details")}`,
316-
),
317-
);
318-
});
319-
socket.on("close",()=>{
320-
resolve();
321-
});
322-
}catch(error){
323-
// If this errors, it is probably a malformed URL.
324-
reject(
277+
constrejectError=(error:unknown)=>{
278+
constbaseUrlRaw=restClient.getAxiosInstance().defaults.baseURL!;
279+
returnreject(
325280
newError(
326281
`Failed to watch workspace build on${baseUrlRaw}:${errToStr(error,"no further details")}`,
327282
),
328283
);
329-
}
284+
};
285+
286+
constsocket=webSocketClient.watchBuildLogsByBuildId(
287+
workspace.latest_build.id,
288+
logs,
289+
);
290+
constcloseHandler=()=>{
291+
resolve();
292+
};
293+
socket.addEventListener("close",closeHandler);
294+
socket.addEventListener("message",(data)=>{
295+
constlog=data.parsedMessage!;
296+
writeEmitter.fire(log.output+"\r\n");
297+
});
298+
socket.addEventListener("error",(error)=>{
299+
// Do not want to trigger the close handler.
300+
socket.removeEventListener("close",closeHandler);
301+
socket.close();
302+
rejectError(error);
303+
});
330304
});
331305

332306
writeEmitter.fire("Build complete\r\n");

‎src/extension.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { CertificateError, getErrorDetail } from "./error";
1010
import{Remote}from"./remote";
1111
import{Storage}from"./storage";
1212
import{toSafeHost}from"./util";
13+
import{CoderWebSocketClient}from"./websocket/webSocketClient";
1314
import{WorkspaceQuery,WorkspaceProvider}from"./workspacesProvider";
1415

1516
exportasyncfunctionactivate(ctx:vscode.ExtensionContext):Promise<void>{
@@ -69,18 +70,23 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
6970

7071
// TODO this won't get updated when users change their settings; Listen to changes and update this
7172
consthttpAgent=awaitcreateHttpAgent();
73+
constwebSocketClient=newCoderWebSocketClient(
74+
restClient,
75+
httpAgent,
76+
storage,
77+
);
7278
constmyWorkspacesProvider=newWorkspaceProvider(
7379
WorkspaceQuery.Mine,
7480
restClient,
7581
storage,
76-
httpAgent,
82+
webSocketClient,
7783
5,
7884
);
7985
constallWorkspacesProvider=newWorkspaceProvider(
8086
WorkspaceQuery.All,
8187
restClient,
8288
storage,
83-
httpAgent,
89+
webSocketClient,
8490
);
8591

8692
// createTreeView, unlike registerTreeDataProvider, gives us the tree view API

‎src/inbox.ts‎

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import{Api}from"coder/site/src/api/api";
21
import{
32
Workspace,
43
GetInboxNotificationResponse,
54
}from"coder/site/src/api/typesGenerated";
6-
import{ProxyAgent}from"proxy-agent";
75
import*asvscodefrom"vscode";
8-
import{errToStr}from"./api-helper";
96
import{typeStorage}from"./storage";
10-
import{OneWayCodeWebSocket}from"./websocket/OneWayCodeWebSocket";
11-
import{watchInboxNotifications}from"./websocket/ws-helper";
7+
import{OneWayCodeWebSocket}from"./websocket/oneWayCodeWebSocket";
8+
import{CoderWebSocketClient}from"./websocket/webSocketClient";
129

1310
// These are the template IDs of our notifications.
1411
// Maybe in the future we should avoid hardcoding
@@ -23,8 +20,7 @@ export class Inbox implements vscode.Disposable {
2320

2421
constructor(
2522
workspace:Workspace,
26-
httpAgent:ProxyAgent,
27-
restClient:Api,
23+
webSocketClient:CoderWebSocketClient,
2824
storage:Storage,
2925
){
3026
this.#storage=storage;
@@ -36,9 +32,7 @@ export class Inbox implements vscode.Disposable {
3632

3733
constwatchTargets=[workspace.id];
3834

39-
this.#socket=watchInboxNotifications(
40-
restClient,
41-
httpAgent,
35+
this.#socket=webSocketClient.watchInboxNotifications(
4236
watchTemplates,
4337
watchTargets,
4438
);
@@ -47,18 +41,14 @@ export class Inbox implements vscode.Disposable {
4741
this.#storage.output.info("Listening to Coder Inbox");
4842
});
4943

50-
this.#socket.addEventListener("error",(error)=>{
51-
this.notifyError(error);
44+
this.#socket.addEventListener("error",()=>{
45+
// Errors are already logged internally
5246
this.dispose();
5347
});
5448

5549
this.#socket.addEventListener("message",(data)=>{
56-
try{
57-
constinboxMessage=data.parsedMessage!;
58-
vscode.window.showInformationMessage(inboxMessage.notification.title);
59-
}catch(error){
60-
this.notifyError(error);
61-
}
50+
constinboxMessage=data.parsedMessage!;
51+
vscode.window.showInformationMessage(inboxMessage.notification.title);
6252
});
6353
}
6454

@@ -69,12 +59,4 @@ export class Inbox implements vscode.Disposable {
6959
this.#disposed=true;
7060
}
7161
}
72-
73-
privatenotifyError(error:unknown){
74-
constmessage=errToStr(
75-
error,
76-
"Got empty error while monitoring Coder Inbox",
77-
);
78-
this.#storage.output.error(message);
79-
}
8062
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp