| @ -1,205 +1,205 @@ | |||||
| package main | package main | ||||
| import ( | import ( | ||||
| "errors" | |||||
| "github.com/aler9/gortsplib" | |||||
| "github.com/gofiber/fiber/v2" | |||||
| "image" | |||||
| "log" | |||||
| "net/url" | |||||
| "time" | |||||
| "errors" | |||||
| "github.com/aler9/gortsplib" | |||||
| "github.com/gofiber/fiber/v2" | |||||
| "image" | |||||
| "log" | |||||
| "net/url" | |||||
| "time" | |||||
| ) | ) | ||||
| type SceneCommand struct { | type SceneCommand struct { | ||||
| Scene string `json:"scene"` | |||||
| PushUrl string `json:"pushUrl"` | |||||
| CameraUrls []string `json:"cameraURls"` | |||||
| proc func(int64) error | |||||
| areaConfigs []AreaConfig `json:"-"` | |||||
| Scene string `json:"scene"` | |||||
| PushUrl string `json:"pushUrl"` | |||||
| CameraUrls []string `json:"cameraURls"` | |||||
| proc func(int64) error | |||||
| areaConfigs []AreaConfig `json:"-"` | |||||
| } | } | ||||
| type SceneData struct { | type SceneData struct { | ||||
| State string `json:"state"` | |||||
| LiveUrl []string `json:"liveUrl"` | |||||
| State string `json:"state"` | |||||
| LiveUrl []string `json:"liveUrl"` | |||||
| } | } | ||||
| type Pointer struct { | type Pointer struct { | ||||
| Id string `json:"id"` | |||||
| PercentX float32 `json:"percentX"` | |||||
| PercentY float32 `json:"percentY"` | |||||
| Id string `json:"id"` | |||||
| PercentX float32 `json:"percentX"` | |||||
| PercentY float32 `json:"percentY"` | |||||
| } | } | ||||
| type AreaConfig struct { | type AreaConfig struct { | ||||
| AreaId string `json:"areaId"` | |||||
| PointersNum int `json:"pointersNum"` | |||||
| Pointers []Pointer `json:"pointers"` | |||||
| AreaId string `json:"areaId"` | |||||
| PointersNum int `json:"pointersNum"` | |||||
| Pointers []Pointer `json:"pointers"` | |||||
| } | } | ||||
| type SceneReadyResponse struct { | type SceneReadyResponse struct { | ||||
| Scene string `json:"scene"` | |||||
| Timestamp int64 `json:"timestamp"` | |||||
| SceneData SceneData `json:"sceneData"` | |||||
| Scene string `json:"scene"` | |||||
| Timestamp int64 `json:"timestamp"` | |||||
| SceneData SceneData `json:"sceneData"` | |||||
| } | } | ||||
| var currentScene *SceneCommand | var currentScene *SceneCommand | ||||
| var sceneStopChannel chan bool | var sceneStopChannel chan bool | ||||
| func validateSceneCmd(cmd SceneCommand) error { | func validateSceneCmd(cmd SceneCommand) error { | ||||
| switch cmd.Scene { | |||||
| case "pullUp", "standJump", "sitUps": | |||||
| if len(cmd.CameraUrls) < 1 { | |||||
| return errors.New("cameraUrls can not less than 1") | |||||
| } | |||||
| case "race": | |||||
| if len(cmd.CameraUrls) < 2 { | |||||
| return errors.New("cameraUrls can not less than 2") | |||||
| } | |||||
| default: | |||||
| return errors.New("unknown scene type:" + cmd.Scene) | |||||
| } | |||||
| if u, e := url.Parse(cmd.PushUrl); nil != e { | |||||
| return errors.New("invalid pushUrl:" + e.Error()) | |||||
| } else if u.Scheme != "http" && u.Scheme != "https" { | |||||
| return errors.New("can not support pushUrl with " + u.Scheme) | |||||
| } | |||||
| return nil | |||||
| switch cmd.Scene { | |||||
| case "pullUp", "standJump", "sitUps": | |||||
| if len(cmd.CameraUrls) < 1 { | |||||
| return errors.New("cameraUrls can not less than 1") | |||||
| } | |||||
| case "race": | |||||
| if len(cmd.CameraUrls) < 2 { | |||||
| return errors.New("cameraUrls can not less than 2") | |||||
| } | |||||
| default: | |||||
| return errors.New("unknown scene type:" + cmd.Scene) | |||||
| } | |||||
| if u, e := url.Parse(cmd.PushUrl); nil != e { | |||||
| return errors.New("invalid pushUrl:" + e.Error()) | |||||
| } else if u.Scheme != "http" && u.Scheme != "https" { | |||||
| return errors.New("can not support pushUrl with " + u.Scheme) | |||||
| } | |||||
| return nil | |||||
| } | } | ||||
| func setScene(c *fiber.Ctx) error { | func setScene(c *fiber.Ctx) error { | ||||
| var sceneCmd SceneCommand | |||||
| if err := c.BodyParser(&sceneCmd); nil != err { | |||||
| log.Println("ERROR:", c.Body()) | |||||
| return failureResponse(c, "-1", err.Error(), 200) | |||||
| } else if nil != currentScene { | |||||
| return failureResponse(c, "1", "A working scene is started", 200) | |||||
| } else if err = validateSceneCmd(sceneCmd); nil != err { | |||||
| return failureResponse(c, "2", err.Error(), 200) | |||||
| } else { | |||||
| // currentScene = &sceneCmd | |||||
| log.Println("Starting scene ...") | |||||
| log.Println(sceneCmd) | |||||
| if e := sceneTaskProc(&sceneCmd); nil != e { | |||||
| return failureResponse(c, "3", err.Error(), 200) | |||||
| } else { | |||||
| return successResponse(c, "Updated successfully.") | |||||
| } | |||||
| } | |||||
| var sceneCmd SceneCommand | |||||
| if err := c.BodyParser(&sceneCmd); nil != err { | |||||
| log.Println("ERROR:", c.Body()) | |||||
| return failureResponse(c, "-1", err.Error(), 200) | |||||
| } else if nil != currentScene { | |||||
| return failureResponse(c, "1", "A working scene is started", 200) | |||||
| } else if err = validateSceneCmd(sceneCmd); nil != err { | |||||
| return failureResponse(c, "2", err.Error(), 200) | |||||
| } else { | |||||
| // currentScene = &sceneCmd | |||||
| log.Println("Starting scene ...") | |||||
| log.Println(sceneCmd) | |||||
| if e := sceneTaskProc(&sceneCmd); nil != e { | |||||
| return failureResponse(c, "3", err.Error(), 200) | |||||
| } else { | |||||
| return successResponse(c, "Updated successfully.") | |||||
| } | |||||
| } | |||||
| } | } | ||||
| func setAreaConfig(c *fiber.Ctx) error { | func setAreaConfig(c *fiber.Ctx) error { | ||||
| var cfg []AreaConfig | |||||
| if e := c.BodyParser(&cfg); nil != e { | |||||
| log.Println("ERROR:", c.Body()) | |||||
| return failureResponse(c, "-1", e.Error(), 200) | |||||
| } else if nil == currentScene { | |||||
| return failureResponse(c, "1", "No working scene is started", 200) | |||||
| } | |||||
| currentScene.areaConfigs = cfg | |||||
| return successResponse(c, "Updated successfully.") | |||||
| var cfg []AreaConfig | |||||
| if e := c.BodyParser(&cfg); nil != e { | |||||
| log.Println("ERROR:", c.Body()) | |||||
| return failureResponse(c, "-1", e.Error(), 200) | |||||
| } else if nil == currentScene { | |||||
| return failureResponse(c, "1", "No working scene is started", 200) | |||||
| } | |||||
| currentScene.areaConfigs = cfg | |||||
| return successResponse(c, "Updated successfully.") | |||||
| } | } | ||||
| func getAreaConfig(c *fiber.Ctx) error { | func getAreaConfig(c *fiber.Ctx) error { | ||||
| if nil == currentScene { | |||||
| return failureResponse(c, "1", "No working scene is started", 200) | |||||
| } else { | |||||
| return successResponseData(c, "success", currentScene.areaConfigs) | |||||
| } | |||||
| if nil == currentScene { | |||||
| return failureResponse(c, "1", "No working scene is started", 200) | |||||
| } else { | |||||
| return successResponseData(c, "success", currentScene.areaConfigs) | |||||
| } | |||||
| } | } | ||||
| func stopScene(c *fiber.Ctx) error { | func stopScene(c *fiber.Ctx) error { | ||||
| if nil != testStopChannel { | |||||
| testStopChannel <- true | |||||
| } | |||||
| if nil != sceneStopChannel { | |||||
| sceneStopChannel <- true | |||||
| } | |||||
| return successResponse(c, "Updated successfully.") | |||||
| if nil != testStopChannel { | |||||
| testStopChannel <- true | |||||
| } | |||||
| if nil != sceneStopChannel { | |||||
| sceneStopChannel <- true | |||||
| } | |||||
| return successResponse(c, "Updated successfully.") | |||||
| } | } | ||||
| func getStatus(c *fiber.Ctx) error { | func getStatus(c *fiber.Ctx) error { | ||||
| var scene = "" | |||||
| var seq int64 = 0 | |||||
| if nil != currentScene { | |||||
| scene = currentScene.Scene | |||||
| } | |||||
| if nil != currentTest { | |||||
| seq = currentTest.SequenceId | |||||
| } | |||||
| return successResponseEx(c, "success", scene, seq) | |||||
| var scene = "" | |||||
| var seq int64 = 0 | |||||
| if nil != currentScene { | |||||
| scene = currentScene.Scene | |||||
| } | |||||
| if nil != currentTest { | |||||
| seq = currentTest.SequenceId | |||||
| } | |||||
| return successResponseEx(c, "success", scene, seq) | |||||
| } | } | ||||
| var capturedImage image.Image | var capturedImage image.Image | ||||
| func sceneTaskProc(cmd *SceneCommand) error { | func sceneTaskProc(cmd *SceneCommand) error { | ||||
| var f func(int64) error = nil | |||||
| switch cmd.Scene { | |||||
| case "pullUp": | |||||
| f = pullUpTask | |||||
| case "standJump": | |||||
| f = standJumpTask | |||||
| case "sitUps": | |||||
| f = sitUpsTask | |||||
| case "race": | |||||
| f = raceTask | |||||
| default: | |||||
| return errors.New("unknown scene type:" + cmd.Scene) | |||||
| } | |||||
| if len(cmd.CameraUrls) < 1 { | |||||
| return errors.New("no camera specified") | |||||
| } | |||||
| var cc *gortsplib.Client | |||||
| if c, u, e := setupRtsp(cmd.CameraUrls[0]); nil != e { | |||||
| log.Println("setupRtsp failed:", e) | |||||
| } else { | |||||
| cc = c | |||||
| go func() { | |||||
| if e := playRtsp(c, u, func(img image.Image) { | |||||
| //log.Println("...capturedImage:>", img.Bounds()) | |||||
| capturedImage = img | |||||
| }); nil != e { | |||||
| //log.Println("playRtsp failed:>", e) | |||||
| } | |||||
| }() | |||||
| } | |||||
| sceneStopChannel = make(chan bool) | |||||
| var tk = time.NewTicker(time.Second * 3) | |||||
| go func() { | |||||
| defer func() { | |||||
| tk.Stop() | |||||
| close(sceneStopChannel) | |||||
| if nil != cc { | |||||
| _ = cc.Close() | |||||
| } | |||||
| sceneStopChannel = nil | |||||
| }() | |||||
| currentScene = cmd | |||||
| currentScene.proc = f | |||||
| time.Sleep(time.Second) | |||||
| var st = SceneReadyResponse{ | |||||
| Scene: cmd.Scene, | |||||
| Timestamp: time.Now().Unix(), | |||||
| SceneData: SceneData{ | |||||
| State: "SCENE READY", | |||||
| LiveUrl: cmd.CameraUrls, | |||||
| }, | |||||
| } | |||||
| go httpPostEx(cmd.PushUrl, st, 3) | |||||
| for { | |||||
| select { | |||||
| case <-tk.C: | |||||
| // log.Println(" ...") | |||||
| case <-sceneStopChannel: | |||||
| log.Println("Scene Stopping...") | |||||
| go pushEvent(cmd.PushUrl, cmd.Scene, 0, "SCENE END", nil) | |||||
| currentScene = nil | |||||
| return | |||||
| } | |||||
| } | |||||
| }() | |||||
| return nil | |||||
| var f func(int64) error = nil | |||||
| switch cmd.Scene { | |||||
| case "pullUp": | |||||
| f = pullUpTask | |||||
| case "standJump": | |||||
| f = standJumpTask | |||||
| case "sitUps": | |||||
| f = sitUpsTask | |||||
| case "race": | |||||
| f = raceTask | |||||
| default: | |||||
| return errors.New("unknown scene type:" + cmd.Scene) | |||||
| } | |||||
| if len(cmd.CameraUrls) < 1 { | |||||
| return errors.New("no camera specified") | |||||
| } | |||||
| var cc *gortsplib.Client | |||||
| if c, u, e := setupRtsp(cmd.CameraUrls[0]); nil != e { | |||||
| log.Println("setupRtsp failed:", e) | |||||
| } else { | |||||
| cc = c | |||||
| go func() { | |||||
| if e := playRtsp(c, u, func(img image.Image) { | |||||
| // log.Println("...capturedImage:>", img.Bounds()) | |||||
| capturedImage = img | |||||
| }); nil != e { | |||||
| // log.Println("playRtsp failed:>", e) | |||||
| } | |||||
| }() | |||||
| } | |||||
| sceneStopChannel = make(chan bool) | |||||
| var tk = time.NewTicker(time.Second * 3) | |||||
| go func() { | |||||
| defer func() { | |||||
| tk.Stop() | |||||
| close(sceneStopChannel) | |||||
| if nil != cc { | |||||
| _ = cc.Close() | |||||
| } | |||||
| sceneStopChannel = nil | |||||
| }() | |||||
| currentScene = cmd | |||||
| currentScene.proc = f | |||||
| time.Sleep(time.Second) | |||||
| var st = SceneReadyResponse{ | |||||
| Scene: cmd.Scene, | |||||
| Timestamp: time.Now().UnixMilli(), | |||||
| SceneData: SceneData{ | |||||
| State: "SCENE READY", | |||||
| LiveUrl: cmd.CameraUrls, | |||||
| }, | |||||
| } | |||||
| go httpPostEx(cmd.PushUrl, st, 3) | |||||
| for { | |||||
| select { | |||||
| case <-tk.C: | |||||
| // log.Println(" ...") | |||||
| case <-sceneStopChannel: | |||||
| log.Println("Scene Stopping...") | |||||
| go pushEvent(cmd.PushUrl, cmd.Scene, 0, "SCENE END", nil) | |||||
| currentScene = nil | |||||
| return | |||||
| } | |||||
| } | |||||
| }() | |||||
| return nil | |||||
| } | } | ||||
| func init() { | func init() { | ||||
| currentScene = nil | |||||
| sceneStopChannel = nil | |||||
| currentScene = nil | |||||
| sceneStopChannel = nil | |||||
| } | } | ||||