Implement getFile
This commit is contained in:
parent
b1a4d4a8c7
commit
c8ed6b77e9
7 changed files with 101 additions and 16 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,4 +4,5 @@ clessy-broker
|
|||
clessy-mods
|
||||
clessy-stats
|
||||
clessy-stats-import
|
||||
stats-web/Chart.bundle.js
|
||||
stats-web/Chart.bundle.js
|
||||
impact.ttf
|
|
@ -1,13 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/hamcha/clessy/tg"
|
||||
)
|
||||
|
||||
func executeClientCommand(action tg.ClientCommand) {
|
||||
func executeClientCommand(action tg.ClientCommand, client net.Conn) {
|
||||
switch action.Type {
|
||||
case tg.CmdSendTextMessage:
|
||||
data := *(action.TextMessageData)
|
||||
api.SendTextMessage(data)
|
||||
case tg.CmdGetFile:
|
||||
data := *(action.FileRequestData)
|
||||
api.GetFile(data, client, *action.Callback)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func handleClient(c net.Conn) {
|
|||
log.Printf("%s\n", string(bytes))
|
||||
continue
|
||||
}
|
||||
executeClientCommand(cmd)
|
||||
executeClientCommand(cmd, c)
|
||||
}
|
||||
removeCon(c)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
@ -61,13 +65,77 @@ func (t Telegram) SendTextMessage(data tg.ClientTextMessageData) {
|
|||
checkerr("SendTextMessage", err)
|
||||
}
|
||||
|
||||
// GetFile sends a "getFile" API call to Telegram's servers and fetches the file
|
||||
// specified afterward. The file will be then send back to the client that requested it
|
||||
// with the specified callback id.
|
||||
func (t Telegram) GetFile(data tg.FileRequestData, client net.Conn, callback int) {
|
||||
fail := func(msg string) {
|
||||
errmsg, _ := json.Marshal(tg.BrokerUpdate{
|
||||
Type: tg.BError,
|
||||
Error: &msg,
|
||||
Callback: &callback,
|
||||
})
|
||||
fmt.Fprintln(client, string(errmsg))
|
||||
}
|
||||
|
||||
postdata := url.Values{
|
||||
"file_id": {data.FileID},
|
||||
}
|
||||
resp, err := http.PostForm(t.apiURL("getFile"), postdata)
|
||||
if checkerr("GetFile/post", err) {
|
||||
fail("Server didn't like my request")
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var filespecs tg.APIFile
|
||||
err = json.NewDecoder(resp.Body).Decode(&filespecs)
|
||||
if checkerr("GetFile/json.Decode", err) {
|
||||
fail("Server sent garbage (or error)")
|
||||
return
|
||||
}
|
||||
|
||||
path := "https://api.telegram.org/file/bot" + t.Token + "/" + *filespecs.Path
|
||||
fileresp, err := http.Get(path)
|
||||
if checkerr("GetFile/get", err) {
|
||||
fail("Could not retrieve file from Telegram's servers")
|
||||
return
|
||||
}
|
||||
defer fileresp.Body.Close()
|
||||
|
||||
rawdata, err := ioutil.ReadAll(fileresp.Body)
|
||||
if checkerr("GetFile/ioutil.ReadAll", err) {
|
||||
fail("Could not read file data")
|
||||
return
|
||||
}
|
||||
|
||||
rawlen := len(rawdata)
|
||||
if rawlen != *filespecs.Size {
|
||||
// ???
|
||||
log.Printf("[GetFile] WARN ?? Downloaded file does not match provided filesize: %d != %d\n", rawlen, *filespecs.Size)
|
||||
}
|
||||
b64data := base64.StdEncoding.EncodeToString(rawdata)
|
||||
|
||||
clientmsg, err := json.Marshal(tg.BrokerUpdate{
|
||||
Type: tg.BFile,
|
||||
Bytes: &b64data,
|
||||
Callback: &callback,
|
||||
})
|
||||
if checkerr("GetFile/json.Marshal", err) {
|
||||
fail("Could not serialize reply JSON")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(client, string(clientmsg))
|
||||
}
|
||||
|
||||
func (t Telegram) apiURL(method string) string {
|
||||
return APIEndpoint + "bot" + t.Token + "/" + method
|
||||
}
|
||||
|
||||
func checkerr(method string, err error) bool {
|
||||
if err != nil {
|
||||
log.Printf("Received error with call to %s: %s\n", method, err.Error())
|
||||
log.Printf("[%s] Error: %s\n", method, err.Error())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -15,6 +15,7 @@ func initmods() {
|
|||
func dispatch(broker *tg.Broker, update tg.APIMessage) {
|
||||
metafora(broker, update)
|
||||
viaggi(broker, update)
|
||||
memegen(broker, update)
|
||||
}
|
||||
|
||||
func isCommand(update tg.APIMessage, cmdname string) bool {
|
||||
|
|
|
@ -66,7 +66,13 @@ func (b *Broker) SendPhoto(chat *APIChat, data []byte, caption *string, original
|
|||
// 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)
|
||||
// Make file request
|
||||
b.sendCmd(ClientCommand{
|
||||
Type: CmdGetFile,
|
||||
FileRequestData: &FileRequestData{
|
||||
FileID: fileID,
|
||||
},
|
||||
Callback: &cid,
|
||||
})
|
||||
return cid
|
||||
}
|
||||
|
||||
|
|
|
@ -9,14 +9,18 @@ const (
|
|||
|
||||
// BFile is a file retrieval response update
|
||||
BFile BrokerUpdateType = "file"
|
||||
|
||||
// BError is an error the broker occurred while fulfilling a request
|
||||
BError BrokerUpdateType = "error"
|
||||
)
|
||||
|
||||
// BrokerUpdate is what is sent by the broker as update
|
||||
type BrokerUpdate struct {
|
||||
Type BrokerUpdateType
|
||||
Callback *int
|
||||
Message *APIMessage
|
||||
Bytes *string
|
||||
Callback *int `json:",omitempty"`
|
||||
Error *string `json:",omitempty"`
|
||||
Message *APIMessage `json:",omitempty"`
|
||||
Bytes *string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ClientCommandType distinguishes requests sent by clients to the broker
|
||||
|
@ -37,27 +41,27 @@ const (
|
|||
type ClientTextMessageData struct {
|
||||
ChatID int
|
||||
Text string
|
||||
ReplyID *int
|
||||
ReplyID *int `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ClientPhotoData is the required data for a CmdSendPhoto request
|
||||
type ClientPhotoData struct {
|
||||
ChatID int
|
||||
Bytes string
|
||||
Caption *string
|
||||
ReplyID *int
|
||||
Caption *string `json:",omitempty"`
|
||||
ReplyID *int `json:",omitempty"`
|
||||
}
|
||||
|
||||
// FileRequestData is the required data for a CmdGetFile request
|
||||
type FileRequestData struct {
|
||||
FileID int
|
||||
FileID string
|
||||
}
|
||||
|
||||
// ClientCommand is a request sent by clients to the broker
|
||||
type ClientCommand struct {
|
||||
Type ClientCommandType
|
||||
TextMessageData *ClientTextMessageData
|
||||
PhotoData *ClientPhotoData
|
||||
FileRequestData *FileRequestData
|
||||
Callback *int
|
||||
TextMessageData *ClientTextMessageData `json:",omitempty"`
|
||||
PhotoData *ClientPhotoData `json:",omitempty"`
|
||||
FileRequestData *FileRequestData `json:",omitempty"`
|
||||
Callback *int `json:",omitempty"`
|
||||
}
|
||||
|
|
Reference in a new issue