|
@ -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 |
|
|
} |
|
|
} |