wmnnd

wmnnd

Hi there,

for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might find it useful as well, I decided to share it with everyone and release it as free software. You can install version 0.1.1 from hex.pm.

What can it do?

Belt allows you to store files on remote or local systems. Currently, SFTP, S3 and the local filesystem are supported as targets. Belt is especially useful if you want to target multiple storage systems that are configured at runtime (e. g. because they are user-provided).
Belt is built on top of GenStage and also supports asynchronous uploads.

Belt also offers some convenience functions such as retrieving hashes of a file.

How does it work?

Here is a little example on how to use Belt:

#Simple file upload
{:ok, config} = Belt.Provider.SFTP.new(host: "example.com", directory: "/var/files",
                                       user: "…", password: "…")
Belt.store(config, "/path/to/local/file.ext")
#=> {:ok, %Belt.FileInfo{…}}


#Asynchronous file upload
{:ok, config} = Belt.Provider.S3.new(access_key_id: "…", secret_access_key: "…",
                                     bucket: "belt-file-bucket")
{:ok, job} = Belt.store_async(config, "/path/to/local/file.ext")
#Do other things while Belt is uploading in the background
Belt.await(job)
#=> {:ok, %Belt.FileInfo{…}}

You can read more on how to install and configure Belt in the Getting Started guide.

Roadmap

Belt is definitely usable the way it is right now but I have planned several additional features such as an Ecto integration.

Feedback welcome!

Suggestions for useful new features are more than welcome.
Also, if you discover bugs or find the documentation lacking in any way, please file a bug report.

Showing Posts 1 to 10

Eiji

Eiji

@wmnnd: nice!

I have some questions:

  1. supports asynchronous uploads - is it support add upload file to queue, so we can send only x files at one time and y files on one storage type at one time
  2. Do you support/plan to upload done callback/event?
  3. Do you support/plan to create mirrors between storages?
  4. Do you support/plan to sync files/folders automatically?
  5. Do you support/plan to priorities? For example. You have a 1GB folder, but none of your project storage providers support that big space, so you want to split it automatically for x providers and then download/sync that folder to another machine automatically.
wmnnd

wmnnd OP

@Eiji: Thank you for your questions!

  1. This is not currently implemented but I will add it in the next release! You will be able to limit uploads both overall and per storage Provider.
  2. Belt has a concept of Jobs that work similar to Tasks in Elixir. You can easily use that mechanism for creating callbacks already. But I suppose it’s a feature worth exploring. How would you like to see it implemented? Would you want to be able to execute arbitrary code when a Job has been completed? Is this considered good practice in Elixir? So far I haven’t seen many examples of this kind of callback being used.
  3. Queries to multiple targets are not there yet but they are on my to-do list already.
  4. I think this would exceed the scope of a pure file storage library, but you easily implement something like this on top of Belt.
  5. This is an interesting idea but Belt does not currently keep track of the available storage size a provider has available.
hassan

hassan

Currently, SFTP, S3 and the local filesystem are supported as targets.

Cool, I’m working a lot with AWS right now, so this response may be
colored by spending a lot of time with the AWS CLI, but

  1. It seems wrong to have to specify a bucket as an option to config;
    aws s3 ls alone will give me a list of buckets, which is useful for
    further processing

  2. I may have missed it, but most aws-related tools support pulling
    secret keys from the standard ~/.aws/credentials file (and reading
    an AWS_PROFILE env var if present). Is that supported? And if
    not would you entertain a PR?

Regardless, thanks for publishing this.

wmnnd

wmnnd OP

@hassan: Thank you for your feedback!

  1. One of the ideas behind Belt is to abstract different storage providers behind a unified API. From how I see S3, only a set of credentials with a bucket is an actual valid storage destination. But maybe it’d be worth adding a wrapper for ExAws.S3.list_buckets/1 to Belt.Provider.S3. Do you think that would be worth it in order to avoid having to work directly with ExAws?
  2. Right now, there is no mechanism in Belt that pulls default configuration for any provider. However, I would like to add support for default destinations so you can also use Belt if you don’t need to configure providers at runtime. ExAws which is used by Belt already has support for reading AWS CLI files. How do you imagine using Belt with defaults read from the CLI file? My current approach would be something like this:
{:ok, config} = Belt.Provider.S3.default_config(override_options \\ [])

You could then configure defaults in your config file. A provider could also automatically try to pull common environment variables. What do you think about this idea?

Eiji

Eiji

@wmnnd:
1, 3 - nice :slight_smile:
2. I think that GenStage will be really good here, so I can listen on what you will produce, so in async mode background job could catch errors and apply callbacks on specified producer events.
4. If we are talking about Producer -> Consumers scenario then it could be good to have a stand alone process that checks differences between shared files/folders, so after example app will got event that something was changed it could call callback to (ask) sync data.

hassan

hassan

  1. One of the ideas behind Belt is to abstract different storage providers behind a unified API. From how I see S3, only a set of credentials with a bucket is an actual valid storage destination. But maybe it’d be worth adding a wrapper for ExAws.S3.list_buckets/1 to Belt.Provider.S3. Do you think that would be worth it in order to avoid having to work directly with ExAws?

Put that way, probably not a high priority :slight_smile:

  1. Right now, there is no mechanism in Belt that pulls default configuration for any provider. However, I would like to add support for default destinations so you can also use Belt if you don’t need to configure providers at runtime. ExAws which is used by Belt already has support for reading AWS CLI files. How do you imagine using Belt with defaults read from the CLI file? My current approach would be something like this:

{:ok, config} = Belt.Provider.S3.default_config(override_options \ )

You could then configure defaults in your config file. A provider could also automatically try to pull common environment variables. What do you think about this idea?

Good point, let me look at how ExAws handles config first before
offering any more useless suggestions :grinning_face:

LostKobrakai

LostKobrakai

I’m sure you did your research, but I want to share it anyways: there’s https://flysystem.thephpleague.com/, which does what you created in php. This might be interesting in terms of kick-starting other cloud providers.

wmnnd

wmnnd OP

@LostKobrakai: Cool, thank you for pointing this out!
I’ll see if I can’t get some good ideas from there :slight_smile: Is there something in particular that you like about Flysystem?

wmnnd

wmnnd OP

New version 0.1.2

I have just released a small update, version 0.1.2.
It comes with the following changes:

Changelog

  • Added Belt.delete_all/2 and Belt.delete_scope/3
  • Added default configurations with Belt.Provider.default/1
    You can now configure your own defaults with Mix.Config. Belt.Provider.S3 can also make use of the AWS environment variables and AWS CLI config (read more). Thanks to @hassan for suggesting this.

Roadmap

Next up will be:

  • Improved configuration of the maximum number concurrent jobs
  • Caching of completed job replies.
  • Ecto integration.

Feedback and suggestions regarding functionality, code quality and/or documentation are always welcome!

wmnnd

wmnnd OP

New version 0.1.4

I have just released a little update, version 0.1.4.

Changelog

  • Added Belt.Ecto.Config for storing Provider config structs with Ecto
    You can now directly store config structs in your database and Belt will take care of serializing and deserializing those structs so that no manual conversion is necessary. This is what it looks like:
#in migrations

create table(:belt_providers) do
  add :config, :map #Belt.Ecto.Config uses Ecto primitive :map
end
#in schemas

schema "belt_providers" do
  field :config, Belt.Ecto.Config
end

Roadmap

Next up will be:

  • Improved configuration of the maximum number concurrent jobs
  • Caching of completed job replies.
  • Ecto Type for storing FileInfo structs

I’m looking forward to your feedback :slight_smile:

Where Next? Top

Trending in Announcing Top

mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
quatermain
Hello, I’m sharing my plugin here in forum after some time so it has time to mature and proof yourself. I use Claude Code daily on a pr...
New
gtcode
Aloha gang, There’s a new class of AI model out from TypeSafe. Jev is their flagship model. You can learn about it here: ...
New
LostKobrakai
I’ve recently created a small library phoenix_vite integrating the vite build tooling with phoenix. It provides an igniter.installer t...
New
danschultzer
I needed something like premailer for rails, and after searching, I decided to make an easy-to-use library to handle inline styles and co...
New
kraleppa
If you’ve ever had to debug a BEAM node you know it can be a painful process. Parsing raw data, or dealing with clutter often gets in the...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
raa-ziq
Hi everyone :waving_hand: I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
AstonJ
AI tools and services seem to be the new JS framework - with new ones popping up every 5 minutes - hence it might be worth posting one of...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews