Existem diversos modelos de gateway (um para cada fabricante diferente de reconhecimento facial, por exemplo). Todos têm uma arquitetura muito parecida, mas pequenas diferenças entre si em função de particularidades de cada fabricante.
Toda a parte comum está organizada num pacote Composer iongrade/gatewaycommon.
Como regra geral, todos os gateways têm um diretório jobs aonde estão os serviços que devem ser executados. Mais ainda, provavelmente há um arquivo daemon.php que orquestra todos os serviços necessários (coloca todo mundo no ar e garante que continuem em execução). Geralmente, que esse arquivo seja o entrypoint do container.
Mais abaixo, teremos a descrição de cada serviço disponibilizado pelo iongrade/gatewaycommon. Cada um deles provavelmente terá um arquivo helper para iniciar sua execução (o arquivo que será orquestrado pelo daemon).
ENTIDADES IMPORTANTES
AppConfiguration
Classe que tem as configuração básicas do gateway (modelo, número de série, facility, versão, etc...). Deve ser registrado manualmente no injetor de dependências.
DeviceInterface
Representa um dispositivo físico (um equipamento de reconhecimento facial, por exemplo).
A definição de um DeviceInterface exige alguns dados básicos, como IP, porta, usuário e senha. Existe uma propriedade de metadata que pode ser usada para guardar "outras coisas específicas"
DeviceRepository
É uma collection de DeviceInterfaces.
DeviceRepositoryCollection
Um agrupador de 02 tipos diferentes de DeviceRepositories: um repositório de "devices normais" (getDevices()) e um repositório de "devices LPR" ( getDevicesLPR()), porque existem diferenças importantes entre as duas coisas.
Cartao/Controlador/Pessoa
Entidades iguais às do Accelero, mas bastante simplificadas.
NormalizedObject/NormalizedObjectInterface
Quase todas as mensagens enviadas pelo Accelero para o gateway são "normalizadas" para uma classe comum pra simplificar o tratamento. Isso existe porque podem haver pequenas diferenças entre as mensagens enviadas pelo Accelero dependendo do modelo, e a padronização/normalização disso acontece no gateway.
FUNCIONAMENTO BÁSICO
O gateway tem algumas responsabilidades básicas:
- saber quais são os dispositivos pelos quais ele é responsável;
- saber se esses dispositivos estão online;
- receber mensagens/instruções do Accelero para "fazer algo nos dispositivos" e fazer;
- devolver uma resposta para o Accelero dizendo "se deu certo ou não" a execução de alguma instrução;
- informar periodicamente o Accelero o "status geral das coisas" (status do gateway, status de comunicação com os dispositivos, informações gerais que sejam importantes...).
Toda comunicação com o Accelero é feito via MQTT em tópicos específicos para cada gateway (além de broadcasts):
{FACILITY}/{MODELO}/{SERIAL}/#
Em geral, quatro tópicos são assinados pelo gateway:
| Tópico | Descrição |
|---|---|
{FACILITY}/{MODELO}/{SERIAL}/messages | Mensagens com instruções de operação, como "cadastrar pessoa", "excluir pessoa", "envio de configurações", etc... |
{FACILITY}/{MODELO}/{SERIAL}/pendencies/# | Tópico legado, equivalente ao messages |
{FACILITY}/{MODELO}/{SERIAL}/remotecommand | Tópico backdoor não-documentado para permitir a execução remota de comands no host do gateway. |
{FACILITY}/broadcast/to | Tópico usado basicamente para recepção de keepalives do Accelero. |
O que mais importa para a operação normal são mensagens recebidas no tópico messages/pendencies.
Todas as mensagens enviadas pelo Accelero são formatadas em JSON, e o "roteamento" acontece pela chave command, algo como:
//Mensagem enviada pelo Accelero:
//{"command": "enrollfacial", "dados": ...}
function onMessage(Message $message) : void {
$data = json_decode($message->payload, true);
$command = $data['command'] ?? null;
switch ($command) {
case 'enrollfacial':
cadastraFacial($data);)
break;
case 'deleteuser':
deletaUsuario($data);
break;
}
}
SERVIÇOS COMUNS
ControladorScanner
Conecta-se no broker e fica "lendo" mensagens de status/keepalive dos controladores (Aurum/Neon). Com isso, descobre o IP dos controladores e fica fazendo "pings" periódicos.
Sabendo quais controladores estão online (ou não), o gateway pode decidir como lidar com situações como "câmeras de LPR" em que PODE haver comunicações diretas com os controladores.
GarbageCollector
Periodicamente (padrão, 1 hora) o gateway varre as pendências não-tratadas e exclui aquelas que estão paradas há muito tempo (padrão, 1 semana).
StatsFetcher
Periodicamente o gateway recolhe "informações estatísticas" sobre os dispositivos que ele administra. Quais informações são recolhidas depende do que está disponível em cada modelo de facial, mas geralmente é "status de comunicação" (o IP do facial está pingando?) e "status de uso" (quantas faces estão cadastradas em cada facial?). Essas informações são salvas em um cache e enviadas para o Accelero junto com as mensagens de keepalive.
Listener
É o serviço que "fala no MQTT", tanto pra receber pendências do Accelero quando pra enviar mensagens para o Accelero. Não faz nenhum tratamento de mensagens, é apenas o "correio".
Chegou alguma pendência, grava em um arquivo num diretório específica para alguém tratar.
Quando alguém que enviar uma mensagem pro broker, salva a mensagem num arquivo num outro diretório específica, e o Listener faz o efetivo envio.
PendencyHandler / PendencyHandlerDaemon
O PendencyHandler é o serviço que cuida de cada dispositivo específico. Se o gateway administra 10 faciais, haverá 10 cópias do PendencyHandler em execução. O PendencyHandlerDaemon "sobe" cada uma dessas instâncias e garante que estejam sempre no ar.
O handler fica o tempo todo scanneando o "diretório de pendências do facial que ele está cuidando", e se encontrar algum arquivo (cada arquivo é uma pendência), faz o tratamento e prepara a resposta (que será despachada pelo Listener).