Storehouse.Batch (Storehouse v0.2.0)

Copy Markdown View Source

Uploads straight to the store, many at a time: what a frontend that is not a LiveView (React, Vue, a native app) asks of the app around the browser's PUTs. presign/2 signs a batch, register/2 checks the files once they are there. Storehouse.Plug.Presign and Storehouse.Plug.Register answer them in JSON.

Each gives one result per item, in order: some files are refused (their type, their size, the room left) and the others go ahead.

  • {:ok, upload} - presign/2: signed (Storehouse.presign_upload/4), with a :token that the browser gives back with the key to register/2.
  • {:ok, file} - register/2: checked, a Storehouse.File.
  • {:existing, file} - a file the app has already (:existing): nothing to upload, nothing kept twice.
  • {:error, code} - an atom the frontend translates: :not_accepted, :too_large, :storage_full, :invalid_checksum, :not_owner, :invalid_token, :invalid_item, :too_many, or the store's.

The token

Each upload presign/2 signs comes with a token: its key and owner, signed with :secret (the endpoint's secret_key_base, which Storehouse.Plug.Presign and Storehouse.Plug.Register take from the conn). register/2 checks only a key whose token is valid, for the same owner, and less than a day old: any other is {:error, :invalid_token}, and the file at it is left as it is. So a request can never name a file already stored (to have it deleted when it fails a check), or one of another person of the same owner.

The room

:room is shared by the batch: each file presigned (or registered) takes its size from what the next one sees, so ten files that fit one at a time but not together are not all signed. A file the app has already takes none.

Summary

Functions

The most items a batch takes, by default.

Signs uploads of items, each a map with "name", "type", "bytes" and, optionally, "checksum" (the SHA-256 the browser read, hex or Base64). String or atom keys.

Checks the files a browser uploaded (Storehouse.verify_upload/2): items are maps with "key" and "token" (those presign/2 gave) and, optionally, "name". A key without its token (another's, a file already stored) is refused with :invalid_token, and the file at it is left as it is. Two files of the same bytes in one batch are one: the second gives {:existing, first}, and its copy is deleted.

Functions

max_items()

@spec max_items() :: pos_integer()

The most items a batch takes, by default.

presign(items, opts \\ [])

@spec presign([map()], keyword()) :: {:ok, [tuple()]} | {:error, :too_many}

Signs uploads of items, each a map with "name", "type", "bytes" and, optionally, "checksum" (the SHA-256 the browser read, hex or Base64). String or atom keys.

Takes the options of Storehouse.presign_upload/4 (:accept, :max_bytes, :owner, :existing, :key, :cache, :expires_in, :adapter), with :room shared by the batch, :max_items (100): a larger batch gives {:error, :too_many}, and :secret, which signs each upload's token (required).

register(items, opts \\ [])

@spec register([map()], keyword()) :: {:ok, [tuple()]} | {:error, :too_many}

Checks the files a browser uploaded (Storehouse.verify_upload/2): items are maps with "key" and "token" (those presign/2 gave) and, optionally, "name". A key without its token (another's, a file already stored) is refused with :invalid_token, and the file at it is left as it is. Two files of the same bytes in one batch are one: the second gives {:existing, first}, and its copy is deleted.

Takes the options of Storehouse.verify_upload/2 (:accept, :max_bytes, :max_pixels, :owner, :existing, :metadata, :adapter), with :room shared by the batch (the sizes the store gives), :max_items, and :secret, as for presign/2.