feat: update ws client (v1.2.0) + push ping

This commit is contained in:
minish 2025-12-30 03:37:50 -05:00
parent 1ea035e9dc
commit dcb08f003b
Signed by: min
SSH Key Fingerprint: SHA256:h4k7JNrfe1dzv1WE3oGVeAY9DPSZXIu3/j89+6DtHWE
6 changed files with 52 additions and 10 deletions

View File

@ -1,6 +1,7 @@
package autopush
import (
"context"
"crypto/ecdh"
"crypto/sha256"
"encoding/base64"
@ -18,6 +19,7 @@ const MOZILLA_PUSH_SERVICE = "wss://push.services.mozilla.com"
type AutoPushClient struct {
*websocket.WebSocketClient
awaitingPong bool
ece *rfc8291.RFC8291
helloChan chan HelloResponse
notificationChan chan Notification
@ -49,8 +51,13 @@ func unmarshaler[T any](payload json.RawMessage, label MessageType) (data *T) {
return data
}
func (c *AutoPushClient) Ping() error {
c.awaitingPong = true
return c.SendJSON(struct{}{})
}
func (c *AutoPushClient) Hello(uaid string, channelIDs []string) (HelloResponse, error) {
return request(c, c.helloChan, 5, "hello timeout", HelloRequest{
return request(c, c.helloChan, 5, "hello", HelloRequest{
Type: HELLO,
UAID: uaid,
ChannelIDs: channelIDs,
@ -59,7 +66,7 @@ func (c *AutoPushClient) Hello(uaid string, channelIDs []string) (HelloResponse,
}
func (c *AutoPushClient) Register(channelID string, vapidKey string) (RegisterResponse, error) {
return request(c, c.registerChan, 5, "register timeout", RegisterRequest{
return request(c, c.registerChan, 5, "register", RegisterRequest{
Type: REGISTER,
ChannelID: channelID,
Key: vapidKey,
@ -67,7 +74,7 @@ func (c *AutoPushClient) Register(channelID string, vapidKey string) (RegisterRe
}
func (c *AutoPushClient) Unregister(channelID string) (UnregisterResponse, error) {
return request(c, c.unregisterChan, 5, "unregister timeout", UnregisterRequest{
return request(c, c.unregisterChan, 5, "unregister", UnregisterRequest{
Type: UNREGISTER,
ChannelID: channelID,
})
@ -102,7 +109,8 @@ func (c *AutoPushClient) Decrypt(
return &result, nil
}
func NewAutoPushClient() (ap *AutoPushClient, ch chan Notification) {
func NewAutoPushClient(ctx context.Context) (ap *AutoPushClient, ch chan Notification) {
ctx, cancel := context.WithCancel(ctx)
ap = &AutoPushClient{
ece: rfc8291.NewRFC8291(sha256.New),
helloChan: make(chan HelloResponse),
@ -110,8 +118,29 @@ func NewAutoPushClient() (ap *AutoPushClient, ch chan Notification) {
registerChan: make(chan RegisterResponse),
unregisterChan: make(chan UnregisterResponse),
WebSocketClient: websocket.NewWebSocketClient(
nil,
ctx,
func(ws *websocket.WebSocketClient) {
// 3min: 10x more often than firefox
// if this is below 45sec, autopush will disconnect us
//
// https://github.com/mozilla-services/autopush-rs/blob/master/autoconnect/autoconnect-ws/autoconnect-ws-sm/src/identified/on_client_msg.rs#L295
// https://searchfox.org/firefox-main/source/dom/push/PushServiceWebSocket.sys.mjs#463
// https://searchfox.org/firefox-main/source/modules/libpref/init/all.js#3230
pushPing := time.NewTicker(55 * time.Second)
go func() {
for {
select {
case <-ctx.Done():
return
case <-pushPing.C:
ap.Ping()
}
}
}()
},
func(ws *websocket.WebSocketClient) {
cancel()
close(ap.helloChan)
close(ap.notificationChan)
close(ap.registerChan)
@ -125,9 +154,17 @@ func NewAutoPushClient() (ap *AutoPushClient, ch chan Notification) {
return
}
if message.Type == NULL {
message.Type = PING
}
switch message.Type {
case PING:
ws.SendJSON("{}")
if ap.awaitingPong {
ap.awaitingPong = false
} else {
ap.Ping()
}
case HELLO:
if data := unmarshaler[HelloResponse](payload, HELLO); data != nil {

View File

@ -11,6 +11,7 @@ const (
type MessageType string
const (
NULL MessageType = ""
PING MessageType = "ping"
ACK MessageType = "ack"
HELLO MessageType = "hello"

View File

@ -1,6 +1,7 @@
package main
import (
"context"
"crypto/ecdh"
"encoding/base64"
"encoding/json"
@ -101,6 +102,7 @@ func main() {
}
nicoPushClient, notificationChan, err := nicopush.NewNicoPushClient(
context.Background(),
config.UAID,
config.ChannelIDs,
config.AuthSecret,

2
go.mod
View File

@ -3,7 +3,7 @@ module git.min.rip/min/webpush-client-go
go 1.23.6
require (
git.min.rip/min/websocket-client-go v1.1.1
git.min.rip/min/websocket-client-go v1.2.0
github.com/google/uuid v1.6.0
golang.org/x/crypto v0.35.0
golang.org/x/net v0.35.0

4
go.sum
View File

@ -1,5 +1,5 @@
git.min.rip/min/websocket-client-go v1.1.1 h1:oBIGt2HGPRpeqNY+isDagIKQUQ1W3KhVWJrp0vsMdwA=
git.min.rip/min/websocket-client-go v1.1.1/go.mod h1:qE2autSEJU74jUb+tET0J+Ozg2w7BVtg31Toq83kz4Q=
git.min.rip/min/websocket-client-go v1.2.0 h1:hIwowEju/7lHHC3V6544jatB8Z9faKWbKD6gqZJwRq4=
git.min.rip/min/websocket-client-go v1.2.0/go.mod h1:qE2autSEJU74jUb+tET0J+Ozg2w7BVtg31Toq83kz4Q=
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=

View File

@ -2,6 +2,7 @@ package nicopush
import (
"bytes"
"context"
"crypto/ecdh"
"crypto/sha256"
"encoding/base64"
@ -32,6 +33,7 @@ type NicoPushClient struct {
}
func NewNicoPushClient(
ctx context.Context,
uaid string,
channelIDs []string,
authSecret []byte,
@ -43,7 +45,7 @@ func NewNicoPushClient(
return nil, nil, err
}
ap, ch := autopush.NewAutoPushClient()
ap, ch := autopush.NewAutoPushClient(ctx)
client := &NicoPushClient{
autoPushClient: ap,