Abstract WebSocket adapter interface to support multiple libraries
This PR introduces a WebSocket adapter interface to decouple go-vncproxy from any specific WebSocket library, enabling support for multiple WebSocket implementations while maintaining full backward compatibility.
Problem
Previously, go-vncproxy was tightly coupled to golang.org/x/net/websocket, making it difficult for users to integrate with other popular WebSocket libraries like github.com/gorilla/websocket or github.com/coder/websocket.
Solution
WebSocket Adapter Interface
Introduced two key interfaces:
type WebSocketAdapter interface {
Read(p []byte) (n int, err error)
Write(p []byte) (n int, err error)
Close() error
RemoteAddr() string
Request() *http.Request
SetBinaryMode() error
}
type WebSocketUpgrader interface {
Upgrade(w http.ResponseWriter, r *http.Request) (WebSocketAdapter, error)
}
Backward Compatibility
All existing code continues to work unchanged:
// This still works exactly as before
vncProxy := vncproxy.New(&vncproxy.Config{...})
r.GET("/ws", func(ctx *gin.Context) {
h := websocket.Handler(vncProxy.ServeWS)
h.ServeHTTP(ctx.Writer, ctx.Request)
})
New Extensible API
Users can now easily integrate custom WebSocket libraries:
// Using the new adapter interface
vncProxy := vncproxy.New(&vncproxy.Config{
WebSocketAdapter: customUpgrader, // Any WebSocket library
})
r.GET("/ws", func(ctx *gin.Context) {
handler := vncProxy.HTTPHandler()
handler.ServeHTTP(ctx.Writer, ctx.Request)
})
Custom Adapter Support
The PR includes documentation and examples for implementing custom adapters, such as for Gorilla WebSocket:
type GorillaWebSocketAdapter struct {
conn *websocket.Conn
request *http.Request
}
func (a *GorillaWebSocketAdapter) Read(p []byte) (n int, err error) {
_, data, err := a.conn.ReadMessage()
if err != nil {
return 0, err
}
return copy(p, data), nil
}
// ... implement other interface methods
Changes Made
-
New files:
-
websocket_adapter.go: Core interface definitions -
net_websocket_adapter.go: Default adapter for golang.org/x/net/websocket -
websocket_adapter_test.go: Comprehensive test suite -
example_gorilla_adapter.go: Example adapter implementation
-
-
Modified files:
-
proxy.go: Added adapter support while preserving existing API -
peer.go: Updated to use WebSocketAdapter interface -
example/main.go: Enhanced with usage examples -
README.md: Comprehensive documentation with examples
-
Benefits
- 🔌 Library Independence: Support for any WebSocket library
- 🔄 Zero Breaking Changes: Complete backward compatibility
- 📦 Batteries Included: Default implementation using existing library
- 🎯 Minimal Footprint: Surgical changes with maximum extensibility
- 📚 Well Documented: Clear examples for custom implementations
Testing
Added comprehensive tests including:
- Mock WebSocket adapter implementation
- Integration tests with the default adapter
- Interface compliance verification
All existing tests continue to pass, ensuring no regressions.
This change significantly improves the library's flexibility and extensibility while maintaining its simplicity and backward compatibility.
Original prompt
This section details on the original issue you should resolve
<issue_title>Abstract a WebSocket adapter interface to support multiple libraries</issue_title> <issue_description>To improve compatibility with different WebSocket libraries, introduce an abstraction layer via a WebSocket adapter interface. Provide a default implementation using golang.org/x/net/websocket and allow custom adapters for libraries such as github.com/coder/websocket and github.com/gorilla/websocket.
Proposed approach:
- Define a unified WebSocketAdapter interface that covers connect/upgrade, read, write, close, and error handling, including binary/text frames and context cancellation.
- Implement the default adapter based on golang.org/x/net/websocket.
- Expose clear extension points so users can implement adapters for other libraries (e.g., coder/websocket, gorilla/websocket).
- Document how to implement and plug in a custom adapter.
This change increases extensibility and decouples go-vncproxy from any specific WebSocket library.</issue_description>
<agent_instructions>implement this</agent_instructions>
Comments on the Issue (you are @copilot in this section)
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.