mirror of
https://github.com/zhaojh329/rttys.git
synced 2026-02-27 09:53:21 +08:00
146 lines
2.6 KiB
Go
146 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"rttys/client"
|
|
"rttys/utils"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
jsoniter "github.com/json-iterator/go"
|
|
)
|
|
|
|
const commandTimeout = 30 // second
|
|
|
|
const (
|
|
rttyCmdErrInvalid = 1001
|
|
rttyCmdErrOffline = 1002
|
|
rttyCmdErrTimeout = 1003
|
|
)
|
|
|
|
var cmdErrMsg = map[int]string{
|
|
rttyCmdErrInvalid: "invalid format",
|
|
rttyCmdErrOffline: "device offline",
|
|
rttyCmdErrTimeout: "timeout",
|
|
}
|
|
|
|
type commandInfo struct {
|
|
Cmd string `json:"cmd"`
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type commandReq struct {
|
|
cancel context.CancelFunc
|
|
dev client.Client
|
|
c *gin.Context
|
|
data []byte
|
|
}
|
|
|
|
var commands sync.Map
|
|
|
|
func handleCmdResp(br *broker, data []byte) {
|
|
token := jsoniter.Get(data, "token").ToString()
|
|
|
|
if req, ok := commands.Load(token); ok {
|
|
req := req.(*commandReq)
|
|
req.c.String(http.StatusOK, jsoniter.Get(data, "attrs").ToString())
|
|
req.cancel()
|
|
}
|
|
}
|
|
|
|
func cmdErrReply(err int, req *commandReq) {
|
|
req.c.JSON(http.StatusOK, gin.H{
|
|
"err": err,
|
|
"msg": cmdErrMsg[err],
|
|
})
|
|
req.cancel()
|
|
}
|
|
|
|
func handleCmdReq(br *broker, c *gin.Context) {
|
|
devid := c.Param("devid")
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
req := &commandReq{
|
|
cancel: cancel,
|
|
c: c,
|
|
}
|
|
|
|
dev, ok := br.devices[devid]
|
|
if !ok {
|
|
cmdErrReply(rttyCmdErrOffline, req)
|
|
return
|
|
}
|
|
|
|
req.dev = dev
|
|
|
|
content, err := ioutil.ReadAll(c.Request.Body)
|
|
if err != nil {
|
|
c.Status(http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
cmdInfo := commandInfo{}
|
|
err = jsoniter.Unmarshal(content, &cmdInfo)
|
|
if err != nil || cmdInfo.Cmd == "" {
|
|
cmdErrReply(rttyCmdErrInvalid, req)
|
|
return
|
|
}
|
|
|
|
token := utils.GenUniqueID("cmd")
|
|
|
|
params := jsoniter.Get(content, "params")
|
|
|
|
data := make([]string, 5)
|
|
|
|
data[0] = jsoniter.Get(content, "username").ToString()
|
|
data[1] = jsoniter.Get(content, "password").ToString()
|
|
data[2] = jsoniter.Get(content, "cmd").ToString()
|
|
data[3] = token
|
|
data[4] = string(byte(params.Size()))
|
|
|
|
req.data = []byte(strings.Join(data, string(byte(0))))
|
|
|
|
for i := 0; i < params.Size(); i++ {
|
|
req.data = append(req.data, params.Get(i).ToString()...)
|
|
req.data = append(req.data, 0)
|
|
}
|
|
|
|
br.cmdReq <- req
|
|
|
|
waitTime := commandTimeout
|
|
|
|
wait := c.Query("wait")
|
|
if wait != "" {
|
|
waitTime, _ = strconv.Atoi(wait)
|
|
}
|
|
|
|
if waitTime == 0 {
|
|
c.Status(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
commands.Store(token, req)
|
|
|
|
if waitTime < 0 || waitTime > commandTimeout {
|
|
waitTime = commandTimeout
|
|
}
|
|
|
|
tmr := time.NewTimer(time.Second * time.Duration(waitTime))
|
|
|
|
select {
|
|
case <-tmr.C:
|
|
cmdErrReply(rttyCmdErrTimeout, req)
|
|
commands.Delete(token)
|
|
case <-ctx.Done():
|
|
}
|
|
}
|