package main import ( "errors" "github.com/gofiber/fiber/v2" "log" "math/rand" "time" ) type TestCommand struct { Command string `json:"cmd"` SequenceId int64 `json:"sequenceId"` } type TestData struct { State string `json:"state"` ExceptionType int `json:"exceptionType,omitempty"` ExceptionDesc string `json:"exceptionDesc,omitempty"` Image string `json:"image,omitempty"` DistanceCM int `json:"distanceCM,omitempty"` Counts int `json:"counts,omitempty"` DurationSec float32 `json:"durationSec,omitempty"` } type TestStat struct { Scene string `json:"scene"` Timestamp int64 `json:"timestamp"` SequenceId int64 `json:"sequenceId"` TestData TestData `json:"sceneData"` } type TestException struct { Type int Desc string } var currentTest *TestCommand var random *rand.Rand var testExceptChannel chan TestException var testStopChannel chan bool var testDurations map[string][2]int func setTestCmd(c *fiber.Ctx) error { var testCmd TestCommand if err := c.BodyParser(&testCmd); nil != err { log.Println("ERROR:", c.Body()) return failureResponse(c, "-1", err.Error(), 200) } else if nil == currentScene { return failureResponse(c, "1", "not in a working scene", 200) } else { switch testCmd.Command { case "START": log.Println("START ...") if nil != currentTest { return failureResponse(c, "2", "A test already started", 200) } if e := recogTaskProc(&testCmd); nil != e { return failureResponse(c, "3", e.Error(), 200) } case "STOP": testStopChannel <- true log.Println("STOP ...") case "CANCEL": testStopChannel <- true log.Println("CANCEL ...") default: log.Println("UNKNOWN ...") } return successResponse(c, "Updated successfully.") } } func pullUpTask(seq int64) error { var tk = time.NewTicker(time.Millisecond * 200) defer func() { tk.Stop() }() time.Sleep(time.Millisecond * 300) go pushEvent(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, "TEST READY", false, false) var started = false for { select { case <-testStopChannel: go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "TEST END", true, true) return nil case except := <-testExceptChannel: if except.Type != 0 { go pushException(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, except.Type, except.Desc, true) } case <-tk.C: log.Println("===") if !started { go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "START", true, true) started = true } else { go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "COUNT", true, true) } } } } func standJumpTask(seq int64) error { var tk = time.NewTicker(time.Millisecond * 100) defer func() { tk.Stop() }() time.Sleep(time.Millisecond * 500) go pushEvent(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, "TEST READY", false, false) var started = false for { select { case <-testStopChannel: go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "TEST END", true, true) return nil case except := <-testExceptChannel: if except.Type != 0 { go pushException(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, except.Type, except.Desc, true) } case <-tk.C: log.Println("===") if !started { go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "START", true, true) started = true } } } } func sitUpsTask(seq int64) error { var tk = time.NewTicker(time.Millisecond * 200) defer func() { tk.Stop() }() time.Sleep(time.Millisecond * 600) go pushEvent(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, "TEST READY", false, false) var started = false for { select { case <-testStopChannel: go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "TEST END", true, true) return nil case except := <-testExceptChannel: if except.Type != 0 { go pushException(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, except.Type, except.Desc, true) } case <-tk.C: log.Println("===") if !started { go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "START", true, true) started = true } else { go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "COUNT", true, true) } } } } func raceTask(seq int64) error { var tk = time.NewTicker(time.Millisecond * 100) defer func() { tk.Stop() }() time.Sleep(time.Millisecond * 800) go pushEvent(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, "TEST READY", false, false) var started = false for { select { case <-testStopChannel: go pushEvent(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, "TEST END", true, true) return nil case except := <-testExceptChannel: if except.Type != 0 { go pushException(currentScene.PushUrl, currentScene.Scene, currentTest.SequenceId, except.Type, except.Desc, true) } case <-tk.C: log.Println("===") if !started { go pushEvent(currentScene.PushUrl, currentScene.Scene, seq, "START", true, true) started = true } } } } func pushException(url string, scene string, seq int64, tp int, desc string, img bool) { var st = TestStat{ Scene: scene, Timestamp: time.Now().Unix(), SequenceId: seq, TestData: TestData{ State: "EXCEPT", ExceptionType: tp, ExceptionDesc: desc, }, } if img { st.TestData.Image = IMAGES[random.Intn(len(IMAGES))] } httpPostEx(url, st, 3) } func pushEvent(url string, scene string, seq int64, state string, img bool, val bool) { var st = TestStat{ Scene: scene, Timestamp: time.Now().Unix(), SequenceId: seq, TestData: TestData{ State: state, }, } if img { st.TestData.Image = IMAGES[random.Intn(len(IMAGES))] } if val { switch scene { case "pullUp": st.TestData.Counts = random.Intn(20) case "standJump": st.TestData.DistanceCM = random.Intn(300) case "sitUps": st.TestData.Counts = random.Intn(20) case "race": st.TestData.DurationSec = random.Float32() default: } } httpPostEx(url, st, 3) } func recogTaskProc(cmd *TestCommand) error { testStopChannel = make(chan bool) testExceptChannel = make(chan TestException) random = rand.New(rand.NewSource(time.Now().UnixNano())) if nil == currentScene { return errors.New("invalid scene state") } if nil == currentScene.proc { return errors.New("invalid scene mode processor") } currentTest = cmd go func() { defer func() { close(testStopChannel) close(testExceptChannel) testStopChannel = nil testExceptChannel = nil currentTest = nil }() if e := currentScene.proc(cmd.SequenceId); nil != e { log.Println(">>>>", e) } }() go func() { var min = testDurations[currentScene.Scene][0] var max = testDurations[currentScene.Scene][1] for i := 0; i < random.Intn(max-min)+min; i++ { time.Sleep(time.Second) } testStopChannel <- true }() return nil } func init() { random = rand.New(rand.NewSource(time.Now().UnixNano())) currentTest = nil testExceptChannel = nil testStopChannel = nil testDurations = map[string][2]int{ "pullUp": [2]int{30, 80}, "standJump": [2]int{10, 30}, "sitUps": [2]int{60, 70}, "race": [2]int{9, 15}, } }