Skip to content

Commit 32ffc7e

Browse files
authored
Merge pull request #62 from zweihander/rpc-unit-tests
client: RPC engine
2 parents f664ae7 + edfd21a commit 32ffc7e

File tree

10 files changed

+588
-175
lines changed

10 files changed

+588
-175
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ require (
1414
go.uber.org/zap v1.16.0
1515
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
1616
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7
17+
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
1718
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
1819
)

telegram/client.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/gotd/td/internal/mt"
1616
"github.com/gotd/td/internal/proto"
1717
"github.com/gotd/td/internal/tmap"
18+
"github.com/gotd/td/telegram/internal/rpc"
1819
"github.com/gotd/td/tg"
1920
"github.com/gotd/td/transport"
2021
)
@@ -84,23 +85,14 @@ type Client struct {
8485
updateHandler UpdateHandler // immutable
8586
sessionStorage SessionStorage // immutable
8687

87-
// callbacks for RPC requests, protected by rpcMux.
88-
// Key is request message id.
89-
rpc map[int64]func(b *bin.Buffer, rpcErr error) error
90-
rpcMux sync.Mutex
88+
rpc *rpc.Engine
9189

92-
// callbacks for ack protected by ackMux
93-
ack map[int64]func()
94-
ackMux sync.Mutex
9590
// ackSendChan is queue for outgoing message id's that require waiting for
9691
// ack from server.
9792
ackSendChan chan int64
9893
ackBatchSize int
9994
ackInterval time.Duration
10095

101-
maxRetries int
102-
retryInterval time.Duration
103-
10496
// callbacks for ping results protected by pingMux.
10597
// Key is ping id.
10698
ping map[int64]func()
@@ -140,18 +132,13 @@ func NewClient(appID int, appHash string, opt Options) *Client {
140132
cipher: crypto.NewClientCipher(opt.Random),
141133
log: opt.Logger,
142134
ping: map[int64]func(){},
143-
rpc: map[int64]func(b *bin.Buffer, rpcErr error) error{},
144135

145136
sessionCreated: createCondOnce(),
146137

147-
ack: map[int64]func(){},
148138
ackSendChan: make(chan int64),
149139
ackInterval: opt.AckInterval,
150140
ackBatchSize: opt.AckBatchSize,
151141

152-
maxRetries: opt.MaxRetries,
153-
retryInterval: opt.RetryInterval,
154-
155142
ctx: clientCtx,
156143
cancel: clientCancel,
157144

@@ -169,6 +156,12 @@ func NewClient(appID int, appHash string, opt Options) *Client {
169156
),
170157
}
171158

159+
client.rpc = rpc.New(client.write, rpc.Config{
160+
Logger: opt.Logger.Named("rpc"),
161+
RetryInterval: opt.RetryInterval,
162+
MaxRetries: opt.MaxRetries,
163+
})
164+
172165
// Initializing internal RPC caller.
173166
client.tg = tg.NewClient(client)
174167

telegram/handle_ack.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,10 @@ func (c *Client) handleAck(b *bin.Buffer) error {
1313
if err := ack.Decode(b); err != nil {
1414
return xerrors.Errorf("decode: %w", err)
1515
}
16-
c.log.With(zap.Int64s("messages", ack.MsgIds)).Debug("Ack")
17-
18-
c.ackMux.Lock()
19-
defer c.ackMux.Unlock()
2016

21-
for _, msgID := range ack.MsgIds {
22-
fn, found := c.ack[msgID]
23-
if !found {
24-
c.log.Warn("ack callback is not set", zap.Int64("message_id", msgID))
25-
continue
26-
}
17+
c.log.With(zap.Int64s("messages", ack.MsgIds)).Debug("Ack")
2718

28-
fn()
29-
delete(c.ack, msgID)
30-
}
19+
c.rpc.NotifyAcks(ack.MsgIds)
3120

3221
return nil
3322
}

telegram/handle_bad_msg.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,15 @@ func (c *Client) handleBadMsg(b *bin.Buffer) error {
6161
return err
6262
}
6363

64-
c.rpcMux.Lock()
65-
f, ok := c.rpc[bad.BadMsgID]
66-
c.rpcMux.Unlock()
67-
if ok {
68-
return f(b, &badMessageError{Code: bad.ErrorCode})
69-
}
70-
64+
c.rpc.NotifyError(bad.BadMsgID, &badMessageError{Code: bad.ErrorCode})
7165
return nil
7266
case mt.BadServerSaltTypeID:
7367
var bad mt.BadServerSalt
7468
if err := bad.Decode(b); err != nil {
7569
return err
7670
}
7771

78-
c.rpcMux.Lock()
79-
f, ok := c.rpc[bad.BadMsgID]
80-
c.rpcMux.Unlock()
81-
if ok {
82-
return f(b, &badMessageError{Code: bad.ErrorCode, NewSalt: bad.NewServerSalt})
83-
}
84-
72+
c.rpc.NotifyError(bad.BadMsgID, &badMessageError{Code: bad.ErrorCode, NewSalt: bad.NewServerSalt})
8573
return nil
8674
default:
8775
return xerrors.Errorf("unknown type id 0x%d", id)

telegram/handle_message_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/gotd/td/bin"
11+
"github.com/gotd/td/telegram/internal/rpc"
1112

1213
"go.uber.org/zap"
1314
)
@@ -57,6 +58,7 @@ func TestClientHandleMessageCorpus(t *testing.T) {
5758
rand: Zero{},
5859
log: zap.NewNop(),
5960
sessionCreated: createCondOnce(),
61+
rpc: rpc.New(rpc.NopSend, rpc.Config{}),
6062
}
6163
c.sessionCreated.Done()
6264

telegram/handle_result.go

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,32 +45,18 @@ func (c *Client) handleResult(b *bin.Buffer) error {
4545
return xerrors.Errorf("error decode: %w", err)
4646
}
4747

48-
c.rpcMux.Lock()
49-
f, ok := c.rpc[res.RequestMessageID]
50-
c.rpcMux.Unlock()
51-
if ok {
52-
e := &Error{
53-
Code: rpcErr.ErrorCode,
54-
Message: rpcErr.ErrorMessage,
55-
}
56-
e.extractArgument()
57-
return f(nil, e)
48+
e := &Error{
49+
Code: rpcErr.ErrorCode,
50+
Message: rpcErr.ErrorMessage,
5851
}
52+
e.extractArgument()
5953

54+
c.rpc.NotifyError(res.RequestMessageID, e)
6055
return nil
6156
}
6257
if id == mt.PongTypeID {
6358
return c.handlePong(b)
6459
}
6560

66-
c.rpcMux.Lock()
67-
f, ok := c.rpc[res.RequestMessageID]
68-
c.rpcMux.Unlock()
69-
70-
if ok {
71-
return f(b, nil)
72-
}
73-
74-
c.log.Debug("Got unexpected result")
75-
return nil
61+
return c.rpc.NotifyResult(res.RequestMessageID, b)
7662
}

telegram/internal/rpc/ack.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package rpc
2+
3+
import (
4+
"context"
5+
6+
"go.uber.org/zap"
7+
)
8+
9+
// NotifyAcks notifies engine about received acknowledgements.
10+
func (e *Engine) NotifyAcks(ids []int64) {
11+
for _, id := range ids {
12+
e.mux.Lock()
13+
cb, ok := e.ack[id]
14+
e.mux.Unlock()
15+
16+
if !ok {
17+
e.log.Warn("ack callback not set", zap.Int64("msg_id", id))
18+
continue
19+
}
20+
21+
cb()
22+
}
23+
}
24+
25+
// waitAck blocks until acknowledgement on message id is received.
26+
func (e *Engine) waitAck(ctx context.Context, id int64) error {
27+
got := make(chan struct{})
28+
29+
e.mux.Lock()
30+
e.ack[id] = func() { close(got) }
31+
e.mux.Unlock()
32+
33+
defer func() {
34+
e.mux.Lock()
35+
delete(e.ack, id)
36+
e.mux.Unlock()
37+
}()
38+
39+
select {
40+
case <-ctx.Done():
41+
return ctx.Err()
42+
case <-got:
43+
return nil
44+
}
45+
}

0 commit comments

Comments
 (0)