<repo_name>thihenos/gcp-node-examples<file_sep>/node-storage/README.md
# image-watermark API

estrutura de pastas:
```bash
├── server                     # Configuração do server
│   ├── config 				   # Configs - Redis | Datastore | Promisses Handler
│   ├── functions 			   # "Controllers" para conexão com Redis e Datastore
│   ├── secure 				   # Variáveis de ambiente e JSON de autenteicação
│   └── services 			   # Chamadas de validações
├── bitbucket-pipelines.yml    # Configuração do Pipeline
├── package.json               # Dependências
├── app.yaml                   # Configuração App Engine
├── index.js 				           # Configurações iniciais do serviço
└── README.md                  # Esse Arquivo
```

# Onde estou?
Projeto : autoavaliar-apps
GCloud Function : imageWatermark

# Comandos principais:
 - `npm start` : inicia a aplicação apontando para a produção
 - `npm test` : inicia a aplicação em modo teste

##  Como funciona a API ?
### 1 - Usando a API
Inicialmente, a **HG-API** irá enviar uma requisição POST para o do Cloud Function

> POST https://us-central1-autoavaliar-apps.cloudfunctions.net/imageWatermark

 Nesta  requisição, deverá ser enviado os seguintes dados
```javascript
// Exemplo de JSON enviado na requisição
"message" : {
  "attributes" : {
    "method" : 'storage', //base64 | storage
    "bucketDownload" : 'photo-ecossistema', //Nome do intervalo
    "bucketUpload" : 'photo-ecossistema', //Nome do intervalo
    "country" : 'ar', // br | qualquer pais já será considerado AutoAction
    "token" : <HG_TOKEN> //token enviado pela HG
  },
  "data" : '<BASE64>'
}
```
### 2 - A lógica
- A aplicação irá converter o base64 do atributo DATA da requisição, que consistirá nos endereços das imagens do storage
- A aplicação irá validar a autenticidade do **TOKEN** da HG e irá validar se é correspondente com o SECRET que estará armazenado na variável de ambiente
- Após validar, a API executa a seguinte operação me *promises*
  - Download do arquivo do bucket
  - Resize da imagem para 800X600
  - Aplicação da Marca D'agua
  - Upload no storage
  - Remoção dos arquivos na pasta temp e download

```javascript
// Em caso positivo
  res.status(200).send({message : 'Fotos tratadas com sucesso!'});
// Em caso positivo de autenticação porem sem imagens
  res.status(204).send({message : 'Não há arquivo na requisição!'});
// Em caso negativo
 response.status(403).send({message : 'Chamada não permitida'});
```
# To Do

- Processamento em batch de base64

## Dicas:
 É extremamente importante que o nodemon esteja instalado na máquina de quem for rodar a aplicação

 Caso seja necessário a reconfiguração do Redis, será necessário editar os dados nas variáveis de ambiente, que estarão dentro do do path `server/secure/.env`

 #### Podemos também utilizar!
  * Utilizar a lib [jimp-watermak](https://www.npmjs.com/package/jimp-watermark) para carimbar o logo nas imagens.
  * Utilizar a lib [image-watermak](https://github.com/luthraG/image-watermark) criar marca d'agua.
  * Utilizar a lib para [caption](https://stackoverflow.com/questions/50465099/watermark-in-image-using-nodejs)

# Pipeline
A pipeline vai efetuar o deploy da API no projeto autoavaliar-apps como um Cloud Function com o nome de imageWatermark
<file_sep>/node-appengine/README.md
# Hold - API

topologia:
```mermaid
graph LR
    U[Luke] -->|"[POST] /api/setQueue"| Z[Express]
	    Z --> View{token?}
            View --> |Não| S[401 - Unauthorized]
	        View -->|Sim| C1{Config no cache ?}
        C1-->|Não|M1[Datastore]
        C1-->|Sim|D1{Entidade configurada ?}
        M1 -->DT[Setar dados no Redis]
        DT-->D1
        D1 --> |Não|Default[5 Min]
        D1 --> |Sim|D2[Tempo da entidade]
    end
```


![picture](graph.png)

estrutura de pastas:
```bash
├── server                     # Configuração do server
│   ├── config 				   # Configs - Redis | Datastore | Promisses Handler
│   ├── functions 			   # "Controllers" para conexão com Redis e Datastore
│   ├── secure 				   # Variáveis de ambiente e JSON de autenteicação
│   ├── services 			   # Chamadas de validações
│   └── routes.js              # Roteamento REST
├── bitbucket-pipelines.yml    # Configuração do Pipeline
├── package.json               # Dependências
├── app.yaml                   # Configuração App Engine
├── server.js 				   # Configurações iniciais do serviço
└── README.md      # Esse Arquivo 
```
# Comandos principais:
 - `npm start` : inicia a aplicação apontando para a produção
 - `npm run dev` : inicia a aplicação apontando para a produção, rodando node monitor para desenvolvimento
 
##  Como funciona a API ?
### 1 - Configurações
A intenção do desenvolvimento da *API* é para controlar a quantidade de requisições de integrações para não acarretar problemas de chamadas excessivas. A *API* trabalhará como um semáforo controlando as requisições por quantidade de requisições permitidas e o tempo de espera para a próxima requisição.
Essas configurações serão armazenadas no **Datatore** do projeto **sa-hg-db**, onde poderemos contar com as seguintes informações:
```javascript
// Entidade holdConfig
{
"entity_id" : "10", //Id da entidade
"instance_id": "23", //Id da instância
"max_intersection": "10", //Maximo de chamadas permitidas por essa entidade
"root" : "LUKE-ESTOQUE", //Nome do ROOT que enviariá a chamada
"ttl" : "5", //Tempo de vida na fila do REDIS em minutos
"ttr": "5"// Assim que chegar no seu limite de max_intersection, esse será o tempo que a proxima chamada deverá respeitar em minutos
}
```
### 2 - Usando a API
Inicialmente, o **LUKE** irá enviar uma requisição POST para o endereço 

> /api/setQueue

 Nesta  requisição, deverá ser enviado os seguintes dados 
```javascript
// Exemplo de JSON enviado na requisição
"headers": {
"Content-Type": "application/json",
"token": "<PASSWORD>"
},
"body": {
	"root" : "ENTIDADE" //Será definido e configurado no datastore
}
```
### 3 - A lógica
- A aplicação irá validar a autenticidade do **TOKEN** 
- Iremos validar se as configurações já tenham sido carregadas do Datastore para o Redis
	- Se não foi carregado, será carregado no Redis com validade de um dia
	- Caso tenha sido carregado posteriormente, prosseguiremos para o próximo passo
- Validaremos se o **ROOT** que está invocando a *API* está configurado , em caso positivo
	- Iremos incrementar mais uma chamada no Redis, caso não tenha chego no limite definido na sessão **1 - Configurações** 
	- Retornaremos o status conforme o step anterior definir, com as seguintes informações
	- Lembrando que o `ttr` será retornado em minutos
```javascript
// Em caso positivo
 response.status(200).send({message : 'Chamada permitida!', grant : true});
// Em caso negativo
 response.status(403).send({message : 'Chamada não permitida', ttr: 10 , grant : false});
```
 - Validaremos se o **ROOT** que está invocando a *API* está configurado , em caso negativo, enviaremos a requisição para uma fila **DEFAULT** que terá como padrão o máximo de apenas 5 chamadas.
	- Iremos incrementar mais uma chamada no **Redis** na fila **DEFAULT**, caso não tenha chego no limite de 5 chamadas
	- Retornaremos o status conforme o step anterior definir, com as seguintes informações
	- Lembrando que o `ttr` será retornado em minutos

```javascript
// Em caso positivo
 response.status(200).send({message : 'Chamada permitida!', grant : true});
// Em caso negativo
 response.status(403).send({message : 'Chamada não permitida', ttr: 5, grant : false});
```

## Dicas:
 É extremamente importante que o nodemon esteja instalado na máquina de quem for rodar a aplicação
 
 Caso seja necessário a reconfiguração do Redis, será necessário editar os dados nas variáveis de ambiente, que estarão dentro do do path `server/secure/.env`

# Pipeline
A pipeline vai efetuar o deploy da API no projeto sa-hg-sys no modo standard 
<file_sep>/node-function/index.js
/**
 * Autor : @thihenos
 * Script de testes para Google Cloud Function
 *
 * Descrição: 
 * Parametros:
    - teste: texto simples para ser exibido no retorno
 */

exports.examplo = (req, res) => {
  res.status(200).send(req.body.message);
};
<file_sep>/node-storage/download.js
const {Storage} = require('@google-cloud/storage');
const storage = new Storage({keyFilename: "./secret/keyFile.json"});

console.log(`-------------------- Download de imagem  ------------------`);

    return new Promise((resolve, reject) => {

      const myBucket = storage.bucket(`teste-nerds-gcp`);
      const file = myBucket.file('sups.jpeg');

      //Download do arquivo do bucket para a pasta temporária
      file.download({destination: `./src/sups.jpeg`}, function(err) {
        if(err){
          console.log(err);
          reject(err);
        }
      });

    }).catch((erro)=>{
      console.log(erro);
    });
<file_sep>/node-storage/update.js
const {Storage} = require('@google-cloud/storage');
const storage = new Storage({keyFilename: "./secret/keyFile.json"});


  async function uploadFile() {
    await storage.bucket('teste-nerds-gcp').upload(`./src/bat.jpeg`, {
      destination: `bat.jpeg`,
      public : true
    });
    console.log(`-------------------- Upload de imagem no storage ------------------`);
  }

  //Função de upload e remoção dos arquivos temporários
  uploadFile().then(()=>{
         
  }).then(()=>{
      console.log('Upload Finalizado!')
  }).catch(console.error);

