Chrysostomos Nanakos fe8a3e6625
refactor(dht-proxy): unify ResponseStatus+ErrorKind into single LookupCode enum (#1473)
Signed-off-by: Chrysostomos Nanakos <chris@include.gr>
2026-06-24 19:49:02 +00:00

119 lines
3.0 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 pkg/stew/objects
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
LookupCode* {.pure.} = enum
Ok = 0
NotFound = 1
ErrDecodeFailed = 100
ErrInvalidCid = 101
ErrInternal = 200
ErrResponseTooLarge = 201
ErrTooBusy = 202
LookupRequest* = object
queryType*: QueryType
queryBytes*: seq[byte]
LookupResponse* = object
code*: LookupCode
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.code.uint32)
for spr in resp.providers:
pb.write(2, 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 not checkedEnumAssign(req.queryType, qt):
return err(ProtoError.IncorrectBlob)
discard ?pb.getField(2, req.queryBytes)
ok(req)
proc decode*(
_: type LookupResponse, data: openArray[byte]
): ProtoResult[LookupResponse] =
let pb = initProtoBuffer(data)
var
resp = LookupResponse()
codeOrd: uint32
if ?pb.getField(1, codeOrd):
if not checkedEnumAssign(resp.code, codeOrd):
return err(ProtoError.IncorrectBlob)
discard ?pb.getRepeatedField(2, resp.providers)
ok(resp)
proc packProviders*(
providers: seq[seq[byte]], budget_bytes: int
): Result[seq[seq[byte]], LookupCode] =
if providers.len == 0:
error "packProviders called with no providers"
return err(LookupCode.ErrInternal)
let single = LookupResponse(code: LookupCode.Ok, providers: providers[0 ..< 1])
if single.encode().len > budget_bytes:
return err(LookupCode.ErrResponseTooLarge)
var
lo = 1
hi = providers.len
while lo < hi:
let
mid = (lo + hi + 1) div 2
test = LookupResponse(code: LookupCode.Ok, providers: providers[0 ..< mid])
if test.encode().len <= budget_bytes:
lo = mid
else:
hi = mid - 1
ok(providers[0 ..< lo])