listen to mempool.space websocket
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
go-rpi-rgb-led-matrix/lib/rpi-rgb-led-matrix/
|
||||||
+92
-19
@@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.dvdt.dev/david/bitcoin-ticker-pi/display"
|
"git.dvdt.dev/david/bitcoin-ticker-pi/display"
|
||||||
@@ -14,8 +16,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RefreshRateHz = 60
|
RefreshRateHz = 1
|
||||||
MempoolURL = "wss://mempool.dvdt.dev/v1/api/ws"
|
MempoolURL = "mempool.space"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -31,38 +33,92 @@ func main() {
|
|||||||
display.NewSlot(5, 5, 4, 44, 0),
|
display.NewSlot(5, 5, 4, 44, 0),
|
||||||
display.NewSlot(7, 13, 8, 5, 9),
|
display.NewSlot(7, 13, 8, 5, 9),
|
||||||
display.NewSlot(12, 5, 4, 7, 27),
|
display.NewSlot(12, 5, 4, 7, 27),
|
||||||
display.NewSlot(8, 5, 4, 28, 27),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
ticker := time.NewTicker(time.Second / RefreshRateHz)
|
ticker := time.NewTicker(time.Second / RefreshRateHz)
|
||||||
tdone := make(chan struct{})
|
tdone := make(chan struct{})
|
||||||
mdone := make(chan struct{})
|
mdone := make(chan struct{})
|
||||||
blocks := make(chan mempool.Block)
|
msgs := make(chan mempool.Message)
|
||||||
errs := make(chan error)
|
errs := make(chan error)
|
||||||
|
|
||||||
mp := mempool.New(MempoolURL)
|
mp := mempool.New(MempoolURL, &http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
})
|
||||||
err := mp.Init()
|
err := mp.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func(done chan struct{}, t *time.Ticker) {
|
currentBlockHeight, err := mp.CurrentBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
highfee, medfee, lowfee, err := mp.CurrentFees()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var blockHeight int
|
||||||
|
blockHeightMutex := &sync.Mutex{}
|
||||||
|
var fees mempool.Fees
|
||||||
|
feesMutex := &sync.Mutex{}
|
||||||
|
var price int
|
||||||
|
priceMutex := &sync.Mutex{}
|
||||||
|
|
||||||
|
blockHeight = currentBlockHeight
|
||||||
|
fees.FastestFee = highfee
|
||||||
|
fees.HalfHourFee = medfee
|
||||||
|
fees.HourFee = lowfee
|
||||||
|
|
||||||
|
go mp.Listen(ctx, msgs, errs, mdone)
|
||||||
|
|
||||||
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case m := <-msgs:
|
||||||
return
|
fmt.Printf("%+v\n", m)
|
||||||
case <-ticker.C:
|
if m.Fees != nil {
|
||||||
updateSlots(d, 44000, 821000, 100, 200, 300)
|
feesMutex.Lock()
|
||||||
|
fees = *m.Fees
|
||||||
|
feesMutex.Unlock()
|
||||||
|
}
|
||||||
|
if m.Block != nil {
|
||||||
|
blockHeightMutex.Lock()
|
||||||
|
blockHeight = int(m.Block.Height)
|
||||||
|
blockHeightMutex.Unlock()
|
||||||
|
}
|
||||||
|
if m.Conversions != nil {
|
||||||
|
priceMutex.Lock()
|
||||||
|
price = m.Conversions.USD
|
||||||
|
priceMutex.Unlock()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(tdone, ticker)
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-tdone:
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
d.Clear()
|
||||||
|
d.Render()
|
||||||
|
err = updateSlots(d, price, blockHeight, fees.HourFee, fees.HalfHourFee, fees.FastestFee)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSlots(d *display.Display, price, height, lfee, mfee, hfee int) error {
|
func updateSlots(d *display.Display, price, height, lfee, mfee, hfee int) error {
|
||||||
priceStr := fmt.Sprintf("%d", price)
|
d.Clear()
|
||||||
|
|
||||||
var priceSegments []display.Segment
|
var priceSegments []display.Segment
|
||||||
priceSegments = append(priceSegments, strToDisplaySegments("dollar", fonts.Green)...)
|
priceSegments = append(priceSegments, display.Segment{Text: "dollar", Color: fonts.Green})
|
||||||
priceSegments = append(priceSegments, strToDisplaySegments(fmt.Sprintf("%d", price), fonts.White)...)
|
priceSegments = append(priceSegments, strToDisplaySegments(fmt.Sprintf("%d", price), fonts.White)...)
|
||||||
|
|
||||||
err := d.UpdateTopLeft(priceSegments)
|
err := d.UpdateTopLeft(priceSegments)
|
||||||
@@ -71,8 +127,12 @@ func updateSlots(d *display.Display, price, height, lfee, mfee, hfee int) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
var moscowTimeSegments []display.Segment
|
var moscowTimeSegments []display.Segment
|
||||||
moscowTimeSegments = append(moscowTimeSegments, strToDisplaySegments("satoshi", fonts.Orange)...)
|
moscowTime := 0
|
||||||
moscowTimeSegments = append(moscowTimeSegments, strToDisplaySegments(fmt.Sprintf("%d", 100000000/price), fonts.White)...)
|
if price > 0 {
|
||||||
|
moscowTime = 100000000 / price
|
||||||
|
}
|
||||||
|
moscowTimeSegments = append(moscowTimeSegments, display.Segment{Text: "satoshi", Color: fonts.Orange})
|
||||||
|
moscowTimeSegments = append(moscowTimeSegments, strToDisplaySegments(fmt.Sprintf("%d", moscowTime), fonts.White)...)
|
||||||
|
|
||||||
err = d.UpdateTopRight(moscowTimeSegments)
|
err = d.UpdateTopRight(moscowTimeSegments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -80,18 +140,31 @@ func updateSlots(d *display.Display, price, height, lfee, mfee, hfee int) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
var heightSegments []display.Segment
|
var heightSegments []display.Segment
|
||||||
heightSegments = append(heightSegments, strToDisplaySegments("height", fonts.Blue)...)
|
heightSegments = append(heightSegments, display.Segment{Text: "height", Color: fonts.Blue})
|
||||||
heightSegments = append(heightSegments, strToDisplaySegments(fmt.Sprintf("%d", height), fonts.White)...)
|
heightSegments = append(heightSegments, strToDisplaySegments(fmt.Sprintf("%d", height), fonts.White)...)
|
||||||
|
|
||||||
err = d.UpdateCenter(heightSegments)
|
err = d.UpdateMain(heightSegments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
var feeSegments []display.Segment
|
||||||
|
feeSegments = append(feeSegments, display.Segment{Text: "low", Color: fonts.Green})
|
||||||
|
feeSegments = append(feeSegments, strToDisplaySegments(fmt.Sprintf("%d", lfee), fonts.White)...)
|
||||||
|
feeSegments = append(feeSegments, display.Segment{Text: "medium", Color: fonts.Orange})
|
||||||
|
feeSegments = append(feeSegments, strToDisplaySegments(fmt.Sprintf("%d", mfee), fonts.White)...)
|
||||||
|
feeSegments = append(feeSegments, display.Segment{Text: "high", Color: fonts.Red})
|
||||||
|
feeSegments = append(feeSegments, strToDisplaySegments(fmt.Sprintf("%d", hfee), fonts.White)...)
|
||||||
|
|
||||||
|
err = d.UpdateBottom(feeSegments)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
func strToDisplaySegments(s string, c color.Color) []display.Segment {
|
func strToDisplaySegments(s string, c color.RGBA) []display.Segment {
|
||||||
var segs []display.Segment
|
var segs []display.Segment
|
||||||
for _, r := range s {
|
for _, r := range s {
|
||||||
segs = append(segs, display.Segment{Text: string(r), Color: c})
|
segs = append(segs, display.Segment{Text: string(r), Color: c})
|
||||||
|
|||||||
+26
-28
@@ -1,71 +1,69 @@
|
|||||||
package display
|
package display
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
|
"image/draw"
|
||||||
|
|
||||||
|
"git.dvdt.dev/david/bitcoin-ticker-pi/fonts"
|
||||||
rgbmatrix "git.dvdt.dev/david/bitcoin-ticker-pi/go-rpi-rgb-led-matrix"
|
rgbmatrix "git.dvdt.dev/david/bitcoin-ticker-pi/go-rpi-rgb-led-matrix"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Display struct {
|
type Display struct {
|
||||||
canvas *rgbmatrix.Canvas
|
canvas *rgbmatrix.Canvas
|
||||||
|
|
||||||
tl, tr, c, bl, br *Slot
|
topleft, topright, main, bottom *Slot
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(canvas *rgbmatrix.Canvas, tl, tr, c, bl, br *Slot) *Display {
|
func New(canvas *rgbmatrix.Canvas, topleft, topright, main, bottom *Slot) *Display {
|
||||||
return &display{
|
return &Display{
|
||||||
canvas: canvas,
|
canvas: canvas,
|
||||||
tl: tl,
|
topleft: topleft,
|
||||||
tr: tr,
|
topright: topright,
|
||||||
c: c,
|
main: main,
|
||||||
bl: bl,
|
bottom: bottom,
|
||||||
br: br,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Display) UpdateTopLeft(text []Segment) error {
|
func (d *Display) UpdateTopLeft(text []Segment) error {
|
||||||
err := d.tl.Update(text)
|
err := d.topleft.Update(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.tl.Draw(d.canvas)
|
d.topleft.Draw(d.canvas)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Display) UpdateTopRight(text []Segment) error {
|
func (d *Display) UpdateTopRight(text []Segment) error {
|
||||||
err := d.tr.Update(text)
|
err := d.topright.Update(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.tr.Draw(d.canvas)
|
d.topright.Draw(d.canvas)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Display) UpdateCenter(text []Segment) error {
|
func (d *Display) UpdateMain(text []Segment) error {
|
||||||
err := d.c.Update(text)
|
err := d.main.Update(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.c.Draw(d.canvas)
|
d.main.Draw(d.canvas)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Display) UpdateBottomLeft(text []Segment) error {
|
func (d *Display) UpdateBottom(text []Segment) error {
|
||||||
err := d.bl.Update(text)
|
err := d.bottom.Update(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.bl.Draw(d.canvas)
|
d.bottom.Draw(d.canvas)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Display) UpdateBottomRight(text []Segment) error {
|
|
||||||
err := d.br.Update(text)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.bl.Draw(d.canvas)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Display) Render() error {
|
func (d *Display) Render() error {
|
||||||
return d.canvas.Render()
|
return d.canvas.Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Display) Clear() {
|
||||||
|
draw.Draw(d.canvas, d.canvas.Bounds(), &image.Uniform{fonts.Black}, image.ZP, draw.Src)
|
||||||
|
}
|
||||||
|
|||||||
+11
-11
@@ -21,7 +21,7 @@ var (
|
|||||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||||
{1, 1, 1, 0, 1, 1, 1, 0},
|
{1, 1, 1, 0, 1, 1, 1, 0},
|
||||||
{1, 1, 0, 0, 0, 1, 1, 0},
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
{1, 0, 0, 0, 1, 1, 1, 0},
|
{0, 0, 0, 0, 1, 1, 1, 0},
|
||||||
{0, 0, 0, 0, 1, 1, 1, 0},
|
{0, 0, 0, 0, 1, 1, 1, 0},
|
||||||
{0, 0, 0, 1, 1, 1, 0, 0},
|
{0, 0, 0, 1, 1, 1, 0, 0},
|
||||||
{0, 0, 1, 1, 1, 0, 0, 0},
|
{0, 0, 1, 1, 1, 0, 0, 0},
|
||||||
@@ -108,19 +108,19 @@ var (
|
|||||||
{0, 0, 1, 1, 0, 0, 0, 0},
|
{0, 0, 1, 1, 0, 0, 0, 0},
|
||||||
},
|
},
|
||||||
"8": {
|
"8": {
|
||||||
{0, 0, 1, 1, 1, 0, 0, 0},
|
|
||||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||||
{1, 1, 1, 0, 1, 1, 1, 0},
|
{1, 1, 1, 1, 1, 1, 1, 0},
|
||||||
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
{1, 1, 0, 0, 0, 1, 1, 0},
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
{1, 1, 1, 0, 1, 1, 1, 0},
|
|
||||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
|
||||||
{0, 0, 1, 1, 1, 0, 0, 0},
|
|
||||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
|
||||||
{1, 1, 1, 0, 1, 1, 1, 0},
|
|
||||||
{1, 1, 0, 0, 0, 1, 1, 0},
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
{1, 1, 1, 0, 1, 1, 1, 0},
|
|
||||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||||
{0, 0, 1, 1, 1, 0, 0, 0},
|
{0, 0, 1, 1, 1, 0, 0, 0},
|
||||||
|
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||||
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
|
{1, 1, 0, 0, 0, 1, 1, 0},
|
||||||
|
{1, 1, 1, 1, 1, 1, 1, 0},
|
||||||
|
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||||
},
|
},
|
||||||
"9": {
|
"9": {
|
||||||
{0, 0, 1, 1, 1, 0, 0, 0},
|
{0, 0, 1, 1, 1, 0, 0, 0},
|
||||||
@@ -134,8 +134,8 @@ var (
|
|||||||
{0, 0, 0, 0, 0, 1, 1, 0},
|
{0, 0, 0, 0, 0, 1, 1, 0},
|
||||||
{0, 0, 0, 0, 0, 1, 1, 0},
|
{0, 0, 0, 0, 0, 1, 1, 0},
|
||||||
{0, 1, 0, 0, 1, 1, 1, 0},
|
{0, 1, 0, 0, 1, 1, 1, 0},
|
||||||
{0, 1, 1, 0, 0, 0, 0, 0},
|
{0, 1, 1, 1, 1, 1, 1, 0},
|
||||||
{0, 0, 1, 1, 0, 0, 0, 0},
|
{0, 0, 1, 1, 1, 1, 0, 0},
|
||||||
},
|
},
|
||||||
"0": {
|
"0": {
|
||||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||||
|
|||||||
+100
-10
@@ -5,7 +5,11 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
@@ -14,19 +18,27 @@ var (
|
|||||||
ErrNotWebsocket = errors.New("provided addr was not websocket")
|
ErrNotWebsocket = errors.New("provided addr was not websocket")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WSEndpoint = "api/v1/ws"
|
||||||
|
)
|
||||||
|
|
||||||
type mempool struct {
|
type mempool struct {
|
||||||
addr string
|
baseUrl string
|
||||||
ws *websocket.Conn
|
httpClient *http.Client
|
||||||
|
ws *websocket.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(addr string) *mempool {
|
func New(baseUrl string, httpClient *http.Client) *mempool {
|
||||||
return &mempool{
|
return &mempool{
|
||||||
addr: addr,
|
baseUrl: baseUrl,
|
||||||
|
httpClient: &http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mempool) Init() error {
|
func (m *mempool) Init() error {
|
||||||
u, err := url.Parse(m.addr)
|
u, err := url.Parse(fmt.Sprintf("wss://%s/%s", m.baseUrl, WSEndpoint))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -40,15 +52,93 @@ func (m *mempool) Init() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Data []string `json:"data"`
|
||||||
|
}{
|
||||||
|
Action: "want",
|
||||||
|
Data: []string{"blocks", "stats"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.WriteMessage(websocket.BinaryMessage, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
m.ws = c
|
m.ws = c
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mempool) Listen(ctx context.Context, blocks chan Block, errs chan error, done chan struct{}) {
|
func (m *mempool) CurrentBlockHeight() (int, error) {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://%s/api/blocks/tip/height", m.baseUrl), nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusInternalServerError {
|
||||||
|
return 0, errors.New("server error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
|
return 0, errors.New("client error")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.Atoi(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mempool) CurrentFees() (int, int, int, error) {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://%s/api/v1/fees/recommended", m.baseUrl), nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusInternalServerError {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Fastest int `json:"fastestFee"`
|
||||||
|
HalfHour int `json:"halfHourFee"`
|
||||||
|
Hour int `json:"hourFee"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(b, &data)
|
||||||
|
return data.Fastest, data.HalfHour, data.Hour, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mempool) Listen(ctx context.Context, messages chan Message, errs chan error, done chan struct{}) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
close(blocks)
|
close(messages)
|
||||||
close(errs)
|
close(errs)
|
||||||
close(done)
|
close(done)
|
||||||
return
|
return
|
||||||
@@ -59,14 +149,14 @@ func (m *mempool) Listen(ctx context.Context, blocks chan Block, errs chan error
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var b Block
|
var m Message
|
||||||
err = json.Unmarshal(message, &b)
|
err = json.Unmarshal(message, &m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs <- err
|
errs <- err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks <- b
|
messages <- m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,29 @@
|
|||||||
package mempool
|
package mempool
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
Block *Block `json:"block"`
|
||||||
|
Conversions *Conversions `json:"conversions"`
|
||||||
|
Fees *Fees `json:"fees"`
|
||||||
|
}
|
||||||
|
|
||||||
type Block struct {
|
type Block struct {
|
||||||
Height int64 `json:"height"`
|
Height int64 `json:"height"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Conversions struct {
|
||||||
|
USD int `json:"USD"`
|
||||||
|
EUR int `json:"EUR"`
|
||||||
|
GBP int `json:"GBP"`
|
||||||
|
CAD int `json:"CAD"`
|
||||||
|
CHF int `json:"CHF"`
|
||||||
|
AUD int `json:"AUD"`
|
||||||
|
JPY int `json:"JPY"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fees struct {
|
||||||
|
FastestFee int `json:"fastestFee"`
|
||||||
|
HalfHourFee int `json:"halfHourFee"`
|
||||||
|
HourFee int `json:"hourFee"`
|
||||||
|
EconomyFee int `json:"economyFee"`
|
||||||
|
MinimumFee int `json:"minimumFee"`
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user