feat(api): dashboard and general info [ close #125 ]
This commit is contained in:
parent
2d9257f21c
commit
8843cd9dab
|
|
@ -62,7 +62,12 @@ func StartApi(a Api) {
|
||||||
iot.HandleFunc("/{sn}/fw_update", a.deviceFwUpdate).Methods("PUT")
|
iot.HandleFunc("/{sn}/fw_update", a.deviceFwUpdate).Methods("PUT")
|
||||||
iot.HandleFunc("/{sn}/wifi", a.deviceWifi).Methods("PUT", "GET")
|
iot.HandleFunc("/{sn}/wifi", a.deviceWifi).Methods("PUT", "GET")
|
||||||
mtp := r.PathPrefix("/api/mtp").Subrouter()
|
mtp := r.PathPrefix("/api/mtp").Subrouter()
|
||||||
mtp.HandleFunc("/mqtt", a.MqttInfo).Methods("GET")
|
mtp.HandleFunc("", a.mtpInfo).Methods("GET")
|
||||||
|
dash := r.PathPrefix("/api/info").Subrouter()
|
||||||
|
dash.HandleFunc("/vendors", a.vendorsInfo).Methods("GET")
|
||||||
|
dash.HandleFunc("/status", a.statusInfo).Methods("GET")
|
||||||
|
dash.HandleFunc("/device_class", a.productClassInfo).Methods("GET")
|
||||||
|
dash.HandleFunc("/general", a.generalInfo).Methods("GET")
|
||||||
users := r.PathPrefix("/api/users").Subrouter()
|
users := r.PathPrefix("/api/users").Subrouter()
|
||||||
users.HandleFunc("", a.retrieveUsers).Methods("GET")
|
users.HandleFunc("", a.retrieveUsers).Methods("GET")
|
||||||
|
|
||||||
|
|
@ -75,6 +80,10 @@ func StartApi(a Api) {
|
||||||
return middleware.Middleware(handler)
|
return middleware.Middleware(handler)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
dash.Use(func(handler http.Handler) http.Handler {
|
||||||
|
return middleware.Middleware(handler)
|
||||||
|
})
|
||||||
|
|
||||||
users.Use(func(handler http.Handler) http.Handler {
|
users.Use(func(handler http.Handler) http.Handler {
|
||||||
return middleware.Middleware(handler)
|
return middleware.Middleware(handler)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
146
backend/services/controller/internal/api/info.go
Normal file
146
backend/services/controller/internal/api/info.go
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/leandrofars/oktopus/internal/db"
|
||||||
|
"github.com/leandrofars/oktopus/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StatusCount struct {
|
||||||
|
Online int
|
||||||
|
Offline int
|
||||||
|
}
|
||||||
|
|
||||||
|
type GeneralInfo struct {
|
||||||
|
MqttRtt time.Duration
|
||||||
|
ProductClassCount []db.ProductClassCount
|
||||||
|
StatusCount StatusCount
|
||||||
|
VendorsCount []db.VendorsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Api) generalInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var result GeneralInfo
|
||||||
|
|
||||||
|
productclasscount, err := a.Db.RetrieveProductsClassInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vendorcount, err := a.Db.RetrieveVendorsInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
statuscount, err := a.Db.RetrieveStatusInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range statuscount {
|
||||||
|
switch v.Status {
|
||||||
|
case utils.Online:
|
||||||
|
result.StatusCount.Online = v.Count
|
||||||
|
case utils.Offline:
|
||||||
|
result.StatusCount.Offline = v.Count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.VendorsCount = vendorcount
|
||||||
|
result.ProductClassCount = productclasscount
|
||||||
|
|
||||||
|
/* ------------ TODO: [mqtt rtt] create common function for this ------------ */
|
||||||
|
//TODO: address with value from env or something like that
|
||||||
|
conn, err := net.Dial("tcp", "127.0.0.1:1883")
|
||||||
|
if err != nil {
|
||||||
|
json.NewEncoder(w).Encode("Error to connect to broker")
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
info, err := tcpInfo(conn.(*net.TCPConn))
|
||||||
|
if err != nil {
|
||||||
|
json.NewEncoder(w).Encode("Error to get TCP socket info")
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rtt := time.Duration(info.Rtt) * time.Microsecond
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
result.MqttRtt = rtt / 1000
|
||||||
|
|
||||||
|
err = json.NewEncoder(w).Encode(result)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Api) vendorsInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vendors, err := a.Db.RetrieveVendorsInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(vendors)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Api) productClassInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vendors, err := a.Db.RetrieveProductsClassInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(vendors)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Api) statusInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vendors, err := a.Db.RetrieveStatusInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var status StatusCount
|
||||||
|
for _, v := range vendors {
|
||||||
|
switch v.Status {
|
||||||
|
case utils.Online:
|
||||||
|
status.Online = v.Count
|
||||||
|
case utils.Offline:
|
||||||
|
status.Offline = v.Count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.NewEncoder(w).Encode(status)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -10,10 +10,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type mqttInfo struct {
|
type mqttInfo struct {
|
||||||
Rtt time.Duration
|
MqttRtt time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) MqttInfo(w http.ResponseWriter, r *http.Request) {
|
func (a *Api) mtpInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
//TODO: address with value from env or something like that
|
//TODO: address with value from env or something like that
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:1883")
|
conn, err := net.Dial("tcp", "127.0.0.1:1883")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -31,7 +31,7 @@ func (a *Api) MqttInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
rtt := time.Duration(info.Rtt) * time.Microsecond
|
rtt := time.Duration(info.Rtt) * time.Microsecond
|
||||||
json.NewEncoder(w).Encode(mqttInfo{
|
json.NewEncoder(w).Encode(mqttInfo{
|
||||||
Rtt: rtt / 1000,
|
MqttRtt: rtt / 1000,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,14 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
SN string
|
SN string
|
||||||
Model string
|
Model string
|
||||||
Customer string
|
Customer string
|
||||||
Vendor string
|
Vendor string
|
||||||
Version string
|
Version string
|
||||||
Status uint8
|
ProductClass string
|
||||||
MTP []map[string]string
|
Status uint8
|
||||||
|
MTP []map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) CreateDevice(device Device) error {
|
func (d *Database) CreateDevice(device Device) error {
|
||||||
|
|
|
||||||
97
backend/services/controller/internal/db/info.go
Normal file
97
backend/services/controller/internal/db/info.go
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VendorsCount struct {
|
||||||
|
Vendor string `bson:"_id" json:"vendor"`
|
||||||
|
Count int `bson:"count" json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductClassCount struct {
|
||||||
|
ProductClass string `bson:"_id" json:"productClass"`
|
||||||
|
Count int `bson:"count" json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatusCount struct {
|
||||||
|
Status int `bson:"_id" json:"status"`
|
||||||
|
Count int `bson:"count" json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) RetrieveVendorsInfo() ([]VendorsCount, error) {
|
||||||
|
var results []VendorsCount
|
||||||
|
cursor, err := d.devices.Aggregate(d.ctx, []bson.M{
|
||||||
|
{
|
||||||
|
"$group": bson.M{
|
||||||
|
"_id": "$vendor",
|
||||||
|
"count": bson.M{"$sum": 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close(d.ctx)
|
||||||
|
if err := cursor.All(d.ctx, &results); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, result := range results {
|
||||||
|
log.Println(result)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) RetrieveStatusInfo() ([]StatusCount, error) {
|
||||||
|
var results []StatusCount
|
||||||
|
cursor, err := d.devices.Aggregate(d.ctx, []bson.M{
|
||||||
|
{
|
||||||
|
"$group": bson.M{
|
||||||
|
"_id": "$status",
|
||||||
|
"count": bson.M{"$sum": 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close(d.ctx)
|
||||||
|
if err := cursor.All(d.ctx, &results); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, result := range results {
|
||||||
|
log.Println(result)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) RetrieveProductsClassInfo() ([]ProductClassCount, error) {
|
||||||
|
var results []ProductClassCount
|
||||||
|
cursor, err := d.devices.Aggregate(d.ctx, []bson.M{
|
||||||
|
{
|
||||||
|
"$group": bson.M{
|
||||||
|
"_id": "$productclass",
|
||||||
|
"count": bson.M{"$sum": 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close(d.ctx)
|
||||||
|
if err := cursor.All(d.ctx, &results); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, result := range results {
|
||||||
|
log.Println(result)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: fix this function to also change device status at different mtp
|
||||||
func (d *Database) UpdateStatus(sn string, status uint8) error {
|
func (d *Database) UpdateStatus(sn string, status uint8) error {
|
||||||
var result bson.M
|
var result bson.M
|
||||||
err := d.devices.FindOneAndUpdate(d.ctx, bson.D{{"sn", sn}}, bson.D{{"$set", bson.D{{"status", status}}}}).Decode(&result)
|
err := d.devices.FindOneAndUpdate(d.ctx, bson.D{{"sn", sn}}, bson.D{{"$set", bson.D{{"status", status}}}}).Decode(&result)
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,7 @@ func (m *Mqtt) handleNewDevice(deviceMac string) {
|
||||||
"Device.DeviceInfo.ModelName",
|
"Device.DeviceInfo.ModelName",
|
||||||
"Device.DeviceInfo.SoftwareVersion",
|
"Device.DeviceInfo.SoftwareVersion",
|
||||||
"Device.DeviceInfo.SerialNumber",
|
"Device.DeviceInfo.SerialNumber",
|
||||||
|
"Device.DeviceInfo.ProductClass",
|
||||||
},
|
},
|
||||||
MaxDepth: 1,
|
MaxDepth: 1,
|
||||||
},
|
},
|
||||||
|
|
@ -284,6 +285,7 @@ func (m *Mqtt) handleNewDevicesResponse(p []byte, sn string) {
|
||||||
device.Vendor = msg.ReqPathResults[0].ResolvedPathResults[0].ResultParams["Manufacturer"]
|
device.Vendor = msg.ReqPathResults[0].ResolvedPathResults[0].ResultParams["Manufacturer"]
|
||||||
device.Model = msg.ReqPathResults[1].ResolvedPathResults[0].ResultParams["ModelName"]
|
device.Model = msg.ReqPathResults[1].ResolvedPathResults[0].ResultParams["ModelName"]
|
||||||
device.Version = msg.ReqPathResults[2].ResolvedPathResults[0].ResultParams["SoftwareVersion"]
|
device.Version = msg.ReqPathResults[2].ResolvedPathResults[0].ResultParams["SoftwareVersion"]
|
||||||
|
device.ProductClass = msg.ReqPathResults[4].ResolvedPathResults[0].ResultParams["ProductClass"]
|
||||||
device.SN = sn
|
device.SN = sn
|
||||||
|
|
||||||
mtp := map[string]string{
|
mtp := map[string]string{
|
||||||
|
|
@ -291,6 +293,7 @@ func (m *Mqtt) handleNewDevicesResponse(p []byte, sn string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
device.MTP = append(device.MTP, mtp)
|
device.MTP = append(device.MTP, mtp)
|
||||||
|
device.Status = utils.Online
|
||||||
|
|
||||||
err = m.DB.CreateDevice(device)
|
err = m.DB.CreateDevice(device)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user