Conversation
There was a problem hiding this comment.
Pull request overview
This PR substantially reworks the Go server configuration/runtime and replaces the TypeScript wrapper API, while adding logging, Docker packaging, DNS cache changes, and new build outputs.
Changes:
- Moves Go config loading into
wisp/config.goand adds new runtime options/logging/DNS behavior. - Replaces the old TypeScript builder/server wrapper with a
Mrrowispclass. - Updates packaging/build outputs, Docker support, and example configuration.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Broadens ignored local binary names. |
Dockerfile |
Adds container build/runtime image. |
build.sh |
Changes binary output layout and package file copying. |
example.config.json |
Replaces/expands sample server configuration. |
go.mod |
Updates Go version and dependencies. |
go.sum |
Updates dependency checksums. |
main.go |
Simplifies config loading and adds graceful shutdown/static serving. |
package.json |
Updates package metadata, scripts, dependencies, and types entry. |
pnpm-lock.yaml |
Adds pnpm lockfile. |
src/index.ts |
Replaces exports with new Mrrowisp wrapper implementation. |
src/logger.ts |
Adds TypeScript-side colored logger. |
src/path.ts |
Changes runtime paths for config and platform binaries. |
src/server/index.ts |
Removes old builder/server implementation. |
src/types.d.ts |
Removes old public TypeScript declarations. |
wisp/config.go |
Adds Go config model/load/copy helpers. |
wisp/dnscache.go |
Adds DNS cache config, TTL cleanup, singleflight, and IP ordering. |
wisp/logger.go |
Adds Go logger abstraction. |
wisp/twisp.go |
Updates extended WebSocket length encoding. |
wisp/v2.go |
Changes v2 extensions/auth handling. |
wisp/windows.go |
Adds Windows TWisp stubs. |
wisp/wisp-connection.go |
Adds connection fields, pending-data limits, pooled write path, and close handling changes. |
wisp/wisp-stream.go |
Adds hostname normalization, proxy handling changes, pending-data accounting, and logging. |
wisp/wisp.go |
Changes handler setup, resolver init, compression behavior, and v2 helper. |
wisp/wsreader.go |
Adds WebSocket frame validation and max-payload handling. |
Comments suppressed due to low confidence (10)
wisp/wisp.go:53
- PermessageDeflate is now hard-coded off even though Config still exposes WebsocketPermessageDeflate. Any configuration that enables compression will be silently ignored, which is a regression from the previous behavior and makes the option ineffective.
buf := make([]byte, readBufSize)
return buf
},
}
src/index.ts:182
- spawn errors are no longer handled. If the packaged binary is missing, not executable, or cannot be started, ChildProcess emits an 'error' event; without a listener this can become an unhandled error and crash the consumer process instead of failing start() predictably.
this.process = spawn(binPath, ["--config", JSON.stringify(this.config)], {
stdio: "pipe"
});
wisp/wisp-stream.go:88
- socks4a:// URLs are normalized to socks4://, but the code still constructs a SOCKS5 dialer unconditionally. A SOCKS4/SOCKS4a proxy configured here will be spoken to with the SOCKS5 protocol and fail to connect; either reject unsupported schemes or select the correct proxy implementation.
return
}
resolvedHostname = selected
}
src/index.ts:253
- stop() is async but resolves immediately after sending SIGTERM instead of waiting for the child process to exit. Callers that await stop() can proceed while the server is still holding the port, making immediate restarts race and potentially fail the port availability check.
async stop() {
if (this.process) {
this.process.kill("SIGTERM");
this.process = undefined;
wisp/wsreader.go:110
- Invalid or reserved WebSocket opcodes are silently ignored. Per the WebSocket protocol these are protocol errors and should close the connection (for example with 1002); continuing leaves misbehaving clients connected and makes the empty if block ineffective.
continue
case 0x1:
c.handleWispFrame(payload)
wisp/config.go:36
- Port whitelist entries are part of the new Config but are never consulted in handleConnect or anywhere else. Even if a config manages to load this field, connections to ports outside the whitelist will still be allowed.
Whitelist struct {
Hostnames map[string]struct{}
Ports map[uint16]struct{}
}
wisp/wisp-connection.go:84
- queueWritePooled marks frames as pooled, but writeLoop never checks req.pool after the send. These frames are allocated per read and are never returned to any pool, so the new pooled path adds complexity without reducing allocations.
c.terminateNetwork()
}
func (c *wispConnection) writeLoop() {
for req := range c.writeCh {
src/index.ts:178
- start() resolves immediately after spawning the child instead of waiting for the server's readiness signal. Callers can successfully await start() and then route traffic before the Go server is listening, causing transient proxy failures; the previous implementation resolved only after the startup log was observed.
async start() {
if (await detect(this.config.port) !== this.config.port) {
logger.error(`port ${this.config.port} is not available!! >w<`);
return;
}
wisp/wisp.go:94
- This helper identifies configurations that must use v2, but it is never called. As a result a client can omit Sec-WebSocket-Protocol and be handled as v1, bypassing the password-auth handshake even when PasswordAuthRequired is true.
if response != "" {
_, _ = w.Write([]byte(response))
}
return
}
src/index.ts:169
- Instances without an override share the same defaultConfig object by reference. Because config is public and mutable, changes made through one Mrrowisp instance can leak into later instances; clone the default config for every constructor call before applying overrides.
constructor(config?: Partial<MrrowispConfig>) {
this.config = defaultConfig;
this.process = undefined;
if (config) {
this.config = { ...this.config, ...config };
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+19
to
+20
| AllowTCP bool `json:"allowTCP"` | ||
| AllowUDP bool `json:"allowUDP"` |
Comment on lines
+22
to
+24
| AllowDirectIP bool `json:"allowDirectIP"` | ||
| AllowPrivateIPs bool `json:"allowPrivateIPs"` | ||
| AllowLoopbackIPs bool `json:"allowLoopbackIPs"` |
| /** | ||
| * Username/password credential map. | ||
| */ | ||
| passwordUsers: Map<string, string>; |
| @@ -35,15 +33,19 @@ type wispStream struct { | |||
|
|
|||
| const dnsLookupTimeout = 10 * time.Second | |||
Comment on lines
+52
to
+53
| ParseRealIP bool `json:"parseRealIP"` | ||
| NonWSResponse string `json:"nonWSResponse"` |
Comment on lines
+19
to
+20
| AllowTCP bool `json:"allowTCP"` | ||
| AllowUDP bool `json:"allowUDP"` |
Comment on lines
7
to
9
| warn: 1, | ||
| error: 2, | ||
| info: 3, |
Comment on lines
29
to
32
| opcode := headerBuffer[0] & 0x0F | ||
| masked := headerBuffer[1]&0x80 != 0 | ||
| lengthCode := headerBuffer[1] & 0x7F | ||
|
|
Comment on lines
+29
to
+32
| Blacklist struct { | ||
| Hostnames map[string]struct{} | ||
| Ports map[uint16]struct{} | ||
| } |
Comment on lines
+29
to
+32
| Blacklist struct { | ||
| Hostnames map[string]struct{} | ||
| Ports map[uint16]struct{} | ||
| } |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.