github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin-swagger/swagger.go (about) 1 package ginSwagger 2 3 import ( 4 "github.com/hellobchain/newcryptosm/http" 5 "html/template" 6 "os" 7 "path/filepath" 8 "regexp" 9 "sync" 10 11 "github.com/hellobchain/third_party/gin-swagger/webdav" 12 13 "github.com/hellobchain/third_party/gin" 14 "github.com/swaggo/swag" 15 ) 16 17 type swaggerConfig struct { 18 URL string 19 DocExpansion string 20 Title string 21 Oauth2RedirectURL template.JS 22 DefaultModelsExpandDepth int 23 DeepLinking bool 24 PersistAuthorization bool 25 Oauth2DefaultClientID string 26 } 27 28 // Config stores ginSwagger configuration variables. 29 type Config struct { 30 // The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`. 31 URL string 32 DocExpansion string 33 InstanceName string 34 Title string 35 DefaultModelsExpandDepth int 36 DeepLinking bool 37 PersistAuthorization bool 38 Oauth2DefaultClientID string 39 } 40 41 func (config Config) toSwaggerConfig() swaggerConfig { 42 return swaggerConfig{ 43 URL: config.URL, 44 DeepLinking: config.DeepLinking, 45 DocExpansion: config.DocExpansion, 46 DefaultModelsExpandDepth: config.DefaultModelsExpandDepth, 47 Oauth2RedirectURL: "`${window.location.protocol}//${window.location.host}$" + 48 "{window.location.pathname.split('/').slice(0, window.location.pathname.split('/').length - 1).join('/')}" + 49 "/oauth2-redirect.html`", 50 Title: config.Title, 51 PersistAuthorization: config.PersistAuthorization, 52 Oauth2DefaultClientID: config.Oauth2DefaultClientID, 53 } 54 } 55 56 // URL presents the url pointing to API definition (normally swagger.json or swagger.yaml). 57 func URL(url string) func(*Config) { 58 return func(c *Config) { 59 c.URL = url 60 } 61 } 62 63 // DocExpansion list, full, none. 64 func DocExpansion(docExpansion string) func(*Config) { 65 return func(c *Config) { 66 c.DocExpansion = docExpansion 67 } 68 } 69 70 // DeepLinking set the swagger deep linking configuration. 71 func DeepLinking(deepLinking bool) func(*Config) { 72 return func(c *Config) { 73 c.DeepLinking = deepLinking 74 } 75 } 76 77 // DefaultModelsExpandDepth set the default expansion depth for models 78 // (set to -1 completely hide the models). 79 func DefaultModelsExpandDepth(depth int) func(*Config) { 80 return func(c *Config) { 81 c.DefaultModelsExpandDepth = depth 82 } 83 } 84 85 // InstanceName set the instance name that was used to generate the swagger documents 86 // Defaults to swag.Name ("swagger"). 87 func InstanceName(name string) func(*Config) { 88 return func(c *Config) { 89 c.InstanceName = name 90 } 91 } 92 93 // PersistAuthorization Persist authorization information over browser close/refresh. 94 // Defaults to false. 95 func PersistAuthorization(persistAuthorization bool) func(*Config) { 96 return func(c *Config) { 97 c.PersistAuthorization = persistAuthorization 98 } 99 } 100 101 // Oauth2DefaultClientID set the default client ID used for OAuth2 102 func Oauth2DefaultClientID(oauth2DefaultClientID string) func(*Config) { 103 return func(c *Config) { 104 c.Oauth2DefaultClientID = oauth2DefaultClientID 105 } 106 } 107 108 // WrapHandler wraps `http.Handler` into `gin.HandlerFunc`. 109 func WrapHandler(handler *webdav.Handler, options ...func(*Config)) gin.HandlerFunc { 110 var config = Config{ 111 URL: "doc.json", 112 DocExpansion: "list", 113 InstanceName: swag.Name, 114 Title: "Swagger UI", 115 DefaultModelsExpandDepth: 1, 116 DeepLinking: true, 117 PersistAuthorization: false, 118 Oauth2DefaultClientID: "", 119 } 120 121 for _, c := range options { 122 c(&config) 123 } 124 125 return CustomWrapHandler(&config, handler) 126 } 127 128 // CustomWrapHandler wraps `http.Handler` into `gin.HandlerFunc`. 129 func CustomWrapHandler(config *Config, handler *webdav.Handler) gin.HandlerFunc { 130 var once sync.Once 131 132 if config.InstanceName == "" { 133 config.InstanceName = swag.Name 134 } 135 136 if config.Title == "" { 137 config.Title = "Swagger UI" 138 } 139 140 // create a template with name 141 index, _ := template.New("swagger_index.html").Parse(swaggerIndexTpl) 142 143 var matcher = regexp.MustCompile(`(.*)(index\.html|doc\.json|favicon-16x16\.png|favicon-32x32\.png|/oauth2-redirect\.html|swagger-ui\.css|swagger-ui\.css\.map|swagger-ui\.js|swagger-ui\.js\.map|swagger-ui-bundle\.js|swagger-ui-bundle\.js\.map|swagger-ui-standalone-preset\.js|swagger-ui-standalone-preset\.js\.map)[?|.]*`) 144 145 return func(ctx *gin.Context) { 146 if ctx.Request.Method != http.MethodGet { 147 ctx.AbortWithStatus(http.StatusMethodNotAllowed) 148 149 return 150 } 151 152 matches := matcher.FindStringSubmatch(ctx.Request.RequestURI) 153 154 if len(matches) != 3 { 155 ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound)) 156 157 return 158 } 159 160 path := matches[2] 161 once.Do(func() { 162 handler.Prefix = matches[1] 163 }) 164 165 switch filepath.Ext(path) { 166 case ".html": 167 ctx.Header("Content-Type", "text/html; charset=utf-8") 168 case ".css": 169 ctx.Header("Content-Type", "text/css; charset=utf-8") 170 case ".js": 171 ctx.Header("Content-Type", "application/javascript") 172 case ".png": 173 ctx.Header("Content-Type", "image/png") 174 case ".json": 175 ctx.Header("Content-Type", "application/json; charset=utf-8") 176 } 177 178 switch path { 179 case "index.html": 180 _ = index.Execute(ctx.Writer, config.toSwaggerConfig()) 181 case "doc.json": 182 doc, err := swag.ReadDoc(config.InstanceName) 183 if err != nil { 184 ctx.AbortWithStatus(http.StatusInternalServerError) 185 186 return 187 } 188 189 ctx.String(http.StatusOK, doc) 190 default: 191 handler.ServeHTTP(ctx.Writer, ctx.Request) 192 } 193 } 194 } 195 196 // DisablingWrapHandler turn handler off 197 // if specified environment variable passed. 198 func DisablingWrapHandler(handler *webdav.Handler, envName string) gin.HandlerFunc { 199 if os.Getenv(envName) != "" { 200 return func(c *gin.Context) { 201 // Simulate behavior when route unspecified and 202 // return 404 HTTP code 203 c.String(http.StatusNotFound, "") 204 } 205 } 206 207 return WrapHandler(handler) 208 } 209 210 // DisablingCustomWrapHandler turn handler off 211 // if specified environment variable passed. 212 func DisablingCustomWrapHandler(config *Config, handler *webdav.Handler, envName string) gin.HandlerFunc { 213 if os.Getenv(envName) != "" { 214 return func(c *gin.Context) { 215 // Simulate behavior when route unspecified and 216 // return 404 HTTP code 217 c.String(http.StatusNotFound, "") 218 } 219 } 220 221 return CustomWrapHandler(config, handler) 222 } 223 224 const swaggerIndexTpl = `<!-- HTML for static distribution bundle build --> 225 <!DOCTYPE html> 226 <html lang="en"> 227 <head> 228 <meta charset="UTF-8"> 229 <title>{{.Title}}</title> 230 <link rel="stylesheet" type="text/css" href="./swagger-ui.css" > 231 <link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" /> 232 <link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" /> 233 <style> 234 html 235 { 236 box-sizing: border-box; 237 overflow: -moz-scrollbars-vertical; 238 overflow-y: scroll; 239 } 240 *, 241 *:before, 242 *:after 243 { 244 box-sizing: inherit; 245 } 246 247 body { 248 margin:0; 249 background: #fafafa; 250 } 251 </style> 252 </head> 253 254 <body> 255 256 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0"> 257 <defs> 258 <symbol viewBox="0 0 20 20" id="unlocked"> 259 <path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path> 260 </symbol> 261 262 <symbol viewBox="0 0 20 20" id="locked"> 263 <path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/> 264 </symbol> 265 266 <symbol viewBox="0 0 20 20" id="close"> 267 <path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/> 268 </symbol> 269 270 <symbol viewBox="0 0 20 20" id="large-arrow"> 271 <path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/> 272 </symbol> 273 274 <symbol viewBox="0 0 20 20" id="large-arrow-down"> 275 <path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/> 276 </symbol> 277 278 279 <symbol viewBox="0 0 24 24" id="jump-to"> 280 <path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/> 281 </symbol> 282 283 <symbol viewBox="0 0 24 24" id="expand"> 284 <path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/> 285 </symbol> 286 287 </defs> 288 </svg> 289 290 <div id="swagger-ui"></div> 291 292 <script src="./swagger-ui-bundle.js"> </script> 293 <script src="./swagger-ui-standalone-preset.js"> </script> 294 <script> 295 window.onload = function() { 296 // Build a system 297 const ui = SwaggerUIBundle({ 298 url: "{{.URL}}", 299 dom_id: '#swagger-ui', 300 validatorUrl: null, 301 oauth2RedirectUrl: {{.Oauth2RedirectURL}}, 302 persistAuthorization: {{.PersistAuthorization}}, 303 presets: [ 304 SwaggerUIBundle.presets.apis, 305 SwaggerUIStandalonePreset 306 ], 307 plugins: [ 308 SwaggerUIBundle.plugins.DownloadUrl 309 ], 310 layout: "StandaloneLayout", 311 docExpansion: "{{.DocExpansion}}", 312 deepLinking: {{.DeepLinking}}, 313 defaultModelsExpandDepth: {{.DefaultModelsExpandDepth}} 314 }) 315 316 const defaultClientId = "{{.Oauth2DefaultClientID}}"; 317 if (defaultClientId) { 318 ui.initOAuth({ 319 clientId: defaultClientId 320 }) 321 } 322 323 window.ui = ui 324 } 325 </script> 326 </body> 327 328 </html> 329 `