Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support sending in-chat payment through JSON API CORE-9825 #15330

Merged
merged 6 commits into from
Jan 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 24 additions & 29 deletions go/chat/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1121,17 +1121,8 @@ func (h *Server) PostLocal(ctx context.Context, arg chat1.PostLocalArg) (res cha
}

// Run Stellar UI on any payments in the body
bodyTyp, err := arg.Msg.MessageBody.MessageType()
if err == nil && bodyTyp == chat1.MessageType_TEXT {
text := arg.Msg.MessageBody.Text().Body
payments, err := h.runStellarSendUI(ctx, 0, uid, arg.ConversationID, text)
if err != nil {
return res, err
}
arg.Msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{
Body: text,
Payments: payments,
})
if arg.Msg.MessageBody, err = h.runStellarSendUI(ctx, 0, uid, arg.ConversationID, arg.Msg.MessageBody); err != nil {
return res, err
}

// Make sure sender is set
Expand Down Expand Up @@ -1204,13 +1195,18 @@ func (h *Server) PostEditNonblock(ctx context.Context, arg chat1.PostEditNonbloc
}

func (h *Server) runStellarSendUI(ctx context.Context, sessionID int, uid gregor1.UID,
convID chat1.ConversationID, body string) (res []chat1.TextPayment, err error) {
ui := h.getChatUI(sessionID)
convID chat1.ConversationID, msgBody chat1.MessageBody) (res chat1.MessageBody, err error) {
defer h.Trace(ctx, func() error { return err }, "runStellarSendUI")()
ui := h.getChatUI(sessionID)
bodyTyp, err := msgBody.MessageType()
if err != nil || bodyTyp != chat1.MessageType_TEXT {
return msgBody, nil
}
body := msgBody.Text().Body
parsedPayments := h.G().StellarSender.ParsePayments(ctx, uid, convID, body)
if len(parsedPayments) == 0 {
h.Debug(ctx, "runStellarSendUI: no payments")
return nil, nil
return msgBody, nil
}
h.Debug(ctx, "runStellarSendUI: payments found, showing confirm screen")
if err := ui.ChatStellarShowConfirm(ctx); err != nil {
Expand All @@ -1237,26 +1233,20 @@ func (h *Server) runStellarSendUI(ctx context.Context, sessionID int, uid gregor
if err != nil {
// Send regardless here
h.Debug(ctx, "runStellarSendUI: failed to send payments, but continuing on: %s", err)
return nil, nil
return msgBody, nil
}
return payments, nil
return chat1.NewMessageBodyWithText(chat1.MessageText{
Body: body,
Payments: payments,
}), nil
}

func (h *Server) PostTextNonblock(ctx context.Context, arg chat1.PostTextNonblockArg) (res chat1.PostLocalNonblockRes, err error) {
ctx = Context(ctx, h.G(), arg.IdentifyBehavior, nil, h.identNotifier)
defer h.Trace(ctx, func() error { return err }, "PostTextNonblock")()
uid, err := utils.AssertLoggedInUID(ctx, h.G())
if err != nil {
return res, err
}

// Determine if the messages contains any Stellar payments, and execute them if so
payments, err := h.runStellarSendUI(ctx, arg.SessionID, uid, arg.ConversationID, arg.Body)
if err != nil {
return res, err
}

var parg chat1.PostLocalNonblockArg
parg.SessionID = arg.SessionID
parg.ClientPrev = arg.ClientPrev
parg.ConversationID = arg.ConversationID
parg.IdentifyBehavior = arg.IdentifyBehavior
Expand All @@ -1265,8 +1255,7 @@ func (h *Server) PostTextNonblock(ctx context.Context, arg chat1.PostTextNonbloc
parg.Msg.ClientHeader.TlfName = arg.TlfName
parg.Msg.ClientHeader.TlfPublic = arg.TlfPublic
parg.Msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{
Body: arg.Body,
Payments: payments,
Body: arg.Body,
})
if arg.EphemeralLifetime != nil {
parg.Msg.ClientHeader.EphemeralMetadata = &chat1.MsgEphemeralMetadata{
Expand Down Expand Up @@ -1432,6 +1421,12 @@ func (h *Server) PostLocalNonblock(ctx context.Context, arg chat1.PostLocalNonbl
return res, fmt.Errorf("no TLF name specified")
}

// Determine if the messages contains any Stellar payments, and execute them if so
if arg.Msg.MessageBody, err = h.runStellarSendUI(ctx, arg.SessionID, uid, arg.ConversationID,
arg.Msg.MessageBody); err != nil {
return res, err
}

// Add outbox information
var prevMsgID chat1.MessageID
if arg.ClientPrev == 0 {
Expand All @@ -1456,7 +1451,7 @@ func (h *Server) PostLocalNonblock(ctx context.Context, arg chat1.PostLocalNonbl
sender := NewBlockingSender(h.G(), h.boxer, h.remoteClient)
nonblockSender := NewNonblockingSender(h.G(), sender)

obid, _, err := nonblockSender.Send(ctx, arg.ConversationID, arg.Msg, arg.ClientPrev, arg.OutboxID)
obid, _, err := nonblockSender.Send(ctx, arg.ConversationID, arg.Msg, prevMsgID, arg.OutboxID)
if err != nil {
return res, fmt.Errorf("PostLocalNonblock: unable to send message: err: %s", err.Error())
}
Expand Down
151 changes: 151 additions & 0 deletions go/chat/utils/dummy_chat_ui.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package utils

import (
"golang.org/x/net/context"

"github.com/keybase/client/go/protocol/chat1"
"github.com/keybase/client/go/protocol/keybase1"
)

type DummyChatUI struct{}

func (r DummyChatUI) ChatAttachmentDownloadStart(ctx context.Context, sessionID int) error {
return nil
}

func (r DummyChatUI) ChatAttachmentDownloadProgress(ctx context.Context,
arg chat1.ChatAttachmentDownloadProgressArg) error {
return nil
}

func (r DummyChatUI) ChatAttachmentDownloadDone(ctx context.Context, sessionID int) error {
return nil
}

func (r DummyChatUI) ChatInboxConversation(ctx context.Context, arg chat1.ChatInboxConversationArg) error {
return nil
}

func (r DummyChatUI) ChatInboxFailed(ctx context.Context, arg chat1.ChatInboxFailedArg) error {
return nil
}

func (r DummyChatUI) ChatInboxUnverified(ctx context.Context, arg chat1.ChatInboxUnverifiedArg) error {
return nil
}

func (r DummyChatUI) ChatThreadCached(ctx context.Context, arg chat1.ChatThreadCachedArg) error {
return nil
}

func (r DummyChatUI) ChatThreadFull(ctx context.Context, arg chat1.ChatThreadFullArg) error {
return nil
}

func (r DummyChatUI) ChatConfirmChannelDelete(ctx context.Context, arg chat1.ChatConfirmChannelDeleteArg) (bool, error) {
return true, nil
}

func (r DummyChatUI) ChatSearchHit(ctx context.Context, arg chat1.ChatSearchHitArg) error {
return nil
}

func (r DummyChatUI) ChatSearchDone(ctx context.Context, arg chat1.ChatSearchDoneArg) error {
return nil
}

func (r DummyChatUI) ChatSearchInboxHit(ctx context.Context, arg chat1.ChatSearchInboxHitArg) error {
return nil
}

func (r DummyChatUI) ChatSearchInboxDone(ctx context.Context, arg chat1.ChatSearchInboxDoneArg) error {
return nil
}

func (r DummyChatUI) ChatSearchIndexStatus(ctx context.Context, arg chat1.ChatSearchIndexStatusArg) error {
return nil
}

func (r DummyChatUI) ChatStellarDataConfirm(ctx context.Context, arg chat1.ChatStellarDataConfirmArg) (bool, error) {
return true, nil
}

func (r DummyChatUI) ChatStellarShowConfirm(ctx context.Context, sessionID int) error {
return nil
}

func (r DummyChatUI) ChatStellarDataError(ctx context.Context, arg chat1.ChatStellarDataErrorArg) (bool, error) {
return true, nil
}

func (r DummyChatUI) ChatStellarDone(ctx context.Context, arg chat1.ChatStellarDoneArg) error {
return nil
}

type DummyChatNotifications struct{}

func (d DummyChatNotifications) NewChatActivity(ctx context.Context, arg chat1.NewChatActivityArg) error {
return nil
}

func (d DummyChatNotifications) ChatIdentifyUpdate(context.Context, keybase1.CanonicalTLFNameAndIDWithBreaks) error {
return nil
}
func (d DummyChatNotifications) ChatTLFFinalize(context.Context, chat1.ChatTLFFinalizeArg) error {
return nil
}
func (d DummyChatNotifications) ChatTLFResolve(context.Context, chat1.ChatTLFResolveArg) error {
return nil
}
func (d DummyChatNotifications) ChatInboxStale(context.Context, keybase1.UID) error { return nil }
func (d DummyChatNotifications) ChatThreadsStale(context.Context, chat1.ChatThreadsStaleArg) error {
return nil
}
func (d DummyChatNotifications) ChatTypingUpdate(context.Context, []chat1.ConvTypingUpdate) error {
return nil
}
func (d DummyChatNotifications) ChatJoinedConversation(context.Context, chat1.ChatJoinedConversationArg) error {
return nil
}
func (d DummyChatNotifications) ChatLeftConversation(context.Context, chat1.ChatLeftConversationArg) error {
return nil
}
func (d DummyChatNotifications) ChatResetConversation(context.Context, chat1.ChatResetConversationArg) error {
return nil
}
func (d DummyChatNotifications) ChatInboxSyncStarted(context.Context, keybase1.UID) error {
return nil
}
func (d DummyChatNotifications) ChatInboxSynced(context.Context, chat1.ChatInboxSyncedArg) error {
return nil
}
func (d DummyChatNotifications) ChatSetConvRetention(context.Context, chat1.ChatSetConvRetentionArg) error {
return nil
}
func (d DummyChatNotifications) ChatSetTeamRetention(context.Context, chat1.ChatSetTeamRetentionArg) error {
return nil
}
func (d DummyChatNotifications) ChatSetConvSettings(context.Context, chat1.ChatSetConvSettingsArg) error {
return nil
}
func (d DummyChatNotifications) ChatSubteamRename(context.Context, chat1.ChatSubteamRenameArg) error {
return nil
}
func (d DummyChatNotifications) ChatKBFSToImpteamUpgrade(context.Context, chat1.ChatKBFSToImpteamUpgradeArg) error {
return nil
}
func (d DummyChatNotifications) ChatAttachmentUploadStart(context.Context, chat1.ChatAttachmentUploadStartArg) error {
return nil
}
func (d DummyChatNotifications) ChatAttachmentUploadProgress(context.Context, chat1.ChatAttachmentUploadProgressArg) error {
return nil
}
func (d DummyChatNotifications) ChatPaymentInfo(context.Context, chat1.ChatPaymentInfoArg) error {
return nil
}
func (d DummyChatNotifications) ChatRequestInfo(context.Context, chat1.ChatRequestInfoArg) error {
return nil
}
func (d DummyChatNotifications) ChatPromptUnfurl(context.Context, chat1.ChatPromptUnfurlArg) error {
return nil
}
10 changes: 5 additions & 5 deletions go/client/chat_api_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ type sendOptionsV1 struct {
Nonblock bool `json:"nonblock"`
MembersType string `json:"members_type"`
EphemeralLifetime ephemeralLifetime `json:"exploding_lifetime"`
ConfirmLumenSend bool `json:"confirm_lumen_send"`
}

func (s sendOptionsV1) Check() error {
Expand Down Expand Up @@ -450,8 +451,8 @@ func (a *ChatAPI) SendV1(ctx context.Context, c Call, w io.Writer) error {
}

// opts are valid for send v1

return a.encodeReply(c, a.svcHandler.SendV1(ctx, opts), w)
chatUI := NewChatAPIUI(AllowStellarPayments(opts.ConfirmLumenSend))
return a.encodeReply(c, a.svcHandler.SendV1(ctx, opts, chatUI), w)
}

func (a *ChatAPI) EditV1(ctx context.Context, c Call, w io.Writer) error {
Expand Down Expand Up @@ -518,8 +519,7 @@ func (a *ChatAPI) AttachV1(ctx context.Context, c Call, w io.Writer) error {
}

// opts are valid for attach v1

return a.encodeReply(c, a.svcHandler.AttachV1(ctx, opts), w)
return a.encodeReply(c, a.svcHandler.AttachV1(ctx, opts, NewChatAPIUI(), NewChatAPINotifications()), w)
}

func (a *ChatAPI) DownloadV1(ctx context.Context, c Call, w io.Writer) error {
Expand All @@ -536,7 +536,7 @@ func (a *ChatAPI) DownloadV1(ctx context.Context, c Call, w io.Writer) error {

// opts are valid for download v1

return a.encodeReply(c, a.svcHandler.DownloadV1(ctx, opts), w)
return a.encodeReply(c, a.svcHandler.DownloadV1(ctx, opts, NewChatAPIUI()), w)
}

func (a *ChatAPI) SetStatusV1(ctx context.Context, c Call, w io.Writer) error {
Expand Down
8 changes: 5 additions & 3 deletions go/client/chat_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"
"testing"

"github.com/keybase/client/go/protocol/chat1"
"golang.org/x/net/context"
)

Expand Down Expand Up @@ -115,7 +116,7 @@ func (c *chatEcho) GetV1(context.Context, getOptionsV1) Reply {
return Reply{Result: echoOK}
}

func (c *chatEcho) SendV1(context.Context, sendOptionsV1) Reply {
func (c *chatEcho) SendV1(context.Context, sendOptionsV1, chat1.ChatUiInterface) Reply {
return Reply{Result: echoOK}
}

Expand All @@ -131,11 +132,12 @@ func (c *chatEcho) ReactionV1(context.Context, reactionOptionsV1) Reply {
return Reply{Result: echoOK}
}

func (c *chatEcho) AttachV1(context.Context, attachOptionsV1) Reply {
func (c *chatEcho) AttachV1(context.Context, attachOptionsV1, chat1.ChatUiInterface,
chat1.NotifyChatInterface) Reply {
return Reply{Result: echoOK}
}

func (c *chatEcho) DownloadV1(context.Context, downloadOptionsV1) Reply {
func (c *chatEcho) DownloadV1(context.Context, downloadOptionsV1, chat1.ChatUiInterface) Reply {
return Reply{Result: echoOK}
}

Expand Down
46 changes: 46 additions & 0 deletions go/client/chat_api_ui.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package client

import (
"github.com/keybase/client/go/chat/utils"
"github.com/keybase/client/go/protocol/chat1"
"golang.org/x/net/context"
)

type ChatAPIUI struct {
utils.DummyChatUI
allowStellarPayments bool
}

func AllowStellarPayments(enabled bool) func(*ChatAPIUI) {
return func(c *ChatAPIUI) {
c.SetAllowStellarPayments(enabled)
}
}

func NewChatAPIUI(opts ...func(*ChatAPIUI)) *ChatAPIUI {
c := &ChatAPIUI{
DummyChatUI: utils.DummyChatUI{},
}
for _, o := range opts {
o(c)
}
return c
}

func (u *ChatAPIUI) ChatStellarDataConfirm(ctx context.Context, arg chat1.ChatStellarDataConfirmArg) (bool, error) {
return u.allowStellarPayments, nil
}

func (u *ChatAPIUI) SetAllowStellarPayments(enabled bool) {
u.allowStellarPayments = enabled
}

type ChatAPINotifications struct {
utils.DummyChatNotifications
}

func NewChatAPINotifications() *ChatAPINotifications {
return &ChatAPINotifications{
DummyChatNotifications: utils.DummyChatNotifications{},
}
}
Loading