-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
channel.go
139 lines (115 loc) · 3.34 KB
/
channel.go
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2021-22 Kirill Scherba <[email protected]>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Teonet channel module
package teonet
import (
"bytes"
"strings"
"time"
"github.com/teonet-go/tru"
)
const (
newChannelPrefix = "new-"
newConnectionPrefix = "conn-"
addressLen = 35
)
// Channel stract and method receiver
type Channel struct {
a string // Teonet address
c *tru.Channel // TRU channel
// Channel closed by CloseTo function, or reconnection set off by
// ReconnectOff function
closing bool
}
// new create new teonet channel
func (c *channels) new(channel *tru.Channel) *Channel {
address := newChannelPrefix + tru.RandomString(addressLen-len(newChannelPrefix))
return &Channel{address, channel, false}
}
// Channel get teonet channel by address
func (teo Teonet) Channel(addr string) (ch *Channel, exists bool) {
return teo.channels.get(addr)
}
// Channel get teonet channel by ip address
func (teo Teonet) ChannelByIP(addr string) (ch *Channel, exists bool) {
return teo.channels.getByIP(addr)
}
// ServerMode return true if channel in server mode
func (c Channel) ServerMode() bool {
return c.c.ServerMode()
}
// ClientMode return true if channel in client mode
func (c Channel) ClientMode() bool {
return !c.c.ServerMode()
}
// Triptime return channels triptime
func (c Channel) Triptime() time.Duration {
return c.c.Triptime()
}
// Send data to channel
func (c Channel) Send(data []byte, attr ...interface{}) (id int, err error) {
var delivery = c.checkSendAttr(attr...)
return c.c.WriteTo(data, delivery)
}
// checkSendAttr check Send function attributes:
// return delevery callback 'func(p *tru.Packet, err error)' and make
// subscribe to answer with callback 'func(c *Channel, p *Packet, e *Event) bool'
func (c Channel) checkSendAttr(attr ...interface{}) (delivery func(p *tru.Packet, err error)) {
var teo *Teonet
for i := range attr {
switch v := attr[i].(type) {
// Packet delivery callback
case func(p *tru.Packet, err error):
delivery = v
// Teonet
case *Teonet:
teo = v
// Answer callback
case func(c *Channel, p *Packet, e *Event) bool:
if teo != nil {
c.subscribeToAnswer(teo, v)
}
default:
log.Error.Printf("wrong type in send attribute: %T\n", v)
}
}
return
}
// subscribeToAnswer subscribe to channel answer
func (c Channel) subscribeToAnswer(teo *Teonet, f func(c *Channel, p *Packet, e *Event) bool) (scr *subscribeData, err error) {
scr, err = teo.Subscribe(c.a, func(c *Channel, p *Packet, e *Event) bool {
if f(c, p, e) {
teo.Unsubscribe(scr)
return true
}
return false
})
if err != nil {
return
}
return
}
// String is channel stringify and return string with channel address
func (c Channel) String() string {
if c.a == "" {
return c.c.Addr().String()
}
return c.a
}
// Address eturn string with channel address
func (c Channel) Address() string {
return c.a
}
// Channel return return poiner to tru channel
func (c Channel) Channel() *tru.Channel {
return c.c
}
// IsNew return true if channel has 'new' prefix
func (c Channel) IsNew() bool {
return strings.HasPrefix(c.Address(), newChannelPrefix)
}
// IsConn return true if channel has 'connect' prefix
func (c Channel) IsConn(data []byte) bool {
return bytes.HasPrefix(data, []byte(newConnectionPrefix))
}