Repository navigation
Expand file tree
/
Copy pathconnector.go
More file actions
executable file
·117 lines (88 loc) · 2.77 KB
/
Copy pathconnector.go
File metadata and controls
executable file
·117 lines (88 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package govpp
import (
"os"
log "github.com/Sirupsen/logrus"
"github.com/fdio-stack/govpp/api"
)
// Connection wraps a shared memory connection to VPP via VppAdapter.
type Connection struct {
vpp VppAdapter
clients map[uint32]*api.Channel
maxClientId uint32
encoder *BinaryEncoder
}
var conn *Connection // global handle to Connection used in the callback
func Connect() *Connection {
adapter := &PneumVppAdapter{}
return connectWithAdapter(adapter)
}
func connectWithAdapter(vppAdapter VppAdapter) *Connection {
// TODO: move logger to connection / channel?
log.SetOutput(os.Stdout)
log.SetLevel(log.DebugLevel)
c := &Connection{vpp: vppAdapter, encoder: &BinaryEncoder{}}
c.clients = make(map[uint32]*api.Channel)
c.vpp.SetMsgRecvCallback(msgRecvCb)
c.vpp.Connect() // TODO: errcheck, wait in loop
conn = c // TODO: allow only one connection, make this thread-safe
return c
}
func (c *Connection) Disconnect() {
c.vpp.Disconnect()
}
func (c *Connection) NewApiChannel() *api.Channel {
ch := &api.Channel{}
// TODO: atomic
c.maxClientId++
ch.ID = c.maxClientId
//ch.ID = uint32(unsafe.Pointer(&ch)) // TODO: generate ID from pointer, remove ID from channel structure
ch.ReqChan = make(chan *api.VppRequest)
ch.ReplyChan = make(chan *api.VppReply)
ch.Decoder = c.encoder
// TODO: lock
c.clients[ch.ID] = ch
go c.watchRequests(ch)
return ch
}
func msgRecvCb(context uint32, msgId uint16, data []byte) {
log.WithFields(log.Fields{
"Connection": context,
"msg_id": msgId,
"msg_size": len(data),
}).Debug("Received a message from VPP.")
// match client according to the Connection
// TODO: lock
client, ok := conn.clients[context]
if ok {
// send the data to he client
client.ReplyChan <- &api.VppReply{MessageId: uint16(msgId), Data: data, LastPart: true} // TODO: proper multipart handling
} else {
log.WithFields(log.Fields{
"Connection": context,
"msg_id": msgId,
}).Error("Channel Connection not known, ignoring the message.")
}
}
func (c *Connection) releaseClient(cl *api.Channel) {
log.WithFields(log.Fields{
"Connection": cl.ID,
}).Debug("Channel disconnected.")
// TODO: remove the client from client map
}
func (c *Connection) watchRequests(cl *api.Channel) {
for req := range cl.ReqChan {
msgId := c.getMsgId(req.Message.GetMessageName(), req.Message.GetCrcString())
data, _ := c.encoder.EncodeMsg(req.Message, msgId) // TODO: handle error
log.WithFields(log.Fields{
"Connection": cl.ID,
"msg_id": msgId,
"msg_size": len(data),
}).Debug("Sending a message to VPP.")
c.vpp.SendMsg(cl.ID, data)
}
// after closing the channel, release the client
c.releaseClient(cl)
}
func (c *Connection) getMsgId(msgName string, msgCrc string) uint16 {
return c.vpp.GetMsgId(msgName, msgCrc)
}