mirror of
https://github.com/XZB-1248/Spark
synced 2025-10-05 00:02:41 +08:00
243 lines
6.8 KiB
Go
243 lines
6.8 KiB
Go
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)
|
||
}
|