package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strconv"
"sync"
"github.com/go-telegram-bot-api/telegram-bot-api"
)
var flagPort = flag.String("port", "8008", "determined the port the sercice runs on")
var flagTgTokenFile = flag.String("tgtoken", "/run/secrets/tg_bot_token", "determines the location of the telegram bot token file")
var changelllyAPIKeyFile = flag.String("chapikey", "/run/secrets/ch_api_key", "determines the file that holds the changelly api key")
var alertFile = flag.String("alertfile", "/run/secrets/alerts", "determines the locaiton of the alert files")
var alertsCheckInterval = flag.Int64("alertinterval", 60., "in seconds, the amount of time between alert checks")
const cryptocomparePriceURL = "https://min-api.cryptocompare.com/data/price?"
const changellyURL = "https://api.changelly.com"
func getTgToken() string {
tgTokenJsonBytes, err := ioutil.ReadFile(*flagTgTokenFile)
if err != nil {
log.Fatal(err)
}
type TgToken struct {
Token string `json:"token"`
}
var tgToken TgToken
err = json.Unmarshal(tgTokenJsonBytes, &tgToken)
if err != nil {
log.Fatal(err)
}
return tgToken.Token
}
func runTgBot() {
botToken := getTgToken()
bot, err := tgbotapi.NewBotAPI(botToken)
if err != nil {
log.Panic(err)
}
bot.Debug = true
log.Printf("Authorized on account %s", bot.Self.UserName)
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
updates, err := bot.GetUpdatesChan(u)
if err != nil {
log.Panic(err)
}
for update := range updates {
if update.Message == nil {
continue
}
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
msg.ReplyToMessageID = update.Message.MessageID
bot.Send(msg)
}
}
type priceChanStruct struct {
name string
price float64
}
type errorChanStruct struct {
hasError bool
err error
}
func sendGetToCryptoCompare(
name, unit string,
wg *sync.WaitGroup,
priceChan chan<- priceChanStruct,
errChan chan<- errorChanStruct) {
defer wg.Done()
params := "fsym=" + url.QueryEscape(name) + "&" +
"tsyms=" + url.QueryEscape(unit)
path := cryptocomparePriceURL + params
fmt.Println(path)
resp, err := http.Get(path)
if err != nil {
priceChan <- priceChanStruct{name: name, price: 0.}
errChan <- errorChanStruct{hasError: true, err: err}
fmt.Println(err.Error())
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
priceChan <- priceChanStruct{name: name, price: 0.}
errChan <- errorChanStruct{hasError: true, err: err}
fmt.Println(err.Error())
}
jsonBody := make(map[string]float64)
err = json.Unmarshal(body, &jsonBody)
if err != nil {
priceChan <- priceChanStruct{name: name, price: 0.}
errChan <- errorChanStruct{hasError: true, err: err}
fmt.Println(err.Error())
}
fmt.Println(string(body))
//FIXME-blocks forever
priceChan <- priceChanStruct{name: name, price: jsonBody[unit]}
errChan <- errorChanStruct{hasError: false, err: nil}
fmt.Println("done and done")
}
//TODO
func healthHandler(w http.ResponseWriter, r *http.Request) {
}
func cryptoHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/crypto" {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
}
var name string
var unit string
params := r.URL.Query()
for key, value := range params {
switch key {
case "name":
name = value[0]
case "unit":
unit = value[0]
default:
log.Fatal("bad parameters for the crypto endpoint.")
}
}
var wg sync.WaitGroup
priceChan := make(chan priceChanStruct, 1)
errChan := make(chan errorChanStruct, 1)
defer close(errChan)
defer close(priceChan)
wg.Add(1)
go sendGetToCryptoCompare(name, unit, &wg, priceChan, errChan)
wg.Wait()
select {
case err := <-errChan:
if err.hasError != false {
log.Printf(err.err.Error())
}
default:
log.Fatal("this shouldnt have happened")
}
var price priceChanStruct
select {
case priceCh := <-priceChan:
price = priceCh
default:
log.Fatal("this shouldnt have happened")
}
json.NewEncoder(w).Encode(map[string]interface{}{"name": price.name, "price": price.price, "unit": unit})
}
func pairHandler(w http.ResponseWriter, r *http.Request) {
var err error
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
}
var one string
var two string
var multiplier float64
params := r.URL.Query()
for key, value := range params {
switch key {
case "one":
one = value[0]
case "two":
two = value[0]
case "multiplier":
multiplier, err = strconv.ParseFloat(value[0], 64)
if err != nil {
log.Fatal(err)
}
default:
log.Fatal("bad parameters for the pair endpoint.")
}
}
fmt.Println(one, two, multiplier)
var wg sync.WaitGroup
priceChan := make(chan priceChanStruct, 2)
errChan := make(chan errorChanStruct, 2)
defer close(priceChan)
defer close(errChan)
wg.Add(2)
go sendGetToCryptoCompare(one, "USD", &wg, priceChan, errChan)
go sendGetToCryptoCompare(two, "USD", &wg, priceChan, errChan)
wg.Wait()
fmt.Println("getting fucked here")
for i := 0; i < 2; i++ {
select {
case err := <-errChan:
if err.hasError != false {
log.Printf(err.err.Error())
}
default:
log.Fatal("this shouldnt have happened")
}
}
var priceOne float64
var priceTwo float64
for i := 0; i < 2; i++ {
select {
case price := <-priceChan:
if price.name == one {
priceOne = price.price
}
if price.name == two {
priceTwo = price.price
}
default:
log.Fatal("this shouldnt have happened")
}
}
ratio := priceOne * multiplier / priceTwo
fmt.Println(ratio)
json.NewEncoder(w).Encode(map[string]interface{}{"ratio": ratio})
}
func getAlerts() map[string]interface{} {
alertsBytes, err := ioutil.ReadFile(*flagTgTokenFile)
if err != nil {
log.Fatal(err)
return make(map[string]interface{})
}
alertsJson := make(map[string]interface{})
err = json.Unmarshal(alertsBytes, &alertsJson)
if err != nil {
log.Fatal(err)
return make(map[string]interface{})
}
return alertsJson
}
func alertManager() {
alerts := getAlerts()
fmt.Println(alerts)
}
func startServer() {
http.HandleFunc("/health", healthHandler)
http.HandleFunc("/crypto", cryptoHandler)
http.HandleFunc("/pair", pairHandler)
if err := http.ListenAndServe(":"+*flagPort, nil); err != nil {
log.Fatal(err)
}
}
func main() {
go runTgBot()
go alertManager()
startServer()
}