-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
multi: add market data API endpoints
Exposes a rate-limited HTTP API. Data endpoints are accessible via HTTP or WebSockets. The result for the WebSocket request is identical to the REST API response. /spots is the spot price and booked volume of all markets. /candles is candlestick data, available in bin sizes of 24h, 1h, 15m, and per-epoch sticks. An example URL is /candles/dcr/btc/15m. /orderbook is already a WebSocket route, but is now also accessible by HTTP. An example URL is /orderbook/dcr/btc /config is another WebSocket route that is also now available over HTTP too. The data API implements a data cache, but does not cache pre-encoded responses for /candles or /orderbook (yet). **server/db** Market history is stored as a row per epoch. I've created a new table for this, though we could also combine with the existing epoch table that holds match proof info if preferred. I've made no attempt to integrate pre-existing data. Data will be collected from the time of upgrade only. The upgrade is silent, since we don't have upgrade infrastructure in place yet for the server. **server/comms** The config route is now registered as an http handler, but also called from the websocket message handler. HTTP requests are rate-limited using `"golang.org/x/time/rate"`. There is both a global rate limiter and a per-IP rate limiter. The rate limits apply to un-authenticated routes only. The /config request is has an exception as a "critical' route. * enable/disable via admin api. config route not metered on ws * use better http json response encoding pattern
- Loading branch information
Showing
46 changed files
with
2,400 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// This code is available on the terms of the project LICENSE.md file, | ||
// also available online at https://blueoakcouncil.org/license/1.0.0. | ||
|
||
package dex | ||
|
||
import ( | ||
"net" | ||
) | ||
|
||
// IPKey is a IP address byte array. For an IPV6 address, the IPKey drops the | ||
// interface identifier, which is the second half of the address. | ||
type IPKey [net.IPv6len / 2]byte | ||
|
||
// NewIPKey parses an IP address string into an IPKey. | ||
func NewIPKey(addr string) IPKey { | ||
host, _, err := net.SplitHostPort(addr) | ||
if err == nil && host != "" { | ||
addr = host | ||
} | ||
netIP := net.ParseIP(addr) | ||
ip := netIP.To4() | ||
if ip == nil { | ||
ip = netIP.To16() | ||
} | ||
var ipKey IPKey | ||
copy(ipKey[:], ip) | ||
return ipKey | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// This code is available on the terms of the project LICENSE.md file, | ||
// also available online at https://blueoakcouncil.org/license/1.0.0. | ||
|
||
package dex | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestIPKey(t *testing.T) { | ||
if NewIPKey("127.0.0.1") == NewIPKey("127.0.0.2") { | ||
t.Fatalf("IPKey v4 failed basic comparison test, %x = %x", NewIPKey("127.0.0.1"), NewIPKey("127.0.0.2")) | ||
} | ||
if NewIPKey("[a:b:c:d::]:1234") == NewIPKey("[a:b:c:e::]:1234") { | ||
t.Fatalf("IPKey v6 failed basic comparison test, %x = %x", NewIPKey("[a:b:c:d]"), NewIPKey("[a:b:c:d]")) | ||
} | ||
|
||
tests := []struct { | ||
name, addr1, addr2 string | ||
wantEqual bool | ||
}{ | ||
{ | ||
name: "ipv4 unequal", | ||
addr1: "127.0.0.1", | ||
addr2: "127.0.0.2", | ||
wantEqual: false, | ||
}, | ||
{ | ||
name: "ipv4 equal", | ||
addr1: "127.0.0.1", | ||
addr2: "127.0.0.1", | ||
wantEqual: true, | ||
}, | ||
{ | ||
name: "ipv4 port unequal", | ||
addr1: "127.0.0.1:1234", | ||
addr2: "127.0.0.2:1234", | ||
wantEqual: false, | ||
}, | ||
{ | ||
name: "ipv4 port equal", | ||
addr1: "127.0.0.1:1234", | ||
addr2: "127.0.0.1:1234", | ||
wantEqual: true, | ||
}, | ||
{ | ||
name: "ipv4 port equal noport", | ||
addr1: "127.0.0.1", | ||
addr2: "127.0.0.1:1234", | ||
wantEqual: true, | ||
}, | ||
{ | ||
name: "ipv6 port unequal", | ||
addr1: "[a:b:c:d::]:1234", | ||
addr2: "[a:b:c:e::]:1234", | ||
wantEqual: false, | ||
}, | ||
{ | ||
name: "ipv6 port equal", | ||
addr1: "[a:b:c:d::]:1234", | ||
addr2: "[a:b:c:d::]:1234", | ||
wantEqual: true, | ||
}, | ||
{ | ||
name: "ipv6 port equal noport", | ||
addr1: "a:b:c:d::", | ||
addr2: "[a:b:c:d::]:1234", | ||
wantEqual: true, | ||
}, | ||
{ | ||
name: "ipv6 mask equal", | ||
addr1: "[a:b:c:d:e:f:a:b]:1234", | ||
addr2: "[a:b:c:d:f:d:c:f]:1234", | ||
wantEqual: true, | ||
}, | ||
} | ||
|
||
zeroKey := IPKey{} | ||
|
||
for _, tt := range tests { | ||
ipKey1 := NewIPKey(tt.addr1) | ||
ipKey2 := NewIPKey(tt.addr2) | ||
|
||
if ipKey1 == zeroKey || ipKey2 == zeroKey { | ||
t.Fatalf("%s: zeroKey found. ipKey1 = %x, ipKey2 = %x", tt.name, ipKey1[:], ipKey2[:]) | ||
} | ||
|
||
if (ipKey1 == ipKey2) != tt.wantEqual { | ||
t.Fatalf("%s: wantEqual = %t, addr1 = %s, addr2 = %s, ipKey1 = %x, ipKey2 = %x", | ||
tt.name, tt.wantEqual, tt.addr1, tt.addr2, ipKey1[:], ipKey2[:]) | ||
} | ||
} | ||
} |
Oops, something went wrong.