Add GoSRT & improvements (repo-merge)

Commits (Ingo Oppermann):
- Add experimental SRT connection stats and logs
- Hide /config/reload endpoint in reade-only mode
- Add SRT server
- Create v16 in go.mod
- Fix data races, tests, lint, and update dependencies
- Add trailing slash for routed directories (datarhei/restreamer#340)
- Allow relative URLs in content in static routes

Co-Authored-By: Ingo Oppermann <57445+ioppermann@users.noreply.github.com>
This commit is contained in:
Jan Stabenow
2022-06-23 22:13:58 +02:00
parent d7db9e4efe
commit eb1cc37456
323 changed files with 17524 additions and 10050 deletions

View File

@@ -1,7 +1,7 @@
# Dockerfile References: https://docs.docker.com/engine/reference/builder/
# Start from the latest golang base image
FROM golang:1.17-alpine as builder
FROM golang:1.18.3-alpine as builder
# Set the Current Working Directory inside the container
WORKDIR /app

View File

@@ -63,7 +63,7 @@ $ go install github.com/swaggo/swag/cmd/swag@latest
swag init
```
确保导入了生成的`docs/docs.go`文件这样特定的配置文件才会被初始化。如果通用API指数没有写在`main.go`中,可以使用`-g`标识符来告知swag。
确保导入了生成的`docs/docs.go`文件这样特定的配置文件才会被初始化。如果通用API注释没有写在`main.go`中,可以使用`-g`标识符来告知swag。
```bash
swag init -g http/api.go

View File

@@ -388,10 +388,6 @@ func (ps *tagBaseFieldParser) ComplementSchema(schema *spec.Schema) error {
varNamesTag := ps.tag.Get("x-enum-varnames")
if varNamesTag != "" {
if schema.Extensions == nil {
schema.Extensions = map[string]interface{}{}
}
varNames := strings.Split(varNamesTag, ",")
if len(varNames) != len(field.enums) {
return fmt.Errorf("invalid count of x-enum-varnames. expected %d, got %d", len(field.enums), len(varNames))
@@ -403,7 +399,19 @@ func (ps *tagBaseFieldParser) ComplementSchema(schema *spec.Schema) error {
field.enumVarNames = append(field.enumVarNames, v)
}
schema.Extensions["x-enum-varnames"] = field.enumVarNames
if field.schemaType == ARRAY {
// Add the var names in the items schema
if schema.Items.Schema.Extensions == nil {
schema.Items.Schema.Extensions = map[string]interface{}{}
}
schema.Items.Schema.Extensions["x-enum-varnames"] = field.enumVarNames
} else {
// Add to top level schema
if schema.Extensions == nil {
schema.Extensions = map[string]interface{}{}
}
schema.Extensions["x-enum-varnames"] = field.enumVarNames
}
}
eleSchema := schema

109
vendor/github.com/swaggo/swag/generics.go generated vendored Normal file
View File

@@ -0,0 +1,109 @@
//go:build go1.18
// +build go1.18
package swag
import (
"go/ast"
"strings"
)
func typeSpecFullName(typeSpecDef *TypeSpecDef) string {
fullName := typeSpecDef.FullName()
if typeSpecDef.TypeSpec.TypeParams != nil {
fullName = fullName + "["
for i, typeParam := range typeSpecDef.TypeSpec.TypeParams.List {
if i > 0 {
fullName = fullName + "-"
}
fullName = fullName + typeParam.Names[0].Name
}
fullName = fullName + "]"
}
return fullName
}
func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {
genericParams := strings.Split(strings.TrimRight(fullGenericForm, "]"), "[")
if len(genericParams) == 1 {
return nil
}
genericParams = strings.Split(genericParams[1], ",")
for i, p := range genericParams {
genericParams[i] = strings.TrimSpace(p)
}
genericParamTypeDefs := map[string]*TypeSpecDef{}
if len(genericParams) != len(original.TypeSpec.TypeParams.List) {
return nil
}
for i, genericParam := range genericParams {
tdef, ok := pkgDefs.uniqueDefinitions[genericParam]
if !ok {
return nil
}
genericParamTypeDefs[original.TypeSpec.TypeParams.List[i].Names[0].Name] = tdef
}
parametrizedTypeSpec := &TypeSpecDef{
File: original.File,
PkgPath: original.PkgPath,
TypeSpec: &ast.TypeSpec{
Doc: original.TypeSpec.Doc,
Comment: original.TypeSpec.Comment,
Assign: original.TypeSpec.Assign,
},
}
ident := &ast.Ident{
NamePos: original.TypeSpec.Name.NamePos,
Obj: original.TypeSpec.Name.Obj,
}
genNameParts := strings.Split(fullGenericForm, "[")
if strings.Contains(genNameParts[0], ".") {
genNameParts[0] = strings.Split(genNameParts[0], ".")[1]
}
ident.Name = genNameParts[0] + "-" + strings.Replace(strings.Join(genericParams, "-"), ".", "_", -1)
ident.Name = strings.Replace(strings.Replace(ident.Name, "\t", "", -1), " ", "", -1)
parametrizedTypeSpec.TypeSpec.Name = ident
origStructType := original.TypeSpec.Type.(*ast.StructType)
newStructTypeDef := &ast.StructType{
Struct: origStructType.Struct,
Incomplete: origStructType.Incomplete,
Fields: &ast.FieldList{
Opening: origStructType.Fields.Opening,
Closing: origStructType.Fields.Closing,
},
}
for _, field := range origStructType.Fields.List {
newField := &ast.Field{
Doc: field.Doc,
Names: field.Names,
Tag: field.Tag,
Comment: field.Comment,
}
if genTypeSpec, ok := genericParamTypeDefs[field.Type.(*ast.Ident).Name]; ok {
newField.Type = genTypeSpec.TypeSpec.Type
} else {
newField.Type = field.Type
}
newStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)
}
parametrizedTypeSpec.TypeSpec.Type = newStructTypeDef
return parametrizedTypeSpec
}

12
vendor/github.com/swaggo/swag/generics_other.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
//go:build !go1.18
// +build !go1.18
package swag
func typeSpecFullName(typeSpecDef *TypeSpecDef) string {
return typeSpecDef.FullName()
}
func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {
return original
}

74
vendor/github.com/swaggo/swag/golist.go generated vendored Normal file
View File

@@ -0,0 +1,74 @@
package swag
import (
"bytes"
"context"
"encoding/json"
"fmt"
"go/build"
"os/exec"
"path/filepath"
)
func listPackages(ctx context.Context, dir string, env []string, args ...string) (pkgs []*build.Package, finalErr error) {
cmd := exec.CommandContext(ctx, "go", append([]string{"list", "-json", "-e"}, args...)...)
cmd.Env = env
cmd.Dir = dir
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
var stderrBuf bytes.Buffer
cmd.Stderr = &stderrBuf
defer func() {
if stderrBuf.Len() > 0 {
finalErr = fmt.Errorf("%v\n%s", finalErr, stderrBuf.Bytes())
}
}()
err = cmd.Start()
if err != nil {
return nil, err
}
dec := json.NewDecoder(stdout)
for dec.More() {
var pkg build.Package
err = dec.Decode(&pkg)
if err != nil {
return nil, err
}
pkgs = append(pkgs, &pkg)
}
err = cmd.Wait()
if err != nil {
return nil, err
}
return pkgs, nil
}
func (parser *Parser) getAllGoFileInfoFromDepsByList(pkg *build.Package) error {
ignoreInternal := pkg.Goroot && !parser.ParseInternal
if ignoreInternal { // ignored internal
return nil
}
srcDir := pkg.Dir
var err error
for i := range pkg.GoFiles {
err = parser.parseFile(pkg.ImportPath, filepath.Join(srcDir, pkg.GoFiles[i]), nil)
if err != nil {
return err
}
}
// parse .go source files that import "C"
for i := range pkg.CgoFiles {
err = parser.parseFile(pkg.ImportPath, filepath.Join(srcDir, pkg.CgoFiles[i]), nil)
if err != nil {
return err
}
}
return nil
}

View File

@@ -385,7 +385,7 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F
if objectType == PRIMITIVE {
param.Schema = PrimitiveSchema(refType)
} else {
schema, err := operation.parseAPIObjectSchema(objectType, refType, astFile)
schema, err := operation.parseAPIObjectSchema(commentLine, objectType, refType, astFile)
if err != nil {
return err
}
@@ -933,7 +933,16 @@ func (operation *Operation) parseCombinedObjectSchema(refType string, astFile *a
}), nil
}
func (operation *Operation) parseAPIObjectSchema(schemaType, refType string, astFile *ast.File) (*spec.Schema, error) {
func (operation *Operation) parseAPIObjectSchema(commentLine, schemaType, refType string, astFile *ast.File) (*spec.Schema, error) {
if strings.HasSuffix(refType, ",") && strings.Contains(refType, "[") {
// regexp may have broken generics syntax. find closing bracket and add it back
allMatchesLenOffset := strings.Index(commentLine, refType) + len(refType)
lostPartEndIdx := strings.Index(commentLine[allMatchesLenOffset:], "]")
if lostPartEndIdx >= 0 {
refType += commentLine[allMatchesLenOffset : allMatchesLenOffset+lostPartEndIdx+1]
}
}
switch schemaType {
case OBJECT:
if !strings.HasPrefix(refType, "[]") {
@@ -969,7 +978,7 @@ func (operation *Operation) ParseResponseComment(commentLine string, astFile *as
description := strings.Trim(matches[4], "\"")
schema, err := operation.parseAPIObjectSchema(strings.Trim(matches[2], "{}"), matches[3], astFile)
schema, err := operation.parseAPIObjectSchema(commentLine, strings.Trim(matches[2], "{}"), matches[3], astFile)
if err != nil {
return err
}

View File

@@ -6,6 +6,7 @@ import (
"go/token"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
@@ -78,6 +79,11 @@ func (pkgDefs *PackagesDefinitions) CollectAstFile(packageDir, path string, astF
func rangeFiles(files map[*ast.File]*AstFileInfo, handle func(filename string, file *ast.File) error) error {
sortedFiles := make([]*AstFileInfo, 0, len(files))
for _, info := range files {
// ignore package path prefix with 'vendor' or $GOROOT,
// because the router info of api will not be included these files.
if strings.HasPrefix(info.PackagePath, "vendor") || strings.HasPrefix(info.Path, runtime.GOROOT()) {
continue
}
sortedFiles = append(sortedFiles, info)
}
@@ -128,7 +134,8 @@ func (pkgDefs *PackagesDefinitions) parseTypesFromFile(astFile *ast.File, packag
pkgDefs.uniqueDefinitions = make(map[string]*TypeSpecDef)
}
fullName := typeSpecDef.FullName()
fullName := typeSpecFullName(typeSpecDef)
anotherTypeDef, ok := pkgDefs.uniqueDefinitions[fullName]
if ok {
if typeSpecDef.PkgPath == anotherTypeDef.PkgPath {
@@ -286,7 +293,7 @@ func (pkgDefs *PackagesDefinitions) FindTypeSpec(typeName string, file *ast.File
return pkgDefs.uniqueDefinitions[typeName]
}
parts := strings.Split(typeName, ".")
parts := strings.Split(strings.Split(typeName, "[")[0], ".")
if len(parts) > 1 {
isAliasPkgName := func(file *ast.File, pkgName string) bool {
if file != nil && file.Imports != nil {
@@ -322,6 +329,22 @@ func (pkgDefs *PackagesDefinitions) FindTypeSpec(typeName string, file *ast.File
}
}
if strings.Contains(typeName, "[") {
// joinedParts differs from typeName in that it does not contain any type parameters
joinedParts := strings.Join(parts, ".")
for tName, tSpec := range pkgDefs.uniqueDefinitions {
if !strings.Contains(tName, "[") {
continue
}
if strings.Contains(tName, joinedParts) {
if parametrized := pkgDefs.parametrizeStruct(tSpec, typeName); parametrized != nil {
return parametrized
}
}
}
}
return pkgDefs.findTypeSpec(pkgPath, parts[1])
}

View File

@@ -1,6 +1,7 @@
package swag
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -48,9 +49,21 @@ const (
deprecatedAttr = "@deprecated"
securityAttr = "@security"
titleAttr = "@title"
conNameAttr = "@contact.name"
conURLAttr = "@contact.url"
conEmailAttr = "@contact.email"
licNameAttr = "@license.name"
licURLAttr = "@license.url"
versionAttr = "@version"
descriptionAttr = "@description"
descriptionMarkdownAttr = "@description.markdown"
secBasicAttr = "@securitydefinitions.basic"
secAPIKeyAttr = "@securitydefinitions.apikey"
secApplicationAttr = "@securitydefinitions.oauth2.application"
secImplicitAttr = "@securitydefinitions.oauth2.implicit"
secPasswordAttr = "@securitydefinitions.oauth2.password"
secAccessCodeAttr = "@securitydefinitions.oauth2.accesscode"
tosAttr = "@termsofservice"
xCodeSamplesAttr = "@x-codesamples"
scopeAttrPrefix = "@scope."
)
@@ -140,6 +153,9 @@ type Parser struct {
// Overrides allows global replacements of types. A blank replacement will be skipped.
Overrides map[string]string
// parseGoList whether swag use go list to parse dependency
parseGoList bool
}
// FieldParserFactory create FieldParser.
@@ -241,7 +257,10 @@ func SetStrict(strict bool) func(*Parser) {
// SetDebugger allows the use of user-defined implementations.
func SetDebugger(logger Debugger) func(parser *Parser) {
return func(p *Parser) {
p.debug = logger
if logger != nil {
p.debug = logger
}
}
}
@@ -261,6 +280,13 @@ func SetOverrides(overrides map[string]string) func(parser *Parser) {
}
}
// ParseUsingGoList sets whether swag use go list to parse dependency
func ParseUsingGoList(enabled bool) func(parser *Parser) {
return func(p *Parser) {
p.parseGoList = enabled
}
}
// ParseAPI parses general api info for given searchDir and mainAPIFile.
func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string, parseDepth int) error {
return parser.ParseAPIMultiSearchDir([]string{searchDir}, mainAPIFile, parseDepth)
@@ -287,26 +313,41 @@ func (parser *Parser) ParseAPIMultiSearchDir(searchDirs []string, mainAPIFile st
return err
}
// Use 'go list' command instead of depth.Resolve()
if parser.ParseDependency {
var tree depth.Tree
tree.ResolveInternal = true
tree.MaxDepth = parseDepth
if parser.parseGoList {
pkgs, err := listPackages(context.Background(), filepath.Dir(absMainAPIFilePath), nil, "-deps")
if err != nil {
return fmt.Errorf("pkg %s cannot find all dependencies, %s", filepath.Dir(absMainAPIFilePath), err)
}
pkgName, err := getPkgName(filepath.Dir(absMainAPIFilePath))
if err != nil {
return err
}
length := len(pkgs)
for i := 0; i < length; i++ {
err := parser.getAllGoFileInfoFromDepsByList(pkgs[i])
if err != nil {
return err
}
}
} else {
var t depth.Tree
t.ResolveInternal = true
t.MaxDepth = parseDepth
err = tree.Resolve(pkgName)
if err != nil {
return fmt.Errorf("pkg %s cannot find all dependencies, %s", pkgName, err)
}
for i := 0; i < len(tree.Root.Deps); i++ {
err := parser.getAllGoFileInfoFromDeps(&tree.Root.Deps[i])
pkgName, err := getPkgName(filepath.Dir(absMainAPIFilePath))
if err != nil {
return err
}
err = t.Resolve(pkgName)
if err != nil {
return fmt.Errorf("pkg %s cannot find all dependencies, %s", pkgName, err)
}
for i := 0; i < len(t.Root.Deps); i++ {
err := parser.getAllGoFileInfoFromDeps(&t.Root.Deps[i])
if err != nil {
return err
}
}
}
}
@@ -356,14 +397,6 @@ func getPkgName(searchDir string) (string, error) {
return outStr, nil
}
func initIfEmpty(license *spec.License) *spec.License {
if license == nil {
return new(spec.License)
}
return license
}
// ParseGeneralAPIInfo parses general api info for given mainAPIFile path.
func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
fileTree, err := goparser.ParseFile(token.NewFileSet(), mainAPIFile, nil, goparser.ParseComments)
@@ -396,16 +429,15 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
commentLine := comments[line]
attribute := strings.Split(commentLine, " ")[0]
value := strings.TrimSpace(commentLine[len(attribute):])
multilineBlock := false
if previousAttribute == attribute {
multilineBlock = true
}
switch strings.ToLower(attribute) {
case versionAttr:
parser.swagger.Info.Version = value
case titleAttr:
parser.swagger.Info.Title = value
switch attr := strings.ToLower(attribute); attr {
case versionAttr, titleAttr, tosAttr, licNameAttr, licURLAttr, conNameAttr, conURLAttr, conEmailAttr:
setSwaggerInfo(parser.swagger, attr, value)
case descriptionAttr:
if multilineBlock {
parser.swagger.Info.Description += "\n" + value
@@ -413,32 +445,20 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
continue
}
parser.swagger.Info.Description = value
case "@description.markdown":
setSwaggerInfo(parser.swagger, attr, value)
case descriptionMarkdownAttr:
commentInfo, err := getMarkdownForTag("api", parser.markdownFileDir)
if err != nil {
return err
}
parser.swagger.Info.Description = string(commentInfo)
case "@termsofservice":
parser.swagger.Info.TermsOfService = value
case "@contact.name":
parser.swagger.Info.Contact.Name = value
case "@contact.email":
parser.swagger.Info.Contact.Email = value
case "@contact.url":
parser.swagger.Info.Contact.URL = value
case "@license.name":
parser.swagger.Info.License = initIfEmpty(parser.swagger.Info.License)
parser.swagger.Info.License.Name = value
case "@license.url":
parser.swagger.Info.License = initIfEmpty(parser.swagger.Info.License)
parser.swagger.Info.License.URL = value
setSwaggerInfo(parser.swagger, descriptionAttr, string(commentInfo))
case "@host":
parser.swagger.Host = value
case "@basepath":
parser.swagger.BasePath = value
case acceptAttr:
err := parser.ParseAcceptComment(value)
if err != nil {
@@ -450,7 +470,7 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
return err
}
case "@schemes":
parser.swagger.Schemes = getSchemes(commentLine)
parser.swagger.Schemes = strings.Split(value, " ")
case "@tag.name":
parser.swagger.Tags = append(parser.swagger.Tags, spec.Tag{
TagProps: spec.TagProps{
@@ -487,43 +507,15 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
tag.TagProps.ExternalDocs.Description = value
replaceLastTag(parser.swagger.Tags, tag)
case "@securitydefinitions.basic":
parser.swagger.SecurityDefinitions[value] = spec.BasicAuth()
case "@securitydefinitions.apikey":
attrMap, _, extensions, err := parseSecAttr(attribute, []string{"@in", "@name"}, comments, &line)
case secBasicAttr, secAPIKeyAttr, secApplicationAttr, secImplicitAttr, secPasswordAttr, secAccessCodeAttr:
scheme, err := parseSecAttributes(attribute, comments, &line)
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = tryAddDescription(spec.APIKeyAuth(attrMap["@name"], attrMap["@in"]), extensions)
case "@securitydefinitions.oauth2.application":
attrMap, scopes, extensions, err := parseSecAttr(attribute, []string{"@tokenurl"}, comments, &line)
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = scheme
parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2Application(attrMap["@tokenurl"], scopes, extensions), extensions)
case "@securitydefinitions.oauth2.implicit":
attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@authorizationurl"}, comments, &line)
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2Implicit(attrs["@authorizationurl"], scopes, ext), ext)
case "@securitydefinitions.oauth2.password":
attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@tokenurl"}, comments, &line)
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2Password(attrs["@tokenurl"], scopes, ext), ext)
case "@securitydefinitions.oauth2.accesscode":
attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@tokenurl", "@authorizationurl"}, comments, &line)
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = tryAddDescription(secOAuth2AccessToken(attrs["@authorizationurl"], attrs["@tokenurl"], scopes, ext), ext)
case "@query.collection.format":
parser.collectionFormatInQuery = value
default:
@@ -578,14 +570,140 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
return nil
}
func tryAddDescription(spec *spec.SecurityScheme, extensions map[string]interface{}) *spec.SecurityScheme {
if val, ok := extensions["@description"]; ok {
if str, ok := val.(string); ok {
spec.Description = str
func setSwaggerInfo(swagger *spec.Swagger, attribute, value string) {
switch attribute {
case versionAttr:
swagger.Info.Version = value
case titleAttr:
swagger.Info.Title = value
case tosAttr:
swagger.Info.TermsOfService = value
case descriptionAttr:
swagger.Info.Description = value
case conNameAttr:
swagger.Info.Contact.Name = value
case conEmailAttr:
swagger.Info.Contact.Email = value
case conURLAttr:
swagger.Info.Contact.URL = value
case licNameAttr:
swagger.Info.License = initIfEmpty(swagger.Info.License)
swagger.Info.License.Name = value
case licURLAttr:
swagger.Info.License = initIfEmpty(swagger.Info.License)
swagger.Info.License.URL = value
}
}
func parseSecAttributes(context string, lines []string, index *int) (*spec.SecurityScheme, error) {
const (
in = "@in"
name = "@name"
descriptionAttr = "@description"
tokenURL = "@tokenurl"
authorizationURL = "@authorizationurl"
)
var search []string
attribute := strings.ToLower(strings.Split(lines[*index], " ")[0])
switch attribute {
case secBasicAttr:
return spec.BasicAuth(), nil
case secAPIKeyAttr:
search = []string{in, name}
case secApplicationAttr, secPasswordAttr:
search = []string{tokenURL}
case secImplicitAttr:
search = []string{authorizationURL}
case secAccessCodeAttr:
search = []string{tokenURL, authorizationURL}
}
// For the first line we get the attributes in the context parameter, so we skip to the next one
*index++
attrMap, scopes := make(map[string]string), make(map[string]string)
extensions, description := make(map[string]interface{}), ""
for ; *index < len(lines); *index++ {
v := lines[*index]
securityAttr := strings.ToLower(strings.Split(v, " ")[0])
for _, findterm := range search {
if securityAttr == findterm {
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
continue
}
}
isExists, err := isExistsScope(securityAttr)
if err != nil {
return nil, err
}
if isExists {
scopes[securityAttr[len(scopeAttrPrefix):]] = v[len(securityAttr):]
}
if strings.HasPrefix(securityAttr, "@x-") {
// Add the custom attribute without the @
extensions[securityAttr[1:]] = strings.TrimSpace(v[len(securityAttr):])
}
// Not mandatory field
if securityAttr == descriptionAttr {
description = strings.TrimSpace(v[len(securityAttr):])
}
// next securityDefinitions
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
// Go back to the previous line and break
*index--
break
}
}
return spec
if len(attrMap) != len(search) {
return nil, fmt.Errorf("%s is %v required", context, search)
}
var scheme *spec.SecurityScheme
switch attribute {
case secAPIKeyAttr:
scheme = spec.APIKeyAuth(attrMap[name], attrMap[in])
case secApplicationAttr:
scheme = spec.OAuth2Application(attrMap[tokenURL])
case secImplicitAttr:
scheme = spec.OAuth2Implicit(attrMap[authorizationURL])
case secPasswordAttr:
scheme = spec.OAuth2Password(attrMap[tokenURL])
case secAccessCodeAttr:
scheme = spec.OAuth2AccessToken(attrMap[authorizationURL], attrMap[tokenURL])
}
scheme.Description = description
for extKey, extValue := range extensions {
scheme.AddExtension(extKey, extValue)
}
for scope, scopeDescription := range scopes {
scheme.AddScope(scope, scopeDescription)
}
return scheme, nil
}
func initIfEmpty(license *spec.License) *spec.License {
if license == nil {
return new(spec.License)
}
return license
}
// ParseAcceptComment parses comment for given `accept` comment string.
@@ -611,121 +729,6 @@ func isGeneralAPIComment(comments []string) bool {
return true
}
func parseSecAttr(context string, search []string, lines []string, index *int) (map[string]string, map[string]string, map[string]interface{}, error) {
attrMap := map[string]string{}
scopes := map[string]string{}
extensions := map[string]interface{}{}
// For the first line we get the attributes in the context parameter, so we skip to the next one
*index++
for ; *index < len(lines); *index++ {
v := lines[*index]
securityAttr := strings.ToLower(strings.Split(v, " ")[0])
for _, findterm := range search {
if securityAttr == findterm {
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
continue
}
}
isExists, err := isExistsScope(securityAttr)
if err != nil {
return nil, nil, nil, err
}
if isExists {
scopes[securityAttr[len(scopeAttrPrefix):]] = v[len(securityAttr):]
}
if strings.HasPrefix(securityAttr, "@x-") {
// Add the custom attribute without the @
extensions[securityAttr[1:]] = strings.TrimSpace(v[len(securityAttr):])
}
// Not mandatory field
if securityAttr == "@description" {
extensions[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
}
// next securityDefinitions
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
// Go back to the previous line and break
*index--
break
}
}
if len(attrMap) != len(search) {
return nil, nil, nil, fmt.Errorf("%s is %v required", context, search)
}
return attrMap, scopes, extensions, nil
}
type (
authExtensions map[string]interface{}
authScopes map[string]string
)
func secOAuth2Application(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme {
securityScheme := spec.OAuth2Application(tokenURL)
securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions)
for scope, description := range scopes {
securityScheme.AddScope(scope, description)
}
return securityScheme
}
func secOAuth2Implicit(authorizationURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme {
securityScheme := spec.OAuth2Implicit(authorizationURL)
securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions)
for scope, description := range scopes {
securityScheme.AddScope(scope, description)
}
return securityScheme
}
func secOAuth2Password(tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme {
securityScheme := spec.OAuth2Password(tokenURL)
securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions)
for scope, description := range scopes {
securityScheme.AddScope(scope, description)
}
return securityScheme
}
func secOAuth2AccessToken(authorizationURL, tokenURL string, scopes authScopes, extensions authExtensions) *spec.SecurityScheme {
securityScheme := spec.OAuth2AccessToken(authorizationURL, tokenURL)
securityScheme.VendorExtensible.Extensions = handleSecuritySchemaExtensions(extensions)
for scope, description := range scopes {
securityScheme.AddScope(scope, description)
}
return securityScheme
}
func handleSecuritySchemaExtensions(providedExtensions authExtensions) spec.Extensions {
var extensions spec.Extensions
if len(providedExtensions) > 0 {
extensions = make(map[string]interface{}, len(providedExtensions))
for key, value := range providedExtensions {
extensions[key] = value
}
}
return extensions
}
func getMarkdownForTag(tagName string, dirPath string) ([]byte, error) {
filesInfos, err := ioutil.ReadDir(dirPath)
if err != nil {
@@ -771,13 +774,6 @@ func isExistsScope(scope string) (bool, error) {
return strings.Contains(scope, scopeAttrPrefix), nil
}
// getSchemes parses swagger schemes for given commentLine.
func getSchemes(commentLine string) []string {
attribute := strings.ToLower(strings.Split(commentLine, " ")[0])
return strings.Split(strings.TrimSpace(commentLine[len(attribute):]), " ")
}
// ParseRouterAPIInfo parses router api info for given astFile.
func (parser *Parser) ParseRouterAPIInfo(fileName string, astFile *ast.File) error {
for _, astDescription := range astFile.Decls {
@@ -1365,7 +1361,7 @@ func replaceLastTag(slice []spec.Tag, element spec.Tag) {
slice = append(slice[:len(slice)-1], element)
}
// defineTypeOfExample example value define the type (object and array unsupported)
// defineTypeOfExample example value define the type (object and array unsupported).
func defineTypeOfExample(schemaType, arrayType, exampleValue string) (interface{}, error) {
switch schemaType {
case STRING:

View File

@@ -1,4 +1,4 @@
package swag
// Version of swag.
const Version = "v1.8.1"
const Version = "v1.8.3"