n9m/cmd/dev-server/main.go
Alexander Lazarenko 7c348629d6
Add custom notFoundError type and improve error handling
Introduce the notFoundError struct to provide more detailed error messages for missing handlers like alarms, JSON operations, and payload types. Update error handling to leverage the new custom type and use errors.As for better flexibility. Additionally, update module imports to version v2 in relevant files.
2025-02-23 11:51:16 +03:00

170 lines
3.5 KiB
Go

package main
import (
"errors"
"fmt"
"gitea.unprism.ru/KRBL/n9m/v2"
"io"
"net"
"os"
"syscall"
)
func main() {
ln, err := net.Listen("tcp", "0.0.0.0:5556")
if err != nil {
panic(err)
}
for {
var conn net.Conn
conn, err = ln.Accept()
if err != nil {
continue
}
go handle(conn)
}
}
func handleSpecialPackages(_ *n9m.SmartPackage, pack n9m.Package) error {
switch pack.SSRC {
case n9m.SpecialPayloadTypeGPS:
fmt.Printf("%+v\n", pack.GPS)
return nil
default:
return fmt.Errorf("unhandled special operation: %d", pack.SSRC)
}
}
func handleCertificateConnect(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
var params n9m.CertificateConnectRequest
if err = pack.GetParametersAs(&params); err != nil {
return fmt.Errorf("failed to get parameters: %w", err)
}
var response = n9m.CertificateConnectResponse{
ErrorCode: 0,
CommandMask: n9m.CommandMaskAll,
}
pack.SetResponse(response)
if _, err = sPack.Write(pack.PackPackage()); err != nil {
return fmt.Errorf("failed to write package: %w", err)
}
fmt.Println("Connected:", params.SerialNumber)
sPack.Storage["serial"] = params.SerialNumber
var request n9m.ConfigModelGetRequest
request.MDVR = "?"
pack.Payload.Module = "CONFIGMODEL"
pack.Payload.Operation = "GET"
pack.SetParameters(request)
sPack.Write(pack.PackPackage())
return
}
func handleKeepAlive(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
serial := sPack.Storage["serial"]
fmt.Println(serial, "still alive!")
pack.SetResponse(nil)
sPack.Write(pack.PackPackage())
return
}
func handleGetConfig(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
serial := sPack.Storage["serial"]
os.WriteFile(fmt.Sprintf("./%s.json", serial), pack.RawPayload, 0644)
return
}
func handleUselessAlarms(sPack *n9m.SmartPackage, pack n9m.Package, response n9m.SendAlarmInfoResponse) (err error) {
return nil
}
func handleVideoLossAlarm(sPack *n9m.SmartPackage, pack n9m.Package, response n9m.SendAlarmInfoResponse) (err error) {
fmt.Println("Video loss alarm!")
return nil
}
func handleCameraCoveredAlarm(sPack *n9m.SmartPackage, pack n9m.Package, response n9m.SendAlarmInfoResponse) (err error) {
fmt.Println("Camera covered alarm!")
return nil
}
func createSmartPackage(conn net.Conn) (pack *n9m.SmartPackage) {
pack = n9m.NewSmartPackage(conn)
pack.AddPayloadHandler(n9m.PayloadTypeSpecial, handleSpecialPackages)
pack.AddJSONHandler("CERTIFICATE", "CONNECT", handleCertificateConnect)
pack.AddJSONHandler("CERTIFICATE", "KEEPALIVE", handleKeepAlive)
pack.AddJSONHandler("CONFIGMODEL", "GET", handleGetConfig)
pack.AddAlarmHandler(n9m.AlarmTypeMotionDetection, handleUselessAlarms)
pack.AddAlarmHandler(n9m.AlarmTypeVideoLoss, handleVideoLossAlarm)
pack.AddAlarmHandler(n9m.AlarmTypeCameraCovered, handleCameraCoveredAlarm)
return
}
/*
go func() {
pack := packS
pack.Payload.Module = "EVEM"
pack.Payload.Operation = "GALARMING"
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for range ticker.C {
fmt.Println("Sent!")
if _, err := conn.Write(pack.PackPackage()); err != nil {
fmt.Println("Failed to send GALARMING:", err)
return
}
}
}()
*/
func isNetConnClosedErr(err error) bool {
switch {
case
errors.Is(err, net.ErrClosed),
errors.Is(err, io.EOF),
errors.Is(err, syscall.EPIPE):
return true
default:
return false
}
}
func handle(conn net.Conn) {
pack := createSmartPackage(conn)
var err error
for {
if err = pack.Handle(); err != nil {
fmt.Println("Error:", err)
if isNetConnClosedErr(err) {
return
}
}
}
}