| | |
| | | .idea |
| | | gat1400Exchange |
| | | gat1400Exchange* |
| | | gat1400.db |
| | | logs |
New file |
| | |
| | | VER="3.1.0" |
| | | DATA=$(shell date +%Y%m%d) |
| | | GIT=$(shell git rev-parse --short HEAD) |
| | | BRANCH=$(shell git rev-parse --abbrev-ref HEAD) |
| | | |
| | | build: |
| | | go build -v -a -ldflags "-X main.MinVersion=$(VER) -X main.PublishDate=$(DATA) -X main.CommitId=$(GIT) -X main.Branch=$(BRANCH)" |
| | | arm64: |
| | | CGO_ENABLED=1 \ |
| | | GOOS=linux \ |
| | | GOARCH=arm64 \ |
| | | CC=/opt/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc \ |
| | | CXX=/opt/l4t-gcc/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc \ |
| | | CGO_CFLAGS="--sysroot=/opt/l4t-gcc/sysroot-glibc-linaro-2.25-2018.05-aarch64-linux-gnu" \ |
| | | CGO_CXXFLAGS="--sysroot=/opt/l4t-gcc/sysroot-glibc-linaro-2.25-2018.05-aarch64-linux-gnu" \ |
| | | CGO_LDFLAGS="--sysroot=/opt/l4t-gcc/sysroot-glibc-linaro-2.25-2018.05-aarch64-linux-gnu -lstdc++" \ |
| | | go build -v -a -tags=agx -ldflags "-X main.MinVersion=$(VER) -X main.PublishDate=$(DATA) -X main.CommitId=$(GIT)" -o gat1400Exchange-arm64 |
| | | clean: |
| | | rm -f gat1400Exchange* |
| | |
| | | package client |
| | | |
| | | import ( |
| | | "context" |
| | | "fmt" |
| | | "math/rand" |
| | | "time" |
| | | |
| | | "gat1400Exchange/config" |
| | | "gat1400Exchange/pkg/logger" |
| | | "gat1400Exchange/vo" |
| | | ) |
| | | |
| | | func Init1400Client() { |
| | | func Init1400Client(ctx context.Context) { |
| | | if !config.ClientConf.Enable { |
| | | logger.Debug("GAT/1400 Client disabled") |
| | | return |
| | | } |
| | | |
| | | register() |
| | | go registerLoop(ctx) |
| | | go keepaliveLoop(ctx) |
| | | go syncTimeLoop(ctx) |
| | | |
| | | } |
| | | |
| | | func registerLoop(ctx context.Context) { |
| | | ticker := time.NewTicker(1 * time.Second) |
| | | for { |
| | | select { |
| | | case <-ctx.Done(): |
| | | unRegister() |
| | | return |
| | | case <-ticker.C: |
| | | if clientStatus != vo.StatusSuccess { |
| | | fmt.Println("register") |
| | | if !register() { |
| | | randNum := rand.Intn(300) + 1 |
| | | // 随机等待300s, 重新注册 |
| | | ticker.Reset(time.Duration(randNum) * time.Second) |
| | | } else { |
| | | ticker.Reset(1 * time.Second) |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | func keepaliveLoop(ctx context.Context) { |
| | | var failCount int |
| | | ticker := time.NewTicker(time.Duration(config.ClientConf.HeartbeatInterval) * time.Second) |
| | | for { |
| | | select { |
| | | case <-ctx.Done(): |
| | | return |
| | | case <-ticker.C: |
| | | if status := keepalive(); status != vo.StatusSuccess { |
| | | failCount++ |
| | | |
| | | if failCount > config.ClientConf.HeartbeatFailCount { |
| | | clientStatus = status |
| | | } |
| | | } else { |
| | | failCount = 0 |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | func syncTimeLoop(ctx context.Context) { |
| | | ticker := time.NewTicker(time.Duration(config.ClientConf.HeartbeatInterval*10) * time.Second) |
| | | for { |
| | | select { |
| | | case <-ctx.Done(): |
| | | return |
| | | case <-ticker.C: |
| | | syncTime() |
| | | } |
| | | } |
| | | } |
| | |
| | | package client |
| | | |
| | | import ( |
| | | "encoding/json" |
| | | "fmt" |
| | | "gat1400Exchange/util" |
| | | "io/ioutil" |
| | | |
| | | "gat1400Exchange/config" |
| | | "gat1400Exchange/pkg/logger" |
| | | "gat1400Exchange/vo" |
| | | |
| | | dac "github.com/xinsnake/go-http-digest-auth-client" |
| | | ) |
| | |
| | | TimeUrI = "/VIID/System/Time" |
| | | ) |
| | | |
| | | func register() { |
| | | url := fmt.Sprintf("http://%s:%s%s", config.ClientConf.ServerAddr, config.ClientConf.ServerPort, RegisterUrI) |
| | | dr := dac.NewRequest(config.ClientConf.Username, config.ClientConf.Password, "GET", url, "") |
| | | var clientStatus = vo.StatusOtherError |
| | | |
| | | var headers = map[string]string{ |
| | | "User-Agent": "AI camera", |
| | | "Accept": "*", |
| | | "User-Identify": config.ClientConf.ChannelNo, |
| | | "Content-Type": "application/VIID+JSON", |
| | | } |
| | | |
| | | func register() bool { |
| | | url := fmt.Sprintf("%s://%s:%s%s", config.ClientConf.Proto, config.ClientConf.ServerAddr, config.ClientConf.ServerPort, RegisterUrI) |
| | | req := vo.RequestRegister{RegisterObject: vo.RequestDeviceID{DeviceID: config.ClientConf.ChannelNo}} |
| | | reqByte, _ := json.Marshal(req) |
| | | |
| | | dr := dac.NewRequest(config.ClientConf.Username, config.ClientConf.Password, "POST", url, string(reqByte)) |
| | | if headers != nil { |
| | | for k, v := range headers { |
| | | dr.Header.Set(k, v) |
| | | } |
| | | dr.Header.Del("Accept-Encoding") |
| | | } |
| | | |
| | | resp, err := dr.Execute() |
| | | if err != nil { |
| | | logger.Error(err.Error()) |
| | | return |
| | | return false |
| | | } |
| | | |
| | | defer resp.Body.Close() |
| | | |
| | | body, err := ioutil.ReadAll(resp.Body) |
| | | if err != nil { |
| | | logger.Error(err.Error()) |
| | | return |
| | | return false |
| | | } |
| | | |
| | | fmt.Printf(string(body)) |
| | | fmt.Println("rsp:", string(body)) |
| | | var registerResponse vo.ResponseStatus |
| | | err = json.Unmarshal(body, ®isterResponse) |
| | | if err != nil { |
| | | fmt.Println("register error,", err.Error()) |
| | | return false |
| | | } |
| | | |
| | | clientStatus = registerResponse.StatusCode |
| | | |
| | | if registerResponse.StatusCode == vo.StatusSuccess { |
| | | fmt.Println("register success") |
| | | // 注册成功后提交保活和校时 |
| | | keepalive() |
| | | syncTime() |
| | | } else { |
| | | fmt.Println("register failure, ", registerResponse.StatusString) |
| | | } |
| | | |
| | | return clientStatus == vo.StatusSuccess |
| | | } |
| | | |
| | | func keepalive() { |
| | | func keepalive() int { |
| | | if clientStatus != vo.StatusSuccess { |
| | | return clientStatus |
| | | } |
| | | |
| | | var body = vo.RequestKeepalive{ |
| | | KeepaliveObject: vo.RequestDeviceID{ |
| | | DeviceID: config.ClientConf.ChannelNo, |
| | | }, |
| | | } |
| | | |
| | | b, _ := json.Marshal(body) |
| | | rsp, err := util.HttpPost(KeepaliveUrI, headers, b) |
| | | if err != nil { |
| | | logger.Warn("Keepalive request failed, %s", err.Error()) |
| | | return vo.StatusOtherError |
| | | } |
| | | |
| | | var stat vo.ResponseStatus |
| | | err = json.Unmarshal(rsp, &stat) |
| | | if err != nil { |
| | | logger.Warn("Keepalive response unmarshal failed, %s", err.Error()) |
| | | return vo.StatusOtherError |
| | | } |
| | | |
| | | return stat.StatusCode |
| | | } |
| | | |
| | | func unRegister() { |
| | |
| | | } |
| | | |
| | | func syncTime() { |
| | | |
| | | if clientStatus != vo.StatusSuccess { |
| | | return |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | type client struct { |
| | | DeviceID string `mapstructure:"device-id"` |
| | | Username string `mapstructure:"username"` |
| | | Password string `mapstructure:"password"` |
| | | ServerAddr string `mapstructure:"server-addr"` |
| | | ServerPort string `mapstructure:"server-port"` |
| | | Proto string `mapstructure:"proto" ` // http, https |
| | | UploadType string `mapstructure:"upload-type"` // binary, url |
| | | ChannelNo string `mapstructure:"channel-number"` // 通道号, 同id |
| | | HeartbeatInterval int `mapstructure:"heartbeat-interval"` // 心跳周期 |
| | | HeartbeatCount int `mapstructure:"heartbeat-count"` // 心跳超时次数 |
| | | Enable bool `mapstructure:"enable"` |
| | | DeviceID string `mapstructure:"device-id"` |
| | | Username string `mapstructure:"username"` |
| | | Password string `mapstructure:"password"` |
| | | ServerAddr string `mapstructure:"server-addr"` |
| | | ServerPort string `mapstructure:"server-port"` |
| | | Proto string `mapstructure:"proto" ` // http, https |
| | | UploadType string `mapstructure:"upload-type"` // binary, url |
| | | ChannelNo string `mapstructure:"channel-number"` // 通道号, 同id |
| | | HeartbeatInterval int `mapstructure:"heartbeat-interval"` // 心跳周期 |
| | | HeartbeatFailCount int `mapstructure:"heartbeat-count"` // 心跳超时次数 |
| | | Enable bool `mapstructure:"enable"` |
| | | } |
| | | |
| | | type logConfig struct { |
| | |
| | | ForwardConf.RetryInterval = 5 |
| | | } |
| | | |
| | | if ClientConf.HeartbeatInterval == 0 { |
| | | ClientConf.HeartbeatInterval = 30 |
| | | } |
| | | |
| | | if ClientConf.Proto == "" { |
| | | ClientConf.Proto = "http" |
| | | } |
| | | |
| | | logger.SetLogLevel(LogConf.Level) |
| | | } |
| | |
| | | import ( |
| | | "context" |
| | | "fmt" |
| | | "gat1400Exchange/client" |
| | | "gat1400Exchange/cron" |
| | | "net/http" |
| | | "os" |
| | | "os/signal" |
| | | "syscall" |
| | | "time" |
| | | |
| | | "gat1400Exchange/client" |
| | | "gat1400Exchange/config" |
| | | "gat1400Exchange/cron" |
| | | "gat1400Exchange/models" |
| | | "gat1400Exchange/pkg/logger" |
| | | "gat1400Exchange/routes" |
| | |
| | | } |
| | | |
| | | // 启动1400客户端 |
| | | go client.Init1400Client() |
| | | ctx, cancel := context.WithCancel(context.Background()) |
| | | go client.Init1400Client(ctx) |
| | | |
| | | // 启动网络视频字符叠加器服务 |
| | | go service.NVCSServer() |
| | |
| | | |
| | | // The context is used to inform the server it has 5 seconds to finish |
| | | // the request it is currently handling |
| | | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| | | //ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| | | defer cancel() |
| | | if err := srv.Shutdown(ctx); err != nil { |
| | | logger.Error("Server forced to shutdown:", err) |
| | |
| | | |
| | | logger.Info("Report device info. %+v", dev) |
| | | |
| | | _, err = util.HttpPost(config.ForwardConf.ReportServer, nil, data) |
| | | headers := map[string]string{"Content-Type": "applicaiton/json; charset=UTF-8"} |
| | | _, err = util.HttpPost(config.ForwardConf.ReportServer, headers, data) |
| | | if err != nil { |
| | | return err |
| | | } |
| | |
| | | return nil, err |
| | | } |
| | | |
| | | req.Header.Set("Content-Type", "applicaiton/json; charset=UTF-8") |
| | | //req.Header.Set("Content-Type", "applicaiton/json; charset=UTF-8") |
| | | if header != nil { |
| | | for k, v := range header { |
| | | req.Header.Set(k, v) |
| | |
| | | KeepaliveObject RequestDeviceID `json:"KeepaliveObject"` |
| | | } |
| | | |
| | | type RequestRegister struct { |
| | | RegisterObject RequestDeviceID `json:"RegisterObject"` |
| | | } |
| | | |
| | | type RequestUnRegister struct { |
| | | UnRegisterObject RequestDeviceID `json:"UnRegisterObject"` |
| | | } |