diff --git a/configuration/index.html b/configuration/index.html index b5afb11f774fa491a2552de60b340f5b1c0931eb..5c85e4d3d5dd14be281e8c9ffdcbf9b930e11a61 100644 --- a/configuration/index.html +++ b/configuration/index.html @@ -464,9 +464,9 @@ <h1>Configuration</h1> -<p>Rustus is highly configurable you can configure rustus with CLI or you can use environment variables.</p> -<div class="admonition info"> -<p class="admonition-title">Info</p> +<p>Rustus is highly configurable. You can adjust it with CLI or you can use environment variables.</p> +<div class="admonition warning"> +<p class="admonition-title">Warning</p> <p>Some options can be passed only through as CLI parameters</p> </div> <div class="admonition info"> @@ -568,7 +568,7 @@ about it requested from storage to get actual path of an upload.</p> <p>Available info storages:</p> <ul> <li><code>file-info-storage</code> - stores information in files on disk;</li> -<li><code>redis-info-storage</code> - information is stored in redis;</li> +<li><code>redis-info-storage</code> - information is stored in Redis;</li> <li><code>db-info-storage</code> - information is stored in database;</li> </ul> <h3 id="file-info-storage">File info storage</h3> @@ -580,9 +580,8 @@ storing information about uploads. But if you don't plan to have many uploads, i <div class="tabbed-set tabbed-alternate" data-tabs="3:2"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">CLI</label><label for="__tabbed_3_2">ENV</label></div> <div class="tabbed-content"> <div class="tabbed-block"> -<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>rustus --force-fsync <span class="se">\</span> -<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a> --storage <span class="s2">"file-info-storage"</span> <span class="se">\</span> -<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a> --info-dir <span class="s2">"./data"</span> +<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>rustus --info-storage <span class="s2">"file-info-storage"</span> <span class="se">\</span> +<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a> --info-dir <span class="s2">"./data"</span> </code></pre></div> </div> <div class="tabbed-block"> @@ -598,18 +597,17 @@ storing information about uploads. But if you don't plan to have many uploads, i <p>Redis db is a good way to store information.</p> <div class="admonition note"> <p class="admonition-title">Note</p> -<p>If you're using redis as a cluster -you must provide connection string for master redis server. +<p>If you're using Redis as a cluster +you must provide connection string for master Redis server. Since rustus need to have latest information and it writes a lot.</p> </div> -<p><code>--info-db-dsn</code> - connection string for your redis database. -It's required if redis-info-storage is chosen.</p> +<p><code>--info-db-dsn</code> - connection string for your Redis database. +It's required if <code>redis-info-storage</code> is chosen.</p> <div class="tabbed-set tabbed-alternate" data-tabs="4:2"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">CLI</label><label for="__tabbed_4_2">ENV</label></div> <div class="tabbed-content"> <div class="tabbed-block"> -<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>rustus --force-fsync <span class="se">\</span> -<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a> --storage <span class="s2">"redis-info-storage"</span> <span class="se">\</span> -<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a> --info-db-dsn <span class="s2">"redis://localhost/0"</span> +<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>rustus --info-storage <span class="s2">"redis-info-storage"</span> <span class="se">\</span> +<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a> --info-db-dsn <span class="s2">"redis://localhost/0"</span> </code></pre></div> </div> <div class="tabbed-block"> @@ -622,9 +620,9 @@ It's required if redis-info-storage is chosen.</p> </div> </div> <h3 id="db-info-storage">DB info storage</h3> -<p>Rustus can store information about upload in database.</p> -<p>It's a good and reliable option. But rustus can't work -with replicas since it requires most recent information +<p>Rustus can store information about upload in a database.</p> +<p>It's a good and reliable option. But Rustus can't work +with replicas, since it requires the most recent information about uploads.</p> <p>You can use <code>postgresql</code>, <code>mysql</code> or even <code>sqlite</code> schemas to connect to database.</p> @@ -632,9 +630,8 @@ connect to database.</p> <div class="tabbed-set tabbed-alternate" data-tabs="5:2"><input checked="checked" id="__tabbed_5_1" name="__tabbed_5" type="radio" /><input id="__tabbed_5_2" name="__tabbed_5" type="radio" /><div class="tabbed-labels"><label for="__tabbed_5_1">CLI</label><label for="__tabbed_5_2">ENV</label></div> <div class="tabbed-content"> <div class="tabbed-block"> -<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a>rustus --force-fsync <span class="se">\</span> -<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a> --storage <span class="s2">"db-info-storage"</span> <span class="se">\</span> -<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a> --info-db-dsn <span class="s2">"postgresql://user:password@localhost/db"</span> +<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a>rustus --info-storage <span class="s2">"db-info-storage"</span> <span class="se">\</span> +<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a> --info-db-dsn <span class="s2">"postgresql://user:password@localhost/db"</span> </code></pre></div> </div> <div class="tabbed-block"> @@ -647,10 +644,10 @@ connect to database.</p> </div> </div> <h2 id="configuring-tus">Configuring TUS</h2> -<p>Since tus protocol offers extensibility you can turn off some protocol extensions.</p> +<p>Since TUS protocol offers extensibility you can turn off some protocol extensions.</p> <p>Available extensions:</p> <ul> -<li><code>getting</code> - rustus specific extension that helps you download uploaded files with get request;</li> +<li><code>getting</code> - Rustus specific extension that helps you download uploaded files with get request;</li> <li><code>creation</code> - helps you to create files (It's like a core feature you better have this enabled);</li> <li><code>termination</code> - allows you to delete uploads with DELETE request;</li> <li><code>creation-with-upload</code> - allows you to write first bytes of a file while creating;</li> @@ -659,18 +656,20 @@ connect to database.</p> <li><code>checksum</code> - allows you to verify checksum of every batch.</li> </ul> <p>You can read more about extensions on <a href="https://tus.io/protocols/resumable-upload.html#protocol-extensions">official web-site</a>.</p> -<p><code>--tus-extensions</code> - a list of enabled extensions.</p> +<p><code>--tus-extensions</code> - a list of enabled extensions. +<code>--remove-parts</code> - remove parts files after successfull concatentation (disabled by default).</p> <p>By default all extensions are enabled.</p> <div class="tabbed-set tabbed-alternate" data-tabs="6:2"><input checked="checked" id="__tabbed_6_1" name="__tabbed_6" type="radio" /><input id="__tabbed_6_2" name="__tabbed_6" type="radio" /><div class="tabbed-labels"><label for="__tabbed_6_1">CLI</label><label for="__tabbed_6_2">ENV</label></div> <div class="tabbed-content"> <div class="tabbed-block"> -<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>rustus --tus-extensions <span class="s2">"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum"</span> +<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>rustus --remove-parts <span class="se">\</span> +<a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a> --tus-extensions <span class="s2">"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum"</span> </code></pre></div> </div> <div class="tabbed-block"> <div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="nb">export</span> <span class="nv">RUSTUS_TUS_EXTENSIONS</span><span class="o">=</span><span class="s2">"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum"</span> <a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a> -<a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>rustus +<a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>rustus --remove-parts </code></pre></div> </div> </div> diff --git a/deploy/index.html b/deploy/index.html index 028bd45e294b9dce1cb8f111e30a1de1153ac050..fc77d38ddb37ae2297b56fa8ebe9fb3794ef3df8 100644 --- a/deploy/index.html +++ b/deploy/index.html @@ -456,8 +456,13 @@ <h1 id="deployment">Deployment</h1> <p>Deploying an application is always a challenge. Rustus was made to make deployment as easy as possible. -Since this application works with files so if you want to scale number of rustus instances you -have to somehow make different rustus instances to work with the same data or info directory.</p> +Since Rustus works with files you have to be careful while scaling it. All rustus instances +must have access to the same data and info storages.</p> +<div class="admonition info"> +<p class="admonition-title">Info</p> +<p>If you want to track you rustus instances with <strong>prometheus</strong> you can +always get metrics at <code>/metrics</code> endpoint.</p> +</div> <h2 id="docker-compose">Docker compose</h2> <div class="highlight"><span class="filename">docker-compose.yml</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># This is super simple configuration</span><span class="w"></span> <a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s">"3.7"</span><span class="w"></span> @@ -511,42 +516,55 @@ use config as this one:</p> <p>The main idea is that traffic that comes into nginx-proxy is routed in one of multiple rustus containers. Here I used <code>jwilder/nginx-proxy</code> but you can use other -reverse-proxies such as raw <code>nginx proxy</code> or <code>traefik</code>.</p> +reverse-proxies such as <a href="https://www.nginx.com/">Nginx proxy</a>, <a href="https://traefik.io/">Traefik</a> or <a href="https://www.envoyproxy.io/">Envoy proxy</a>.</p> <p>Now you can run multiple rustus instnaces like this.</p> <div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>docker compose up --scale <span class="nv">rustus</span><span class="o">=</span><span class="m">3</span> </code></pre></div> <p>After that you can upload files to <code>http://localhost:8080/files</code></p> <h2 id="kubernetes">Kubernetes</h2> -<p>Configuration for kubernetes is almost the same as docker. +<p>Configuration for Kubernetes is almost the same as for Docker. But the most preferable way is an official helm chart.</p> -<p>Load balancing is done by kubernetes so you just have to -create volume to mount data and info directories.</p> +<p>Load balancing is done by Kubernetes, so you just have to +create a volume to mount data and info directories.</p> <h2 id="helm">Helm</h2> <p>You can install rustus by running this set of commands: <div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>helm repo add <span class="s2">"rustus"</span> <span class="s2">"https://s3rius.github.io/rustus/helm_releases"</span> <a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>helm repo update -<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a>helm repo install <span class="s2">"rustus/rustus"</span> +<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a>helm install <span class="s2">"rustus"</span> <span class="s2">"rustus/rustus"</span> </code></pre></div></p> <h3 id="configuration">Configuration</h3> -<p>But of course it can be configured.</p> +<p>Since default deplyment may not fit you. +You can adjust it to satisfy your needs. +You can do it easily with helm.</p> +<p>At first you need to save default values on disk.</p> <div class="highlight"><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="c1"># You can download basic configuration by running</span> <a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>helm show values <span class="s2">"rustus/rustus"</span> > values.yml </code></pre></div> -<p>By editing values.yml you can configure many different options.</p> <div class="admonition warning"> <p class="admonition-title">Warning</p> <p>For production use you must provide and mount PersistentVolumeClaim in order to scale rustus.</p> <p>This helm chart has only one replica by default.</p> </div> +<p>You can read more about configuration below.</p> +<p>After you done editing <code>values.yml</code>, you can apply the configuration like this:</p> +<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>helm upgrade <span class="se">\</span> +<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a>--install <span class="se">\ </span><span class="c1"># Install chart if it's not installed</span> +<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a>--namespace rustus <span class="se">\ </span><span class="c1"># k8s namespace</span> +<a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a>--create-namespace <span class="se">\ </span><span class="c1"># Creates namespace if it doesn't exist</span> +<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a>--atomic <span class="se">\ </span><span class="c1"># Ensures that everything is deployed correctly</span> +<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a>--values <span class="s2">"values.yml"</span> <span class="se">\ </span><span class="c1"># Link to values.yml file</span> +<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="s2">"rustus"</span> <span class="se">\ </span><span class="c1"># name of a release</span> +<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="s2">"rustus/rustus"</span> <span class="c1"># Name of the chart</span> +</code></pre></div> <h3 id="persistence">Persistence</h3> -<p>You can add pvc mount by editing <code>persistence</code> section. +<p>You can add PVC mount by editing <code>persistence</code> section. The most preferable way is to create <code>PersistentVolume</code> and <code>PersistentVolumeClaim</code> before installing this chart.</p> <p>After you created claim you can apply this values file to mount your claim into rustus. -<div class="highlight"><span class="filename">values.yml</span><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="nt">persistence</span><span class="p">:</span><span class="w"></span> -<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="w"> </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"></span> -<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="w"> </span><span class="nt">existingClaim</span><span class="p">:</span><span class="w"> </span><span class="s">"rustus-pvc"</span><span class="w"></span> +<div class="highlight"><span class="filename">values.yml</span><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="nt">persistence</span><span class="p">:</span><span class="w"></span> +<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="w"> </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"></span> +<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="nt">existingClaim</span><span class="p">:</span><span class="w"> </span><span class="s">"rustus-pvc"</span><span class="w"></span> </code></pre></div></p> <div class="admonition warning"> <p class="admonition-title">Warning</p> @@ -557,12 +575,12 @@ as you specified for data storage.</p> </div> <h3 id="subcharts">Subcharts</h3> <p>For example if you want to use redis as your info storage.</p> -<div class="highlight"><span class="filename">values.yml</span><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="nt">env</span><span class="p">:</span><span class="w"></span> -<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="w"> </span><span class="nt">RUSTUS_INFO_STORAGE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">redis-info-storage</span><span class="w"></span> -<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="nt">RUSTUS_INFO_DB_DSN</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">redis://:pass@rustus-redis-master/0</span><span class="w"></span> -<a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a> -<a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a><span class="nt">redis</span><span class="p">:</span><span class="w"></span> -<a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="w"> </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"></span> +<div class="highlight"><span class="filename">values.yml</span><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="nt">env</span><span class="p">:</span><span class="w"></span> +<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="nt">RUSTUS_INFO_STORAGE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">redis-info-storage</span><span class="w"></span> +<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="nt">RUSTUS_INFO_DB_DSN</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">redis://:pass@rustus-redis-master/0</span><span class="w"></span> +<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a> +<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="nt">redis</span><span class="p">:</span><span class="w"></span> +<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="w"> </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"></span> </code></pre></div> <p><code>redis</code>, <code>postgersql</code> and <code>mysql</code> are subcharts.</p> <p>You can find information about configuration these subcharts here:</p> @@ -572,16 +590,6 @@ as you specified for data storage.</p> <li><a href="https://github.com/bitnami/charts/tree/master/bitnami/postgresql">Repo</a> for postgresql.</li> </ul> <p>In production you may ignore these subcharts to deploy your own redis or mysql or postgresql.</p> -<p>After you done editing <code>values.yml</code> you can apply the configuration like this:</p> -<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>helm upgrade <span class="se">\</span> -<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>--install <span class="se">\ </span><span class="c1"># Install chart if it's not installed</span> -<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a>--namespace rustus <span class="se">\ </span><span class="c1"># k8s namespace</span> -<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a>--create-namespace <span class="se">\ </span><span class="c1"># Creates namespace if it doesn't exist</span> -<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a>--atomic <span class="se">\ </span><span class="c1"># Ensures that everything is deployed correctly</span> -<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a>--values <span class="s2">"values.yml"</span> <span class="se">\ </span><span class="c1"># Link to values.yml file</span> -<a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="s2">"rustus"</span> <span class="se">\ </span><span class="c1"># name of a release</span> -<a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a><span class="s2">"rustus/rustus"</span> <span class="c1"># Name of the chart</span> -</code></pre></div> </article> diff --git a/index.html b/index.html index 56d620af218c9640d9a2e35f9fc1896ae08acf00..89d60b9a0c3370c1b18d21264affc6ad61140bfe 100644 --- a/index.html +++ b/index.html @@ -292,7 +292,7 @@ <li class="md-nav__item"> <a href="#using-docker" class="md-nav__link"> - Using docker + Using Docker </a> </li> @@ -410,7 +410,7 @@ <li class="md-nav__item"> <a href="#using-docker" class="md-nav__link"> - Using docker + Using Docker </a> </li> @@ -447,47 +447,49 @@ </div> <p>Rustus is a <a href="https://tus.io">TUS</a> protocol implementation that helps you handle file uploads.</p> -<p>This project has many features that makes it easy to integrate in your service.</p> +<p>This project has many features that makes it easy to integrate with your application.</p> <h2 id="installation">Installation</h2> -<p>You can install rustus by 4 different ways.</p> +<p>You can install rustus in four different ways.</p> <h3 id="from-source">From source</h3> <p>To build it from source rust must be installed. Preferred version is 1.59.0.</p> -<p><div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>git clone https://github.com/s3rius/rustus.git +<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>git clone https://github.com/s3rius/rustus.git <a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="nb">cd</span> rustus -<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>cargo install --path . --features<span class="o">=</span>all +<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>cargo install --path . --features<span class="o">=</span>all,metrics </code></pre></div> -Also you can speedup build by disabling some features.</p> +<p>Also, you can speedup build by disabling some features.</p> <p>Available features:</p> <ul> -<li><code>amqp_notifier</code> - adds amqp protocol support for notifying about upload status;</li> -<li><code>db_info_storage</code> - adds support for storing information about upload in different databases (Postgres, MySQL, SQLite);</li> -<li><code>http_notifier</code> - adds support for notifying about upload status via http protocol;</li> -<li><code>redis_info_storage</code> - adds support for storing information about upload in redis database;</li> +<li><code>amqp_notifier</code> - adds <code>AMQP</code> protocol support for notifying about upload status;</li> +<li><code>db_info_storage</code> - adds support for storing information about upload in different databases (<code>Postgres</code>, <code>MySQL</code>, <code>SQLite</code>);</li> +<li><code>http_notifier</code> - adds support for notifying about upload status via <code>HTTP</code> protocol;</li> +<li><code>redis_info_storage</code> - adds support for storing information about upload in <code>Redis</code> database;</li> <li><code>hashers</code> - adds support for checksum verification;</li> -<li><code>all</code> - enables all rustus features.</li> +<li><code>metrics</code> - adds rustus specific metrics to prometheus endpoint;</li> +<li><code>all</code> - enables all rustus features except <code>metrics</code>.</li> </ul> <p>All precompiled binaries have all features enabled.</p> <h3 id="with-cargo">With cargo</h3> -<p>If you have cargo installed maybe it would be easier to +<p>If you have cargo installed, it might be easier to install it directly from crates.io.</p> <div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>cargo install rustus --features<span class="o">=</span>all </code></pre></div> <h3 id="binaries">Binaries</h3> -<p>All precompiled binaries available on github releases page. +<p>All precompiled binaries available on Github releases page. You can download binaries from <a href="https://github.com/s3rius/rustus/releases">here</a>, unpack it and run.</p> <div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>./rustus </code></pre></div> -<p>Make sure that you download version for your cpu and os.</p> -<h3 id="using-docker">Using docker</h3> -<p>One of the most simple ways to run rustus is docker.</p> +<p>Make sure you download right version for your CPU architecture and OS.</p> +<h3 id="using-docker">Using Docker</h3> +<p>One of the most simple ways to run rustus is <code>Docker</code>.</p> <p>Rustus has two containers for each version. -1. debian based image -2. alpine based image</p> -<p>Alpine based images are more lightweight than debian</p> -<p>To run rustus you just need to run this command</p> +1. Debian based image +2. Alpine based image</p> +<p>Alpine based images are more lightweight than Debian</p> +<p>To run Rustus with Docker you just need to run this command</p> <div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>docker run --rm -p <span class="s2">"1081:1081"</span> -d s3rius/rustus --log-level <span class="s2">"DEBUG"</span> </code></pre></div> +<p>More information about Rustus docker images you can find on <a href="https://hub.docker.com/r/s3rius/rustus/">Docker hub page</a>.</p> </article> diff --git a/search/search_index.json b/search/search_index.json index f8db5d12216747ef369b67a2e84c2f386f245c4e..520cf26828f413dfa2294abe535d9c7b43ba9699 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Rustus is a TUS protocol implementation that helps you handle file uploads. This project has many features that makes it easy to integrate in your service. Installation You can install rustus by 4 different ways. From source To build it from source rust must be installed. Preferred version is 1.59.0. git clone https://github.com/s3rius/rustus.git cd rustus cargo install --path . --features = all Also you can speedup build by disabling some features. Available features: amqp_notifier - adds amqp protocol support for notifying about upload status; db_info_storage - adds support for storing information about upload in different databases (Postgres, MySQL, SQLite); http_notifier - adds support for notifying about upload status via http protocol; redis_info_storage - adds support for storing information about upload in redis database; hashers - adds support for checksum verification; all - enables all rustus features. All precompiled binaries have all features enabled. With cargo If you have cargo installed maybe it would be easier to install it directly from crates.io. cargo install rustus --features = all Binaries All precompiled binaries available on github releases page. You can download binaries from here , unpack it and run. ./rustus Make sure that you download version for your cpu and os. Using docker One of the most simple ways to run rustus is docker. Rustus has two containers for each version. 1. debian based image 2. alpine based image Alpine based images are more lightweight than debian To run rustus you just need to run this command docker run --rm -p \"1081:1081\" -d s3rius/rustus --log-level \"DEBUG\"","title":"Welcome page"},{"location":"#installation","text":"You can install rustus by 4 different ways.","title":"Installation"},{"location":"#from-source","text":"To build it from source rust must be installed. Preferred version is 1.59.0. git clone https://github.com/s3rius/rustus.git cd rustus cargo install --path . --features = all Also you can speedup build by disabling some features. Available features: amqp_notifier - adds amqp protocol support for notifying about upload status; db_info_storage - adds support for storing information about upload in different databases (Postgres, MySQL, SQLite); http_notifier - adds support for notifying about upload status via http protocol; redis_info_storage - adds support for storing information about upload in redis database; hashers - adds support for checksum verification; all - enables all rustus features. All precompiled binaries have all features enabled.","title":"From source"},{"location":"#with-cargo","text":"If you have cargo installed maybe it would be easier to install it directly from crates.io. cargo install rustus --features = all","title":"With cargo"},{"location":"#binaries","text":"All precompiled binaries available on github releases page. You can download binaries from here , unpack it and run. ./rustus Make sure that you download version for your cpu and os.","title":"Binaries"},{"location":"#using-docker","text":"One of the most simple ways to run rustus is docker. Rustus has two containers for each version. 1. debian based image 2. alpine based image Alpine based images are more lightweight than debian To run rustus you just need to run this command docker run --rm -p \"1081:1081\" -d s3rius/rustus --log-level \"DEBUG\"","title":"Using docker"},{"location":"configuration/","text":"Rustus is highly configurable you can configure rustus with CLI or you can use environment variables. Info Some options can be passed only through as CLI parameters Info Information about hooks you can find on Hooks page . Configuring server We use actix to run server. You can configure on wich host and port rustus is listenging. Also you can configure number of actix workers that handle connections. --max-body-size is the max number of bytes that users can send in request body. --url is a base URL for all tus requests. --workers by default is euqal to number of physical CPU cores. Edit it carefully. CLI ENV rustus --host \"0.0.0.0\" \\ --port 1081 \\ --workers 8 \\ --max-body-size 1000000 \\ --url \"/files\" \\ --log-level \"INFO\" export RUSTUS_SERVER_HOST = \"0.0.0.0\" export RUSTUS_SERVER_PORT = \"1081\" export RUSTUS_SERVER_WORKERS = \"8\" export RUSTUS_MAX_BODY_SIZE = \"1000000\" export RUSTUS_URL = \"/files\" export RUSTUS_LOG_LEVEL = \"INFO\" rustus Configuring data storage Info Currently only file storage is available, so if you pass to --storage parameter other than file-storage you will get an error. Also you can not pass --force-fsync through environment variables. --storage is a type of data storage to be used. --data-dir is a path to the directory where all files are stored. --dir-structure is a pattern of a directory structure inside data dir. You can use variables within the pattern. Available variables: {year} - current year; {month} - current month number from 1 to 12; {day} - current day number from 1 to 31; {hour} - hour number from 0 to 23; {minute} - minute number from 0 to 59; {env[ENV_NAME]} - environment variable where ENV_NAME is name of your variable. Note All environment variables are saved in memory during rustus startup. So you cannot change variable dynamically. Even if you change env used in structure pattern it won't change. For example if you use {env[HOSTNAME]}/{year}/{month}/{day} as your dir-structure, rustus stores files like: $ tree data data \u2514\u2500\u2500 rtus-68cb5b8746-5mgw9 \u2514\u2500\u2500 2022 \u2514\u2500\u2500 1 \u2514\u2500\u2500 8 \u251c\u2500\u2500 0bd911d4054d41c6a3ad54be67ee3e66 \u2514\u2500\u2500 5bc9c62384494c439e2a064b82a39cc6 CLI ENV rustus --force-fsync \\ --storage \"file-storage\" \\ --data-dir \"./data/\" \\ --dir-structure \"{year}/{month}/{day}\" export RUSTUS_STORAGE = \"file-storage\" export RUSTUS_DATA_DIR = \"./data/\" export RUSTUS_DIR_STRUCTURE = \"{year}/{month}/{day}\" rustus --force-fsync Configuring info storage Info storages are used to store information about file uploads. These storages must be persistent, because every time chunk is uploaded rustus updates information about upload. And when someone wants to download file, information about it requested from storage to get actual path of an upload. Available info storages: file-info-storage - stores information in files on disk; redis-info-storage - information is stored in redis; db-info-storage - information is stored in database; File info storage file info storage stores information in files on disk. It's default info storage. Every download has it's own associated file. All .info files stored in flat structure so it's the least preferable way of storing information about uploads. But if you don't plan to have many uploads, it may fit well. --info-dir - directory where all .info file will be stored (default is ./data ). CLI ENV rustus --force-fsync \\ --storage \"file-info-storage\" \\ --info-dir \"./data\" export RUSTUS_INFO_STORAGE = \"file-info-storage\" export RUSTUS_INFO_DIR = \"./data\" rustus Redis info storage Redis db is a good way to store information. Note If you're using redis as a cluster you must provide connection string for master redis server. Since rustus need to have latest information and it writes a lot. --info-db-dsn - connection string for your redis database. It's required if redis-info-storage is chosen. CLI ENV rustus --force-fsync \\ --storage \"redis-info-storage\" \\ --info-db-dsn \"redis://localhost/0\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"redis://localhost\" rustus DB info storage Rustus can store information about upload in database. It's a good and reliable option. But rustus can't work with replicas since it requires most recent information about uploads. You can use postgresql , mysql or even sqlite schemas to connect to database. --info-db-dsn - connection string for your database. CLI ENV rustus --force-fsync \\ --storage \"db-info-storage\" \\ --info-db-dsn \"postgresql://user:password@localhost/db\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"postgresql://user:password@localhost/db\" rustus Configuring TUS Since tus protocol offers extensibility you can turn off some protocol extensions. Available extensions: getting - rustus specific extension that helps you download uploaded files with get request; creation - helps you to create files (It's like a core feature you better have this enabled); termination - allows you to delete uploads with DELETE request; creation-with-upload - allows you to write first bytes of a file while creating; creation-defer-length - allows you to create file without specifying file length; concatenation - allows you to concatenate finished partial uploads. checksum - allows you to verify checksum of every batch. You can read more about extensions on official web-site . --tus-extensions - a list of enabled extensions. By default all extensions are enabled. CLI ENV rustus --tus-extensions \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" export RUSTUS_TUS_EXTENSIONS = \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" rustus","title":"Configuration"},{"location":"configuration/#configuring-server","text":"We use actix to run server. You can configure on wich host and port rustus is listenging. Also you can configure number of actix workers that handle connections. --max-body-size is the max number of bytes that users can send in request body. --url is a base URL for all tus requests. --workers by default is euqal to number of physical CPU cores. Edit it carefully. CLI ENV rustus --host \"0.0.0.0\" \\ --port 1081 \\ --workers 8 \\ --max-body-size 1000000 \\ --url \"/files\" \\ --log-level \"INFO\" export RUSTUS_SERVER_HOST = \"0.0.0.0\" export RUSTUS_SERVER_PORT = \"1081\" export RUSTUS_SERVER_WORKERS = \"8\" export RUSTUS_MAX_BODY_SIZE = \"1000000\" export RUSTUS_URL = \"/files\" export RUSTUS_LOG_LEVEL = \"INFO\" rustus","title":"Configuring server"},{"location":"configuration/#configuring-data-storage","text":"Info Currently only file storage is available, so if you pass to --storage parameter other than file-storage you will get an error. Also you can not pass --force-fsync through environment variables. --storage is a type of data storage to be used. --data-dir is a path to the directory where all files are stored. --dir-structure is a pattern of a directory structure inside data dir. You can use variables within the pattern. Available variables: {year} - current year; {month} - current month number from 1 to 12; {day} - current day number from 1 to 31; {hour} - hour number from 0 to 23; {minute} - minute number from 0 to 59; {env[ENV_NAME]} - environment variable where ENV_NAME is name of your variable. Note All environment variables are saved in memory during rustus startup. So you cannot change variable dynamically. Even if you change env used in structure pattern it won't change. For example if you use {env[HOSTNAME]}/{year}/{month}/{day} as your dir-structure, rustus stores files like: $ tree data data \u2514\u2500\u2500 rtus-68cb5b8746-5mgw9 \u2514\u2500\u2500 2022 \u2514\u2500\u2500 1 \u2514\u2500\u2500 8 \u251c\u2500\u2500 0bd911d4054d41c6a3ad54be67ee3e66 \u2514\u2500\u2500 5bc9c62384494c439e2a064b82a39cc6 CLI ENV rustus --force-fsync \\ --storage \"file-storage\" \\ --data-dir \"./data/\" \\ --dir-structure \"{year}/{month}/{day}\" export RUSTUS_STORAGE = \"file-storage\" export RUSTUS_DATA_DIR = \"./data/\" export RUSTUS_DIR_STRUCTURE = \"{year}/{month}/{day}\" rustus --force-fsync","title":"Configuring data storage"},{"location":"configuration/#configuring-info-storage","text":"Info storages are used to store information about file uploads. These storages must be persistent, because every time chunk is uploaded rustus updates information about upload. And when someone wants to download file, information about it requested from storage to get actual path of an upload. Available info storages: file-info-storage - stores information in files on disk; redis-info-storage - information is stored in redis; db-info-storage - information is stored in database;","title":"Configuring info storage"},{"location":"configuration/#file-info-storage","text":"file info storage stores information in files on disk. It's default info storage. Every download has it's own associated file. All .info files stored in flat structure so it's the least preferable way of storing information about uploads. But if you don't plan to have many uploads, it may fit well. --info-dir - directory where all .info file will be stored (default is ./data ). CLI ENV rustus --force-fsync \\ --storage \"file-info-storage\" \\ --info-dir \"./data\" export RUSTUS_INFO_STORAGE = \"file-info-storage\" export RUSTUS_INFO_DIR = \"./data\" rustus","title":"File info storage"},{"location":"configuration/#redis-info-storage","text":"Redis db is a good way to store information. Note If you're using redis as a cluster you must provide connection string for master redis server. Since rustus need to have latest information and it writes a lot. --info-db-dsn - connection string for your redis database. It's required if redis-info-storage is chosen. CLI ENV rustus --force-fsync \\ --storage \"redis-info-storage\" \\ --info-db-dsn \"redis://localhost/0\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"redis://localhost\" rustus","title":"Redis info storage"},{"location":"configuration/#db-info-storage","text":"Rustus can store information about upload in database. It's a good and reliable option. But rustus can't work with replicas since it requires most recent information about uploads. You can use postgresql , mysql or even sqlite schemas to connect to database. --info-db-dsn - connection string for your database. CLI ENV rustus --force-fsync \\ --storage \"db-info-storage\" \\ --info-db-dsn \"postgresql://user:password@localhost/db\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"postgresql://user:password@localhost/db\" rustus","title":"DB info storage"},{"location":"configuration/#configuring-tus","text":"Since tus protocol offers extensibility you can turn off some protocol extensions. Available extensions: getting - rustus specific extension that helps you download uploaded files with get request; creation - helps you to create files (It's like a core feature you better have this enabled); termination - allows you to delete uploads with DELETE request; creation-with-upload - allows you to write first bytes of a file while creating; creation-defer-length - allows you to create file without specifying file length; concatenation - allows you to concatenate finished partial uploads. checksum - allows you to verify checksum of every batch. You can read more about extensions on official web-site . --tus-extensions - a list of enabled extensions. By default all extensions are enabled. CLI ENV rustus --tus-extensions \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" export RUSTUS_TUS_EXTENSIONS = \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" rustus","title":"Configuring TUS"},{"location":"deploy/","text":"Deployment Deploying an application is always a challenge. Rustus was made to make deployment as easy as possible. Since this application works with files so if you want to scale number of rustus instances you have to somehow make different rustus instances to work with the same data or info directory. Docker compose docker-compose.yml # This is super simple configuration version : \"3.7\" services : rustus : image : s3rius/rustus volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data volumes : rustus_data_volume : After running docker compose up you will see rustus startup logs. If you want to deploy multiple rustus instances you can simply use config as this one: docker-compose.yml version : \"3.7\" services : proxy : image : jwilder/nginx-proxy:alpine container_name : proxy # Actual proxy ports. ports : - 8080:80 volumes : # This thing helps to locate containers # within this composition to generate nginx config. - /var/run/docker.sock:/tmp/docker.sock:ro rustus : image : s3rius/rustus ports : # Ports definition # To generate correct nginx config. - 1081 volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data environment : # Idk why but without this variable # load balancing with jwilder/nginx-proxy doesn't work. VIRTUAL_HOST : localhost volumes : rustus_data_volume : # This is named volume The main idea is that traffic that comes into nginx-proxy is routed in one of multiple rustus containers. Here I used jwilder/nginx-proxy but you can use other reverse-proxies such as raw nginx proxy or traefik . Now you can run multiple rustus instnaces like this. docker compose up --scale rustus = 3 After that you can upload files to http://localhost:8080/files Kubernetes Configuration for kubernetes is almost the same as docker. But the most preferable way is an official helm chart. Load balancing is done by kubernetes so you just have to create volume to mount data and info directories. Helm You can install rustus by running this set of commands: helm repo add \"rustus\" \"https://s3rius.github.io/rustus/helm_releases\" helm repo update helm repo install \"rustus/rustus\" Configuration But of course it can be configured. # You can download basic configuration by running helm show values \"rustus/rustus\" > values.yml By editing values.yml you can configure many different options. Warning For production use you must provide and mount PersistentVolumeClaim in order to scale rustus. This helm chart has only one replica by default. Persistence You can add pvc mount by editing persistence section. The most preferable way is to create PersistentVolume and PersistentVolumeClaim before installing this chart. After you created claim you can apply this values file to mount your claim into rustus. values.yml persistence : enabled : true existingClaim : \"rustus-pvc\" Warning Currently there's no ability to create multiple mounts and if you use file info storage you must specify the same direcotry as you specified for data storage. But it would be better to use other type of info-storage. Subcharts For example if you want to use redis as your info storage. values.yml env : RUSTUS_INFO_STORAGE : redis-info-storage RUSTUS_INFO_DB_DSN : redis://:pass@rustus-redis-master/0 redis : enabled : true redis , postgersql and mysql are subcharts. You can find information about configuration these subcharts here: Repo for redis; Repo for mysql; Repo for postgresql. In production you may ignore these subcharts to deploy your own redis or mysql or postgresql. After you done editing values.yml you can apply the configuration like this: helm upgrade \\ --install \\ # Install chart if it's not installed --namespace rustus \\ # k8s namespace --create-namespace \\ # Creates namespace if it doesn't exist --atomic \\ # Ensures that everything is deployed correctly --values \"values.yml\" \\ # Link to values.yml file \"rustus\" \\ # name of a release \"rustus/rustus\" # Name of the chart","title":"Deployment"},{"location":"deploy/#deployment","text":"Deploying an application is always a challenge. Rustus was made to make deployment as easy as possible. Since this application works with files so if you want to scale number of rustus instances you have to somehow make different rustus instances to work with the same data or info directory.","title":"Deployment"},{"location":"deploy/#docker-compose","text":"docker-compose.yml # This is super simple configuration version : \"3.7\" services : rustus : image : s3rius/rustus volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data volumes : rustus_data_volume : After running docker compose up you will see rustus startup logs. If you want to deploy multiple rustus instances you can simply use config as this one: docker-compose.yml version : \"3.7\" services : proxy : image : jwilder/nginx-proxy:alpine container_name : proxy # Actual proxy ports. ports : - 8080:80 volumes : # This thing helps to locate containers # within this composition to generate nginx config. - /var/run/docker.sock:/tmp/docker.sock:ro rustus : image : s3rius/rustus ports : # Ports definition # To generate correct nginx config. - 1081 volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data environment : # Idk why but without this variable # load balancing with jwilder/nginx-proxy doesn't work. VIRTUAL_HOST : localhost volumes : rustus_data_volume : # This is named volume The main idea is that traffic that comes into nginx-proxy is routed in one of multiple rustus containers. Here I used jwilder/nginx-proxy but you can use other reverse-proxies such as raw nginx proxy or traefik . Now you can run multiple rustus instnaces like this. docker compose up --scale rustus = 3 After that you can upload files to http://localhost:8080/files","title":"Docker compose"},{"location":"deploy/#kubernetes","text":"Configuration for kubernetes is almost the same as docker. But the most preferable way is an official helm chart. Load balancing is done by kubernetes so you just have to create volume to mount data and info directories.","title":"Kubernetes"},{"location":"deploy/#helm","text":"You can install rustus by running this set of commands: helm repo add \"rustus\" \"https://s3rius.github.io/rustus/helm_releases\" helm repo update helm repo install \"rustus/rustus\"","title":"Helm"},{"location":"deploy/#configuration","text":"But of course it can be configured. # You can download basic configuration by running helm show values \"rustus/rustus\" > values.yml By editing values.yml you can configure many different options. Warning For production use you must provide and mount PersistentVolumeClaim in order to scale rustus. This helm chart has only one replica by default.","title":"Configuration"},{"location":"deploy/#persistence","text":"You can add pvc mount by editing persistence section. The most preferable way is to create PersistentVolume and PersistentVolumeClaim before installing this chart. After you created claim you can apply this values file to mount your claim into rustus. values.yml persistence : enabled : true existingClaim : \"rustus-pvc\" Warning Currently there's no ability to create multiple mounts and if you use file info storage you must specify the same direcotry as you specified for data storage. But it would be better to use other type of info-storage.","title":"Persistence"},{"location":"deploy/#subcharts","text":"For example if you want to use redis as your info storage. values.yml env : RUSTUS_INFO_STORAGE : redis-info-storage RUSTUS_INFO_DB_DSN : redis://:pass@rustus-redis-master/0 redis : enabled : true redis , postgersql and mysql are subcharts. You can find information about configuration these subcharts here: Repo for redis; Repo for mysql; Repo for postgresql. In production you may ignore these subcharts to deploy your own redis or mysql or postgresql. After you done editing values.yml you can apply the configuration like this: helm upgrade \\ --install \\ # Install chart if it's not installed --namespace rustus \\ # k8s namespace --create-namespace \\ # Creates namespace if it doesn't exist --atomic \\ # Ensures that everything is deployed correctly --values \"values.yml\" \\ # Link to values.yml file \"rustus\" \\ # name of a release \"rustus/rustus\" # Name of the chart","title":"Subcharts"},{"location":"hooks/","text":"Rustus can notify about uploads using hooks. This is useful when you integrate rustus in your architecture. Apps can keep track of every upload using this feature. Rustus has different event types for different moments of an upload's lifecycle. pre-create - This hook means that someone wants to create an upload; post-create - someone successfully created an upload; post-receive - someone uploaded a new part of an upload; post-terminate - someone deleted upload; post-finish - someone finished uploading file. Note Pre-create hook is very important. If at least one of hooks fails, upload is canceled. But AMQP hooks won't cancel the upload, since it's non blocking type of hooks. You can disable some hooks by using --hooks parameter. CLI ENV rustus --hooks \"pre-create,post-create,post-receive,post-terminate,post-finish\" export RUSTUS_HOOKS = \"pre-create,post-create,post-receive,post-terminate,post-finish\" rustus Fomat Information about every hook using JSON format. Format can be configured using --hooks-format parameter or RUSTUS_HOOKS_FORMAT environment variable. Available formats: default tusd default tusd { \"upload\" : { \"id\" : \"\" , \"offset\" : 0 , \"length\" : 39729945 , \"path\" : null , \"created_at\" : 1641620821 , \"deferred_size\" : false , \"metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" } }, \"request\" : { \"URI\" : \"/files\" , \"method\" : \"POST\" , \"remote_addr\" : \"127.0.0.1\" , \"headers\" : { \"accept-encoding\" : \"gzip, deflate\" , \"connection\" : \"keep-alive\" , \"host\" : \"localhost:1081\" , \"upload-metadata\" : \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" , \"tus-resumable\" : \"1.0.0\" , \"content-length\" : \"0\" , \"upload-length\" : \"39729945\" , \"user-agent\" : \"python-requests/2.26.0\" , \"accept\" : \"*/*\" } } } { \"Upload\" : { \"ID\" : \"\" , \"Offset\" : 0 , \"Size\" : 39729945 , \"IsFinal\" : true , \"IsPartial\" : false , \"PartialUploads\" : null , \"SizeIsDeferred\" : false , \"Metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" }, \"Storage\" : { \"Type\" : \"filestore\" , \"Path\" : null } }, \"HTTPRequest\" : { \"URI\" : \"/files\" , \"Method\" : \"POST\" , \"RemoteAddr\" : \"127.0.0.1\" , \"Header\" : { \"host\" : [ \"localhost:1081\" ], \"user-agent\" : [ \"python-requests/2.26.0\" ], \"accept\" : [ \"*/*\" ], \"content-length\" : [ \"0\" ], \"upload-metadata\" : [ \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" ], \"connection\" : [ \"keep-alive\" ], \"tus-resumable\" : [ \"1.0.0\" ], \"upload-length\" : [ \"39729945\" ], \"accept-encoding\" : [ \"gzip, deflate\" ] } } } Hook types Rustus offers multiple types of Hooks. We'll take a brief look on each type. File hooks Rustus can work with two types of file hooks. Single file hook Hooks directory The main difference is that in case if use single file hook, hook name is passed as a command line argument to an executable file, but if you use hooks directory then hook name is used to determine a file to call. Let's take a look at the examples. Parameters: * --hooks-file - path to an executable file; * --hooks-dir - path to a directory with executable files. single_file_hook.sh #!/bin/bash # Hook name would be \"pre-create\", \"post-create\" and so on. HOOK_NAME = \" $1 \" HOOK_INFO = \" $2 \" MEME = \" $( echo \" $HOOK_INFO \" | jq \".upload .metadata .meme\" | xargs ) \" # Here we check if name in metadata is equal to pepe. if [[ $MEME = \"pepe\" ]] ; then echo \"This meme isn't allowed\" 1 > & 2 ; exit 1 fi As you can see it uses first CLI parameter as a hook name and all hook data is received from the second one. Let's make it executable and make rustus use this hook. CLI ENV chmod +x \"hooks/single_file_hook.sh\" rustus --hooks-file \"hooks/single_file_hook.sh\" chmod +x \"hooks/single_file_hook.sh\" export RUSTUS_HOOKS_FILE = \"hooks/single_file_hook.sh\" rustus If you would like to use directory hooks you must create directory with the following structure: hooks \u251c\u2500\u2500 post-create \u251c\u2500\u2500 post-finish \u251c\u2500\u2500 post-receive \u251c\u2500\u2500 post-terminate \u2514\u2500\u2500 pre-create Warning If some hook file isn't found, rustus throws an error. In case with pre-create hook it can be fatal. Http Hooks Http hooks use HTTP to send POST requests to some endpoint. Configuration parameters: --hooks-http-proxy-headers - list of headers to proxy (separated by commas) to listener's endpoint; --hooks-http-urls - list of absolute urls to send request to (separated by commas). Note Hook names are passed as header called Hook-Name . CLI ENV rustus --hooks-http-urls \"https://httpbin.org/post\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"https://httpbin.org/post\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus Example application To be more verbose let's create simple web server that handles uploads using FastAPI . At first we need to install dependencies using pip. pip install fastapi uvicorn server.py from fastapi import FastAPI , Header , HTTPException from typing import Optional app = FastAPI () @app . post ( \"/hooks\" ) def hook ( authorization : Optional [ str ] = Header ( None ), hook_name : Optional [ str ] = Header ( None ), ): print ( f \"Received: { hook_name } \" ) if authorization != \"Bearer jwt\" : raise HTTPException ( 401 ) return None Now we can run this server using uvicorn. uvicorn server:app --port 8080 Let's configure rustus to use this server as a hook reciever. CLI ENV rustus --hooks-http-urls \"http://localhost:8000/hooks\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"http://localhost:8000/hooks\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus That's it. AMQP hooks AMQP hooks are used to store information about uploads using RabbitMQ. Configuration parameters: --hooks-amqp-url - connection string to RabbitMQ; --hooks-amqp-queues-prefix - prefix for queues for every event queue; --hooks-amqp-exchange - name of exchange to use. This hook will send every message in an exchange with routing keys like queues names. Queues are named like {prefix}.{event type} . Eg rustus.pre-create and so on. Warning Since we can't really track message delivery and responses Rustus doesn't stop in any case. CLI ENV rustus --hooks-amqp-url \"amqp://guest:guest@localhost:5672\" \\ --hooks-amqp-queues-prefix \"rustus_queue\" \\ --hooks-amqp-exchange \"rustus\" export RUSTUS_HOOKS_AMQP_URL = \"amqp://guest:guest@localhost:5672\" export RUSTUS_HOOKS_AMQP_QUEUES_PREFIX = \"rustus_queue\" export RUSTUS_HOOKS_AMQP_EXCHANGE = \"rustus\" rustus","title":"Setting up hooks"},{"location":"hooks/#fomat","text":"Information about every hook using JSON format. Format can be configured using --hooks-format parameter or RUSTUS_HOOKS_FORMAT environment variable. Available formats: default tusd default tusd { \"upload\" : { \"id\" : \"\" , \"offset\" : 0 , \"length\" : 39729945 , \"path\" : null , \"created_at\" : 1641620821 , \"deferred_size\" : false , \"metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" } }, \"request\" : { \"URI\" : \"/files\" , \"method\" : \"POST\" , \"remote_addr\" : \"127.0.0.1\" , \"headers\" : { \"accept-encoding\" : \"gzip, deflate\" , \"connection\" : \"keep-alive\" , \"host\" : \"localhost:1081\" , \"upload-metadata\" : \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" , \"tus-resumable\" : \"1.0.0\" , \"content-length\" : \"0\" , \"upload-length\" : \"39729945\" , \"user-agent\" : \"python-requests/2.26.0\" , \"accept\" : \"*/*\" } } } { \"Upload\" : { \"ID\" : \"\" , \"Offset\" : 0 , \"Size\" : 39729945 , \"IsFinal\" : true , \"IsPartial\" : false , \"PartialUploads\" : null , \"SizeIsDeferred\" : false , \"Metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" }, \"Storage\" : { \"Type\" : \"filestore\" , \"Path\" : null } }, \"HTTPRequest\" : { \"URI\" : \"/files\" , \"Method\" : \"POST\" , \"RemoteAddr\" : \"127.0.0.1\" , \"Header\" : { \"host\" : [ \"localhost:1081\" ], \"user-agent\" : [ \"python-requests/2.26.0\" ], \"accept\" : [ \"*/*\" ], \"content-length\" : [ \"0\" ], \"upload-metadata\" : [ \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" ], \"connection\" : [ \"keep-alive\" ], \"tus-resumable\" : [ \"1.0.0\" ], \"upload-length\" : [ \"39729945\" ], \"accept-encoding\" : [ \"gzip, deflate\" ] } } }","title":"Fomat"},{"location":"hooks/#hook-types","text":"Rustus offers multiple types of Hooks. We'll take a brief look on each type.","title":"Hook types"},{"location":"hooks/#file-hooks","text":"Rustus can work with two types of file hooks. Single file hook Hooks directory The main difference is that in case if use single file hook, hook name is passed as a command line argument to an executable file, but if you use hooks directory then hook name is used to determine a file to call. Let's take a look at the examples. Parameters: * --hooks-file - path to an executable file; * --hooks-dir - path to a directory with executable files. single_file_hook.sh #!/bin/bash # Hook name would be \"pre-create\", \"post-create\" and so on. HOOK_NAME = \" $1 \" HOOK_INFO = \" $2 \" MEME = \" $( echo \" $HOOK_INFO \" | jq \".upload .metadata .meme\" | xargs ) \" # Here we check if name in metadata is equal to pepe. if [[ $MEME = \"pepe\" ]] ; then echo \"This meme isn't allowed\" 1 > & 2 ; exit 1 fi As you can see it uses first CLI parameter as a hook name and all hook data is received from the second one. Let's make it executable and make rustus use this hook. CLI ENV chmod +x \"hooks/single_file_hook.sh\" rustus --hooks-file \"hooks/single_file_hook.sh\" chmod +x \"hooks/single_file_hook.sh\" export RUSTUS_HOOKS_FILE = \"hooks/single_file_hook.sh\" rustus If you would like to use directory hooks you must create directory with the following structure: hooks \u251c\u2500\u2500 post-create \u251c\u2500\u2500 post-finish \u251c\u2500\u2500 post-receive \u251c\u2500\u2500 post-terminate \u2514\u2500\u2500 pre-create Warning If some hook file isn't found, rustus throws an error. In case with pre-create hook it can be fatal.","title":"File hooks"},{"location":"hooks/#http-hooks","text":"Http hooks use HTTP to send POST requests to some endpoint. Configuration parameters: --hooks-http-proxy-headers - list of headers to proxy (separated by commas) to listener's endpoint; --hooks-http-urls - list of absolute urls to send request to (separated by commas). Note Hook names are passed as header called Hook-Name . CLI ENV rustus --hooks-http-urls \"https://httpbin.org/post\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"https://httpbin.org/post\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus","title":"Http Hooks"},{"location":"hooks/#example-application","text":"To be more verbose let's create simple web server that handles uploads using FastAPI . At first we need to install dependencies using pip. pip install fastapi uvicorn server.py from fastapi import FastAPI , Header , HTTPException from typing import Optional app = FastAPI () @app . post ( \"/hooks\" ) def hook ( authorization : Optional [ str ] = Header ( None ), hook_name : Optional [ str ] = Header ( None ), ): print ( f \"Received: { hook_name } \" ) if authorization != \"Bearer jwt\" : raise HTTPException ( 401 ) return None Now we can run this server using uvicorn. uvicorn server:app --port 8080 Let's configure rustus to use this server as a hook reciever. CLI ENV rustus --hooks-http-urls \"http://localhost:8000/hooks\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"http://localhost:8000/hooks\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus That's it.","title":"Example application"},{"location":"hooks/#amqp-hooks","text":"AMQP hooks are used to store information about uploads using RabbitMQ. Configuration parameters: --hooks-amqp-url - connection string to RabbitMQ; --hooks-amqp-queues-prefix - prefix for queues for every event queue; --hooks-amqp-exchange - name of exchange to use. This hook will send every message in an exchange with routing keys like queues names. Queues are named like {prefix}.{event type} . Eg rustus.pre-create and so on. Warning Since we can't really track message delivery and responses Rustus doesn't stop in any case. CLI ENV rustus --hooks-amqp-url \"amqp://guest:guest@localhost:5672\" \\ --hooks-amqp-queues-prefix \"rustus_queue\" \\ --hooks-amqp-exchange \"rustus\" export RUSTUS_HOOKS_AMQP_URL = \"amqp://guest:guest@localhost:5672\" export RUSTUS_HOOKS_AMQP_QUEUES_PREFIX = \"rustus_queue\" export RUSTUS_HOOKS_AMQP_EXCHANGE = \"rustus\" rustus","title":"AMQP hooks"}]} \ No newline at end of file +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Rustus is a TUS protocol implementation that helps you handle file uploads. This project has many features that makes it easy to integrate with your application. Installation You can install rustus in four different ways. From source To build it from source rust must be installed. Preferred version is 1.59.0. git clone https://github.com/s3rius/rustus.git cd rustus cargo install --path . --features = all,metrics Also, you can speedup build by disabling some features. Available features: amqp_notifier - adds AMQP protocol support for notifying about upload status; db_info_storage - adds support for storing information about upload in different databases ( Postgres , MySQL , SQLite ); http_notifier - adds support for notifying about upload status via HTTP protocol; redis_info_storage - adds support for storing information about upload in Redis database; hashers - adds support for checksum verification; metrics - adds rustus specific metrics to prometheus endpoint; all - enables all rustus features except metrics . All precompiled binaries have all features enabled. With cargo If you have cargo installed, it might be easier to install it directly from crates.io. cargo install rustus --features = all Binaries All precompiled binaries available on Github releases page. You can download binaries from here , unpack it and run. ./rustus Make sure you download right version for your CPU architecture and OS. Using Docker One of the most simple ways to run rustus is Docker . Rustus has two containers for each version. 1. Debian based image 2. Alpine based image Alpine based images are more lightweight than Debian To run Rustus with Docker you just need to run this command docker run --rm -p \"1081:1081\" -d s3rius/rustus --log-level \"DEBUG\" More information about Rustus docker images you can find on Docker hub page .","title":"Welcome page"},{"location":"#installation","text":"You can install rustus in four different ways.","title":"Installation"},{"location":"#from-source","text":"To build it from source rust must be installed. Preferred version is 1.59.0. git clone https://github.com/s3rius/rustus.git cd rustus cargo install --path . --features = all,metrics Also, you can speedup build by disabling some features. Available features: amqp_notifier - adds AMQP protocol support for notifying about upload status; db_info_storage - adds support for storing information about upload in different databases ( Postgres , MySQL , SQLite ); http_notifier - adds support for notifying about upload status via HTTP protocol; redis_info_storage - adds support for storing information about upload in Redis database; hashers - adds support for checksum verification; metrics - adds rustus specific metrics to prometheus endpoint; all - enables all rustus features except metrics . All precompiled binaries have all features enabled.","title":"From source"},{"location":"#with-cargo","text":"If you have cargo installed, it might be easier to install it directly from crates.io. cargo install rustus --features = all","title":"With cargo"},{"location":"#binaries","text":"All precompiled binaries available on Github releases page. You can download binaries from here , unpack it and run. ./rustus Make sure you download right version for your CPU architecture and OS.","title":"Binaries"},{"location":"#using-docker","text":"One of the most simple ways to run rustus is Docker . Rustus has two containers for each version. 1. Debian based image 2. Alpine based image Alpine based images are more lightweight than Debian To run Rustus with Docker you just need to run this command docker run --rm -p \"1081:1081\" -d s3rius/rustus --log-level \"DEBUG\" More information about Rustus docker images you can find on Docker hub page .","title":"Using Docker"},{"location":"configuration/","text":"Rustus is highly configurable. You can adjust it with CLI or you can use environment variables. Warning Some options can be passed only through as CLI parameters Info Information about hooks you can find on Hooks page . Configuring server We use actix to run server. You can configure on wich host and port rustus is listenging. Also you can configure number of actix workers that handle connections. --max-body-size is the max number of bytes that users can send in request body. --url is a base URL for all tus requests. --workers by default is euqal to number of physical CPU cores. Edit it carefully. CLI ENV rustus --host \"0.0.0.0\" \\ --port 1081 \\ --workers 8 \\ --max-body-size 1000000 \\ --url \"/files\" \\ --log-level \"INFO\" export RUSTUS_SERVER_HOST = \"0.0.0.0\" export RUSTUS_SERVER_PORT = \"1081\" export RUSTUS_SERVER_WORKERS = \"8\" export RUSTUS_MAX_BODY_SIZE = \"1000000\" export RUSTUS_URL = \"/files\" export RUSTUS_LOG_LEVEL = \"INFO\" rustus Configuring data storage Info Currently only file storage is available, so if you pass to --storage parameter other than file-storage you will get an error. Also you can not pass --force-fsync through environment variables. --storage is a type of data storage to be used. --data-dir is a path to the directory where all files are stored. --dir-structure is a pattern of a directory structure inside data dir. You can use variables within the pattern. Available variables: {year} - current year; {month} - current month number from 1 to 12; {day} - current day number from 1 to 31; {hour} - hour number from 0 to 23; {minute} - minute number from 0 to 59; {env[ENV_NAME]} - environment variable where ENV_NAME is name of your variable. Note All environment variables are saved in memory during rustus startup. So you cannot change variable dynamically. Even if you change env used in structure pattern it won't change. For example if you use {env[HOSTNAME]}/{year}/{month}/{day} as your dir-structure, rustus stores files like: $ tree data data \u2514\u2500\u2500 rtus-68cb5b8746-5mgw9 \u2514\u2500\u2500 2022 \u2514\u2500\u2500 1 \u2514\u2500\u2500 8 \u251c\u2500\u2500 0bd911d4054d41c6a3ad54be67ee3e66 \u2514\u2500\u2500 5bc9c62384494c439e2a064b82a39cc6 CLI ENV rustus --force-fsync \\ --storage \"file-storage\" \\ --data-dir \"./data/\" \\ --dir-structure \"{year}/{month}/{day}\" export RUSTUS_STORAGE = \"file-storage\" export RUSTUS_DATA_DIR = \"./data/\" export RUSTUS_DIR_STRUCTURE = \"{year}/{month}/{day}\" rustus --force-fsync Configuring info storage Info storages are used to store information about file uploads. These storages must be persistent, because every time chunk is uploaded rustus updates information about upload. And when someone wants to download file, information about it requested from storage to get actual path of an upload. Available info storages: file-info-storage - stores information in files on disk; redis-info-storage - information is stored in Redis; db-info-storage - information is stored in database; File info storage file info storage stores information in files on disk. It's default info storage. Every download has it's own associated file. All .info files stored in flat structure so it's the least preferable way of storing information about uploads. But if you don't plan to have many uploads, it may fit well. --info-dir - directory where all .info file will be stored (default is ./data ). CLI ENV rustus --info-storage \"file-info-storage\" \\ --info-dir \"./data\" export RUSTUS_INFO_STORAGE = \"file-info-storage\" export RUSTUS_INFO_DIR = \"./data\" rustus Redis info storage Redis db is a good way to store information. Note If you're using Redis as a cluster you must provide connection string for master Redis server. Since rustus need to have latest information and it writes a lot. --info-db-dsn - connection string for your Redis database. It's required if redis-info-storage is chosen. CLI ENV rustus --info-storage \"redis-info-storage\" \\ --info-db-dsn \"redis://localhost/0\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"redis://localhost\" rustus DB info storage Rustus can store information about upload in a database. It's a good and reliable option. But Rustus can't work with replicas, since it requires the most recent information about uploads. You can use postgresql , mysql or even sqlite schemas to connect to database. --info-db-dsn - connection string for your database. CLI ENV rustus --info-storage \"db-info-storage\" \\ --info-db-dsn \"postgresql://user:password@localhost/db\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"postgresql://user:password@localhost/db\" rustus Configuring TUS Since TUS protocol offers extensibility you can turn off some protocol extensions. Available extensions: getting - Rustus specific extension that helps you download uploaded files with get request; creation - helps you to create files (It's like a core feature you better have this enabled); termination - allows you to delete uploads with DELETE request; creation-with-upload - allows you to write first bytes of a file while creating; creation-defer-length - allows you to create file without specifying file length; concatenation - allows you to concatenate finished partial uploads. checksum - allows you to verify checksum of every batch. You can read more about extensions on official web-site . --tus-extensions - a list of enabled extensions. --remove-parts - remove parts files after successfull concatentation (disabled by default). By default all extensions are enabled. CLI ENV rustus --remove-parts \\ --tus-extensions \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" export RUSTUS_TUS_EXTENSIONS = \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" rustus --remove-parts","title":"Configuration"},{"location":"configuration/#configuring-server","text":"We use actix to run server. You can configure on wich host and port rustus is listenging. Also you can configure number of actix workers that handle connections. --max-body-size is the max number of bytes that users can send in request body. --url is a base URL for all tus requests. --workers by default is euqal to number of physical CPU cores. Edit it carefully. CLI ENV rustus --host \"0.0.0.0\" \\ --port 1081 \\ --workers 8 \\ --max-body-size 1000000 \\ --url \"/files\" \\ --log-level \"INFO\" export RUSTUS_SERVER_HOST = \"0.0.0.0\" export RUSTUS_SERVER_PORT = \"1081\" export RUSTUS_SERVER_WORKERS = \"8\" export RUSTUS_MAX_BODY_SIZE = \"1000000\" export RUSTUS_URL = \"/files\" export RUSTUS_LOG_LEVEL = \"INFO\" rustus","title":"Configuring server"},{"location":"configuration/#configuring-data-storage","text":"Info Currently only file storage is available, so if you pass to --storage parameter other than file-storage you will get an error. Also you can not pass --force-fsync through environment variables. --storage is a type of data storage to be used. --data-dir is a path to the directory where all files are stored. --dir-structure is a pattern of a directory structure inside data dir. You can use variables within the pattern. Available variables: {year} - current year; {month} - current month number from 1 to 12; {day} - current day number from 1 to 31; {hour} - hour number from 0 to 23; {minute} - minute number from 0 to 59; {env[ENV_NAME]} - environment variable where ENV_NAME is name of your variable. Note All environment variables are saved in memory during rustus startup. So you cannot change variable dynamically. Even if you change env used in structure pattern it won't change. For example if you use {env[HOSTNAME]}/{year}/{month}/{day} as your dir-structure, rustus stores files like: $ tree data data \u2514\u2500\u2500 rtus-68cb5b8746-5mgw9 \u2514\u2500\u2500 2022 \u2514\u2500\u2500 1 \u2514\u2500\u2500 8 \u251c\u2500\u2500 0bd911d4054d41c6a3ad54be67ee3e66 \u2514\u2500\u2500 5bc9c62384494c439e2a064b82a39cc6 CLI ENV rustus --force-fsync \\ --storage \"file-storage\" \\ --data-dir \"./data/\" \\ --dir-structure \"{year}/{month}/{day}\" export RUSTUS_STORAGE = \"file-storage\" export RUSTUS_DATA_DIR = \"./data/\" export RUSTUS_DIR_STRUCTURE = \"{year}/{month}/{day}\" rustus --force-fsync","title":"Configuring data storage"},{"location":"configuration/#configuring-info-storage","text":"Info storages are used to store information about file uploads. These storages must be persistent, because every time chunk is uploaded rustus updates information about upload. And when someone wants to download file, information about it requested from storage to get actual path of an upload. Available info storages: file-info-storage - stores information in files on disk; redis-info-storage - information is stored in Redis; db-info-storage - information is stored in database;","title":"Configuring info storage"},{"location":"configuration/#file-info-storage","text":"file info storage stores information in files on disk. It's default info storage. Every download has it's own associated file. All .info files stored in flat structure so it's the least preferable way of storing information about uploads. But if you don't plan to have many uploads, it may fit well. --info-dir - directory where all .info file will be stored (default is ./data ). CLI ENV rustus --info-storage \"file-info-storage\" \\ --info-dir \"./data\" export RUSTUS_INFO_STORAGE = \"file-info-storage\" export RUSTUS_INFO_DIR = \"./data\" rustus","title":"File info storage"},{"location":"configuration/#redis-info-storage","text":"Redis db is a good way to store information. Note If you're using Redis as a cluster you must provide connection string for master Redis server. Since rustus need to have latest information and it writes a lot. --info-db-dsn - connection string for your Redis database. It's required if redis-info-storage is chosen. CLI ENV rustus --info-storage \"redis-info-storage\" \\ --info-db-dsn \"redis://localhost/0\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"redis://localhost\" rustus","title":"Redis info storage"},{"location":"configuration/#db-info-storage","text":"Rustus can store information about upload in a database. It's a good and reliable option. But Rustus can't work with replicas, since it requires the most recent information about uploads. You can use postgresql , mysql or even sqlite schemas to connect to database. --info-db-dsn - connection string for your database. CLI ENV rustus --info-storage \"db-info-storage\" \\ --info-db-dsn \"postgresql://user:password@localhost/db\" export RUSTUS_INFO_STORAGE = \"redis-info-storage\" export RUSTUS_INFO_DB_DSN = \"postgresql://user:password@localhost/db\" rustus","title":"DB info storage"},{"location":"configuration/#configuring-tus","text":"Since TUS protocol offers extensibility you can turn off some protocol extensions. Available extensions: getting - Rustus specific extension that helps you download uploaded files with get request; creation - helps you to create files (It's like a core feature you better have this enabled); termination - allows you to delete uploads with DELETE request; creation-with-upload - allows you to write first bytes of a file while creating; creation-defer-length - allows you to create file without specifying file length; concatenation - allows you to concatenate finished partial uploads. checksum - allows you to verify checksum of every batch. You can read more about extensions on official web-site . --tus-extensions - a list of enabled extensions. --remove-parts - remove parts files after successfull concatentation (disabled by default). By default all extensions are enabled. CLI ENV rustus --remove-parts \\ --tus-extensions \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" export RUSTUS_TUS_EXTENSIONS = \"getting,creation,termination,creation-with-upload,creation-defer-length,concatenation,checksum\" rustus --remove-parts","title":"Configuring TUS"},{"location":"deploy/","text":"Deployment Deploying an application is always a challenge. Rustus was made to make deployment as easy as possible. Since Rustus works with files you have to be careful while scaling it. All rustus instances must have access to the same data and info storages. Info If you want to track you rustus instances with prometheus you can always get metrics at /metrics endpoint. Docker compose docker-compose.yml # This is super simple configuration version : \"3.7\" services : rustus : image : s3rius/rustus volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data volumes : rustus_data_volume : After running docker compose up you will see rustus startup logs. If you want to deploy multiple rustus instances you can simply use config as this one: docker-compose.yml version : \"3.7\" services : proxy : image : jwilder/nginx-proxy:alpine container_name : proxy # Actual proxy ports. ports : - 8080:80 volumes : # This thing helps to locate containers # within this composition to generate nginx config. - /var/run/docker.sock:/tmp/docker.sock:ro rustus : image : s3rius/rustus ports : # Ports definition # To generate correct nginx config. - 1081 volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data environment : # Idk why but without this variable # load balancing with jwilder/nginx-proxy doesn't work. VIRTUAL_HOST : localhost volumes : rustus_data_volume : # This is named volume The main idea is that traffic that comes into nginx-proxy is routed in one of multiple rustus containers. Here I used jwilder/nginx-proxy but you can use other reverse-proxies such as Nginx proxy , Traefik or Envoy proxy . Now you can run multiple rustus instnaces like this. docker compose up --scale rustus = 3 After that you can upload files to http://localhost:8080/files Kubernetes Configuration for Kubernetes is almost the same as for Docker. But the most preferable way is an official helm chart. Load balancing is done by Kubernetes, so you just have to create a volume to mount data and info directories. Helm You can install rustus by running this set of commands: helm repo add \"rustus\" \"https://s3rius.github.io/rustus/helm_releases\" helm repo update helm install \"rustus\" \"rustus/rustus\" Configuration Since default deplyment may not fit you. You can adjust it to satisfy your needs. You can do it easily with helm. At first you need to save default values on disk. # You can download basic configuration by running helm show values \"rustus/rustus\" > values.yml Warning For production use you must provide and mount PersistentVolumeClaim in order to scale rustus. This helm chart has only one replica by default. You can read more about configuration below. After you done editing values.yml , you can apply the configuration like this: helm upgrade \\ --install \\ # Install chart if it's not installed --namespace rustus \\ # k8s namespace --create-namespace \\ # Creates namespace if it doesn't exist --atomic \\ # Ensures that everything is deployed correctly --values \"values.yml\" \\ # Link to values.yml file \"rustus\" \\ # name of a release \"rustus/rustus\" # Name of the chart Persistence You can add PVC mount by editing persistence section. The most preferable way is to create PersistentVolume and PersistentVolumeClaim before installing this chart. After you created claim you can apply this values file to mount your claim into rustus. values.yml persistence : enabled : true existingClaim : \"rustus-pvc\" Warning Currently there's no ability to create multiple mounts and if you use file info storage you must specify the same direcotry as you specified for data storage. But it would be better to use other type of info-storage. Subcharts For example if you want to use redis as your info storage. values.yml env : RUSTUS_INFO_STORAGE : redis-info-storage RUSTUS_INFO_DB_DSN : redis://:pass@rustus-redis-master/0 redis : enabled : true redis , postgersql and mysql are subcharts. You can find information about configuration these subcharts here: Repo for redis; Repo for mysql; Repo for postgresql. In production you may ignore these subcharts to deploy your own redis or mysql or postgresql.","title":"Deployment"},{"location":"deploy/#deployment","text":"Deploying an application is always a challenge. Rustus was made to make deployment as easy as possible. Since Rustus works with files you have to be careful while scaling it. All rustus instances must have access to the same data and info storages. Info If you want to track you rustus instances with prometheus you can always get metrics at /metrics endpoint.","title":"Deployment"},{"location":"deploy/#docker-compose","text":"docker-compose.yml # This is super simple configuration version : \"3.7\" services : rustus : image : s3rius/rustus volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data volumes : rustus_data_volume : After running docker compose up you will see rustus startup logs. If you want to deploy multiple rustus instances you can simply use config as this one: docker-compose.yml version : \"3.7\" services : proxy : image : jwilder/nginx-proxy:alpine container_name : proxy # Actual proxy ports. ports : - 8080:80 volumes : # This thing helps to locate containers # within this composition to generate nginx config. - /var/run/docker.sock:/tmp/docker.sock:ro rustus : image : s3rius/rustus ports : # Ports definition # To generate correct nginx config. - 1081 volumes : # Volume mouted to default data directory # So it's available across multiple containers. - rustus_data_volume:/app/data environment : # Idk why but without this variable # load balancing with jwilder/nginx-proxy doesn't work. VIRTUAL_HOST : localhost volumes : rustus_data_volume : # This is named volume The main idea is that traffic that comes into nginx-proxy is routed in one of multiple rustus containers. Here I used jwilder/nginx-proxy but you can use other reverse-proxies such as Nginx proxy , Traefik or Envoy proxy . Now you can run multiple rustus instnaces like this. docker compose up --scale rustus = 3 After that you can upload files to http://localhost:8080/files","title":"Docker compose"},{"location":"deploy/#kubernetes","text":"Configuration for Kubernetes is almost the same as for Docker. But the most preferable way is an official helm chart. Load balancing is done by Kubernetes, so you just have to create a volume to mount data and info directories.","title":"Kubernetes"},{"location":"deploy/#helm","text":"You can install rustus by running this set of commands: helm repo add \"rustus\" \"https://s3rius.github.io/rustus/helm_releases\" helm repo update helm install \"rustus\" \"rustus/rustus\"","title":"Helm"},{"location":"deploy/#configuration","text":"Since default deplyment may not fit you. You can adjust it to satisfy your needs. You can do it easily with helm. At first you need to save default values on disk. # You can download basic configuration by running helm show values \"rustus/rustus\" > values.yml Warning For production use you must provide and mount PersistentVolumeClaim in order to scale rustus. This helm chart has only one replica by default. You can read more about configuration below. After you done editing values.yml , you can apply the configuration like this: helm upgrade \\ --install \\ # Install chart if it's not installed --namespace rustus \\ # k8s namespace --create-namespace \\ # Creates namespace if it doesn't exist --atomic \\ # Ensures that everything is deployed correctly --values \"values.yml\" \\ # Link to values.yml file \"rustus\" \\ # name of a release \"rustus/rustus\" # Name of the chart","title":"Configuration"},{"location":"deploy/#persistence","text":"You can add PVC mount by editing persistence section. The most preferable way is to create PersistentVolume and PersistentVolumeClaim before installing this chart. After you created claim you can apply this values file to mount your claim into rustus. values.yml persistence : enabled : true existingClaim : \"rustus-pvc\" Warning Currently there's no ability to create multiple mounts and if you use file info storage you must specify the same direcotry as you specified for data storage. But it would be better to use other type of info-storage.","title":"Persistence"},{"location":"deploy/#subcharts","text":"For example if you want to use redis as your info storage. values.yml env : RUSTUS_INFO_STORAGE : redis-info-storage RUSTUS_INFO_DB_DSN : redis://:pass@rustus-redis-master/0 redis : enabled : true redis , postgersql and mysql are subcharts. You can find information about configuration these subcharts here: Repo for redis; Repo for mysql; Repo for postgresql. In production you may ignore these subcharts to deploy your own redis or mysql or postgresql.","title":"Subcharts"},{"location":"hooks/","text":"Rustus can notify about uploads using hooks. This is useful when you integrate rustus in your architecture. Apps can keep track of every upload using this feature. Rustus has different event types for different moments of an upload's lifecycle. pre-create - This hook means that someone wants to create an upload; post-create - someone successfully created an upload; post-receive - someone uploaded a new part of an upload; post-terminate - someone deleted upload; post-finish - someone finished uploading file. Note Pre-create hook is very important. If at least one of hooks fails, upload is canceled. But AMQP hooks won't cancel the upload, since it's non blocking type of hooks. You can disable some hooks by using --hooks parameter. CLI ENV rustus --hooks \"pre-create,post-create,post-receive,post-terminate,post-finish\" export RUSTUS_HOOKS = \"pre-create,post-create,post-receive,post-terminate,post-finish\" rustus Fomat Information about every hook using JSON format. Format can be configured using --hooks-format parameter or RUSTUS_HOOKS_FORMAT environment variable. Available formats: default tusd default tusd { \"upload\" : { \"id\" : \"\" , \"offset\" : 0 , \"length\" : 39729945 , \"path\" : null , \"created_at\" : 1641620821 , \"deferred_size\" : false , \"metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" } }, \"request\" : { \"URI\" : \"/files\" , \"method\" : \"POST\" , \"remote_addr\" : \"127.0.0.1\" , \"headers\" : { \"accept-encoding\" : \"gzip, deflate\" , \"connection\" : \"keep-alive\" , \"host\" : \"localhost:1081\" , \"upload-metadata\" : \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" , \"tus-resumable\" : \"1.0.0\" , \"content-length\" : \"0\" , \"upload-length\" : \"39729945\" , \"user-agent\" : \"python-requests/2.26.0\" , \"accept\" : \"*/*\" } } } { \"Upload\" : { \"ID\" : \"\" , \"Offset\" : 0 , \"Size\" : 39729945 , \"IsFinal\" : true , \"IsPartial\" : false , \"PartialUploads\" : null , \"SizeIsDeferred\" : false , \"Metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" }, \"Storage\" : { \"Type\" : \"filestore\" , \"Path\" : null } }, \"HTTPRequest\" : { \"URI\" : \"/files\" , \"Method\" : \"POST\" , \"RemoteAddr\" : \"127.0.0.1\" , \"Header\" : { \"host\" : [ \"localhost:1081\" ], \"user-agent\" : [ \"python-requests/2.26.0\" ], \"accept\" : [ \"*/*\" ], \"content-length\" : [ \"0\" ], \"upload-metadata\" : [ \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" ], \"connection\" : [ \"keep-alive\" ], \"tus-resumable\" : [ \"1.0.0\" ], \"upload-length\" : [ \"39729945\" ], \"accept-encoding\" : [ \"gzip, deflate\" ] } } } Hook types Rustus offers multiple types of Hooks. We'll take a brief look on each type. File hooks Rustus can work with two types of file hooks. Single file hook Hooks directory The main difference is that in case if use single file hook, hook name is passed as a command line argument to an executable file, but if you use hooks directory then hook name is used to determine a file to call. Let's take a look at the examples. Parameters: * --hooks-file - path to an executable file; * --hooks-dir - path to a directory with executable files. single_file_hook.sh #!/bin/bash # Hook name would be \"pre-create\", \"post-create\" and so on. HOOK_NAME = \" $1 \" HOOK_INFO = \" $2 \" MEME = \" $( echo \" $HOOK_INFO \" | jq \".upload .metadata .meme\" | xargs ) \" # Here we check if name in metadata is equal to pepe. if [[ $MEME = \"pepe\" ]] ; then echo \"This meme isn't allowed\" 1 > & 2 ; exit 1 fi As you can see it uses first CLI parameter as a hook name and all hook data is received from the second one. Let's make it executable and make rustus use this hook. CLI ENV chmod +x \"hooks/single_file_hook.sh\" rustus --hooks-file \"hooks/single_file_hook.sh\" chmod +x \"hooks/single_file_hook.sh\" export RUSTUS_HOOKS_FILE = \"hooks/single_file_hook.sh\" rustus If you would like to use directory hooks you must create directory with the following structure: hooks \u251c\u2500\u2500 post-create \u251c\u2500\u2500 post-finish \u251c\u2500\u2500 post-receive \u251c\u2500\u2500 post-terminate \u2514\u2500\u2500 pre-create Warning If some hook file isn't found, rustus throws an error. In case with pre-create hook it can be fatal. Http Hooks Http hooks use HTTP to send POST requests to some endpoint. Configuration parameters: --hooks-http-proxy-headers - list of headers to proxy (separated by commas) to listener's endpoint; --hooks-http-urls - list of absolute urls to send request to (separated by commas). Note Hook names are passed as header called Hook-Name . CLI ENV rustus --hooks-http-urls \"https://httpbin.org/post\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"https://httpbin.org/post\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus Example application To be more verbose let's create simple web server that handles uploads using FastAPI . At first we need to install dependencies using pip. pip install fastapi uvicorn server.py from fastapi import FastAPI , Header , HTTPException from typing import Optional app = FastAPI () @app . post ( \"/hooks\" ) def hook ( authorization : Optional [ str ] = Header ( None ), hook_name : Optional [ str ] = Header ( None ), ): print ( f \"Received: { hook_name } \" ) if authorization != \"Bearer jwt\" : raise HTTPException ( 401 ) return None Now we can run this server using uvicorn. uvicorn server:app --port 8080 Let's configure rustus to use this server as a hook reciever. CLI ENV rustus --hooks-http-urls \"http://localhost:8000/hooks\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"http://localhost:8000/hooks\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus That's it. AMQP hooks AMQP hooks are used to store information about uploads using RabbitMQ. Configuration parameters: --hooks-amqp-url - connection string to RabbitMQ; --hooks-amqp-queues-prefix - prefix for queues for every event queue; --hooks-amqp-exchange - name of exchange to use. This hook will send every message in an exchange with routing keys like queues names. Queues are named like {prefix}.{event type} . Eg rustus.pre-create and so on. Warning Since we can't really track message delivery and responses Rustus doesn't stop in any case. CLI ENV rustus --hooks-amqp-url \"amqp://guest:guest@localhost:5672\" \\ --hooks-amqp-queues-prefix \"rustus_queue\" \\ --hooks-amqp-exchange \"rustus\" export RUSTUS_HOOKS_AMQP_URL = \"amqp://guest:guest@localhost:5672\" export RUSTUS_HOOKS_AMQP_QUEUES_PREFIX = \"rustus_queue\" export RUSTUS_HOOKS_AMQP_EXCHANGE = \"rustus\" rustus","title":"Setting up hooks"},{"location":"hooks/#fomat","text":"Information about every hook using JSON format. Format can be configured using --hooks-format parameter or RUSTUS_HOOKS_FORMAT environment variable. Available formats: default tusd default tusd { \"upload\" : { \"id\" : \"\" , \"offset\" : 0 , \"length\" : 39729945 , \"path\" : null , \"created_at\" : 1641620821 , \"deferred_size\" : false , \"metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" } }, \"request\" : { \"URI\" : \"/files\" , \"method\" : \"POST\" , \"remote_addr\" : \"127.0.0.1\" , \"headers\" : { \"accept-encoding\" : \"gzip, deflate\" , \"connection\" : \"keep-alive\" , \"host\" : \"localhost:1081\" , \"upload-metadata\" : \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" , \"tus-resumable\" : \"1.0.0\" , \"content-length\" : \"0\" , \"upload-length\" : \"39729945\" , \"user-agent\" : \"python-requests/2.26.0\" , \"accept\" : \"*/*\" } } } { \"Upload\" : { \"ID\" : \"\" , \"Offset\" : 0 , \"Size\" : 39729945 , \"IsFinal\" : true , \"IsPartial\" : false , \"PartialUploads\" : null , \"SizeIsDeferred\" : false , \"Metadata\" : { \"filename\" : \"38MB_video.mp4\" , \"meme\" : \"hehe2\" }, \"Storage\" : { \"Type\" : \"filestore\" , \"Path\" : null } }, \"HTTPRequest\" : { \"URI\" : \"/files\" , \"Method\" : \"POST\" , \"RemoteAddr\" : \"127.0.0.1\" , \"Header\" : { \"host\" : [ \"localhost:1081\" ], \"user-agent\" : [ \"python-requests/2.26.0\" ], \"accept\" : [ \"*/*\" ], \"content-length\" : [ \"0\" ], \"upload-metadata\" : [ \"meme aGVoZTI=,filename MzhNQl92aWRlby5tcDQ=\" ], \"connection\" : [ \"keep-alive\" ], \"tus-resumable\" : [ \"1.0.0\" ], \"upload-length\" : [ \"39729945\" ], \"accept-encoding\" : [ \"gzip, deflate\" ] } } }","title":"Fomat"},{"location":"hooks/#hook-types","text":"Rustus offers multiple types of Hooks. We'll take a brief look on each type.","title":"Hook types"},{"location":"hooks/#file-hooks","text":"Rustus can work with two types of file hooks. Single file hook Hooks directory The main difference is that in case if use single file hook, hook name is passed as a command line argument to an executable file, but if you use hooks directory then hook name is used to determine a file to call. Let's take a look at the examples. Parameters: * --hooks-file - path to an executable file; * --hooks-dir - path to a directory with executable files. single_file_hook.sh #!/bin/bash # Hook name would be \"pre-create\", \"post-create\" and so on. HOOK_NAME = \" $1 \" HOOK_INFO = \" $2 \" MEME = \" $( echo \" $HOOK_INFO \" | jq \".upload .metadata .meme\" | xargs ) \" # Here we check if name in metadata is equal to pepe. if [[ $MEME = \"pepe\" ]] ; then echo \"This meme isn't allowed\" 1 > & 2 ; exit 1 fi As you can see it uses first CLI parameter as a hook name and all hook data is received from the second one. Let's make it executable and make rustus use this hook. CLI ENV chmod +x \"hooks/single_file_hook.sh\" rustus --hooks-file \"hooks/single_file_hook.sh\" chmod +x \"hooks/single_file_hook.sh\" export RUSTUS_HOOKS_FILE = \"hooks/single_file_hook.sh\" rustus If you would like to use directory hooks you must create directory with the following structure: hooks \u251c\u2500\u2500 post-create \u251c\u2500\u2500 post-finish \u251c\u2500\u2500 post-receive \u251c\u2500\u2500 post-terminate \u2514\u2500\u2500 pre-create Warning If some hook file isn't found, rustus throws an error. In case with pre-create hook it can be fatal.","title":"File hooks"},{"location":"hooks/#http-hooks","text":"Http hooks use HTTP to send POST requests to some endpoint. Configuration parameters: --hooks-http-proxy-headers - list of headers to proxy (separated by commas) to listener's endpoint; --hooks-http-urls - list of absolute urls to send request to (separated by commas). Note Hook names are passed as header called Hook-Name . CLI ENV rustus --hooks-http-urls \"https://httpbin.org/post\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"https://httpbin.org/post\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus","title":"Http Hooks"},{"location":"hooks/#example-application","text":"To be more verbose let's create simple web server that handles uploads using FastAPI . At first we need to install dependencies using pip. pip install fastapi uvicorn server.py from fastapi import FastAPI , Header , HTTPException from typing import Optional app = FastAPI () @app . post ( \"/hooks\" ) def hook ( authorization : Optional [ str ] = Header ( None ), hook_name : Optional [ str ] = Header ( None ), ): print ( f \"Received: { hook_name } \" ) if authorization != \"Bearer jwt\" : raise HTTPException ( 401 ) return None Now we can run this server using uvicorn. uvicorn server:app --port 8080 Let's configure rustus to use this server as a hook reciever. CLI ENV rustus --hooks-http-urls \"http://localhost:8000/hooks\" \\ --hooks-http-proxy-headers \"Authorization\" export RUSTUS_HOOKS_HTTP_URLS = \"http://localhost:8000/hooks\" export RUSTUS_HOOKS_HTTP_PROXY_HEADERS = \"Authorization\" rustus That's it.","title":"Example application"},{"location":"hooks/#amqp-hooks","text":"AMQP hooks are used to store information about uploads using RabbitMQ. Configuration parameters: --hooks-amqp-url - connection string to RabbitMQ; --hooks-amqp-queues-prefix - prefix for queues for every event queue; --hooks-amqp-exchange - name of exchange to use. This hook will send every message in an exchange with routing keys like queues names. Queues are named like {prefix}.{event type} . Eg rustus.pre-create and so on. Warning Since we can't really track message delivery and responses Rustus doesn't stop in any case. CLI ENV rustus --hooks-amqp-url \"amqp://guest:guest@localhost:5672\" \\ --hooks-amqp-queues-prefix \"rustus_queue\" \\ --hooks-amqp-exchange \"rustus\" export RUSTUS_HOOKS_AMQP_URL = \"amqp://guest:guest@localhost:5672\" export RUSTUS_HOOKS_AMQP_QUEUES_PREFIX = \"rustus_queue\" export RUSTUS_HOOKS_AMQP_EXCHANGE = \"rustus\" rustus","title":"AMQP hooks"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 336f48e8d60ece406cd52b170b89bbd1e0afd1df..8b316462c1176d5e586cbc5c7316203dad5887c6 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,22 +2,22 @@ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://s3rius.github.io/rustus/</loc> - <lastmod>2022-03-28</lastmod> + <lastmod>2022-04-02</lastmod> <changefreq>daily</changefreq> </url> <url> <loc>https://s3rius.github.io/rustus/configuration/</loc> - <lastmod>2022-03-28</lastmod> + <lastmod>2022-04-02</lastmod> <changefreq>daily</changefreq> </url> <url> <loc>https://s3rius.github.io/rustus/deploy/</loc> - <lastmod>2022-03-28</lastmod> + <lastmod>2022-04-02</lastmod> <changefreq>daily</changefreq> </url> <url> <loc>https://s3rius.github.io/rustus/hooks/</loc> - <lastmod>2022-03-28</lastmod> + <lastmod>2022-04-02</lastmod> <changefreq>daily</changefreq> </url> </urlset> \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index ebaa75eb2af63527adfb1b62cc391a9b709161ba..48d7048a5176900caa22413ca6e81907a0d106f8 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ