1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"encoding/base64"
8	"time"
9
10	"github.com/keybase/client/go/kex2"
11)
12
13// KexRouter implements the kex2.MessageRouter interface.
14type KexRouter struct {
15	MetaContextified
16}
17
18// NewKexRouter creates a contextified KexRouter.
19func NewKexRouter(m MetaContext) *KexRouter {
20	return &KexRouter{
21		MetaContextified: NewMetaContextified(m),
22	}
23}
24
25// Post implements Post in the kex2.MessageRouter interface.
26func (k *KexRouter) Post(sessID kex2.SessionID, sender kex2.DeviceID, seqno kex2.Seqno, msg []byte) (err error) {
27	mctx := k.M().WithLogTag("KEXR")
28	mctx.Debug("+ KexRouter.Post(%x, %x, %d, ...)", sessID, sender, seqno)
29	defer func() {
30		mctx.Debug("- KexRouter.Post(%x, %x, %d) -> %s", sessID, sender, seqno, ErrToOk(err))
31	}()
32
33	arg := APIArg{
34		Endpoint: "kex2/send",
35		Args: HTTPArgs{
36			"I":      HexArg(sessID[:]),
37			"sender": HexArg(sender[:]),
38			"seqno":  I{Val: int(seqno)},
39			"msg":    B64Arg(msg),
40		},
41	}
42	mctx = mctx.BackgroundWithLogTags()
43	kexAPITimeout(&arg, time.Second*5)
44	_, err = mctx.G().API.Post(mctx, arg)
45
46	return err
47}
48
49type kexResp struct {
50	Msgs []struct {
51		Msg string `json:"msg"`
52	} `json:"msgs"`
53	Status AppStatus `json:"status"`
54}
55
56func (k *kexResp) GetAppStatus() *AppStatus {
57	return &k.Status
58}
59
60func kexAPITimeout(arg *APIArg, initial time.Duration) {
61	arg.RetryCount = 5
62	arg.RetryMultiplier = 1.0
63	initialMin := time.Second * 3
64	if initial < initialMin {
65		initial = initialMin
66	}
67	arg.InitialTimeout = initial
68}
69
70// Get implements Get in the kex2.MessageRouter interface.
71func (k *KexRouter) Get(sessID kex2.SessionID, receiver kex2.DeviceID, low kex2.Seqno, poll time.Duration) (msgs [][]byte, err error) {
72	mctx := k.M().WithLogTag("KEXR")
73	mctx.Debug("+ KexRouter.Get(%x, %x, %d, %s)", sessID, receiver, low, poll)
74	defer func() {
75		mctx.Debug("- KexRouter.Get(%x, %x, %d, %s) -> %s (messages: %d)", sessID, receiver, low, poll, ErrToOk(err), len(msgs))
76	}()
77
78	if poll > HTTPPollMaximum {
79		poll = HTTPPollMaximum
80	}
81
82	arg := APIArg{
83		Endpoint: "kex2/receive",
84		Args: HTTPArgs{
85			"I":        HexArg(sessID[:]),
86			"receiver": HexArg(receiver[:]),
87			"low":      I{Val: int(low)},
88			"poll":     I{Val: int(poll / time.Millisecond)},
89		},
90	}
91	kexAPITimeout(&arg, 2*poll)
92	var j kexResp
93
94	if err = mctx.G().API.GetDecode(mctx.BackgroundWithLogTags(), arg, &j); err != nil {
95		return nil, err
96	}
97	if j.Status.Code != SCOk {
98		return nil, AppStatusError{Code: j.Status.Code, Name: j.Status.Name, Desc: j.Status.Desc}
99	}
100
101	for _, m := range j.Msgs {
102		dec, err := base64.StdEncoding.DecodeString(m.Msg)
103		if err != nil {
104			return nil, err
105		}
106		msgs = append(msgs, dec)
107	}
108
109	return msgs, nil
110}
111