230 lines
6.3 KiB
Go
230 lines
6.3 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
swaggerFiles "github.com/swaggo/files"
|
|
"github.com/swaggo/swag"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func SwaggerHandler() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
rawPath := c.Request.URL.Path
|
|
relPath := strings.TrimPrefix(rawPath, "/swagger")
|
|
if relPath == "" || relPath == "/" {
|
|
c.Request.URL.Path = "/index.html"
|
|
} else {
|
|
c.Request.URL.Path = relPath
|
|
}
|
|
|
|
isCSS := strings.HasSuffix(relPath, "swagger-ui.css")
|
|
isInitializer := strings.HasSuffix(relPath, "swagger-initializer.js")
|
|
isDocJSON := strings.HasSuffix(relPath, "doc.json")
|
|
|
|
if isDocJSON {
|
|
doc, _ := swag.ReadDoc()
|
|
c.Header("Content-Type", "application/json; charset=utf-8")
|
|
c.Writer.WriteHeader(200)
|
|
c.Writer.Write([]byte(doc))
|
|
c.Request.URL.Path = rawPath
|
|
return
|
|
}
|
|
|
|
if isInitializer {
|
|
c.Header("Content-Type", "application/javascript; charset=utf-8")
|
|
c.Writer.WriteHeader(200)
|
|
c.Writer.Write([]byte(chineseInitializer))
|
|
c.Request.URL.Path = rawPath
|
|
return
|
|
}
|
|
|
|
if isCSS {
|
|
crw := &captureResponseWriter{
|
|
ginWriter: c.Writer,
|
|
code: 200,
|
|
}
|
|
c.Writer = crw
|
|
|
|
swaggerFiles.Handler.ServeHTTP(crw, c.Request)
|
|
|
|
c.Writer = crw.ginWriter
|
|
|
|
if crw.code == 200 && crw.buf.Len() > 0 {
|
|
body := append(crw.buf.Bytes(), []byte(brandingCSS)...)
|
|
c.Header("Content-Length", strconv.Itoa(len(body)))
|
|
c.Header("Content-Type", "text/css; charset=utf-8")
|
|
c.Writer.WriteHeader(crw.code)
|
|
c.Writer.Write(body)
|
|
c.Request.URL.Path = rawPath
|
|
return
|
|
}
|
|
|
|
if crw.buf.Len() > 0 {
|
|
c.Writer.WriteHeader(crw.code)
|
|
c.Writer.Write(crw.buf.Bytes())
|
|
c.Request.URL.Path = rawPath
|
|
return
|
|
}
|
|
|
|
c.Writer.WriteHeader(crw.code)
|
|
c.Request.URL.Path = rawPath
|
|
return
|
|
}
|
|
|
|
swaggerFiles.Handler.ServeHTTP(c.Writer, c.Request)
|
|
c.Request.URL.Path = rawPath
|
|
}
|
|
}
|
|
|
|
type captureResponseWriter struct {
|
|
ginWriter gin.ResponseWriter
|
|
code int
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func (w *captureResponseWriter) Header() http.Header { return w.ginWriter.Header() }
|
|
func (w *captureResponseWriter) Write(b []byte) (int, error) { return w.buf.Write(b) }
|
|
func (w *captureResponseWriter) WriteHeader(code int) { w.code = code }
|
|
func (w *captureResponseWriter) WriteString(s string) (int, error) { return w.buf.WriteString(s) }
|
|
func (w *captureResponseWriter) Status() int { return w.code }
|
|
func (w *captureResponseWriter) Size() int { return w.buf.Len() }
|
|
func (w *captureResponseWriter) Written() bool { return w.buf.Len() > 0 }
|
|
func (w *captureResponseWriter) WriteHeaderNow() {}
|
|
func (w *captureResponseWriter) Pusher() http.Pusher { return nil }
|
|
func (w *captureResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
return w.ginWriter.Hijack()
|
|
}
|
|
func (w *captureResponseWriter) CloseNotify() <-chan bool { return w.ginWriter.CloseNotify() }
|
|
func (w *captureResponseWriter) Flush() {}
|
|
|
|
const chineseInitializer = `
|
|
window.onload = function() {
|
|
window.ui = SwaggerUIBundle({
|
|
url: "./doc.json",
|
|
dom_id: '#swagger-ui',
|
|
deepLinking: true,
|
|
presets: [
|
|
SwaggerUIBundle.presets.apis,
|
|
SwaggerUIStandalonePreset
|
|
],
|
|
plugins: [
|
|
SwaggerUIBundle.plugins.DownloadUrl
|
|
],
|
|
layout: "StandaloneLayout",
|
|
validatorUrl: null,
|
|
defaultModelsExpandDepth: 1,
|
|
defaultModelExpandDepth: 1,
|
|
docExpansion: "list",
|
|
filter: true,
|
|
showExtensions: true,
|
|
showCommonExtensions: true,
|
|
withCredentials: false,
|
|
persistAuthorization: true,
|
|
tryItOutEnabled: false,
|
|
requestSnippetsEnabled: true,
|
|
displayRequestDuration: true,
|
|
syntaxHighlight: {
|
|
activate: true,
|
|
theme: "agate"
|
|
}
|
|
});
|
|
|
|
setTimeout(function() {
|
|
const translations = {
|
|
'Available authorizations': '可用授权',
|
|
'Close': '关闭',
|
|
'Scopes for': '作用域',
|
|
'Authorize': '授权',
|
|
'Cancel': '取消',
|
|
'Authorized': '已授权',
|
|
'Logout': '登出',
|
|
'Edit': '编辑',
|
|
'Select a definition': '选择定义',
|
|
'Search': '搜索',
|
|
'Top': '顶部',
|
|
'Parameters': '参数',
|
|
'Responses': '响应',
|
|
'Try it out': '试一试',
|
|
'Clear': '清除',
|
|
'Download': '下载',
|
|
'Show/Hide': '显示/隐藏',
|
|
'List Operations': '列表操作',
|
|
'Expand Operations': '展开操作',
|
|
'Models': '模型'
|
|
};
|
|
|
|
document.querySelectorAll('span, button, div, label').forEach(function(el) {
|
|
const text = el.textContent.trim();
|
|
if (translations[text]) {
|
|
el.textContent = translations[text];
|
|
}
|
|
});
|
|
|
|
document.title = 'MengStack API 文档';
|
|
}, 500);
|
|
};
|
|
`
|
|
|
|
const brandingCSS = `
|
|
/* MengStack API branding — replace Swagger SmartBear logo */
|
|
.topbar {
|
|
display: flex !important;
|
|
align-items: center !important;
|
|
background-color: #1b1b1f !important;
|
|
padding: 8px 20px !important;
|
|
min-height: 50px !important;
|
|
position: relative !important;
|
|
}
|
|
.topbar > * {
|
|
visibility: hidden !important;
|
|
width: 0 !important;
|
|
height: 0 !important;
|
|
overflow: hidden !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
flex: 0 !important;
|
|
}
|
|
.topbar::before {
|
|
content: "MengStack API \6587\6863" !important;
|
|
visibility: visible !important;
|
|
width: auto !important;
|
|
height: auto !important;
|
|
overflow: visible !important;
|
|
flex: 0 0 auto !important;
|
|
color: #fff !important;
|
|
font-size: 20px !important;
|
|
font-weight: 700 !important;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
letter-spacing: 1px !important;
|
|
text-decoration: none !important;
|
|
position: absolute !important;
|
|
left: 20px !important;
|
|
top: 50% !important;
|
|
transform: translateY(-50%) !important;
|
|
}
|
|
.topbar::after {
|
|
content: "v0.3.0" !important;
|
|
visibility: visible !important;
|
|
width: auto !important;
|
|
height: auto !important;
|
|
overflow: visible !important;
|
|
flex: 0 0 auto !important;
|
|
color: rgba(255,255,255,0.5) !important;
|
|
font-size: 12px !important;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
position: absolute !important;
|
|
left: 230px !important;
|
|
top: 50% !important;
|
|
transform: translateY(-50%) !important;
|
|
}
|
|
.swagger-ui {
|
|
margin-top: 0 !important;
|
|
}
|
|
`
|