Implement getFile

This commit is contained in:
Hamcha 2016-02-20 21:40:24 +01:00
parent b1a4d4a8c7
commit c8ed6b77e9
7 changed files with 101 additions and 16 deletions

3
.gitignore vendored
View file

@ -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

View file

@ -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)
}
}

View file

@ -45,7 +45,7 @@ func handleClient(c net.Conn) {
log.Printf("%s\n", string(bytes))
continue
}
executeClientCommand(cmd)
executeClientCommand(cmd, c)
}
removeCon(c)
}

View file

@ -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

View file

@ -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 {

View file

@ -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
}

View file

@ -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"`
}