mirror of
https://github.com/status-im/status-go.git
synced 2026-08-31 09:01:16 +00:00
`common` was a grab-bag with no domain: the issue's own preamble names it as the kind of package that must not exist. Every symbol moves to the package that owns it, and the directory is deleted. common/dbsetup -> internal/db/dbsetup common/devices.go -> internal/platform common/pausable*.go -> internal/pausable LogOnPanic -> internal/panics TruncateWithDot(N) -> internal/logutils RecoverKey, ValidateDisplayName, display-name errors -> protocol/common IpfsGatewayURL -> internal/ipfs.GatewayURL Archives/TorrentTorrentsRelativePath, MainnetEthereumNetworkURL -> params StatusService -> pkg/backend/node ErrBigIntSetFromString -> services/wallet IsNil, Ptr -> inlined at their call sites IsENSName -> deleted, it had no callers Notes: - LogOnPanic gets its own package rather than living in logutils. It reports to Sentry, and logutils is imported by nearly everything: put the guard in logutils and the Sentry SDK lands in every dependency graph in the tree (213 -> 250 packages). internal/panics imports logutils and sentry, which is the direction root `common` had. - TruncateWithDot is log redaction, not string formatting: every one of its 121 call sites is inside a log or error message, so it belongs next to the logger. - Moving RecoverKey and ValidateDisplayName into protocol/common removes the common -> protocol layering inversion; all their callers were already inside protocol/. - Makefile lint-panics target follows LogOnPanic to its new path. refs #7067
238 lines
6.3 KiB
Go
238 lines
6.3 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ecdsa"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/status-im/status-go/internal/crypto"
|
|
"github.com/status-im/status-go/internal/instrumentation/trace"
|
|
"github.com/status-im/status-go/internal/panics"
|
|
"github.com/status-im/status-go/pkg/messaging/adapters"
|
|
common "github.com/status-im/status-go/pkg/messaging/common"
|
|
processor "github.com/status-im/status-go/pkg/messaging/controller/processor"
|
|
sender "github.com/status-im/status-go/pkg/messaging/controller/sender"
|
|
"github.com/status-im/status-go/pkg/messaging/events"
|
|
"github.com/status-im/status-go/pkg/messaging/types"
|
|
"github.com/status-im/status-go/pkg/pubsub"
|
|
)
|
|
|
|
type Controller struct {
|
|
identity *ecdsa.PrivateKey
|
|
stack *common.MessagingStack
|
|
sender *sender.Sender
|
|
processor *processor.Processor
|
|
|
|
messageConfirmationStorage common.MessageConfirmationPersistence
|
|
hashRatchetStorage common.HashRatchetPersistence
|
|
|
|
publisher *pubsub.Publisher
|
|
logger *zap.Logger
|
|
|
|
wg sync.WaitGroup
|
|
quit chan struct{}
|
|
}
|
|
|
|
func NewController(
|
|
identity *ecdsa.PrivateKey,
|
|
stack *common.MessagingStack,
|
|
messageConfirmationStorage common.MessageConfirmationPersistence,
|
|
hashRatchetStorage common.HashRatchetPersistence,
|
|
publisher *pubsub.Publisher,
|
|
logger *zap.Logger,
|
|
tracer trace.Tracer,
|
|
) *Controller {
|
|
return &Controller{
|
|
identity: identity,
|
|
stack: stack,
|
|
sender: sender.NewSender(identity, stack, logger, tracer),
|
|
processor: processor.NewProcessor(identity, stack, messageConfirmationStorage, hashRatchetStorage, logger, tracer),
|
|
messageConfirmationStorage: messageConfirmationStorage,
|
|
hashRatchetStorage: hashRatchetStorage,
|
|
publisher: publisher,
|
|
logger: logger.Named("controller"),
|
|
quit: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
func (c *Controller) Start() error {
|
|
subscriptions, err := c.stack.Encryption.Start(c.identity)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// process stored shared secrets
|
|
err = c.processor.ProcessSharedSecrets(subscriptions.SharedSecrets)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = c.StartReliability()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.runSubscriptionsLoop()
|
|
c.runSegmentsCleanupLoop()
|
|
c.runHashRatchetCleanupLoop()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Controller) Stop() (rerr error) {
|
|
close(c.quit)
|
|
|
|
c.stack.Reliability.Close()
|
|
|
|
err := c.stack.Encryption.Stop()
|
|
if err != nil {
|
|
rerr = errors.Wrap(rerr, "failed to stop encryption layer: "+err.Error())
|
|
}
|
|
|
|
err = c.stack.Transport.Stop()
|
|
if err != nil {
|
|
rerr = errors.Wrap(rerr, "failed to stop transport layer: "+err.Error())
|
|
}
|
|
|
|
c.wg.Wait()
|
|
|
|
return
|
|
}
|
|
|
|
func (c *Controller) StartReliability() error {
|
|
return c.stack.Reliability.Start(c.sender.SendPrivateReliability)
|
|
}
|
|
|
|
func (c *Controller) StopReliability() {
|
|
c.stack.Reliability.Stop()
|
|
}
|
|
|
|
func (c *Controller) SaveHashRatchetMessage(groupID []byte, keyID []byte, m *types.ReceivedMessage) error {
|
|
return c.hashRatchetStorage.SaveMessage(groupID, keyID, m)
|
|
}
|
|
|
|
func (c *Controller) GetHashRatchetMessagesCountForGroup(groupID []byte) (int, error) {
|
|
return c.hashRatchetStorage.GetMessagesCountForGroup(groupID)
|
|
}
|
|
|
|
func (c *Controller) Sender() *sender.Sender {
|
|
return c.sender
|
|
}
|
|
|
|
func (c *Controller) Processor() *processor.Processor {
|
|
return c.processor
|
|
}
|
|
|
|
func (c *Controller) runSubscriptionsLoop() {
|
|
c.wg.Add(1)
|
|
defer c.wg.Done()
|
|
|
|
go func() {
|
|
defer panics.LogOnPanic()
|
|
|
|
scheduledSendSub, scheduledSendUnsub := pubsub.Subscribe[sender.ScheduledReliableSend](c.sender.Publisher(), 100)
|
|
defer scheduledSendUnsub()
|
|
|
|
sentSub, sentUnsub := pubsub.Subscribe[sender.SentMessage](c.sender.Publisher(), 100)
|
|
defer sentUnsub()
|
|
|
|
unawareOfInstallationSub, unawareOfInstallationUnsub := pubsub.Subscribe[processor.SenderUnawareOfInstallation](c.processor.Publisher(), 100)
|
|
defer unawareOfInstallationUnsub()
|
|
|
|
for {
|
|
select {
|
|
case scheduledSend, ok := <-scheduledSendSub:
|
|
if !ok {
|
|
return
|
|
}
|
|
// We don't need to receive confirmations from our own devices
|
|
if crypto.IsPubKeyEqual(scheduledSend.Recipient, &c.identity.PublicKey) {
|
|
continue
|
|
}
|
|
|
|
confirmation := &common.MessageConfirmation{
|
|
PublicKey: crypto.CompressPubkey(scheduledSend.Recipient),
|
|
MessageID: scheduledSend.MessageID,
|
|
DataSyncID: scheduledSend.ReliabilityMessageID,
|
|
}
|
|
|
|
err := c.messageConfirmationStorage.InsertPendingConfirmation(confirmation)
|
|
if err != nil {
|
|
c.logger.Error("failed to insert pending confirmation", zap.Error(err))
|
|
}
|
|
|
|
case messageSent, ok := <-sentSub:
|
|
if !ok {
|
|
return
|
|
}
|
|
var pubkey *ecdsa.PublicKey
|
|
if messageSent.Private {
|
|
pubkey = messageSent.Recipient
|
|
}
|
|
pubsub.Publish(c.publisher, events.SentMessage{
|
|
PublicKey: pubkey,
|
|
Installations: adapters.FromEncryptionInstallations(messageSent.RecipientInstallations),
|
|
MessageIDs: messageSent.MessageIDs,
|
|
})
|
|
|
|
case unawareOfInstallation, ok := <-unawareOfInstallationSub:
|
|
if !ok {
|
|
return
|
|
}
|
|
err := c.sender.SendPrivateAdvertiseBundle(context.Background(), unawareOfInstallation.PublicKey)
|
|
if err != nil {
|
|
c.logger.Error("failed to handle ErrDeviceNotFound", zap.Error(err))
|
|
}
|
|
|
|
case <-c.quit:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (c *Controller) cleanupLoop(logger *zap.Logger, cleanupFunc func() error) {
|
|
c.wg.Add(1)
|
|
defer c.wg.Done()
|
|
|
|
go func() {
|
|
defer panics.LogOnPanic()
|
|
|
|
// Delay by a few minutes to minimize messenger's startup time
|
|
var interval time.Duration = 5 * time.Minute
|
|
for {
|
|
select {
|
|
case <-time.After(interval):
|
|
// Set the regular interval after the first execution
|
|
interval = 1 * time.Hour
|
|
|
|
err := cleanupFunc()
|
|
if err != nil {
|
|
logger.Error("failed to cleanup", zap.Error(err))
|
|
}
|
|
|
|
case <-c.quit:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (c *Controller) runSegmentsCleanupLoop() {
|
|
c.cleanupLoop(c.logger.Named("segmentsCleanupLoop"), func() error {
|
|
monthAgo := time.Now().AddDate(0, -1, 0)
|
|
return c.stack.Segmentation.CleanupStaleSegments(monthAgo)
|
|
})
|
|
}
|
|
|
|
func (c *Controller) runHashRatchetCleanupLoop() {
|
|
c.cleanupLoop(c.logger.Named("hashRatchetCleanupLoop"), func() error {
|
|
monthAgo := time.Now().AddDate(0, -1, 0).Unix()
|
|
return c.hashRatchetStorage.DeleteMessagesOlderThan(monthAgo)
|
|
})
|
|
}
|