Skip to content

Commit d2990ed

Browse files
authored
feat: Integrate into New API (#312)
* feat: Integrate into New API * fix: Code style
1 parent 65a932f commit d2990ed

File tree

3 files changed

+159
-3
lines changed

3 files changed

+159
-3
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package handler
2+
3+
import (
4+
"strings"
5+
6+
app_errors "gpt-load/internal/errors"
7+
"gpt-load/internal/models"
8+
"gpt-load/internal/response"
9+
10+
"github.com/gin-gonic/gin"
11+
"github.com/sirupsen/logrus"
12+
)
13+
14+
// IntegrationGroupInfo represents group info for integration response
15+
type IntegrationGroupInfo struct {
16+
Name string `json:"name"`
17+
DisplayName string `json:"display_name"`
18+
ChannelType string `json:"channel_type"`
19+
Path string `json:"path"`
20+
}
21+
22+
// IntegrationInfoResponse represents the integration info response
23+
type IntegrationInfoResponse struct {
24+
Code int `json:"code"`
25+
Message string `json:"message"`
26+
Data []IntegrationGroupInfo `json:"data"`
27+
}
28+
29+
// GetIntegrationInfo handles the integration info request
30+
func (s *Server) GetIntegrationInfo(c *gin.Context) {
31+
key := c.Query("key")
32+
if key == "" {
33+
response.Error(c, app_errors.NewAPIError(app_errors.ErrValidation, "Proxy key is required"))
34+
return
35+
}
36+
37+
path := c.Request.URL.Path
38+
isGroupSpecific := strings.HasPrefix(path, "/proxy/")
39+
40+
var groupsToCheck []*models.Group
41+
42+
if isGroupSpecific {
43+
parts := strings.Split(strings.TrimPrefix(path, "/proxy/"), "/")
44+
if len(parts) == 0 || parts[0] == "" {
45+
response.Error(c, app_errors.NewAPIError(app_errors.ErrValidation, "Invalid group path"))
46+
return
47+
}
48+
49+
groupName := parts[0]
50+
51+
// Get group from GroupManager cache (already has ProxyKeysMap parsed)
52+
group, err := s.GroupManager.GetGroupByName(groupName)
53+
if err != nil {
54+
response.Error(c, app_errors.NewAPIError(app_errors.ErrResourceNotFound, "Group not found"))
55+
return
56+
}
57+
58+
groupsToCheck = []*models.Group{group}
59+
} else {
60+
// Get all groups
61+
groups, err := s.GroupService.ListGroups(c.Request.Context())
62+
if err != nil {
63+
response.Error(c, app_errors.NewAPIError(app_errors.ErrInternalServer, "Internal server error"))
64+
return
65+
}
66+
67+
// Convert to pointer slice and load from cache to get ProxyKeysMap
68+
for i := range groups {
69+
cachedGroup, err := s.GroupManager.GetGroupByName(groups[i].Name)
70+
if err != nil {
71+
logrus.Warnf("Failed to get group %s from cache: %v", groups[i].Name, err)
72+
continue
73+
}
74+
groupsToCheck = append(groupsToCheck, cachedGroup)
75+
}
76+
}
77+
78+
var result []IntegrationGroupInfo
79+
for _, group := range groupsToCheck {
80+
if hasProxyKeyPermission(group, key) {
81+
channelType := getEffectiveChannelType(group)
82+
path := buildPath(isGroupSpecific, group.Name, channelType, group.ValidationEndpoint)
83+
84+
result = append(result, IntegrationGroupInfo{
85+
Name: group.Name,
86+
DisplayName: group.DisplayName,
87+
ChannelType: channelType,
88+
Path: path,
89+
})
90+
}
91+
}
92+
93+
if len(result) == 0 {
94+
response.Error(c, app_errors.NewAPIError(app_errors.ErrValidation, "Invalid or unauthorized proxy key"))
95+
return
96+
}
97+
98+
response.Success(c, result)
99+
}
100+
101+
// getEffectiveChannelType returns the effective channel type
102+
func getEffectiveChannelType(group *models.Group) string {
103+
if group.ChannelType != "openai" {
104+
return group.ChannelType
105+
}
106+
107+
if group.ValidationEndpoint == "" {
108+
return "openai"
109+
}
110+
111+
defaultEndpoint := "/v1/chat/completions"
112+
113+
if group.ValidationEndpoint == defaultEndpoint {
114+
return "openai"
115+
}
116+
117+
return "custom"
118+
}
119+
120+
// hasProxyKeyPermission checks if the key has permission to access the group
121+
func hasProxyKeyPermission(group *models.Group, key string) bool {
122+
_, exists1 := group.ProxyKeysMap[key]
123+
_, exists2 := group.EffectiveConfig.ProxyKeysMap[key]
124+
return exists1 || exists2
125+
}
126+
127+
// buildPath returns the appropriate path based on request type and channel type
128+
func buildPath(isGroupSpecific bool, groupName string, channelType string, validationEndpoint string) string {
129+
if channelType == "custom" {
130+
if isGroupSpecific {
131+
return validationEndpoint
132+
}
133+
return "/proxy/" + groupName + validationEndpoint
134+
}
135+
136+
if isGroupSpecific {
137+
return ""
138+
}
139+
return "/proxy/" + groupName
140+
}

internal/middleware/middleware.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ func ProxyAuth(gm *services.GroupManager) gin.HandlerFunc {
171171
}
172172
}
173173

174+
// ProxyRouteDispatcher dispatches special routes before proxy authentication
175+
func ProxyRouteDispatcher(serverHandler interface{ GetIntegrationInfo(*gin.Context) }) gin.HandlerFunc {
176+
return func(c *gin.Context) {
177+
if c.Param("path") == "/api/integration/info" {
178+
serverHandler.GetIntegrationInfo(c)
179+
c.Abort()
180+
return
181+
}
182+
183+
c.Next()
184+
}
185+
}
186+
174187
// Recovery creates a recovery middleware with custom error handling
175188
func Recovery() gin.HandlerFunc {
176189
return gin.CustomRecovery(func(c *gin.Context, recovered any) {

internal/router/router.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func NewRouter(
6666
// 注册路由
6767
registerSystemRoutes(router, serverHandler)
6868
registerAPIRoutes(router, serverHandler, configManager)
69-
registerProxyRoutes(router, proxyServer, groupManager)
69+
registerProxyRoutes(router, proxyServer, groupManager, serverHandler)
7070
registerFrontendRoutes(router, buildFS, indexPage)
7171

7272
return router
@@ -100,6 +100,7 @@ func registerAPIRoutes(
100100
// registerPublicAPIRoutes 公开API路由
101101
func registerPublicAPIRoutes(api *gin.RouterGroup, serverHandler *handler.Server) {
102102
api.POST("/auth/login", serverHandler.Login)
103+
api.GET("/integration/info", serverHandler.GetIntegrationInfo)
103104
}
104105

105106
// registerProtectedAPIRoutes 认证API路由
@@ -172,12 +173,14 @@ func registerProxyRoutes(
172173
router *gin.Engine,
173174
proxyServer *proxy.ProxyServer,
174175
groupManager *services.GroupManager,
176+
serverHandler *handler.Server,
175177
) {
176-
proxyGroup := router.Group("/proxy")
178+
proxyGroup := router.Group("/proxy/:group_name")
177179

180+
proxyGroup.Use(middleware.ProxyRouteDispatcher(serverHandler))
178181
proxyGroup.Use(middleware.ProxyAuth(groupManager))
179182

180-
proxyGroup.Any("/:group_name/*path", proxyServer.HandleProxy)
183+
proxyGroup.Any("/*path", proxyServer.HandleProxy)
181184
}
182185

183186
// registerFrontendRoutes 注册前端路由

0 commit comments

Comments
 (0)