88// - Proper logging.
99// - Proper error handling in general.
1010// - Support both websocket and regular GET requests on /.
11+ // - Write logs in the standard Tox format.
1112//
1213// Copyright 2022-2025 The TokTok team.
1314// Copyright 2021 Michael.liu.
@@ -22,6 +23,9 @@ import (
2223 "log"
2324 "net"
2425 "net/http"
26+ "os"
27+ "regexp"
28+ "strings"
2529
2630 "github.com/gorilla/websocket"
2731)
@@ -31,18 +35,20 @@ var (
3135 targetAddr = flag .String ("t" , "127.0.0.1:5900" , "tcp service address" )
3236)
3337
38+ // Should be enough to fit any Tox TCP packets.
39+ const bufferSize = 2048
40+
3441var upgrader = websocket.Upgrader {
35- // Should be enough to fit any Tox TCP packets.
36- ReadBufferSize : 2048 ,
37- WriteBufferSize : 2048 ,
42+ ReadBufferSize : bufferSize ,
43+ WriteBufferSize : bufferSize ,
3844 Subprotocols : []string {"binary" },
3945 CheckOrigin : func (r * http.Request ) bool {
4046 return true
4147 },
4248}
4349
4450func forwardTCP (wsconn * websocket.Conn , conn net.Conn ) {
45- var tcpbuffer [2048 ]byte
51+ var tcpbuffer [bufferSize ]byte
4652 defer wsconn .Close ()
4753 defer conn .Close ()
4854 for {
@@ -97,7 +103,52 @@ func serveWs(w http.ResponseWriter, r *http.Request) {
97103
98104}
99105
106+ type logEntry struct {
107+ time string
108+ file string
109+ line string
110+ message string
111+ }
112+
113+ type logWriter struct {}
114+
115+ // Write implements the io.Writer interface.
116+ //
117+ // This parses the Go log format and outputs it as the standard Tox format.
118+ //
119+ // Go format:
120+ // "15:02:46.433968 websockify.go:106: Starting up websockify endpoint\n"
121+ //
122+ // Standard Tox format:
123+ // "[15:02:46.433 UTC] (websockify) websockify.go:106 : Debug: Starting up websockify endpoint"
124+ func (writer * logWriter ) Write (bytes []byte ) (int , error ) {
125+ // Parse the Go log format (skipping the last 3 digits of the microseconds).
126+ re := regexp .MustCompile (`^(\d{2}:\d{2}:\d{2}\.\d{3})\d{3} ([^:]+):(\d+): (.*)$` )
127+ matches := re .FindStringSubmatch (strings .TrimSuffix (string (bytes ), "\n " ))
128+ if len (matches ) != 5 {
129+ // If the log format doesn't match, just print it as is.
130+ fmt .Fprintf (os .Stderr , "%s (unparsed)" , string (bytes ))
131+ return len (bytes ), nil
132+ }
133+
134+ // Extract the log fields.
135+ entry := logEntry {
136+ time : matches [1 ],
137+ file : matches [2 ],
138+ line : matches [3 ],
139+ message : matches [4 ],
140+ }
141+
142+ // Print the Go log format in the standard Tox format to stderr.
143+ fmt .Fprintf (os .Stderr , "[%s UTC] (websockify) %s:%s : Debug: %s\n " , entry .time , entry .file , entry .line , entry .message )
144+
145+ return len (bytes ), nil
146+ }
147+
100148func main () {
149+ log .SetFlags (log .Ltime | log .Lshortfile | log .LUTC | log .Lmicroseconds )
150+ log .SetOutput (new (logWriter ))
151+
101152 flag .Parse ()
102153 log .Println ("Starting up websockify endpoint" )
103154
0 commit comments