2020-10-28 07:56:14 +00:00
|
|
|
package localnotifications
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
2021-01-26 11:49:37 +00:00
|
|
|
"encoding/json"
|
2020-10-28 07:56:14 +00:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/event"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
|
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
2021-09-09 14:28:54 +00:00
|
|
|
"github.com/status-im/status-go/services/wallet/transfer"
|
2020-10-28 07:56:14 +00:00
|
|
|
"github.com/status-im/status-go/signal"
|
|
|
|
)
|
|
|
|
|
|
|
|
type PushCategory string
|
|
|
|
|
2021-01-26 11:49:37 +00:00
|
|
|
type NotificationType string
|
2020-10-28 07:56:14 +00:00
|
|
|
|
2021-03-31 16:23:45 +00:00
|
|
|
type NotificationBody interface {
|
|
|
|
json.Marshaler
|
2020-10-28 07:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Notification struct {
|
2021-03-31 16:23:45 +00:00
|
|
|
ID common.Hash
|
|
|
|
Platform float32
|
|
|
|
Body NotificationBody
|
|
|
|
BodyType NotificationType
|
|
|
|
Title string
|
|
|
|
Message string
|
|
|
|
Category PushCategory
|
|
|
|
Deeplink string
|
|
|
|
Image string
|
|
|
|
IsScheduled bool
|
|
|
|
ScheduledTime string
|
|
|
|
IsConversation bool
|
|
|
|
IsGroupConversation bool
|
|
|
|
ConversationID string
|
|
|
|
Timestamp uint64
|
|
|
|
Author NotificationAuthor
|
2021-08-19 13:16:45 +00:00
|
|
|
Deleted bool
|
2021-03-31 16:23:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type NotificationAuthor struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Icon string `json:"icon"`
|
|
|
|
Name string `json:"name"`
|
2021-01-26 11:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// notificationAlias is an interim struct used for json un/marshalling
|
|
|
|
type notificationAlias struct {
|
2021-03-31 16:23:45 +00:00
|
|
|
ID common.Hash `json:"id"`
|
|
|
|
Platform float32 `json:"platform,omitempty"`
|
|
|
|
Body json.RawMessage `json:"body"`
|
|
|
|
BodyType NotificationType `json:"bodyType"`
|
|
|
|
Title string `json:"title,omitempty"`
|
|
|
|
Message string `json:"message,omitempty"`
|
|
|
|
Category PushCategory `json:"category,omitempty"`
|
|
|
|
Deeplink string `json:"deepLink,omitempty"`
|
|
|
|
Image string `json:"imageUrl,omitempty"`
|
|
|
|
IsScheduled bool `json:"isScheduled,omitempty"`
|
|
|
|
ScheduledTime string `json:"scheduleTime,omitempty"`
|
|
|
|
IsConversation bool `json:"isConversation,omitempty"`
|
|
|
|
IsGroupConversation bool `json:"isGroupConversation,omitempty"`
|
|
|
|
ConversationID string `json:"conversationId,omitempty"`
|
|
|
|
Timestamp uint64 `json:"timestamp,omitempty"`
|
|
|
|
Author NotificationAuthor `json:"notificationAuthor,omitempty"`
|
2021-08-19 13:16:45 +00:00
|
|
|
Deleted bool `json:"deleted,omitempty"`
|
2020-10-28 07:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MessageEvent - structure used to pass messages from chat to bus
|
|
|
|
type MessageEvent struct{}
|
|
|
|
|
|
|
|
// CustomEvent - structure used to pass custom user set messages to bus
|
|
|
|
type CustomEvent struct{}
|
|
|
|
|
|
|
|
type transmitter struct {
|
|
|
|
publisher *event.Feed
|
|
|
|
|
|
|
|
wg sync.WaitGroup
|
|
|
|
quit chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Service keeps the state of message bus
|
|
|
|
type Service struct {
|
|
|
|
started bool
|
2020-12-28 15:09:25 +00:00
|
|
|
WatchingEnabled bool
|
2021-09-09 14:28:54 +00:00
|
|
|
chainID uint64
|
2020-10-28 07:56:14 +00:00
|
|
|
transmitter *transmitter
|
|
|
|
walletTransmitter *transmitter
|
|
|
|
db *Database
|
2021-09-09 14:28:54 +00:00
|
|
|
walletDB *transfer.Database
|
2020-10-28 07:56:14 +00:00
|
|
|
accountsDB *accounts.Database
|
|
|
|
}
|
|
|
|
|
2023-08-11 11:28:45 +00:00
|
|
|
func NewService(appDB *sql.DB, walletDB *transfer.Database, chainID uint64) (*Service, error) {
|
2021-09-09 14:28:54 +00:00
|
|
|
db := NewDB(appDB, chainID)
|
2022-03-23 18:47:00 +00:00
|
|
|
accountsDB, err := accounts.NewDB(appDB)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-10-28 07:56:14 +00:00
|
|
|
trans := &transmitter{}
|
|
|
|
walletTrans := &transmitter{}
|
|
|
|
|
|
|
|
return &Service{
|
|
|
|
db: db,
|
2021-09-09 14:28:54 +00:00
|
|
|
chainID: chainID,
|
2020-10-28 07:56:14 +00:00
|
|
|
walletDB: walletDB,
|
|
|
|
accountsDB: accountsDB,
|
|
|
|
transmitter: trans,
|
|
|
|
walletTransmitter: walletTrans,
|
2022-03-23 18:47:00 +00:00
|
|
|
}, nil
|
2020-10-28 07:56:14 +00:00
|
|
|
}
|
|
|
|
|
2021-01-26 11:49:37 +00:00
|
|
|
func (n *Notification) MarshalJSON() ([]byte, error) {
|
|
|
|
|
2021-03-31 16:23:45 +00:00
|
|
|
var body json.RawMessage
|
|
|
|
if n.Body != nil {
|
|
|
|
encodedBody, err := n.Body.MarshalJSON()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2021-01-26 11:49:37 +00:00
|
|
|
}
|
2021-03-31 16:23:45 +00:00
|
|
|
body = encodedBody
|
2021-01-26 11:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
alias := notificationAlias{
|
2021-03-31 16:23:45 +00:00
|
|
|
ID: n.ID,
|
|
|
|
Platform: n.Platform,
|
|
|
|
Body: body,
|
|
|
|
BodyType: n.BodyType,
|
|
|
|
Category: n.Category,
|
|
|
|
Title: n.Title,
|
|
|
|
Message: n.Message,
|
|
|
|
Deeplink: n.Deeplink,
|
|
|
|
Image: n.Image,
|
|
|
|
IsScheduled: n.IsScheduled,
|
|
|
|
ScheduledTime: n.ScheduledTime,
|
|
|
|
IsConversation: n.IsConversation,
|
|
|
|
IsGroupConversation: n.IsGroupConversation,
|
|
|
|
ConversationID: n.ConversationID,
|
|
|
|
Timestamp: n.Timestamp,
|
|
|
|
Author: n.Author,
|
2021-08-19 13:16:45 +00:00
|
|
|
Deleted: n.Deleted,
|
2021-01-26 11:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return json.Marshal(alias)
|
|
|
|
}
|
|
|
|
|
2021-03-31 16:23:45 +00:00
|
|
|
func PushMessages(ns []*Notification) {
|
2021-01-26 11:49:37 +00:00
|
|
|
for _, n := range ns {
|
|
|
|
pushMessage(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 07:56:14 +00:00
|
|
|
func pushMessage(notification *Notification) {
|
2022-02-15 16:05:13 +00:00
|
|
|
log.Debug("Pushing a new push notification")
|
2020-10-28 07:56:14 +00:00
|
|
|
signal.SendLocalNotifications(notification)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start Worker which processes all incoming messages
|
2021-06-30 11:40:54 +00:00
|
|
|
func (s *Service) Start() error {
|
2020-10-28 07:56:14 +00:00
|
|
|
s.started = true
|
|
|
|
|
|
|
|
s.transmitter.quit = make(chan struct{})
|
|
|
|
s.transmitter.publisher = &event.Feed{}
|
|
|
|
|
|
|
|
events := make(chan TransactionEvent, 10)
|
|
|
|
sub := s.transmitter.publisher.Subscribe(events)
|
|
|
|
|
|
|
|
s.transmitter.wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer s.transmitter.wg.Done()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-s.transmitter.quit:
|
|
|
|
sub.Unsubscribe()
|
|
|
|
return
|
|
|
|
case err := <-sub.Err():
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Local notifications transmitter failed with", "error", err)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
case event := <-events:
|
|
|
|
s.transactionsHandler(event)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
log.Info("Successful start")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop worker
|
|
|
|
func (s *Service) Stop() error {
|
|
|
|
s.started = false
|
|
|
|
|
|
|
|
if s.transmitter.quit != nil {
|
|
|
|
close(s.transmitter.quit)
|
|
|
|
s.transmitter.wg.Wait()
|
|
|
|
s.transmitter.quit = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.walletTransmitter.quit != nil {
|
|
|
|
close(s.walletTransmitter.quit)
|
|
|
|
s.walletTransmitter.wg.Wait()
|
|
|
|
s.walletTransmitter.quit = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// APIs returns list of available RPC APIs.
|
|
|
|
func (s *Service) APIs() []rpc.API {
|
|
|
|
return []rpc.API{
|
|
|
|
{
|
|
|
|
Namespace: "localnotifications",
|
|
|
|
Version: "0.1.0",
|
|
|
|
Service: NewAPI(s),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Protocols returns list of p2p protocols.
|
|
|
|
func (s *Service) Protocols() []p2p.Protocol {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) IsStarted() bool {
|
|
|
|
return s.started
|
|
|
|
}
|