From f3083820dcb8b22a429cf68502480ddd0b3d56b1 Mon Sep 17 00:00:00 2001 From: Alexander Lazarenko Date: Fri, 7 Feb 2025 21:04:06 +0300 Subject: [PATCH] Added testing and rewrite serializer Signed-off-by: Alexander Lazarenko --- .gitignore | 1 + certificate.go | 38 ++++++++ configmodel.go | 4 + devemm.go | 4 +- evem.go | 3 + go.mod | 10 +- go.sum | 7 -- io.go | 198 ++++++++++++++++----------------------- mediastreammodel.go | 8 +- scheme.go | 50 ++++++---- storm.go | 4 + test/certificate_test.go | 28 ++++++ 12 files changed, 199 insertions(+), 156 deletions(-) create mode 100644 .gitignore create mode 100644 test/certificate_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/certificate.go b/certificate.go index 5b0daa1..18a0865 100644 --- a/certificate.go +++ b/certificate.go @@ -1,5 +1,41 @@ package n9m +type NetConnectionType uint + +const ( + NetConnectionWired NetConnectionType = iota + NetConnectionWireless +) + +type TimeShiftSupportFlag uint8 + +const ( + TimeShiftNotSupported TimeShiftSupportFlag = iota + TimeShiftSupported +) + +type FileSystemVersionNumber uint8 + +const ( + FileSystemVersion4 FileSystemVersionNumber = iota + FileSystemVersion5 +) + +type CertificateConnectRequest struct { + Net NetConnectionType `json:"NET"` + SerialNumber string `json:"DNSO"` + DeviceName string `json:"DEVNAME"` + ChannelsNumber uint `json:"CHANNEL"` + LicensePlate string `json:"CARNUM"` + DeviceNumber string `json:"AUTONO"` + VehicleNumber string `json:"AUTOCAR"` + TimeShiftSupport TimeShiftSupportFlag `json:"TSE"` + FileSystemVersion FileSystemVersionNumber `json:"FSV"` + ICCID string `json:"ICCID"` + EvidenceSupport string `json:"EV"` +} + +/* func (e *Package) RequestConnect(session string, serial string, numOfCams int) { e.Payload = map[string]any{ "MODULE": "CERTIFICATE", @@ -39,3 +75,5 @@ func (e *Package) ResponseCertificateConnect(Sid string) { "SESSION": Sid, } } + +*/ diff --git a/configmodel.go b/configmodel.go index d6d4348..90835c2 100644 --- a/configmodel.go +++ b/configmodel.go @@ -1,5 +1,7 @@ package n9m +/* + // request reqistration parameters (directly to register) func (e *Package) RequestParameters(params map[string]any, serial int, session string) { e.Payload = map[string]any{ @@ -69,3 +71,5 @@ func (e *Package) ResponseConfigModelSet(Sid string) { "SESSION": Sid, } } + +*/ diff --git a/devemm.go b/devemm.go index db3e473..36db1e9 100644 --- a/devemm.go +++ b/devemm.go @@ -1,6 +1,6 @@ package n9m -import "fmt" +/* // main server util func (e *Package) RequestGeolocation(serial int, Sid string) { @@ -34,3 +34,5 @@ func (e *Package) ResponseGeolocation(errorCode int, errorCause string, serial i }, } } + +*/ diff --git a/evem.go b/evem.go index 08616c1..0cde99a 100644 --- a/evem.go +++ b/evem.go @@ -1,5 +1,6 @@ package n9m +/* // main server util func (e *Package) ResponseAlarm(alarmType int64, alarmUID int64, cmdno int64, cmdtype int64, run int64, serial string, Sid string) { e.Payload = map[string]any{ @@ -16,3 +17,5 @@ func (e *Package) ResponseAlarm(alarmType int64, alarmUID int64, cmdno int64, cm "SESSION": Sid, } } + +*/ diff --git a/go.mod b/go.mod index 470e4f8..ee04968 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,4 @@ module gitea.unprism.ru/KRBL/n9m go 1.21.3 -require ( - github.com/icza/bitio v1.1.0 - github.com/tidwall/gjson v1.17.0 -) - -require ( - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.1 // indirect -) +require github.com/icza/bitio v1.1.0 diff --git a/go.sum b/go.sum index 3023f7c..04176ee 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,3 @@ github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0= github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= -github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= -github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= diff --git a/io.go b/io.go index ceaecc4..d3305e2 100644 --- a/io.go +++ b/io.go @@ -3,48 +3,11 @@ package n9m import ( "bytes" "encoding/json" - "fmt" "log" "github.com/icza/bitio" - "github.com/tidwall/gjson" ) -// Extract fields from JSON -func (e *Package) SaveJsonFields() { - if value, exist := e.Payload["MODULE"]; exist { - e.Json.Module = value.(string) - } else { - e.Json.Module = "" - } - - if value, exist := e.Payload["KEY"]; exist { - e.Json.Key = value.(string) - } else { - e.Json.Key = "" - } - - if value, exist := e.Payload["OPERATION"]; exist { - e.Json.Operation = value.(string) - } else { - e.Json.Operation = "" - } - - if value, exist := e.Payload["RESPONSE"]; exist { - e.Json.Response = value.(map[string]interface{}) - } else { - e.Json.Response = make(map[string]interface{}) - } - - if value, exist := e.Payload["PARAMETER"]; exist { - e.Json.Parameters = value.(map[string]interface{}) - } else if value, exist := e.Payload["PARAMETERS"]; exist { - e.Json.Parameters = value.(map[string]interface{}) - } else { - e.Json.Parameters = make(map[string]interface{}) - } -} - // Read package func (e *Package) ReadPackage() bool { if len(e.Accum) < 12 { @@ -52,124 +15,129 @@ func (e *Package) ReadPackage() bool { } r := bitio.NewReader(bytes.NewBuffer(e.Accum)) - e.Version = r.TryReadBits(2) - e.Encription = r.TryReadBits(1) - e.Mark = r.TryReadBits(1) - e.CC = r.TryReadBits(4) - e.PayloadType = r.TryReadBits(8) - e.SSRC = r.TryReadBits(16) + e.Version = uint8(r.TryReadBits(2)) + e.EncryptionFlag = r.TryReadBool() + e.CompressFlag = r.TryReadBool() + e.CSRCCount = uint8(r.TryReadBits(4)) + e.PayloadType = PayloadType(r.TryReadBits(8)) + e.SSRC = uint16(r.TryReadBits(16)) - // log.Println(e.PayloadType) - - is_special := e.Encription == 1 && e.Mark == 1 - if is_special { + if e.EncryptionFlag && e.CompressFlag { + // TODO: get snippet, that use this code r.TryReadBits(8 * 4) - e.PayloadLen = r.TryReadBits(8) + e.payloadLen = r.TryReadBits(8) r.TryReadBits(3 * 8) - if uint64(len(e.Accum)) < e.PayloadLen+12 { + if uint64(len(e.Accum)) < e.payloadLen+12 { return false } } else { - e.PayloadLen = r.TryReadBits(32) + e.payloadLen = r.TryReadBits(32) + // WTF: e.CC is useless for i := uint64(0); i < 1; i++ { e.CSRC[i] = r.TryReadBits(32) } } - numOfBytes := 0 - rawbytes := []byte{} - if e.PayloadLen != 0 { - if e.PayloadLen > 1000000 { - log.Printf("%v\n", e) - log.Panicln("CORRUPTED PACKAGE") - } - - rawbytes = make([]byte, e.PayloadLen) - numOfBytes, _ = r.Read(rawbytes) + if e.payloadLen > 1e6 { + log.Printf("%v\n", e) + log.Panicln("CORRUPTED PACKAGE") } - if numOfBytes != int(e.PayloadLen) { + numOfBytes := 0 + + if e.payloadLen != 0 { + e.RawPayload = make([]byte, e.payloadLen) + numOfBytes = r.TryRead(e.RawPayload) + } else { + e.RawPayload = []byte{} + } + + if numOfBytes != int(e.payloadLen) { return false } - e.Raw = e.Accum[:12+e.PayloadLen] - e.Accum = e.Accum[12+e.PayloadLen:] - e.RawPayload = rawbytes + e.Accum = e.Accum[12+e.payloadLen:] - var ok bool - e.GPayload = gjson.Parse(string(rawbytes)) - e.Payload, ok = e.GPayload.Value().(map[string]interface{}) - if !ok { - e.Payload = gjson.Parse("{}").Value().(map[string]interface{}) + if e.PayloadType == PayloadTypeData { + if err := json.Unmarshal(e.RawPayload, &e.Payload); err != nil { + log.Printf("Error parsing JSON payload: %v", err) + return false + } } - e.SaveJsonFields() + if r.TryError != nil { + log.Printf("TryError encountered: %v", r.TryError) + return false + } - return e.PayloadLen > 0 + return true +} + +func (e *Package) PackPayload() (err error) { + e.RawPayload, err = json.Marshal(e.Payload) + e.payloadLen = uint64(len(e.RawPayload)) + + if e.payloadLen != 0 { + e.RawPayload = append(e.RawPayload, 0) + e.payloadLen++ + } + + return } func (e *Package) PackPackage() []byte { - e.SaveJsonFields() + var err error - b := &bytes.Buffer{} - w := bitio.NewWriter(b) - - w.TryWriteBits(e.Version, 2) - w.TryWriteBits(e.Encription, 1) - w.TryWriteBits(e.Mark, 1) - w.TryWriteBits(e.CC, 4) - w.TryWriteBits(e.PayloadType, 8) - w.TryWriteBits(e.SSRC, 16) - conv, err := json.Marshal(e.Payload) - - if err != nil { - fmt.Println(err) - return nil + if err = e.PackPayload(); err != nil { + log.Printf("Error while packing payload: %v", err) + return []byte{} } - e.PayloadLen = uint64(len(conv)) - if e.PayloadLen != 0 { - e.PayloadLen++ - } - w.TryWriteBits(e.PayloadLen, 32) - - // WTF: e.CC is useless - for i := uint64(0); i < 1; i++ { - w.TryWriteBits(e.CSRC[i], 32) - } - if e.PayloadLen != 0 { - w.Write(conv) - w.Write([]byte{0}) - } - w.Close() - - return b.Bytes() + return e.PackRawPackage() } func (e *Package) PackRawPackage() []byte { + var err error + b := &bytes.Buffer{} w := bitio.NewWriter(b) - w.TryWriteBits(e.Version, 2) - w.TryWriteBits(e.Encription, 1) - w.TryWriteBits(e.Mark, 1) - w.TryWriteBits(e.CC, 4) - w.TryWriteBits(e.PayloadType, 8) - w.TryWriteBits(e.SSRC, 16) - e.PayloadLen = uint64(len(e.RawPayload) + 1) - w.TryWriteBits(e.PayloadLen, 32) + w.TryWriteBits(uint64(e.Version), 2) + + w.TryWriteBool(e.EncryptionFlag) + w.TryWriteBool(e.CompressFlag) + + w.TryWriteBits(uint64(e.CSRCCount), 4) + w.TryWriteBits(uint64(e.PayloadType), 8) + w.TryWriteBits(uint64(e.SSRC), 16) + + w.TryWriteBits(e.payloadLen, 32) // WTF: e.CC is useless for i := uint64(0); i < 1; i++ { w.TryWriteBits(e.CSRC[i], 32) } - if e.PayloadLen != 0 { - w.Write(e.RawPayload) - w.Write([]byte{0}) + + if e.payloadLen != 0 { + w.TryWrite(e.RawPayload) + } + + if err = w.Close(); err != nil { + log.Printf("Error while closing writer: %v", err) + return []byte{} } - w.Close() return b.Bytes() } + +func (e *Package) GetParametersAs(parameters any) error { + marshal, err := json.Marshal(e.Payload.Parameter) + + if err != nil { + return err + } + + return json.Unmarshal(marshal, parameters) +} diff --git a/mediastreammodel.go b/mediastreammodel.go index de7dc1f..3f5b536 100644 --- a/mediastreammodel.go +++ b/mediastreammodel.go @@ -1,10 +1,6 @@ package n9m -import ( - "fmt" - "os" -) - +/* var ip string = os.Getenv("SERVER_IP") func (e *Package) MediaRequestDownloadVideo(token int, serial string, session string, camNo int, date string, begin_time string, end_time string, recordID string, serverId int) { @@ -108,3 +104,5 @@ func (e *Package) ControlRemotePlayback(token int, serial string, session string "SESSION": session, } } + +*/ diff --git a/scheme.go b/scheme.go index 02e7edd..12b67ab 100644 --- a/scheme.go +++ b/scheme.go @@ -1,32 +1,44 @@ package n9m -import "github.com/tidwall/gjson" +type PayloadType uint8 -type PayloadJson struct { - Module string - Key string - Operation string - Parameters map[string]interface{} - Response map[string]interface{} +const ( + PayloadTypeData PayloadType = 0 + PayloadTypeLive PayloadType = 2 + PayloadTypeDownload PayloadType = 3 + PayloadTypePlayback PayloadType = 4 + PayloadTypeCapturedPhotos PayloadType = 6 + PayloadTypeParameterImport PayloadType = 10 + PayloadTypeParameterExport PayloadType = 11 + PayloadTypeTransmissionSubStream PayloadType = 15 + PayloadTypeRecordingSubStream PayloadType = 16 + PayloadTypeBlackBox PayloadType = 17 + PayloadTypeGPS PayloadType = 22 + PayloadTypeMaintainData PayloadType = 30 +) + +type Message struct { + Module string `json:"MODULE"` + Session string `json:"SESSION"` + Operation string `json:"OPERATION"` + Parameter interface{} `json:"PARAMETER,omitempty"` + Response interface{} `json:"RESPONSE,omitempty"` } type Package struct { - Version uint64 - Encription uint64 - Mark uint64 - CC uint64 - PayloadType uint64 - SSRC uint64 + Version uint8 + EncryptionFlag bool + CompressFlag bool + CSRCCount uint8 + + PayloadType PayloadType + SSRC uint16 Reserved uint64 CSRC [16]uint64 - PayloadLen uint64 - GPayload gjson.Result - Payload map[string]interface{} + payloadLen uint64 + Payload Message RawPayload []byte - Raw []byte Accum []byte - - Json PayloadJson } diff --git a/storm.go b/storm.go index 977420c..13e5d17 100644 --- a/storm.go +++ b/storm.go @@ -1,5 +1,7 @@ package n9m +/* + func (e *Package) ResponseCalendar(errorCode int, errorCause string, serial int, dates []string) { e.Payload = map[string]any{ "MODULE": "STORM", @@ -78,3 +80,5 @@ func (e *Package) RequestFileList(queryTime string, serial int, session string, "SESSION": session, } } + +*/ diff --git a/test/certificate_test.go b/test/certificate_test.go new file mode 100644 index 0000000..3273fe5 --- /dev/null +++ b/test/certificate_test.go @@ -0,0 +1,28 @@ +package test + +import ( + "fmt" + "gitea.unprism.ru/KRBL/n9m" + "testing" +) + +func TestCertificateConnection(t *testing.T) { + dump := []byte{0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe9, 0x52, 0x0, 0x0, 0x0, 0x7b, 0x22, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x22, 0x3a, 0x22, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x22, 0x2c, 0x22, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x22, 0x3a, 0x22, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x22, 0x2c, 0x22, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x22, 0x3a, 0x7b, 0x22, 0x41, 0x55, 0x54, 0x4f, 0x43, 0x41, 0x52, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x41, 0x55, 0x54, 0x4f, 0x4e, 0x4f, 0x22, 0x3a, 0x22, 0x30, 0x22, 0x2c, 0x22, 0x43, 0x41, 0x52, 0x4e, 0x55, 0x4d, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x22, 0x3a, 0x31, 0x32, 0x2c, 0x22, 0x43, 0x49, 0x44, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x43, 0x4e, 0x41, 0x4d, 0x45, 0x22, 0x3a, 0x22, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x45, 0x52, 0x5f, 0x4e, 0x55, 0x4c, 0x4c, 0x22, 0x2c, 0x22, 0x44, 0x45, 0x56, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x44, 0x45, 0x56, 0x4e, 0x41, 0x4d, 0x45, 0x22, 0x3a, 0x22, 0x4d, 0x44, 0x56, 0x52, 0x22, 0x2c, 0x22, 0x44, 0x45, 0x56, 0x54, 0x59, 0x50, 0x45, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x44, 0x4c, 0x49, 0x50, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x4c, 0x49, 0x50, 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x4d, 0x54, 0x22, 0x3a, 0x22, 0x65, 0x74, 0x68, 0x30, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x44, 0x4c, 0x50, 0x22, 0x3a, 0x5b, 0x38, 0x30, 0x2c, 0x39, 0x30, 0x30, 0x36, 0x5d, 0x2c, 0x22, 0x44, 0x53, 0x4e, 0x4f, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x38, 0x38, 0x30, 0x33, 0x36, 0x31, 0x42, 0x38, 0x22, 0x2c, 0x22, 0x45, 0x49, 0x44, 0x22, 0x3a, 0x22, 0x6e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x22, 0x2c, 0x22, 0x45, 0x56, 0x22, 0x3a, 0x22, 0x56, 0x31, 0x2e, 0x31, 0x22, 0x2c, 0x22, 0x46, 0x53, 0x56, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x4c, 0x49, 0x4e, 0x45, 0x4e, 0x4f, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x4d, 0x41, 0x43, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x49, 0x4d, 0x41, 0x43, 0x22, 0x3a, 0x22, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x4d, 0x54, 0x22, 0x3a, 0x22, 0x65, 0x74, 0x68, 0x30, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x4d, 0x4f, 0x44, 0x45, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x4d, 0x54, 0x59, 0x50, 0x45, 0x22, 0x3a, 0x33, 0x31, 0x2c, 0x22, 0x4e, 0x45, 0x54, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x50, 0x52, 0x4f, 0x22, 0x3a, 0x22, 0x31, 0x2e, 0x30, 0x2e, 0x35, 0x22, 0x2c, 0x22, 0x53, 0x54, 0x59, 0x50, 0x45, 0x22, 0x3a, 0x35, 0x34, 0x2c, 0x22, 0x54, 0x53, 0x45, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x55, 0x4e, 0x41, 0x4d, 0x45, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x55, 0x4e, 0x4f, 0x22, 0x3a, 0x22, 0x22, 0x7d, 0x2c, 0x22, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x22, 0x3a, 0x22, 0x36, 0x63, 0x65, 0x64, 0x35, 0x63, 0x66, 0x37, 0x2d, 0x61, 0x34, 0x35, 0x63, 0x2d, 0x34, 0x61, 0x63, 0x61, 0x2d, 0x62, 0x39, 0x64, 0x35, 0x2d, 0x66, 0x65, 0x39, 0x34, 0x61, 0x62, 0x36, 0x32, 0x66, 0x39, 0x65, 0x61, 0x22, 0x7d, 0xa} + pack := n9m.Package{} + + pack.AddToAccum(dump) + + if !pack.ReadPackage() { + t.Error("Package wasn't read!") + return + } + + var connectionParams n9m.CertificateConnectRequest + + if err := pack.GetParametersAs(&connectionParams); err != nil { + t.Error(err) + return + } + + fmt.Println(connectionParams) +}