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  `