Reorganize into shared file.

This commit is contained in:
Itamar Turner-Trauring 2022-01-06 12:36:46 -05:00
parent 9c20ac8e7b
commit 90a25d0109
3 changed files with 99 additions and 62 deletions

View File

@ -24,7 +24,7 @@ from base64 import b64encode
import attr
# TODO Make sure to import Python version?
from cbor2 import loads
from cbor2 import loads, dumps
from twisted.web.http_headers import Headers
@ -32,6 +32,8 @@ from twisted.internet.defer import inlineCallbacks, returnValue, fail, Deferred
from hyperlink import DecodedURL
import treq
from .http_common import swissnum_auth_header, Secrets
class ClientException(Exception):
"""An unexpected error."""
@ -44,11 +46,6 @@ def _decode_cbor(response):
return fail(ClientException(response.code, response.phrase))
def swissnum_auth_header(swissnum): # type: (bytes) -> bytes
"""Return value for ``Authentication`` header."""
return b"Tahoe-LAFS " + b64encode(swissnum).strip()
@attr.s
class ImmutableCreateResult(object):
"""Result of creating a storage index for an immutable."""
@ -57,12 +54,75 @@ class ImmutableCreateResult(object):
allocated = attr.ib(type=Set[int])
class StorageClient(object):
"""
HTTP client that talks to the HTTP storage server.
"""
def __init__(
self, url, swissnum, treq=treq
): # type: (DecodedURL, bytes, Union[treq,StubTreq]) -> None
self._base_url = url
self._swissnum = swissnum
self._treq = treq
def _url(self, path):
"""Get a URL relative to the base URL."""
return self._base_url.click(path)
def _get_headers(self): # type: () -> Headers
"""Return the basic headers to be used by default."""
headers = Headers()
headers.addRawHeader(
"Authorization",
swissnum_auth_header(self._swissnum),
)
return headers
def _request(
self,
method,
url,
lease_renewal_secret=None,
lease_cancel_secret=None,
upload_secret=None,
**kwargs
):
"""
Like ``treq.request()``, but with optional secrets that get translated
into corresponding HTTP headers.
"""
headers = self._get_headers()
for secret, value in [
(Secrets.LEASE_RENEW, lease_renewal_secret),
(Secrets.LEASE_CANCEL, lease_cancel_secret),
(Secrets.UPLOAD, upload_secret),
]:
if value is None:
continue
headers.addRawHeader(
"X-Tahoe-Authorization",
b"%s %s" % (secret.value.encode("ascii"), b64encode(value).strip()),
)
return self._treq.request(method, url, headers=headers, **kwargs)
@inlineCallbacks
def get_version(self):
"""
Return the version metadata for the server.
"""
url = self._url("/v1/version")
response = yield self._request("GET", url, {})
decoded_response = yield _decode_cbor(response)
returnValue(decoded_response)
class StorageClientImmutables(object):
"""
APIs for interacting with immutables.
"""
def __init__(self, client): # type: (StorageClient) -> None
def __init__(self, client: StorageClient):# # type: (StorageClient) -> None
self._client = client
@inlineCallbacks
@ -87,6 +147,11 @@ class StorageClientImmutables(object):
Result fires when creating the storage index succeeded, if creating the
storage index failed the result will fire with an exception.
"""
url = self._client._url("/v1/immutable/" + str(storage_index, "ascii"))
message = dumps(
{"share-numbers": share_numbers, "allocated-size": allocated_size}
)
self._client._request("POST", )
@inlineCallbacks
def write_share_chunk(
@ -121,48 +186,3 @@ class StorageClientImmutables(object):
the HTTP protocol will be simplified, see
https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3777
"""
class StorageClient(object):
"""
HTTP client that talks to the HTTP storage server.
"""
def __init__(
self, url, swissnum, treq=treq
): # type: (DecodedURL, bytes, Union[treq,StubTreq]) -> None
self._base_url = url
self._swissnum = swissnum
self._treq = treq
def _get_headers(self): # type: () -> Headers
"""Return the basic headers to be used by default."""
headers = Headers()
headers.addRawHeader(
"Authorization",
swissnum_auth_header(self._swissnum),
)
return headers
def _request(self, method, url, secrets, **kwargs):
"""
Like ``treq.request()``, but additional argument of secrets mapping
``http_server.Secret`` to the bytes value of the secret.
"""
headers = self._get_headers()
for key, value in secrets.items():
headers.addRawHeader(
"X-Tahoe-Authorization",
b"%s %s" % (key.value.encode("ascii"), b64encode(value).strip()),
)
return self._treq.request(method, url, headers=headers, **kwargs)
@inlineCallbacks
def get_version(self):
"""
Return the version metadata for the server.
"""
url = self._base_url.click("/v1/version")
response = yield self._request("GET", url, {})
decoded_response = yield _decode_cbor(response)
returnValue(decoded_response)

View File

@ -0,0 +1,25 @@
"""
Common HTTP infrastructure for the storge server.
"""
from future.utils import PY2
if PY2:
# fmt: off
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
# fmt: on
from enum import Enum
from base64 import b64encode
def swissnum_auth_header(swissnum): # type: (bytes) -> bytes
"""Return value for ``Authentication`` header."""
return b"Tahoe-LAFS " + b64encode(swissnum).strip()
class Secrets(Enum):
"""Different kinds of secrets the client may send."""
LEASE_RENEW = "lease-renew-secret"
LEASE_CANCEL = "lease-cancel-secret"
UPLOAD = "upload-secret"

View File

@ -17,7 +17,6 @@ else:
from typing import Dict, List, Set
from functools import wraps
from enum import Enum
from base64 import b64decode
from klein import Klein
@ -28,19 +27,11 @@ import attr
from cbor2 import dumps, loads
from .server import StorageServer
from .http_client import swissnum_auth_header
from .http_common import swissnum_auth_header, Secrets
from .immutable import BucketWriter
from ..util.hashutil import timing_safe_compare
class Secrets(Enum):
"""Different kinds of secrets the client may send."""
LEASE_RENEW = "lease-renew-secret"
LEASE_CANCEL = "lease-cancel-secret"
UPLOAD = "upload-secret"
class ClientSecretsException(Exception):
"""The client did not send the appropriate secrets."""
@ -201,3 +192,4 @@ class HTTPServer(object):
# New upload.
# TODO self._storage_server.allocate_buckets() with given inputs.
# TODO add results to self._uploads.
pass