Skip to content

Commit b8710ec

Browse files
committed
Simplify: remove TTL/expiry, keep session alive while bridge connected
- Remove SESSION_TTL and expiresAt — session stays alive as long as bridge is connected (heartbeat updates lastActivity) - Remove file upload/download API and WebSocket protocol - Remove file_read/file_write from bridge - Show connect URL (https://connectyouragent.com/c/CODE) in bridge terminal output - Simplify frontend: remove expiry display, just show connected/waiting - Clean up tests: remove file/expiry tests that no longer apply - Keep heartbeat/pong for connection health detection
1 parent 2eb3157 commit b8710ec

6 files changed

Lines changed: 101 additions & 706 deletions

File tree

bridge/main.go

Lines changed: 9 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"bytes"
5-
"encoding/base64"
65
"encoding/json"
76
"fmt"
87
"io"
@@ -27,7 +26,6 @@ const (
2726
reconnectBaseDelay = 1 * time.Second
2827
reconnectMaxDelay = 30 * time.Second
2928
pongWait = 60 * time.Second
30-
maxFileSize = 50 * 1024 * 1024
3129
)
3230

3331
var sessionCodePattern = regexp.MustCompile(`^[0-9a-f]{12}$`)
@@ -84,6 +82,12 @@ func main() {
8482
fatal("Usage: cya-bridge <session code>")
8583
}
8684

85+
// Derive HTTP base URL from WebSocket URL for the connect link
86+
baseURL := strings.Replace(wsURL, "ws://", "http://", 1)
87+
baseURL = strings.Replace(baseURL, "wss://", "https://", 1)
88+
baseURL = strings.TrimSuffix(baseURL, "/ws")
89+
connectURL := baseURL + "/c/" + code
90+
8791
quit := make(chan struct{})
8892
sig := make(chan os.Signal, 1)
8993
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
@@ -105,7 +109,7 @@ func main() {
105109
default:
106110
}
107111

108-
_, reconnect := dialAndRun(wsURL, code, quit)
112+
_, reconnect := dialAndRun(wsURL, code, connectURL, quit)
109113
if !reconnect {
110114
return
111115
}
@@ -311,134 +315,14 @@ func readCommands(wsc *wsConn, dot string) bool {
311315
"exit_code": code,
312316
"truncated": truncated,
313317
})
314-
case "file_read":
315-
var msg struct {
316-
ID string `json:"id"`
317-
Path string `json:"path"`
318-
Encoding string `json:"encoding"`
319-
}
320-
_ = json.Unmarshal(data, &msg)
321-
if msg.ID == "" {
322-
continue
323-
}
324-
handleFileRead(wsc, msg.ID, msg.Path)
325-
case "file_write":
326-
var msg struct {
327-
ID string `json:"id"`
328-
Path string `json:"path"`
329-
Data string `json:"data"`
330-
Encoding string `json:"encoding"`
331-
}
332-
_ = json.Unmarshal(data, &msg)
333-
if msg.ID == "" {
334-
continue
335-
}
336-
handleFileWrite(wsc, msg.ID, msg.Path, msg.Data, msg.Encoding)
337318
case "bye":
338319
wsc.close()
339320
return false
340321
}
341322
}
342323
}
343324

344-
func handleFileRead(wsc *wsConn, id, path string) {
345-
printLine(ansiCyan+"📖"+ansiReset, " ", ansiBold, "File read:", ansiReset, " ", path)
346-
data, size, err := readFile(path)
347-
if err != nil {
348-
wsc.sendJSON(map[string]any{
349-
"type": "file_read_result",
350-
"id": id,
351-
"path": path,
352-
"error": err.Error(),
353-
"size": 0,
354-
"data": "",
355-
"encoding": "base64",
356-
})
357-
return
358-
}
359-
wsc.sendJSON(map[string]any{
360-
"type": "file_read_result",
361-
"id": id,
362-
"path": path,
363-
"data": data,
364-
"size": size,
365-
"encoding": "base64",
366-
})
367-
}
368-
369-
func handleFileWrite(wsc *wsConn, id, path, data, encoding string) {
370-
printLine(ansiCyan+"📝"+ansiReset, " ", ansiBold, "File write:", ansiReset, " ", path)
371-
bytesWritten, err := writeFile(path, data, encoding)
372-
if err != nil {
373-
wsc.sendJSON(map[string]any{
374-
"type": "file_write_result",
375-
"id": id,
376-
"path": path,
377-
"error": err.Error(),
378-
"bytes_written": 0,
379-
})
380-
return
381-
}
382-
wsc.sendJSON(map[string]any{
383-
"type": "file_write_result",
384-
"id": id,
385-
"path": path,
386-
"bytes_written": bytesWritten,
387-
})
388-
}
389-
390-
func readFile(path string) (string, int64, error) {
391-
fi, err := os.Stat(path)
392-
if err != nil {
393-
return "", 0, fmt.Errorf("cannot access %s: %w", path, err)
394-
}
395-
if fi.Size() > maxFileSize {
396-
return "", 0, fmt.Errorf("file too large: %d bytes (max %d)", fi.Size(), maxFileSize)
397-
}
398-
399-
f, err := os.Open(path)
400-
if err != nil {
401-
return "", 0, fmt.Errorf("cannot open %s: %w", path, err)
402-
}
403-
defer f.Close()
404-
405-
data, err := io.ReadAll(f)
406-
if err != nil {
407-
return "", 0, fmt.Errorf("cannot read %s: %w", path, err)
408-
}
409-
410-
encoded := base64.StdEncoding.EncodeToString(data)
411-
return encoded, fi.Size(), nil
412-
}
413-
414-
func writeFile(path, data, encoding string) (int, error) {
415-
var raw []byte
416-
switch encoding {
417-
case "base64", "":
418-
var err error
419-
raw, err = base64.StdEncoding.DecodeString(data)
420-
if err != nil {
421-
// Try base64url
422-
raw, err = base64.URLEncoding.DecodeString(data)
423-
if err != nil {
424-
return 0, fmt.Errorf("invalid base64 data: %w", err)
425-
}
426-
}
427-
default:
428-
return 0, fmt.Errorf("unsupported encoding: %s", encoding)
429-
}
430-
431-
if len(raw) > maxFileSize {
432-
return 0, fmt.Errorf("data too large: %d bytes (max %d)", len(raw), maxFileSize)
433-
}
434-
435-
if err := os.WriteFile(path, raw, 0644); err != nil {
436-
return 0, fmt.Errorf("cannot write %s: %w", path, err)
437-
}
438-
return len(raw), nil
439-
}
440-
441-
func dialAndRun(wsURL, code string, quit <-chan struct{}) (string, bool) {
325+
func dialAndRun(wsURL, code, connectURL string, quit <-chan struct{}) (string, bool) {
442326
dialer := websocket.Dialer{HandshakeTimeout: 15 * time.Second}
443327
conn, resp, err := dialer.Dial(wsURL, http.Header{})
444328
if err != nil {
@@ -459,6 +343,7 @@ func dialAndRun(wsURL, code string, quit <-chan struct{}) (string, bool) {
459343
setCurrentBridge(bridge)
460344

461345
dot := ansiCyan + "●" + ansiReset
346+
printLine(dot, " ", connectURL, ansiReset)
462347
printLine(dot, " ", ansiBold, code, ansiReset, " — Ctrl+C to disconnect")
463348

464349
// Set up heartbeat: expect pong within pongWait

0 commit comments

Comments
 (0)