121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
|
|
"src.dualinventive.com/go/lib/dilog"
|
|
|
|
"src.dualinventive.com/go/nbiot-interface/internal/cdp"
|
|
)
|
|
|
|
//Middleware represents something to wrap a message handler with.
|
|
//A middleware should provide both flavors, UDP and CDP.
|
|
type Middleware interface {
|
|
UDP(func([]byte)) func([]byte)
|
|
CDP(cdp.UplinkMsgReportHandlerFunc) cdp.UplinkMsgReportHandlerFunc
|
|
}
|
|
|
|
//EchoMiddleware implements the Middleware interface.
|
|
//It echoes incoming messages to a configured endpoint.
|
|
//The given headers will be used in the resulting communication.
|
|
type EchoMiddleware struct {
|
|
Logger dilog.Logger
|
|
Endpoint string
|
|
Headers map[string]string
|
|
client *http.Client
|
|
ch chan cdp.EndpointMessageReport
|
|
}
|
|
|
|
//CDP wraps a CDP message handler, and echos the incoming message after handling.
|
|
func (m *EchoMiddleware) CDP(handler cdp.UplinkMsgReportHandlerFunc) cdp.UplinkMsgReportHandlerFunc {
|
|
return func(emp *cdp.EndpointMessageReport) {
|
|
handler(emp)
|
|
m.queue(emp)
|
|
}
|
|
}
|
|
|
|
//UDP wraps a UDP message handler, and echos the incoming message after handling.
|
|
func (m *EchoMiddleware) UDP(handler func(payload []byte)) func(payload []byte) {
|
|
return func(payload []byte) {
|
|
handler(payload)
|
|
emp := cdp.NewEndpointMessage(payload, time.Now())
|
|
m.queue(emp)
|
|
}
|
|
}
|
|
|
|
//queue queues given message report in the echo channel.
|
|
//Messages in this channel will be sent over http post to configured endpoint/
|
|
func (m *EchoMiddleware) queue(emp *cdp.EndpointMessageReport) {
|
|
select {
|
|
case m.ch <- *emp:
|
|
m.Logger.Debug("echo message queued")
|
|
default:
|
|
m.Logger.Warning("echo buffer full, dropping message")
|
|
}
|
|
}
|
|
|
|
//send actually echoes the payload to the configured endpoint using a http request following CDP messaging.
|
|
func (m *EchoMiddleware) send(emp cdp.EndpointMessageReport) {
|
|
logger := m.Logger.WithField("emp", emp)
|
|
body, err := json.Marshal(emp)
|
|
if err != nil {
|
|
logger.WithError(err).Error("failed to marshal echo request body")
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", m.Endpoint, bytes.NewBuffer(body))
|
|
if err != nil {
|
|
logger.WithError(err).Error("failed to create echo request")
|
|
}
|
|
|
|
req.Header.Add("Content-Type", "application/json")
|
|
for key, value := range m.Headers {
|
|
req.Header.Add(key, value)
|
|
}
|
|
|
|
resp, err := m.client.Do(req)
|
|
if err != nil {
|
|
logger.WithError(err).Error("failed to send echo request")
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
logger.WithField("status", resp.StatusCode).Warning("echo response is not 200 OK")
|
|
}
|
|
}
|
|
|
|
//NewEchoMiddleware returns a new struct
|
|
func NewEchoMiddleware(
|
|
ctx context.Context,
|
|
logger dilog.Logger,
|
|
endpoint string,
|
|
headers map[string]string,
|
|
buffer int) *EchoMiddleware {
|
|
client := &http.Client{}
|
|
ch := make(chan cdp.EndpointMessageReport, buffer)
|
|
|
|
mw := &EchoMiddleware{
|
|
Logger: logger,
|
|
Endpoint: endpoint,
|
|
Headers: headers,
|
|
client: client,
|
|
ch: ch,
|
|
}
|
|
|
|
go func(ctx context.Context, m *EchoMiddleware, ch chan cdp.EndpointMessageReport) {
|
|
for {
|
|
select {
|
|
case emp := <-ch:
|
|
m.Logger.WithField("emp", emp).Debug("sending echo request")
|
|
m.send(emp)
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}(ctx, mw, ch)
|
|
|
|
return mw
|
|
}
|