refactor: update WebSocket API routes for improved clarity and structure

This commit is contained in:
mlogclub
2026-04-25 10:50:23 +08:00
parent 270bb83fdb
commit 2c884c13cf
5 changed files with 46 additions and 60 deletions
+7 -2
View File
@@ -13,6 +13,7 @@ import (
"cs-agent/internal/controllers/third" "cs-agent/internal/controllers/third"
"cs-agent/internal/middleware" "cs-agent/internal/middleware"
"cs-agent/internal/pkg/config" "cs-agent/internal/pkg/config"
"cs-agent/internal/services"
"github.com/kataras/iris/v12" "github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/cors" "github.com/kataras/iris/v12/middleware/cors"
@@ -91,13 +92,17 @@ func addRouter(app *iris.Application) {
mcpHandler.ServeHTTP(w, r) mcpHandler.ServeHTTP(w, r)
}))) })))
app.Get("/api/dashboard/ws", middleware.AuthMiddleware, middleware.DashboardWsMiddleware) mvc.Configure(app.Party("/api/ws"), func(m *mvc.Application) {
app.Get("/api/open/im/ws", middleware.OpenImWsMiddleware) m.Router.Get("/dashboard", middleware.AuthMiddleware, services.WsService.HandleDashboardWS)
m.Router.Get("/open", services.WsService.HandleOpenWS)
})
mvc.Configure(app.Party("/api"), func(m *mvc.Application) { mvc.Configure(app.Party("/api"), func(m *mvc.Application) {
m.Party("/auth").Handle(new(api.AuthController)) m.Party("/auth").Handle(new(api.AuthController))
m.Party("/channel").Handle(new(api.ChannelController)) m.Party("/channel").Handle(new(api.ChannelController))
// m.Router.Get("/ws", middleware.OpenImWsMiddleware)
m.Party("/conversation", middleware.ExternalInfoMiddleware).Handle(new(api.ConversationController)) m.Party("/conversation", middleware.ExternalInfoMiddleware).Handle(new(api.ConversationController))
m.Party("/message", middleware.ExternalInfoMiddleware).Handle(new(api.MessageController)) m.Party("/message", middleware.ExternalInfoMiddleware).Handle(new(api.MessageController))
}) })
-50
View File
@@ -1,50 +0,0 @@
package middleware
import (
"cs-agent/internal/pkg/openidentity"
"cs-agent/internal/services"
"log/slog"
"github.com/kataras/iris/v12"
"github.com/mlogclub/simple/web"
)
func DashboardWsMiddleware(ctx iris.Context) {
principal := services.AuthService.GetAuthPrincipal(ctx)
if principal == nil {
if _, err := services.AuthService.Authenticate(ctx); err != nil {
_ = ctx.StopWithJSON(iris.StatusUnauthorized, web.JsonError(err))
return
}
principal = services.AuthService.GetAuthPrincipal(ctx)
}
if err := services.WsService.UpgradeAdminConnection(ctx, principal); err != nil {
slog.Error("upgrade admin websocket failed", "error", err, "path", ctx.Path())
ctx.StopExecution()
return
}
}
func OpenImWsMiddleware(ctx iris.Context) {
channel := services.ChannelService.GetEnabledChannel(ctx)
if channel == nil {
_ = ctx.StopWithJSON(iris.StatusBadRequest, web.JsonErrorMsg("接入渠道不存在或已停用"))
return
}
principal := services.AuthService.GetAuthPrincipal(ctx)
var external *openidentity.ExternalInfo
if principal == nil {
ext, err := openidentity.GetExternalInfo(ctx)
if err != nil {
_ = ctx.StopWithJSON(iris.StatusUnauthorized, web.JsonError(err))
return
}
external = ext
}
if err := services.WsService.UpgradeUserConnection(ctx, principal, external); err != nil {
slog.Error("upgrade open im websocket failed", "error", err, "path", ctx.Path(), "channelId", channel.ChannelID, "channel_id", channel.ID)
ctx.StopExecution()
return
}
}
+37 -6
View File
@@ -4,6 +4,7 @@ import (
"cs-agent/internal/models" "cs-agent/internal/models"
"cs-agent/internal/pkg/dto" "cs-agent/internal/pkg/dto"
"cs-agent/internal/pkg/enums" "cs-agent/internal/pkg/enums"
"cs-agent/internal/pkg/errorsx"
"cs-agent/internal/pkg/openidentity" "cs-agent/internal/pkg/openidentity"
"cs-agent/internal/pkg/utils" "cs-agent/internal/pkg/utils"
"encoding/json" "encoding/json"
@@ -17,6 +18,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/kataras/iris/v12" "github.com/kataras/iris/v12"
"github.com/mlogclub/simple/web"
) )
var WsService = newWsService() var WsService = newWsService()
@@ -38,14 +40,43 @@ func newWsService() *wsService {
} }
} }
// UpgradeUserConnection 开放 IM 用户侧 WebSocket。 func (s *wsService) HandleDashboardWS(ctx iris.Context) {
// principal 非空时表示站内用户;否则应传入 external(IM 访客)。二者勿混用为同一业务身份。 principal := AuthService.GetAuthPrincipal(ctx)
func (s *wsService) UpgradeUserConnection(ctx iris.Context, principal *dto.AuthPrincipal, external *openidentity.ExternalInfo) error { if principal == nil {
return s.upgradeConnection(ctx, principal, external, realtimeRoleUser) _ = ctx.StopWithJSON(iris.StatusUnauthorized, web.JsonError(errorsx.Unauthorized("未登录或登录已过期")))
return
}
if err := s.upgradeConnection(ctx, principal, nil, realtimeRoleAdmin); err != nil {
slog.Error("upgrade admin websocket failed", "error", err, "path", ctx.Path())
ctx.StopExecution()
return
}
} }
func (s *wsService) UpgradeAdminConnection(ctx iris.Context, principal *dto.AuthPrincipal) error { func (s *wsService) HandleOpenWS(ctx iris.Context) {
return s.upgradeConnection(ctx, principal, nil, realtimeRoleAdmin) channel := ChannelService.GetEnabledChannel(ctx)
if channel == nil {
_ = ctx.StopWithJSON(iris.StatusBadRequest, web.JsonErrorMsg("接入渠道不存在或已停用"))
return
}
var (
principal = AuthService.GetAuthPrincipal(ctx)
external *openidentity.ExternalInfo
)
if principal == nil {
ext, err := openidentity.GetExternalInfo(ctx)
if err != nil {
_ = ctx.StopWithJSON(iris.StatusUnauthorized, web.JsonError(err))
return
}
external = ext
}
if err := s.upgradeConnection(ctx, principal, external, realtimeRoleUser); err != nil {
slog.Error("upgrade open im websocket failed", "error", err, "path", ctx.Path(), "channelId", channel.ChannelID, "channel_id", channel.ID)
ctx.StopExecution()
return
}
} }
func (s *wsService) upgradeConnection(ctx iris.Context, principal *dto.AuthPrincipal, external *openidentity.ExternalInfo, role string) error { func (s *wsService) upgradeConnection(ctx iris.Context, principal *dto.AuthPrincipal, external *openidentity.ExternalInfo, role string) error {
+1 -1
View File
@@ -542,7 +542,7 @@ export function createAdminWebSocketUrl() {
const params = new URLSearchParams({ const params = new URLSearchParams({
accessToken: session.accessToken, accessToken: session.accessToken,
}) })
return `${baseUrl}/api/dashboard/ws?${params.toString()}` return `${baseUrl}/api/ws/dashboard?${params.toString()}`
} }
export function fetchChannels( export function fetchChannels(
+1 -1
View File
@@ -32,6 +32,6 @@ export function createImRealtimeConnection() {
? `&externalName=${encodeURIComponent(externalName)}` ? `&externalName=${encodeURIComponent(externalName)}`
: "" : ""
return new WebSocket( return new WebSocket(
`${baseUrl}/api/open/im/ws?externalId=${externalId}&externalSource=${externalSource}&channelId=${channelId}${nameQuery}` `${baseUrl}/api/ws/open?externalId=${externalId}&externalSource=${externalSource}&channelId=${channelId}${nameQuery}`
) )
} }