handle notifications at-most-once
This commit is contained in:
parent
d7222c89e0
commit
640f5533ca
|
@ -2125,7 +2125,7 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
continue
|
||||
}
|
||||
logger.Debug("Handling PushNotificationRequest")
|
||||
if err := m.pushNotificationServer.HandlePushNotificationRequest(publicKey, msg.ParsedMessage.Interface().(protobuf.PushNotificationRequest)); err != nil {
|
||||
if err := m.pushNotificationServer.HandlePushNotificationRequest(publicKey, msg.ID, msg.ParsedMessage.Interface().(protobuf.PushNotificationRequest)); err != nil {
|
||||
logger.Warn("failed to handle PushNotificationRequest", zap.Error(err))
|
||||
}
|
||||
// We continue in any case, no changes to messenger
|
||||
|
|
|
@ -2,7 +2,6 @@ package pushnotificationserver
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -60,9 +59,9 @@ func PushNotificationRegistrationToGoRushRequest(requestAndRegistrations []*Requ
|
|||
Message: defaultNotificationMessage,
|
||||
Topic: registration.ApnTopic,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hex.EncodeToString(request.Message),
|
||||
EncryptedMessage: types.EncodeHex(request.Message),
|
||||
ChatID: types.EncodeHex(request.ChatId),
|
||||
PublicKey: hex.EncodeToString(request.PublicKey),
|
||||
PublicKey: types.EncodeHex(request.PublicKey),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package pushnotificationserver
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
|
@ -13,10 +13,10 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
message1 := []byte("message-1")
|
||||
message2 := []byte("message-2")
|
||||
message3 := []byte("message-3")
|
||||
hexMessage1 := hex.EncodeToString(message1)
|
||||
hexMessage2 := hex.EncodeToString(message2)
|
||||
hexMessage3 := hex.EncodeToString(message3)
|
||||
chatID := "chat-id"
|
||||
hexMessage1 := types.EncodeHex(message1)
|
||||
hexMessage2 := types.EncodeHex(message2)
|
||||
hexMessage3 := types.EncodeHex(message3)
|
||||
chatID := []byte("chat-id")
|
||||
publicKey1 := []byte("public-key-1")
|
||||
publicKey2 := []byte("public-key-2")
|
||||
installationID1 := "installation-id-1"
|
||||
|
@ -76,8 +76,8 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
Message: defaultNotificationMessage,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hexMessage1,
|
||||
ChatID: chatID,
|
||||
PublicKey: hex.EncodeToString(publicKey1),
|
||||
ChatID: types.EncodeHex(chatID),
|
||||
PublicKey: types.EncodeHex(publicKey1),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -86,8 +86,8 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
Message: defaultNotificationMessage,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hexMessage2,
|
||||
ChatID: chatID,
|
||||
PublicKey: hex.EncodeToString(publicKey1),
|
||||
ChatID: types.EncodeHex(chatID),
|
||||
PublicKey: types.EncodeHex(publicKey1),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -96,8 +96,8 @@ func TestPushNotificationRegistrationToGoRushRequest(t *testing.T) {
|
|||
Message: defaultNotificationMessage,
|
||||
Data: &GoRushRequestData{
|
||||
EncryptedMessage: hexMessage3,
|
||||
ChatID: chatID,
|
||||
PublicKey: hex.EncodeToString(publicKey2),
|
||||
ChatID: types.EncodeHex(chatID),
|
||||
PublicKey: types.EncodeHex(publicKey2),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// sources:
|
||||
// 1593601728_initial_schema.down.sql (200B)
|
||||
// 1593601728_initial_schema.up.sql (675B)
|
||||
// 1598419937_add_push_notifications_table.down.sql (51B)
|
||||
// 1598419937_add_push_notifications_table.up.sql (104B)
|
||||
// doc.go (382B)
|
||||
|
||||
package migrations
|
||||
|
@ -86,7 +88,7 @@ func _1593601728_initial_schemaDownSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1593601728_initial_schema.down.sql", size: 200, mode: os.FileMode(0644), modTime: time.Unix(1595840384, 0)}
|
||||
info := bindataFileInfo{name: "1593601728_initial_schema.down.sql", size: 200, mode: os.FileMode(0644), modTime: time.Unix(1596198373, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x88, 0x8a, 0x61, 0x81, 0x57, 0x45, 0x9b, 0x97, 0x9b, 0x1f, 0xf6, 0x94, 0x8a, 0x20, 0xb3, 0x2b, 0xff, 0x69, 0x49, 0xf4, 0x58, 0xcc, 0xd0, 0x55, 0xcc, 0x9a, 0x8b, 0xb6, 0x7f, 0x29, 0x53, 0xc1}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -106,11 +108,51 @@ func _1593601728_initial_schemaUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1593601728_initial_schema.up.sql", size: 675, mode: os.FileMode(0644), modTime: time.Unix(1595840384, 0)}
|
||||
info := bindataFileInfo{name: "1593601728_initial_schema.up.sql", size: 675, mode: os.FileMode(0644), modTime: time.Unix(1596198373, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfd, 0x61, 0x90, 0x79, 0xd9, 0x14, 0x65, 0xe9, 0x96, 0x53, 0x17, 0x33, 0x54, 0xeb, 0x8b, 0x5d, 0x95, 0x99, 0x10, 0x36, 0x58, 0xdd, 0xb2, 0xbf, 0x45, 0xd9, 0xbb, 0xc4, 0x92, 0xe, 0xce, 0x2}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1598419937_add_push_notifications_tableDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\x28\x2d\xce\x88\xcf\xcb\x2f\xc9\x4c\xcb\x4c\x4e\x2c\xc9\xcc\xcf\x8b\x2f\x4e\x2d\x2a\x4b\x2d\x42\x11\x2b\xb6\xe6\x02\x04\x00\x00\xff\xff\xb7\xdc\x38\x53\x33\x00\x00\x00")
|
||||
|
||||
func _1598419937_add_push_notifications_tableDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1598419937_add_push_notifications_tableDownSql,
|
||||
"1598419937_add_push_notifications_table.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1598419937_add_push_notifications_tableDownSql() (*asset, error) {
|
||||
bytes, err := _1598419937_add_push_notifications_tableDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1598419937_add_push_notifications_table.down.sql", size: 51, mode: os.FileMode(0644), modTime: time.Unix(1598420015, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x98, 0xc8, 0x30, 0x45, 0x5b, 0xc5, 0x7d, 0x13, 0x5d, 0xe7, 0xc8, 0x23, 0x43, 0xf7, 0xdc, 0x9c, 0xe2, 0xdd, 0x63, 0xf0, 0xb7, 0x16, 0x40, 0xc, 0xda, 0xb9, 0x16, 0x70, 0x2b, 0x5a, 0x7e}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1598419937_add_push_notifications_tableUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x0e\x72\x75\x0c\x71\x55\x08\x71\x74\xf2\x71\x55\xf0\x74\x53\xf0\xf3\x0f\x51\x70\x8d\xf0\x0c\x0e\x09\x56\x28\x28\x2d\xce\x88\xcf\xcb\x2f\xc9\x4c\xcb\x4c\x4e\x2c\xc9\xcc\xcf\x8b\x2f\x4e\x2d\x2a\x4b\x2d\x42\x11\x2b\x56\xd0\xe0\x52\x50\xc8\x4c\x51\x70\xf2\xf1\x77\x02\xeb\xf6\x0b\xf5\xf1\xd1\xe1\x52\x50\x08\xf5\xf3\x0c\x0c\x75\xd5\xc8\x4c\xd1\xe4\xd2\xb4\xe6\x02\x04\x00\x00\xff\xff\xf3\xc8\x52\x6b\x68\x00\x00\x00")
|
||||
|
||||
func _1598419937_add_push_notifications_tableUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1598419937_add_push_notifications_tableUpSql,
|
||||
"1598419937_add_push_notifications_table.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1598419937_add_push_notifications_tableUpSql() (*asset, error) {
|
||||
bytes, err := _1598419937_add_push_notifications_tableUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1598419937_add_push_notifications_table.up.sql", size: 104, mode: os.FileMode(0644), modTime: time.Unix(1598419975, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2, 0x3e, 0xef, 0xf, 0xc2, 0xdf, 0xbc, 0x99, 0x7a, 0xc2, 0xd3, 0x64, 0x4f, 0x4c, 0x7e, 0xfc, 0x2e, 0x8c, 0xa7, 0x54, 0xd3, 0x4d, 0x25, 0x98, 0x41, 0xbc, 0xea, 0xd7, 0x2, 0xc1, 0xd0, 0x52}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\x3d\x6e\xec\x30\x0c\x84\x7b\x9d\x62\xb0\xcd\x36\xcf\x52\xf3\xaa\x74\x29\xd3\xe7\x02\x5c\x89\x96\x88\xb5\x24\x43\xa4\xf7\xe7\xf6\x81\x37\x01\xe2\x2e\xed\x87\xf9\x86\xc3\x10\xf0\x59\x44\x31\xcb\xc2\x10\x45\xe3\xc8\xaa\x34\x9e\xb8\x70\xa4\x4d\x19\xa7\x2c\x56\xb6\x8b\x8f\xbd\x06\x35\xb2\x4d\x27\xa9\xa1\x4a\x1e\x64\x1c\x6e\xff\x4f\x2e\x04\x44\x6a\x67\x43\xa1\x96\x16\x7e\x75\x29\xd4\x68\x98\xb4\x8c\xbb\x58\x01\x61\x1d\x3c\xcb\xc3\xe3\xdd\xb0\x30\xa9\xc1\x0a\xd9\x59\x61\x85\x11\x49\x79\xaf\x99\xfb\x40\xee\xd3\x45\x5a\x22\x23\xbf\xa3\x8f\xf9\x40\xf6\x85\x91\x96\x85\x13\xe6\xd1\xeb\xcb\x55\xaa\x8c\x24\x83\xa3\xf5\xf1\xfc\x07\x52\x65\x43\xa3\xca\xba\xfb\x85\x6e\x8c\xd6\x7f\xce\x83\x5a\xfa\xfb\x23\xdc\xfb\xb8\x2a\x48\xc1\x8f\x95\xa3\x71\xf2\xce\xad\x14\xaf\x94\x19\xdf\x39\xe9\x4d\x9d\x0b\x21\xf7\xb7\xcc\x8d\x77\xf3\xb8\x73\x5a\xaf\xf9\x90\xc4\xd4\xe1\x7d\xf8\x05\x3e\x77\xf8\xe0\xbe\x02\x00\x00\xff\xff\x4d\x1d\x5d\x50\x7e\x01\x00\x00")
|
||||
|
||||
func docGoBytes() ([]byte, error) {
|
||||
|
@ -126,7 +168,7 @@ func docGo() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "doc.go", size: 382, mode: os.FileMode(0644), modTime: time.Unix(1595840384, 0)}
|
||||
info := bindataFileInfo{name: "doc.go", size: 382, mode: os.FileMode(0644), modTime: time.Unix(1596198373, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc0, 0x2f, 0x1e, 0x64, 0x9, 0x93, 0xe4, 0x8b, 0xf2, 0x98, 0x5a, 0x45, 0xe2, 0x80, 0x88, 0x67, 0x7a, 0x2d, 0xd7, 0x4b, 0xd1, 0x73, 0xb6, 0x6d, 0x15, 0xc2, 0x0, 0x34, 0xcd, 0xa0, 0xdb, 0x20}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -226,6 +268,10 @@ var _bindata = map[string]func() (*asset, error){
|
|||
|
||||
"1593601728_initial_schema.up.sql": _1593601728_initial_schemaUpSql,
|
||||
|
||||
"1598419937_add_push_notifications_table.down.sql": _1598419937_add_push_notifications_tableDownSql,
|
||||
|
||||
"1598419937_add_push_notifications_table.up.sql": _1598419937_add_push_notifications_tableUpSql,
|
||||
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
|
@ -270,9 +316,11 @@ type bintree struct {
|
|||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"1593601728_initial_schema.down.sql": &bintree{_1593601728_initial_schemaDownSql, map[string]*bintree{}},
|
||||
"1593601728_initial_schema.up.sql": &bintree{_1593601728_initial_schemaUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
"1593601728_initial_schema.down.sql": &bintree{_1593601728_initial_schemaDownSql, map[string]*bintree{}},
|
||||
"1593601728_initial_schema.up.sql": &bintree{_1593601728_initial_schemaUpSql, map[string]*bintree{}},
|
||||
"1598419937_add_push_notifications_table.down.sql": &bintree{_1598419937_add_push_notifications_tableDownSql, map[string]*bintree{}},
|
||||
"1598419937_add_push_notifications_table.up.sql": &bintree{_1598419937_add_push_notifications_tableUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
DROP TABLE push_notification_server_notifications;
|
|
@ -0,0 +1,4 @@
|
|||
CREATE TABLE IF NOT EXISTS push_notification_server_notifications (
|
||||
id BLOB NOT NULL,
|
||||
UNIQUE(id)
|
||||
);
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
sqlite3 "github.com/mutecomm/go-sqlcipher"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
|
@ -32,6 +33,8 @@ type Persistence interface {
|
|||
GetIdentity() (*ecdsa.PrivateKey, error)
|
||||
// SaveIdentity saves the server identity key
|
||||
SaveIdentity(*ecdsa.PrivateKey) error
|
||||
// PushNotificationExists checks whether a push notification exists and inserts it otherwise
|
||||
PushNotificationExists([]byte) (bool, error)
|
||||
}
|
||||
|
||||
type SQLitePersistence struct {
|
||||
|
@ -178,3 +181,14 @@ func (p *SQLitePersistence) GetIdentity() (*ecdsa.PrivateKey, error) {
|
|||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
func (p *SQLitePersistence) PushNotificationExists(messageID []byte) (bool, error) {
|
||||
_, err := p.db.Exec(`INSERT INTO push_notification_server_notifications VALUES (?)`, messageID)
|
||||
if err != nil && err.(sqlite3.Error).ExtendedCode == sqlite3.ErrConstraintUnique {
|
||||
return true, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -81,3 +81,22 @@ func (s *SQLitePersistenceSuite) TestSaveDifferentIdenities() {
|
|||
s.Require().NoError(s.persistence.SaveIdentity(key1))
|
||||
s.Require().Error(s.persistence.SaveIdentity(key2))
|
||||
}
|
||||
|
||||
func (s *SQLitePersistenceSuite) TestExists() {
|
||||
messageID1 := []byte("1")
|
||||
messageID2 := []byte("2")
|
||||
|
||||
result, err := s.persistence.PushNotificationExists(messageID1)
|
||||
s.Require().NoError(err)
|
||||
s.Require().False(result)
|
||||
|
||||
result, err = s.persistence.PushNotificationExists(messageID1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require()
|
||||
s.Require().True(result)
|
||||
|
||||
result, err = s.persistence.PushNotificationExists(messageID2)
|
||||
s.Require().NoError(err)
|
||||
s.Require().False(result)
|
||||
}
|
||||
|
|
|
@ -137,8 +137,21 @@ func (s *Server) HandlePushNotificationQuery(publicKey *ecdsa.PublicKey, message
|
|||
|
||||
// HandlePushNotificationRequest will send a gorush notification and send a response back to the user
|
||||
func (s *Server) HandlePushNotificationRequest(publicKey *ecdsa.PublicKey,
|
||||
messageID []byte,
|
||||
request protobuf.PushNotificationRequest) error {
|
||||
s.config.Logger.Info("handling pn request")
|
||||
s.config.Logger.Info("handling pn request", zap.Binary("message-id", messageID))
|
||||
|
||||
// This is at-most-once semantic for now
|
||||
exists, err := s.persistence.PushNotificationExists(messageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
s.config.Logger.Info("already handled")
|
||||
return nil
|
||||
}
|
||||
|
||||
response := s.buildPushNotificationRequestResponseAndSendNotification(&request)
|
||||
if response == nil {
|
||||
return nil
|
||||
|
|
Loading…
Reference in New Issue