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  }