initial commit

This commit is contained in:
XZB
2022-03-16 16:26:28 +08:00
commit 740e33f3a1
73 changed files with 12937 additions and 0 deletions

242
server/handler/handler.go Normal file
View File

@@ -0,0 +1,242 @@
package handler
import (
"Spark/modules"
"Spark/server/common"
"Spark/utils"
"Spark/utils/melody"
"fmt"
"github.com/gin-gonic/gin"
"github.com/kataras/golog"
"net/http"
"time"
)
// APIRouter 负责分配各种API接口
func APIRouter(ctx *gin.RouterGroup, auth gin.HandlerFunc) {
ctx.PUT(`/device/screenshot/put`, putScreenshot)
ctx.PUT(`/device/file/put`, putDeviceFile)
ctx.Any(`/device/terminal`, initTerminal)
group := ctx.Group(`/`, auth)
{
group.POST(`/device/screenshot/get`, getScreenshot)
group.POST(`/device/process/list`, listDeviceProcesses)
group.POST(`/device/process/kill`, killDeviceProcess)
group.POST(`/device/file/remove`, removeDeviceFile)
group.POST(`/device/file/list`, listDeviceFiles)
group.POST(`/device/file/get`, getDeviceFile)
group.POST(`/device/list`, getDevices)
group.POST(`/device/:act`, callDevice)
group.POST(`/client/check`, checkClient)
group.POST(`/client/generate`, generateClient)
}
}
// putScreenshot 负责获取client发送过来的屏幕截图
func putScreenshot(ctx *gin.Context) {
errMsg := ctx.GetHeader(`Error`)
trigger := ctx.GetHeader(`Trigger`)
if len(trigger) == 0 {
ctx.JSON(http.StatusBadRequest, modules.Packet{Code: -1, Msg: `参数不完整`})
return
}
if len(errMsg) > 0 {
evCaller(modules.Packet{
Code: 1,
Msg: fmt.Sprintf(`截图失败:%v`, errMsg),
Data: map[string]interface{}{
`callback`: trigger,
},
}, nil)
ctx.JSON(http.StatusOK, modules.Packet{Code: 0})
return
}
data, err := ctx.GetRawData()
if len(data) == 0 {
msg := ``
if err != nil {
msg = fmt.Sprintf(`截图读取失败:%v`, err)
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: msg})
} else {
msg = `截图失败:未知错误`
ctx.JSON(http.StatusOK, modules.Packet{Code: 0})
}
evCaller(modules.Packet{
Code: 1,
Msg: msg,
Data: map[string]interface{}{
`callback`: trigger,
},
}, nil)
return
}
evCaller(modules.Packet{
Code: 0,
Data: map[string]interface{}{
`screenshot`: data,
`callback`: trigger,
},
}, nil)
ctx.JSON(http.StatusOK, modules.Packet{Code: 0})
}
// getScreenshot 负责发送指令给client让其截图
func getScreenshot(ctx *gin.Context) {
var form struct {
Conn string `json:"uuid" yaml:"uuid" form:"uuid"`
Device string `json:"device" yaml:"device" form:"device"`
}
if ctx.ShouldBind(&form) != nil || (len(form.Conn) == 0 && len(form.Device) == 0) {
ctx.JSON(http.StatusBadRequest, modules.Packet{Code: -1, Msg: `参数不完整`})
return
}
target := ``
trigger := utils.GetStrUUID()
if len(form.Conn) == 0 {
ok := false
target, ok = common.CheckDevice(form.Device)
if !ok {
ctx.JSON(http.StatusBadGateway, modules.Packet{Code: 1, Msg: `未找到该设备`})
return
}
} else {
target = form.Conn
if !common.Devices.Has(target) {
ctx.JSON(http.StatusBadGateway, modules.Packet{Code: 1, Msg: `未找到该设备`})
return
}
}
common.SendPackUUID(modules.Packet{Code: 0, Act: `screenshot`, Data: gin.H{`event`: trigger}}, target)
ok := addEventOnce(func(p modules.Packet, _ *melody.Session) {
if p.Code != 0 {
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: p.Msg})
} else {
data, ok := p.Data[`screenshot`]
if !ok {
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `截图获取失败`})
return
}
screenshot, ok := data.([]byte)
if !ok {
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `截图获取失败`})
return
}
ctx.Data(200, `image/png`, screenshot)
}
}, target, trigger, 5*time.Second)
if !ok {
ctx.JSON(http.StatusGatewayTimeout, modules.Packet{Code: 1, Msg: `响应超时`})
}
}
// getDevices 负责获取所有device的基本信息
func getDevices(ctx *gin.Context) {
devices := make(map[string]modules.Device)
common.Devices.IterCb(func(uuid string, v interface{}) bool {
device, ok := v.(*modules.Device)
if ok {
devices[uuid] = *device
}
return true
})
ctx.JSON(http.StatusOK, modules.CommonPack{Code: 0, Data: devices})
}
// callDevice 负责把HTTP网关发送的请求转发给client
func callDevice(ctx *gin.Context) {
var form struct {
Conn string `json:"uuid" yaml:"uuid" form:"uuid"`
Device string `json:"device" yaml:"device" form:"device"`
}
act := ctx.Param(`act`)
if ctx.ShouldBind(&form) != nil || len(act) == 0 || (len(form.Conn) == 0 && len(form.Device) == 0) {
ctx.JSON(http.StatusBadRequest, modules.Packet{Code: -1, Msg: `参数不完整`})
return
}
connUUID := ``
trigger := utils.GetStrUUID()
if len(form.Conn) == 0 {
ok := false
connUUID, ok = common.CheckDevice(form.Device)
if !ok {
ctx.JSON(http.StatusBadGateway, modules.Packet{Code: 1, Msg: `未找到该设备`})
return
}
} else {
connUUID = form.Conn
if !common.Devices.Has(connUUID) {
ctx.JSON(http.StatusBadGateway, modules.Packet{Code: 1, Msg: `未找到该设备`})
return
}
}
common.SendPackUUID(modules.Packet{Act: act, Data: gin.H{`event`: trigger}}, connUUID)
ok := addEventOnce(func(p modules.Packet, _ *melody.Session) {
if p.Code != 0 {
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: p.Msg})
} else {
ctx.JSON(http.StatusOK, modules.Packet{Code: 0})
}
}, connUUID, trigger, 5*time.Second)
if !ok {
ctx.JSON(http.StatusGatewayTimeout, modules.Packet{Code: 1, Msg: `响应超时`})
}
}
// WSDevice 负责处理client设备信息上报的事件
func WSDevice(data []byte, session *melody.Session) error {
var pack struct {
Code int `json:"code,omitempty"`
Act string `json:"act,omitempty"`
Msg string `json:"msg,omitempty"`
Device modules.Device `json:"data"`
}
err := utils.JSON.Unmarshal(data, &pack)
if err != nil {
golog.Error(err)
session.Close()
return err
}
addr, ok := session.Get(`Address`)
if ok {
pack.Device.WAN = addr.(string)
} else {
pack.Device.WAN = `Unknown`
}
if pack.Act == `report` {
// 查询设备列表中,该设备是否已经上线
// 如果已经上线就找到对应的session发送命令使其退出
exSession := ``
common.Devices.IterCb(func(uuid string, v interface{}) bool {
device := v.(*modules.Device)
if device.ID == pack.Device.ID {
exSession = uuid
target, ok := common.Melody.GetSessionByUUID(uuid)
if ok {
common.SendPack(modules.Packet{Act: `offline`}, target)
target.Close()
}
return false
}
return true
})
if len(exSession) > 0 {
common.Devices.Remove(exSession)
}
}
common.Devices.Set(session.UUID, &pack.Device)
if pack.Act == `setDevice` {
common.SendPack(modules.Packet{Act: `heartbeat`}, session)
} else {
common.SendPack(modules.Packet{Code: 0}, session)
}
return nil
}
// WSRouter 负责处理client回复的packet
func WSRouter(pack modules.Packet, session *melody.Session) {
evCaller(pack, session)
}