From 28f34c2d4921356dfe606639ea34f641284d7322 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Tue, 29 May 2018 15:53:45 +0430 Subject: [PATCH 01/11] made cryptolive module --- cryptolive/cryptolive.go | 44 +++++++++++++ cryptolive/widget.go | 133 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 cryptolive/cryptolive.go create mode 100644 cryptolive/widget.go diff --git a/cryptolive/cryptolive.go b/cryptolive/cryptolive.go new file mode 100644 index 00000000..adc99660 --- /dev/null +++ b/cryptolive/cryptolive.go @@ -0,0 +1,44 @@ +package cryptolive + +type list struct { + items []*fromCurrency +} + +type fromCurrency struct { + name string + displayName string + to []*toCurrency +} + +type toCurrency struct { + name string + price float32 +} + +type cResponse struct { + BTC float32 `json:"BTC"` + HBZ float32 `json:"HBZ"` + ETH float32 `json:"ETH"` + EOS float32 `json:"EOS"` + BCH float32 `json:"BCH"` + TRX float32 `json:"TRX"` + XRP float32 `json:"XRP"` + LTC float32 `json:"LTC"` + ETC float32 `json:"ETC"` + ADA float32 `json:"ADA"` + CMT float32 `json:"CMT"` + DASH float32 `json:"DASH"` + ZEC float32 `json:"ZEC"` + IOT float32 `json:"IOT"` + ONT float32 `json:"ONT"` + NEO float32 `json:"NEO"` + BTG float32 `json:"BTG"` + LSK float32 `json:"LSK"` + ELA float32 `json:"ELA"` + DTA float32 `json:"DTA"` + NANO float32 `json:"NANO"` + WTC float32 `json:"WTC"` + DOGE float32 `json:"DOGE"` + USD float32 `json:"USD"` + EUR float32 `json:"EUR"` +} diff --git a/cryptolive/widget.go b/cryptolive/widget.go new file mode 100644 index 00000000..8ddf2408 --- /dev/null +++ b/cryptolive/widget.go @@ -0,0 +1,133 @@ +package cryptolive + +import ( + "fmt" + "time" + + "github.com/cizixs/gohttp" + + "reflect" + + "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" +) + +// Config is a pointer to the global config object +var Config *config.Config + +var started = false + +// Widget define wtf widget to register widget later +type Widget struct { + wtf.TextWidget + + CurrentIcon int + + *list +} + +// NewWidget Make new instance of widget +func NewWidget() *Widget { + started = false + widget := Widget{ + TextWidget: wtf.NewTextWidget(" $ CryptoLive ", "cryptolive", false), + } + + currenciesMap, _ := Config.Map("wtf.mods.cryptolive.currencies") + + var currencies []*fromCurrency + + for currency := range currenciesMap { + displayName, _ := Config.String("wtf.mods.cryptolive.currencies." + currency + ".displayName") + toCList, _ := Config.List("wtf.mods.cryptolive.currencies." + currency + ".to") + var toList []*toCurrency + for _, v := range toCList { + toList = append(toList, &toCurrency{ + name: v.(string), + price: -1, + }) + } + currencies = append(currencies, &fromCurrency{ + name: currency, + displayName: displayName, + to: toList, + }) + } + + widget.list = &list{ + items: currencies, + } + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +// Refresh & update after interval time +func (widget *Widget) Refresh() { + if widget.Disabled() { + return + } + + if started == false { + go func() { + for { + widget.updateCurrencies() + time.Sleep(time.Duration(widget.RefreshInterval()) * time.Second) + } + }() + + } + + started = true + + widget.UpdateRefreshedAt() + widget.View.Clear() + display(widget) +} + +/* -------------------- Unexported Functions -------------------- */ + +func display(widget *Widget) { + str := "" + for _, item := range widget.list.items { + str += fmt.Sprintf("[coral]%s[gray](%s):\n", item.displayName, item.name) + for _, toItem := range item.to { + str += fmt.Sprintf("\t%s[%s]: %f\n", toItem.name, "green", toItem.price) + } + str += "\n" + } + + fmt.Fprintf( + widget.View, + "\n%s", + str, + ) +} + +func (widget *Widget) updateCurrencies() { + defer func() { + recover() + }() + for _, fromCurrency := range widget.list.items { + request := gohttp.New().Path("data", "price").Query("fsym", fromCurrency.name) + tsyms := "" + for _, toCurrency := range fromCurrency.to { + tsyms += fmt.Sprintf("%s,", toCurrency.name) + } + + response, err := request.Query("tsyms", tsyms).Get("https://min-api.cryptocompare.com") + if err != nil { + } + + jsonResponse := &cResponse{} + response.AsJSON(jsonResponse) + + responseRef := reflect.Indirect(reflect.ValueOf(jsonResponse)) + for idx, toCurrency := range fromCurrency.to { + fromCurrency.to[idx].price = responseRef.FieldByName(toCurrency.name).Interface().(float32) + } + + } + +} From 909b82f8de9b3421a446374fdcb7d8873da12df9 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Tue, 29 May 2018 20:17:37 +0430 Subject: [PATCH 02/11] add some comments --- wtf.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wtf.go b/wtf.go index 948870be..19b7e5b0 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/cryptolive" "github.com/senorprogrammer/wtf/gcal" "github.com/senorprogrammer/wtf/git" "github.com/senorprogrammer/wtf/github" @@ -171,6 +172,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { todo.Config = Config weather.Config = Config wtf.Config = Config + cryptolive.Config = Config Widgets = []wtf.Wtfable{ bamboohr.NewWidget(), @@ -190,6 +192,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { textfile.NewWidget(app, pages), todo.NewWidget(app, pages), weather.NewWidget(app, pages), + cryptolive.NewWidget(), } FocusTracker = wtf.FocusTracker{ From 50843a5069ef1f1b8a30feaa2848f54e92d6f6dd Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Tue, 29 May 2018 20:33:34 +0430 Subject: [PATCH 03/11] add time interval for send http request --- cryptolive/widget.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cryptolive/widget.go b/cryptolive/widget.go index 8ddf2408..fce5ae45 100644 --- a/cryptolive/widget.go +++ b/cryptolive/widget.go @@ -21,7 +21,8 @@ var started = false type Widget struct { wtf.TextWidget - CurrentIcon int + // time interval for send http request + updateInterval int *list } @@ -30,7 +31,8 @@ type Widget struct { func NewWidget() *Widget { started = false widget := Widget{ - TextWidget: wtf.NewTextWidget(" $ CryptoLive ", "cryptolive", false), + TextWidget: wtf.NewTextWidget(" $ CryptoLive ", "cryptolive", false), + updateInterval: Config.UInt("wtf.mods.cryptolive.updateInterval", 10), } currenciesMap, _ := Config.Map("wtf.mods.cryptolive.currencies") @@ -73,7 +75,7 @@ func (widget *Widget) Refresh() { go func() { for { widget.updateCurrencies() - time.Sleep(time.Duration(widget.RefreshInterval()) * time.Second) + time.Sleep(time.Duration(widget.updateInterval) * time.Second) } }() @@ -129,5 +131,4 @@ func (widget *Widget) updateCurrencies() { } } - } From 82d267300957bdb1fba5e19b5db9cc582c850566 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sat, 2 Jun 2018 11:38:29 +0430 Subject: [PATCH 04/11] clean up cryptolive --- cryptolive/cryptolive.go | 10 ++++++++++ cryptolive/widget.go | 43 ++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/cryptolive/cryptolive.go b/cryptolive/cryptolive.go index adc99660..462c144e 100644 --- a/cryptolive/cryptolive.go +++ b/cryptolive/cryptolive.go @@ -42,3 +42,13 @@ type cResponse struct { USD float32 `json:"USD"` EUR float32 `json:"EUR"` } + +/* -------------------- Unexported Functions -------------------- */ + +func (l *list) addItem(name string, displayName string, to []*toCurrency) { + l.items = append(l.items, &fromCurrency{ + name: name, + displayName: displayName, + to: to, + }) +} diff --git a/cryptolive/widget.go b/cryptolive/widget.go index fce5ae45..4edbb8a7 100644 --- a/cryptolive/widget.go +++ b/cryptolive/widget.go @@ -35,32 +35,22 @@ func NewWidget() *Widget { updateInterval: Config.UInt("wtf.mods.cryptolive.updateInterval", 10), } + widget.setList() + + return &widget +} + +func (widget *Widget) setList() { currenciesMap, _ := Config.Map("wtf.mods.cryptolive.currencies") - var currencies []*fromCurrency + widget.list = &list{} for currency := range currenciesMap { displayName, _ := Config.String("wtf.mods.cryptolive.currencies." + currency + ".displayName") - toCList, _ := Config.List("wtf.mods.cryptolive.currencies." + currency + ".to") - var toList []*toCurrency - for _, v := range toCList { - toList = append(toList, &toCurrency{ - name: v.(string), - price: -1, - }) - } - currencies = append(currencies, &fromCurrency{ - name: currency, - displayName: displayName, - to: toList, - }) + toList := getToList(currency) + widget.list.addItem(currency, displayName, toList) } - widget.list = &list{ - items: currencies, - } - - return &widget } /* -------------------- Exported Functions -------------------- */ @@ -132,3 +122,18 @@ func (widget *Widget) updateCurrencies() { } } + +func getToList(fromName string) []*toCurrency { + toNames, _ := Config.List("wtf.mods.cryptolive.currencies." + fromName + ".to") + + var toList []*toCurrency + + for _, to := range toNames { + toList = append(toList, &toCurrency{ + name: to.(string), + price: -1, + }) + } + + return toList +} From 350ba132c741699bb645e90c042e9d0ed551871f Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sat, 2 Jun 2018 12:49:56 +0430 Subject: [PATCH 05/11] clean up, handle error, use net/http, read colors from config file --- cryptolive/widget.go | 113 +++++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 36 deletions(-) diff --git a/cryptolive/widget.go b/cryptolive/widget.go index 4edbb8a7..0bd669d3 100644 --- a/cryptolive/widget.go +++ b/cryptolive/widget.go @@ -1,12 +1,12 @@ package cryptolive import ( + "encoding/json" "fmt" + "reflect" "time" - "github.com/cizixs/gohttp" - - "reflect" + "net/http" "github.com/olebedev/config" "github.com/senorprogrammer/wtf/wtf" @@ -16,6 +16,8 @@ import ( var Config *config.Config var started = false +var baseURL = "https://min-api.cryptocompare.com/data/price" +var ok = true // Widget define wtf widget to register widget later type Widget struct { @@ -62,6 +64,7 @@ func (widget *Widget) Refresh() { } if started == false { + // this code should run once go func() { for { widget.updateCurrencies() @@ -75,6 +78,13 @@ func (widget *Widget) Refresh() { widget.UpdateRefreshedAt() widget.View.Clear() + + if !ok { + widget.View.SetText( + fmt.Sprint("Please check your internet connection!"), + ) + return + } display(widget) } @@ -82,45 +92,21 @@ func (widget *Widget) Refresh() { func display(widget *Widget) { str := "" + var ( + fromNameColor = Config.UString("wtf.mods.cryptolive.colors.from.name", "coral") + fromDisplayNameColor = Config.UString("wtf.mods.cryptolive.colors.from.displayName", "gray") + toNameColor = Config.UString("wtf.mods.cryptolive.colors.to.name", "white") + toPriceColor = Config.UString("wtf.mods.cryptolive.colors.to.price", "green") + ) for _, item := range widget.list.items { - str += fmt.Sprintf("[coral]%s[gray](%s):\n", item.displayName, item.name) + str += fmt.Sprintf("[%s]%s[%s](%s):\n", fromNameColor, item.displayName, fromDisplayNameColor, item.name) for _, toItem := range item.to { - str += fmt.Sprintf("\t%s[%s]: %f\n", toItem.name, "green", toItem.price) + str += fmt.Sprintf("\t[%s]%s: [%s]%f\n", toNameColor, toItem.name, toPriceColor, toItem.price) } str += "\n" } - fmt.Fprintf( - widget.View, - "\n%s", - str, - ) -} - -func (widget *Widget) updateCurrencies() { - defer func() { - recover() - }() - for _, fromCurrency := range widget.list.items { - request := gohttp.New().Path("data", "price").Query("fsym", fromCurrency.name) - tsyms := "" - for _, toCurrency := range fromCurrency.to { - tsyms += fmt.Sprintf("%s,", toCurrency.name) - } - - response, err := request.Query("tsyms", tsyms).Get("https://min-api.cryptocompare.com") - if err != nil { - } - - jsonResponse := &cResponse{} - response.AsJSON(jsonResponse) - - responseRef := reflect.Indirect(reflect.ValueOf(jsonResponse)) - for idx, toCurrency := range fromCurrency.to { - fromCurrency.to[idx].price = responseRef.FieldByName(toCurrency.name).Interface().(float32) - } - - } + widget.View.SetText(fmt.Sprintf("\n%s", str)) } func getToList(fromName string) []*toCurrency { @@ -137,3 +123,58 @@ func getToList(fromName string) []*toCurrency { return toList } + +func (widget *Widget) updateCurrencies() { + defer func() { + recover() + }() + for _, fromCurrency := range widget.list.items { + var ( + client http.Client + jsonResponse cResponse + ) + + client = http.Client{ + Timeout: time.Duration(5 * time.Second), + } + + request := makeRequest(fromCurrency) + response, err := client.Do(request) + + if err != nil { + ok = false + } else { + ok = true + } + + defer response.Body.Close() + + _ = json.NewDecoder(response.Body).Decode(&jsonResponse) + + setPrices(&jsonResponse, fromCurrency) + + } +} + +func makeRequest(currency *fromCurrency) *http.Request { + fsym := currency.name + tsyms := "" + for _, to := range currency.to { + tsyms += fmt.Sprintf("%s,", to.name) + } + + url := fmt.Sprintf("%s?fsym=%s&tsyms=%s", baseURL, fsym, tsyms) + request, err := http.NewRequest("GET", url, nil) + + if err != nil { + } + + return request +} + +func setPrices(response *cResponse, currencry *fromCurrency) { + responseRef := reflect.Indirect(reflect.ValueOf(response)) + for idx, toCurrency := range currencry.to { + currencry.to[idx].price = responseRef.FieldByName(toCurrency.name).Interface().(float32) + } +} From 4b91f78c04da76cdabb84650f80d809b2962fc4e Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sat, 2 Jun 2018 13:23:47 +0430 Subject: [PATCH 06/11] fixed display after any update --- cryptolive/widget.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cryptolive/widget.go b/cryptolive/widget.go index 0bd669d3..23203024 100644 --- a/cryptolive/widget.go +++ b/cryptolive/widget.go @@ -129,6 +129,7 @@ func (widget *Widget) updateCurrencies() { recover() }() for _, fromCurrency := range widget.list.items { + var ( client http.Client jsonResponse cResponse @@ -152,8 +153,9 @@ func (widget *Widget) updateCurrencies() { _ = json.NewDecoder(response.Body).Decode(&jsonResponse) setPrices(&jsonResponse, fromCurrency) - } + + display(widget) } func makeRequest(currency *fromCurrency) *http.Request { From ecdd0b0e575ac9cd784946cbac4fb601ccaf0aab Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sat, 2 Jun 2018 13:35:50 +0430 Subject: [PATCH 07/11] misspelled grey --- cryptolive/widget.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptolive/widget.go b/cryptolive/widget.go index 23203024..e90a1569 100644 --- a/cryptolive/widget.go +++ b/cryptolive/widget.go @@ -94,7 +94,7 @@ func display(widget *Widget) { str := "" var ( fromNameColor = Config.UString("wtf.mods.cryptolive.colors.from.name", "coral") - fromDisplayNameColor = Config.UString("wtf.mods.cryptolive.colors.from.displayName", "gray") + fromDisplayNameColor = Config.UString("wtf.mods.cryptolive.colors.from.displayName", "grey") toNameColor = Config.UString("wtf.mods.cryptolive.colors.to.name", "white") toPriceColor = Config.UString("wtf.mods.cryptolive.colors.to.price", "green") ) From 795a28839f3287205c55a97f9575b83d3740d4b1 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sat, 2 Jun 2018 13:37:21 +0430 Subject: [PATCH 08/11] added cryptolive to docs --- docs/posts/modules/cryptolive/index.html | 243 +++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 docs/posts/modules/cryptolive/index.html diff --git a/docs/posts/modules/cryptolive/index.html b/docs/posts/modules/cryptolive/index.html new file mode 100644 index 00000000..63395a42 --- /dev/null +++ b/docs/posts/modules/cryptolive/index.html @@ -0,0 +1,243 @@ + + + + + + + + + + + + + Module: CryptoLive | WTF - A Terminal Dashboard + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Module: CryptoLive

+ +
+ +
+ +

Compare crypto currencies using cryptocompare.com

+ +

Source Code

+
+
wtf/cryptolive/
+
+

Required ENV Variables

+ +

None.

+ +

Keyboard Commands

+ +

None.

+ +

Configuration

+
+
cryptolive:
+  enabled: true
+  position:
+    top: 1
+    left: 2
+    height: 1
+    width: 1
+  refreshInterval: 15
+  updateInterval: 15
+  currencies: 
+   BTC:
+     displayName: Bitcoin
+     to: 
+       - USD
+       - EUR
+       - ETH
+   ETH:
+     displayName: Ethereum
+     to: 
+       - USD
+       - EUR
+       - ETH
+  colors: 
+   from: 
+     name: coral
+     displayName: grey
+   to:
+     name: white
+     price: green
+
+
+
+

Attributes

+ + + +

+ enabled +
Determines whether or not this module is executed and if its data displayed onscreen. +
Values: + true, + false.

+ +

+ position +
Defines where in the grid this module’s widget will be displayed. +
+

+ +

+ updateInterval +
How often, in seconds, this module will update its data. +
Values: A positive integer +
Default Value: 10

+ +

+ colors +
Sets color of texts. +
Values: A valid color +

+ +
+ + +
+ + + + \ No newline at end of file From 67e183e98aed98f87dc3ba425692fd5df9567ac0 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sun, 3 Jun 2018 05:25:25 +0430 Subject: [PATCH 09/11] move cryptolive to cryptoexchanges --- {cryptolive => cryptoexchanges/cryptolive}/cryptolive.go | 0 {cryptolive => cryptoexchanges/cryptolive}/widget.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {cryptolive => cryptoexchanges/cryptolive}/cryptolive.go (100%) rename {cryptolive => cryptoexchanges/cryptolive}/widget.go (100%) diff --git a/cryptolive/cryptolive.go b/cryptoexchanges/cryptolive/cryptolive.go similarity index 100% rename from cryptolive/cryptolive.go rename to cryptoexchanges/cryptolive/cryptolive.go diff --git a/cryptolive/widget.go b/cryptoexchanges/cryptolive/widget.go similarity index 100% rename from cryptolive/widget.go rename to cryptoexchanges/cryptolive/widget.go From 278099285156f1fc3dce3a71fe563a56d5cffbdb Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sun, 3 Jun 2018 05:28:33 +0430 Subject: [PATCH 10/11] fixed cryptolive path --- wtf.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wtf.go b/wtf.go index d1d4b1d4..a170d23b 100644 --- a/wtf.go +++ b/wtf.go @@ -13,7 +13,7 @@ import ( "github.com/senorprogrammer/wtf/bamboohr" "github.com/senorprogrammer/wtf/clocks" "github.com/senorprogrammer/wtf/cmdrunner" - "github.com/senorprogrammer/wtf/cryptolive" + "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" "github.com/senorprogrammer/wtf/gcal" "github.com/senorprogrammer/wtf/git" "github.com/senorprogrammer/wtf/github" From c2d2197ed0a96fbdda58fc67e7bf023b16f16872 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Mon, 4 Jun 2018 05:19:20 +0430 Subject: [PATCH 11/11] use map for http response --- cryptoexchanges/cryptolive/cryptolive.go | 28 +----------------------- cryptoexchanges/cryptolive/widget.go | 4 +--- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/cryptoexchanges/cryptolive/cryptolive.go b/cryptoexchanges/cryptolive/cryptolive.go index 462c144e..b9e641a0 100644 --- a/cryptoexchanges/cryptolive/cryptolive.go +++ b/cryptoexchanges/cryptolive/cryptolive.go @@ -15,33 +15,7 @@ type toCurrency struct { price float32 } -type cResponse struct { - BTC float32 `json:"BTC"` - HBZ float32 `json:"HBZ"` - ETH float32 `json:"ETH"` - EOS float32 `json:"EOS"` - BCH float32 `json:"BCH"` - TRX float32 `json:"TRX"` - XRP float32 `json:"XRP"` - LTC float32 `json:"LTC"` - ETC float32 `json:"ETC"` - ADA float32 `json:"ADA"` - CMT float32 `json:"CMT"` - DASH float32 `json:"DASH"` - ZEC float32 `json:"ZEC"` - IOT float32 `json:"IOT"` - ONT float32 `json:"ONT"` - NEO float32 `json:"NEO"` - BTG float32 `json:"BTG"` - LSK float32 `json:"LSK"` - ELA float32 `json:"ELA"` - DTA float32 `json:"DTA"` - NANO float32 `json:"NANO"` - WTC float32 `json:"WTC"` - DOGE float32 `json:"DOGE"` - USD float32 `json:"USD"` - EUR float32 `json:"EUR"` -} +type cResponse map[string]float32 /* -------------------- Unexported Functions -------------------- */ diff --git a/cryptoexchanges/cryptolive/widget.go b/cryptoexchanges/cryptolive/widget.go index e90a1569..4c652104 100644 --- a/cryptoexchanges/cryptolive/widget.go +++ b/cryptoexchanges/cryptolive/widget.go @@ -3,7 +3,6 @@ package cryptolive import ( "encoding/json" "fmt" - "reflect" "time" "net/http" @@ -175,8 +174,7 @@ func makeRequest(currency *fromCurrency) *http.Request { } func setPrices(response *cResponse, currencry *fromCurrency) { - responseRef := reflect.Indirect(reflect.ValueOf(response)) for idx, toCurrency := range currencry.to { - currencry.to[idx].price = responseRef.FieldByName(toCurrency.name).Interface().(float32) + currencry.to[idx].price = (*response)[toCurrency.name] } }