mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-06-26 12:29:30 +00:00
Signed-off-by: Chrysostomos Nanakos <chris@include.gr> Co-authored-by: Chrysostomos Nanakos <chris@include.gr>
134 lines
3.4 KiB
Nim
134 lines
3.4 KiB
Nim
## Logos Storage
|
|
## Copyright (c) 2026 Status Research & Development GmbH
|
|
## Licensed under either of
|
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
## at your option.
|
|
## This file may not be copied, modified, or distributed except according to
|
|
## those terms.
|
|
|
|
{.push raises: [].}
|
|
|
|
import pkg/libp2p/protobuf/minprotobuf
|
|
import pkg/libp2p_mix
|
|
import pkg/libp2p/routing_record
|
|
|
|
import ../logutils
|
|
|
|
const DhtProxyCodec* = "/storage/dht-proxy/1.0.0"
|
|
|
|
const DefaultMaxInFlightLookups* = 100
|
|
|
|
let MaxLookupRequestBytes* = getMaxMessageSizeForCodec(DhtProxyCodec, 1).expect(
|
|
"DhtProxyCodec framing leaves no room for a Sphinx forward payload"
|
|
)
|
|
|
|
let MaxLookupResponseBytes* = getMaxMessageSizeForCodec(DhtProxyCodec, 0).expect(
|
|
"DhtProxyCodec framing leaves no room for a Sphinx reply payload"
|
|
)
|
|
|
|
type
|
|
QueryType* {.pure.} = enum
|
|
FindProviders = 0
|
|
|
|
ResponseStatus* {.pure.} = enum
|
|
Ok = 0
|
|
NotFound = 1
|
|
Error = 2
|
|
|
|
ErrorKind* {.pure.} = enum
|
|
DecodeFailed = 0
|
|
InvalidCid = 1
|
|
Internal = 2
|
|
ResponseTooLarge = 3
|
|
TooBusy = 4
|
|
|
|
LookupRequest* = object
|
|
queryType*: QueryType
|
|
queryBytes*: seq[byte]
|
|
|
|
LookupResponse* = object
|
|
status*: ResponseStatus
|
|
errorKind*: ErrorKind
|
|
providers*: seq[seq[byte]]
|
|
|
|
proc encode*(req: LookupRequest): seq[byte] =
|
|
var pb = initProtoBuffer()
|
|
pb.write(1, req.queryType.uint32)
|
|
pb.write(2, req.queryBytes)
|
|
pb.finish()
|
|
pb.buffer
|
|
|
|
proc encode*(resp: LookupResponse): seq[byte] =
|
|
var pb = initProtoBuffer()
|
|
pb.write(1, resp.status.uint32)
|
|
if resp.status == ResponseStatus.Error:
|
|
pb.write(2, resp.errorKind.uint32)
|
|
for spr in resp.providers:
|
|
pb.write(3, spr)
|
|
pb.finish()
|
|
pb.buffer
|
|
|
|
proc decode*(_: type LookupRequest, data: openArray[byte]): ProtoResult[LookupRequest] =
|
|
let pb = initProtoBuffer(data)
|
|
var
|
|
req = LookupRequest()
|
|
qt: uint32
|
|
|
|
if ?pb.getField(1, qt):
|
|
if qt > QueryType.high.uint32:
|
|
return err(ProtoError.IncorrectBlob)
|
|
req.queryType = QueryType(qt)
|
|
|
|
discard ?pb.getField(2, req.queryBytes)
|
|
ok(req)
|
|
|
|
proc decode*(
|
|
_: type LookupResponse, data: openArray[byte]
|
|
): ProtoResult[LookupResponse] =
|
|
let pb = initProtoBuffer(data)
|
|
var
|
|
resp = LookupResponse()
|
|
status: uint32
|
|
|
|
if ?pb.getField(1, status):
|
|
if status > ResponseStatus.high.uint32:
|
|
return err(ProtoError.IncorrectBlob)
|
|
resp.status = ResponseStatus(status)
|
|
|
|
if resp.status == ResponseStatus.Error:
|
|
var ek: uint32
|
|
if ?pb.getField(2, ek):
|
|
if ek > ErrorKind.high.uint32:
|
|
return err(ProtoError.IncorrectBlob)
|
|
resp.errorKind = ErrorKind(ek)
|
|
|
|
discard ?pb.getRepeatedField(3, resp.providers)
|
|
|
|
ok(resp)
|
|
|
|
proc packProviders*(
|
|
providers: seq[seq[byte]], budget_bytes: int
|
|
): Result[seq[seq[byte]], ErrorKind] =
|
|
if providers.len == 0:
|
|
error "packProviders called with no providers"
|
|
return err(ErrorKind.Internal)
|
|
|
|
let single = LookupResponse(status: ResponseStatus.Ok, providers: providers[0 ..< 1])
|
|
if single.encode().len > budget_bytes:
|
|
return err(ErrorKind.ResponseTooLarge)
|
|
|
|
var
|
|
lo = 1
|
|
hi = providers.len
|
|
while lo < hi:
|
|
let
|
|
mid = (lo + hi + 1) div 2
|
|
test = LookupResponse(status: ResponseStatus.Ok, providers: providers[0 ..< mid])
|
|
if test.encode().len <= budget_bytes:
|
|
lo = mid
|
|
else:
|
|
hi = mid - 1
|
|
|
|
ok(providers[0 ..< lo])
|