Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
dcb08f003b |
|
|
@ -1,6 +1,7 @@
|
||||||
package autopush
|
package autopush
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdh"
|
"crypto/ecdh"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
|
@ -18,6 +19,7 @@ const MOZILLA_PUSH_SERVICE = "wss://push.services.mozilla.com"
|
||||||
|
|
||||||
type AutoPushClient struct {
|
type AutoPushClient struct {
|
||||||
*websocket.WebSocketClient
|
*websocket.WebSocketClient
|
||||||
|
awaitingPong bool
|
||||||
ece *rfc8291.RFC8291
|
ece *rfc8291.RFC8291
|
||||||
helloChan chan HelloResponse
|
helloChan chan HelloResponse
|
||||||
notificationChan chan Notification
|
notificationChan chan Notification
|
||||||
|
|
@ -49,8 +51,13 @@ func unmarshaler[T any](payload json.RawMessage, label MessageType) (data *T) {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *AutoPushClient) Ping() error {
|
||||||
|
c.awaitingPong = true
|
||||||
|
return c.SendJSON(struct{}{})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *AutoPushClient) Hello(uaid string, channelIDs []string) (HelloResponse, error) {
|
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,
|
Type: HELLO,
|
||||||
UAID: uaid,
|
UAID: uaid,
|
||||||
ChannelIDs: channelIDs,
|
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) {
|
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,
|
Type: REGISTER,
|
||||||
ChannelID: channelID,
|
ChannelID: channelID,
|
||||||
Key: vapidKey,
|
Key: vapidKey,
|
||||||
|
|
@ -67,7 +74,7 @@ func (c *AutoPushClient) Register(channelID string, vapidKey string) (RegisterRe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AutoPushClient) Unregister(channelID string) (UnregisterResponse, error) {
|
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,
|
Type: UNREGISTER,
|
||||||
ChannelID: channelID,
|
ChannelID: channelID,
|
||||||
})
|
})
|
||||||
|
|
@ -102,7 +109,8 @@ func (c *AutoPushClient) Decrypt(
|
||||||
return &result, nil
|
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{
|
ap = &AutoPushClient{
|
||||||
ece: rfc8291.NewRFC8291(sha256.New),
|
ece: rfc8291.NewRFC8291(sha256.New),
|
||||||
helloChan: make(chan HelloResponse),
|
helloChan: make(chan HelloResponse),
|
||||||
|
|
@ -110,8 +118,29 @@ func NewAutoPushClient() (ap *AutoPushClient, ch chan Notification) {
|
||||||
registerChan: make(chan RegisterResponse),
|
registerChan: make(chan RegisterResponse),
|
||||||
unregisterChan: make(chan UnregisterResponse),
|
unregisterChan: make(chan UnregisterResponse),
|
||||||
WebSocketClient: websocket.NewWebSocketClient(
|
WebSocketClient: websocket.NewWebSocketClient(
|
||||||
nil,
|
ctx,
|
||||||
func(ws *websocket.WebSocketClient) {
|
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.helloChan)
|
||||||
close(ap.notificationChan)
|
close(ap.notificationChan)
|
||||||
close(ap.registerChan)
|
close(ap.registerChan)
|
||||||
|
|
@ -125,9 +154,17 @@ func NewAutoPushClient() (ap *AutoPushClient, ch chan Notification) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if message.Type == NULL {
|
||||||
|
message.Type = PING
|
||||||
|
}
|
||||||
|
|
||||||
switch message.Type {
|
switch message.Type {
|
||||||
case PING:
|
case PING:
|
||||||
ws.SendJSON("{}")
|
if ap.awaitingPong {
|
||||||
|
ap.awaitingPong = false
|
||||||
|
} else {
|
||||||
|
ap.Ping()
|
||||||
|
}
|
||||||
|
|
||||||
case HELLO:
|
case HELLO:
|
||||||
if data := unmarshaler[HelloResponse](payload, HELLO); data != nil {
|
if data := unmarshaler[HelloResponse](payload, HELLO); data != nil {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ const (
|
||||||
type MessageType string
|
type MessageType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
NULL MessageType = ""
|
||||||
PING MessageType = "ping"
|
PING MessageType = "ping"
|
||||||
ACK MessageType = "ack"
|
ACK MessageType = "ack"
|
||||||
HELLO MessageType = "hello"
|
HELLO MessageType = "hello"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdh"
|
"crypto/ecdh"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -101,6 +102,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
nicoPushClient, notificationChan, err := nicopush.NewNicoPushClient(
|
nicoPushClient, notificationChan, err := nicopush.NewNicoPushClient(
|
||||||
|
context.Background(),
|
||||||
config.UAID,
|
config.UAID,
|
||||||
config.ChannelIDs,
|
config.ChannelIDs,
|
||||||
config.AuthSecret,
|
config.AuthSecret,
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -3,7 +3,7 @@ module git.min.rip/min/webpush-client-go
|
||||||
go 1.23.6
|
go 1.23.6
|
||||||
|
|
||||||
require (
|
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
|
github.com/google/uuid v1.6.0
|
||||||
golang.org/x/crypto v0.35.0
|
golang.org/x/crypto v0.35.0
|
||||||
golang.org/x/net v0.35.0
|
golang.org/x/net v0.35.0
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -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.2.0 h1:hIwowEju/7lHHC3V6544jatB8Z9faKWbKD6gqZJwRq4=
|
||||||
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/go.mod h1:qE2autSEJU74jUb+tET0J+Ozg2w7BVtg31Toq83kz4Q=
|
||||||
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
||||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package nicopush
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/ecdh"
|
"crypto/ecdh"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
|
@ -32,6 +33,7 @@ type NicoPushClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNicoPushClient(
|
func NewNicoPushClient(
|
||||||
|
ctx context.Context,
|
||||||
uaid string,
|
uaid string,
|
||||||
channelIDs []string,
|
channelIDs []string,
|
||||||
authSecret []byte,
|
authSecret []byte,
|
||||||
|
|
@ -43,7 +45,7 @@ func NewNicoPushClient(
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ap, ch := autopush.NewAutoPushClient()
|
ap, ch := autopush.NewAutoPushClient(ctx)
|
||||||
|
|
||||||
client := &NicoPushClient{
|
client := &NicoPushClient{
|
||||||
autoPushClient: ap,
|
autoPushClient: ap,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue