Leia esse documento em outro idioma: Inglês, Português
O FileHub é um serviço que padroniza o gerenciamento de arquivos, independente da plataforma de armazenamento utilizada. Além disso, ele facilita a persistência de arquivos em mais de uma plataforma de armazenamento, servindo como gateway de requisições, de forma segura e prática.
Seções
O FileHub utiliza um arquivo de configuração XML, onde são definidas as propriedades e como o serviço irá se comportar. Este arquivo poderá ser criado localmente onde o serviço será executado ou remotamente em um repositório Git.
Para informar ao serviço onde está o arquivo de configuração, utiliza-se as seguintes variáveis de ambiente:
* Informação Obrigatória | |
Nome da variável | Descrição |
---|---|
CONFIG_TYPE * | Define se o arquivo está localizado localmente ou remotamente. Valor padrão: LOCAL_FILE Valores possíveis: |
LOCAL_FILE_PATH | Caminho do arquivo no Sistema Operacional Exemplo: C:/filehub/example.xml |
CONFIG_GIT_FILE_PATH |
Endereço do arquivo no repositório Git Obs: Use a URL raw do arquivo no repositório (texto plano) (plain text) |
CONFIG_GIT_FILE_TOKEN | Token de autenticação do repositório Git |
MAX_FILE_SIZE | Tamanho máximo do arquivo. Valor padrão: 7000000000 |
MAX_REQUEST_SIZE | Tamanho máximo da requisição. Valor padrão: 7000000000 |
Antes de executar o serviço é necessário definir quais plataformas de armazenamento serão utilizadas, além de configurar os parâmetros de acesso de cada plataforma de forma independente. Para isso o FileHub utiliza um arquivo XML que será lido quando o serviço iniciar. Nele existem elementos que irão determinar como o FileHub irá processar as requisições. Cada elemento é descrito a seguir:
É o elemento que representa uma plataforma de armazenamento. Um storage possui um ID para identificá-lo no sistema e um tipo. Cada tipo corresponde a um serviço ou plataforma de armazenamento, como por exemplo, um servidor FTP, um serviço em cloud como o S3 da AWS ou um diretório do servidor onde o FileHub está sendo executado, ou seja, cada tipo de storage possui suas propriedades para acesso e especificações.
No arquivo de configuração os storages são definidos dentro da tag storages, como no exemplo abaixo:
<filehub>
<storages>
<storage id="S3-Test" type="AWS_S3">
<region>us-east-2</region>
<secretKeyId>G5HG4G66RDYIYE1</secretKeyId>
<secretKey>6F51E6f1e6F7A2E4F761F61fd51s1F</secretKey>
<bucket>test</bucket>
</storage>
<storage id="FileSystem-Test" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
</filehub>
Exemplo de declaração de storage
Todo elemento storage possui um ID e um type. O ID irá identificar o storage e o type irá definir quais as propriedades de configuração o storage possui. Os tipos de storages são listados a seguir:
Um schema representa um conjunto de storages. Ao realizar qualquer operação no FileHub, seja de upload ou download, será necessário informar qual o schema que deverá ser considerado. Em outras palavras, o serviço FileHub não realiza operações diretamente em um elemento Storage, mas sim em um schema que representa um ou mais storages.
Os schemas são declarados dentro da tag schemas, sendo possível a declaração de mais de um schema. Todo registro de schema possui um name que será o identificador do mesmo nas requisições realizadas no FileHub. Para vincular os storages a determinado schema utilizamos a tag storage-id. O exemplo abaixo mostra como fica uma configuração de um schema que possui dois storages vinculados.
<filehub>
<storages>
<storage id="S3-Test" type="AWS_S3">
<region>us-east-2</region>
<secretKeyId>G5HG4G66RDYIYE1</secretKeyId>
<secretKey>6F51E6f1e6F7A2E4F761F61fd51s1F</secretKey>
<bucket>test</bucket>
</storage>
<storage id="FileSystem-Test" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
<schemas>
<schema name="MySchema">
<storage-id>FileSystem-Test</storage-id>
<storage-id>S3-Test</storage-id>
</schema>
</schemas>
</filehub>
Exemplo de declaração de schema
Não é necessário declarar um schema para cada storage caso exista a necessidade de realizar operações nos storages de forma individual. É possível fazer com que o FileHub realize a leitura do arquivo de configuração, criando um schema para cada storage existente. Para isso, utilize o atributo generate-schema, informando como valor, o nome do schema que deverá ser criado. Veja o exemplo abaixo:
<filehub>
<storages>
<storage id="S3-Test" type="AWS_S3" generate-schema="s3test">
<region>us-east-2</region>
<secretKeyId>G5HG4G66RDYIYE1</secretKeyId>
<secretKey>6F51E6f1e6F7A2E4F761F61fd51s1F</secretKey>
<bucket>test</bucket>
</storage>
<storage id="FileSystem-Test" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
</filehub>
Exemplo de geração de schema diretamente no storage
Utilize o atributo generate-schema no elemento storages caso seja necessário criar um schema com todos os storages existentes. Veja o exemplo abaixo:
<filehub>
<storages generate-schema="all">
<storage id="S3-Test" type="AWS_S3">
<region>us-east-2</region>
<secretKeyId>G5HG4G66RDYIYE1</secretKeyId>
<secretKey>6F51E6f1e6F7A2E4F761F61fd51s1F</secretKey>
<bucket>test</bucket>
</storage>
<storage id="FileSystem-Test" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
</filehub>
Exemplo de geração de schema com todos os storages existentes
Warning Se um schema auto gerado foi criado sem uma trigger default configurada, o schema não terá nenhum tipo de segurança.
Triggers são utilizadas para garantir a segurança das operações. Funcionam como web hooks que irão validar se determinada operação está autorizada ou não por sua aplicação.
O elemento trigger possui um ID para identificação e também um atributo action, que poderá assumir dois valores possíveis:
- ALL: irá considerar a trigger para qualquer tipo de operação, seja de escrita (upload/criação/exclusão) ou leitura (download);
- UPDATE: a trigger só será aplicada para operações de escrita (upload/criação/exclusão).
Warning O termo default é um valor especial e não pode ser utilizado como ID para uma trigger.
Ao configurar uma trigger três propriedades deverão ser informadas:
- header: é o nome do header que deverá ser enviado ao serviço de autorização.
- url: é o endpoint do serviço que irá validar se a requisição é válida ou não. Seu objetivo é verificar se o valor do header é válido. Caso a requisição enviada para este endpoint retornar um código HTTP diferente de 200 (OK) a operação é cancelada.
- http-method (optional): define qual o tipo do método HTTP utilizado na requisição (GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS). O valor padrão é GET.
No XML de configuração as triggers são definidas dentro da tag triggers. Uma trigger deverá ser vinculada a um schema. Esse vínculo é criado através do atributo trigger do schema, isso faz com que todos os storages do schema passem a considerar a trigger em suas operações.
Para deixar mais claro, considere o seguinte exemplo de configuração:
<filehub>
<storages>
<storage id="example" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
<trigger id="user-auth" action="ALL">
<url>http://10.0.0.10:8080/auth</url>
<header>myheader</header>
<http-method>GET</http-method>
</trigger>
<schemas>
<schema name="test" trigger="user-auth">
<storage-id>example</storage-id>
</schema>
</schemas>
</filehub>
Exemplo de declaração de trigger
Observe que a trigger user-auth foi criada e o schema test faz o uso da mesma, ou seja, cada operação realizada para o storage example irá chamar a trigger para verificação de autorização.
O fluxograma abaixo apresenta o processo considerando a operação de upload para a configuração anterior.
Fluxograma de upload de arquivo com trigger
A aplicação que consome o serviço FileHub deverá enviar o header configurado na trigger com um valor, ao receber a requisição, o FileHub irá chamar o endpoint configurado na trigger repassando o header para que o serviço de autorização faça a devida validação. Um token JWT é um bom exemplo do uso desse processo.
Quando uma trigger realiza uma request para a URL configurada, ela enviará as seguintes informações no corpo da requisição (request body):
- schema: o nome do schema selecionado na operação
- operation: o tipo de operação está sendo executada (CREATE_DIRECTORY, RENAME_DIRECTORY, DELETE_DIRECTORY, LIST_FILES, EXIST_DIRECTORY, UPLOAD_MULTIPART_FILE, UPLOAD_BASE64_FILE, DOWNLOAD_FILE, DELETE_FILE, EXIST_FILE, GET_FILE_DETAILS)
- path: o caminho informado
- filenames: uma lista com os nomes dos arquivos que estão sendo manipulados na operação
O seguinte JSON mostra um exemplo desse request body:
{
"schema": "test",
"operation": "UPLOAD_MULTIPART_FILE",
"path": "/accounts/users/avatar/",
"filenames": [ "MyAvatar.jpeg" ]
}
Outra função das triggers é permitir a criação de caminhos customizáveis para os arquivos. Para deixar mais claro essa função da trigger, imagine um sistema onde cada usuário possui um diretório para armazenar suas imagens, teríamos URLs semelhantes a seguinte lista:
- /schema/example/user/paul/photo01
- /schema/example/user/paul/photo02
- /schema/example/user/john/photo01
- /schema/example/user/john/photo02
- /schema/example/user/john/photo03
Observe que para realizar uma operação de upload ou download, a aplicação que irá consumir o FileHub deverá gerenciar os identificadores dos usuários logados. Porém, se essa aplicação consumidora for uma interface web, seria possível alterar esse identificador, comprometendo a segurança no acesso aos arquivos gerenciados pelo FileHub. Para contornar esse problema existe a possibilidade do endpoint configurado na trigger, retornar uma lista de parâmetros que deverão ser utilizados para substituir partes da URL nas operações. O diagrama de sequência a seguir mostra esse processo:
Diagrama de sequência do processo de comunicação com trigger
Note que o parâmetro retornado da resposta do Authorization Service deverá ter o mesmo nome que o parâmetro informado na URL da operação ($user = user).
Note O nome do arquivo também pode ser alterado pelo retorno da requisição através do parâmetro chamado filename.
Warning Caso uma trigger esteja configurada com o atributo action como UPDATE e o header de autorização configurado, seja enviado na requisição, a trigger irá chamar o endpoint configurado.
Existe a possibilidade de criar uma trigger que será chamada em todos os schemas que não definirem uma trigger de forma explícita. Para isso, utiliza-se o atributo default na trigger como mostrado no exemplo abaixo:
<filehub>
<storages>
<storage id="example" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
<trigger id="user-auth" action="ALL" default="true">
<url>http://10.0.0.10:8080/auth</url>
<header>myheader</header>
<http-method>GET</http-method>
</trigger>
</filehub>
Exemplo de trigger padrão
Após o entendimento dos principais conceitos do FileHub, o próximo passo é saber quais as possíveis operações que podem ser executadas pelo serviço.
Os diretórios podem ser vistos como uma forma de agrupar e organizar os arquivos. A maioria dos storages tratam os diretórios como um tipo especial de arquivo, porém existem casos como o S3 da AWS que tratam os diretórios como prefixos, que juntamente com o nome do arquivo, compõem a chave de identificação do arquivo dentro de um bucket. O FileHub facilita o gerenciamento de diretórios, permitindo as seguintes operações:
- Criar um novo diretório
- Renomear um diretório
- Deletar um diretório
- Listar os arquivos existentes dentro do diretório, incluindo outros diretórios
- Verificar se o diretório existe
Caso exista a necessidade de desativar as operações em diretórios, pode-se utilizar o atributo no-dir em uma trigger como mostrado no exemplo abaixo.
<trigger id="user-auth" action="ALL" no-dir="true">
<url>http://10.0.0.10:8080/auth</url>
<header>myheader</header>
<http-method>GET</http-method>
</trigger>
Exemplo de trigger com desativação de diretórios
A operação de upload permite que sejam enviados arquivos que serão salvos em todos os storages vinculados a determinado schema. Quando o FileHub recebe a requisição de upload e a transferência dos arquivos inicia, o FileHub pode enviar o arquivo para os storages de duas maneiras:
- Transferência sequencial: É o tipo de transferência padrão. O FileHub irá transferir os arquivos para cada um dos storages de forma sequencial, obedecendo a ordem de declaração dos storages no schema.
- Transferência paralela: O FileHub transfere os arquivos para os storages ao mesmo tempo. Nesse caso não existe uma ordem de transferência. Para utilizar essa configuração é necessário colocar o atributo parallel-upload na tag schema com o valor true.
<schemas>
<schema name="test-parallel" parallel-upload="true">
<storage-id>example</storage-id>
</schema>
</schemas>
Exemplo de configuração de tranferência paralela
Independente do tipo de transferência realizada, a requisição de upload só irá retornar uma resposta após o término da transferência dos arquivos para todos os storages do schema.
Em alguns cenários, onde se tem apenas 1 storage no schema e os arquivos são pequenos, a operação de transferência é executada rapidamente. Porém, existem casos onde é necessário transferir arquivos maiores para mais de 1 storage, e nesses casos a requisição pode levar um tempo considerável. Para amenizar este problema, utiliza-se o conceito de middle-storage.
O middle-storage define qual dos storages do schema irá servir como intermediário entre a aplicação consumidora e o restante dos storages. Veja o exemplo a seguir:
<filehub>
<storages>
<storage id="S3-Test" type="AWS_S3">
<region>us-east-2</region>
<secretKeyId>G5HG4G66RDYIYE1</secretKeyId>
<secretKey>6F51E6f1e6F7A2E4F761F61fd51s1F</secretKey>
<bucket>test</bucket>
</storage>
<storage id="FileSystem-Test" type="FILE_SYSTEM">
<baseDir>C:\Users\user\filehub</baseDir>
</storage>
</storages>
<schemas>
<schema name="myschema" middle="FileSystem-Test">
<storage-id>FileSystem-Test</storage-id>
<storage-id>S3-Test</storage-id>
</schema>
</schemas>
</filehub>
Exemplo de middle-storage
No exemplo acima, em uma operação de upload, o storage FileSystem-Test irá receber o arquivo, retornar a resposta para a aplicação consumidora e depois irá transferir o arquivo para o storage S3-Test.
Um storage definido como middle-storage e não incluído como um dos storage do schema será considerado um storage temporário. Esse storage irá funcionar igual ao middle-storage, porém irá deletar os arquivos após a operação de upload.
<schemas>
<schema name="myschema" middle="FileSystem-Test">
<storage-id>S3-Test</storage-id>
</schema>
</schemas>
Exemplo de middle-storage temporário
Como mostrado no exemplo acima, o storage FileSystem-Test não está declarado em nenhum elemento storage-id dentro do schema, ou seja, ele é um middle-storage temporário.
Diferente do upload que faz a comunicação com todos os storages de um schema, o download irá utilizar o primeiro storage declarado para fazer a operação de download.
O uso do atributo cache no schema irá afetar a operação de download. Caso o arquivo não exista no primeiro storage do schema, o FileHub irá verificar a existência do arquivo no próximo storage. Se o arquivo existir, o FileHub fará o download do mesmo, porém deixando o arquivo salvo no primeiro storage também.
<schemas>
<schema name="myschema" middle="FileSystem-Test" cache="true">
<storage-id>S3-Test</storage-id>
</schema>
</schemas>
Exemplo de schema com cache
No exemplo anterior, caso seja realizado o download de um arquivo que não exista no FileSystem-Test, o FileHub irá verificar se o S3-Test possui o arquivo. Em caso positivo o download será executado, porém transferindo o arquivo também para o FileSystem-Test, o primeiro storage consultado.
Warning Caso exista um middle-storage associado ao schema, o mesmo será utilizado para o cache, caso contrário, será o primeiro storage do schema.
Warning Não é possível ter um cache-storage atuando como middle-storage temporário.
- Execute o serviço e acesso o seguinte endpoint: http://localhost:8088/swagger-ui/index.html
- Documentação no Apiary: https://filehub.docs.apiary.io
Link do DockerHub: https://hub.docker.com/repository/docker/paulophgf/filehub
Comando Docker Run
docker run -d --name filehub -v {LOCAL_DIR}:/filehub paulophgf/filehub:{FILEHUB_VERSION}
Exemplo:
docker run -d --name filehub -v //c/Users/user/filehub:/filehub paulophgf/filehub:1.0.0
Compose
version: '3.1'
services:
filehub:
image: paulophgf/filehub:1.0.0
hostname: filehub
container_name: filehub
restart: always
networks:
- filehub-default
ports:
- "8088:8088"
volumes:
- /etc/hosts:/etc/hosts:ro
- {LOCAL_DIR}:/filehub # Substitua o valor da variável {LOCAL_DIR} | Exemplos: Win: C:\Users\%user%\filehub ou Linux: /filehub
environment:
CONFIG_TYPE: "LOCAL_FILE" # Escolha umas das opções LOCAL_FILE ou GIT_FILE
LOCAL_FILE_PATH: "filehub/fh-config.xml"
CONFIG_GIT_FILE_PATH: "" # Preencha esta variável caso tenha escolhido GIT_FILE como CONFIG_TYPE
CONFIG_GIT_FILE_TOKEN: "" # Preencha esta variável caso tenha escolhido GIT_FILE como CONFIG_TYPE
JAVA_OPTS : "-Xms512m -Xmx1024m"
networks:
filehub-default:
name: filehub-default