2016-02-09 10:01:05 +00:00
|
|
|
package tg
|
|
|
|
|
|
|
|
import (
|
2016-02-19 16:54:25 +00:00
|
|
|
"encoding/base64"
|
2016-02-09 10:01:05 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
2016-02-19 11:20:13 +00:00
|
|
|
// Broker is a broker connection handler with callback management functions
|
2016-02-09 10:01:05 +00:00
|
|
|
type Broker struct {
|
2016-02-19 11:20:13 +00:00
|
|
|
Socket net.Conn
|
|
|
|
Callbacks []BrokerCallback
|
|
|
|
|
|
|
|
cbFree int
|
2016-02-09 10:01:05 +00:00
|
|
|
}
|
|
|
|
|
2016-02-19 11:20:13 +00:00
|
|
|
// ConnectToBroker creates a Broker connection
|
2016-02-09 10:01:05 +00:00
|
|
|
func ConnectToBroker(brokerAddr string) (*Broker, error) {
|
|
|
|
sock, err := net.Dial("tcp", brokerAddr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
broker := new(Broker)
|
|
|
|
broker.Socket = sock
|
2016-02-19 11:20:13 +00:00
|
|
|
broker.Callbacks = make([]BrokerCallback, 0)
|
|
|
|
broker.cbFree = 0
|
2016-02-09 10:01:05 +00:00
|
|
|
return broker, nil
|
|
|
|
}
|
|
|
|
|
2016-02-19 11:20:13 +00:00
|
|
|
// Close closes a broker connection
|
2016-02-09 10:01:05 +00:00
|
|
|
func (b *Broker) Close() {
|
|
|
|
b.Socket.Close()
|
|
|
|
}
|
|
|
|
|
2016-02-19 16:59:36 +00:00
|
|
|
// SendTextMessage sends a HTML-styles text message to a chat.
|
2016-02-19 11:25:38 +00:00
|
|
|
// A reply_to message ID can be specified as optional parameter.
|
2016-02-09 10:33:38 +00:00
|
|
|
func (b *Broker) SendTextMessage(chat *APIChat, text string, original *int) {
|
2016-02-19 18:25:28 +00:00
|
|
|
b.sendCmd(ClientCommand{
|
2016-02-09 10:01:05 +00:00
|
|
|
Type: CmdSendTextMessage,
|
|
|
|
TextMessageData: &ClientTextMessageData{
|
2016-02-09 10:33:38 +00:00
|
|
|
Text: text,
|
|
|
|
ChatID: chat.ChatID,
|
|
|
|
ReplyID: original,
|
2016-02-09 10:01:05 +00:00
|
|
|
},
|
2016-02-19 16:59:36 +00:00
|
|
|
})
|
2016-02-09 10:01:05 +00:00
|
|
|
}
|
2016-02-19 11:20:13 +00:00
|
|
|
|
2016-02-19 16:59:36 +00:00
|
|
|
// SendPhoto sends a photo with an optional caption to a chat.
|
2016-02-19 16:54:25 +00:00
|
|
|
// A reply_to message ID can be specified as optional parameter.
|
2016-02-20 21:49:50 +00:00
|
|
|
func (b *Broker) SendPhoto(chat *APIChat, data []byte, filename string, caption *string, original *int) {
|
2016-02-19 18:25:28 +00:00
|
|
|
b.sendCmd(ClientCommand{
|
2016-02-19 16:54:25 +00:00
|
|
|
Type: CmdSendPhoto,
|
|
|
|
PhotoData: &ClientPhotoData{
|
2016-02-20 21:49:50 +00:00
|
|
|
ChatID: chat.ChatID,
|
|
|
|
Filename: filename,
|
|
|
|
Bytes: base64.StdEncoding.EncodeToString(data),
|
|
|
|
Caption: caption,
|
|
|
|
ReplyID: original,
|
2016-02-19 16:54:25 +00:00
|
|
|
},
|
2016-02-19 16:59:36 +00:00
|
|
|
})
|
2016-02-19 16:54:25 +00:00
|
|
|
}
|
|
|
|
|
2016-02-19 11:25:38 +00:00
|
|
|
// GetFile sends a file retrieval request to the Broker.
|
|
|
|
// This function is asynchronous as data will be delivered to the given callback.
|
2016-02-19 11:20:13 +00:00
|
|
|
func (b *Broker) GetFile(fileID string, fn BrokerCallback) int {
|
|
|
|
cid := b.RegisterCallback(fn)
|
2016-02-20 20:40:24 +00:00
|
|
|
b.sendCmd(ClientCommand{
|
|
|
|
Type: CmdGetFile,
|
|
|
|
FileRequestData: &FileRequestData{
|
|
|
|
FileID: fileID,
|
|
|
|
},
|
|
|
|
Callback: &cid,
|
|
|
|
})
|
2016-02-19 11:20:13 +00:00
|
|
|
return cid
|
|
|
|
}
|
|
|
|
|
2016-02-19 11:25:38 +00:00
|
|
|
// RegisterCallback assigns a callback ID to the given callback and puts it on the callback list.
|
|
|
|
// This function should never be called by clients.
|
2016-02-19 11:20:13 +00:00
|
|
|
func (b *Broker) RegisterCallback(fn BrokerCallback) int {
|
|
|
|
cblen := len(b.Callbacks)
|
|
|
|
// List is full, append to end
|
|
|
|
if b.cbFree == cblen {
|
|
|
|
b.Callbacks = append(b.Callbacks, fn)
|
|
|
|
b.cbFree++
|
|
|
|
return cblen
|
|
|
|
}
|
|
|
|
// List is not full, use empty slot and find next one
|
|
|
|
id := b.cbFree
|
|
|
|
b.Callbacks[id] = fn
|
|
|
|
next := b.cbFree + 1
|
|
|
|
for ; next < cblen; next++ {
|
|
|
|
if b.Callbacks[next] == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b.cbFree = next
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
2016-02-19 11:25:38 +00:00
|
|
|
// RemoveCallback removes a callback from the callback list by ID.
|
|
|
|
// This function should never be called by clients.
|
2016-02-19 11:20:13 +00:00
|
|
|
func (b *Broker) RemoveCallback(id int) {
|
|
|
|
b.Callbacks[id] = nil
|
|
|
|
if id < b.cbFree {
|
|
|
|
b.cbFree = id
|
|
|
|
}
|
|
|
|
b.resizeCbArray()
|
|
|
|
}
|
|
|
|
|
2016-02-19 11:25:38 +00:00
|
|
|
// SpliceCallback retrieves a callback by ID and removes it from the list.
|
|
|
|
// This function should never be called by clients.
|
2016-02-19 11:20:13 +00:00
|
|
|
func (b *Broker) SpliceCallback(id int) BrokerCallback {
|
|
|
|
defer b.RemoveCallback(id)
|
|
|
|
return b.Callbacks[id]
|
|
|
|
}
|
|
|
|
|
2016-02-19 16:59:36 +00:00
|
|
|
func (b *Broker) sendCmd(cmd ClientCommand) {
|
|
|
|
data, err := json.Marshal(cmd)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[sendCmd] JSON Encode error: %s\n", err.Error())
|
|
|
|
}
|
|
|
|
fmt.Fprintln(b.Socket, string(data))
|
|
|
|
}
|
|
|
|
|
2016-02-19 11:20:13 +00:00
|
|
|
func (b *Broker) resizeCbArray() {
|
|
|
|
var i int
|
|
|
|
cut := false
|
|
|
|
for i = len(b.Callbacks); i > 0; i-- {
|
|
|
|
if b.Callbacks[i-1] != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
cut = true
|
|
|
|
}
|
|
|
|
if cut {
|
|
|
|
b.Callbacks = b.Callbacks[0:i]
|
|
|
|
if b.cbFree > i {
|
|
|
|
b.cbFree = i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|