package n9m import ( "bytes" "encoding/hex" "encoding/json" "fmt" "os" "log" "github.com/icza/bitio" "github.com/tidwall/gjson" ) var ip string = os.Getenv("SERVER_IP") type PayloadJson struct { Module string Key string Operation string Parameters map[string]interface{} Response map[string]interface{} } type Package struct { Version uint64 Encription uint64 Mark uint64 CC uint64 PayloadType uint64 SSRC uint64 Reserved uint64 CSRC [16]uint64 PayloadLen uint64 GPayload gjson.Result Payload map[string]interface{} RawPayload []byte Raw []byte Accum []byte Json PayloadJson } // todo разобраться зачем оно ъ func (e *Package) AddToAccum(data []byte) { e.Accum = append(e.Accum, data...) } 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{}) } } func (e *Package) ReadPackage() bool { if len(e.Accum) < 12 { return false } 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) log.Println(e.PayloadType) is_special := e.Encription == 1 && e.Mark == 1 if is_special { r.TryReadBits(8 * 4) e.PayloadLen = r.TryReadBits(8) r.TryReadBits(3 * 8) if uint64(len(e.Accum)) < e.PayloadLen+12 { return false } } else { 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 numOfBytes != int(e.PayloadLen) { return false } e.Raw = e.Accum[:12+e.PayloadLen] e.Accum = e.Accum[12+e.PayloadLen:] e.RawPayload = rawbytes 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{}) } e.SaveJsonFields() return e.PayloadLen > 0 } func (e *Package) PackPackage() []byte { e.SaveJsonFields() 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 } 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() } func (e *Package) PackRawPackage() []byte { 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) // 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}) } w.Close() return b.Bytes() } // main server util func (e *Package) RequestGeolocation(serial int, Sid string) { e.Payload = map[string]any{ "MODULE": "DEVEMM", "OPERATION": "GETPOS", "PARAMETER": map[string]any{ "SERIAL": serial, }, "SESSION": Sid, } } func (e *Package) ResponseGeolocation(errorCode int, errorCause string, serial int, longitude float32, latitude float32, altitude float32, speed int, course int, time string) { e.Payload = map[string]any{ "MODULE": "DEVEMM", "OPERATION": "GETPOS", "RESPONSE": map[string]any{ "ERRORCODE": errorCode, "ERRORCAUSE": errorCause, "SERIAL": serial, "P": map[string]any{ "V": errorCode == 0, "J": fmt.Sprintf("%4.6v", longitude), "W": fmt.Sprintf("%4.6v", latitude), "H": fmt.Sprintf("%4.6v", altitude), "S": speed, // unit - 0.01 km/h "C": course, // direction (angle from north) "T": time, // yyyymmddhhmmss }, }, } } func (e *Package) RequestConnect(session string, serial string, numOfCams int) { e.Payload = map[string]any{ "MODULE": "CERTIFICATE", "OPERATION": "CONNECT", "PARAMETER": map[string]any{ "DSNO": serial, "CHANNEL": numOfCams, }, "SESSION": session, } } // video server util func (e *Package) ResponseConnect(Sid string, streamName string) { e.Payload = map[string]any{ "MODULE": "CERTIFICATE", "OPERATION": "CREATESTREAM", "RESPONSE": map[string]any{ "ERRORCODE": 0, "STREAMNAME": streamName, }, "SESSION": Sid, } } func (e *Package) ResponseCalendar(errorCode int, errorCause string, serial int, dates []string) { e.Payload = map[string]any{ "MODULE": "STORM", "OPERATION": "GETCALENDAR", "RESPONSE": map[string]any{ "ERRORCODE": errorCode, "ERRORCAUSE": errorCause, "SERIAL": serial, "COUNT": len(dates), "CALENDER": dates, // no CHCALENDER[COUNT] // no T[COUNT] }, } } func (e *Package) RequestCalendar(queryTime string, serial int, session string, camNo int64) { channel := 1 << (camNo - 1) e.Payload = map[string]any{ "MODULE": "STORM", "OPERATION": "GETCALENDAR", "PARAMETER": map[string]any{ "CALENDARTYPE": 1, // Month data "STREAMTYPE": 1, // Main Stream "FILETYPE": 0b111111, // get file type "PICMTYPE": 0b10, // fixed timing pictures (fixed framerate) "APT0": 0xFFFFFF, // get every alarm "APT1": 0xFFFF, // get every alarm "AUDIOTYPE": 0b111, // normal recording, passenger complaints, alarm recording "CHANNEL": channel, // request all channels "QUERYTIME": queryTime, // year + month = xxxxxx "SERIAL": serial, "NEWSTREAMTYPE": 0b111, // master stream (bit1) "RFSTORAGE": 0, // 0 - hdd, 1 - sd }, "SESSION": session, } } // filenames without fileextension func (e *Package) ResponseFileList(errorCode int, errorCause string, serial int, filenames []string, fileextensions []int, ids []string) { e.Payload = map[string]any{ "MODULE": "STORM", "OPERATION": "QUERYFILELIST", "RESPONSE": map[string]any{ "ERRORCODE": errorCode, "ERRORCAUSE": errorCause, "SERIAL": serial, "SENDFILECOUNT": len(filenames), "RECORD": filenames, "FILETYPE": fileextensions, "RECORDID": ids, }, } } func (e *Package) RequestFileList(queryTime string, serial int, session string, camNo int64) { channel := 1 << (camNo - 1) e.Payload = map[string]any{ "MODULE": "STORM", "OPERATION": "QUERYFILELIST", "PARAMETER": map[string]any{ "STREAMTYPE": 1, // Main Stream "FILETYPE": 0b111111, // get all filetypes "PICMTYPE": 0b10, // fixed timing pictures (fixed framerate) "APT0": 0xFFFFFF, // get every alarm "APT1": 0xFFFF, // get every alarm "AUDIOTYPE": 0b111, // normal recording, passenger complaints, alarm recording "CHANNEL": channel, // request all channels "STARTTIME": queryTime + "000000", "ENDTIME": queryTime + "235959", "SERIAL": serial, "NEWSTREAMTYPE": 0b10, // master stream (bit1) "RFSTORAGE": 0, // 0 - hdd, 1 - sd }, "SESSION": session, } } // main server util func (e *Package) ResponseCertificateConnect(Sid string) { e.Payload = map[string]any{ "MODULE": "CERTIFICATE", "OPERATION": "CONNECT", "RESPONSE": map[string]any{ "ERRORCAUSE": "", "ERRORCODE": 0, "MASKCMD": 5, "PRO": "1.0.5", }, "SESSION": Sid, } } // request reqistration parameters (directly to register) func (e *Package) RequestParameters(params map[string]any, serial int, session string) { e.Payload = map[string]any{ "MODULE": "CONFIGMODEL", "OPERATION": "GET", "PARAMETER": map[string]any{ "MDVR": params["MDVR"], "SERIAL": serial, }, "SESSION": session, } } // end of 'RequestParameters' function // set reigeter parameters (directly to register) func (e *Package) SetParameters(params map[string]any, serial int, session string) { e.Payload = map[string]any{ "MODULE": "CONFIGMODEL", "OPERATION": "SET", "PARAMETER": map[string]any{ "MDVR": params["MDVR"], "SERIAL": serial, }, "SESSION": session, } log.Println(e.Payload) } // end of 'SetParameters' function // todo al1 func (e *Package) ConfigeModel(Sid string) { e.Payload = map[string]any{ "MODULE": "CONFIGMODEL", "OPERATION": "SET", "PARAMETER": map[string]any{ "MDVR": map[string]any{ "KEYS": map[string]any{ // KEY parameters "GV": 1, // GPS version }, "PGDSM": map[string]any{ // Network monitoring status parameters "PGPS": map[string]any{ // GPS position "EN": 1, // Real-time position monitoring "TM": 10, // Time interval }, }, "PSI": map[string]any{ // Platform basic information "CG": map[string]any{ // Call information "AS": 0, // Automatic answer }, }, "SUBSTRNET": map[string]any{ "SM": 1, // 0-Smooth .. 4-Clear }, }, }, } } // main server util func (e *Package) MediaRequestAliveVideo(token int, camNo int64, Sid string, serial string, quality int64) { channel := 0 if camNo == 1 { channel = 1 } else { channel = 1 << (camNo - 1) } e.Payload = map[string]any{ "MODULE": "MEDIASTREAMMODEL", "OPERATION": "REQUESTALIVEVIDEO", "PARAMETER": map[string]any{ "AUDIOVALID": 1, "CHANNEL": channel, "FRAMEMODE": 0, "IPANDPORT": ip + ":12092", "STREAMNAME": "LIVE" + "_" + serial + "_" + fmt.Sprint(camNo), "STREAMTYPE": quality, "SERIAL": token, }, "SESSION": Sid, } } // main server util func (e *Package) MediaRequestRemotePlayback(token int, serial string, session string, camNo int, date string, begin_time string, end_time string, serverId int) { e.Payload = map[string]any{ "MODULE": "MEDIASTREAMMODEL", "OPERATION": "REQUESTREMOTEPLAYBACK", "PARAMETER": map[string]any{ "STREAMNAME": "PLAYBACK" + "_" + fmt.Sprint(serial) + "_" + fmt.Sprint(camNo) + "_" + fmt.Sprint(serverId), "STREAMTYPE": 1, // main stream "VIDEOTYPE": 2, // common files "CHANNEL": 1 << (camNo - 1), "STARTTIME": date + begin_time, // "ENDTIME": date + end_time, "IPANDPORT": ip + ":12092", "SERIAL": token, "PBST": 0, }, "SESSION": session, } } // main server util func (e *Package) ControlRemotePlayback(token int, serial string, session string, camNo int, date string, begin_time string, end_time string, serverId int) { e.Payload = map[string]any{ "MODULE": "MEDIASTREAMMODEL", "OPERATION": "CONTROLREMOTEPLAYBACK", "PARAMETER": map[string]any{ "STREAMNAME": fmt.Sprint(serial) + "_" + fmt.Sprint(camNo) + "_" + fmt.Sprint(serverId), "SERIAL": token, "PALYBACKCMD": 5, // main stream "CHANNEL": 268435455, // common files }, "SESSION": session, } } func (e *Package) MediaRequestDownloadVideo(token int, serial string, session string, camNo int, date string, begin_time string, end_time string, recordID string, serverId int) { e.Payload = map[string]any{ "MODULE": "MEDIASTREAMMODEL", "OPERATION": "REQUESTDOWNLOADVIDEO", "PARAMETER": map[string]any{ "PT": 3, "SSRC": 1, "STREAMNAME": "DOWNLOAD" + "_" + serial + "_" + fmt.Sprint(camNo) + "_" + fmt.Sprint(serverId), "STREAMTYPE": 1, // main stream "RECORDID": recordID, "CHANNEL": 1 << (camNo - 1), "STARTTIME": date + begin_time, "ENDTIME": date + end_time, "OFFSETFLAG": 1, "OFFSET": 0, "IPANDPORT": ip + ":12092", "SERIAL": token, "DT": 1, // high speed download }, "SESSION": session, } } // 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{ "MODULE": "EVEM", "OPERATION": "SENDALARMINFO", "RESPONSE": map[string]any{ "ALARMTYPE": alarmType, "ALARMUID": alarmUID, "CMDNO": cmdno, "CMDTYPE": cmdtype, "ERRORCODE": 0, "RUN": run, }, "SESSION": Sid, } } // main server util func (e *Package) ResponseConfigModelSet(Sid string) { e.Payload = map[string]any{ "MODULE": "CONFIGMODUL", "OPERATION": "SET", "RESPONSE": map[string]any{ "ERRORCODE": 0, "ERRORCAUSE": "None", "ERRORDESCRIPTION": "None", }, "SESSION": Sid, } } // todo ъ // why store a string and constantly change it to the same thing // the stored string is not used func (e *Package) GetToken() { hexStream := "3876431502000010380000007b224b4559223a22434c49454e544c4f47494e222c22524553504f4e5345223a7b22434c49454e544944223a2237643531323030227d7d00" e.RawPayload, _ = hex.DecodeString(hexStream) } // the same func (e *Package) RequestGetTokenDop() { hexStream := "3876431501000010360000007b224b4559223a224c4f47494e222c22504152414d223a7b224355534552223a2231222c22505744223a22313233343536227d7d0a00" e.RawPayload, _ = hex.DecodeString(hexStream) }