package handlers import ( "errors" "fmt" "log/slog" q "platform/web/queries" "platform/web/services" "strconv" "strings" "github.com/gofiber/fiber/v2" ) // region CreateChannel type CreateChannelReq struct { ResourceId int32 `json:"resource_id" validate:"required"` Protocol services.ChannelProtocol `json:"protocol" validate:"required,oneof=socks5 http https"` AuthType services.ChannelAuthType `json:"auth_type" validate:"required,oneof=0 1"` Count int `json:"count" validate:"required"` Prov string `json:"prov" validate:"required"` City string `json:"city" validate:"required"` Isp string `json:"isp" validate:"required"` ResultType CreateChannelResultType `json:"result_type" validate:"required,oneof=json text"` ResultBreaker []rune `json:"result_breaker" validate:""` ResultSeparator []rune `json:"result_separator" validate:""` } func CreateChannel(c *fiber.Ctx) error { req := new(CreateChannelReq) if err := c.BodyParser(req); err != nil { return err } if req.ResultType == "" { req.ResultType = CreateChannelResultTypeText } if req.ResultBreaker == nil { req.ResultBreaker = []rune("\r\n") } if req.ResultSeparator == nil { req.ResultSeparator = []rune("|") } // 建立连接通道 auth, ok := c.Locals("auth").(*services.AuthContext) if !ok { return errors.New("user not found") } result, err := services.Channel.CreateChannel( c.Context(), auth, req.ResourceId, req.Protocol, req.AuthType, req.Count, services.NodeFilterConfig{ Isp: req.Isp, Prov: req.Prov, City: req.City, }, ) if err != nil { return err } var separator = string(req.ResultSeparator) switch req.ResultType { case CreateChannelResultTypeJson: return c.JSON(fiber.Map{ "code": 1, "data": result, }) default: var breaker = string(req.ResultBreaker) var str = strings.Builder{} for _, info := range result { str.WriteString(info.Host) str.WriteString(separator) str.WriteString(strconv.Itoa(info.Port)) if info.Username != nil { str.WriteString(separator) str.WriteString(*info.Username) } if info.Password != nil { str.WriteString(separator) str.WriteString(*info.Password) } str.WriteString(breaker) } return c.SendString(str.String()) } } type CreateChannelResultType string const ( CreateChannelResultTypeJson CreateChannelResultType = "json" CreateChannelResultTypeText CreateChannelResultType = "text" ) // endregion // region RemoveChannels type RemoveChannelsReq struct { ByIds []int32 `json:"by_ids" validate:"required"` } func RemoveChannels(c *fiber.Ctx) error { req := new(RemoveChannelsReq) if err := c.BodyParser(req); err != nil { return err } // 获取用户信息 auth, ok := c.Locals("auth").(*services.AuthContext) if !ok { return errors.New("user not found") } // 删除通道 err := services.Channel.RemoveChannels(c.Context(), auth, req.ByIds...) if err != nil { return err } return c.SendStatus(fiber.StatusOK) } // endregion // region CreateChannel(GET) type CreateChannelGetReq struct { ResourceId int32 `query:"i" validate:"required"` Protocol services.ChannelProtocol `query:"x" validate:"required,oneof=socks5 http https"` AuthType services.ChannelAuthType `query:"t" validate:"required,oneof=0 1"` Count int `query:"n" validate:"required"` Prov string `query:"a" validate:"required"` City string `query:"b" validate:"required"` Isp string `query:"s" validate:"required"` ResultType CreateChannelResultType `query:"rt" validate:"required,oneof=json text"` ResultBreaker []rune `query:"rb"` ResultSeparator []rune `query:"rs"` } func CreateChannelGet(c *fiber.Ctx) error { req := new(CreateChannelGetReq) if err := c.QueryParser(req); err != nil { return err } slog.Info("CreateChannelGet", "req", *req) // 验证用户身份 resource, err := q.Resource.Debug().Where(q.Resource.ID.Eq(req.ResourceId)).Take() if err != nil { return err } whitelists, err := q.Whitelist.Debug().Where(q.Whitelist.UserID.Eq(resource.UserID)).Find() if err != nil { return err } if len(whitelists) == 0 { return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("forbidden %s", c.IP())) } var invalid bool for _, whitelist := range whitelists { invalid = whitelist.Host == c.IP() if invalid { break } } if !invalid { return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("forbidden %s", c.IP())) } user, err := q.User.Debug().Where(q.User.ID.Eq(resource.UserID)).Take() if err != nil { return err } auth := &services.AuthContext{ Payload: services.Payload{ Id: user.ID, Type: services.PayloadUser, Name: user.Name, Avatar: user.Avatar, }, } if req.ResultType == "" { req.ResultType = CreateChannelResultTypeText } if req.ResultBreaker == nil { req.ResultBreaker = []rune("\r\n") } if req.ResultSeparator == nil { req.ResultSeparator = []rune("|") } // 建立连接通道 result, err := services.Channel.CreateChannel( c.Context(), auth, req.ResourceId, req.Protocol, req.AuthType, req.Count, services.NodeFilterConfig{ Isp: req.Isp, Prov: req.Prov, City: req.City, }, ) if err != nil { return err } var separator = string(req.ResultSeparator) switch req.ResultType { case CreateChannelResultTypeJson: return c.JSON(fiber.Map{ "code": 1, "data": result, }) default: var breaker = string(req.ResultBreaker) var str = strings.Builder{} for _, info := range result { str.WriteString(info.Host) str.WriteString(separator) str.WriteString(strconv.Itoa(info.Port)) if info.Username != nil { str.WriteString(separator) str.WriteString(*info.Username) } if info.Password != nil { str.WriteString(separator) str.WriteString(*info.Password) } str.WriteString(breaker) } return c.SendString(str.String()) } } // endregion