初次提交

This commit is contained in:
liuzhihang1
2024-06-26 20:45:23 +08:00
parent 4b388a5be1
commit 831ea9889f
57 changed files with 3945 additions and 0 deletions

33
api/api.go Normal file
View File

@@ -0,0 +1,33 @@
package api
import (
"errors"
"msm/consts/ctxflag"
"net/http"
"github.com/gin-gonic/gin"
)
func rOk(ctx *gin.Context, message string, data any) {
jsonData := map[string]any{
"code": 0,
"msg": message,
}
if data != nil {
jsonData["data"] = data
}
ctx.JSON(http.StatusOK, jsonData)
}
func errCheck(ctx *gin.Context, isErr bool, errData any) {
if !isErr {
return
}
if err, ok := errData.(error); ok {
ctx.Set(ctxflag.ERR, err)
}
if err, ok := errData.(string); ok {
ctx.Set(ctxflag.ERR, errors.New(err))
}
panic(0)
}

94
api/config.go Normal file
View File

@@ -0,0 +1,94 @@
package api
import (
"msm/config"
"msm/dao"
"msm/model"
"msm/service/es"
"reflect"
"strconv"
"github.com/gin-gonic/gin"
)
type configApi struct{}
var ConfigApi = new(configApi)
func (c *configApi) GetSystemConfiguration(ctx *gin.Context) {
typeElem := reflect.TypeOf(config.CF).Elem()
valueElem := reflect.ValueOf(config.CF).Elem()
result := []model.SystemConfigurationResp{}
for i := 0; i < typeElem.NumField(); i++ {
typeField := typeElem.Field(i)
valueField := valueElem.Field(i)
var value any
switch typeField.Type.Kind() {
case reflect.Int64, reflect.Int:
value = valueField.Int()
case reflect.String:
value = valueField.String()
case reflect.Bool:
value = valueField.Bool()
case reflect.Float64:
value = valueField.Float()
default:
continue
}
result = append(result, model.SystemConfigurationResp{
Key: typeField.Name,
Value: value,
Default: typeField.Tag.Get("default"),
Describe: typeField.Tag.Get("describe"),
})
}
rOk(ctx, "获取系统配置成功", result)
}
func (c *configApi) SetSystemConfiguration(ctx *gin.Context) {
data := map[string]string{}
errCheck(ctx, ctx.ShouldBindJSON(&data) != nil, "请求参数错误")
typeElem := reflect.TypeOf(config.CF).Elem()
valueElem := reflect.ValueOf(config.CF).Elem()
for i := 0; i < typeElem.NumField(); i++ {
typeField := typeElem.Field(i)
valueField := valueElem.Field(i)
for k, v := range data {
if typeField.Name == k {
var err error
switch typeField.Type.Kind() {
case reflect.String:
valueField.SetString(v)
case reflect.Bool:
value, errV := strconv.ParseBool(v)
err = errV
if err == nil {
valueField.SetBool(value)
}
case reflect.Float64:
value, errV := strconv.ParseFloat(v, 64)
err = errV
if err == nil {
valueField.SetFloat(value)
}
case reflect.Int64, reflect.Int:
value, errV := strconv.ParseInt(v, 10, 64)
err = errV
if err == nil {
valueField.SetInt(value)
}
default:
continue
}
errCheck(ctx, err != nil, k+"类似错误")
errCheck(ctx, dao.ConfigDao.SetConfigValue(k, v) != nil, "修改配置失败")
}
}
}
rOk(ctx, "修改配置成功", nil)
}
func (c *configApi) EsConfigReload(ctx *gin.Context) {
errCheck(ctx, !es.InitEs(), "es连接失败请检查是否启用es或账号密码是否存在错误")
rOk(ctx, "已连接上es", nil)
}

34
api/file.go Normal file
View File

@@ -0,0 +1,34 @@
package api
import (
FileService "msm/service/file"
"github.com/gin-gonic/gin"
)
type file struct{}
var FileApi = new(file)
func (f *file) FilePathHandler(ctx *gin.Context) {
data, err := FileService.FileService.GetFileAndDirByPath(ctx.Query("path"))
errCheck(ctx, err != nil, "文件路径查询失败")
rOk(ctx, "文件路径查询成功", data)
}
func (f *file) FileWriteHandler(ctx *gin.Context) {
path := ctx.PostForm("filePath")
fi, err := ctx.FormFile("data")
errCheck(ctx, err != nil, "文件读取失败")
fiReader, _ := fi.Open()
err = FileService.FileService.UpdateFileData(path, fiReader, fi.Size)
errCheck(ctx, err != nil, "文件数据更新失败")
rOk(ctx, "文件更新成功", nil)
}
func (f *file) FileReadHandler(ctx *gin.Context) {
path := ctx.Query("filePath")
bytes, err := FileService.FileService.ReadFileFromPath(path)
errCheck(ctx, err != nil, "文件数据读取失败")
rOk(ctx, "文件数据读取成功", string(bytes))
}

20
api/log.go Normal file
View File

@@ -0,0 +1,20 @@
package api
import (
"msm/config"
"msm/model"
"msm/service/es"
"github.com/gin-gonic/gin"
)
type logApi struct{}
var LogApi = new(logApi)
func (a *logApi) GetLog(ctx *gin.Context) {
req := model.GetLogReq{}
errCheck(ctx, !config.CF.EsEnable, "elasticsearch未启用或账号密码错误")
errCheck(ctx, ctx.ShouldBindJSON(&req) != nil, "请求体格式错误")
rOk(ctx, "查询成功", es.EsService.Search(req))
}

27
api/permission.go Normal file
View File

@@ -0,0 +1,27 @@
package api
import (
"msm/model"
"msm/dao"
"github.com/gin-gonic/gin"
)
var PermissionApi = new(permissionApi)
type permissionApi struct{}
func (p *permissionApi) EditPermssion(ctx *gin.Context) {
per := model.Permission{}
err := ctx.ShouldBindJSON(&per)
errCheck(ctx, err != nil, err)
err = dao.PermissionDao.EditPermssion(per)
errCheck(ctx, err != nil, err)
rOk(ctx, "权限修改成功", nil)
}
func (p *permissionApi) GetPermissionList(ctx *gin.Context) {
result := dao.PermissionDao.GetPermssionList(ctx.Query("account"))
rOk(ctx, "查询成功", result)
}

101
api/proc.go Normal file
View File

@@ -0,0 +1,101 @@
package api
import (
"msm/consts/ctxflag"
"msm/consts/role"
"msm/dao"
"msm/model"
"msm/service/process"
"strconv"
"github.com/gin-gonic/gin"
)
type procApi struct{}
var ProcApi = new(procApi)
func (p *procApi) CreateNewProcess(ctx *gin.Context) {
req := model.Process{}
ctx.ShouldBindJSON(&req)
index, err := dao.ProcessDao.AddProcessConfig(req)
errCheck(ctx, err != nil, err)
req.Uuid = index
proc, err := process.RunNewProcess(req)
errCheck(ctx, err != nil, err)
process.ProcessCtlService.AddProcess(req.Uuid, proc)
rOk(ctx, "创建成功", gin.H{
"id": req.Uuid,
})
}
func (p *procApi) DeleteNewProcess(ctx *gin.Context) {
uuid, err := strconv.Atoi(ctx.Query("uuid"))
errCheck(ctx, err != nil, "参数有误")
process.ProcessCtlService.KillProcess(uuid)
process.ProcessCtlService.DeleteProcess(uuid)
err = dao.ProcessDao.DeleteProcessConfig(uuid)
errCheck(ctx, err != nil, err)
rOk(ctx, "删除成功", nil)
}
func (p *procApi) KillProcess(ctx *gin.Context) {
uuid, err := strconv.Atoi(ctx.Query("uuid"))
errCheck(ctx, err != nil, "参数有误")
err = process.ProcessCtlService.KillProcess(uuid)
errCheck(ctx, err != nil, err)
rOk(ctx, "成功", nil)
}
func (p *procApi) StartProcess(ctx *gin.Context) {
uuid, err := strconv.Atoi(ctx.Query("uuid"))
errCheck(ctx, err != nil, "参数有误")
prod, err := process.ProcessCtlService.GetProcess(uuid)
if err != nil { // 进程不存在则创建
proc, err := process.RunNewProcess(dao.ProcessDao.GetProcessConfigById(uuid))
errCheck(ctx, err != nil, err)
process.ProcessCtlService.AddProcess(uuid, proc)
rOk(ctx, "成功", nil)
return
}
errCheck(ctx, prod.GetStateState() == 1, "进程还在运行中")
prod.ResetRestartTimes()
prod.ReStart()
// dao.UpdateServerAutoStart(uuid, true)
rOk(ctx, "成功", nil)
}
func (p *procApi) GetProcessList(ctx *gin.Context) {
if ctx.GetInt(ctxflag.ROLE) < int(role.USER) {
rOk(ctx, "进程列表获取成功", process.ProcessCtlService.GetProcessList())
} else {
rOk(ctx, "进程列表获取成功", process.ProcessCtlService.GetProcessListByUser(ctx.GetString(ctxflag.USER_NAME)))
}
}
func (p *procApi) UpdateProcessConfig(ctx *gin.Context) {
req := model.Process{}
ctx.ShouldBindJSON(&req)
process.ProcessCtlService.UpdateProcessConfig(req)
err := dao.ProcessDao.UpdateProcessConfig(req)
errCheck(ctx, err != nil, err)
rOk(ctx, "更改配置成功", nil)
}
func (p *procApi) GetProcessConfig(ctx *gin.Context) {
uuid, err := strconv.Atoi(ctx.Query("uuid"))
errCheck(ctx, err != nil, "参数有误")
data := dao.ProcessDao.GetProcessConfigById(uuid)
errCheck(ctx, data.Uuid == 0, "未查询到信息")
rOk(ctx, "success", data)
}
func (p *procApi) ProcessControl(ctx *gin.Context) {
user := ctx.GetString(ctxflag.USER_NAME)
uuid, err := strconv.Atoi(ctx.Query("uuid"))
errCheck(ctx, err != nil, "参数有误")
proc, err := process.ProcessCtlService.GetProcess(uuid)
errCheck(ctx, err != nil, "进程控制权获取失败")
proc.ProcessControl(user)
rOk(ctx, "获取进程控权成功", nil)
}

50
api/push.go Normal file
View File

@@ -0,0 +1,50 @@
package api
import (
"msm/model"
"strconv"
"msm/dao"
"github.com/gin-gonic/gin"
)
type pushApi struct{}
var PushApi = new(pushApi)
func (p *pushApi) GetPushList(ctx *gin.Context) {
rOk(ctx, "查询成功", dao.PushDao.GetPushList())
}
func (p *pushApi) GetPushById(ctx *gin.Context) {
id, err := strconv.Atoi(ctx.Query("id"))
errCheck(ctx, err != nil, err)
rOk(ctx, "查询成功", dao.PushDao.GetPushConfigById(id))
}
func (p *pushApi) AddPushConfig(ctx *gin.Context) {
data := model.Push{}
err := ctx.ShouldBindJSON(&data)
errCheck(ctx, err != nil, err)
err = dao.PushDao.AddPushConfig(data)
errCheck(ctx, err != nil, err)
rOk(ctx, "添加成功", nil)
}
func (p *pushApi) UpdatePushConfig(ctx *gin.Context) {
data := model.Push{}
err := ctx.ShouldBindJSON(&data)
errCheck(ctx, err != nil, err)
err = dao.PushDao.UpdatePushConfig(data)
errCheck(ctx, err != nil, err)
rOk(ctx, "更新成功", nil)
}
func (p *pushApi) DeletePushConfig(ctx *gin.Context) {
id, err := strconv.Atoi(ctx.Query("id"))
errCheck(ctx, err != nil, err)
err = dao.PushDao.DeletePushConfig(id)
errCheck(ctx, err != nil, err)
rOk(ctx, "删除成功", nil)
}

86
api/user.go Normal file
View File

@@ -0,0 +1,86 @@
package api
import (
"msm/consts/ctxflag"
"msm/consts/role"
"msm/dao"
"msm/model"
"msm/utils"
"github.com/gin-gonic/gin"
)
type userApi struct{}
var UserApi = new(userApi)
const DEFAULT_ROOT_PASSWORD = "root"
func (u *userApi) LoginHandler(ctx *gin.Context) {
info := map[string]string{}
ctx.ShouldBindJSON(&info)
account := info["account"]
password := info["password"]
errCheck(ctx, !u.checkLoginInfo(account, password), "登入失败,账号或密码错误")
token, err := utils.GenToken(account)
errCheck(ctx, err != nil, err)
ctx.JSON(200, gin.H{
"code": 0,
"msg": "登入成功!",
"token": token,
"username": account,
"role": dao.UserDao.GetUserByName(account).Role,
})
}
func (u *userApi) CreateUser(ctx *gin.Context) {
user := model.User{}
err := ctx.ShouldBindJSON(&user)
errCheck(ctx, err != nil, err)
errCheck(ctx, user.Role == int(role.ROOT), "不能添加root账号")
err = dao.UserDao.CreateUser(user)
errCheck(ctx, err != nil, err)
rOk(ctx, "注册成功", nil)
}
func (u *userApi) ChangePassword(ctx *gin.Context) {
user := model.User{}
err := ctx.ShouldBindJSON(&user)
errCheck(ctx, err != nil, err)
reqUser := ctx.GetString(ctxflag.USER_NAME)
errCheck(ctx, ctx.GetInt(ctxflag.ROLE) != int(role.ROOT) && user.Account != "", "参数错误")
var userName string
if user.Account != "" {
userName = user.Account
} else {
userName = reqUser
}
err = dao.UserDao.UpdatePassword(userName, user.Password)
errCheck(ctx, err != nil, err)
rOk(ctx, "修改密码成功", nil)
}
func (u *userApi) DeleteUser(ctx *gin.Context) {
errCheck(ctx, ctx.Query("account") == "root", "无法删除root账户")
err := dao.UserDao.DeleteUser(ctx.Query("account"))
errCheck(ctx, err != nil, "无法删除root账户")
rOk(ctx, "删除成功", nil)
}
func (u *userApi) GetUserList(ctx *gin.Context) {
rOk(ctx, "查询成功", dao.UserDao.GetUserList())
}
func (u *userApi) checkLoginInfo(account, password string) bool {
user := dao.UserDao.GetUserByName(account)
if account == "root" && user.Account == "" {
dao.UserDao.CreateUser(model.User{
Account: "root",
Password: DEFAULT_ROOT_PASSWORD,
Role: int(role.ROOT),
})
return password == DEFAULT_ROOT_PASSWORD
}
return user.Password == utils.Md5(password)
}

96
api/ws.go Normal file
View File

@@ -0,0 +1,96 @@
package api
import (
"context"
"msm/consts/ctxflag"
"msm/log"
"msm/service/process"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
type wsApi struct{}
var WsApi = new(wsApi)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func (w *wsApi) WebsocketHandle(ctx *gin.Context) {
reqUser := ctx.GetString(ctxflag.USER_NAME)
uuid, err := strconv.Atoi(ctx.Query("uuid"))
errCheck(ctx, err != nil, "参数有误")
proc, err := process.ProcessCtlService.GetProcess(uuid)
errCheck(ctx, err != nil, "进程获取失败")
errCheck(ctx, proc.GetStateState() != 1, "进程未运行")
errCheck(ctx, proc.GetControlController() != reqUser && !proc.VerifyControl(), "进程权限不足")
errCheck(ctx, !proc.TryLock(), "进程已被占用")
proc.SetWhoUsing(reqUser)
conn, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
errCheck(ctx, err != nil, "ws升级失败")
log.Logger.Infow("ws连接成功", "进程名称", proc.GetName(), "连接者", proc.GetWhoUsing())
proc.SetControlController("")
wsCtx, cancel := context.WithCancel(context.Background())
w.startWsConnect(conn, proc, cancel)
proc.SetWsConn(conn)
proc.SetIsUsing(true)
close := func(err string) {
proc.SetWhoUsing("")
proc.SetIsUsing(false)
proc.SetWsConn(nil)
conn.Close()
proc.Unlock()
log.Logger.Infow("ws连接断开", "操作类型", err, "进程名称", proc.GetName())
}
conn.SetCloseHandler(func(_ int, _ string) error {
proc.ChangControlChan() <- 1
close("ws连接被断开")
return nil
})
select {
case signal := <-proc.ChangControlChan():
{
if signal == 0 {
close("强制断开ws连接")
}
}
case <-proc.StopChan():
{
close("进程已停止强制断开ws连接")
}
case <-time.After(time.Minute * 10):
{
close("连接时间超过最大时长限制")
}
case <-wsCtx.Done():
{
close("tcp连接建立已被关闭")
}
}
}
func (w *wsApi) startWsConnect(conn *websocket.Conn, proc process.Process, cancel context.CancelFunc) {
proc.ReadCache(conn)
log.Logger.Debugw("ws读取线程已启动")
go func() {
for {
_, b, err := conn.ReadMessage()
if err != nil {
log.Logger.Debugw("ws读取线程已退出", "info", err)
cancel()
return
}
proc.WriteBytes(b)
}
}()
}