-
-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Supporting csharpier server for 0.28.0+
closes #1109
- Loading branch information
Showing
11 changed files
with
1,460 additions
and
1,507 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { ChildProcessWithoutNullStreams, spawn } from "child_process"; | ||
import { Logger } from "./Logger"; | ||
import { FormatFileParameter, FormatFileResult, ICSharpierProcess2 } from "./ICSharpierProcess"; | ||
import fetch from "node-fetch"; | ||
|
||
export class CSharpierProcessServer implements ICSharpierProcess2 { | ||
private csharpierPath: string; | ||
private logger: Logger; | ||
private port: number = 0; | ||
private process: ChildProcessWithoutNullStreams | undefined; | ||
private processFailedToStart = false; | ||
private version: string; | ||
|
||
constructor(logger: Logger, csharpierPath: string, workingDirectory: string, version: string) { | ||
this.logger = logger; | ||
this.csharpierPath = csharpierPath; | ||
this.spawnProcess(csharpierPath, workingDirectory); | ||
this.version = version; | ||
|
||
this.logger.debug("Warm CSharpier with initial format"); | ||
// warm by formatting a file twice, the 3rd time is when it gets really fast | ||
this.formatFile("public class ClassName { }", "/Temp/Test.cs").then(() => { | ||
this.formatFile("public class ClassName { }", "/Temp/Test.cs"); | ||
}); | ||
} | ||
|
||
getProcessFailedToStart(): boolean { | ||
return this.processFailedToStart; | ||
} | ||
|
||
private spawnProcess(csharpierPath: string, workingDirectory: string) { | ||
const csharpierProcess = spawn(csharpierPath, ["--server"], { | ||
stdio: "pipe", | ||
cwd: workingDirectory, | ||
env: { ...process.env, DOTNET_NOLOGO: "1" }, | ||
}); | ||
|
||
csharpierProcess.on("error", data => { | ||
this.logger.warn( | ||
"Failed to spawn the needed csharpier process. Formatting cannot occur.", | ||
data, | ||
); | ||
this.processFailedToStart = true; | ||
}); | ||
|
||
let output = ""; | ||
const regex = /^Started on (\d+)/; | ||
|
||
csharpierProcess.stdout.on("data", chunk => { | ||
output += chunk; | ||
if (regex.test(output) && this.port === 0) { | ||
this.port = parseInt(output.match(regex)![1], 10); | ||
this.logger.debug("Connecting via port " + this.port); | ||
this.process = csharpierProcess; | ||
} | ||
}); | ||
} | ||
|
||
public async formatFile(content: string, filePath: string): Promise<string> { | ||
const parameter = { | ||
fileName: filePath, | ||
fileContents: content, | ||
}; | ||
const result = await this.formatFile2(parameter); | ||
return result?.formattedFile ?? ""; | ||
} | ||
|
||
public async formatFile2(parameter: FormatFileParameter): Promise<FormatFileResult | null> { | ||
if (this.processFailedToStart) { | ||
this.logger.warn("CSharpier process failed to start. Formatting cannot occur."); | ||
return null; | ||
} | ||
|
||
if (typeof this.process === "undefined") { | ||
await new Promise(r => setTimeout(r, 2000)); | ||
} | ||
|
||
if (this.processFailedToStart || typeof this.process === "undefined") { | ||
this.logger.warn("CSharpier process failed to start. Formatting cannot occur."); | ||
return null; | ||
} | ||
|
||
try { | ||
const url = "http://localhost:" + this.port + "/format"; | ||
|
||
const response = await fetch(url, { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify(parameter), | ||
}); | ||
|
||
if (response.status !== 200) { | ||
this.logger.warn( | ||
"Csharpier server returned non-200 status code of " + response.status, | ||
); | ||
return null; | ||
} | ||
|
||
return await response.json(); | ||
} catch (e) { | ||
this.logger.warn("Failed posting to the csharpier server. " + e); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
dispose() { | ||
if (typeof this.process !== "undefined") { | ||
(this.process.stdin as any).pause(); | ||
this.process.kill(); | ||
} | ||
} | ||
|
||
getVersion(): string { | ||
return this.version; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.