This repository has been archived on 2023-07-05. You can view files and clone it, but cannot push or open issues or pull requests.
clessy/tg/broker.go

167 lines
3.9 KiB
Go
Raw Normal View History

2016-02-09 10:01:05 +00:00
package tg
import (
"encoding/base64"
2016-02-09 10:01:05 +00:00
"encoding/json"
"fmt"
"log"
"net"
)
// Broker is a broker connection handler with callback management functions
2016-02-09 10:01:05 +00:00
type Broker struct {
Socket net.Conn
Callbacks []BrokerCallback
cbFree int
2016-02-09 10:01:05 +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
broker.Callbacks = make([]BrokerCallback, 0)
broker.cbFree = 0
2016-02-09 10:01:05 +00:00
return broker, nil
}
// 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.
// A reply_to message ID can be specified as optional parameter.
2016-09-01 12:05:32 +00:00
func (b *Broker) SendTextMessage(chat *APIChat, text string, original *int64) {
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 16:59:36 +00:00
// SendPhoto sends a photo with an optional caption to a chat.
// A reply_to message ID can be specified as optional parameter.
2016-09-01 12:05:32 +00:00
func (b *Broker) SendPhoto(chat *APIChat, data []byte, filename string, caption string, original *int64) {
2016-02-19 18:25:28 +00:00
b.sendCmd(ClientCommand{
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:59:36 +00:00
})
}
// ForwardMessage forwards a message between chats.
func (b *Broker) ForwardMessage(chat *APIChat, message APIMessage) {
b.sendCmd(ClientCommand{
Type: CmdForwardMessage,
ForwardMessageData: &ClientForwardMessageData{
ChatID: chat.ChatID,
FromChatID: message.Chat.ChatID,
MessageID: message.MessageID,
},
})
}
// SendChatAction sets a chat action for 5 seconds or less (canceled at first message sent)
func (b *Broker) SendChatAction(chat *APIChat, action ChatAction) {
b.sendCmd(ClientCommand{
Type: CmdSendChatAction,
ChatActionData: &ClientChatActionData{
ChatID: chat.ChatID,
Action: action,
},
})
}
// GetFile sends a file retrieval request to the Broker.
// This function is asynchronous as data will be delivered to the given callback.
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,
})
return cid
}
// RegisterCallback assigns a callback ID to the given callback and puts it on the callback list.
// This function should never be called by clients.
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
}
// RemoveCallback removes a callback from the callback list by ID.
// This function should never be called by clients.
func (b *Broker) RemoveCallback(id int) {
b.Callbacks[id] = nil
if id < b.cbFree {
b.cbFree = id
}
b.resizeCbArray()
}
// SpliceCallback retrieves a callback by ID and removes it from the list.
// This function should never be called by clients.
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))
}
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
}
}
}