add Tick() export and DialConnManual for JS-driven send loop in WASM

This commit is contained in:
realrasengan
2026-03-30 14:24:44 -07:00
parent bbe416444b
commit 5f8cade139
2 changed files with 41 additions and 1 deletions
+30
View File
@@ -83,6 +83,29 @@ func DialConn(conn Conn, ocb *OCB) (*Client, error) {
return c, nil
}
// DialConnManual creates a mosh client without an internal sendLoop.
// The caller must call Tick() periodically (e.g., every 8-16ms) to flush
// outgoing datagrams. Use this in WASM where Go timers are unreliable.
func DialConnManual(conn Conn, ocb *OCB) (*Client, error) {
c := &Client{
conn: conn,
transport: NewTransport(ocb, false),
ocb: ocb,
outputC: make(chan struct{}, 1),
done: make(chan struct{}),
sentActionCounts: make(map[uint64]int),
}
c.wg.Add(1)
go c.recvLoop()
// Send initial keepalive to associate with the server.
c.transport.ForceNextSend()
c.tick()
return c, nil
}
// Send sends keystrokes to the server.
func (c *Client) Send(keys []byte) {
c.actionsMu.Lock()
@@ -147,6 +170,13 @@ func (c *Client) Transport() *Transport {
return c.transport
}
// Tick flushes pending actions as mosh datagrams. Call this periodically
// from an external timer (e.g., JS setInterval in WASM) when the internal
// sendLoop is not used.
func (c *Client) Tick() {
c.tick()
}
func (c *Client) tick() {
// Batch: compute diff from accumulated actions.
c.actionsMu.Lock()
+11 -1
View File
@@ -72,7 +72,8 @@ func newSession(url, key string) (*session, error) {
return nil, err
}
client, err := mosh.DialConn(conn, ocb)
// Use DialConnManual — no internal sendLoop. JS drives Tick() via setInterval.
client, err := mosh.DialConnManual(conn, ocb)
if err != nil {
conn.Close()
return nil, err
@@ -90,6 +91,8 @@ func (s *session) jsObject() js.Value {
}
data := args[0].String()
s.client.Send([]byte(data))
// Tick immediately so keystrokes go out without waiting for the interval.
s.client.Tick()
return nil
}))
@@ -100,6 +103,13 @@ func (s *session) jsObject() js.Value {
cols := args[0].Int()
rows := args[1].Int()
s.client.Resize(uint16(cols), uint16(rows))
s.client.Tick()
return nil
}))
// tick() — flush pending datagrams. Called by JS setInterval.
obj.Set("tick", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
s.client.Tick()
return nil
}))