diff --git a/mobile/status.go b/mobile/status.go index 18a5ae025..9d4cf2a01 100644 --- a/mobile/status.go +++ b/mobile/status.go @@ -782,6 +782,25 @@ func StopLocalNotifications() string { return makeJSONResponse(err) } +// SetSignalBlocklist sets a blocklist of signal types that can turn signal.send +// a nop. +func SetSignalBlocklist(requestJSON string) string { + var request requests.SetSignalBlocklist + err := json.Unmarshal([]byte(requestJSON), &request) + if err != nil { + return makeJSONResponse(err) + } + + // Index by signal type. + blocklist := make(signal.SignalBlocklist) + for _, v := range request.Blocklist { + blocklist[v] = struct{}{} + } + signal.SetSignalBlocklist(blocklist) + + return makeJSONResponse(nil) +} + // SetMobileSignalHandler setup geth callback to notify about new signal // used for gomobile builds func SetMobileSignalHandler(handler SignalHandler) { diff --git a/mobile/status_test.go b/mobile/status_test.go new file mode 100644 index 000000000..b4f9fab30 --- /dev/null +++ b/mobile/status_test.go @@ -0,0 +1,14 @@ +package statusgo + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func TestSetSignalBlocklist(t *testing.T) { + request := "{\"blocklist\":[\"wakuv2.peerstats\",\"history.request.started\"]}" + require.Equal(t, "{\"error\":\"\"}", SetSignalBlocklist(request)) + + request = "{\"blocklist\":[]}" + require.Equal(t, "{\"error\":\"\"}", SetSignalBlocklist(request)) +} diff --git a/protocol/requests/set_signal_blocklist.go b/protocol/requests/set_signal_blocklist.go new file mode 100644 index 000000000..8aed524a3 --- /dev/null +++ b/protocol/requests/set_signal_blocklist.go @@ -0,0 +1,5 @@ +package requests + +type SetSignalBlocklist struct { + Blocklist []string `json:"blocklist"` +} diff --git a/signal/signals.go b/signal/signals.go index 81aed7ab4..e1ff401bd 100644 --- a/signal/signals.go +++ b/signal/signals.go @@ -15,6 +15,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/log" + "github.com/status-im/status-go/services/wallet/walletevent" ) // MobileSignalHandler is a simple callback function that gets called when any signal is received @@ -23,6 +24,12 @@ type MobileSignalHandler func([]byte) // storing the current signal handler here var mobileSignalHandler MobileSignalHandler +// SignalBlocklist is an optional set of signals that should be blocklisted, +// i.e. not sent. +type SignalBlocklist map[string]struct{} + +var signalBlocklist SignalBlocklist + // All general log messages in this package should be routed through this logger. var logger = log.New("package", "status-go/signal") @@ -40,6 +47,41 @@ func NewEnvelope(typ string, event interface{}) *Envelope { } } +// isSignalBlocklisted returns true when a signal type is present in the +// blocklist, or when not found, if the signal type and event type are present. +// +// The convention is that clients can specify a particular event type from any +// signal by concatenating a forward slash. +// +// Example for signal "wallet" and event type +// "wallet-collectible-status-changed": +// +// "wallet/wallet-collectible-status-changed" +func isSignalBlocklisted(signal *Envelope, event any) bool { + if len(signalBlocklist) > 0 { + // If the signal type is in the blocklist, then "send" is a nop. + if _, ok := signalBlocklist[signal.Type]; ok { + logger.Info("imotta - Signal blocklisted", "signal", signal.Type) + return true + } + + // A signal may encompass an event, in which case we need to concretely + // check the type of the event. + // + // THIS DOES NOT WORK because it creates a circular dependency and the + // compiler will complaint. + if e, ok := event.(walletevent.Event); ok { + name := signal.Type + "/" + string(e.Type) + logger.Info("imotta - Signal blocklisted", "signal", name) + if _, ok := signalBlocklist[name]; ok { + return true + } + } + } + + return false +} + // send sends application signal (in JSON) upwards to application (via default notification handler) func send(typ string, event interface{}) { signal := NewEnvelope(typ, event) @@ -48,6 +90,11 @@ func send(typ string, event interface{}) { logger.Error("Marshalling signal envelope", "error", err) return } + + if isSignalBlocklisted(signal, event) { + return + } + // If a Go implementation of signal handler is set, let's use it. if mobileSignalHandler != nil { mobileSignalHandler(data) @@ -111,6 +158,10 @@ func SetMobileSignalHandler(handler MobileSignalHandler) { mobileSignalHandler = handler } +func SetSignalBlocklist(blocklist SignalBlocklist) { + signalBlocklist = blocklist +} + // SetSignalEventCallback set callback // this function uses C implementation (see `signals.c` file) func SetSignalEventCallback(cb unsafe.Pointer) {