github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/commands/location.go (about) 1 package commands 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/keybase/client/go/chat/globals" 11 "github.com/keybase/client/go/chat/utils" 12 "github.com/keybase/client/go/protocol/chat1" 13 "github.com/keybase/client/go/protocol/gregor1" 14 "github.com/keybase/clockwork" 15 ) 16 17 type Location struct { 18 *baseCommand 19 sync.Mutex 20 displayed bool 21 clock clockwork.Clock 22 } 23 24 func NewLocation(g *globals.Context) *Location { 25 return &Location{ 26 baseCommand: newBaseCommand(g, "location", "", "Post your current location", true), 27 clock: clockwork.NewRealClock(), 28 } 29 } 30 31 func (h *Location) SetClock(clock clockwork.Clock) { 32 h.clock = clock 33 } 34 35 func (h *Location) isLiveLocation(toks []string) *gregor1.Time { 36 if len(toks) != 3 { 37 return nil 38 } 39 if toks[1] != "live" { 40 return nil 41 } 42 dur, err := time.ParseDuration(toks[2]) 43 if err != nil { 44 return nil 45 } 46 rtime := gregor1.ToTime(h.clock.Now().Add(dur)) 47 return &rtime 48 } 49 50 func (h *Location) isStop(toks []string) bool { 51 if len(toks) != 2 { 52 return false 53 } 54 return toks[1] == "stop" 55 } 56 57 func (h *Location) Execute(ctx context.Context, uid gregor1.UID, convID chat1.ConversationID, 58 tlfName, text string, replyTo *chat1.MessageID) (err error) { 59 defer h.Trace(ctx, &err, "Location")() 60 if !h.Match(ctx, text) { 61 return ErrInvalidCommand 62 } 63 toks := strings.Split(text, " ") 64 if h.isStop(toks) { 65 h.G().LiveLocationTracker.StopAllTracking(ctx) 66 err := h.getChatUI().ChatCommandStatus(ctx, convID, "All location tracking stopped", 67 chat1.UICommandStatusDisplayTyp_STATUS, nil) 68 if err != nil { 69 h.Debug(ctx, "Execute: error with command status: %+v", err) 70 } 71 return nil 72 } 73 var liveLocation chat1.LiveLocation 74 liveLocationEndTime := h.isLiveLocation(toks) 75 if liveLocationEndTime != nil { 76 liveLocation.EndTime = *liveLocationEndTime 77 } 78 if _, err := h.G().ChatHelper.SendMsgByIDNonblock(ctx, convID, tlfName, 79 chat1.NewMessageBodyWithText(chat1.MessageText{ 80 Body: text, 81 LiveLocation: &liveLocation, 82 }), chat1.MessageType_TEXT, nil, replyTo); err != nil { 83 return err 84 } 85 return nil 86 } 87 88 func (h *Location) Preview(ctx context.Context, uid gregor1.UID, convID chat1.ConversationID, 89 tlfName, text string) { 90 h.Lock() 91 defer h.Unlock() 92 defer h.Trace(ctx, nil, "Preview")() 93 if !h.Match(ctx, text) { 94 if h.displayed { 95 err := h.getChatUI().ChatCommandMarkdown(ctx, convID, nil) 96 if err != nil { 97 h.Debug(ctx, "Preview: error with markdown: %+v", err) 98 } 99 h.displayed = false 100 } 101 return 102 } 103 usage := fmt.Sprintf(locationUsage, "```", "```") 104 err := h.getChatUI().ChatCommandMarkdown(ctx, convID, &chat1.UICommandMarkdown{ 105 Body: utils.DecorateWithLinks(ctx, utils.EscapeForDecorate(ctx, usage)), 106 Title: &locationTitle, 107 }) 108 if err != nil { 109 h.Debug(ctx, "Preview: error with markdown: %+v", err) 110 } 111 h.displayed = true 112 } 113 114 var locationTitle = `*/location* 115 Post your current location and a map rendered through the use of Google Maps. 116 ` 117 118 var locationUsage = `We take care to guard your privacy: https://keybase.io/docs/chat/location. 119 Variations: %s 120 /location 121 /location live 1h 122 /location stop%s 123 `