diff --git a/cryptoexchanges/bittrex/bittrex.go b/cryptoexchanges/bittrex/bittrex.go new file mode 100644 index 00000000..d4f4eed4 --- /dev/null +++ b/cryptoexchanges/bittrex/bittrex.go @@ -0,0 +1,49 @@ +package bittrex + +type summaryList struct { + items []*fCurrency +} + +// fCurrency From Currency +type fCurrency struct { + name string + displayName string + to []*tCurrency +} + +// tCurrency To Currency +type tCurrency struct { + name string + summaryInfo +} + +type summaryInfo struct { + Low string + High string + Volume string + Last string + OpenSellOrders string + OpenBuyOrders string +} + +type summaryResponse struct { + Success bool `json:"success"` + Message string `json:"message"` + Result []struct { + MarketName string `json:"MarketName"` + High float64 `json:"High"` + Low float64 `json:"Low"` + Last float64 `json:"Last"` + Volume float64 `json:"Volume"` + OpenSellOrders int `json:"OpenSellOrders"` + OpenBuyOrders int `json:"OpenBuyOrders"` + } `json:"result"` +} + +func (list *summaryList) addSummaryItem(name, displayName string, toList []*tCurrency) { + list.items = append(list.items, &fCurrency{ + name: name, + displayName: displayName, + to: toList, + }) +} diff --git a/cryptoexchanges/bittrex/display.go b/cryptoexchanges/bittrex/display.go new file mode 100644 index 00000000..28c368e5 --- /dev/null +++ b/cryptoexchanges/bittrex/display.go @@ -0,0 +1,65 @@ +package bittrex + +import ( + "bytes" + "fmt" + "text/template" +) + +func (widget *Widget) display() { + if ok == false { + widget.View.SetText(fmt.Sprintf("%s", errorText)) + return + } + + str := "" + str += summaryText(&widget.summaryList, &widget.TextColors) + + widget.View.SetText(fmt.Sprintf("%s", str)) +} + +func summaryText(list *summaryList, colors *TextColors) string { + str := "" + + for _, fromCurrency := range list.items { + str += fmt.Sprintf("[%s]%s[%s](%s):\n", colors.base.displayName, fromCurrency.displayName, colors.base.name, fromCurrency.name) + + resultTemplate := template.New("bittrex") + + for _, toCurrency := range fromCurrency.to { + writer := new(bytes.Buffer) + strTemplate, _ := resultTemplate.Parse( + "\t[{{.nameColor}}]{{.mName}}\n" + + formatableText("High", "High") + + formatableText("Low", "Low") + + formatableText("Last", "Last") + + formatableText("Volume", "Volume") + + formatableText("OpenSellOrders", "OpenSellOrders") + + formatableText("OpenBuyOrders", "OpenBuyOrders"), + ) + + strTemplate.Execute(writer, map[string]string{ + "nameColor": colors.market.name, + "fieldColor": colors.market.field, + "valueColor": colors.market.value, + "mName": toCurrency.name, + "High": toCurrency.High, + "Low": toCurrency.Low, + "Last": toCurrency.Last, + "Volume": toCurrency.Volume, + "OpenSellOrders": toCurrency.OpenSellOrders, + "OpenBuyOrders": toCurrency.OpenBuyOrders, + }) + + str += writer.String() + } + + } + + return str + +} + +func formatableText(key, value string) string { + return fmt.Sprintf("\t\t[{{.fieldColor}}]%s: [{{.valueColor}}]{{.%s}}\n", key, value) +} diff --git a/cryptoexchanges/bittrex/widget.go b/cryptoexchanges/bittrex/widget.go new file mode 100644 index 00000000..9f5039dd --- /dev/null +++ b/cryptoexchanges/bittrex/widget.go @@ -0,0 +1,187 @@ +package bittrex + +import ( + "encoding/json" + "fmt" + "time" + + "net/http" + + "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" +) + +// Config is a pointer to the global config object +var Config *config.Config + +type TextColors struct { + base struct { + name string + displayName string + } + market struct { + name string + field string + value string + } +} + +var ok = true +var errorText = "" +var started = false +var baseURL = "https://bittrex.com/api/v1.1/public/getmarketsummary" + +// Widget define wtf widget to register widget later +type Widget struct { + wtf.TextWidget + summaryList + updateInterval int + TextColors +} + +// NewWidget Make new instance of widget +func NewWidget() *Widget { + + widget := Widget{ + TextWidget: wtf.NewTextWidget(" $ Bittrex ", "bittrex", false), + summaryList: summaryList{}, + updateInterval: Config.UInt("wtf.mods.bittrex.updateInterval", 10), + } + + started = false + ok = true + errorText = "" + + widget.config() + widget.setSummaryList() + + return &widget +} + +func (widget *Widget) config() { + widget.TextColors.base.name = Config.UString("wtf.mods.bittrex.colors.base.name", "red") + widget.TextColors.base.displayName = Config.UString("wtf.mods.bittrex.colors.base.displayName", "grey") + widget.TextColors.market.name = Config.UString("wtf.mods.bittrex.colors.market.name", "red") + widget.TextColors.market.field = Config.UString("wtf.mods.bittrex.colors.market.field", "coral") + widget.TextColors.market.value = Config.UString("wtf.mods.bittrex.colors.market.value", "white") +} + +func (widget *Widget) setSummaryList() { + sCurrencies, _ := Config.Map("wtf.mods.bittrex.summary") + for fromCurrencyName := range sCurrencies { + displayName, _ := Config.String("wtf.mods.bittrex.summary." + fromCurrencyName + ".displayName") + toCurrencyList := makeSummaryToList(fromCurrencyName) + widget.summaryList.addSummaryItem(fromCurrencyName, displayName, toCurrencyList) + } +} + +func makeSummaryToList(currencyName string) []*tCurrency { + tCurrencyList := []*tCurrency{} + + configToList, _ := Config.List("wtf.mods.bittrex.summary." + currencyName + ".market") + for _, toCurrencyName := range configToList { + tCurrencyList = append(tCurrencyList, makeToCurrency(toCurrencyName.(string))) + } + + return tCurrencyList +} + +func makeToCurrency(name string) *tCurrency { + return &tCurrency{ + name: name, + summaryInfo: summaryInfo{ + High: "-1", + Low: "-1", + Volume: "-1", + Last: "-1", + OpenBuyOrders: "-1", + OpenSellOrders: "-1", + }, + } +} + +/* -------------------- Exported Functions -------------------- */ + +// Refresh & update after interval time +func (widget *Widget) Refresh() { + if widget.Disabled() { + return + } + + if started == false { + go func() { + for { + widget.updateSummary() + time.Sleep(time.Second * time.Duration(widget.updateInterval)) + } + }() + started = true + } + + widget.UpdateRefreshedAt() + + widget.display() + +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *Widget) updateSummary() { + client := &http.Client{ + Timeout: time.Duration(5 * time.Second), + } + + for _, fromCurrency := range widget.summaryList.items { + for _, toCurrency := range fromCurrency.to { + request := makeRequest(fromCurrency.name, toCurrency.name) + response, err := client.Do(request) + + if err != nil { + ok = false + errorText = "Please Check Your Internet Connection!" + break + } else { + ok = true + errorText = "" + } + + if response.StatusCode != http.StatusOK { + errorText = response.Status + ok = false + break + } else { + ok = true + errorText = "" + } + + defer response.Body.Close() + jsonResponse := summaryResponse{} + decoder := json.NewDecoder(response.Body) + decoder.Decode(&jsonResponse) + + if !jsonResponse.Success { + ok = false + errorText = fmt.Sprintf("%s-%s: %s", fromCurrency.name, toCurrency.name, jsonResponse.Message) + break + } + ok = true + errorText = "" + + toCurrency.Last = fmt.Sprintf("%f", jsonResponse.Result[0].Last) + toCurrency.High = fmt.Sprintf("%f", jsonResponse.Result[0].High) + toCurrency.Low = fmt.Sprintf("%f", jsonResponse.Result[0].Low) + toCurrency.Volume = fmt.Sprintf("%f", jsonResponse.Result[0].Volume) + toCurrency.OpenBuyOrders = fmt.Sprintf("%d", jsonResponse.Result[0].OpenBuyOrders) + toCurrency.OpenSellOrders = fmt.Sprintf("%d", jsonResponse.Result[0].OpenSellOrders) + } + } + + widget.display() +} + +func makeRequest(fName, tName string) *http.Request { + url := fmt.Sprintf("%s?market=%s-%s", baseURL, fName, tName) + request, _ := http.NewRequest("GET", url, nil) + + return request +} diff --git a/wtf.go b/wtf.go index a7c70b4c..660e458c 100644 --- a/wtf.go +++ b/wtf.go @@ -13,6 +13,7 @@ import ( "github.com/senorprogrammer/wtf/bamboohr" "github.com/senorprogrammer/wtf/clocks" "github.com/senorprogrammer/wtf/cmdrunner" + "github.com/senorprogrammer/wtf/cryptoexchanges/bittrex" "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" "github.com/senorprogrammer/wtf/gcal" "github.com/senorprogrammer/wtf/git"