Skip to content

Commit 6a35ab1

Browse files
committed
Add (unimplemented) webview server
1 parent 3a78c09 commit 6a35ab1

2 files changed

Lines changed: 110 additions & 73 deletions

File tree

entry.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { Server } from "./server";
1+
import { MainServer, WebviewServer } from "./server";
22

3-
const server = new Server();
4-
server.listen();
3+
const webviewServer = new WebviewServer();
4+
const server = new MainServer(webviewServer);
5+
webviewServer.listen(8444).then(async () => {
6+
await server.listen(8443);
7+
console.log(`Main server serving ${server.address}`);
8+
console.log(`Webview server serving ${webviewServer.address}`);
9+
}).catch((error) => {
10+
console.error(error);
11+
process.exit(1);
12+
});

server.ts

Lines changed: 99 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -54,30 +54,24 @@ export class HttpError extends Error {
5454
}
5555
}
5656

57-
export class Server {
58-
// Used to notify the IPC server that there is a new client.
59-
public readonly _onDidClientConnect = new Emitter<ClientConnectionEvent>();
60-
public readonly onDidClientConnect = this._onDidClientConnect.event;
61-
62-
private readonly rootPath = path.resolve(__dirname, "../../..");
63-
64-
// This is separate instead of just extending this class since we can't
65-
// use properties in the super call. This manages channels.
66-
private readonly ipc = new IPCServer(this.onDidClientConnect);
67-
68-
// The web server.
69-
private readonly server: http.Server;
70-
71-
private readonly environmentService: EnvironmentService;
72-
private readonly logService: ILogService;
73-
74-
// Persistent connections. These can reconnect within a timeout.
75-
private readonly connections = new Map<ConnectionType, Map<string, Connection>>();
57+
export abstract class Server {
58+
// The underlying web server.
59+
protected readonly server: http.Server;
7660

7761
public constructor() {
7862
this.server = http.createServer(async (request, response): Promise<void> => {
7963
try {
80-
const [content, headers] = await this.handleRequest(request);
64+
if (request.method !== "GET") {
65+
throw new HttpError(
66+
`Unsupported method ${request.method}`,
67+
HttpCode.BadRequest,
68+
);
69+
}
70+
71+
const parsedUrl = url.parse(request.url || "", true);
72+
const requestPath = parsedUrl.pathname || "/";
73+
74+
const [content, headers] = await this.handleRequest(request, parsedUrl, requestPath);
8175
response.writeHead(HttpCode.Ok, {
8276
"Cache-Control": "max-age=86400",
8377
// TODO: ETag?
@@ -89,6 +83,48 @@ export class Server {
8983
response.end(error.message);
9084
}
9185
});
86+
}
87+
88+
protected abstract handleRequest(
89+
request: http.IncomingMessage,
90+
parsedUrl: url.UrlWithParsedQuery,
91+
requestPath: string,
92+
): Promise<[string | Buffer, http.OutgoingHttpHeaders]>;
93+
94+
public listen(port: number): Promise<void> {
95+
return new Promise((resolve, reject) => {
96+
this.server.on("error", reject);
97+
this.server.listen(port, resolve);
98+
});
99+
}
100+
101+
public get address(): string {
102+
const address = this.server.address();
103+
const endpoint = typeof address !== "string"
104+
? ((address.address === "::" ? "localhost" : address.address) + ":" + address.port)
105+
: address;
106+
return `http://${endpoint}`;
107+
}
108+
}
109+
110+
export class MainServer extends Server {
111+
// Used to notify the IPC server that there is a new client.
112+
public readonly _onDidClientConnect = new Emitter<ClientConnectionEvent>();
113+
public readonly onDidClientConnect = this._onDidClientConnect.event;
114+
115+
private readonly rootPath = path.resolve(__dirname, "../../..");
116+
117+
// This is separate instead of just extending this class since we can't
118+
// use properties in the super call. This manages channels.
119+
private readonly ipc = new IPCServer(this.onDidClientConnect);
120+
121+
// Persistent connections. These can reconnect within a timeout.
122+
private readonly connections = new Map<ConnectionType, Map<string, Connection>>();
123+
124+
private readonly services = new ServiceCollection();
125+
126+
public constructor(private readonly webviewServer: WebviewServer) {
127+
super();
92128

93129
this.server.on("upgrade", async (request, socket) => {
94130
const protocol = this.createProtocol(request, socket);
@@ -98,56 +134,44 @@ export class Server {
98134
protocol.dispose(error);
99135
}
100136
});
137+
}
101138

102-
this.server.on("error", (error) => {
103-
console.error(error);
104-
process.exit(1);
105-
});
139+
public async listen(port: number): Promise<void> {
140+
const args = validatePaths(parseMainProcessArgv(process.argv));
106141

107-
let args: ParsedArgs;
108-
try {
109-
args = parseMainProcessArgv(process.argv);
110-
args = validatePaths(args);
111-
} catch (error) {
112-
console.error(error.message);
113-
return process.exit(1);
114-
}
115-
116-
const services = new ServiceCollection();
117-
this.environmentService = new EnvironmentService(args, process.execPath);
118-
services.set(IEnvironmentService, this.environmentService);
142+
const environmentService = new EnvironmentService(args, process.execPath);
143+
this.services.set(IEnvironmentService, environmentService);
119144

120-
this.logService = new SpdLogService(
145+
const logService = new SpdLogService(
121146
RemoteExtensionLogFileName,
122-
this.environmentService.logsPath,
123-
getLogLevel(this.environmentService),
147+
environmentService.logsPath,
148+
getLogLevel(environmentService),
124149
);
125-
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(this.logService));
150+
this.services.set(ILogService, logService);
126151

127-
const instantiationService = new InstantiationService(services);
152+
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService));
153+
154+
const instantiationService = new InstantiationService(this.services);
128155
instantiationService.invokeFunction(() => {
129156
instantiationService.createInstance(LogsDataCleaner);
130157
this.ipc.registerChannel(
131158
REMOTE_FILE_SYSTEM_CHANNEL_NAME,
132-
new FileProviderChannel(this.logService),
159+
new FileProviderChannel(logService),
133160
);
134161
this.ipc.registerChannel(
135162
"remoteextensionsenvironment",
136-
new ExtensionEnvironmentChannel(this.environmentService, this.logService),
163+
new ExtensionEnvironmentChannel(environmentService, logService),
137164
);
138165
});
139-
}
140166

141-
private async handleRequest(request: http.IncomingMessage): Promise<[string | Buffer, http.OutgoingHttpHeaders]> {
142-
if (request.method !== "GET") {
143-
throw new HttpError(
144-
`Unsupported method ${request.method}`,
145-
HttpCode.BadRequest,
146-
);
147-
}
167+
await super.listen(port);
168+
}
148169

149-
const parsedUrl = url.parse(request.url || "", true);
150-
const requestPath = parsedUrl.pathname || "/";
170+
protected async handleRequest(
171+
request: http.IncomingMessage,
172+
parsedUrl: url.UrlWithParsedQuery,
173+
requestPath: string,
174+
): Promise<[string | Buffer, http.OutgoingHttpHeaders]> {
151175
if (requestPath === "/") {
152176
const htmlPath = path.join(
153177
this.rootPath,
@@ -159,21 +183,29 @@ export class Server {
159183
const remoteAuthority = request.headers.host as string;
160184
const transformer = getUriTransformer(remoteAuthority);
161185

162-
const webviewEndpoint = "";
186+
const webviewEndpoint = this.webviewServer.address;
163187

164188
const cwd = process.env.VSCODE_CWD || process.cwd();
165189
const workspacePath = parsedUrl.query.workspace as string | undefined;
166190
const folderPath = !workspacePath ? parsedUrl.query.folder as string | undefined || cwd: undefined;
167191

168192
const options: Options = {
169193
WORKBENCH_WEB_CONGIGURATION: {
170-
workspaceUri: workspacePath ? transformer.transformOutgoing(URI.file(sanitizeFilePath(workspacePath, cwd))) : undefined,
171-
folderUri: folderPath ? transformer.transformOutgoing(URI.file(sanitizeFilePath(folderPath, cwd))) : undefined,
194+
workspaceUri: workspacePath
195+
? transformer.transformOutgoing(URI.file(sanitizeFilePath(workspacePath, cwd)))
196+
: undefined,
197+
folderUri: folderPath
198+
? transformer.transformOutgoing(URI.file(sanitizeFilePath(folderPath, cwd)))
199+
: undefined,
172200
remoteAuthority,
173201
webviewEndpoint,
174202
},
175-
REMOTE_USER_DATA_URI: transformer.transformOutgoing(this.environmentService.webUserDataHome),
176-
PRODUCT_CONFIGURATION: require.__$__nodeRequire(path.resolve(getPathFromAmdModule(require, ""), "../product.json")),
203+
REMOTE_USER_DATA_URI: transformer.transformOutgoing(
204+
(this.services.get(IEnvironmentService) as EnvironmentService).webUserDataHome,
205+
),
206+
PRODUCT_CONFIGURATION: require.__$__nodeRequire(
207+
path.resolve(getPathFromAmdModule(require, ""), "../product.json"),
208+
),
177209
CONNECTION_AUTH_TOKEN: "",
178210
};
179211

@@ -239,17 +271,6 @@ export class Server {
239271
);
240272
}
241273

242-
public listen(port: number = 8443): void {
243-
this.server.listen(port, () => {
244-
const address = this.server.address();
245-
const location = typeof address === "string"
246-
? address
247-
: `port ${address.port}`;
248-
console.log(`Listening on ${location}`);
249-
console.log(`Serving ${this.rootPath}`);
250-
});
251-
}
252-
253274
private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> {
254275
switch (message.desiredConnectionType) {
255276
case ConnectionType.ExtensionHost:
@@ -290,7 +311,9 @@ export class Server {
290311
onDidClientDisconnect: connection.onClose,
291312
});
292313
} else {
293-
connection = new ExtensionHostConnection(protocol, this.logService);
314+
connection = new ExtensionHostConnection(
315+
protocol, this.services.get(ILogService) as ILogService,
316+
);
294317
}
295318
connections.set(protocol.options.reconnectionToken, connection);
296319
connection.onClose(() => {
@@ -309,3 +332,9 @@ export class Server {
309332
return undefined;
310333
}
311334
}
335+
336+
export class WebviewServer extends Server {
337+
protected async handleRequest(): Promise<[string | Buffer, http.OutgoingHttpHeaders]> {
338+
throw new Error("not implemented");
339+
}
340+
}

0 commit comments

Comments
 (0)