src.dualinventive.com/go/nbiot-interface/internal/cdp/endpoint.go

107 lines
2.4 KiB
Go

package cdp
import (
"encoding/json"
"io/ioutil"
"net/http"
"src.dualinventive.com/go/lib/dilog"
)
// Endpoint for T-Mobile CDP HTTP JSON
type Endpoint struct {
mux http.Handler
url string
log dilog.Logger
uplinkMsgReportHandler UplinkMsgReportHandlerFunc
basicAuth *endpointBasicAuth
}
// NewEndpoint create a new endpoint on url
func NewEndpoint(url string, opts ...EndpointOption) (*Endpoint, error) {
ep := &Endpoint{}
for _, option := range opts {
err := option(ep)
if err != nil {
return nil, err
}
}
if ep.log == nil {
ep.log = dilog.Discard
}
ep.url = url
mux := http.NewServeMux()
mux.HandleFunc("/", ep.uplinkMsgDataHandler)
ep.mux = mux
return ep, nil
}
// ListenAndServe listens and serves the endpoint
func (ep *Endpoint) ListenAndServe() error {
return http.ListenAndServe(ep.url, ep.mux)
}
// uplinkMsgDataHandlerReadEndpointMessage reads the EndpointMessage from the http request
func uplinkMsgDataHandlerReadEndpointMessage(r *http.Request) (*EndpointMessage, error) {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
err = r.Body.Close()
if err != nil {
return nil, err
}
epMsg := &EndpointMessage{}
err = json.Unmarshal(data, epMsg)
if err != nil {
return nil, err
}
return epMsg, nil
}
func (ep *Endpoint) uplinkMsgDataHandler(w http.ResponseWriter, r *http.Request) {
if ep.uplinkMsgReportHandler == nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
// When basic authentication option is set we validate the request
if ep.basicAuth != nil {
if !ep.basicAuth.IsRequestAuthenticated(r) {
ep.log.WithFields(dilog.Fields{
"ip": getIPAddress(r),
}).Error("client not authenticated")
w.Header().Set("WWW-Authenticate", "Basic")
w.WriteHeader(http.StatusUnauthorized)
return
}
}
// It is possible the IoT portal probes if the URL is valid with an empty request
if r.ContentLength == 0 {
w.WriteHeader(http.StatusOK)
return
}
epMsg, err := uplinkMsgDataHandlerReadEndpointMessage(r)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
ep.log.WithError(err).Error("uplinkMsgDataHandlerReadEndpointMessage failed")
return
}
for _, report := range epMsg.Reports {
report := report
if report.ResourcePath != ResourcePathUplinkMsgData {
continue
}
ep.uplinkMsgReportHandler(&report)
}
}