listen to mempool.space websocket

This commit is contained in:
2023-12-21 17:33:20 -05:00
parent 9e83d6cc7d
commit babd5d8253
6 changed files with 254 additions and 68 deletions
+100 -10
View File
@@ -5,7 +5,11 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"time"
"github.com/gorilla/websocket"
)
@@ -14,19 +18,27 @@ var (
ErrNotWebsocket = errors.New("provided addr was not websocket")
)
const (
WSEndpoint = "api/v1/ws"
)
type mempool struct {
addr string
ws *websocket.Conn
baseUrl string
httpClient *http.Client
ws *websocket.Conn
}
func New(addr string) *mempool {
func New(baseUrl string, httpClient *http.Client) *mempool {
return &mempool{
addr: addr,
baseUrl: baseUrl,
httpClient: &http.Client{
Timeout: 5 * time.Second,
},
}
}
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 {
return err
}
@@ -40,15 +52,93 @@ func (m *mempool) Init() error {
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
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 {
select {
case <-ctx.Done():
close(blocks)
close(messages)
close(errs)
close(done)
return
@@ -59,14 +149,14 @@ func (m *mempool) Listen(ctx context.Context, blocks chan Block, errs chan error
continue
}
var b Block
err = json.Unmarshal(message, &b)
var m Message
err = json.Unmarshal(message, &m)
if err != nil {
errs <- err
continue
}
blocks <- b
messages <- m
}
}
}
+24
View File
@@ -1,5 +1,29 @@
package mempool
type Message struct {
Block *Block `json:"block"`
Conversions *Conversions `json:"conversions"`
Fees *Fees `json:"fees"`
}
type Block struct {
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"`
}