Compare commits

...

8 Commits
v0.1.0 ... main

12 changed files with 870 additions and 533 deletions

41
certificate.go Normal file
View File

@ -0,0 +1,41 @@
package n9m
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,
}
}
// 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,
}
}

71
configmodel.go Normal file
View File

@ -0,0 +1,71 @@
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{
"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) ResponseConfigModelSet(Sid string) {
e.Payload = map[string]any{
"MODULE": "CONFIGMODUL", // it's not error
"OPERATION": "SET",
"RESPONSE": map[string]any{
"ERRORCODE": 0,
"ERRORCAUSE": "None",
"ERRORDESCRIPTION": "None",
},
"SESSION": Sid,
}
}

36
devemm.go Normal file
View File

@ -0,0 +1,36 @@
package n9m
import "fmt"
// 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
},
},
}
}

18
evem.go Normal file
View File

@ -0,0 +1,18 @@
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{
"MODULE": "EVEM",
"OPERATION": "SENDALARMINFO",
"RESPONSE": map[string]any{
"ALARMTYPE": alarmType,
"ALARMUID": alarmUID,
"CMDNO": cmdno,
"CMDTYPE": cmdtype,
"ERRORCODE": 0,
"RUN": run,
},
"SESSION": Sid,
}
}

13
go.mod
View File

@ -1,10 +1,13 @@
module n9m
module gitea.unprism.ru/KRBL/n9m
go 1.21.3
require (
github.com/icza/bitio v1.1.0 // indirect
github.com/tidwall/gjson v1.17.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
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
)

4
go.sum
View File

@ -1,9 +1,11 @@
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 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
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=

175
io.go Normal file
View File

@ -0,0 +1,175 @@
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 {
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()
}

110
mediastreammodel.go Normal file
View File

@ -0,0 +1,110 @@
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) {
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) 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) {
if end_time == "" {
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,
"IPANDPORT": ip + ":12092",
"SERIAL": token,
"PBST": 0,
},
"SESSION": session,
}
} else {
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,
}
}

295
params.go Normal file
View File

@ -0,0 +1,295 @@
package n9m
type RIP struct {
DEVID string // ID номер устройства
BN string // бортовой номер
BID string // гос. номер
LN string // Название линии
DID string // номер водительского удостоверения
DNAME string // ФИО водителя
}
type VS struct {
VIN string // VIN номер
}
type TIMEP struct {
DATEM int // формат даты
TIMEM int // формат времени
TIMEZ string // часовой пояс
}
type ATP struct {
GE int // Синхронизация времени при помощи ГНСС
NE int // Синхронизация времени при помощи NTP
NS string // NTP сервер для синхронизации
}
type SSP struct {
UPT int // вкл/выкл
DDS int // задержка перед выключением (при выборе зажигания)
UH int // час включения
UM int // минута включения
US int // минута включения
DH int // час выключения
DM int // минута выключения
DS int // секунда выключения
CPM int // время выключения света
}
type SWUS struct {
IOWP int // Включение через IO
GSWP int // включение через G-сенсор
TX string // порог по X для G-сенсорa
TY string // порог по Y для G-сенсорa
TZ string // порог по Z для G-сенсорa
RTWP int // удаленное включение
PHWP int // включение через телефон
PTWP int // включение через SMS
}
type UMP struct {
UIF []UIF // список юзеров
}
type UIF struct {
UN string // username
PW string // password
UR int // level
}
type SUBSTRNET struct {
NEC []NEC
RLE int
SAE int
SM int // Качество дополнительных потоков
TOTALBW int // Максимальная скорость интернета
}
type NEC struct {
AEN int // звук (вкл/выкл)
VEN int // видео (вкл/выкл)
BR int // битрейт
ECT int // кодировка
FR int // фреймрейт
FT int // тип кадров
QLT int // качество трансляции
RST int // разрешение
}
type DOSD struct {
CHN []string // названия каналов
}
type AR struct {
HDAE int // Двойная запись на жесткий диск
HID int // выбрать место для записи резервного потока
RM int // режим записи резервного потока
VEC []VEC // параметры суб. потоков
}
type VEC struct {
VEN int // видео (вкл/выкл)
RST int // разрешение видеопотока
ECT int // кодировка
FR int // фреймрейт
QLT int // качество записи
AEN int // звук (вкл/выкл)
ALT int // качество видео при тревоге
}
type EOSD struct {
COSD []COSD
DE int // показывать ли ID регистратора
DTE int
DX int
DY int
GE int // показывать ли GPS
GX int
GY int
NE int // показывать ли название канала
NX int
NY int
SE int // показывать ли скорость
SX int
SY int
TE int // показывать ли время
TX int
TY int
VE int // показывать ли номер устройства
VX int
VY int
WME int
}
type COSD struct {
EN int
F int
ID int
L int
T string
TP int
X int
Y int
}
type IOP struct {
EN int
AS int
EL int
SDT int
APR APR
}
type SAP struct {
EN int
AS int
WP int
SV int
AT int
APR APR
UN int
}
type APR struct {
AR ARR
SS SS
ET int
}
type ARR struct {
CH int
D int
}
type SS struct {
EN int
}
type UAP struct {
EN int
AS int
VT int
SDT int
}
type PVLAS struct {
EN int
AS int
SDT int
CH int
}
type PMDAS struct {
EN int
AS int
SDT int
CH int
}
type DSM struct {
DSMA int
DSMFE int
RWFE int
}
type GSP struct {
LANT int // Язык системы
GM int // Система геопозиционирования
}
type ETHERNET struct {
IPMODE int // Тип IP
PIP PIP // Параметры IP
DNSMODE int // Автоматическое получение DNS
DNS DNS // Параметры DNS
KEYS KEYS
}
type PIP struct {
IPADDR string // IP адрес
SUBMASK string // Маска подсети
GATEWAY string // Шлюз сети
}
type DNS struct {
PDNS string // Основной DNS
ADNS string // Дополнительный DNS
}
type KEYS struct {
MAC string // MAC-адрес
}
type WIFI struct {
ENABLE int // Статус WIFI
ESSID string // Название точки доступа
ECRYPTTYPE int // Тип защиты WIFI
PWD string // Пароль от WIFI
IPMODE int // Вид IP
PIP PIP // Параметры IP
}
type M3G struct {
M3M M3M // Управление активацией
MP MP // Параметры первого модуля связи
M4G MP // Параметры второго модуля связи
}
type M3M struct {
AT int // Режим работы модуля связи
TN1 string // Номер активации 1
TN2 string // Номер активации 2
TN3 string // Номер активации 3
}
type MP struct {
NM int // Выбор соединения
APN string // APN
UN string // Логин
PW string // Пароль
}
type MCMS struct {
M int // Битовая маска включенных серверов
SP []SP // Параметры сервера
}
type SP struct {
EN int // Статус сервера
CP int // Протокол подключения
NWT int // Способ подключения
CS string // Адрес сервера
MS string // Адрес медиасервера
CPORT int // TCP-порт сервера
MPORT int // TCP-порт медиасервера
CUPORT int // UDP-порт сервера
MUPORT int // UDP-порт медиасервера
}
type Setting struct {
RIP RIP
VS VS
GSP GSP
TIMEP TIMEP
ETHERNET ETHERNET
KEYS KEYS
WIFI WIFI
M3G M3G
MCMS MCMS
ATP ATP
SSP SSP
SWUS SWUS
UMP UMP
SUBSTRNET SUBSTRNET
DOSD DOSD
AR AR
EOSD []EOSD
MAIN []VEC
IOP []IOP
SAP SAP
UAP UAP
PVLAS PVLAS
PMDAS PMDAS
DSM DSM
}

32
scheme.go Normal file
View File

@ -0,0 +1,32 @@
package n9m
import "github.com/tidwall/gjson"
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
}

80
storm.go Normal file
View File

@ -0,0 +1,80 @@
package n9m
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,
}
}

528
utils.go
View File

@ -1,540 +1,14 @@
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 разобраться зачем оно ъ
// add bytes to accum
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() {