3 changed files with 123 additions and 0 deletions
@ -0,0 +1,94 @@ |
|||||||
|
package cmd |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"io/ioutil" |
||||||
|
"net/http" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
"unicode" |
||||||
|
|
||||||
|
"github.com/kf5grd/keybasebot" |
||||||
|
"github.com/teris-io/shortid" |
||||||
|
"samhofi.us/x/keybase/v2/types/chat1" |
||||||
|
) |
||||||
|
|
||||||
|
var ConvertAd = chat1.UserBotCommandInput{ |
||||||
|
Name: "convert", |
||||||
|
Usage: "<currency> to <currency>", |
||||||
|
Description: "Converts between many crypto and fiat currencies. Try !convert 50 USD to XLM", |
||||||
|
} |
||||||
|
|
||||||
|
func Convert(m chat1.MsgSummary, b *keybasebot.Bot) (bool, error) { |
||||||
|
fields := strings.Fields(strings.TrimSpace(strings.Replace(m.Content.Text.Body, "!convert", "", 1))) |
||||||
|
|
||||||
|
// first pass filters
|
||||||
|
if fields == nil || len(fields) != 4 || fields[2] != "to" { |
||||||
|
return true, fmt.Errorf("@%s - Invalid Request.", m.Sender.Username) |
||||||
|
} |
||||||
|
|
||||||
|
// get the arguments
|
||||||
|
lhq := fields[0] |
||||||
|
lhc := strings.ToUpper(fields[1]) |
||||||
|
rhc := strings.ToUpper(fields[3]) |
||||||
|
|
||||||
|
// validate the args
|
||||||
|
leftQuantity, err := strconv.ParseFloat(lhq, 64) |
||||||
|
if err != nil { |
||||||
|
return true, fmt.Errorf("@%s - Unable to parse %s into a number", m.Sender.Username, lhq) |
||||||
|
} |
||||||
|
if !isAlpha(lhc) || !isAlpha(rhc) { |
||||||
|
return true, fmt.Errorf("@%s - Only letters are allowed in currency symbols", m.Sender.Username) |
||||||
|
} |
||||||
|
rate, err := getConversion(lhc, rhc) |
||||||
|
if err != nil { |
||||||
|
eid := shortid.MustGenerate() |
||||||
|
b.Logger.Error("%s: %+v", eid, err) |
||||||
|
b.KB.ReactByConvID(m.ConvID, m.Id, "Error: %s", eid) |
||||||
|
return true, nil |
||||||
|
} |
||||||
|
rhq := leftQuantity * rate |
||||||
|
b.KB.ReactByConvID(m.ConvID, m.Id, fmt.Sprintf("%.4f %s", rhq, rhc)) |
||||||
|
return true, nil |
||||||
|
} |
||||||
|
|
||||||
|
func getConversion(lhc string, rhc string) (float64, error) { |
||||||
|
client := &http.Client{} |
||||||
|
target := fmt.Sprintf("https://api.cryptonator.com/api/ticker/%s-%s", lhc, rhc) |
||||||
|
req, err := http.NewRequest("GET", target, nil) |
||||||
|
if err != nil { |
||||||
|
return 0.0, err |
||||||
|
} |
||||||
|
req.Header.Set("User-Agent", "GoLang Currency Bot ssh0le/0.99") |
||||||
|
resp, err := client.Do(req) |
||||||
|
if err != nil { |
||||||
|
return 0.0, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
body, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return 0.0, err |
||||||
|
} |
||||||
|
var apiResponse CryptApiResponse |
||||||
|
if err := json.Unmarshal(body, &apiResponse); err != nil { |
||||||
|
return 0.0, err |
||||||
|
} |
||||||
|
if !apiResponse.Success { |
||||||
|
return 0.0, fmt.Errorf(apiResponse.Error) |
||||||
|
} |
||||||
|
result, err := strconv.ParseFloat(apiResponse.Ticker.Price, 64) |
||||||
|
if err != nil { |
||||||
|
return 0.0, err |
||||||
|
} |
||||||
|
return result, nil |
||||||
|
} |
||||||
|
|
||||||
|
func isAlpha(s string) bool { |
||||||
|
for _, letter := range s { |
||||||
|
if !unicode.IsLetter(letter) { |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package cmd |
||||||
|
|
||||||
|
// CryptApiResponse hold a response for currency conversions, used in !convert
|
||||||
|
type CryptApiResponse struct { |
||||||
|
Ticker CryptonatorRate `json:"ticker"` |
||||||
|
Timestamp int `json:"timestamp"` |
||||||
|
Success bool `json:"success"` |
||||||
|
Error string `json:"error"` |
||||||
|
} |
||||||
|
|
||||||
|
type CryptonatorRate struct { |
||||||
|
Base string `json:"base"` |
||||||
|
Target string `json:"target"` |
||||||
|
Price string `json:"price"` |
||||||
|
Volume string `json:"volume"` |
||||||
|
Change string `json:"change"` |
||||||
|
Markets []CryptonatorMarket `json:"markets,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
type CryptonatorMarket struct { |
||||||
|
Market string `json:"market"` |
||||||
|
Price string `json:"price"` |
||||||
|
Volume float64 `json:"volume"` |
||||||
|
} |
Loading…
Reference in new issue