Mobile notifications for iOS (#210)

* mobile: wire notification registration and listener

* implement backend components for push notifications

* refactor: agentic comment cleanup

* docs: use proper module name for particle processor

* set required env variables for push notifications

* bump version

* fix: always upsert push token on mobile start

* Revert "fix: always upsert push token on mobile start"

This reverts commit 90ff18a788.

* send push notifications regardless of online status
This commit was merged in pull request #210.
This commit is contained in:
Arjun Patel
2026-05-18 12:44:31 -07:00
committed by GitHub
parent a564ea819b
commit d262f734f0
61 changed files with 1682 additions and 531 deletions
+4 -9
View File
@@ -11,13 +11,12 @@ import (
const sendBufferSize = 256
// Conn wraps a WebSocket connection with identity and a send buffer.
type Conn struct {
id string
humanID string
ws *websocket.Conn
send chan []byte
once sync.Once // ensures close logic runs once
once sync.Once // guards Close
}
func newConn(id, humanID string, ws *websocket.Conn) *Conn {
@@ -29,8 +28,8 @@ func newConn(id, humanID string, ws *websocket.Conn) *Conn {
}
}
// ReadPump reads messages from the WebSocket and forwards them to the hub.
// It blocks until the connection is closed or the context is cancelled.
// ReadPump forwards inbound frames to the hub; blocks until the connection
// closes or ctx is cancelled.
func (c *Conn) ReadPump(ctx context.Context, hub *Hub) {
defer hub.disconnect(c)
@@ -45,7 +44,6 @@ func (c *Conn) ReadPump(ctx context.Context, hub *Hub) {
return
}
// Respond to keep-alive pings
if string(data) == "ping" {
if err := c.ws.Write(ctx, websocket.MessageText, []byte("pong")); err != nil {
slog.Warn("websocket pong write error", "connId", c.id, "error", err)
@@ -84,7 +82,6 @@ func (c *Conn) ReadPump(ctx context.Context, hub *Hub) {
}
}
// WritePump drains the send buffer and writes messages to the WebSocket.
func (c *Conn) WritePump(ctx context.Context) {
for {
select {
@@ -102,8 +99,7 @@ func (c *Conn) WritePump(ctx context.Context) {
}
}
// Send enqueues a ServerMessage to be written to the WebSocket.
// If the send buffer is full, the connection is closed (slow client).
// A full send buffer closes the connection (slow client policy).
func (c *Conn) Send(msg ServerMessage) {
data, err := json.Marshal(msg)
if err != nil {
@@ -119,7 +115,6 @@ func (c *Conn) Send(msg ServerMessage) {
}
}
// Close closes the WebSocket connection and the send channel.
func (c *Conn) Close() {
c.once.Do(func() {
c.ws.Close(websocket.StatusNormalClosure, "closing")