blobsets/src/blobsets/httpstores.nim

109 lines
3.2 KiB
Nim
Raw Normal View History

2019-01-20 17:14:32 +01:00
import std/asyncdispatch, std/httpclient, std/strutils, std/uri
import ../blobsets
type
HttpBlobStream = ref HttpBlobStreamObj
HttpBlobStreamObj = object of BlobStreamObj
client: AsyncHttpClient
url: string
rangePos: BiggestInt
HttpIngestStream = ref HttpIngestStreamObj
HttpIngestStreamObj = object of IngestStreamObj
client: AsyncHttpClient
url: string
ctx: Blake2b256
leaves: seq[BlobId]
leaf: string
buffOff: int
pos, nodeOffset: BiggestInt
HttpStore* = ref HttpStoreObj
HttpStoreObj = object of BlobStoreObj
url: Uri
proc httpBlobClose(s: BlobStream) =
var s = (HttpBlobStream)s
close s.client
proc setPosHttp(s: BlobStream; pos: BiggestInt) =
var s = (HttpBlobStream)s
s.rangePos = pos
proc getPosHttp(s: BlobStream): BiggestInt =
var s = (HttpBlobStream)s
s.rangePos
proc httpBlobRead(s: BlobStream; buffer: pointer; len: Natural): int =
assert(not buffer.isNil)
var s = (HttpBlobStream)s
let
headers = newHttpHeaders({"range": "bytes=$1-$2" % [ $s.rangePos, $(s.rangePos+len) ]})
resp = waitFor s.client.request(s.url, HttpGET, headers=headers)
var body = waitFor resp.body
assert(not body.isNil)
result = (int)min(body.len, len)
if result > 0:
copyMem(buffer, body[0].addr, result)
s.rangePos.inc result
proc httpOpenBlobStream(store: BlobStore; id: BlobId; size: BiggestInt; kind: BlobKind): BlobStream =
var store = HttpStore(store)
let stream = HttpBlobStream(
client: newAsyncHttpClient(),
closeImpl: httpBlobClose,
setPosImpl: setPosHttp,
getPosImpl: getPosHttp,
readImpl: httpBlobRead,
url: $((store.url / $kind) / id.toHex)
)
let resp = waitFor stream.client.head(stream.url)
assert(resp.code in {Http200, Http204}, resp.status)
stream
proc httpFinish(s: IngestStream): tuple[id: BlobId, size: BiggestInt] =
var s = HttpIngestStream(s)
let resp = waitFor s.client.request($s.url, HttpPOST)
if not resp.code.is2xx:
raiseAssert(resp.status)
result.id = toBlobId resp.headers["blob-id"]
result.size = parseBiggestInt resp.headers["blob-size"]
proc httpIngest(x: IngestStream; buf: pointer; len: Natural) =
var
s = HttpIngestStream(x)
body = newString(len)
copyMem(body[0].addr, buf, body.len)
# TODO: zero-copy
let resp = waitFor s.client.request($s.url, HttpPUT, body)
if resp.code != Http204:
raiseAssert(resp.status)
proc httpOpenIngestStream(s: BlobStore; size: BiggestInt; kind: BlobKind): IngestStream =
var store = HttpStore(s)
let
client = newAsyncHttpClient()
url = (store.url / "ingest") / $kind
headers = newHttpHeaders({"ingest-size": $size})
resp = waitFor client.request($url, HttpPOST, headers=headers)
if resp.code == Http201:
var ingestUrl = parseUri resp.headers["Location"]
if not ingestUrl.isAbsolute:
ingestUrl = combine(store.url, ingestUrl)
result = HttpIngestStream(
finishImpl: httpFinish,
ingestImpl: httpIngest,
client: client,
url: $ingestUrl,
leaf: newString(min(size.int, blobLeafSize)),
)
else:
raiseAssert(resp.status)
proc newHttpStore*(url: string): HttpStore =
HttpStore(
url: parseUri url,
openBlobStreamImpl: httpOpenBlobStream,
openIngestStreamImpl: httpOpenIngestStream,
)