github.com/status-im/status-go@v1.1.0/cmd/status-cli/serve.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/json" 6 "os" 7 "os/signal" 8 "syscall" 9 10 "github.com/status-im/status-go/protocol/common" 11 "github.com/status-im/status-go/protocol/protobuf" 12 msignal "github.com/status-im/status-go/signal" 13 14 "github.com/urfave/cli/v2" 15 "go.uber.org/zap" 16 ) 17 18 func serve(cCtx *cli.Context) error { 19 name := cCtx.String(NameFlag) 20 port := cCtx.Int(PortFlag) 21 apiModules := cCtx.String(APIModulesFlag) 22 telemetryUrl := cCtx.String(TelemetryServerURLFlag) 23 interactive := cCtx.Bool(InteractiveFlag) 24 dest := cCtx.String(AddFlag) 25 keyUID := cCtx.String(KeyUIDFlag) 26 isDebugLevel := cCtx.Bool(DebugLevel) 27 fleet := cCtx.String(FleetFlag) 28 cmdName := cCtx.Command.Name 29 30 logger, err := getSLogger(isDebugLevel) 31 if err != nil { 32 zap.S().Fatalf("Error initializing logger: %v", err) 33 } 34 logger.Infof("Running %v command, with:\n%v", cmdName, flagsUsed(cCtx)) 35 36 logger = logger.Named(name) 37 38 cli, err := start(StartParams{ 39 Name: name, 40 Port: port, 41 APIModules: apiModules, 42 TelemetryURL: telemetryUrl, 43 KeyUID: keyUID, 44 Fleet: fleet, 45 }, logger) 46 if err != nil { 47 return err 48 } 49 defer cli.stop() 50 51 // Using the mobile signal handler to listen for received messages 52 // because if we call messenger.RetrieveAll() from different routines we will miss messages in one of them 53 // and the retrieve messages loop is started when starting a node, so we needed a different appproach, 54 // alternatively we could have implemented another notification mechanism in the messenger, but this signal is already in place 55 msignal.SetMobileSignalHandler(msignal.MobileSignalHandler(func(s []byte) { 56 var evt EventType 57 if err := json.Unmarshal(s, &evt); err != nil { 58 logger.Error("unmarshaling event type", zap.Error(err), zap.String("event", string(s))) 59 return 60 } 61 62 switch evt.Type { 63 case msignal.EventNewMessages: 64 var ev EventNewMessages 65 if err := json.Unmarshal(evt.Event, &ev); err != nil { 66 logger.Error("unmarshaling new message event", zap.Error(err), zap.Any("event", evt.Event)) 67 return 68 } 69 for _, message := range ev.Messages { 70 logger.Infof("message received: %v (ID=%v)", message.Text, message.ID) 71 // if request contact, accept it 72 if message.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT { 73 if err := cli.sendContactRequestAcceptance(cCtx.Context, message.ID); err != nil { 74 logger.Errorf("accepting contact request: %v", err) 75 return 76 } 77 } 78 } 79 case "local-notifications": 80 var ev LocalNotification 81 if err := json.Unmarshal(evt.Event, &ev); err != nil { 82 logger.Error("unmarshaling local notification event", zap.Error(err), zap.Any("event", evt.Event)) 83 return 84 } 85 logger.Infof("local notification: %v, title: %v, id: %v", ev.Category, ev.Title, ev.ID) 86 default: 87 logger.Debugf("received event type '%v'\t%v", evt.Type, string(evt.Event)) 88 } 89 })) 90 91 // Send contact request 92 if dest != "" { 93 err := cli.sendContactRequest(cCtx.Context, dest) 94 if err != nil { 95 return err 96 } 97 } 98 99 // nightly testrunner looks for this log to consider node as started 100 logger.Info("retrieve messages...") 101 102 if interactive { 103 ctx, cancel := context.WithCancel(cCtx.Context) 104 go func() { 105 waitForSigExit() 106 cancel() 107 }() 108 interactiveSendMessageLoop(ctx, cli) 109 } else { 110 waitForSigExit() 111 } 112 113 logger.Info("Exiting") 114 115 return nil 116 } 117 118 type EventType struct { 119 Type string `json:"type"` 120 Event json.RawMessage `json:"event"` 121 } 122 123 type EventNewMessages struct { 124 Messages []*common.Message `json:"messages"` 125 } 126 127 type LocalNotification struct { 128 ID string `json:"id"` 129 Title string `json:"title"` 130 Category string `json:"category"` 131 } 132 133 func waitForSigExit() { 134 sig := make(chan os.Signal, 1) 135 signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) 136 <-sig 137 }