Implement getFile
This commit is contained in:
parent
b1a4d4a8c7
commit
c8ed6b77e9
7 changed files with 101 additions and 16 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ clessy-mods
|
||||||
clessy-stats
|
clessy-stats
|
||||||
clessy-stats-import
|
clessy-stats-import
|
||||||
stats-web/Chart.bundle.js
|
stats-web/Chart.bundle.js
|
||||||
|
impact.ttf
|
|
@ -1,13 +1,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/hamcha/clessy/tg"
|
"github.com/hamcha/clessy/tg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func executeClientCommand(action tg.ClientCommand) {
|
func executeClientCommand(action tg.ClientCommand, client net.Conn) {
|
||||||
switch action.Type {
|
switch action.Type {
|
||||||
case tg.CmdSendTextMessage:
|
case tg.CmdSendTextMessage:
|
||||||
data := *(action.TextMessageData)
|
data := *(action.TextMessageData)
|
||||||
api.SendTextMessage(data)
|
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))
|
log.Printf("%s\n", string(bytes))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
executeClientCommand(cmd)
|
executeClientCommand(cmd, c)
|
||||||
}
|
}
|
||||||
removeCon(c)
|
removeCon(c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -61,13 +65,77 @@ func (t Telegram) SendTextMessage(data tg.ClientTextMessageData) {
|
||||||
checkerr("SendTextMessage", err)
|
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 {
|
func (t Telegram) apiURL(method string) string {
|
||||||
return APIEndpoint + "bot" + t.Token + "/" + method
|
return APIEndpoint + "bot" + t.Token + "/" + method
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkerr(method string, err error) bool {
|
func checkerr(method string, err error) bool {
|
||||||
if err != nil {
|
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 true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -15,6 +15,7 @@ func initmods() {
|
||||||
func dispatch(broker *tg.Broker, update tg.APIMessage) {
|
func dispatch(broker *tg.Broker, update tg.APIMessage) {
|
||||||
metafora(broker, update)
|
metafora(broker, update)
|
||||||
viaggi(broker, update)
|
viaggi(broker, update)
|
||||||
|
memegen(broker, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isCommand(update tg.APIMessage, cmdname string) bool {
|
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.
|
// This function is asynchronous as data will be delivered to the given callback.
|
||||||
func (b *Broker) GetFile(fileID string, fn BrokerCallback) int {
|
func (b *Broker) GetFile(fileID string, fn BrokerCallback) int {
|
||||||
cid := b.RegisterCallback(fn)
|
cid := b.RegisterCallback(fn)
|
||||||
// Make file request
|
b.sendCmd(ClientCommand{
|
||||||
|
Type: CmdGetFile,
|
||||||
|
FileRequestData: &FileRequestData{
|
||||||
|
FileID: fileID,
|
||||||
|
},
|
||||||
|
Callback: &cid,
|
||||||
|
})
|
||||||
return cid
|
return cid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,18 @@ const (
|
||||||
|
|
||||||
// BFile is a file retrieval response update
|
// BFile is a file retrieval response update
|
||||||
BFile BrokerUpdateType = "file"
|
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
|
// BrokerUpdate is what is sent by the broker as update
|
||||||
type BrokerUpdate struct {
|
type BrokerUpdate struct {
|
||||||
Type BrokerUpdateType
|
Type BrokerUpdateType
|
||||||
Callback *int
|
Callback *int `json:",omitempty"`
|
||||||
Message *APIMessage
|
Error *string `json:",omitempty"`
|
||||||
Bytes *string
|
Message *APIMessage `json:",omitempty"`
|
||||||
|
Bytes *string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientCommandType distinguishes requests sent by clients to the broker
|
// ClientCommandType distinguishes requests sent by clients to the broker
|
||||||
|
@ -37,27 +41,27 @@ const (
|
||||||
type ClientTextMessageData struct {
|
type ClientTextMessageData struct {
|
||||||
ChatID int
|
ChatID int
|
||||||
Text string
|
Text string
|
||||||
ReplyID *int
|
ReplyID *int `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientPhotoData is the required data for a CmdSendPhoto request
|
// ClientPhotoData is the required data for a CmdSendPhoto request
|
||||||
type ClientPhotoData struct {
|
type ClientPhotoData struct {
|
||||||
ChatID int
|
ChatID int
|
||||||
Bytes string
|
Bytes string
|
||||||
Caption *string
|
Caption *string `json:",omitempty"`
|
||||||
ReplyID *int
|
ReplyID *int `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileRequestData is the required data for a CmdGetFile request
|
// FileRequestData is the required data for a CmdGetFile request
|
||||||
type FileRequestData struct {
|
type FileRequestData struct {
|
||||||
FileID int
|
FileID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientCommand is a request sent by clients to the broker
|
// ClientCommand is a request sent by clients to the broker
|
||||||
type ClientCommand struct {
|
type ClientCommand struct {
|
||||||
Type ClientCommandType
|
Type ClientCommandType
|
||||||
TextMessageData *ClientTextMessageData
|
TextMessageData *ClientTextMessageData `json:",omitempty"`
|
||||||
PhotoData *ClientPhotoData
|
PhotoData *ClientPhotoData `json:",omitempty"`
|
||||||
FileRequestData *FileRequestData
|
FileRequestData *FileRequestData `json:",omitempty"`
|
||||||
Callback *int
|
Callback *int `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue