mirror of
https://gitee.com/WuKongDev/WuKongIM.git
synced 2025-12-06 14:59:08 +08:00
feat: support openapi docs
This commit is contained in:
127
docs/README.md
Normal file
127
docs/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# WuKongIM API Documentation
|
||||
|
||||
This directory contains the API documentation for WuKongIM.
|
||||
|
||||
## Files
|
||||
|
||||
- `openapi.json` - OpenAPI 3.0 specification for the WuKongIM REST API
|
||||
- `README.md` - This documentation file
|
||||
|
||||
## Accessing the API Documentation
|
||||
|
||||
### Swagger UI Interface
|
||||
|
||||
When the WuKongIM server is running, you can access the interactive API documentation at:
|
||||
|
||||
```
|
||||
http://localhost:5001/docs
|
||||
```
|
||||
|
||||
This provides a user-friendly Swagger UI interface where you can:
|
||||
|
||||
- Browse all API endpoints
|
||||
- View detailed request/response schemas
|
||||
- Test API endpoints directly from the browser
|
||||
- Download the OpenAPI specification
|
||||
|
||||
### Direct OpenAPI Specification
|
||||
|
||||
You can also access the raw OpenAPI specification at:
|
||||
|
||||
```
|
||||
http://localhost:5001/docs/openapi.json
|
||||
```
|
||||
|
||||
## API Overview
|
||||
|
||||
The WuKongIM API provides the following functionality:
|
||||
|
||||
### System & Health
|
||||
- Health checks and system status
|
||||
- Migration status monitoring
|
||||
|
||||
### User Management
|
||||
- User authentication and token management
|
||||
- Online status tracking
|
||||
- System user management
|
||||
|
||||
### Connection Management
|
||||
- Connection removal and management
|
||||
- Connection monitoring and statistics
|
||||
|
||||
### Channel Management
|
||||
- Channel creation, update, and deletion
|
||||
- Subscriber management
|
||||
- Blacklist and whitelist management
|
||||
|
||||
### Message Management
|
||||
- Message sending (single and batch)
|
||||
- Message searching and retrieval
|
||||
- Stream message handling
|
||||
|
||||
### Conversation Management
|
||||
- Conversation synchronization
|
||||
- Unread message management
|
||||
|
||||
### Monitoring & Metrics
|
||||
- Connection statistics (`/connz`)
|
||||
- System variables and metrics (`/varz`)
|
||||
|
||||
### Administrative
|
||||
- Manager authentication
|
||||
- System configuration
|
||||
|
||||
## Using the API
|
||||
|
||||
### Authentication
|
||||
|
||||
Most API endpoints require proper authentication. Refer to the specific endpoint documentation in the Swagger UI for authentication requirements.
|
||||
|
||||
### Base URL
|
||||
|
||||
The default base URL for the API is:
|
||||
```
|
||||
http://localhost:5001
|
||||
```
|
||||
|
||||
### Content Type
|
||||
|
||||
Most endpoints expect and return JSON data:
|
||||
```
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
The API uses standard HTTP status codes and returns error information in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Error description"
|
||||
}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Updating the Documentation
|
||||
|
||||
The OpenAPI specification is automatically generated based on the API route definitions in the codebase. To update the documentation:
|
||||
|
||||
1. Modify the API endpoints in the `internal/api/` directory
|
||||
2. Update the `docs/openapi.json` file accordingly
|
||||
3. Restart the WuKongIM server to see the changes
|
||||
|
||||
### Local Development
|
||||
|
||||
For local development, ensure the `docs/openapi.json` file is present in the project root or docs directory. The documentation endpoint will automatically locate and serve the specification file.
|
||||
|
||||
## Support
|
||||
|
||||
For questions about the API or this documentation, please refer to:
|
||||
|
||||
- [WuKongIM GitHub Repository](https://github.com/WuKongIM/WuKongIM)
|
||||
- [WuKongIM Documentation](https://githubim.com)
|
||||
|
||||
## Version
|
||||
|
||||
This documentation is for WuKongIM API version 2.0.0.
|
||||
1970
docs/openapi.json
Normal file
1970
docs/openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
253
internal/api/docs.go
Normal file
253
internal/api/docs.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/WuKongIM/WuKongIM/internal/options"
|
||||
"github.com/WuKongIM/WuKongIM/pkg/wkhttp"
|
||||
"github.com/WuKongIM/WuKongIM/pkg/wklog"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type docs struct {
|
||||
s *Server
|
||||
wklog.Log
|
||||
}
|
||||
|
||||
func newDocs(s *Server) *docs {
|
||||
return &docs{
|
||||
s: s,
|
||||
Log: wklog.NewWKLog("docs"),
|
||||
}
|
||||
}
|
||||
|
||||
// route 配置文档路由
|
||||
func (d *docs) route(r *wkhttp.WKHttp) {
|
||||
// 在生产模式下禁用文档端点以提高安全性和性能
|
||||
if options.G.Mode == options.ReleaseMode {
|
||||
d.Info("Documentation endpoints disabled in release mode for security")
|
||||
r.GET("/docs", d.disabledInRelease) // 显示禁用消息
|
||||
r.GET("/docs/", d.disabledInRelease) // 显示禁用消息
|
||||
r.GET("/docs/openapi.json", d.disabledInRelease) // 显示禁用消息
|
||||
r.GET("/docs/health", d.releaseHealthCheck) // 简化的健康检查
|
||||
return
|
||||
}
|
||||
|
||||
// 开发模式下启用完整的文档功能
|
||||
d.Info("Documentation endpoints enabled in development mode")
|
||||
r.GET("/docs", d.swaggerUI) // Swagger UI 主页面
|
||||
r.GET("/docs/", d.redirectToDocs) // 重定向 /docs/ 到 /docs
|
||||
r.GET("/docs/openapi.json", d.openAPI) // OpenAPI 规范文件
|
||||
r.GET("/docs/health", d.docsHealth) // 文档服务健康检查
|
||||
}
|
||||
|
||||
// redirectToDocs 重定向 /docs/ 到 /docs
|
||||
func (d *docs) redirectToDocs(c *wkhttp.Context) {
|
||||
c.Redirect(http.StatusMovedPermanently, "/docs")
|
||||
}
|
||||
|
||||
// docsHealth 文档服务健康检查
|
||||
func (d *docs) docsHealth(c *wkhttp.Context) {
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"status": "ok",
|
||||
"service": "docs",
|
||||
"description": "WuKongIM API Documentation Service",
|
||||
"endpoints": map[string]string{
|
||||
"swagger_ui": "/docs",
|
||||
"openapi_spec": "/docs/openapi.json",
|
||||
"health_check": "/docs/health",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// disabledInRelease 在生产模式下显示禁用消息
|
||||
func (d *docs) disabledInRelease(c *wkhttp.Context) {
|
||||
c.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"error": "Documentation endpoints are disabled in release mode",
|
||||
"message": "API documentation is only available in development mode for security reasons",
|
||||
"mode": string(options.G.Mode),
|
||||
"suggestion": "To access documentation, run the server in debug mode or check the static documentation files",
|
||||
})
|
||||
}
|
||||
|
||||
// releaseHealthCheck 生产模式下的简化健康检查
|
||||
func (d *docs) releaseHealthCheck(c *wkhttp.Context) {
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"status": "disabled",
|
||||
"service": "docs",
|
||||
"mode": string(options.G.Mode),
|
||||
"description": "Documentation service is disabled in release mode",
|
||||
})
|
||||
}
|
||||
|
||||
// swaggerUI 提供 Swagger UI 界面
|
||||
func (d *docs) swaggerUI(c *wkhttp.Context) {
|
||||
// 生成 Swagger UI HTML
|
||||
html := d.generateSwaggerHTML()
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.String(http.StatusOK, html)
|
||||
}
|
||||
|
||||
// openAPI 提供 OpenAPI 规范文件
|
||||
func (d *docs) openAPI(c *wkhttp.Context) {
|
||||
// 尝试多个可能的 OpenAPI 文件路径
|
||||
possiblePaths := []string{
|
||||
filepath.Join("docs", "openapi.json"), // 相对于工作目录
|
||||
filepath.Join(options.G.DataDir, "..", "docs", "openapi.json"), // 相对于数据目录
|
||||
"./docs/openapi.json", // 当前目录
|
||||
}
|
||||
|
||||
var data []byte
|
||||
var err error
|
||||
var usedPath string
|
||||
|
||||
for _, path := range possiblePaths {
|
||||
data, err = os.ReadFile(path)
|
||||
if err == nil {
|
||||
usedPath = path
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
d.Error("Failed to read openapi.json from any location", zap.Error(err), zap.Strings("tried_paths", possiblePaths))
|
||||
c.JSON(http.StatusInternalServerError, map[string]string{
|
||||
"error": "Failed to load API specification. Please ensure docs/openapi.json exists.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
d.Debug("Successfully loaded OpenAPI spec", zap.String("path", usedPath))
|
||||
|
||||
// 验证 JSON 格式
|
||||
var spec map[string]interface{}
|
||||
if err := json.Unmarshal(data, &spec); err != nil {
|
||||
d.Error("Invalid JSON in openapi.json", zap.Error(err), zap.String("path", usedPath))
|
||||
c.JSON(http.StatusInternalServerError, map[string]string{
|
||||
"error": "Invalid API specification format",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "application/json")
|
||||
c.Header("Access-Control-Allow-Origin", "*") // Allow CORS for Swagger UI
|
||||
c.Data(http.StatusOK, "application/json", data)
|
||||
}
|
||||
|
||||
// generateSwaggerHTML 生成 Swagger UI HTML 页面
|
||||
func (d *docs) generateSwaggerHTML() string {
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>WuKongIM API Documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui.css" />
|
||||
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist@4.15.5/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist@4.15.5/favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
body {
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
.swagger-ui .topbar {
|
||||
background-color: #1b1b1b;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.swagger-ui .topbar .download-url-wrapper {
|
||||
display: none;
|
||||
}
|
||||
.swagger-ui .topbar .link {
|
||||
content: "WuKongIM API Documentation";
|
||||
}
|
||||
.swagger-ui .info .title {
|
||||
color: #3b4151;
|
||||
}
|
||||
.custom-header {
|
||||
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.custom-header h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
font-weight: 300;
|
||||
}
|
||||
.custom-header p {
|
||||
margin: 10px 0 0 0;
|
||||
font-size: 1.1em;
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="custom-header">
|
||||
<h1>🐒 WuKongIM API</h1>
|
||||
<p>High-Performance Instant Messaging System - REST API Documentation</p>
|
||||
</div>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui-bundle.js" charset="UTF-8"></script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui-standalone-preset.js" charset="UTF-8"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: '/docs/openapi.json',
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
validatorUrl: null,
|
||||
docExpansion: "list",
|
||||
defaultModelsExpandDepth: 1,
|
||||
defaultModelExpandDepth: 1,
|
||||
displayRequestDuration: true,
|
||||
tryItOutEnabled: true,
|
||||
filter: true,
|
||||
showExtensions: true,
|
||||
showCommonExtensions: true,
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'],
|
||||
onComplete: function() {
|
||||
console.log('WuKongIM API Documentation loaded successfully');
|
||||
// Add custom styling after load
|
||||
const style = document.createElement('style');
|
||||
style.textContent = '.swagger-ui .topbar-wrapper .link:after { content: "WuKongIM API v2.0"; }';
|
||||
document.head.appendChild(style);
|
||||
},
|
||||
onFailure: function(data) {
|
||||
console.error('Failed to load API specification:', data);
|
||||
// Show user-friendly error message
|
||||
document.getElementById('swagger-ui').innerHTML =
|
||||
'<div style="padding: 40px; text-align: center; color: #721c24; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px; margin: 20px;">' +
|
||||
'<h3>⚠️ Failed to Load API Documentation</h3>' +
|
||||
'<p>Could not load the OpenAPI specification. Please ensure the server is running properly.</p>' +
|
||||
'<p><strong>Error:</strong> ' + (data.message || 'Unknown error') + '</p>' +
|
||||
'</div>';
|
||||
}
|
||||
});
|
||||
// End Swagger UI call region
|
||||
|
||||
window.ui = ui;
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
@@ -141,6 +141,10 @@ func (s *apiServer) setRoutes() {
|
||||
tag := newTag(s.s)
|
||||
tag.route(s.r)
|
||||
|
||||
// docs - API documentation with Swagger UI
|
||||
docs := newDocs(s.s)
|
||||
docs.route(s.r)
|
||||
|
||||
// 分布式api
|
||||
clusterServer, ok := service.Cluster.(*cluster.Server)
|
||||
if ok {
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/WuKongIM/WuKongIM/pkg/wknet"
|
||||
"github.com/WuKongIM/WuKongIM/pkg/wkserver/proto"
|
||||
"github.com/WuKongIM/WuKongIM/version"
|
||||
"github.com/fatih/color"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/judwhite/go-svc"
|
||||
"go.uber.org/zap"
|
||||
@@ -243,37 +244,15 @@ func (s *Server) Init(env svc.Environment) error {
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
// 显示增强的启动横幅
|
||||
s.printEnhancedBanner()
|
||||
|
||||
fmt.Println(`
|
||||
|
||||
__ __ ____ __. .___ _____
|
||||
/ \ / \__ __| |/ _|____ ____ ____ | | / \
|
||||
\ \/\/ / | \ < / _ \ / \ / ___\| |/ \ / \
|
||||
\ /| | / | ( <_> ) | \/ /_/ > / Y \
|
||||
\__/\ / |____/|____|__ \____/|___| /\___ /|___\____|__ /
|
||||
\/ \/ \//_____/ \/
|
||||
|
||||
`)
|
||||
s.Info("WuKongIM is Starting...")
|
||||
s.Info(fmt.Sprintf(" Using config file: %s", s.opts.ConfigFileUsed()))
|
||||
s.Info(fmt.Sprintf(" Mode: %s", s.opts.Mode))
|
||||
s.Info(fmt.Sprintf(" Version: %s", version.Version))
|
||||
s.Info(fmt.Sprintf(" Git: %s", fmt.Sprintf("%s-%s", version.CommitDate, version.Commit)))
|
||||
s.Info(fmt.Sprintf(" Go build: %s", runtime.Version()))
|
||||
s.Info(fmt.Sprintf(" DataDir: %s", s.opts.DataDir))
|
||||
startTime := time.Now()
|
||||
|
||||
s.Info(fmt.Sprintf("Listening for TCP client on %s", s.opts.Addr))
|
||||
s.Info(fmt.Sprintf("Listening for WS client on %s", s.opts.WSAddr))
|
||||
if s.opts.WSSAddr != "" {
|
||||
s.Info(fmt.Sprintf("Listening for WSS client on %s", s.opts.WSSAddr))
|
||||
}
|
||||
s.Info(fmt.Sprintf("Listening for Manager http api on %s", fmt.Sprintf("http://%s", s.opts.HTTPAddr)))
|
||||
|
||||
if s.opts.Manager.On {
|
||||
s.Info(fmt.Sprintf("Listening for Manager on %s", s.opts.Manager.Addr))
|
||||
}
|
||||
|
||||
defer s.Info("Server is ready")
|
||||
defer func() {
|
||||
duration := time.Since(startTime)
|
||||
s.Info(fmt.Sprintf("🚀 Server is ready! (startup time: %v)", duration))
|
||||
}()
|
||||
|
||||
var err error
|
||||
|
||||
@@ -432,6 +411,160 @@ func (s *Server) getSlotId(v string) uint32 {
|
||||
return service.Cluster.GetSlotId(v)
|
||||
}
|
||||
|
||||
// printEnhancedBanner 打印增强的启动横幅
|
||||
func (s *Server) printEnhancedBanner() {
|
||||
// 定义颜色
|
||||
cyan := color.New(color.FgCyan, color.Bold)
|
||||
yellow := color.New(color.FgYellow, color.Bold)
|
||||
green := color.New(color.FgGreen, color.Bold)
|
||||
blue := color.New(color.FgBlue, color.Bold)
|
||||
magenta := color.New(color.FgMagenta, color.Bold)
|
||||
white := color.New(color.FgWhite, color.Bold)
|
||||
|
||||
// 打印空行
|
||||
fmt.Println()
|
||||
|
||||
// 打印 ASCII 艺术字
|
||||
cyan.Println(" ╔══════════════════════════════════════════════════════════════════╗")
|
||||
cyan.Println(" ║ ║")
|
||||
cyan.Print(" ║ ")
|
||||
yellow.Print("🐒 ")
|
||||
magenta.Print("██╗ ██╗██╗ ██╗██╗ ██╗ ██████╗ ███╗ ██╗ ██████╗ ██╗███╗ ███╗")
|
||||
cyan.Println(" ║")
|
||||
cyan.Print(" ║ ")
|
||||
magenta.Print("██║ ██║██║ ██║██║ ██╔╝██╔═══██╗████╗ ██║██╔════╝ ██║████╗ ████║")
|
||||
cyan.Println(" ║")
|
||||
cyan.Print(" ║ ")
|
||||
magenta.Print("██║ █╗ ██║██║ ██║█████╔╝ ██║ ██║██╔██╗ ██║██║ ███╗██║██╔████╔██║")
|
||||
cyan.Println(" ║")
|
||||
cyan.Print(" ║ ")
|
||||
magenta.Print("██║███╗██║██║ ██║██╔═██╗ ██║ ██║██║╚██╗██║██║ ██║██║██║╚██╔╝██║")
|
||||
cyan.Println(" ║")
|
||||
cyan.Print(" ║ ")
|
||||
magenta.Print("╚███╔███╔╝╚██████╔╝██║ ██╗╚██████╔╝██║ ╚████║╚██████╔╝██║██║ ╚═╝ ██║")
|
||||
cyan.Println(" ║")
|
||||
cyan.Print(" ║ ")
|
||||
magenta.Print("╚══╝╚══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝╚═╝ ╚═╝")
|
||||
cyan.Println(" ║")
|
||||
cyan.Println(" ║ ║")
|
||||
cyan.Print(" ║ ")
|
||||
white.Print("High-Performance Instant Messaging System")
|
||||
cyan.Println(" ║")
|
||||
cyan.Println(" ║ ║")
|
||||
cyan.Println(" ╚══════════════════════════════════════════════════════════════════╝")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 系统信息
|
||||
green.Print("🚀 Starting WuKongIM Server...")
|
||||
fmt.Println()
|
||||
fmt.Println()
|
||||
|
||||
// 配置信息
|
||||
blue.Print("📋 Configuration:")
|
||||
fmt.Println()
|
||||
fmt.Printf(" ├─ Config File: %s\n", s.opts.ConfigFileUsed())
|
||||
fmt.Printf(" ├─ Mode: %s\n", s.getModeWithIcon())
|
||||
fmt.Printf(" ├─ Version: %s\n", version.Version)
|
||||
fmt.Printf(" ├─ Git: %s-%s\n", version.CommitDate, version.Commit)
|
||||
fmt.Printf(" ├─ Go Build: %s\n", runtime.Version())
|
||||
fmt.Printf(" └─ Data Directory: %s\n", s.opts.DataDir)
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 网络监听信息
|
||||
yellow.Print("🌐 Network Endpoints:")
|
||||
fmt.Println()
|
||||
fmt.Printf(" ├─ TCP Client: %s\n", s.opts.Addr)
|
||||
fmt.Printf(" ├─ WebSocket: %s\n", s.opts.WSAddr)
|
||||
if s.opts.WSSAddr != "" {
|
||||
fmt.Printf(" ├─ WebSocket Secure: %s\n", s.opts.WSSAddr)
|
||||
}
|
||||
fmt.Printf(" ├─ HTTP API: http://%s\n", s.opts.HTTPAddr)
|
||||
|
||||
// 文档端点信息(根据模式显示)
|
||||
if s.opts.Mode != options.ReleaseMode {
|
||||
green.Printf(" ├─ 📚 API Documentation: http://%s/docs\n", s.opts.HTTPAddr)
|
||||
}
|
||||
|
||||
if s.opts.Manager.On {
|
||||
fmt.Printf(" ├─ Manager: %s\n", s.opts.Manager.Addr)
|
||||
}
|
||||
|
||||
if s.opts.Demo.On {
|
||||
fmt.Printf(" └─ 🎮 Demo: http://%s\n", s.opts.Demo.Addr)
|
||||
} else {
|
||||
fmt.Printf(" └─ Demo: disabled\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 功能状态
|
||||
magenta.Print("⚙️ Features:")
|
||||
fmt.Println()
|
||||
fmt.Printf(" ├─ Cluster Mode: %s\n", s.getClusterStatus())
|
||||
fmt.Printf(" ├─ Conversation: %s\n", s.getBoolStatus(s.opts.Conversation.On))
|
||||
fmt.Printf(" ├─ Token Auth: %s\n", s.getBoolStatus(s.opts.TokenAuthOn))
|
||||
fmt.Printf(" ├─ Encryption: %s\n", s.getBoolStatus(!s.opts.DisableEncryption))
|
||||
fmt.Printf(" └─ Documentation: %s\n", s.getDocsStatus())
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 启动提示
|
||||
white.Print("💡 Quick Links:")
|
||||
fmt.Println()
|
||||
fmt.Printf(" ├─ Health Check: http://%s/health\n", s.opts.HTTPAddr)
|
||||
if s.opts.Mode != options.ReleaseMode {
|
||||
fmt.Printf(" ├─ API Docs: http://%s/docs\n", s.opts.HTTPAddr)
|
||||
}
|
||||
if s.opts.Demo.On {
|
||||
fmt.Printf(" ├─ Chat Demo: http://%s\n", s.opts.Demo.Addr)
|
||||
}
|
||||
fmt.Printf(" └─ System Info: http://%s/varz\n", s.opts.HTTPAddr)
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// getModeWithIcon 获取带图标的模式显示
|
||||
func (s *Server) getModeWithIcon() string {
|
||||
switch s.opts.Mode {
|
||||
case options.ReleaseMode:
|
||||
return "🚀 release (production)"
|
||||
case options.DebugMode:
|
||||
return "🐛 debug (development)"
|
||||
case options.BenchMode:
|
||||
return "⚡ bench (performance testing)"
|
||||
default:
|
||||
return fmt.Sprintf("❓ %s", s.opts.Mode)
|
||||
}
|
||||
}
|
||||
|
||||
// getBoolStatus 获取布尔状态的显示
|
||||
func (s *Server) getBoolStatus(enabled bool) string {
|
||||
if enabled {
|
||||
return "✅ enabled"
|
||||
}
|
||||
return "❌ disabled"
|
||||
}
|
||||
|
||||
// getClusterStatus 获取集群状态
|
||||
func (s *Server) getClusterStatus() string {
|
||||
if len(s.opts.Cluster.InitNodes) > 0 {
|
||||
return fmt.Sprintf("✅ enabled (%d nodes)", len(s.opts.Cluster.InitNodes))
|
||||
}
|
||||
return "❌ standalone mode"
|
||||
}
|
||||
|
||||
// getDocsStatus 获取文档服务状态
|
||||
func (s *Server) getDocsStatus() string {
|
||||
if s.opts.Mode == options.ReleaseMode {
|
||||
return "🔒 disabled (release mode)"
|
||||
}
|
||||
return "📚 enabled (development mode)"
|
||||
}
|
||||
|
||||
func (s *Server) onConnect(conn wknet.Conn) error {
|
||||
conn.SetMaxIdle(time.Second * 2) // 在认证之前,连接最多空闲2秒
|
||||
s.trace.Metrics.App().ConnCountAdd(1)
|
||||
|
||||
Reference in New Issue
Block a user