213 lines
5.3 KiB
Go
213 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"crypto/rand"
|
|
"log/slog"
|
|
"math/big"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/status-im/status-go/protocol/common"
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
"github.com/status-im/status-go/protocol/requests"
|
|
)
|
|
|
|
func (cli *StatusCLI) sendContactRequest(ctx context.Context, toID string) error {
|
|
cli.logger.Info("send contact request, contact public key: ", toID)
|
|
request := &requests.SendContactRequest{
|
|
ID: toID,
|
|
Message: "Hello!",
|
|
}
|
|
resp, err := cli.messenger.SendContactRequest(ctx, request)
|
|
cli.logger.Info("function SendContactRequest response.messages: ", resp.Messages())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (cli *StatusCLI) sendContactRequestAcceptance(ctx context.Context, msgID string) error {
|
|
cli.logger.Info("accept contact request, message ID: ", msgID)
|
|
resp, err := cli.messenger.AcceptContactRequest(ctx, &requests.AcceptContactRequest{ID: types.Hex2Bytes(msgID)})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cli.logger.Info("function AcceptContactRequest response: ", resp.Messages())
|
|
|
|
return nil
|
|
}
|
|
|
|
func (cli *StatusCLI) randomFailure() func() {
|
|
nBig, err := rand.Int(rand.Reader, big.NewInt(100))
|
|
if err != nil {
|
|
cli.logger.Error("failed to generate random number", "err", err)
|
|
return nil
|
|
}
|
|
n := nBig.Int64()
|
|
if n >= 40 {
|
|
return nil
|
|
}
|
|
|
|
cli.backend.StatusNode().WakuV2Service().SkipPublishToTopic(true)
|
|
|
|
return func() {
|
|
cli.backend.StatusNode().WakuV2Service().SkipPublishToTopic(false)
|
|
}
|
|
}
|
|
|
|
func (cli *StatusCLI) sendDirectMessage(ctx context.Context, text string, options ...bool) error {
|
|
randomFailure := false
|
|
if len(options) > 0 {
|
|
randomFailure = options[0]
|
|
}
|
|
|
|
if len(cli.messenger.MutualContacts()) == 0 {
|
|
return nil
|
|
}
|
|
chat := cli.messenger.Chat(cli.messenger.MutualContacts()[0].ID)
|
|
cli.logger.Info("will send message to contact: ", chat.ID)
|
|
|
|
clock, timestamp := chat.NextClockAndTimestamp(cli.messenger.GetTransport())
|
|
inputMessage := common.NewMessage()
|
|
inputMessage.ChatId = chat.ID
|
|
inputMessage.LocalChatID = chat.ID
|
|
inputMessage.Clock = clock
|
|
inputMessage.Timestamp = timestamp
|
|
inputMessage.MessageType = protobuf.MessageType_ONE_TO_ONE
|
|
inputMessage.ContentType = protobuf.ChatMessage_TEXT_PLAIN
|
|
inputMessage.Text = text
|
|
|
|
shouldFail := false
|
|
if randomFailure {
|
|
if postFailure := cli.randomFailure(); postFailure != nil {
|
|
defer postFailure()
|
|
shouldFail = true
|
|
}
|
|
}
|
|
resp, err := cli.messenger.SendChatMessage(ctx, inputMessage)
|
|
if err != nil {
|
|
if shouldFail {
|
|
cli.logger.Info("simulating message failure")
|
|
cli.logger.Error("error sending message", "err", err)
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
for _, message := range resp.Messages() {
|
|
cli.logger.Infof("sent message: %v (ID=%v)", message.Text, message.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (cli *StatusCLI) retrieveMessagesLoop(ctx context.Context, tick time.Duration, msgCh chan string, wg *sync.WaitGroup) {
|
|
defer wg.Done()
|
|
|
|
ticker := time.NewTicker(tick)
|
|
defer ticker.Stop()
|
|
|
|
cli.logger.Info("retrieve messages...")
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
response, err := cli.messenger.RetrieveAll()
|
|
if err != nil {
|
|
cli.logger.Error("failed to retrieve raw messages", "err", err)
|
|
continue
|
|
}
|
|
if response == nil {
|
|
continue
|
|
}
|
|
for _, message := range response.Messages() {
|
|
cli.logger.Infof("message received: %v (ID=%v)", message.Text, message.ID)
|
|
if message.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_MUTUAL_EVENT_SENT {
|
|
msgCh <- message.ID
|
|
}
|
|
}
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// interactiveSendMessageLoop reads input from stdin and sends it as a direct message to the first mutual contact.
|
|
//
|
|
// If multiple CLIs are provided, it will send messages in a round-robin fashion:
|
|
// 1st input message will be from Alice, 2nd from Bob, 3rd from Alice, and so on.
|
|
func interactiveSendMessageLoop(ctx context.Context, clis ...*StatusCLI) {
|
|
reader := bufio.NewReader(os.Stdin)
|
|
i := -1
|
|
n := len(clis)
|
|
if n == 0 {
|
|
slog.Error("at least 1 CLI needed")
|
|
return
|
|
}
|
|
for {
|
|
i++
|
|
if i >= n {
|
|
i = 0
|
|
}
|
|
cli := clis[i] // round robin cli selection
|
|
|
|
if len(cli.messenger.MutualContacts()) == 0 {
|
|
// waits for 1 second before trying again
|
|
time.Sleep(1 * time.Second)
|
|
continue
|
|
}
|
|
cli.logger.Info("Enter your message to send: (type 'quit' or 'q' to exit)")
|
|
|
|
message, err := readInput(ctx, reader)
|
|
if err != nil {
|
|
if err == context.Canceled {
|
|
return
|
|
}
|
|
cli.logger.Error("failed to read input", err)
|
|
continue
|
|
}
|
|
message = strings.TrimSpace(message)
|
|
if message == "quit" || message == "q" || strings.Contains(message, "\x03") {
|
|
return
|
|
}
|
|
if message == "" {
|
|
continue
|
|
}
|
|
if err = cli.sendDirectMessage(ctx, message); err != nil {
|
|
cli.logger.Error("failed to send direct message: ", err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// readInput reads input from the reader and respects context cancellation
|
|
func readInput(ctx context.Context, reader *bufio.Reader) (string, error) {
|
|
inputCh := make(chan string, 1)
|
|
errCh := make(chan error, 1)
|
|
|
|
// Start a goroutine to read input
|
|
go func() {
|
|
input, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
inputCh <- input
|
|
}()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return "", ctx.Err()
|
|
case input := <-inputCh:
|
|
return input, nil
|
|
case err := <-errCh:
|
|
return "", err
|
|
}
|
|
}
|