init: 1.0.0

This commit is contained in:
Chang lue Tsen
2025-04-25 12:08:29 +09:00
commit 8addcc584b
1031 changed files with 76472 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
package server
const Unchanged = "Unchanged"
@@ -0,0 +1,83 @@
package server
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/ppanel-server/internal/config"
"github.com/perfect-panel/ppanel-server/internal/svc"
"github.com/perfect-panel/ppanel-server/internal/types"
"github.com/perfect-panel/ppanel-server/pkg/logger"
"github.com/perfect-panel/ppanel-server/pkg/tool"
"github.com/perfect-panel/ppanel-server/pkg/xerr"
)
type GetServerConfigLogic struct {
logger.Logger
ctx *gin.Context
svcCtx *svc.ServiceContext
}
// Get server config
func NewGetServerConfigLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *GetServerConfigLogic {
return &GetServerConfigLogic{
Logger: logger.WithContext(ctx.Request.Context()),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetServerConfigLogic) GetServerConfig(req *types.GetServerConfigRequest) (resp *types.GetServerConfigResponse, err error) {
cacheKey := fmt.Sprintf("%s%d", config.ServerConfigCacheKey, req.ServerId)
cache, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result()
if err == nil {
if cache != "" {
etag := tool.GenerateETag([]byte(cache))
// Check If-None-Match header
match := l.ctx.GetHeader("If-None-Match")
if match == etag {
return nil, xerr.StatusNotModified
}
l.ctx.Header("ETag", etag)
resp := &types.GetServerConfigResponse{}
err = json.Unmarshal([]byte(cache), resp)
if err != nil {
l.Errorw("[ServerConfigCacheKey] json unmarshal error", logger.Field("error", err.Error()))
return nil, err
}
return resp, nil
}
}
nodeInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId)
if err != nil {
l.Errorw("[GetServerConfig] FindOne error", logger.Field("error", err.Error()))
return nil, err
}
cfg := make(map[string]interface{})
err = json.Unmarshal([]byte(nodeInfo.Config), &cfg)
if err != nil {
l.Errorw("[GetServerConfig] json unmarshal error", logger.Field("error", err.Error()))
return nil, err
}
resp = &types.GetServerConfigResponse{
Basic: types.ServerBasic{
PullInterval: l.svcCtx.Config.Node.NodePullInterval,
PushInterval: l.svcCtx.Config.Node.NodePushInterval,
},
Protocol: nodeInfo.Protocol,
Config: cfg,
}
data, err := json.Marshal(resp)
if err != nil {
l.Errorw("[GetServerConfig] json marshal error", logger.Field("error", err.Error()))
return nil, err
}
etag := tool.GenerateETag(data)
l.ctx.Header("ETag", etag)
if err = l.svcCtx.Redis.Set(l.ctx, cacheKey, data, -1).Err(); err != nil {
l.Errorw("[GetServerConfig] redis set error", logger.Field("error", err.Error()))
}
return resp, nil
}
@@ -0,0 +1,110 @@
package server
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/ppanel-server/internal/config"
"github.com/perfect-panel/ppanel-server/internal/svc"
"github.com/perfect-panel/ppanel-server/internal/types"
"github.com/perfect-panel/ppanel-server/pkg/logger"
"github.com/perfect-panel/ppanel-server/pkg/tool"
"github.com/perfect-panel/ppanel-server/pkg/uuidx"
"github.com/perfect-panel/ppanel-server/pkg/xerr"
)
type GetServerUserListLogic struct {
logger.Logger
ctx *gin.Context
svcCtx *svc.ServiceContext
}
// Get user list
func NewGetServerUserListLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *GetServerUserListLogic {
return &GetServerUserListLogic{
Logger: logger.WithContext(ctx.Request.Context()),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetServerUserListLogic) GetServerUserList(req *types.GetServerUserListRequest) (resp *types.GetServerUserListResponse, err error) {
cacheKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, req.ServerId)
cache, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result()
if err == nil {
if cache != "" {
etag := tool.GenerateETag([]byte(cache))
resp := &types.GetServerUserListResponse{}
// Check If-None-Match header
if match := l.ctx.GetHeader("If-None-Match"); match == etag {
return nil, xerr.StatusNotModified
}
l.ctx.Header("ETag", etag)
err = json.Unmarshal([]byte(cache), resp)
if err != nil {
l.Errorw("[ServerUserListCacheKey] json unmarshal error", logger.Field("error", err.Error()))
return nil, err
}
return resp, nil
}
}
server, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId)
if err != nil {
return nil, err
}
subs, err := l.svcCtx.SubscribeModel.QuerySubscribeIdsByServerIdAndServerGroupId(l.ctx, server.Id, server.GroupId)
if err != nil {
l.Errorw("QuerySubscribeIdsByServerIdAndServerGroupId error", logger.Field("error", err.Error()))
return nil, err
}
if len(subs) == 0 {
return &types.GetServerUserListResponse{
Users: []types.ServerUser{
{
Id: 1,
UUID: uuidx.NewUUID().String(),
},
},
}, nil
}
users := make([]types.ServerUser, 0)
for _, sub := range subs {
data, err := l.svcCtx.UserModel.FindUsersSubscribeBySubscribeId(l.ctx, sub.Id)
if err != nil {
return nil, err
}
for _, datum := range data {
speedLimit := server.SpeedLimit
if (int(sub.SpeedLimit) < server.SpeedLimit && sub.SpeedLimit != 0) ||
(int(sub.SpeedLimit) > server.SpeedLimit && sub.SpeedLimit == 0) {
speedLimit = int(sub.SpeedLimit)
}
users = append(users, types.ServerUser{
Id: datum.Id,
UUID: datum.UUID,
SpeedLimit: int64(speedLimit),
DeviceLimit: sub.DeviceLimit,
})
}
}
if len(users) == 0 {
users = append(users, types.ServerUser{
Id: 1,
UUID: uuidx.NewUUID().String(),
})
}
resp = &types.GetServerUserListResponse{
Users: users,
}
val, _ := json.Marshal(resp)
etag := tool.GenerateETag(val)
l.ctx.Header("ETag", etag)
err = l.svcCtx.Redis.Set(l.ctx, cacheKey, string(val), -1).Err()
if err != nil {
l.Errorw("[ServerUserListCacheKey] redis set error", logger.Field("error", err.Error()))
}
return resp, nil
}
@@ -0,0 +1,70 @@
package server
import (
"context"
"errors"
"fmt"
"github.com/perfect-panel/ppanel-server/internal/model/cache"
"github.com/perfect-panel/ppanel-server/internal/svc"
"github.com/perfect-panel/ppanel-server/internal/types"
"github.com/perfect-panel/ppanel-server/pkg/logger"
)
type PushOnlineUsersLogic struct {
logger.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// NewPushOnlineUsersLogic Push online users
func NewPushOnlineUsersLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PushOnlineUsersLogic {
return &PushOnlineUsersLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *PushOnlineUsersLogic) PushOnlineUsers(req *types.OnlineUsersRequest) error {
// 验证请求数据
if req.ServerId <= 0 || len(req.Users) == 0 {
return errors.New("invalid request parameters")
}
// 验证用户数据
for _, user := range req.Users {
if user.SID <= 0 || user.IP == "" {
return fmt.Errorf("invalid user data: uid=%d, ip=%s", user.SID, user.IP)
}
}
// Find server info
_, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId)
if err != nil {
l.Errorw("[PushOnlineUsers] FindOne error", logger.Field("error", err))
return fmt.Errorf("server not found: %w", err)
}
userOnlineIp := make([]cache.NodeOnlineUser, 0)
for _, user := range req.Users {
userOnlineIp = append(userOnlineIp, cache.NodeOnlineUser{
SID: user.SID,
IP: user.IP,
})
}
err = l.svcCtx.NodeCache.AddOnlineUserIP(l.ctx, userOnlineIp)
if err != nil {
l.Errorw("[PushOnlineUsers] cache operation error", logger.Field("error", err))
return err
}
err = l.svcCtx.NodeCache.UpdateNodeOnlineUser(l.ctx, req.ServerId, userOnlineIp)
if err != nil {
l.Errorw("[PushOnlineUsers] cache operation error", logger.Field("error", err))
return err
}
return nil
}
@@ -0,0 +1,46 @@
package server
import (
"context"
"errors"
"github.com/perfect-panel/ppanel-server/internal/model/cache"
"github.com/perfect-panel/ppanel-server/internal/svc"
"github.com/perfect-panel/ppanel-server/internal/types"
"github.com/perfect-panel/ppanel-server/pkg/logger"
)
type ServerPushStatusLogic struct {
logger.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// Push server status
func NewServerPushStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ServerPushStatusLogic {
return &ServerPushStatusLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ServerPushStatusLogic) ServerPushStatus(req *types.ServerPushStatusRequest) error {
// Find server info
serverInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId)
if err != nil || serverInfo.Id <= 0 {
l.Errorw("[PushOnlineUsers] FindOne error", logger.Field("error", err))
return errors.New("server not found")
}
err = l.svcCtx.NodeCache.UpdateNodeStatus(l.ctx, req.ServerId, cache.NodeStatus{
Cpu: req.Cpu,
Mem: req.Mem,
Disk: req.Disk,
UpdatedAt: req.UpdatedAt,
})
if err != nil {
l.Errorw("[ServerPushStatus] UpdateNodeStatus error", logger.Field("error", err))
return errors.New("update node status failed")
}
return nil
}
@@ -0,0 +1,70 @@
package server
import (
"context"
"encoding/json"
"github.com/hibiken/asynq"
"github.com/perfect-panel/ppanel-server/internal/model/cache"
"github.com/perfect-panel/ppanel-server/internal/svc"
"github.com/perfect-panel/ppanel-server/internal/types"
"github.com/perfect-panel/ppanel-server/pkg/logger"
"github.com/perfect-panel/ppanel-server/pkg/tool"
task "github.com/perfect-panel/ppanel-server/queue/types"
"github.com/pkg/errors"
)
//goland:noinspection GoNameStartsWithPackageName
type ServerPushUserTrafficLogic struct {
logger.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// NewServerPushUserTrafficLogic Push user Traffic
func NewServerPushUserTrafficLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ServerPushUserTrafficLogic {
return &ServerPushUserTrafficLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ServerPushUserTrafficLogic) ServerPushUserTraffic(req *types.ServerPushUserTrafficRequest) error {
// Find server info
serverInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.ServerId)
if err != nil {
l.Errorw("[PushOnlineUsers] FindOne error", logger.Field("error", err))
return errors.New("server not found")
}
// Create traffic task
var request task.TrafficStatistics
var userTraffic []cache.UserTraffic
request.ServerId = serverInfo.Id
tool.DeepCopy(&request.Logs, req.Traffic)
tool.DeepCopy(&userTraffic, req.Traffic)
// update today traffic rank
err = l.svcCtx.NodeCache.AddNodeTodayTraffic(l.ctx, serverInfo.Id, userTraffic)
if err != nil {
l.Errorw("[ServerPushUserTraffic] AddNodeTodayTraffic error", logger.Field("error", err))
return errors.New("add node today traffic error")
}
for _, user := range req.Traffic {
if err = l.svcCtx.NodeCache.AddUserTodayTraffic(l.ctx, user.SID, user.Upload, user.Download); err != nil {
l.Errorw("[ServerPushUserTraffic] AddUserTodayTraffic error", logger.Field("error", err))
continue
}
}
// Push traffic task
val, _ := json.Marshal(request)
t := asynq.NewTask(task.ForthwithTrafficStatistics, val, asynq.MaxRetry(3))
info, err := l.svcCtx.Queue.EnqueueContext(l.ctx, t)
if err != nil {
l.Errorw("[ServerPushUserTraffic] Push traffic task error", logger.Field("error", err.Error()), logger.Field("task", t))
} else {
l.Infow("[ServerPushUserTraffic] Push traffic task success", logger.Field("task", t), logger.Field("info", info))
}
return nil
}