init: 1.0.0
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/xerr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type BatchDeleteNodeGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewBatchDeleteNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchDeleteNodeGroupLogic {
|
||||
return &BatchDeleteNodeGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *BatchDeleteNodeGroupLogic) BatchDeleteNodeGroup(req *types.BatchDeleteNodeGroupRequest) error {
|
||||
// Check if the group is empty
|
||||
count, err := l.svcCtx.ServerModel.QueryServerCountByServerGroups(l.ctx, req.Ids)
|
||||
if err != nil {
|
||||
l.Errorw("[BatchDeleteNodeGroup] Query Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query server error: %v", err)
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.NodeGroupNotEmpty), "group is not empty")
|
||||
}
|
||||
// Delete the group
|
||||
err = l.svcCtx.ServerModel.BatchDeleteNodeGroup(l.ctx, req.Ids)
|
||||
if err != nil {
|
||||
l.Errorw("[BatchDeleteNodeGroup] Delete Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/xerr"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type BatchDeleteNodeLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewBatchDeleteNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchDeleteNodeLogic {
|
||||
return &BatchDeleteNodeLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *BatchDeleteNodeLogic) BatchDeleteNode(req *types.BatchDeleteNodeRequest) error {
|
||||
err := l.svcCtx.DB.Transaction(func(db *gorm.DB) error {
|
||||
for _, id := range req.Ids {
|
||||
err := l.svcCtx.ServerModel.Delete(l.ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[BatchDeleteNode] Delete Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/logger"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/xerr"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/svc"
|
||||
"github.com/perfect-panel/ppanel-server/internal/types"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type CreateNodeGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCreateNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateNodeGroupLogic {
|
||||
return &CreateNodeGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateNodeGroupLogic) CreateNodeGroup(req *types.CreateNodeGroupRequest) error {
|
||||
groupInfo := &server.Group{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
}
|
||||
err := l.svcCtx.ServerModel.InsertGroup(l.ctx, groupInfo)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
"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"
|
||||
queue "github.com/perfect-panel/ppanel-server/queue/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type CreateNodeLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCreateNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateNodeLogic {
|
||||
return &CreateNodeLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateNodeLogic) CreateNode(req *types.CreateNodeRequest) error {
|
||||
config, err := json.Marshal(req.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var serverInfo server.Server
|
||||
tool.DeepCopy(&serverInfo, req)
|
||||
serverInfo.Config = string(config)
|
||||
nodeRelay, err := json.Marshal(req.RelayNode)
|
||||
if err != nil {
|
||||
l.Errorw("[UpdateNode] Marshal RelayNode Error: ", logger.Field("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
if len(req.Tags) > 0 {
|
||||
serverInfo.Tags = strings.Join(req.Tags, ",")
|
||||
}
|
||||
|
||||
serverInfo.LastReportedAt = time.UnixMicro(1218124800)
|
||||
|
||||
serverInfo.City = req.City
|
||||
serverInfo.Country = req.Country
|
||||
|
||||
serverInfo.RelayNode = string(nodeRelay)
|
||||
if req.Protocol == "vless" {
|
||||
var cfg types.Vless
|
||||
if err := json.Unmarshal(config, &cfg); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error())
|
||||
}
|
||||
if cfg.Security == "reality" && cfg.SecurityConfig.RealityPublicKey == "" {
|
||||
public, private, err := tool.Curve25519Genkey(false, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "generate curve25519 key error")
|
||||
}
|
||||
cfg.SecurityConfig.RealityPublicKey = public
|
||||
cfg.SecurityConfig.RealityPrivateKey = private
|
||||
cfg.SecurityConfig.RealityShortId = tool.GenerateShortID(private)
|
||||
}
|
||||
if cfg.SecurityConfig.RealityServerAddr == "" {
|
||||
cfg.SecurityConfig.RealityServerAddr = cfg.SecurityConfig.SNI
|
||||
}
|
||||
if cfg.SecurityConfig.RealityServerPort == 0 {
|
||||
cfg.SecurityConfig.RealityServerPort = 443
|
||||
}
|
||||
config, _ = json.Marshal(cfg)
|
||||
serverInfo.Config = string(config)
|
||||
}
|
||||
|
||||
err = l.svcCtx.ServerModel.Insert(l.ctx, &serverInfo)
|
||||
if err != nil {
|
||||
l.Errorw("[CreateNode] Insert Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create server error: %v", err)
|
||||
}
|
||||
|
||||
// Marshal the task payload
|
||||
payload, err := json.Marshal(queue.GetNodeCountry{
|
||||
Protocol: serverInfo.Protocol,
|
||||
ServerAddr: serverInfo.ServerAddr,
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeCountry]: Marshal Error", logger.Field("error", err.Error()))
|
||||
return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to marshal task payload")
|
||||
}
|
||||
// Create a queue task
|
||||
task := asynq.NewTask(queue.ForthwithGetCountry, payload)
|
||||
// Enqueue the task
|
||||
taskInfo, err := l.svcCtx.Queue.Enqueue(task)
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeCountry]: Enqueue Error", logger.Field("error", err.Error()), logger.Field("payload", string(payload)))
|
||||
return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to enqueue task")
|
||||
}
|
||||
l.Infow("[GetNodeCountry]: Enqueue Success", logger.Field("taskID", taskInfo.ID), logger.Field("payload", string(payload)))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/rules"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type CreateRuleGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// Create rule group
|
||||
func NewCreateRuleGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateRuleGroupLogic {
|
||||
return &CreateRuleGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
func parseAndValidateRules(ruleText, ruleName string) ([]string, error) {
|
||||
var rs []string
|
||||
ruleArr := strings.Split(ruleText, "\n")
|
||||
if len(ruleArr) == 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "rules is empty")
|
||||
}
|
||||
|
||||
for _, s := range ruleArr {
|
||||
r := rules.NewRule(s, ruleName)
|
||||
if r == nil {
|
||||
continue
|
||||
}
|
||||
if err := r.Validate(); err != nil {
|
||||
continue
|
||||
}
|
||||
rs = append(rs, r.String())
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
func (l *CreateRuleGroupLogic) CreateRuleGroup(req *types.CreateRuleGroupRequest) error {
|
||||
rs, err := parseAndValidateRules(req.Rules, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = l.svcCtx.ServerModel.InsertRuleGroup(l.ctx, &server.RuleGroup{
|
||||
Name: req.Name,
|
||||
Icon: req.Icon,
|
||||
Tags: tool.StringSliceToString(req.Tags),
|
||||
Rules: strings.Join(rs, "\n"),
|
||||
Enable: req.Enable,
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[CreateRuleGroup] Insert Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create server rule group error: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/xerr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type DeleteNodeGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewDeleteNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteNodeGroupLogic {
|
||||
return &DeleteNodeGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteNodeGroupLogic) DeleteNodeGroup(req *types.DeleteNodeGroupRequest) error {
|
||||
// Check if the group is empty
|
||||
count, err := l.svcCtx.ServerModel.QueryServerCountByServerGroups(l.ctx, []int64{req.Id})
|
||||
if err != nil {
|
||||
l.Errorw("[DeleteNodeGroup] Query Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query server error: %v", err)
|
||||
}
|
||||
if count > 0 {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.NodeGroupNotEmpty), "group is not empty")
|
||||
}
|
||||
// Delete the group
|
||||
err = l.svcCtx.ServerModel.DeleteGroup(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
l.Errorw("[DeleteNodeGroup] Delete Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DeleteNodeLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewDeleteNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteNodeLogic {
|
||||
return &DeleteNodeLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteNodeLogic) DeleteNode(req *types.DeleteNodeRequest) error {
|
||||
err := l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
|
||||
// Delete server
|
||||
err := l.svcCtx.ServerModel.Delete(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete server to subscribe
|
||||
subs, err := l.svcCtx.SubscribeModel.QuerySubscribeIdsByServerIdAndServerGroupId(l.ctx, req.Id, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, sub := range subs {
|
||||
servers := tool.StringToInt64Slice(sub.Server)
|
||||
newServers := tool.RemoveElementBySlice(servers, req.Id)
|
||||
sub.Server = tool.Int64SliceToString(newServers)
|
||||
if err = l.svcCtx.SubscribeModel.Update(l.ctx, sub); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[DeleteNode] Delete Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete server error: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/xerr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type DeleteRuleGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// Delete rule group
|
||||
func NewDeleteRuleGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteRuleGroupLogic {
|
||||
return &DeleteRuleGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteRuleGroupLogic) DeleteRuleGroup(req *types.DeleteRuleGroupRequest) error {
|
||||
err := l.svcCtx.ServerModel.DeleteRuleGroup(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
l.Errorw("[DeleteRuleGroup] Delete Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete server rule group error: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type GetNodeDetailLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetNodeDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeDetailLogic {
|
||||
return &GetNodeDetailLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetNodeDetailLogic) GetNodeDetail(req *types.GetDetailRequest) (resp *types.Server, err error) {
|
||||
detail, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get server detail error: %v", err.Error())
|
||||
}
|
||||
resp = &types.Server{}
|
||||
tool.DeepCopy(resp, detail)
|
||||
var cfg map[string]interface{}
|
||||
err = json.Unmarshal([]byte(detail.Config), &cfg)
|
||||
if err != nil {
|
||||
cfg = make(map[string]interface{})
|
||||
}
|
||||
resp.Config = cfg
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type GetNodeGroupListLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetNodeGroupListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeGroupListLogic {
|
||||
return &GetNodeGroupListLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetNodeGroupListLogic) GetNodeGroupList() (resp *types.GetNodeGroupListResponse, err error) {
|
||||
nodeGroupList, err := l.svcCtx.ServerModel.QueryAllGroup(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error())
|
||||
}
|
||||
nodeGroups := make([]types.ServerGroup, 0)
|
||||
tool.DeepCopy(&nodeGroups, nodeGroupList)
|
||||
return &types.GetNodeGroupListResponse{
|
||||
Total: int64(len(nodeGroups)),
|
||||
List: nodeGroups,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type GetNodeListLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetNodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeListLogic {
|
||||
return &GetNodeListLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetNodeListLogic) GetNodeList(req *types.GetNodeServerListRequest) (resp *types.GetNodeServerListResponse, err error) {
|
||||
total, list, err := l.svcCtx.ServerModel.FindServerListByFilter(l.ctx, &server.ServerFilter{
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
Search: req.Search,
|
||||
Tag: req.Tag,
|
||||
Group: req.GroupId,
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeList] Query Database Error: ", logger.Field("error", err.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error())
|
||||
}
|
||||
nodes := make([]types.Server, 0)
|
||||
for _, v := range list {
|
||||
node := types.Server{}
|
||||
tool.DeepCopy(&node, v)
|
||||
// default relay mode
|
||||
if node.RelayMode == "" {
|
||||
node.RelayMode = "none"
|
||||
}
|
||||
if len(v.Tags) > 0 {
|
||||
if strings.Contains(v.Tags, ",") {
|
||||
node.Tags = strings.Split(v.Tags, ",")
|
||||
} else {
|
||||
node.Tags = []string{v.Tags}
|
||||
}
|
||||
}
|
||||
// parse config
|
||||
var cfg map[string]interface{}
|
||||
err = json.Unmarshal([]byte(v.Config), &cfg)
|
||||
if err != nil {
|
||||
cfg = make(map[string]interface{})
|
||||
}
|
||||
node.Config = cfg
|
||||
relayNode := make([]types.NodeRelay, 0)
|
||||
err = json.Unmarshal([]byte(v.RelayNode), &relayNode)
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeList] Unmarshal RelayNode Error: ", logger.Field("error", err.Error()), logger.Field("relayNode", v.RelayNode))
|
||||
}
|
||||
node.RelayNode = relayNode
|
||||
var status types.NodeStatus
|
||||
nodeStatus, err := l.svcCtx.NodeCache.GetNodeStatus(l.ctx, v.Id)
|
||||
if err != nil {
|
||||
// redis nil is not a Error
|
||||
if !errors.Is(err, redis.Nil) {
|
||||
l.Errorw("[GetNodeList] Get Node Status Error: ", logger.Field("error", err.Error()))
|
||||
}
|
||||
} else {
|
||||
onlineUser, err := l.svcCtx.NodeCache.GetNodeOnlineUser(l.ctx, v.Id)
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeList] Get Node Online User Error: ", logger.Field("error", err.Error()))
|
||||
} else {
|
||||
status.Online = onlineUser
|
||||
}
|
||||
status.Cpu = nodeStatus.Cpu
|
||||
status.Mem = nodeStatus.Mem
|
||||
status.Disk = nodeStatus.Disk
|
||||
status.UpdatedAt = nodeStatus.UpdatedAt
|
||||
}
|
||||
node.Status = &status
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
return &types.GetNodeServerListResponse{
|
||||
Total: total,
|
||||
List: nodes,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GetNodeTagListLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// Get node tag list
|
||||
func NewGetNodeTagListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNodeTagListLogic {
|
||||
return &GetNodeTagListLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetNodeTagListLogic) GetNodeTagList() (resp *types.GetNodeTagListResponse, err error) {
|
||||
var nodeTags, tags []string
|
||||
err = l.svcCtx.ServerModel.Transaction(l.ctx, func(db *gorm.DB) error {
|
||||
|
||||
return db.Model(&server.Server{}).Select("tags").Pluck("tags", &nodeTags).Error
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get node tag list failed, %s", err.Error())
|
||||
}
|
||||
|
||||
for _, tag := range nodeTags {
|
||||
tags = append(tags, strings.Split(tag, ",")...)
|
||||
}
|
||||
|
||||
// Remove duplicate tags
|
||||
tags = tool.RemoveDuplicateElements(tags...)
|
||||
|
||||
return &types.GetNodeTagListResponse{
|
||||
Tags: tags,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"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/xerr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type GetRuleGroupListLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// Get rule group list
|
||||
func NewGetRuleGroupListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRuleGroupListLogic {
|
||||
return &GetRuleGroupListLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetRuleGroupListLogic) GetRuleGroupList() (resp *types.GetRuleGroupResponse, err error) {
|
||||
nodeRuleGroupList, err := l.svcCtx.ServerModel.QueryAllRuleGroup(l.ctx)
|
||||
if err != nil {
|
||||
l.Errorw("[GetRuleGroupList] Query Database Error: ", logger.Field("error", err.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error())
|
||||
}
|
||||
nodeRuleGroups := make([]types.ServerRuleGroup, len(nodeRuleGroupList))
|
||||
for i, v := range nodeRuleGroupList {
|
||||
nodeRuleGroups[i] = types.ServerRuleGroup{
|
||||
Id: v.Id,
|
||||
Icon: v.Icon,
|
||||
Name: v.Name,
|
||||
Tags: strings.Split(v.Tags, ","),
|
||||
Rules: v.Rules,
|
||||
Enable: v.Enable,
|
||||
CreatedAt: v.CreatedAt.UnixMilli(),
|
||||
UpdatedAt: v.UpdatedAt.UnixMilli(),
|
||||
}
|
||||
}
|
||||
return &types.GetRuleGroupResponse{
|
||||
Total: int64(len(nodeRuleGroups)),
|
||||
List: nodeRuleGroups,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"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 NodeSortLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// Node sort
|
||||
func NewNodeSortLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NodeSortLogic {
|
||||
return &NodeSortLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *NodeSortLogic) NodeSort(req *types.NodeSortRequest) error {
|
||||
err := l.svcCtx.ServerModel.Transaction(l.ctx, func(db *gorm.DB) error {
|
||||
// find all servers id
|
||||
var existingIDs []int64
|
||||
db.Model(&server.Server{}).Select("id").Find(&existingIDs)
|
||||
// check if the id is valid
|
||||
validIDMap := make(map[int64]bool)
|
||||
for _, id := range existingIDs {
|
||||
validIDMap[id] = true
|
||||
}
|
||||
// check if the sort is valid
|
||||
var validItems []types.SortItem
|
||||
for _, item := range req.Sort {
|
||||
if validIDMap[item.Id] {
|
||||
validItems = append(validItems, item)
|
||||
}
|
||||
}
|
||||
// query all servers
|
||||
var servers []*server.Server
|
||||
db.Model(&server.Server{}).Order("sort ASC").Find(&servers)
|
||||
// create a map of the current sort
|
||||
currentSortMap := make(map[int64]int64)
|
||||
for _, item := range servers {
|
||||
currentSortMap[item.Id] = item.Sort
|
||||
}
|
||||
|
||||
// new sort map
|
||||
newSortMap := make(map[int64]int64)
|
||||
for _, item := range validItems {
|
||||
newSortMap[item.Id] = item.Sort
|
||||
}
|
||||
|
||||
var itemsToUpdate []types.SortItem
|
||||
for _, item := range validItems {
|
||||
if oldSort, exists := currentSortMap[item.Id]; exists && oldSort != item.Sort {
|
||||
itemsToUpdate = append(itemsToUpdate, item)
|
||||
}
|
||||
}
|
||||
for _, item := range itemsToUpdate {
|
||||
if err := db.Model(&server.Server{}).Where("id = ?", item.Id).Update("sort", item.Sort).Error; err != nil {
|
||||
l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()), logger.Field("id", item.Id), logger.Field("sort", item.Sort))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/xerr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type UpdateNodeGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewUpdateNodeGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateNodeGroupLogic {
|
||||
return &UpdateNodeGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateNodeGroupLogic) UpdateNodeGroup(req *types.UpdateNodeGroupRequest) error {
|
||||
// check server group exist
|
||||
nodeGroup, err := l.svcCtx.ServerModel.FindOneGroup(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), err.Error())
|
||||
}
|
||||
nodeGroup.Name = req.Name
|
||||
nodeGroup.Description = req.Description
|
||||
err = l.svcCtx.ServerModel.UpdateGroup(l.ctx, nodeGroup)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/device"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"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"
|
||||
queue "github.com/perfect-panel/ppanel-server/queue/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type UpdateNodeLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewUpdateNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateNodeLogic {
|
||||
return &UpdateNodeLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateNodeLogic) UpdateNode(req *types.UpdateNodeRequest) error {
|
||||
// Check server exist
|
||||
nodeInfo, err := l.svcCtx.ServerModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server error: %v", err)
|
||||
}
|
||||
tool.DeepCopy(nodeInfo, req)
|
||||
config, err := json.Marshal(req.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeInfo.Config = string(config)
|
||||
nodeRelay, err := json.Marshal(req.RelayNode)
|
||||
if err != nil {
|
||||
l.Errorw("[UpdateNode] Marshal RelayNode Error: ", logger.Field("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
if len(req.Tags) > 0 {
|
||||
nodeInfo.Tags = strings.Join(req.Tags, ",")
|
||||
}
|
||||
|
||||
nodeInfo.City = req.City
|
||||
nodeInfo.Country = req.Country
|
||||
|
||||
nodeInfo.RelayNode = string(nodeRelay)
|
||||
if req.Protocol == "vless" {
|
||||
var cfg types.Vless
|
||||
if err := json.Unmarshal(config, &cfg); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "json.Unmarshal error: %v", err.Error())
|
||||
}
|
||||
if cfg.Security == "reality" && cfg.SecurityConfig.RealityPublicKey == "" {
|
||||
public, private, err := tool.Curve25519Genkey(false, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "generate curve25519 key error")
|
||||
}
|
||||
cfg.SecurityConfig.RealityPublicKey = public
|
||||
cfg.SecurityConfig.RealityPrivateKey = private
|
||||
cfg.SecurityConfig.RealityShortId = tool.GenerateShortID(private)
|
||||
}
|
||||
if cfg.SecurityConfig.RealityServerAddr == "" {
|
||||
cfg.SecurityConfig.RealityServerAddr = cfg.SecurityConfig.SNI
|
||||
}
|
||||
if cfg.SecurityConfig.RealityServerPort == 0 {
|
||||
cfg.SecurityConfig.RealityServerPort = 443
|
||||
}
|
||||
config, _ = json.Marshal(cfg)
|
||||
nodeInfo.Config = string(config)
|
||||
}
|
||||
err = l.svcCtx.ServerModel.Update(l.ctx, nodeInfo)
|
||||
if err != nil {
|
||||
l.Errorw("[UpdateNode] Update Database Error: ", logger.Field("error", err.Error()))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create server error: %v", err)
|
||||
}
|
||||
|
||||
// Marshal the task payload
|
||||
payload, err := json.Marshal(queue.GetNodeCountry{
|
||||
Protocol: nodeInfo.Protocol,
|
||||
ServerAddr: nodeInfo.ServerAddr,
|
||||
})
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeCountry]: Marshal Error", logger.Field("error", err.Error()))
|
||||
return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to marshal task payload")
|
||||
}
|
||||
// Create a queue task
|
||||
task := asynq.NewTask(queue.ForthwithGetCountry, payload)
|
||||
// Enqueue the task
|
||||
taskInfo, err := l.svcCtx.Queue.Enqueue(task)
|
||||
if err != nil {
|
||||
l.Errorw("[GetNodeCountry]: Enqueue Error", logger.Field("error", err.Error()), logger.Field("payload", string(payload)))
|
||||
return errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to enqueue task")
|
||||
}
|
||||
l.Infow("[GetNodeCountry]: Enqueue Success", logger.Field("taskID", taskInfo.ID), logger.Field("payload", string(payload)))
|
||||
l.svcCtx.DeviceManager.Broadcast(device.SubscribeUpdate)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/tool"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/server"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"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 UpdateRuleGroupLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// NewUpdateRuleGroupLogic Update rule group
|
||||
func NewUpdateRuleGroupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateRuleGroupLogic {
|
||||
return &UpdateRuleGroupLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateRuleGroupLogic) UpdateRuleGroup(req *types.UpdateRuleGroupRequest) error {
|
||||
rs, err := parseAndValidateRules(req.Rules, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = l.svcCtx.ServerModel.UpdateRuleGroup(l.ctx, &server.RuleGroup{
|
||||
Id: req.Id,
|
||||
Icon: req.Icon,
|
||||
Name: req.Name,
|
||||
Tags: tool.StringSliceToString(req.Tags),
|
||||
Rules: strings.Join(rs, "\n"),
|
||||
Enable: req.Enable,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user