mirror of
https://github.com/cf-sonr/radar.git
synced 2026-01-12 11:09:13 +00:00
feat: implement account, profile, network, and activity management
This commit is contained in:
35
internal/api/client.go
Normal file
35
internal/api/client.go
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/syumai/workers/cloudflare/fetch"
|
||||
)
|
||||
|
||||
type Response interface {
|
||||
UnmarshalJSON(data []byte) error
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
MarketAPI
|
||||
}
|
||||
|
||||
type client struct {
|
||||
fc *fetch.Client
|
||||
ctx context.Context
|
||||
MarketAPI
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context) *client {
|
||||
fc := fetch.NewClient()
|
||||
c := &client{
|
||||
fc: fc,
|
||||
ctx: ctx,
|
||||
}
|
||||
marketAPI := NewMarketAPI(c, ctx)
|
||||
c.MarketAPI = marketAPI
|
||||
return c
|
||||
}
|
||||
117
internal/api/market.go
Normal file
117
internal/api/market.go
Normal file
@@ -0,0 +1,117 @@
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
kCryptoAPIURL = "https://api.alternative.me"
|
||||
kCryptoAPIListings = "/v2/listings"
|
||||
kCryptoAPITickers = "/v2/ticker"
|
||||
kCryptoAPIGlobal = "/v2/global"
|
||||
)
|
||||
|
||||
type MarketAPI interface {
|
||||
Listings(symbol string) (*ListingsResponse, error)
|
||||
Ticker(symbol string) (*TickersResponse, error)
|
||||
GlobalMarket() (*GlobalMarketResponse, error)
|
||||
}
|
||||
|
||||
type marketAPI struct {
|
||||
client *client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func NewMarketAPI(c *client, ctx context.Context) *marketAPI {
|
||||
return &marketAPI{
|
||||
client: c,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *marketAPI) Listings(symbol string) (*ListingsResponse, error) {
|
||||
r := buildRequest(m.ctx, fmt.Sprintf("%s/%s", kCryptoAPIListings, symbol))
|
||||
v := &ListingsResponse{}
|
||||
err := doFetch(m.client.fc, r, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (m *marketAPI) Ticker(symbol string) (*TickersResponse, error) {
|
||||
r := buildRequest(m.ctx, fmt.Sprintf("%s/%s", kCryptoAPITickers, symbol))
|
||||
v := &TickersResponse{}
|
||||
err := doFetch(m.client.fc, r, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (m *marketAPI) GlobalMarket() (*GlobalMarketResponse, error) {
|
||||
r := buildRequest(m.ctx, kCryptoAPIGlobal)
|
||||
v := &GlobalMarketResponse{}
|
||||
err := doFetch(m.client.fc, r, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
type ListingsResponse struct {
|
||||
Data []struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
WebsiteSlug string `json:"website_slug"`
|
||||
} `json:"data"`
|
||||
Metadata struct {
|
||||
Timestamp int `json:"timestamp"`
|
||||
NumCryptocurrencies int `json:"num_cryptocurrencies"`
|
||||
Error any `json:"error"`
|
||||
} `json:"metadata"`
|
||||
}
|
||||
|
||||
func (r *ListingsResponse) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, r)
|
||||
}
|
||||
|
||||
type TickersResponse struct {
|
||||
Data []struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Price struct {
|
||||
USD float64 `json:"USD"`
|
||||
} `json:"price"`
|
||||
} `json:"data"`
|
||||
Metadata struct {
|
||||
Timestamp int `json:"timestamp"`
|
||||
Error any `json:"error"`
|
||||
} `json:"metadata"`
|
||||
}
|
||||
|
||||
func (r *TickersResponse) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, r)
|
||||
}
|
||||
|
||||
type GlobalMarketResponse struct {
|
||||
Data []struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Price struct {
|
||||
USD float64 `json:"USD"`
|
||||
} `json:"price"`
|
||||
} `json:"data"`
|
||||
Metadata struct {
|
||||
Timestamp int `json:"timestamp"`
|
||||
Error any `json:"error"`
|
||||
} `json:"metadata"`
|
||||
}
|
||||
|
||||
func (r *GlobalMarketResponse) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, r)
|
||||
}
|
||||
43
internal/api/utils.go
Normal file
43
internal/api/utils.go
Normal file
@@ -0,0 +1,43 @@
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/syumai/workers/cloudflare/fetch"
|
||||
)
|
||||
|
||||
func buildRequest(c context.Context, url string) *fetch.Request {
|
||||
r, err := fetch.NewRequest(c, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
r.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0")
|
||||
return r
|
||||
}
|
||||
|
||||
func doFetch(c *fetch.Client, r *fetch.Request, v Response) error {
|
||||
resp, err := c.Do(r, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close() // Ensure body is always closed
|
||||
|
||||
// Check for non-200 status codes
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Directly decode JSON into the response struct
|
||||
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
|
||||
return fmt.Errorf("failed to decode response: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user