
Uma biblioteca Go para usar a API websocket do zeek broker.
Esta biblioteca implementa a interface websocket do Zeek Broker.
Funções auxiliares são fornecidas com mapeamentos razoáveis entre os tipos Zeek e Go.
A biblioteca contém dois pacotes:
encodingencoding modela a estrutura de dados recursiva baseada em JSON para representar tipos Zeek (o struct Data), bem como a codificação Broker de eventos e mensagens de erro Zeek (o struct DataMessage). Essas estruturas podem (e em alguns casos devem) ser usadas diretamente (veja o exemplo de assinatura na próxima seção), mas algumas funções auxiliares tornam a construção de mensagens mais conveniente. Para construir uma string Zeek manualmente:
zeekString := encoding.Data{
DataType: encoding.TypeString,
DataValue: "foo",
}
...ou via a função auxiliar:
zeekString := encoding.String("foo")
O auxiliar vector, em particular, é uma função variádica que aceita encoding.Data:
zeekVector := encoding.Vector(encoding.Count(1), encoding.Count(2), encoding.Count(3))
Por fim, eventos podem ser criados diretamente:
zeekEvent := encoding.NewEvent("some_event_name", zeekVector, zeekString)
clientclient fornece o elo websocket para comunicar com a API WS do broker, encapsulando github.com/gorilla/websocket:
Para publicar um evento:
broker, err := client.NewClient(...)
err := broker.PublishEvent("/the/topic", zeekEvent)
As assinaturas de tópicos são passadas como uma fatia de strings para client.Newclient(). O método ReadEvent() do client retorna um único evento do Broker (em qualquer um dos tópicos assinados) ou um erro que pode ocorrer na própria biblioteca ou erros recebidos do Broker):
broker, err := client.NewClient(..., []string{"/the/topic"})
topic, zeekEvent, err := broker.ReadEvent()
Se a conexão com o broker for encerrada normalmente, a função client.IsNormalWebsocketClose() pode ser usada para verificar o erro retornado.
O código do client deve acessar os valores dos argumentos do evento por meio de asserções de tipo:
if len(evt.Arguments) < someConstantGreaterOrEqualToOne {
// handle too few arguments case
}
if evt.Arguments[0].DataType != encoding.TypeString {
// handle unexpected data type case
}
stringArgument0, ok := evt.Arguments[0].DataValue.(string)
if !ok {
// handle type assertion error - this would indicate a bug (we trust+verify).
}
// now we use stringArgument0
O tratamento e o despacho assíncronos de eventos recebidos por meio de assinaturas seriam melhor implementados como um wrapper de Client.ReadEvent(). Uma implementação simples é fornecida em client.AsyncSubscription().
O tratamento mais avançado da conexão websocket (por exemplo, definindo timeouts, lidando com reconexão, etc.) é melhor implementado como um wrapper de client.Client, ou uma implementação nova/substituta que use o pacote encoding (contribuições/PRs são bem-vindos!).
As conexões de rede do Broker (tanto nativas quanto a interface websocket) habilitam TLS por padrão com uma configuração incomum que desativa a verificação de host e seleciona um conjunto de cifras que permitem criptografia sem certificados (Anonymous Diffie-Hellman / AECDH). Para usar esse modo, é necessário passar weirdtls.BrokerDefaultTLSDialer como argumento da função dialer para encoding.NewClient. Observe que isso adiciona OpenSSL como dependência.
Alternativamente, a implementação crypto/tls da biblioteca padrão pode ser usada se ambos os lados (o client e o zeek/broker) estiverem configurados para usar TLS com certificados. Esta biblioteca fornece uma função auxiliar conveniente (securetls.MakeSecureDialer()) que retorna uma função dialer a partir de arquivos PEM para a CA e o certificado/chave do client. Veja este caso de teste btest para um exemplo dessa configuração.
Por fim, o TLS pode ser desativado para conexões do broker usando redef Broker::disable_ssl = T;. Veja este caso de teste btest para um exemplo em que encoding.NewClient é chamado com argumentos para operação insegura.
No zeek 7.2, a API websocket será movida para fora do broker para o framework Cluster, e o padrão é desativar o TLS. Este caso de teste btest usa as novas funções do lado do zeek e demonstra o uso desta biblioteca chamando encoding.NewClient() com o argumento secure definido como false.
Quando o zeek 7.2 se tornar a versão LTS, uma nova versão (major) desta biblioteca removerá o suporte ao modo TLS AECDH descrito na seção acima, eliminando a dependência do OpenSSL.
Executando um script broker no lado do zeek:
$ cd example/
$ zeek listen.zeek
Agora execute o exemplo:
$ cd example/
$ go build && ./example
2023/05/05 12:56:55 connected to remote endpoint with UUID=c9b0bfd6-3b8d-5de2-a51c-9af7b81aaad3 version=2.5.0-dev
2023/05/05 12:56:55 > topic=/topic/test | event ping("my-message": string, "1": count)
2023/05/05 12:56:55 < topic=/topic/test | event pong("my-message": string, "2": count)
2023/05/05 12:56:56 > topic=/topic/test | event ping("my-message": string, "2": count)
2023/05/05 12:56:56 < topic=/topic/test | event pong("my-message": string, "3": count)
...enquanto isso, o script zeek:
peer added, [id=e537f8b4-de32-52ea-9587-4e6e15bdfe20, network=[address=127.0.0.1, bound_port=50690/tcp]]
receiver got ping: my-message, 1
receiver got ping: my-message, 2
A maioria dos auxiliares e das estruturas de dados básicas no pacote encoding tem testes unitários (execute go test ./...).
Testes de ponta a ponta são implementados como dois casos de btest (execute cd tests/; btest).