github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/mobilepush.go (about) 1 package chat 2 3 import ( 4 "context" 5 "encoding/base64" 6 "time" 7 8 "github.com/keybase/client/go/chat/globals" 9 "github.com/keybase/client/go/libkb" 10 11 "github.com/keybase/client/go/chat/storage" 12 "github.com/keybase/client/go/chat/utils" 13 "github.com/keybase/client/go/protocol/chat1" 14 "github.com/keybase/client/go/protocol/gregor1" 15 "github.com/keybase/client/go/protocol/keybase1" 16 "github.com/keybase/go-codec/codec" 17 "github.com/keybase/go-framed-msgpack-rpc/rpc" 18 ) 19 20 type remoteNotificationSuccessHandler struct{} 21 22 func (g *remoteNotificationSuccessHandler) HandlerName() string { 23 return "remote notification success" 24 } 25 func (g *remoteNotificationSuccessHandler) OnConnect(ctx context.Context, conn *rpc.Connection, cli rpc.GenericClient, srv *rpc.Server) error { 26 return nil 27 } 28 func (g *remoteNotificationSuccessHandler) OnConnectError(err error, reconnectThrottleDuration time.Duration) { 29 } 30 func (g *remoteNotificationSuccessHandler) OnDisconnected(ctx context.Context, status rpc.DisconnectStatus) { 31 } 32 func (g *remoteNotificationSuccessHandler) OnDoCommandError(err error, nextTime time.Duration) {} 33 func (g *remoteNotificationSuccessHandler) ShouldRetry(name string, err error) bool { 34 return false 35 } 36 func (g *remoteNotificationSuccessHandler) ShouldRetryOnConnect(err error) bool { 37 return false 38 } 39 40 type MobilePush struct { 41 globals.Contextified 42 utils.DebugLabeler 43 } 44 45 func NewMobilePush(g *globals.Context) *MobilePush { 46 return &MobilePush{ 47 Contextified: globals.NewContextified(g), 48 DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "MobilePush", false), 49 } 50 } 51 52 func (h *MobilePush) AckNotificationSuccess(ctx context.Context, pushIDs []string) { 53 defer h.Trace(ctx, nil, "AckNotificationSuccess: pushID: %v", pushIDs)() 54 conn, token, err := utils.GetGregorConn(ctx, h.G(), h.DebugLabeler, 55 func(nist *libkb.NIST) rpc.ConnectionHandler { 56 return &remoteNotificationSuccessHandler{} 57 }) 58 if err != nil { 59 return 60 } 61 defer conn.Shutdown() 62 63 // Make remote successful call on our ad hoc conn 64 cli := chat1.RemoteClient{Cli: NewRemoteClient(h.G(), conn.GetClient())} 65 if err = cli.RemoteNotificationSuccessful(ctx, 66 chat1.RemoteNotificationSuccessfulArg{ 67 AuthToken: token, 68 CompanionPushIDs: pushIDs, 69 }); err != nil { 70 h.Debug(ctx, "AckNotificationSuccess: failed to invoke remote notification success: %s", err) 71 } 72 } 73 74 func (h *MobilePush) UnboxPushNotification(ctx context.Context, uid gregor1.UID, 75 convID chat1.ConversationID, membersType chat1.ConversationMembersType, payload string) (res chat1.MessageUnboxed, err error) { 76 defer h.Trace(ctx, &err, "UnboxPushNotification: convID: %v", convID)() 77 // Parse the message payload 78 bMsg, err := base64.StdEncoding.DecodeString(payload) 79 if err != nil { 80 h.Debug(ctx, "UnboxPushNotification: invalid message payload: %s", err) 81 return res, err 82 } 83 var msgBoxed chat1.MessageBoxed 84 mh := codec.MsgpackHandle{WriteExt: true} 85 if err = codec.NewDecoderBytes(bMsg, &mh).Decode(&msgBoxed); err != nil { 86 h.Debug(ctx, "UnboxPushNotification: failed to msgpack decode payload: %s", err) 87 return res, err 88 } 89 90 // Unbox first 91 vis := keybase1.TLFVisibility_PRIVATE 92 if msgBoxed.ClientHeader.TlfPublic { 93 vis = keybase1.TLFVisibility_PUBLIC 94 } 95 unboxInfo := newBasicUnboxConversationInfo(convID, membersType, nil, vis) 96 msgUnboxed, err := NewBoxer(h.G()).UnboxMessage(ctx, msgBoxed, unboxInfo, nil) 97 if err != nil { 98 h.Debug(ctx, "UnboxPushNotification: unbox failed, bailing: %s", err) 99 return res, err 100 } 101 102 // Check to see if this will be a strict append before adding to the body cache 103 if err := h.G().ConvSource.AcquireConversationLock(ctx, uid, convID); err != nil { 104 return res, err 105 } 106 maxMsgID, err := storage.New(h.G(), h.G().ConvSource).GetMaxMsgID(ctx, convID, uid) 107 if err == nil { 108 if msgUnboxed.GetMessageID() > maxMsgID { 109 if err = h.G().ConvSource.PushUnboxed(ctx, unboxInfo, uid, []chat1.MessageUnboxed{msgUnboxed}); err != nil { 110 h.Debug(ctx, "UnboxPushNotification: failed to push message to conv source: %s", 111 err.Error()) 112 } 113 } else { 114 h.Debug(ctx, "UnboxPushNotification: message from the past, skipping insert: msgID: %d maxMsgID: %d", msgUnboxed.GetMessageID(), maxMsgID) 115 } 116 } else { 117 h.Debug(ctx, "UnboxPushNotification: failed to fetch max msg ID: %s", err) 118 } 119 h.G().ConvSource.ReleaseConversationLock(ctx, uid, convID) 120 return msgUnboxed, nil 121 }