feat(server): implement server management handlers and database schema
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var _ Model = (*customServerModel)(nil)
|
||||
|
||||
//goland:noinspection GoNameStartsWithPackageName
|
||||
type (
|
||||
Model interface {
|
||||
serverModel
|
||||
NodeModel
|
||||
customServerLogicModel
|
||||
}
|
||||
serverModel interface {
|
||||
InsertServer(ctx context.Context, data *Server, tx ...*gorm.DB) error
|
||||
FindOneServer(ctx context.Context, id int64) (*Server, error)
|
||||
UpdateServer(ctx context.Context, data *Server, tx ...*gorm.DB) error
|
||||
DeleteServer(ctx context.Context, id int64, tx ...*gorm.DB) error
|
||||
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
|
||||
}
|
||||
|
||||
NodeModel interface {
|
||||
InsertNode(ctx context.Context, data *Node, tx ...*gorm.DB) error
|
||||
FindOneNode(ctx context.Context, id int64) (*Node, error)
|
||||
UpdateNode(ctx context.Context, data *Node, tx ...*gorm.DB) error
|
||||
DeleteNode(ctx context.Context, id int64, tx ...*gorm.DB) error
|
||||
}
|
||||
|
||||
customServerModel struct {
|
||||
*defaultServerModel
|
||||
}
|
||||
defaultServerModel struct {
|
||||
*gorm.DB
|
||||
}
|
||||
)
|
||||
|
||||
func newServerModel(db *gorm.DB) *defaultServerModel {
|
||||
return &defaultServerModel{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// NewModel returns a model for the database table.
|
||||
func NewModel(conn *gorm.DB) Model {
|
||||
return &customServerModel{
|
||||
defaultServerModel: newServerModel(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) InsertServer(ctx context.Context, data *Server, tx ...*gorm.DB) error {
|
||||
db := m.DB
|
||||
if len(tx) > 0 {
|
||||
db = tx[0]
|
||||
}
|
||||
return db.WithContext(ctx).Create(data).Error
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) FindOneServer(ctx context.Context, id int64) (*Server, error) {
|
||||
var server Server
|
||||
err := m.WithContext(ctx).Model(&Server{}).Where("id = ?", id).First(&server).Error
|
||||
return &server, err
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) UpdateServer(ctx context.Context, data *Server, tx ...*gorm.DB) error {
|
||||
_, err := m.FindOneServer(ctx, data.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db := m.DB
|
||||
if len(tx) > 0 {
|
||||
db = tx[0]
|
||||
}
|
||||
return db.WithContext(ctx).Save(data).Error
|
||||
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) DeleteServer(ctx context.Context, id int64, tx ...*gorm.DB) error {
|
||||
db := m.DB
|
||||
if len(tx) > 0 {
|
||||
db = tx[0]
|
||||
}
|
||||
return db.WithContext(ctx).Where("`id` = ?", id).Delete(&Server{}).Error
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) InsertNode(ctx context.Context, data *Node, tx ...*gorm.DB) error {
|
||||
db := m.DB
|
||||
if len(tx) > 0 {
|
||||
db = tx[0]
|
||||
}
|
||||
return db.WithContext(ctx).Create(data).Error
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) FindOneNode(ctx context.Context, id int64) (*Node, error) {
|
||||
var node Node
|
||||
err := m.WithContext(ctx).Model(&Node{}).Where("id = ?", id).First(&node).Error
|
||||
return &node, err
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) UpdateNode(ctx context.Context, data *Node, tx ...*gorm.DB) error {
|
||||
_, err := m.FindOneNode(ctx, data.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db := m.DB
|
||||
if len(tx) > 0 {
|
||||
db = tx[0]
|
||||
}
|
||||
return db.WithContext(ctx).Save(data).Error
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) DeleteNode(ctx context.Context, id int64, tx ...*gorm.DB) error {
|
||||
db := m.DB
|
||||
if len(tx) > 0 {
|
||||
db = tx[0]
|
||||
}
|
||||
return db.WithContext(ctx).Where("`id` = ?", id).Delete(&Node{}).Error
|
||||
}
|
||||
|
||||
func (m *defaultServerModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error {
|
||||
return m.WithContext(ctx).Transaction(fn)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package node
|
||||
|
||||
import "context"
|
||||
|
||||
type customServerLogicModel interface {
|
||||
FilterServerList(ctx context.Context, params *FilterParams) (int64, []*Server, error)
|
||||
FilterNodeList(ctx context.Context, params *FilterParams) (int64, []*Node, error)
|
||||
}
|
||||
|
||||
// FilterParams Filter Server Params
|
||||
type FilterParams struct {
|
||||
Page int
|
||||
Size int
|
||||
Search string
|
||||
}
|
||||
|
||||
// FilterServerList Filter Server List
|
||||
func (m *customServerModel) FilterServerList(ctx context.Context, params *FilterParams) (int64, []*Server, error) {
|
||||
var servers []*Server
|
||||
var total int64
|
||||
query := m.WithContext(ctx).Model(&Server{})
|
||||
if params == nil {
|
||||
params = &FilterParams{
|
||||
Page: 1,
|
||||
Size: 10,
|
||||
}
|
||||
}
|
||||
if params.Search != "" {
|
||||
s := "%" + params.Search + "%"
|
||||
query = query.Where("`name` LIKE ? OR `address` LIKE ?", s, s)
|
||||
}
|
||||
err := query.Count(&total).Limit(params.Size).Offset((params.Page - 1) * params.Size).Find(&servers).Error
|
||||
return total, servers, err
|
||||
}
|
||||
|
||||
// FilterNodeList Filter Node List
|
||||
func (m *customServerModel) FilterNodeList(ctx context.Context, params *FilterParams) (int64, []*Node, error) {
|
||||
var nodes []*Node
|
||||
var total int64
|
||||
query := m.WithContext(ctx).Model(&Node{})
|
||||
if params == nil {
|
||||
params = &FilterParams{
|
||||
Page: 1,
|
||||
Size: 10,
|
||||
}
|
||||
}
|
||||
if params.Search != "" {
|
||||
s := "%" + params.Search + "%"
|
||||
query = query.Where("`name` LIKE ? OR `address` LIKE ? OR `tags` LIKE ? OR `port` LIKE ? ", s, s, s, s)
|
||||
}
|
||||
err := query.Count(&total).Limit(params.Size).Offset((params.Page - 1) * params.Size).Find(&nodes).Error
|
||||
return total, nodes, err
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package node
|
||||
|
||||
import "time"
|
||||
|
||||
type Node struct {
|
||||
Id int64 `gorm:"primary_key"`
|
||||
Name string `gorm:"type:varchar(100);not null;default:'';comment:Node Name"`
|
||||
Tags string `gorm:"type:varchar(255);not null;default:'';comment:Tags"`
|
||||
Port uint16 `gorm:"not null;default:0;comment:Connect Port"`
|
||||
Address string `gorm:"type:varchar(255);not null;default:'';comment:Connect Address"`
|
||||
ServerId int64 `gorm:"not null;default:0;comment:Server ID"`
|
||||
Protocol string `gorm:"type:varchar(100);not null;default:'';comment:Protocol"`
|
||||
Enabled *bool `gorm:"type:boolean;not null;default:true;comment:Enabled"`
|
||||
CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"`
|
||||
UpdatedAt time.Time `gorm:"comment:Update Time"`
|
||||
}
|
||||
|
||||
func (Node) TableName() string {
|
||||
return "nodes"
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Id int64 `gorm:"primary_key"`
|
||||
Name string `gorm:"type:varchar(100);not null;default:'';comment:Server Name"`
|
||||
Country string `gorm:"type:varchar(128);not null;default:'';comment:Country"`
|
||||
City string `gorm:"type:varchar(128);not null;default:'';comment:City"`
|
||||
Ratio float32 `gorm:"type:DECIMAL(4,2);not null;default:0;comment:Traffic Ratio"`
|
||||
Address string `gorm:"type:varchar(100);not null;default:'';comment:Server Address"`
|
||||
Sort int `gorm:"type:int;not null;default:0;comment:Sort"`
|
||||
Protocols string `gorm:"type:text;default:null;comment:Protocol"`
|
||||
LastReportedAt time.Time `gorm:"comment:Last Reported Time"`
|
||||
CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"`
|
||||
UpdatedAt time.Time `gorm:"comment:Update Time"`
|
||||
}
|
||||
|
||||
func (*Server) TableName() string {
|
||||
return "servers"
|
||||
}
|
||||
|
||||
// MarshalProtocols Marshal server protocols to json
|
||||
func (m *Server) MarshalProtocols(list []Protocol) error {
|
||||
var validate = make(map[string]bool)
|
||||
for _, protocol := range list {
|
||||
if protocol.Type == "" {
|
||||
return errors.New("protocol type is required")
|
||||
}
|
||||
if _, exists := validate[protocol.Type]; exists {
|
||||
return errors.New("duplicate protocol type: " + protocol.Type)
|
||||
}
|
||||
validate[protocol.Type] = true
|
||||
}
|
||||
data, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Protocols = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalProtocols Unmarshal server protocols from json
|
||||
func (m *Server) UnmarshalProtocols() ([]Protocol, error) {
|
||||
var list []Protocol
|
||||
if m.Protocols == "" {
|
||||
return list, nil
|
||||
}
|
||||
err := json.Unmarshal([]byte(m.Protocols), &list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
type Protocol struct {
|
||||
Type string `json:"type"`
|
||||
Port uint16 `json:"port"`
|
||||
Security string `json:"security,omitempty"`
|
||||
SNI string `json:"sni,omitempty"`
|
||||
AllowInsecure bool `json:"allow_insecure,omitempty"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
RealityServerAddr string `json:"reality_server_addr,omitempty"`
|
||||
RealityServerPort int `json:"reality_server_port,omitempty"`
|
||||
RealityPrivateKey string `json:"reality_private_key,omitempty"`
|
||||
RealityPublicKey string `json:"reality_public_key,omitempty"`
|
||||
RealityShortId string `json:"reality_short_id,omitempty"`
|
||||
Transport string `json:"transport,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
ServiceName string `json:"service_name,omitempty"`
|
||||
Cipher string `json:"cipher,omitempty"`
|
||||
ServerKey string `json:"server_key,omitempty"`
|
||||
Flow string `json:"flow,omitempty"`
|
||||
HopPorts string `json:"hop_ports,omitempty"`
|
||||
HopInterval int `json:"hop_interval,omitempty"`
|
||||
ObfsPassword string `json:"obfs_password,omitempty"`
|
||||
DisableSNI bool `json:"disable_sni,omitempty"`
|
||||
ReduceRtt bool `json:"reduce_rtt,omitempty"`
|
||||
UDPRelayMode string `json:"udp_relay_mode,omitempty"`
|
||||
CongestionController string `json:"congestion_controller,omitempty"`
|
||||
}
|
||||
|
||||
// Marshal protocol to json
|
||||
func (m *Protocol) Marshal() ([]byte, error) {
|
||||
type Alias Protocol
|
||||
return json.Marshal(&struct {
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(m),
|
||||
})
|
||||
}
|
||||
|
||||
// Unmarshal json to protocol
|
||||
func (m *Protocol) Unmarshal(data []byte) error {
|
||||
type Alias Protocol
|
||||
aux := &struct {
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(m),
|
||||
}
|
||||
return json.Unmarshal(data, &aux)
|
||||
}
|
||||
Reference in New Issue
Block a user