Introduce proxy for VPP
[govpp.git] / proxy / client.go
1 package proxy
2
3 import (
4         "fmt"
5         "log"
6         "net/rpc"
7         "reflect"
8         "time"
9
10         "git.fd.io/govpp.git/api"
11 )
12
13 type Client struct {
14         serverAddr string
15         rpc        *rpc.Client
16 }
17
18 // Connect dials remote proxy server on given address and
19 // returns new client if successful.
20 func Connect(addr string) (*Client, error) {
21         client, err := rpc.DialHTTP("tcp", addr)
22         if err != nil {
23                 log.Fatal("Connection error: ", err)
24         }
25         c := &Client{
26                 serverAddr: addr,
27                 rpc:        client,
28         }
29         return c, nil
30 }
31
32 // NewStatsClient returns new StatsClient which implements api.StatsProvider.
33 func (c *Client) NewStatsClient() (*StatsClient, error) {
34         stats := &StatsClient{
35                 rpc: c.rpc,
36         }
37         return stats, nil
38 }
39
40 // NewBinapiClient returns new BinapiClient which implements api.Channel.
41 func (c *Client) NewBinapiClient() (*BinapiClient, error) {
42         binapi := &BinapiClient{
43                 rpc: c.rpc,
44         }
45         return binapi, nil
46 }
47
48 type StatsClient struct {
49         rpc *rpc.Client
50 }
51
52 func (s *StatsClient) GetSystemStats(sysStats *api.SystemStats) error {
53         req := StatsRequest{StatsType: "system"}
54         resp := StatsResponse{SysStats: sysStats}
55         return s.rpc.Call("StatsRPC.GetStats", req, &resp)
56 }
57
58 func (s *StatsClient) GetNodeStats(nodeStats *api.NodeStats) error {
59         req := StatsRequest{StatsType: "node"}
60         resp := StatsResponse{NodeStats: nodeStats}
61         return s.rpc.Call("StatsRPC.GetStats", req, &resp)
62 }
63
64 func (s *StatsClient) GetInterfaceStats(ifaceStats *api.InterfaceStats) error {
65         req := StatsRequest{StatsType: "interface"}
66         resp := StatsResponse{IfaceStats: ifaceStats}
67         return s.rpc.Call("StatsRPC.GetStats", req, &resp)
68 }
69
70 func (s *StatsClient) GetErrorStats(errStats *api.ErrorStats) error {
71         req := StatsRequest{StatsType: "error"}
72         resp := StatsResponse{ErrStats: errStats}
73         return s.rpc.Call("StatsRPC.GetStats", req, &resp)
74 }
75
76 func (s *StatsClient) GetBufferStats(bufStats *api.BufferStats) error {
77         req := StatsRequest{StatsType: "buffer"}
78         resp := StatsResponse{BufStats: bufStats}
79         return s.rpc.Call("StatsRPC.GetStats", req, &resp)
80 }
81
82 type BinapiClient struct {
83         rpc *rpc.Client
84 }
85
86 func (b *BinapiClient) SendRequest(msg api.Message) api.RequestCtx {
87         req := &requestCtx{
88                 rpc: b.rpc,
89                 req: msg,
90         }
91         log.Printf("SendRequest: %T %+v", msg, msg)
92         return req
93 }
94
95 type requestCtx struct {
96         rpc *rpc.Client
97         req api.Message
98 }
99
100 func (r *requestCtx) ReceiveReply(msg api.Message) error {
101         req := BinapiRequest{
102                 Msg:      r.req,
103                 ReplyMsg: msg,
104         }
105         resp := BinapiResponse{}
106
107         err := r.rpc.Call("BinapiRPC.Invoke", req, &resp)
108         if err != nil {
109                 return fmt.Errorf("RPC call failed: %v", err)
110         }
111
112         // we set the value of msg to the value from response
113         reflect.ValueOf(msg).Elem().Set(reflect.ValueOf(resp.Msg).Elem())
114
115         return nil
116 }
117
118 func (b *BinapiClient) SendMultiRequest(msg api.Message) api.MultiRequestCtx {
119         req := &multiRequestCtx{
120                 rpc: b.rpc,
121                 req: msg,
122         }
123         log.Printf("SendMultiRequest: %T %+v", msg, msg)
124         return req
125 }
126
127 type multiRequestCtx struct {
128         rpc *rpc.Client
129         req api.Message
130
131         index   int
132         replies []api.Message
133 }
134
135 func (r *multiRequestCtx) ReceiveReply(msg api.Message) (stop bool, err error) {
136         // we call Invoke only on first ReceiveReply
137         if r.index == 0 {
138                 req := BinapiRequest{
139                         Msg:      r.req,
140                         ReplyMsg: msg,
141                         IsMulti:  true,
142                 }
143                 resp := BinapiResponse{}
144
145                 err := r.rpc.Call("BinapiRPC.Invoke", req, &resp)
146                 if err != nil {
147                         return false, fmt.Errorf("RPC call failed: %v", err)
148                 }
149
150                 r.replies = resp.Msgs
151         }
152
153         if r.index >= len(r.replies) {
154                 return true, nil
155         }
156
157         // we set the value of msg to the value from response
158         reflect.ValueOf(msg).Elem().Set(reflect.ValueOf(r.replies[r.index]).Elem())
159         r.index++
160
161         return false, nil
162 }
163
164 func (b *BinapiClient) SubscribeNotification(notifChan chan api.Message, event api.Message) (api.SubscriptionCtx, error) {
165         panic("implement me")
166 }
167
168 func (b *BinapiClient) SetReplyTimeout(timeout time.Duration) {
169         panic("implement me")
170 }
171
172 func (b *BinapiClient) CheckCompatiblity(msgs ...api.Message) error {
173         return nil // TODO: proxy this
174 }
175
176 func (b *BinapiClient) Close() {
177         b.rpc.Close()
178 }