github.com/wtfutil/wtf@v0.43.0/modules/cryptocurrency/blockfolio/widget.go (about) 1 package blockfolio 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "log" 8 "net/http" 9 10 "github.com/rivo/tview" 11 "github.com/wtfutil/wtf/view" 12 ) 13 14 type Widget struct { 15 view.TextWidget 16 17 device_token string 18 settings *Settings 19 } 20 21 func NewWidget(tviewApp *tview.Application, redrawChan chan bool, settings *Settings) *Widget { 22 widget := Widget{ 23 TextWidget: view.NewTextWidget(tviewApp, redrawChan, nil, settings.Common), 24 25 device_token: settings.deviceToken, 26 settings: settings, 27 } 28 29 return &widget 30 } 31 32 /* -------------------- Exported Functions -------------------- */ 33 34 func (widget *Widget) Refresh() { 35 36 widget.Redraw(widget.content) 37 } 38 39 /* -------------------- Unexported Functions -------------------- */ 40 func (widget *Widget) content() (string, string, bool) { 41 positions, err := Fetch(widget.device_token) 42 title := widget.CommonSettings().Title 43 if err != nil { 44 return title, err.Error(), true 45 } 46 47 res := "" 48 totalFiat := float32(0.0) 49 50 for i := 0; i < len(positions.PositionList); i++ { 51 colorForChange := widget.settings.colors.grows 52 53 if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { 54 colorForChange = widget.settings.colors.drop 55 } 56 57 totalFiat += positions.PositionList[i].HoldingValueFiat 58 59 if widget.settings.displayHoldings { 60 res += fmt.Sprintf( 61 "[%s]%-6s - %5.2f ([%s]%.3fk [%s]%.2f%s)\n", 62 widget.settings.colors.name, 63 positions.PositionList[i].Coin, 64 positions.PositionList[i].Quantity, 65 colorForChange, 66 positions.PositionList[i].HoldingValueFiat/1000, 67 colorForChange, 68 positions.PositionList[i].TwentyFourHourPercentChangeFiat, 69 "%", 70 ) 71 } else { 72 res += fmt.Sprintf( 73 "[%s]%-6s - %5.2f ([%s]%.2f%s)\n", 74 widget.settings.colors.name, 75 positions.PositionList[i].Coin, 76 positions.PositionList[i].Quantity, 77 colorForChange, 78 positions.PositionList[i].TwentyFourHourPercentChangeFiat, 79 "%", 80 ) 81 } 82 } 83 84 if widget.settings.displayHoldings { 85 res += fmt.Sprintf("\n[%s]Total value: $%.3fk", "green", totalFiat/1000) 86 } 87 88 return title, res, true 89 } 90 91 // always the same 92 const magic = "edtopjhgn2345piuty89whqejfiobh89-2q453" 93 94 type Position struct { 95 Coin string `json:"coin"` 96 LastPriceFiat float32 `json:"lastPriceFiat"` 97 TwentyFourHourPercentChangeFiat float32 `json:"twentyFourHourPercentChangeFiat"` 98 Quantity float32 `json:"quantity"` 99 HoldingValueFiat float32 `json:"holdingValueFiat"` 100 } 101 102 type AllPositionsResponse struct { 103 PositionList []Position `json:"positionList"` 104 } 105 106 func MakeApiRequest(token string, method string) ([]byte, error) { 107 client := &http.Client{} 108 url := "https://api-v0.blockfolio.com/rest/" + method + "/" + token + "?use_alias=true&fiat_currency=USD" 109 req, err := http.NewRequest("GET", url, http.NoBody) 110 if err != nil { 111 return nil, err 112 } 113 req.Header.Add("magic", magic) 114 resp, err := client.Do(req) 115 if err != nil { 116 return nil, err 117 } 118 defer func() { _ = resp.Body.Close() }() 119 body, err := io.ReadAll(resp.Body) 120 if err != nil { 121 return nil, err 122 } 123 return body, err 124 } 125 126 func GetAllPositions(token string) (*AllPositionsResponse, error) { 127 jsn, _ := MakeApiRequest(token, "get_all_positions") 128 var parsed AllPositionsResponse 129 130 err := json.Unmarshal(jsn, &parsed) 131 if err != nil { 132 log.Fatalf("Failed to parse json %v", err) 133 return nil, err 134 } 135 return &parsed, err 136 } 137 138 func Fetch(token string) (*AllPositionsResponse, error) { 139 return GetAllPositions(token) 140 }