From bdcc5134b101498c84578c73e288e1922565392c Mon Sep 17 00:00:00 2001 From: ychao_1983 Date: Thu, 26 May 2022 17:08:44 +0800 Subject: [PATCH 001/562] phone verify --- go.mod | 11 +- go.sum | 50 + modules/phone/phone.go | 62 + modules/setting/phone.go | 44 + modules/setting/setting.go | 1 + .../alibabacloud-gateway-spi/LICENSE | 201 + .../alibabacloud-gateway-spi/client/client.go | 305 ++ .../alibabacloud-go/darabonba-openapi/LICENSE | 201 + .../darabonba-openapi/client/client.go | 1623 ++++++++ vendor/github.com/alibabacloud-go/debug/LICENSE | 201 + .../alibabacloud-go/debug/debug/assert.go | 12 + .../alibabacloud-go/debug/debug/debug.go | 36 + .../dysmsapi-20170525/v2/client/client.go | 4124 ++++++++++++++++++++ .../endpoint-util/service/service.go | 41 + .../alibabacloud-go/openapi-util/LICENSE | 201 + .../openapi-util/service/service.go | 635 +++ .../alibabacloud-go/tea-utils/service/service.go | 462 +++ .../alibabacloud-go/tea-utils/service/util.go | 52 + .../alibabacloud-go/tea-xml/service/service.go | 105 + vendor/github.com/alibabacloud-go/tea/LICENSE | 201 + .../alibabacloud-go/tea/tea/json_parser.go | 333 ++ vendor/github.com/alibabacloud-go/tea/tea/tea.go | 1121 ++++++ vendor/github.com/alibabacloud-go/tea/tea/trans.go | 491 +++ .../github.com/alibabacloud-go/tea/utils/assert.go | 64 + .../github.com/alibabacloud-go/tea/utils/logger.go | 109 + .../alibabacloud-go/tea/utils/progress.go | 60 + vendor/github.com/aliyun/credentials-go/LICENSE | 201 + .../credentials/access_key_credential.go | 41 + .../credentials/bearer_token_credential.go | 40 + .../credentials-go/credentials/credential.go | 349 ++ .../credentials/credential_updater.go | 25 + .../credentials-go/credentials/ecs_ram_role.go | 136 + .../credentials-go/credentials/env_provider.go | 43 + .../credentials/instance_provider.go | 28 + .../credentials-go/credentials/profile_provider.go | 350 ++ .../aliyun/credentials-go/credentials/provider.go | 13 + .../credentials-go/credentials/provider_chain.go | 32 + .../credentials/request/common_request.go | 59 + .../credentials/response/common_response.go | 53 + .../credentials/rsa_key_pair_credential.go | 145 + .../credentials/session_credential.go | 7 + .../credentials-go/credentials/sts_credential.go | 43 + .../credentials/sts_role_arn_credential.go | 163 + .../credentials-go/credentials/utils/runtime.go | 35 + .../credentials-go/credentials/utils/utils.go | 146 + vendor/github.com/clbanning/mxj/v2/.travis.yml | 4 + vendor/github.com/clbanning/mxj/v2/LICENSE | 22 + vendor/github.com/clbanning/mxj/v2/anyxml.go | 201 + .../github.com/clbanning/mxj/v2/atomFeedString.xml | 54 + vendor/github.com/clbanning/mxj/v2/doc.go | 138 + vendor/github.com/clbanning/mxj/v2/escapechars.go | 93 + vendor/github.com/clbanning/mxj/v2/exists.go | 9 + vendor/github.com/clbanning/mxj/v2/files.go | 287 ++ .../github.com/clbanning/mxj/v2/files_test.badjson | 2 + .../github.com/clbanning/mxj/v2/files_test.badxml | 9 + vendor/github.com/clbanning/mxj/v2/files_test.json | 2 + vendor/github.com/clbanning/mxj/v2/files_test.xml | 9 + .../clbanning/mxj/v2/files_test_dup.json | 1 + .../github.com/clbanning/mxj/v2/files_test_dup.xml | 1 + .../clbanning/mxj/v2/files_test_indent.json | 12 + .../clbanning/mxj/v2/files_test_indent.xml | 8 + vendor/github.com/clbanning/mxj/v2/go.mod | 3 + vendor/github.com/clbanning/mxj/v2/gob.go | 35 + vendor/github.com/clbanning/mxj/v2/json.go | 323 ++ vendor/github.com/clbanning/mxj/v2/keyvalues.go | 668 ++++ vendor/github.com/clbanning/mxj/v2/leafnode.go | 112 + vendor/github.com/clbanning/mxj/v2/misc.go | 86 + vendor/github.com/clbanning/mxj/v2/mxj.go | 128 + vendor/github.com/clbanning/mxj/v2/newmap.go | 184 + vendor/github.com/clbanning/mxj/v2/readme.md | 207 + vendor/github.com/clbanning/mxj/v2/remove.go | 37 + vendor/github.com/clbanning/mxj/v2/rename.go | 61 + vendor/github.com/clbanning/mxj/v2/set.go | 26 + vendor/github.com/clbanning/mxj/v2/setfieldsep.go | 20 + vendor/github.com/clbanning/mxj/v2/songtext.xml | 29 + vendor/github.com/clbanning/mxj/v2/strict.go | 30 + vendor/github.com/clbanning/mxj/v2/struct.go | 54 + vendor/github.com/clbanning/mxj/v2/updatevalues.go | 258 ++ vendor/github.com/clbanning/mxj/v2/xml.go | 1410 +++++++ vendor/github.com/clbanning/mxj/v2/xmlseq.go | 877 +++++ vendor/github.com/clbanning/mxj/v2/xmlseq2.go | 18 + vendor/github.com/json-iterator/go/README.md | 36 +- vendor/github.com/json-iterator/go/any_str.go | 4 +- vendor/github.com/json-iterator/go/config.go | 4 +- vendor/github.com/json-iterator/go/iter_object.go | 4 +- .../json-iterator/go/reflect_extension.go | 2 +- vendor/github.com/json-iterator/go/reflect_map.go | 80 +- .../json-iterator/go/reflect_optional.go | 4 - .../json-iterator/go/reflect_struct_decoder.go | 22 +- vendor/github.com/json-iterator/go/stream.go | 5 +- vendor/github.com/tjfoc/gmsm/LICENSE | 201 + vendor/github.com/tjfoc/gmsm/sm3/sm3.go | 260 ++ .../yuin/goldmark/extension/typographer.go | 7 +- .../github.com/yuin/goldmark/parser/atx_heading.go | 2 +- vendor/golang.org/x/sync/semaphore/semaphore.go | 11 +- vendor/gopkg.in/ini.v1/Makefile | 2 +- vendor/gopkg.in/ini.v1/README.md | 8 +- vendor/gopkg.in/ini.v1/codecov.yml | 9 + vendor/gopkg.in/ini.v1/data_source.go | 2 + vendor/gopkg.in/ini.v1/file.go | 153 +- vendor/gopkg.in/ini.v1/ini.go | 16 +- vendor/gopkg.in/ini.v1/key.go | 120 +- vendor/gopkg.in/ini.v1/parser.go | 21 +- vendor/gopkg.in/ini.v1/section.go | 4 +- vendor/gopkg.in/ini.v1/struct.go | 171 +- vendor/modules.txt | 43 +- 106 files changed, 19043 insertions(+), 221 deletions(-) create mode 100644 modules/phone/phone.go create mode 100644 modules/setting/phone.go create mode 100644 vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/LICENSE create mode 100644 vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/client/client.go create mode 100644 vendor/github.com/alibabacloud-go/darabonba-openapi/LICENSE create mode 100644 vendor/github.com/alibabacloud-go/darabonba-openapi/client/client.go create mode 100644 vendor/github.com/alibabacloud-go/debug/LICENSE create mode 100644 vendor/github.com/alibabacloud-go/debug/debug/assert.go create mode 100644 vendor/github.com/alibabacloud-go/debug/debug/debug.go create mode 100644 vendor/github.com/alibabacloud-go/dysmsapi-20170525/v2/client/client.go create mode 100644 vendor/github.com/alibabacloud-go/endpoint-util/service/service.go create mode 100644 vendor/github.com/alibabacloud-go/openapi-util/LICENSE create mode 100644 vendor/github.com/alibabacloud-go/openapi-util/service/service.go create mode 100644 vendor/github.com/alibabacloud-go/tea-utils/service/service.go create mode 100644 vendor/github.com/alibabacloud-go/tea-utils/service/util.go create mode 100644 vendor/github.com/alibabacloud-go/tea-xml/service/service.go create mode 100644 vendor/github.com/alibabacloud-go/tea/LICENSE create mode 100644 vendor/github.com/alibabacloud-go/tea/tea/json_parser.go create mode 100644 vendor/github.com/alibabacloud-go/tea/tea/tea.go create mode 100644 vendor/github.com/alibabacloud-go/tea/tea/trans.go create mode 100644 vendor/github.com/alibabacloud-go/tea/utils/assert.go create mode 100644 vendor/github.com/alibabacloud-go/tea/utils/logger.go create mode 100644 vendor/github.com/alibabacloud-go/tea/utils/progress.go create mode 100644 vendor/github.com/aliyun/credentials-go/LICENSE create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/access_key_credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/bearer_token_credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/credential_updater.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/ecs_ram_role.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/env_provider.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/instance_provider.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/profile_provider.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/provider.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/provider_chain.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/request/common_request.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/response/common_response.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/rsa_key_pair_credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/session_credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/sts_credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/sts_role_arn_credential.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/utils/runtime.go create mode 100644 vendor/github.com/aliyun/credentials-go/credentials/utils/utils.go create mode 100644 vendor/github.com/clbanning/mxj/v2/.travis.yml create mode 100644 vendor/github.com/clbanning/mxj/v2/LICENSE create mode 100644 vendor/github.com/clbanning/mxj/v2/anyxml.go create mode 100644 vendor/github.com/clbanning/mxj/v2/atomFeedString.xml create mode 100644 vendor/github.com/clbanning/mxj/v2/doc.go create mode 100644 vendor/github.com/clbanning/mxj/v2/escapechars.go create mode 100644 vendor/github.com/clbanning/mxj/v2/exists.go create mode 100644 vendor/github.com/clbanning/mxj/v2/files.go create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test.badjson create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test.badxml create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test.json create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test.xml create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test_dup.json create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test_dup.xml create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test_indent.json create mode 100644 vendor/github.com/clbanning/mxj/v2/files_test_indent.xml create mode 100644 vendor/github.com/clbanning/mxj/v2/go.mod create mode 100644 vendor/github.com/clbanning/mxj/v2/gob.go create mode 100644 vendor/github.com/clbanning/mxj/v2/json.go create mode 100644 vendor/github.com/clbanning/mxj/v2/keyvalues.go create mode 100644 vendor/github.com/clbanning/mxj/v2/leafnode.go create mode 100644 vendor/github.com/clbanning/mxj/v2/misc.go create mode 100644 vendor/github.com/clbanning/mxj/v2/mxj.go create mode 100644 vendor/github.com/clbanning/mxj/v2/newmap.go create mode 100644 vendor/github.com/clbanning/mxj/v2/readme.md create mode 100644 vendor/github.com/clbanning/mxj/v2/remove.go create mode 100644 vendor/github.com/clbanning/mxj/v2/rename.go create mode 100644 vendor/github.com/clbanning/mxj/v2/set.go create mode 100644 vendor/github.com/clbanning/mxj/v2/setfieldsep.go create mode 100644 vendor/github.com/clbanning/mxj/v2/songtext.xml create mode 100644 vendor/github.com/clbanning/mxj/v2/strict.go create mode 100644 vendor/github.com/clbanning/mxj/v2/struct.go create mode 100644 vendor/github.com/clbanning/mxj/v2/updatevalues.go create mode 100644 vendor/github.com/clbanning/mxj/v2/xml.go create mode 100644 vendor/github.com/clbanning/mxj/v2/xmlseq.go create mode 100644 vendor/github.com/clbanning/mxj/v2/xmlseq2.go create mode 100644 vendor/github.com/tjfoc/gmsm/LICENSE create mode 100644 vendor/github.com/tjfoc/gmsm/sm3/sm3.go create mode 100644 vendor/gopkg.in/ini.v1/codecov.yml diff --git a/go.mod b/go.mod index c1e959f8e..0a9d0226c 100755 --- a/go.mod +++ b/go.mod @@ -22,8 +22,13 @@ require ( github.com/PuerkitoBio/goquery v1.5.0 github.com/RichardKnop/machinery v1.6.9 github.com/RoaringBitmap/roaring v0.4.23 // indirect + github.com/alibabacloud-go/darabonba-openapi v0.1.18 + github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 + github.com/alibabacloud-go/tea v1.1.17 + github.com/alibabacloud-go/tea-xml v1.1.2 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/blevesearch/bleve v1.0.7 + github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 // indirect github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect @@ -112,9 +117,9 @@ require ( github.com/urfave/cli v1.22.1 github.com/xanzy/go-gitlab v0.31.0 github.com/yohcop/openid-go v1.0.0 - github.com/yuin/goldmark v1.1.27 + github.com/yuin/goldmark v1.1.30 github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 - golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 + golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/mod v0.3.0 // indirect golang.org/x/net v0.0.0-20200513185701-a91f0712d120 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d @@ -126,7 +131,7 @@ require ( gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - gopkg.in/ini.v1 v1.52.0 + gopkg.in/ini.v1 v1.56.0 gopkg.in/ldap.v3 v3.0.2 gopkg.in/macaron.v1 v1.3.9 // indirect gopkg.in/testfixtures.v2 v2.5.0 diff --git a/go.sum b/go.sum index d9dc14b64..9293fd947 100755 --- a/go.sum +++ b/go.sum @@ -78,6 +78,35 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBb github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= +github.com/alibabacloud-go/darabonba-openapi v0.1.18 h1:3eUVmAr7WCJp7fgIvmCd9ZUyuwtJYbtUqJIed5eXCmk= +github.com/alibabacloud-go/darabonba-openapi v0.1.18/go.mod h1:PB4HffMhJVmAgNKNq3wYbTUlFvPgxJpTzd1F5pTuUsc= +github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 h1:z+OU7LbWtQitWJ8SAn55hEQkJPCsEPJc97TvGCZV+4s= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9/go.mod h1:AT91gCNJPsemf4lHLNgWTf/RsgmpdOprWvQ3FYvtwGk= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.0.11 h1:iYnqOPR5hyEEnNZmebGyRMkkEJRWUEjDiiaOHZ5aNhA= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17 h1:05R5DnaJXe9sCNIe8KUgWHC/z6w/VZIwczgUwzRnul8= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.4.3 h1:8SzwmmRrOnQ09Hf5a9GyfJc0d7Sjv6fmsZoF4UDbFjo= +github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M= +github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= @@ -125,6 +154,8 @@ github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs= @@ -369,6 +400,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= @@ -432,6 +464,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -673,11 +707,13 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= @@ -707,6 +743,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= @@ -722,6 +759,8 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toqueteos/trie v1.0.0 h1:8i6pXxNUXNRAqP246iibb7w/pSFquNTQ+uNfriG7vlk= github.com/toqueteos/trie v1.0.0/go.mod h1:Ywk48QhEqhU1+DwhMkJ2x7eeGxDHiGkAdc9+0DYcbsM= @@ -761,6 +800,8 @@ github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30 h1:j4d4Lw3zqZelDhBksEo3BnWg9xhXRQGJPPSL6OApZjI= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo= github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60/go.mod h1:i9VhcIHN2PxXMbQrKqXNueok6QNONoPjNMoj9MygVL0= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -800,9 +841,12 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -848,6 +892,7 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -868,6 +913,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -933,6 +980,7 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ= golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1012,6 +1060,8 @@ gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/macaron.v1 v1.3.9 h1:Dw+DDRYdXgQyEsPlfAfKz+UA5qVUrH3KPD7JhmZ9MFc= diff --git a/modules/phone/phone.go b/modules/phone/phone.go new file mode 100644 index 000000000..eb5b58f5a --- /dev/null +++ b/modules/phone/phone.go @@ -0,0 +1,62 @@ +package phone + +import ( + "math" + "math/rand" + "regexp" + "strconv" + "time" + + "code.gitea.io/gitea/modules/setting" + + openapi "github.com/alibabacloud-go/darabonba-openapi/client" + dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v2/client" + util "github.com/alibabacloud-go/tea-utils/service" + "github.com/alibabacloud-go/tea/tea" +) + +func IsValidPhoneNumber(phoneNumber string) bool { + pattern := "^1[3-9]\\d{9}$" + match, _ := regexp.MatchString(pattern, phoneNumber) + return match +} + +func GenerateVerifyCode(n int) string { + min := int(math.Pow10(n - 1)) + max := int(math.Pow10(n)) + rand.Seed(time.Now().UnixNano()) + return strconv.Itoa(rand.Intn(max-min) + min) + +} + +func createClient(accessKeyId *string, accessKeySecret *string) (_result *dysmsapi20170525.Client, _err error) { + config := &openapi.Config{ + // 您的AccessKey ID + AccessKeyId: accessKeyId, + // 您的AccessKey Secret + AccessKeySecret: accessKeySecret, + } + // 访问的域名 + config.Endpoint = tea.String("dysmsapi.aliyuncs.com") + _result = &dysmsapi20170525.Client{} + _result, _err = dysmsapi20170525.NewClient(config) + return _result, _err +} + +func SendVerifyCode(phoneNumber string, verifyCode string) error { + client, _err := createClient(&setting.PhoneService.AccessKeyId, &setting.PhoneService.AccessKeySecret) + if _err != nil { + return _err + } + + sendSmsRequest := &dysmsapi20170525.SendSmsRequest{ + SignName: tea.String(setting.PhoneService.SignName), + TemplateCode: tea.String(setting.PhoneService.TemplateCode), + PhoneNumbers: tea.String(phoneNumber), + TemplateParam: tea.String("{\"code\":\"" + verifyCode + "\"}"), + } + runtime := &util.RuntimeOptions{} + // 复制代码运行请自行打印 API 的返回值 + _, _err = client.SendSmsWithOptions(sendSmsRequest, runtime) + return _err +} diff --git a/modules/setting/phone.go b/modules/setting/phone.go new file mode 100644 index 000000000..37f9d6c26 --- /dev/null +++ b/modules/setting/phone.go @@ -0,0 +1,44 @@ +package setting + +import ( + "code.gitea.io/gitea/modules/log" +) + +type Phone struct { + Enabled bool + VerifyCodeLength int + AccessKeyId string + AccessKeySecret string + SignName string + TemplateCode string + CodeTimeout int + RetryInterval int + MaxRetryTimes int +} + +var ( + // Phone verify info + PhoneService *Phone +) + +func newPhoneService() { + sec := Cfg.Section("phone") + // Check phone setting. + if !sec.Key("ENABLED").MustBool() { + return + } + + PhoneService = &Phone{ + Enabled: sec.Key("ENABLED").MustBool(), + VerifyCodeLength: sec.Key("VERIFY_CODE_LEN").MustInt(6), + AccessKeyId: sec.Key("AccessKeyId").String(), + AccessKeySecret: sec.Key("AccessKeySecret").String(), + SignName: sec.Key("SignName").String(), + TemplateCode: sec.Key("TemplateCode").String(), + CodeTimeout: sec.Key("CODE_TIMEOUT").MustInt(60 * 5), + RetryInterval: sec.Key("RETRY_INTERVAL").MustInt(60 * 2), + MaxRetryTimes: sec.Key("MAX_RETRY").MustInt(5), + } + + log.Info("Phone Service Enabled") +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 5c87b68c5..6bdf299af 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1519,4 +1519,5 @@ func NewServices() { newIndexerService() newTaskService() NewQueueService() + newPhoneService() } diff --git a/vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/LICENSE b/vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/LICENSE new file mode 100644 index 000000000..0c44dcefe --- /dev/null +++ b/vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/client/client.go b/vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/client/client.go new file mode 100644 index 000000000..1d47c93aa --- /dev/null +++ b/vendor/github.com/alibabacloud-go/alibabacloud-gateway-spi/client/client.go @@ -0,0 +1,305 @@ +// This file is auto-generated, don't edit it. Thanks. +package client + +import ( + "io" + + "github.com/alibabacloud-go/tea/tea" + credential "github.com/aliyun/credentials-go/credentials" +) + +type InterceptorContext struct { + Request *InterceptorContextRequest `json:"request,omitempty" xml:"request,omitempty" require:"true" type:"Struct"` + Configuration *InterceptorContextConfiguration `json:"configuration,omitempty" xml:"configuration,omitempty" require:"true" type:"Struct"` + Response *InterceptorContextResponse `json:"response,omitempty" xml:"response,omitempty" require:"true" type:"Struct"` +} + +func (s InterceptorContext) String() string { + return tea.Prettify(s) +} + +func (s InterceptorContext) GoString() string { + return s.String() +} + +func (s *InterceptorContext) SetRequest(v *InterceptorContextRequest) *InterceptorContext { + s.Request = v + return s +} + +func (s *InterceptorContext) SetConfiguration(v *InterceptorContextConfiguration) *InterceptorContext { + s.Configuration = v + return s +} + +func (s *InterceptorContext) SetResponse(v *InterceptorContextResponse) *InterceptorContext { + s.Response = v + return s +} + +type InterceptorContextRequest struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty"` + Query map[string]*string `json:"query,omitempty" xml:"query,omitempty"` + Body interface{} `json:"body,omitempty" xml:"body,omitempty"` + Stream io.Reader `json:"stream,omitempty" xml:"stream,omitempty"` + HostMap map[string]*string `json:"hostMap,omitempty" xml:"hostMap,omitempty"` + Pathname *string `json:"pathname,omitempty" xml:"pathname,omitempty" require:"true"` + ProductId *string `json:"productId,omitempty" xml:"productId,omitempty" require:"true"` + Action *string `json:"action,omitempty" xml:"action,omitempty" require:"true"` + Version *string `json:"version,omitempty" xml:"version,omitempty" require:"true"` + Protocol *string `json:"protocol,omitempty" xml:"protocol,omitempty" require:"true"` + Method *string `json:"method,omitempty" xml:"method,omitempty" require:"true"` + AuthType *string `json:"authType,omitempty" xml:"authType,omitempty" require:"true"` + BodyType *string `json:"bodyType,omitempty" xml:"bodyType,omitempty" require:"true"` + ReqBodyType *string `json:"reqBodyType,omitempty" xml:"reqBodyType,omitempty" require:"true"` + Style *string `json:"style,omitempty" xml:"style,omitempty"` + Credential credential.Credential `json:"credential,omitempty" xml:"credential,omitempty" require:"true"` + SignatureVersion *string `json:"signatureVersion,omitempty" xml:"signatureVersion,omitempty"` + SignatureAlgorithm *string `json:"signatureAlgorithm,omitempty" xml:"signatureAlgorithm,omitempty"` + UserAgent *string `json:"userAgent,omitempty" xml:"userAgent,omitempty" require:"true"` +} + +func (s InterceptorContextRequest) String() string { + return tea.Prettify(s) +} + +func (s InterceptorContextRequest) GoString() string { + return s.String() +} + +func (s *InterceptorContextRequest) SetHeaders(v map[string]*string) *InterceptorContextRequest { + s.Headers = v + return s +} + +func (s *InterceptorContextRequest) SetQuery(v map[string]*string) *InterceptorContextRequest { + s.Query = v + return s +} + +func (s *InterceptorContextRequest) SetBody(v interface{}) *InterceptorContextRequest { + s.Body = v + return s +} + +func (s *InterceptorContextRequest) SetStream(v io.Reader) *InterceptorContextRequest { + s.Stream = v + return s +} + +func (s *InterceptorContextRequest) SetHostMap(v map[string]*string) *InterceptorContextRequest { + s.HostMap = v + return s +} + +func (s *InterceptorContextRequest) SetPathname(v string) *InterceptorContextRequest { + s.Pathname = &v + return s +} + +func (s *InterceptorContextRequest) SetProductId(v string) *InterceptorContextRequest { + s.ProductId = &v + return s +} + +func (s *InterceptorContextRequest) SetAction(v string) *InterceptorContextRequest { + s.Action = &v + return s +} + +func (s *InterceptorContextRequest) SetVersion(v string) *InterceptorContextRequest { + s.Version = &v + return s +} + +func (s *InterceptorContextRequest) SetProtocol(v string) *InterceptorContextRequest { + s.Protocol = &v + return s +} + +func (s *InterceptorContextRequest) SetMethod(v string) *InterceptorContextRequest { + s.Method = &v + return s +} + +func (s *InterceptorContextRequest) SetAuthType(v string) *InterceptorContextRequest { + s.AuthType = &v + return s +} + +func (s *InterceptorContextRequest) SetBodyType(v string) *InterceptorContextRequest { + s.BodyType = &v + return s +} + +func (s *InterceptorContextRequest) SetReqBodyType(v string) *InterceptorContextRequest { + s.ReqBodyType = &v + return s +} + +func (s *InterceptorContextRequest) SetStyle(v string) *InterceptorContextRequest { + s.Style = &v + return s +} + +func (s *InterceptorContextRequest) SetCredential(v credential.Credential) *InterceptorContextRequest { + s.Credential = v + return s +} + +func (s *InterceptorContextRequest) SetSignatureVersion(v string) *InterceptorContextRequest { + s.SignatureVersion = &v + return s +} + +func (s *InterceptorContextRequest) SetSignatureAlgorithm(v string) *InterceptorContextRequest { + s.SignatureAlgorithm = &v + return s +} + +func (s *InterceptorContextRequest) SetUserAgent(v string) *InterceptorContextRequest { + s.UserAgent = &v + return s +} + +type InterceptorContextConfiguration struct { + RegionId *string `json:"regionId,omitempty" xml:"regionId,omitempty" require:"true"` + Endpoint *string `json:"endpoint,omitempty" xml:"endpoint,omitempty"` + EndpointRule *string `json:"endpointRule,omitempty" xml:"endpointRule,omitempty"` + EndpointMap map[string]*string `json:"endpointMap,omitempty" xml:"endpointMap,omitempty"` + EndpointType *string `json:"endpointType,omitempty" xml:"endpointType,omitempty"` + Network *string `json:"network,omitempty" xml:"network,omitempty"` + Suffix *string `json:"suffix,omitempty" xml:"suffix,omitempty"` +} + +func (s InterceptorContextConfiguration) String() string { + return tea.Prettify(s) +} + +func (s InterceptorContextConfiguration) GoString() string { + return s.String() +} + +func (s *InterceptorContextConfiguration) SetRegionId(v string) *InterceptorContextConfiguration { + s.RegionId = &v + return s +} + +func (s *InterceptorContextConfiguration) SetEndpoint(v string) *InterceptorContextConfiguration { + s.Endpoint = &v + return s +} + +func (s *InterceptorContextConfiguration) SetEndpointRule(v string) *InterceptorContextConfiguration { + s.EndpointRule = &v + return s +} + +func (s *InterceptorContextConfiguration) SetEndpointMap(v map[string]*string) *InterceptorContextConfiguration { + s.EndpointMap = v + return s +} + +func (s *InterceptorContextConfiguration) SetEndpointType(v string) *InterceptorContextConfiguration { + s.EndpointType = &v + return s +} + +func (s *InterceptorContextConfiguration) SetNetwork(v string) *InterceptorContextConfiguration { + s.Network = &v + return s +} + +func (s *InterceptorContextConfiguration) SetSuffix(v string) *InterceptorContextConfiguration { + s.Suffix = &v + return s +} + +type InterceptorContextResponse struct { + StatusCode *int `json:"statusCode,omitempty" xml:"statusCode,omitempty"` + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty"` + Body io.Reader `json:"body,omitempty" xml:"body,omitempty"` + DeserializedBody interface{} `json:"deserializedBody,omitempty" xml:"deserializedBody,omitempty"` +} + +func (s InterceptorContextResponse) String() string { + return tea.Prettify(s) +} + +func (s InterceptorContextResponse) GoString() string { + return s.String() +} + +func (s *InterceptorContextResponse) SetStatusCode(v int) *InterceptorContextResponse { + s.StatusCode = &v + return s +} + +func (s *InterceptorContextResponse) SetHeaders(v map[string]*string) *InterceptorContextResponse { + s.Headers = v + return s +} + +func (s *InterceptorContextResponse) SetBody(v io.Reader) *InterceptorContextResponse { + s.Body = v + return s +} + +func (s *InterceptorContextResponse) SetDeserializedBody(v interface{}) *InterceptorContextResponse { + s.DeserializedBody = v + return s +} + +type AttributeMap struct { + Attributes map[string]interface{} `json:"attributes,omitempty" xml:"attributes,omitempty" require:"true"` + Key map[string]*string `json:"key,omitempty" xml:"key,omitempty" require:"true"` +} + +func (s AttributeMap) String() string { + return tea.Prettify(s) +} + +func (s AttributeMap) GoString() string { + return s.String() +} + +func (s *AttributeMap) SetAttributes(v map[string]interface{}) *AttributeMap { + s.Attributes = v + return s +} + +func (s *AttributeMap) SetKey(v map[string]*string) *AttributeMap { + s.Key = v + return s +} + +type ClientInterface interface { + ModifyConfiguration(context *InterceptorContext, attributeMap *AttributeMap) error + ModifyRequest(context *InterceptorContext, attributeMap *AttributeMap) error + ModifyResponse(context *InterceptorContext, attributeMap *AttributeMap) error +} + +type Client struct { +} + +func NewClient() (*Client, error) { + client := new(Client) + err := client.Init() + return client, err +} + +func (client *Client) Init() (_err error) { + return nil +} + +func (client *Client) ModifyConfiguration(context *InterceptorContext, attributeMap *AttributeMap) (_err error) { + panic("No Support!") +} + +func (client *Client) ModifyRequest(context *InterceptorContext, attributeMap *AttributeMap) (_err error) { + panic("No Support!") +} + +func (client *Client) ModifyResponse(context *InterceptorContext, attributeMap *AttributeMap) (_err error) { + panic("No Support!") +} diff --git a/vendor/github.com/alibabacloud-go/darabonba-openapi/LICENSE b/vendor/github.com/alibabacloud-go/darabonba-openapi/LICENSE new file mode 100644 index 000000000..0c44dcefe --- /dev/null +++ b/vendor/github.com/alibabacloud-go/darabonba-openapi/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/alibabacloud-go/darabonba-openapi/client/client.go b/vendor/github.com/alibabacloud-go/darabonba-openapi/client/client.go new file mode 100644 index 000000000..6da3e1fdd --- /dev/null +++ b/vendor/github.com/alibabacloud-go/darabonba-openapi/client/client.go @@ -0,0 +1,1623 @@ +// This file is auto-generated, don't edit it. Thanks. +/** + * This is for OpenApi SDK + */ +package client + +import ( + "io" + + spi "github.com/alibabacloud-go/alibabacloud-gateway-spi/client" + openapiutil "github.com/alibabacloud-go/openapi-util/service" + util "github.com/alibabacloud-go/tea-utils/service" + xml "github.com/alibabacloud-go/tea-xml/service" + "github.com/alibabacloud-go/tea/tea" + credential "github.com/aliyun/credentials-go/credentials" +) + +/** + * Model for initing client + */ +type Config struct { + // accesskey id + AccessKeyId *string `json:"accessKeyId,omitempty" xml:"accessKeyId,omitempty"` + // accesskey secret + AccessKeySecret *string `json:"accessKeySecret,omitempty" xml:"accessKeySecret,omitempty"` + // security token + SecurityToken *string `json:"securityToken,omitempty" xml:"securityToken,omitempty"` + // http protocol + Protocol *string `json:"protocol,omitempty" xml:"protocol,omitempty"` + // http method + Method *string `json:"method,omitempty" xml:"method,omitempty"` + // region id + RegionId *string `json:"regionId,omitempty" xml:"regionId,omitempty"` + // read timeout + ReadTimeout *int `json:"readTimeout,omitempty" xml:"readTimeout,omitempty"` + // connect timeout + ConnectTimeout *int `json:"connectTimeout,omitempty" xml:"connectTimeout,omitempty"` + // http proxy + HttpProxy *string `json:"httpProxy,omitempty" xml:"httpProxy,omitempty"` + // https proxy + HttpsProxy *string `json:"httpsProxy,omitempty" xml:"httpsProxy,omitempty"` + // credential + Credential credential.Credential `json:"credential,omitempty" xml:"credential,omitempty"` + // endpoint + Endpoint *string `json:"endpoint,omitempty" xml:"endpoint,omitempty"` + // proxy white list + NoProxy *string `json:"noProxy,omitempty" xml:"noProxy,omitempty"` + // max idle conns + MaxIdleConns *int `json:"maxIdleConns,omitempty" xml:"maxIdleConns,omitempty"` + // network for endpoint + Network *string `json:"network,omitempty" xml:"network,omitempty"` + // user agent + UserAgent *string `json:"userAgent,omitempty" xml:"userAgent,omitempty"` + // suffix for endpoint + Suffix *string `json:"suffix,omitempty" xml:"suffix,omitempty"` + // socks5 proxy + Socks5Proxy *string `json:"socks5Proxy,omitempty" xml:"socks5Proxy,omitempty"` + // socks5 network + Socks5NetWork *string `json:"socks5NetWork,omitempty" xml:"socks5NetWork,omitempty"` + // endpoint type + EndpointType *string `json:"endpointType,omitempty" xml:"endpointType,omitempty"` + // OpenPlatform endpoint + OpenPlatformEndpoint *string `json:"openPlatformEndpoint,omitempty" xml:"openPlatformEndpoint,omitempty"` + // Deprecated + // credential type + Type *string `json:"type,omitempty" xml:"type,omitempty"` + // Signature Version + SignatureVersion *string `json:"signatureVersion,omitempty" xml:"signatureVersion,omitempty"` + // Signature Algorithm + SignatureAlgorithm *string `json:"signatureAlgorithm,omitempty" xml:"signatureAlgorithm,omitempty"` +} + +func (s Config) String() string { + return tea.Prettify(s) +} + +func (s Config) GoString() string { + return s.String() +} + +func (s *Config) SetAccessKeyId(v string) *Config { + s.AccessKeyId = &v + return s +} + +func (s *Config) SetAccessKeySecret(v string) *Config { + s.AccessKeySecret = &v + return s +} + +func (s *Config) SetSecurityToken(v string) *Config { + s.SecurityToken = &v + return s +} + +func (s *Config) SetProtocol(v string) *Config { + s.Protocol = &v + return s +} + +func (s *Config) SetMethod(v string) *Config { + s.Method = &v + return s +} + +func (s *Config) SetRegionId(v string) *Config { + s.RegionId = &v + return s +} + +func (s *Config) SetReadTimeout(v int) *Config { + s.ReadTimeout = &v + return s +} + +func (s *Config) SetConnectTimeout(v int) *Config { + s.ConnectTimeout = &v + return s +} + +func (s *Config) SetHttpProxy(v string) *Config { + s.HttpProxy = &v + return s +} + +func (s *Config) SetHttpsProxy(v string) *Config { + s.HttpsProxy = &v + return s +} + +func (s *Config) SetCredential(v credential.Credential) *Config { + s.Credential = v + return s +} + +func (s *Config) SetEndpoint(v string) *Config { + s.Endpoint = &v + return s +} + +func (s *Config) SetNoProxy(v string) *Config { + s.NoProxy = &v + return s +} + +func (s *Config) SetMaxIdleConns(v int) *Config { + s.MaxIdleConns = &v + return s +} + +func (s *Config) SetNetwork(v string) *Config { + s.Network = &v + return s +} + +func (s *Config) SetUserAgent(v string) *Config { + s.UserAgent = &v + return s +} + +func (s *Config) SetSuffix(v string) *Config { + s.Suffix = &v + return s +} + +func (s *Config) SetSocks5Proxy(v string) *Config { + s.Socks5Proxy = &v + return s +} + +func (s *Config) SetSocks5NetWork(v string) *Config { + s.Socks5NetWork = &v + return s +} + +func (s *Config) SetEndpointType(v string) *Config { + s.EndpointType = &v + return s +} + +func (s *Config) SetOpenPlatformEndpoint(v string) *Config { + s.OpenPlatformEndpoint = &v + return s +} + +func (s *Config) SetType(v string) *Config { + s.Type = &v + return s +} + +func (s *Config) SetSignatureVersion(v string) *Config { + s.SignatureVersion = &v + return s +} + +func (s *Config) SetSignatureAlgorithm(v string) *Config { + s.SignatureAlgorithm = &v + return s +} + +type OpenApiRequest struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty"` + Query map[string]*string `json:"query,omitempty" xml:"query,omitempty"` + Body interface{} `json:"body,omitempty" xml:"body,omitempty"` + Stream io.Reader `json:"stream,omitempty" xml:"stream,omitempty"` + HostMap map[string]*string `json:"hostMap,omitempty" xml:"hostMap,omitempty"` + EndpointOverride *string `json:"endpointOverride,omitempty" xml:"endpointOverride,omitempty"` +} + +func (s OpenApiRequest) String() string { + return tea.Prettify(s) +} + +func (s OpenApiRequest) GoString() string { + return s.String() +} + +func (s *OpenApiRequest) SetHeaders(v map[string]*string) *OpenApiRequest { + s.Headers = v + return s +} + +func (s *OpenApiRequest) SetQuery(v map[string]*string) *OpenApiRequest { + s.Query = v + return s +} + +func (s *OpenApiRequest) SetBody(v interface{}) *OpenApiRequest { + s.Body = v + return s +} + +func (s *OpenApiRequest) SetStream(v io.Reader) *OpenApiRequest { + s.Stream = v + return s +} + +func (s *OpenApiRequest) SetHostMap(v map[string]*string) *OpenApiRequest { + s.HostMap = v + return s +} + +func (s *OpenApiRequest) SetEndpointOverride(v string) *OpenApiRequest { + s.EndpointOverride = &v + return s +} + +type Params struct { + Action *string `json:"action,omitempty" xml:"action,omitempty" require:"true"` + Version *string `json:"version,omitempty" xml:"version,omitempty" require:"true"` + Protocol *string `json:"protocol,omitempty" xml:"protocol,omitempty" require:"true"` + Pathname *string `json:"pathname,omitempty" xml:"pathname,omitempty" require:"true"` + Method *string `json:"method,omitempty" xml:"method,omitempty" require:"true"` + AuthType *string `json:"authType,omitempty" xml:"authType,omitempty" require:"true"` + BodyType *string `json:"bodyType,omitempty" xml:"bodyType,omitempty" require:"true"` + ReqBodyType *string `json:"reqBodyType,omitempty" xml:"reqBodyType,omitempty" require:"true"` + Style *string `json:"style,omitempty" xml:"style,omitempty"` +} + +func (s Params) String() string { + return tea.Prettify(s) +} + +func (s Params) GoString() string { + return s.String() +} + +func (s *Params) SetAction(v string) *Params { + s.Action = &v + return s +} + +func (s *Params) SetVersion(v string) *Params { + s.Version = &v + return s +} + +func (s *Params) SetProtocol(v string) *Params { + s.Protocol = &v + return s +} + +func (s *Params) SetPathname(v string) *Params { + s.Pathname = &v + return s +} + +func (s *Params) SetMethod(v string) *Params { + s.Method = &v + return s +} + +func (s *Params) SetAuthType(v string) *Params { + s.AuthType = &v + return s +} + +func (s *Params) SetBodyType(v string) *Params { + s.BodyType = &v + return s +} + +func (s *Params) SetReqBodyType(v string) *Params { + s.ReqBodyType = &v + return s +} + +func (s *Params) SetStyle(v string) *Params { + s.Style = &v + return s +} + +type Client struct { + Endpoint *string + RegionId *string + Protocol *string + Method *string + UserAgent *string + EndpointRule *string + EndpointMap map[string]*string + Suffix *string + ReadTimeout *int + ConnectTimeout *int + HttpProxy *string + HttpsProxy *string + Socks5Proxy *string + Socks5NetWork *string + NoProxy *string + Network *string + ProductId *string + MaxIdleConns *int + EndpointType *string + OpenPlatformEndpoint *string + Credential credential.Credential + SignatureVersion *string + SignatureAlgorithm *string + Headers map[string]*string + Spi spi.ClientInterface +} + +/** + * Init client with Config + * @param config config contains the necessary information to create a client + */ +func NewClient(config *Config) (*Client, error) { + client := new(Client) + err := client.Init(config) + return client, err +} + +func (client *Client) Init(config *Config) (_err error) { + if tea.BoolValue(util.IsUnset(tea.ToMap(config))) { + _err = tea.NewSDKError(map[string]interface{}{ + "code": "ParameterMissing", + "message": "'config' can not be unset", + }) + return _err + } + + if !tea.BoolValue(util.Empty(config.AccessKeyId)) && !tea.BoolValue(util.Empty(config.AccessKeySecret)) { + if !tea.BoolValue(util.Empty(config.SecurityToken)) { + config.Type = tea.String("sts") + } else { + config.Type = tea.String("access_key") + } + + credentialConfig := &credential.Config{ + AccessKeyId: config.AccessKeyId, + Type: config.Type, + AccessKeySecret: config.AccessKeySecret, + SecurityToken: config.SecurityToken, + } + client.Credential, _err = credential.NewCredential(credentialConfig) + if _err != nil { + return _err + } + + } else if !tea.BoolValue(util.IsUnset(config.Credential)) { + client.Credential = config.Credential + } + + client.Endpoint = config.Endpoint + client.EndpointType = config.EndpointType + client.Network = config.Network + client.Suffix = config.Suffix + client.Protocol = config.Protocol + client.Method = config.Method + client.RegionId = config.RegionId + client.UserAgent = config.UserAgent + client.ReadTimeout = config.ReadTimeout + client.ConnectTimeout = config.ConnectTimeout + client.HttpProxy = config.HttpProxy + client.HttpsProxy = config.HttpsProxy + client.NoProxy = config.NoProxy + client.Socks5Proxy = config.Socks5Proxy + client.Socks5NetWork = config.Socks5NetWork + client.MaxIdleConns = config.MaxIdleConns + client.SignatureVersion = config.SignatureVersion + client.SignatureAlgorithm = config.SignatureAlgorithm + return nil +} + +/** + * Encapsulate the request and invoke the network + * @param action api name + * @param version product version + * @param protocol http or https + * @param method e.g. GET + * @param authType authorization type e.g. AK + * @param bodyType response body type e.g. String + * @param request object of OpenApiRequest + * @param runtime which controls some details of call api, such as retry times + * @return the response + */ +func (client *Client) DoRPCRequest(action *string, version *string, protocol *string, method *string, authType *string, bodyType *string, request *OpenApiRequest, runtime *util.RuntimeOptions) (_result map[string]interface{}, _err error) { + _err = tea.Validate(request) + if _err != nil { + return _result, _err + } + _err = tea.Validate(runtime) + if _err != nil { + return _result, _err + } + _runtime := map[string]interface{}{ + "timeouted": "retry", + "readTimeout": tea.IntValue(util.DefaultNumber(runtime.ReadTimeout, client.ReadTimeout)), + "connectTimeout": tea.IntValue(util.DefaultNumber(runtime.ConnectTimeout, client.ConnectTimeout)), + "httpProxy": tea.StringValue(util.DefaultString(runtime.HttpProxy, client.HttpProxy)), + "httpsProxy": tea.StringValue(util.DefaultString(runtime.HttpsProxy, client.HttpsProxy)), + "noProxy": tea.StringValue(util.DefaultString(runtime.NoProxy, client.NoProxy)), + "socks5Proxy": tea.StringValue(util.DefaultString(runtime.Socks5Proxy, client.Socks5Proxy)), + "socks5NetWork": tea.StringValue(util.DefaultString(runtime.Socks5NetWork, client.Socks5NetWork)), + "maxIdleConns": tea.IntValue(util.DefaultNumber(runtime.MaxIdleConns, client.MaxIdleConns)), + "retry": map[string]interface{}{ + "retryable": tea.BoolValue(runtime.Autoretry), + "maxAttempts": tea.IntValue(util.DefaultNumber(runtime.MaxAttempts, tea.Int(3))), + }, + "backoff": map[string]interface{}{ + "policy": tea.StringValue(util.DefaultString(runtime.BackoffPolicy, tea.String("no"))), + "period": tea.IntValue(util.DefaultNumber(runtime.BackoffPeriod, tea.Int(1))), + }, + "ignoreSSL": tea.BoolValue(runtime.IgnoreSSL), + } + + _resp := make(map[string]interface{}) + for _retryTimes := 0; tea.BoolValue(tea.AllowRetry(_runtime["retry"], tea.Int(_retryTimes))); _retryTimes++ { + if _retryTimes > 0 { + _backoffTime := tea.GetBackoffTime(_runtime["backoff"], tea.Int(_retryTimes)) + if tea.IntValue(_backoffTime) > 0 { + tea.Sleep(_backoffTime) + } + } + + _resp, _err = func() (map[string]interface{}, error) { + request_ := tea.NewRequest() + request_.Protocol = util.DefaultString(client.Protocol, protocol) + request_.Method = method + request_.Pathname = tea.String("/") + request_.Query = tea.Merge(map[string]*string{ + "Action": action, + "Format": tea.String("json"), + "Version": version, + "Timestamp": openapiutil.GetTimestamp(), + "SignatureNonce": util.GetNonce(), + }, request.Query) + headers, _err := client.GetRpcHeaders() + if _err != nil { + return _result, _err + } + + if tea.BoolValue(util.IsUnset(headers)) { + // endpoint is setted in product client + request_.Headers = map[string]*string{ + "host": client.Endpoint, + "x-acs-version": version, + "x-acs-action": action, + "user-agent": client.GetUserAgent(), + } + } else { + request_.Headers = tea.Merge(map[string]*string{ + "host": client.Endpoint, + "x-acs-version": version, + "x-acs-action": action, + "user-agent": client.GetUserAgent(), + }, headers) + } + + if !tea.BoolValue(util.IsUnset(request.Body)) { + m := util.AssertAsMap(request.Body) + tmp := util.AnyifyMapValue(openapiutil.Query(m)) + request_.Body = tea.ToReader(util.ToFormString(tmp)) + request_.Headers["content-type"] = tea.String("application/x-www-form-urlencoded") + } + + if !tea.BoolValue(util.EqualString(authType, tea.String("Anonymous"))) { + accessKeyId, _err := client.GetAccessKeyId() + if _err != nil { + return _result, _err + } + + accessKeySecret, _err := client.GetAccessKeySecret() + if _err != nil { + return _result, _err + } + + securityToken, _err := client.GetSecurityToken() + if _err != nil { + return _result, _err + } + + if !tea.BoolValue(util.Empty(securityToken)) { + request_.Query["SecurityToken"] = securityToken + } + + request_.Query["SignatureMethod"] = tea.String("HMAC-SHA1") + request_.Query["SignatureVersion"] = tea.String("1.0") + request_.Query["AccessKeyId"] = accessKeyId + var t map[string]interface{} + if !tea.BoolValue(util.IsUnset(request.Body)) { + t = util.AssertAsMap(request.Body) + } + + signedParam := tea.Merge(request_.Query, + openapiutil.Query(t)) + request_.Query["Signature"] = openapiutil.GetRPCSignature(signedParam, request_.Method, accessKeySecret) + } + + response_, _err := tea.DoRequest(request_, _runtime) + if _err != nil { + return _result, _err + } + if tea.BoolValue(util.Is4xx(response_.StatusCode)) || tea.BoolValue(util.Is5xx(response_.StatusCode)) { + _res, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + err := util.AssertAsMap(_res) + requestId := DefaultAny(err["RequestId"], err["requestId"]) + _err = tea.NewSDKError(map[string]interface{}{ + "code": tea.ToString(DefaultAny(err["Code"], err["code"])), + "message": "code: " + tea.ToString(tea.IntValue(response_.StatusCode)) + ", " + tea.ToString(DefaultAny(err["Message"], err["message"])) + " request id: " + tea.ToString(requestId), + "data": err, + }) + return _result, _err + } + + if tea.BoolValue(util.EqualString(bodyType, tea.String("binary"))) { + resp := map[string]interface{}{ + "body": response_.Body, + "headers": response_.Headers, + } + _result = resp + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("byte"))) { + byt, _err := util.ReadAsBytes(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": byt, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("string"))) { + str, _err := util.ReadAsString(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": tea.StringValue(str), + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("json"))) { + obj, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + res := util.AssertAsMap(obj) + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": res, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("array"))) { + arr, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": arr, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else { + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]map[string]*string{ + "headers": response_.Headers, + }, &_result) + return _result, _err + } + + }() + if !tea.BoolValue(tea.Retryable(_err)) { + break + } + } + + return _resp, _err +} + +/** + * Encapsulate the request and invoke the network + * @param action api name + * @param version product version + * @param protocol http or https + * @param method e.g. GET + * @param authType authorization type e.g. AK + * @param pathname pathname of every api + * @param bodyType response body type e.g. String + * @param request object of OpenApiRequest + * @param runtime which controls some details of call api, such as retry times + * @return the response + */ +func (client *Client) DoROARequest(action *string, version *string, protocol *string, method *string, authType *string, pathname *string, bodyType *string, request *OpenApiRequest, runtime *util.RuntimeOptions) (_result map[string]interface{}, _err error) { + _err = tea.Validate(request) + if _err != nil { + return _result, _err + } + _err = tea.Validate(runtime) + if _err != nil { + return _result, _err + } + _runtime := map[string]interface{}{ + "timeouted": "retry", + "readTimeout": tea.IntValue(util.DefaultNumber(runtime.ReadTimeout, client.ReadTimeout)), + "connectTimeout": tea.IntValue(util.DefaultNumber(runtime.ConnectTimeout, client.ConnectTimeout)), + "httpProxy": tea.StringValue(util.DefaultString(runtime.HttpProxy, client.HttpProxy)), + "httpsProxy": tea.StringValue(util.DefaultString(runtime.HttpsProxy, client.HttpsProxy)), + "noProxy": tea.StringValue(util.DefaultString(runtime.NoProxy, client.NoProxy)), + "socks5Proxy": tea.StringValue(util.DefaultString(runtime.Socks5Proxy, client.Socks5Proxy)), + "socks5NetWork": tea.StringValue(util.DefaultString(runtime.Socks5NetWork, client.Socks5NetWork)), + "maxIdleConns": tea.IntValue(util.DefaultNumber(runtime.MaxIdleConns, client.MaxIdleConns)), + "retry": map[string]interface{}{ + "retryable": tea.BoolValue(runtime.Autoretry), + "maxAttempts": tea.IntValue(util.DefaultNumber(runtime.MaxAttempts, tea.Int(3))), + }, + "backoff": map[string]interface{}{ + "policy": tea.StringValue(util.DefaultString(runtime.BackoffPolicy, tea.String("no"))), + "period": tea.IntValue(util.DefaultNumber(runtime.BackoffPeriod, tea.Int(1))), + }, + "ignoreSSL": tea.BoolValue(runtime.IgnoreSSL), + } + + _resp := make(map[string]interface{}) + for _retryTimes := 0; tea.BoolValue(tea.AllowRetry(_runtime["retry"], tea.Int(_retryTimes))); _retryTimes++ { + if _retryTimes > 0 { + _backoffTime := tea.GetBackoffTime(_runtime["backoff"], tea.Int(_retryTimes)) + if tea.IntValue(_backoffTime) > 0 { + tea.Sleep(_backoffTime) + } + } + + _resp, _err = func() (map[string]interface{}, error) { + request_ := tea.NewRequest() + request_.Protocol = util.DefaultString(client.Protocol, protocol) + request_.Method = method + request_.Pathname = pathname + request_.Headers = tea.Merge(map[string]*string{ + "date": util.GetDateUTCString(), + "host": client.Endpoint, + "accept": tea.String("application/json"), + "x-acs-signature-nonce": util.GetNonce(), + "x-acs-signature-method": tea.String("HMAC-SHA1"), + "x-acs-signature-version": tea.String("1.0"), + "x-acs-version": version, + "x-acs-action": action, + "user-agent": util.GetUserAgent(client.UserAgent), + }, request.Headers) + if !tea.BoolValue(util.IsUnset(request.Body)) { + request_.Body = tea.ToReader(util.ToJSONString(request.Body)) + request_.Headers["content-type"] = tea.String("application/json; charset=utf-8") + } + + if !tea.BoolValue(util.IsUnset(request.Query)) { + request_.Query = request.Query + } + + if !tea.BoolValue(util.EqualString(authType, tea.String("Anonymous"))) { + accessKeyId, _err := client.GetAccessKeyId() + if _err != nil { + return _result, _err + } + + accessKeySecret, _err := client.GetAccessKeySecret() + if _err != nil { + return _result, _err + } + + securityToken, _err := client.GetSecurityToken() + if _err != nil { + return _result, _err + } + + if !tea.BoolValue(util.Empty(securityToken)) { + request_.Headers["x-acs-accesskey-id"] = accessKeyId + request_.Headers["x-acs-security-token"] = securityToken + } + + stringToSign := openapiutil.GetStringToSign(request_) + request_.Headers["authorization"] = tea.String("acs " + tea.StringValue(accessKeyId) + ":" + tea.StringValue(openapiutil.GetROASignature(stringToSign, accessKeySecret))) + } + + response_, _err := tea.DoRequest(request_, _runtime) + if _err != nil { + return _result, _err + } + if tea.BoolValue(util.EqualNumber(response_.StatusCode, tea.Int(204))) { + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]map[string]*string{ + "headers": response_.Headers, + }, &_result) + return _result, _err + } + + if tea.BoolValue(util.Is4xx(response_.StatusCode)) || tea.BoolValue(util.Is5xx(response_.StatusCode)) { + _res, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + err := util.AssertAsMap(_res) + requestId := DefaultAny(err["RequestId"], err["requestId"]) + requestId = DefaultAny(requestId, err["requestid"]) + _err = tea.NewSDKError(map[string]interface{}{ + "code": tea.ToString(DefaultAny(err["Code"], err["code"])), + "message": "code: " + tea.ToString(tea.IntValue(response_.StatusCode)) + ", " + tea.ToString(DefaultAny(err["Message"], err["message"])) + " request id: " + tea.ToString(requestId), + "data": err, + }) + return _result, _err + } + + if tea.BoolValue(util.EqualString(bodyType, tea.String("binary"))) { + resp := map[string]interface{}{ + "body": response_.Body, + "headers": response_.Headers, + } + _result = resp + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("byte"))) { + byt, _err := util.ReadAsBytes(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": byt, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("string"))) { + str, _err := util.ReadAsString(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": tea.StringValue(str), + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("json"))) { + obj, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + res := util.AssertAsMap(obj) + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": res, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("array"))) { + arr, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": arr, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else { + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]map[string]*string{ + "headers": response_.Headers, + }, &_result) + return _result, _err + } + + }() + if !tea.BoolValue(tea.Retryable(_err)) { + break + } + } + + return _resp, _err +} + +/** + * Encapsulate the request and invoke the network with form body + * @param action api name + * @param version product version + * @param protocol http or https + * @param method e.g. GET + * @param authType authorization type e.g. AK + * @param pathname pathname of every api + * @param bodyType response body type e.g. String + * @param request object of OpenApiRequest + * @param runtime which controls some details of call api, such as retry times + * @return the response + */ +func (client *Client) DoROARequestWithForm(action *string, version *string, protocol *string, method *string, authType *string, pathname *string, bodyType *string, request *OpenApiRequest, runtime *util.RuntimeOptions) (_result map[string]interface{}, _err error) { + _err = tea.Validate(request) + if _err != nil { + return _result, _err + } + _err = tea.Validate(runtime) + if _err != nil { + return _result, _err + } + _runtime := map[string]interface{}{ + "timeouted": "retry", + "readTimeout": tea.IntValue(util.DefaultNumber(runtime.ReadTimeout, client.ReadTimeout)), + "connectTimeout": tea.IntValue(util.DefaultNumber(runtime.ConnectTimeout, client.ConnectTimeout)), + "httpProxy": tea.StringValue(util.DefaultString(runtime.HttpProxy, client.HttpProxy)), + "httpsProxy": tea.StringValue(util.DefaultString(runtime.HttpsProxy, client.HttpsProxy)), + "noProxy": tea.StringValue(util.DefaultString(runtime.NoProxy, client.NoProxy)), + "socks5Proxy": tea.StringValue(util.DefaultString(runtime.Socks5Proxy, client.Socks5Proxy)), + "socks5NetWork": tea.StringValue(util.DefaultString(runtime.Socks5NetWork, client.Socks5NetWork)), + "maxIdleConns": tea.IntValue(util.DefaultNumber(runtime.MaxIdleConns, client.MaxIdleConns)), + "retry": map[string]interface{}{ + "retryable": tea.BoolValue(runtime.Autoretry), + "maxAttempts": tea.IntValue(util.DefaultNumber(runtime.MaxAttempts, tea.Int(3))), + }, + "backoff": map[string]interface{}{ + "policy": tea.StringValue(util.DefaultString(runtime.BackoffPolicy, tea.String("no"))), + "period": tea.IntValue(util.DefaultNumber(runtime.BackoffPeriod, tea.Int(1))), + }, + "ignoreSSL": tea.BoolValue(runtime.IgnoreSSL), + } + + _resp := make(map[string]interface{}) + for _retryTimes := 0; tea.BoolValue(tea.AllowRetry(_runtime["retry"], tea.Int(_retryTimes))); _retryTimes++ { + if _retryTimes > 0 { + _backoffTime := tea.GetBackoffTime(_runtime["backoff"], tea.Int(_retryTimes)) + if tea.IntValue(_backoffTime) > 0 { + tea.Sleep(_backoffTime) + } + } + + _resp, _err = func() (map[string]interface{}, error) { + request_ := tea.NewRequest() + request_.Protocol = util.DefaultString(client.Protocol, protocol) + request_.Method = method + request_.Pathname = pathname + request_.Headers = tea.Merge(map[string]*string{ + "date": util.GetDateUTCString(), + "host": client.Endpoint, + "accept": tea.String("application/json"), + "x-acs-signature-nonce": util.GetNonce(), + "x-acs-signature-method": tea.String("HMAC-SHA1"), + "x-acs-signature-version": tea.String("1.0"), + "x-acs-version": version, + "x-acs-action": action, + "user-agent": util.GetUserAgent(client.UserAgent), + }, request.Headers) + if !tea.BoolValue(util.IsUnset(request.Body)) { + m := util.AssertAsMap(request.Body) + request_.Body = tea.ToReader(openapiutil.ToForm(m)) + request_.Headers["content-type"] = tea.String("application/x-www-form-urlencoded") + } + + if !tea.BoolValue(util.IsUnset(request.Query)) { + request_.Query = request.Query + } + + if !tea.BoolValue(util.EqualString(authType, tea.String("Anonymous"))) { + accessKeyId, _err := client.GetAccessKeyId() + if _err != nil { + return _result, _err + } + + accessKeySecret, _err := client.GetAccessKeySecret() + if _err != nil { + return _result, _err + } + + securityToken, _err := client.GetSecurityToken() + if _err != nil { + return _result, _err + } + + if !tea.BoolValue(util.Empty(securityToken)) { + request_.Headers["x-acs-accesskey-id"] = accessKeyId + request_.Headers["x-acs-security-token"] = securityToken + } + + stringToSign := openapiutil.GetStringToSign(request_) + request_.Headers["authorization"] = tea.String("acs " + tea.StringValue(accessKeyId) + ":" + tea.StringValue(openapiutil.GetROASignature(stringToSign, accessKeySecret))) + } + + response_, _err := tea.DoRequest(request_, _runtime) + if _err != nil { + return _result, _err + } + if tea.BoolValue(util.EqualNumber(response_.StatusCode, tea.Int(204))) { + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]map[string]*string{ + "headers": response_.Headers, + }, &_result) + return _result, _err + } + + if tea.BoolValue(util.Is4xx(response_.StatusCode)) || tea.BoolValue(util.Is5xx(response_.StatusCode)) { + _res, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + err := util.AssertAsMap(_res) + _err = tea.NewSDKError(map[string]interface{}{ + "code": tea.ToString(DefaultAny(err["Code"], err["code"])), + "message": "code: " + tea.ToString(tea.IntValue(response_.StatusCode)) + ", " + tea.ToString(DefaultAny(err["Message"], err["message"])) + " request id: " + tea.ToString(DefaultAny(err["RequestId"], err["requestId"])), + "data": err, + }) + return _result, _err + } + + if tea.BoolValue(util.EqualString(bodyType, tea.String("binary"))) { + resp := map[string]interface{}{ + "body": response_.Body, + "headers": response_.Headers, + } + _result = resp + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("byte"))) { + byt, _err := util.ReadAsBytes(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": byt, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("string"))) { + str, _err := util.ReadAsString(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": tea.StringValue(str), + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("json"))) { + obj, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + res := util.AssertAsMap(obj) + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": res, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(bodyType, tea.String("array"))) { + arr, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": arr, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else { + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]map[string]*string{ + "headers": response_.Headers, + }, &_result) + return _result, _err + } + + }() + if !tea.BoolValue(tea.Retryable(_err)) { + break + } + } + + return _resp, _err +} + +/** + * Encapsulate the request and invoke the network + * @param action api name + * @param version product version + * @param protocol http or https + * @param method e.g. GET + * @param authType authorization type e.g. AK + * @param bodyType response body type e.g. String + * @param request object of OpenApiRequest + * @param runtime which controls some details of call api, such as retry times + * @return the response + */ +func (client *Client) DoRequest(params *Params, request *OpenApiRequest, runtime *util.RuntimeOptions) (_result map[string]interface{}, _err error) { + _err = tea.Validate(params) + if _err != nil { + return _result, _err + } + _err = tea.Validate(request) + if _err != nil { + return _result, _err + } + _err = tea.Validate(runtime) + if _err != nil { + return _result, _err + } + _runtime := map[string]interface{}{ + "timeouted": "retry", + "readTimeout": tea.IntValue(util.DefaultNumber(runtime.ReadTimeout, client.ReadTimeout)), + "connectTimeout": tea.IntValue(util.DefaultNumber(runtime.ConnectTimeout, client.ConnectTimeout)), + "httpProxy": tea.StringValue(util.DefaultString(runtime.HttpProxy, client.HttpProxy)), + "httpsProxy": tea.StringValue(util.DefaultString(runtime.HttpsProxy, client.HttpsProxy)), + "noProxy": tea.StringValue(util.DefaultString(runtime.NoProxy, client.NoProxy)), + "socks5Proxy": tea.StringValue(util.DefaultString(runtime.Socks5Proxy, client.Socks5Proxy)), + "socks5NetWork": tea.StringValue(util.DefaultString(runtime.Socks5NetWork, client.Socks5NetWork)), + "maxIdleConns": tea.IntValue(util.DefaultNumber(runtime.MaxIdleConns, client.MaxIdleConns)), + "retry": map[string]interface{}{ + "retryable": tea.BoolValue(runtime.Autoretry), + "maxAttempts": tea.IntValue(util.DefaultNumber(runtime.MaxAttempts, tea.Int(3))), + }, + "backoff": map[string]interface{}{ + "policy": tea.StringValue(util.DefaultString(runtime.BackoffPolicy, tea.String("no"))), + "period": tea.IntValue(util.DefaultNumber(runtime.BackoffPeriod, tea.Int(1))), + }, + "ignoreSSL": tea.BoolValue(runtime.IgnoreSSL), + } + + _resp := make(map[string]interface{}) + for _retryTimes := 0; tea.BoolValue(tea.AllowRetry(_runtime["retry"], tea.Int(_retryTimes))); _retryTimes++ { + if _retryTimes > 0 { + _backoffTime := tea.GetBackoffTime(_runtime["backoff"], tea.Int(_retryTimes)) + if tea.IntValue(_backoffTime) > 0 { + tea.Sleep(_backoffTime) + } + } + + _resp, _err = func() (map[string]interface{}, error) { + request_ := tea.NewRequest() + request_.Protocol = util.DefaultString(client.Protocol, params.Protocol) + request_.Method = params.Method + request_.Pathname = params.Pathname + request_.Query = request.Query + // endpoint is setted in product client + request_.Headers = tea.Merge(map[string]*string{ + "host": client.Endpoint, + "x-acs-version": params.Version, + "x-acs-action": params.Action, + "user-agent": client.GetUserAgent(), + "x-acs-date": openapiutil.GetTimestamp(), + "x-acs-signature-nonce": util.GetNonce(), + "accept": tea.String("application/json"), + }, request.Headers) + if tea.BoolValue(util.EqualString(params.Style, tea.String("RPC"))) { + headers, _err := client.GetRpcHeaders() + if _err != nil { + return _result, _err + } + + if !tea.BoolValue(util.IsUnset(headers)) { + request_.Headers = tea.Merge(request_.Headers, + headers) + } + + } + + signatureAlgorithm := util.DefaultString(client.SignatureAlgorithm, tea.String("ACS3-HMAC-SHA256")) + hashedRequestPayload := openapiutil.HexEncode(openapiutil.Hash(util.ToBytes(tea.String("")), signatureAlgorithm)) + if !tea.BoolValue(util.IsUnset(request.Stream)) { + tmp, _err := util.ReadAsBytes(request.Stream) + if _err != nil { + return _result, _err + } + + hashedRequestPayload = openapiutil.HexEncode(openapiutil.Hash(tmp, signatureAlgorithm)) + request_.Body = tea.ToReader(tmp) + request_.Headers["content-type"] = tea.String("application/octet-stream") + } else { + if !tea.BoolValue(util.IsUnset(request.Body)) { + if tea.BoolValue(util.EqualString(params.ReqBodyType, tea.String("json"))) { + jsonObj := util.ToJSONString(request.Body) + hashedRequestPayload = openapiutil.HexEncode(openapiutil.Hash(util.ToBytes(jsonObj), signatureAlgorithm)) + request_.Body = tea.ToReader(jsonObj) + request_.Headers["content-type"] = tea.String("application/json; charset=utf-8") + } else { + m := util.AssertAsMap(request.Body) + formObj := openapiutil.ToForm(m) + hashedRequestPayload = openapiutil.HexEncode(openapiutil.Hash(util.ToBytes(formObj), signatureAlgorithm)) + request_.Body = tea.ToReader(formObj) + request_.Headers["content-type"] = tea.String("application/x-www-form-urlencoded") + } + + } + + } + + request_.Headers["x-acs-content-sha256"] = hashedRequestPayload + if !tea.BoolValue(util.EqualString(params.AuthType, tea.String("Anonymous"))) { + authType, _err := client.GetType() + if _err != nil { + return _result, _err + } + + if tea.BoolValue(util.EqualString(authType, tea.String("bearer"))) { + bearerToken, _err := client.GetBearerToken() + if _err != nil { + return _result, _err + } + + request_.Headers["x-acs-bearer-token"] = bearerToken + } else { + accessKeyId, _err := client.GetAccessKeyId() + if _err != nil { + return _result, _err + } + + accessKeySecret, _err := client.GetAccessKeySecret() + if _err != nil { + return _result, _err + } + + securityToken, _err := client.GetSecurityToken() + if _err != nil { + return _result, _err + } + + if !tea.BoolValue(util.Empty(securityToken)) { + request_.Headers["x-acs-accesskey-id"] = accessKeyId + request_.Headers["x-acs-security-token"] = securityToken + } + + request_.Headers["Authorization"] = openapiutil.GetAuthorization(request_, signatureAlgorithm, hashedRequestPayload, accessKeyId, accessKeySecret) + } + + } + + response_, _err := tea.DoRequest(request_, _runtime) + if _err != nil { + return _result, _err + } + if tea.BoolValue(util.Is4xx(response_.StatusCode)) || tea.BoolValue(util.Is5xx(response_.StatusCode)) { + err := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(response_.Headers["content-type"])) && tea.BoolValue(util.EqualString(response_.Headers["content-type"], tea.String("text/xml;charset=utf-8"))) { + _str, _err := util.ReadAsString(response_.Body) + if _err != nil { + return _result, _err + } + + respMap := xml.ParseXml(_str, nil) + err = util.AssertAsMap(respMap["Error"]) + } else { + _res, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + err = util.AssertAsMap(_res) + } + + err["statusCode"] = response_.StatusCode + _err = tea.NewSDKError(map[string]interface{}{ + "code": tea.ToString(DefaultAny(err["Code"], err["code"])), + "message": "code: " + tea.ToString(tea.IntValue(response_.StatusCode)) + ", " + tea.ToString(DefaultAny(err["Message"], err["message"])) + " request id: " + tea.ToString(DefaultAny(err["RequestId"], err["requestId"])), + "data": err, + }) + return _result, _err + } + + if tea.BoolValue(util.EqualString(params.BodyType, tea.String("binary"))) { + resp := map[string]interface{}{ + "body": response_.Body, + "headers": response_.Headers, + } + _result = resp + return _result, _err + } else if tea.BoolValue(util.EqualString(params.BodyType, tea.String("byte"))) { + byt, _err := util.ReadAsBytes(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": byt, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(params.BodyType, tea.String("string"))) { + str, _err := util.ReadAsString(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": tea.StringValue(str), + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(params.BodyType, tea.String("json"))) { + obj, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + res := util.AssertAsMap(obj) + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": res, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else if tea.BoolValue(util.EqualString(params.BodyType, tea.String("array"))) { + arr, _err := util.ReadAsJSON(response_.Body) + if _err != nil { + return _result, _err + } + + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "body": arr, + "headers": response_.Headers, + }, &_result) + return _result, _err + } else { + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]map[string]*string{ + "headers": response_.Headers, + }, &_result) + return _result, _err + } + + }() + if !tea.BoolValue(tea.Retryable(_err)) { + break + } + } + + return _resp, _err +} + +/** + * Encapsulate the request and invoke the network + * @param action api name + * @param version product version + * @param protocol http or https + * @param method e.g. GET + * @param authType authorization type e.g. AK + * @param bodyType response body type e.g. String + * @param request object of OpenApiRequest + * @param runtime which controls some details of call api, such as retry times + * @return the response + */ +func (client *Client) Execute(params *Params, request *OpenApiRequest, runtime *util.RuntimeOptions) (_result map[string]interface{}, _err error) { + _err = tea.Validate(params) + if _err != nil { + return _result, _err + } + _err = tea.Validate(request) + if _err != nil { + return _result, _err + } + _err = tea.Validate(runtime) + if _err != nil { + return _result, _err + } + _runtime := map[string]interface{}{ + "timeouted": "retry", + "readTimeout": tea.IntValue(util.DefaultNumber(runtime.ReadTimeout, client.ReadTimeout)), + "connectTimeout": tea.IntValue(util.DefaultNumber(runtime.ConnectTimeout, client.ConnectTimeout)), + "httpProxy": tea.StringValue(util.DefaultString(runtime.HttpProxy, client.HttpProxy)), + "httpsProxy": tea.StringValue(util.DefaultString(runtime.HttpsProxy, client.HttpsProxy)), + "noProxy": tea.StringValue(util.DefaultString(runtime.NoProxy, client.NoProxy)), + "socks5Proxy": tea.StringValue(util.DefaultString(runtime.Socks5Proxy, client.Socks5Proxy)), + "socks5NetWork": tea.StringValue(util.DefaultString(runtime.Socks5NetWork, client.Socks5NetWork)), + "maxIdleConns": tea.IntValue(util.DefaultNumber(runtime.MaxIdleConns, client.MaxIdleConns)), + "retry": map[string]interface{}{ + "retryable": tea.BoolValue(runtime.Autoretry), + "maxAttempts": tea.IntValue(util.DefaultNumber(runtime.MaxAttempts, tea.Int(3))), + }, + "backoff": map[string]interface{}{ + "policy": tea.StringValue(util.DefaultString(runtime.BackoffPolicy, tea.String("no"))), + "period": tea.IntValue(util.DefaultNumber(runtime.BackoffPeriod, tea.Int(1))), + }, + "ignoreSSL": tea.BoolValue(runtime.IgnoreSSL), + } + + _resp := make(map[string]interface{}) + for _retryTimes := 0; tea.BoolValue(tea.AllowRetry(_runtime["retry"], tea.Int(_retryTimes))); _retryTimes++ { + if _retryTimes > 0 { + _backoffTime := tea.GetBackoffTime(_runtime["backoff"], tea.Int(_retryTimes)) + if tea.IntValue(_backoffTime) > 0 { + tea.Sleep(_backoffTime) + } + } + + _resp, _err = func() (map[string]interface{}, error) { + request_ := tea.NewRequest() + // spi = new Gateway();//Gateway implements SPI,这一步在产品 SDK 中实例化 + headers, _err := client.GetRpcHeaders() + if _err != nil { + return _result, _err + } + + requestContext := &spi.InterceptorContextRequest{ + Headers: tea.Merge(request.Headers, + headers), + Query: request.Query, + Body: request.Body, + Stream: request.Stream, + HostMap: request.HostMap, + Pathname: params.Pathname, + ProductId: client.ProductId, + Action: params.Action, + Version: params.Version, + Protocol: util.DefaultString(client.Protocol, params.Protocol), + Method: util.DefaultString(client.Method, params.Method), + AuthType: params.AuthType, + BodyType: params.BodyType, + ReqBodyType: params.ReqBodyType, + Style: params.Style, + Credential: client.Credential, + SignatureVersion: client.SignatureVersion, + SignatureAlgorithm: client.SignatureAlgorithm, + UserAgent: client.GetUserAgent(), + } + configurationContext := &spi.InterceptorContextConfiguration{ + RegionId: client.RegionId, + Endpoint: util.DefaultString(request.EndpointOverride, client.Endpoint), + EndpointRule: client.EndpointRule, + EndpointMap: client.EndpointMap, + EndpointType: client.EndpointType, + Network: client.Network, + Suffix: client.Suffix, + } + interceptorContext := &spi.InterceptorContext{ + Request: requestContext, + Configuration: configurationContext, + } + attributeMap := &spi.AttributeMap{} + // 1. spi.modifyConfiguration(context: SPI.InterceptorContext, attributeMap: SPI.AttributeMap); + _err = client.Spi.ModifyConfiguration(interceptorContext, attributeMap) + if _err != nil { + return _result, _err + } + // 2. spi.modifyRequest(context: SPI.InterceptorContext, attributeMap: SPI.AttributeMap); + _err = client.Spi.ModifyRequest(interceptorContext, attributeMap) + if _err != nil { + return _result, _err + } + request_.Protocol = interceptorContext.Request.Protocol + request_.Method = interceptorContext.Request.Method + request_.Pathname = interceptorContext.Request.Pathname + request_.Query = interceptorContext.Request.Query + request_.Body = interceptorContext.Request.Stream + request_.Headers = interceptorContext.Request.Headers + response_, _err := tea.DoRequest(request_, _runtime) + if _err != nil { + return _result, _err + } + responseContext := &spi.InterceptorContextResponse{ + StatusCode: response_.StatusCode, + Headers: response_.Headers, + Body: response_.Body, + } + interceptorContext.Response = responseContext + // 3. spi.modifyResponse(context: SPI.InterceptorContext, attributeMap: SPI.AttributeMap); + _err = client.Spi.ModifyResponse(interceptorContext, attributeMap) + if _err != nil { + return _result, _err + } + _result = make(map[string]interface{}) + _err = tea.Convert(map[string]interface{}{ + "headers": interceptorContext.Response.Headers, + "body": interceptorContext.Response.DeserializedBody, + }, &_result) + return _result, _err + }() + if !tea.BoolValue(tea.Retryable(_err)) { + break + } + } + + return _resp, _err +} + +func (client *Client) CallApi(params *Params, request *OpenApiRequest, runtime *util.RuntimeOptions) (_result map[string]interface{}, _err error) { + if tea.BoolValue(util.IsUnset(tea.ToMap(params))) { + _err = tea.NewSDKError(map[string]interface{}{ + "code": "ParameterMissing", + "message": "'params' can not be unset", + }) + return _result, _err + } + + if tea.BoolValue(util.IsUnset(client.SignatureAlgorithm)) || !tea.BoolValue(util.EqualString(client.SignatureAlgorithm, tea.String("v2"))) { + _result = make(map[string]interface{}) + _body, _err := client.DoRequest(params, request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err + } else if tea.BoolValue(util.EqualString(params.Style, tea.String("ROA"))) && tea.BoolValue(util.EqualString(params.ReqBodyType, tea.String("json"))) { + _result = make(map[string]interface{}) + _body, _err := client.DoROARequest(params.Action, params.Version, params.Protocol, params.Method, params.AuthType, params.Pathname, params.BodyType, request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err + } else if tea.BoolValue(util.EqualString(params.Style, tea.String("ROA"))) { + _result = make(map[string]interface{}) + _body, _err := client.DoROARequestWithForm(params.Action, params.Version, params.Protocol, params.Method, params.AuthType, params.Pathname, params.BodyType, request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err + } else { + _result = make(map[string]interface{}) + _body, _err := client.DoRPCRequest(params.Action, params.Version, params.Protocol, params.Method, params.AuthType, params.BodyType, request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err + } + +} + +/** + * Get user agent + * @return user agent + */ +func (client *Client) GetUserAgent() (_result *string) { + userAgent := util.GetUserAgent(client.UserAgent) + _result = userAgent + return _result +} + +/** + * Get accesskey id by using credential + * @return accesskey id + */ +func (client *Client) GetAccessKeyId() (_result *string, _err error) { + if tea.BoolValue(util.IsUnset(client.Credential)) { + _result = tea.String("") + return _result, _err + } + + accessKeyId, _err := client.Credential.GetAccessKeyId() + if _err != nil { + return _result, _err + } + + _result = accessKeyId + return _result, _err +} + +/** + * Get accesskey secret by using credential + * @return accesskey secret + */ +func (client *Client) GetAccessKeySecret() (_result *string, _err error) { + if tea.BoolValue(util.IsUnset(client.Credential)) { + _result = tea.String("") + return _result, _err + } + + secret, _err := client.Credential.GetAccessKeySecret() + if _err != nil { + return _result, _err + } + + _result = secret + return _result, _err +} + +/** + * Get security token by using credential + * @return security token + */ +func (client *Client) GetSecurityToken() (_result *string, _err error) { + if tea.BoolValue(util.IsUnset(client.Credential)) { + _result = tea.String("") + return _result, _err + } + + token, _err := client.Credential.GetSecurityToken() + if _err != nil { + return _result, _err + } + + _result = token + return _result, _err +} + +/** + * Get bearer token by credential + * @return bearer token + */ +func (client *Client) GetBearerToken() (_result *string, _err error) { + if tea.BoolValue(util.IsUnset(client.Credential)) { + _result = tea.String("") + return _result, _err + } + + token := client.Credential.GetBearerToken() + _result = token + return _result, _err +} + +/** + * Get credential type by credential + * @return credential type e.g. access_key + */ +func (client *Client) GetType() (_result *string, _err error) { + if tea.BoolValue(util.IsUnset(client.Credential)) { + _result = tea.String("") + return _result, _err + } + + authType := client.Credential.GetType() + _result = authType + return _result, _err +} + +/** + * If inputValue is not null, return it or return defaultValue + * @param inputValue users input value + * @param defaultValue default value + * @return the final result + */ +func DefaultAny(inputValue interface{}, defaultValue interface{}) (_result interface{}) { + if tea.BoolValue(util.IsUnset(inputValue)) { + _result = defaultValue + return _result + } + + _result = inputValue + return _result +} + +/** + * If the endpointRule and config.endpoint are empty, throw error + * @param config config contains the necessary information to create a client + */ +func (client *Client) CheckConfig(config *Config) (_err error) { + if tea.BoolValue(util.Empty(client.EndpointRule)) && tea.BoolValue(util.Empty(config.Endpoint)) { + _err = tea.NewSDKError(map[string]interface{}{ + "code": "ParameterMissing", + "message": "'config.endpoint' can not be empty", + }) + return _err + } + + return _err +} + +/** + * set RPC header for debug + * @param headers headers for debug, this header can be used only once. + */ +func (client *Client) SetRpcHeaders(headers map[string]*string) (_err error) { + client.Headers = headers + return _err +} + +/** + * get RPC header for debug + */ +func (client *Client) GetRpcHeaders() (_result map[string]*string, _err error) { + headers := client.Headers + client.Headers = nil + _result = headers + return _result, _err +} diff --git a/vendor/github.com/alibabacloud-go/debug/LICENSE b/vendor/github.com/alibabacloud-go/debug/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/debug/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/alibabacloud-go/debug/debug/assert.go b/vendor/github.com/alibabacloud-go/debug/debug/assert.go new file mode 100644 index 000000000..6fca15a63 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/debug/debug/assert.go @@ -0,0 +1,12 @@ +package debug + +import ( + "reflect" + "testing" +) + +func assertEqual(t *testing.T, a, b interface{}) { + if !reflect.DeepEqual(a, b) { + t.Errorf("%v != %v", a, b) + } +} diff --git a/vendor/github.com/alibabacloud-go/debug/debug/debug.go b/vendor/github.com/alibabacloud-go/debug/debug/debug.go new file mode 100644 index 000000000..c977cb8c3 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/debug/debug/debug.go @@ -0,0 +1,36 @@ +package debug + +import ( + "fmt" + "os" + "strings" +) + +type Debug func(format string, v ...interface{}) + +var hookGetEnv = func() string { + return os.Getenv("DEBUG") +} + +var hookPrint = func(input string) { + fmt.Println(input) +} + +func Init(flag string) Debug { + enable := false + + env := hookGetEnv() + parts := strings.Split(env, ",") + for _, part := range parts { + if part == flag { + enable = true + break + } + } + + return func(format string, v ...interface{}) { + if enable { + hookPrint(fmt.Sprintf(format, v...)) + } + } +} diff --git a/vendor/github.com/alibabacloud-go/dysmsapi-20170525/v2/client/client.go b/vendor/github.com/alibabacloud-go/dysmsapi-20170525/v2/client/client.go new file mode 100644 index 000000000..a5f0a894a --- /dev/null +++ b/vendor/github.com/alibabacloud-go/dysmsapi-20170525/v2/client/client.go @@ -0,0 +1,4124 @@ +// This file is auto-generated, don't edit it. Thanks. +/** + * + */ +package client + +import ( + openapi "github.com/alibabacloud-go/darabonba-openapi/client" + endpointutil "github.com/alibabacloud-go/endpoint-util/service" + openapiutil "github.com/alibabacloud-go/openapi-util/service" + util "github.com/alibabacloud-go/tea-utils/service" + "github.com/alibabacloud-go/tea/tea" +) + +type AddShortUrlRequest struct { + EffectiveDays *string `json:"EffectiveDays,omitempty" xml:"EffectiveDays,omitempty"` + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + ShortUrlName *string `json:"ShortUrlName,omitempty" xml:"ShortUrlName,omitempty"` + SourceUrl *string `json:"SourceUrl,omitempty" xml:"SourceUrl,omitempty"` +} + +func (s AddShortUrlRequest) String() string { + return tea.Prettify(s) +} + +func (s AddShortUrlRequest) GoString() string { + return s.String() +} + +func (s *AddShortUrlRequest) SetEffectiveDays(v string) *AddShortUrlRequest { + s.EffectiveDays = &v + return s +} + +func (s *AddShortUrlRequest) SetOwnerId(v int64) *AddShortUrlRequest { + s.OwnerId = &v + return s +} + +func (s *AddShortUrlRequest) SetResourceOwnerAccount(v string) *AddShortUrlRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *AddShortUrlRequest) SetResourceOwnerId(v int64) *AddShortUrlRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *AddShortUrlRequest) SetShortUrlName(v string) *AddShortUrlRequest { + s.ShortUrlName = &v + return s +} + +func (s *AddShortUrlRequest) SetSourceUrl(v string) *AddShortUrlRequest { + s.SourceUrl = &v + return s +} + +type AddShortUrlResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Data *AddShortUrlResponseBodyData `json:"Data,omitempty" xml:"Data,omitempty" type:"Struct"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s AddShortUrlResponseBody) String() string { + return tea.Prettify(s) +} + +func (s AddShortUrlResponseBody) GoString() string { + return s.String() +} + +func (s *AddShortUrlResponseBody) SetCode(v string) *AddShortUrlResponseBody { + s.Code = &v + return s +} + +func (s *AddShortUrlResponseBody) SetData(v *AddShortUrlResponseBodyData) *AddShortUrlResponseBody { + s.Data = v + return s +} + +func (s *AddShortUrlResponseBody) SetMessage(v string) *AddShortUrlResponseBody { + s.Message = &v + return s +} + +func (s *AddShortUrlResponseBody) SetRequestId(v string) *AddShortUrlResponseBody { + s.RequestId = &v + return s +} + +type AddShortUrlResponseBodyData struct { + ExpireDate *string `json:"ExpireDate,omitempty" xml:"ExpireDate,omitempty"` + ShortUrl *string `json:"ShortUrl,omitempty" xml:"ShortUrl,omitempty"` + SourceUrl *string `json:"SourceUrl,omitempty" xml:"SourceUrl,omitempty"` +} + +func (s AddShortUrlResponseBodyData) String() string { + return tea.Prettify(s) +} + +func (s AddShortUrlResponseBodyData) GoString() string { + return s.String() +} + +func (s *AddShortUrlResponseBodyData) SetExpireDate(v string) *AddShortUrlResponseBodyData { + s.ExpireDate = &v + return s +} + +func (s *AddShortUrlResponseBodyData) SetShortUrl(v string) *AddShortUrlResponseBodyData { + s.ShortUrl = &v + return s +} + +func (s *AddShortUrlResponseBodyData) SetSourceUrl(v string) *AddShortUrlResponseBodyData { + s.SourceUrl = &v + return s +} + +type AddShortUrlResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *AddShortUrlResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s AddShortUrlResponse) String() string { + return tea.Prettify(s) +} + +func (s AddShortUrlResponse) GoString() string { + return s.String() +} + +func (s *AddShortUrlResponse) SetHeaders(v map[string]*string) *AddShortUrlResponse { + s.Headers = v + return s +} + +func (s *AddShortUrlResponse) SetBody(v *AddShortUrlResponseBody) *AddShortUrlResponse { + s.Body = v + return s +} + +type AddSmsSignRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + Remark *string `json:"Remark,omitempty" xml:"Remark,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SignFileList []*AddSmsSignRequestSignFileList `json:"SignFileList,omitempty" xml:"SignFileList,omitempty" type:"Repeated"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` + SignSource *int32 `json:"SignSource,omitempty" xml:"SignSource,omitempty"` +} + +func (s AddSmsSignRequest) String() string { + return tea.Prettify(s) +} + +func (s AddSmsSignRequest) GoString() string { + return s.String() +} + +func (s *AddSmsSignRequest) SetOwnerId(v int64) *AddSmsSignRequest { + s.OwnerId = &v + return s +} + +func (s *AddSmsSignRequest) SetRemark(v string) *AddSmsSignRequest { + s.Remark = &v + return s +} + +func (s *AddSmsSignRequest) SetResourceOwnerAccount(v string) *AddSmsSignRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *AddSmsSignRequest) SetResourceOwnerId(v int64) *AddSmsSignRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *AddSmsSignRequest) SetSignFileList(v []*AddSmsSignRequestSignFileList) *AddSmsSignRequest { + s.SignFileList = v + return s +} + +func (s *AddSmsSignRequest) SetSignName(v string) *AddSmsSignRequest { + s.SignName = &v + return s +} + +func (s *AddSmsSignRequest) SetSignSource(v int32) *AddSmsSignRequest { + s.SignSource = &v + return s +} + +type AddSmsSignRequestSignFileList struct { + FileContents *string `json:"FileContents,omitempty" xml:"FileContents,omitempty"` + FileSuffix *string `json:"FileSuffix,omitempty" xml:"FileSuffix,omitempty"` +} + +func (s AddSmsSignRequestSignFileList) String() string { + return tea.Prettify(s) +} + +func (s AddSmsSignRequestSignFileList) GoString() string { + return s.String() +} + +func (s *AddSmsSignRequestSignFileList) SetFileContents(v string) *AddSmsSignRequestSignFileList { + s.FileContents = &v + return s +} + +func (s *AddSmsSignRequestSignFileList) SetFileSuffix(v string) *AddSmsSignRequestSignFileList { + s.FileSuffix = &v + return s +} + +type AddSmsSignResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` +} + +func (s AddSmsSignResponseBody) String() string { + return tea.Prettify(s) +} + +func (s AddSmsSignResponseBody) GoString() string { + return s.String() +} + +func (s *AddSmsSignResponseBody) SetCode(v string) *AddSmsSignResponseBody { + s.Code = &v + return s +} + +func (s *AddSmsSignResponseBody) SetMessage(v string) *AddSmsSignResponseBody { + s.Message = &v + return s +} + +func (s *AddSmsSignResponseBody) SetRequestId(v string) *AddSmsSignResponseBody { + s.RequestId = &v + return s +} + +func (s *AddSmsSignResponseBody) SetSignName(v string) *AddSmsSignResponseBody { + s.SignName = &v + return s +} + +type AddSmsSignResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *AddSmsSignResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s AddSmsSignResponse) String() string { + return tea.Prettify(s) +} + +func (s AddSmsSignResponse) GoString() string { + return s.String() +} + +func (s *AddSmsSignResponse) SetHeaders(v map[string]*string) *AddSmsSignResponse { + s.Headers = v + return s +} + +func (s *AddSmsSignResponse) SetBody(v *AddSmsSignResponseBody) *AddSmsSignResponse { + s.Body = v + return s +} + +type AddSmsTemplateRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + Remark *string `json:"Remark,omitempty" xml:"Remark,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + TemplateContent *string `json:"TemplateContent,omitempty" xml:"TemplateContent,omitempty"` + TemplateName *string `json:"TemplateName,omitempty" xml:"TemplateName,omitempty"` + TemplateType *int32 `json:"TemplateType,omitempty" xml:"TemplateType,omitempty"` +} + +func (s AddSmsTemplateRequest) String() string { + return tea.Prettify(s) +} + +func (s AddSmsTemplateRequest) GoString() string { + return s.String() +} + +func (s *AddSmsTemplateRequest) SetOwnerId(v int64) *AddSmsTemplateRequest { + s.OwnerId = &v + return s +} + +func (s *AddSmsTemplateRequest) SetRemark(v string) *AddSmsTemplateRequest { + s.Remark = &v + return s +} + +func (s *AddSmsTemplateRequest) SetResourceOwnerAccount(v string) *AddSmsTemplateRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *AddSmsTemplateRequest) SetResourceOwnerId(v int64) *AddSmsTemplateRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *AddSmsTemplateRequest) SetTemplateContent(v string) *AddSmsTemplateRequest { + s.TemplateContent = &v + return s +} + +func (s *AddSmsTemplateRequest) SetTemplateName(v string) *AddSmsTemplateRequest { + s.TemplateName = &v + return s +} + +func (s *AddSmsTemplateRequest) SetTemplateType(v int32) *AddSmsTemplateRequest { + s.TemplateType = &v + return s +} + +type AddSmsTemplateResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` +} + +func (s AddSmsTemplateResponseBody) String() string { + return tea.Prettify(s) +} + +func (s AddSmsTemplateResponseBody) GoString() string { + return s.String() +} + +func (s *AddSmsTemplateResponseBody) SetCode(v string) *AddSmsTemplateResponseBody { + s.Code = &v + return s +} + +func (s *AddSmsTemplateResponseBody) SetMessage(v string) *AddSmsTemplateResponseBody { + s.Message = &v + return s +} + +func (s *AddSmsTemplateResponseBody) SetRequestId(v string) *AddSmsTemplateResponseBody { + s.RequestId = &v + return s +} + +func (s *AddSmsTemplateResponseBody) SetTemplateCode(v string) *AddSmsTemplateResponseBody { + s.TemplateCode = &v + return s +} + +type AddSmsTemplateResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *AddSmsTemplateResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s AddSmsTemplateResponse) String() string { + return tea.Prettify(s) +} + +func (s AddSmsTemplateResponse) GoString() string { + return s.String() +} + +func (s *AddSmsTemplateResponse) SetHeaders(v map[string]*string) *AddSmsTemplateResponse { + s.Headers = v + return s +} + +func (s *AddSmsTemplateResponse) SetBody(v *AddSmsTemplateResponseBody) *AddSmsTemplateResponse { + s.Body = v + return s +} + +type DeleteShortUrlRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SourceUrl *string `json:"SourceUrl,omitempty" xml:"SourceUrl,omitempty"` +} + +func (s DeleteShortUrlRequest) String() string { + return tea.Prettify(s) +} + +func (s DeleteShortUrlRequest) GoString() string { + return s.String() +} + +func (s *DeleteShortUrlRequest) SetOwnerId(v int64) *DeleteShortUrlRequest { + s.OwnerId = &v + return s +} + +func (s *DeleteShortUrlRequest) SetResourceOwnerAccount(v string) *DeleteShortUrlRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *DeleteShortUrlRequest) SetResourceOwnerId(v int64) *DeleteShortUrlRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *DeleteShortUrlRequest) SetSourceUrl(v string) *DeleteShortUrlRequest { + s.SourceUrl = &v + return s +} + +type DeleteShortUrlResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s DeleteShortUrlResponseBody) String() string { + return tea.Prettify(s) +} + +func (s DeleteShortUrlResponseBody) GoString() string { + return s.String() +} + +func (s *DeleteShortUrlResponseBody) SetCode(v string) *DeleteShortUrlResponseBody { + s.Code = &v + return s +} + +func (s *DeleteShortUrlResponseBody) SetMessage(v string) *DeleteShortUrlResponseBody { + s.Message = &v + return s +} + +func (s *DeleteShortUrlResponseBody) SetRequestId(v string) *DeleteShortUrlResponseBody { + s.RequestId = &v + return s +} + +type DeleteShortUrlResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *DeleteShortUrlResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s DeleteShortUrlResponse) String() string { + return tea.Prettify(s) +} + +func (s DeleteShortUrlResponse) GoString() string { + return s.String() +} + +func (s *DeleteShortUrlResponse) SetHeaders(v map[string]*string) *DeleteShortUrlResponse { + s.Headers = v + return s +} + +func (s *DeleteShortUrlResponse) SetBody(v *DeleteShortUrlResponseBody) *DeleteShortUrlResponse { + s.Body = v + return s +} + +type DeleteSmsSignRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` +} + +func (s DeleteSmsSignRequest) String() string { + return tea.Prettify(s) +} + +func (s DeleteSmsSignRequest) GoString() string { + return s.String() +} + +func (s *DeleteSmsSignRequest) SetOwnerId(v int64) *DeleteSmsSignRequest { + s.OwnerId = &v + return s +} + +func (s *DeleteSmsSignRequest) SetResourceOwnerAccount(v string) *DeleteSmsSignRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *DeleteSmsSignRequest) SetResourceOwnerId(v int64) *DeleteSmsSignRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *DeleteSmsSignRequest) SetSignName(v string) *DeleteSmsSignRequest { + s.SignName = &v + return s +} + +type DeleteSmsSignResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` +} + +func (s DeleteSmsSignResponseBody) String() string { + return tea.Prettify(s) +} + +func (s DeleteSmsSignResponseBody) GoString() string { + return s.String() +} + +func (s *DeleteSmsSignResponseBody) SetCode(v string) *DeleteSmsSignResponseBody { + s.Code = &v + return s +} + +func (s *DeleteSmsSignResponseBody) SetMessage(v string) *DeleteSmsSignResponseBody { + s.Message = &v + return s +} + +func (s *DeleteSmsSignResponseBody) SetRequestId(v string) *DeleteSmsSignResponseBody { + s.RequestId = &v + return s +} + +func (s *DeleteSmsSignResponseBody) SetSignName(v string) *DeleteSmsSignResponseBody { + s.SignName = &v + return s +} + +type DeleteSmsSignResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *DeleteSmsSignResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s DeleteSmsSignResponse) String() string { + return tea.Prettify(s) +} + +func (s DeleteSmsSignResponse) GoString() string { + return s.String() +} + +func (s *DeleteSmsSignResponse) SetHeaders(v map[string]*string) *DeleteSmsSignResponse { + s.Headers = v + return s +} + +func (s *DeleteSmsSignResponse) SetBody(v *DeleteSmsSignResponseBody) *DeleteSmsSignResponse { + s.Body = v + return s +} + +type DeleteSmsTemplateRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` +} + +func (s DeleteSmsTemplateRequest) String() string { + return tea.Prettify(s) +} + +func (s DeleteSmsTemplateRequest) GoString() string { + return s.String() +} + +func (s *DeleteSmsTemplateRequest) SetOwnerId(v int64) *DeleteSmsTemplateRequest { + s.OwnerId = &v + return s +} + +func (s *DeleteSmsTemplateRequest) SetResourceOwnerAccount(v string) *DeleteSmsTemplateRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *DeleteSmsTemplateRequest) SetResourceOwnerId(v int64) *DeleteSmsTemplateRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *DeleteSmsTemplateRequest) SetTemplateCode(v string) *DeleteSmsTemplateRequest { + s.TemplateCode = &v + return s +} + +type DeleteSmsTemplateResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` +} + +func (s DeleteSmsTemplateResponseBody) String() string { + return tea.Prettify(s) +} + +func (s DeleteSmsTemplateResponseBody) GoString() string { + return s.String() +} + +func (s *DeleteSmsTemplateResponseBody) SetCode(v string) *DeleteSmsTemplateResponseBody { + s.Code = &v + return s +} + +func (s *DeleteSmsTemplateResponseBody) SetMessage(v string) *DeleteSmsTemplateResponseBody { + s.Message = &v + return s +} + +func (s *DeleteSmsTemplateResponseBody) SetRequestId(v string) *DeleteSmsTemplateResponseBody { + s.RequestId = &v + return s +} + +func (s *DeleteSmsTemplateResponseBody) SetTemplateCode(v string) *DeleteSmsTemplateResponseBody { + s.TemplateCode = &v + return s +} + +type DeleteSmsTemplateResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *DeleteSmsTemplateResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s DeleteSmsTemplateResponse) String() string { + return tea.Prettify(s) +} + +func (s DeleteSmsTemplateResponse) GoString() string { + return s.String() +} + +func (s *DeleteSmsTemplateResponse) SetHeaders(v map[string]*string) *DeleteSmsTemplateResponse { + s.Headers = v + return s +} + +func (s *DeleteSmsTemplateResponse) SetBody(v *DeleteSmsTemplateResponseBody) *DeleteSmsTemplateResponse { + s.Body = v + return s +} + +type ListTagResourcesRequest struct { + NextToken *string `json:"NextToken,omitempty" xml:"NextToken,omitempty"` + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PageSize *int32 `json:"PageSize,omitempty" xml:"PageSize,omitempty"` + ProdCode *string `json:"ProdCode,omitempty" xml:"ProdCode,omitempty"` + RegionId *string `json:"RegionId,omitempty" xml:"RegionId,omitempty"` + ResourceId []*string `json:"ResourceId,omitempty" xml:"ResourceId,omitempty" type:"Repeated"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + ResourceType *string `json:"ResourceType,omitempty" xml:"ResourceType,omitempty"` + Tag []*ListTagResourcesRequestTag `json:"Tag,omitempty" xml:"Tag,omitempty" type:"Repeated"` +} + +func (s ListTagResourcesRequest) String() string { + return tea.Prettify(s) +} + +func (s ListTagResourcesRequest) GoString() string { + return s.String() +} + +func (s *ListTagResourcesRequest) SetNextToken(v string) *ListTagResourcesRequest { + s.NextToken = &v + return s +} + +func (s *ListTagResourcesRequest) SetOwnerId(v int64) *ListTagResourcesRequest { + s.OwnerId = &v + return s +} + +func (s *ListTagResourcesRequest) SetPageSize(v int32) *ListTagResourcesRequest { + s.PageSize = &v + return s +} + +func (s *ListTagResourcesRequest) SetProdCode(v string) *ListTagResourcesRequest { + s.ProdCode = &v + return s +} + +func (s *ListTagResourcesRequest) SetRegionId(v string) *ListTagResourcesRequest { + s.RegionId = &v + return s +} + +func (s *ListTagResourcesRequest) SetResourceId(v []*string) *ListTagResourcesRequest { + s.ResourceId = v + return s +} + +func (s *ListTagResourcesRequest) SetResourceOwnerAccount(v string) *ListTagResourcesRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *ListTagResourcesRequest) SetResourceOwnerId(v int64) *ListTagResourcesRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *ListTagResourcesRequest) SetResourceType(v string) *ListTagResourcesRequest { + s.ResourceType = &v + return s +} + +func (s *ListTagResourcesRequest) SetTag(v []*ListTagResourcesRequestTag) *ListTagResourcesRequest { + s.Tag = v + return s +} + +type ListTagResourcesRequestTag struct { + Key *string `json:"Key,omitempty" xml:"Key,omitempty"` + Value *string `json:"Value,omitempty" xml:"Value,omitempty"` +} + +func (s ListTagResourcesRequestTag) String() string { + return tea.Prettify(s) +} + +func (s ListTagResourcesRequestTag) GoString() string { + return s.String() +} + +func (s *ListTagResourcesRequestTag) SetKey(v string) *ListTagResourcesRequestTag { + s.Key = &v + return s +} + +func (s *ListTagResourcesRequestTag) SetValue(v string) *ListTagResourcesRequestTag { + s.Value = &v + return s +} + +type ListTagResourcesResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + NextToken *string `json:"NextToken,omitempty" xml:"NextToken,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + TagResources *ListTagResourcesResponseBodyTagResources `json:"TagResources,omitempty" xml:"TagResources,omitempty" type:"Struct"` +} + +func (s ListTagResourcesResponseBody) String() string { + return tea.Prettify(s) +} + +func (s ListTagResourcesResponseBody) GoString() string { + return s.String() +} + +func (s *ListTagResourcesResponseBody) SetCode(v string) *ListTagResourcesResponseBody { + s.Code = &v + return s +} + +func (s *ListTagResourcesResponseBody) SetNextToken(v string) *ListTagResourcesResponseBody { + s.NextToken = &v + return s +} + +func (s *ListTagResourcesResponseBody) SetRequestId(v string) *ListTagResourcesResponseBody { + s.RequestId = &v + return s +} + +func (s *ListTagResourcesResponseBody) SetTagResources(v *ListTagResourcesResponseBodyTagResources) *ListTagResourcesResponseBody { + s.TagResources = v + return s +} + +type ListTagResourcesResponseBodyTagResources struct { + TagResource []*ListTagResourcesResponseBodyTagResourcesTagResource `json:"TagResource,omitempty" xml:"TagResource,omitempty" type:"Repeated"` +} + +func (s ListTagResourcesResponseBodyTagResources) String() string { + return tea.Prettify(s) +} + +func (s ListTagResourcesResponseBodyTagResources) GoString() string { + return s.String() +} + +func (s *ListTagResourcesResponseBodyTagResources) SetTagResource(v []*ListTagResourcesResponseBodyTagResourcesTagResource) *ListTagResourcesResponseBodyTagResources { + s.TagResource = v + return s +} + +type ListTagResourcesResponseBodyTagResourcesTagResource struct { + ResourceId *string `json:"ResourceId,omitempty" xml:"ResourceId,omitempty"` + ResourceType *string `json:"ResourceType,omitempty" xml:"ResourceType,omitempty"` + TagKey *string `json:"TagKey,omitempty" xml:"TagKey,omitempty"` + TagValue *string `json:"TagValue,omitempty" xml:"TagValue,omitempty"` +} + +func (s ListTagResourcesResponseBodyTagResourcesTagResource) String() string { + return tea.Prettify(s) +} + +func (s ListTagResourcesResponseBodyTagResourcesTagResource) GoString() string { + return s.String() +} + +func (s *ListTagResourcesResponseBodyTagResourcesTagResource) SetResourceId(v string) *ListTagResourcesResponseBodyTagResourcesTagResource { + s.ResourceId = &v + return s +} + +func (s *ListTagResourcesResponseBodyTagResourcesTagResource) SetResourceType(v string) *ListTagResourcesResponseBodyTagResourcesTagResource { + s.ResourceType = &v + return s +} + +func (s *ListTagResourcesResponseBodyTagResourcesTagResource) SetTagKey(v string) *ListTagResourcesResponseBodyTagResourcesTagResource { + s.TagKey = &v + return s +} + +func (s *ListTagResourcesResponseBodyTagResourcesTagResource) SetTagValue(v string) *ListTagResourcesResponseBodyTagResourcesTagResource { + s.TagValue = &v + return s +} + +type ListTagResourcesResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *ListTagResourcesResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s ListTagResourcesResponse) String() string { + return tea.Prettify(s) +} + +func (s ListTagResourcesResponse) GoString() string { + return s.String() +} + +func (s *ListTagResourcesResponse) SetHeaders(v map[string]*string) *ListTagResourcesResponse { + s.Headers = v + return s +} + +func (s *ListTagResourcesResponse) SetBody(v *ListTagResourcesResponseBody) *ListTagResourcesResponse { + s.Body = v + return s +} + +type ModifySmsSignRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + Remark *string `json:"Remark,omitempty" xml:"Remark,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SignFileList []*ModifySmsSignRequestSignFileList `json:"SignFileList,omitempty" xml:"SignFileList,omitempty" type:"Repeated"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` + SignSource *int32 `json:"SignSource,omitempty" xml:"SignSource,omitempty"` +} + +func (s ModifySmsSignRequest) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsSignRequest) GoString() string { + return s.String() +} + +func (s *ModifySmsSignRequest) SetOwnerId(v int64) *ModifySmsSignRequest { + s.OwnerId = &v + return s +} + +func (s *ModifySmsSignRequest) SetRemark(v string) *ModifySmsSignRequest { + s.Remark = &v + return s +} + +func (s *ModifySmsSignRequest) SetResourceOwnerAccount(v string) *ModifySmsSignRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *ModifySmsSignRequest) SetResourceOwnerId(v int64) *ModifySmsSignRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *ModifySmsSignRequest) SetSignFileList(v []*ModifySmsSignRequestSignFileList) *ModifySmsSignRequest { + s.SignFileList = v + return s +} + +func (s *ModifySmsSignRequest) SetSignName(v string) *ModifySmsSignRequest { + s.SignName = &v + return s +} + +func (s *ModifySmsSignRequest) SetSignSource(v int32) *ModifySmsSignRequest { + s.SignSource = &v + return s +} + +type ModifySmsSignRequestSignFileList struct { + FileContents *string `json:"FileContents,omitempty" xml:"FileContents,omitempty"` + FileSuffix *string `json:"FileSuffix,omitempty" xml:"FileSuffix,omitempty"` +} + +func (s ModifySmsSignRequestSignFileList) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsSignRequestSignFileList) GoString() string { + return s.String() +} + +func (s *ModifySmsSignRequestSignFileList) SetFileContents(v string) *ModifySmsSignRequestSignFileList { + s.FileContents = &v + return s +} + +func (s *ModifySmsSignRequestSignFileList) SetFileSuffix(v string) *ModifySmsSignRequestSignFileList { + s.FileSuffix = &v + return s +} + +type ModifySmsSignResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` +} + +func (s ModifySmsSignResponseBody) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsSignResponseBody) GoString() string { + return s.String() +} + +func (s *ModifySmsSignResponseBody) SetCode(v string) *ModifySmsSignResponseBody { + s.Code = &v + return s +} + +func (s *ModifySmsSignResponseBody) SetMessage(v string) *ModifySmsSignResponseBody { + s.Message = &v + return s +} + +func (s *ModifySmsSignResponseBody) SetRequestId(v string) *ModifySmsSignResponseBody { + s.RequestId = &v + return s +} + +func (s *ModifySmsSignResponseBody) SetSignName(v string) *ModifySmsSignResponseBody { + s.SignName = &v + return s +} + +type ModifySmsSignResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *ModifySmsSignResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s ModifySmsSignResponse) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsSignResponse) GoString() string { + return s.String() +} + +func (s *ModifySmsSignResponse) SetHeaders(v map[string]*string) *ModifySmsSignResponse { + s.Headers = v + return s +} + +func (s *ModifySmsSignResponse) SetBody(v *ModifySmsSignResponseBody) *ModifySmsSignResponse { + s.Body = v + return s +} + +type ModifySmsTemplateRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + Remark *string `json:"Remark,omitempty" xml:"Remark,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` + TemplateContent *string `json:"TemplateContent,omitempty" xml:"TemplateContent,omitempty"` + TemplateName *string `json:"TemplateName,omitempty" xml:"TemplateName,omitempty"` + TemplateType *int32 `json:"TemplateType,omitempty" xml:"TemplateType,omitempty"` +} + +func (s ModifySmsTemplateRequest) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsTemplateRequest) GoString() string { + return s.String() +} + +func (s *ModifySmsTemplateRequest) SetOwnerId(v int64) *ModifySmsTemplateRequest { + s.OwnerId = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetRemark(v string) *ModifySmsTemplateRequest { + s.Remark = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetResourceOwnerAccount(v string) *ModifySmsTemplateRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetResourceOwnerId(v int64) *ModifySmsTemplateRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetTemplateCode(v string) *ModifySmsTemplateRequest { + s.TemplateCode = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetTemplateContent(v string) *ModifySmsTemplateRequest { + s.TemplateContent = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetTemplateName(v string) *ModifySmsTemplateRequest { + s.TemplateName = &v + return s +} + +func (s *ModifySmsTemplateRequest) SetTemplateType(v int32) *ModifySmsTemplateRequest { + s.TemplateType = &v + return s +} + +type ModifySmsTemplateResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` +} + +func (s ModifySmsTemplateResponseBody) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsTemplateResponseBody) GoString() string { + return s.String() +} + +func (s *ModifySmsTemplateResponseBody) SetCode(v string) *ModifySmsTemplateResponseBody { + s.Code = &v + return s +} + +func (s *ModifySmsTemplateResponseBody) SetMessage(v string) *ModifySmsTemplateResponseBody { + s.Message = &v + return s +} + +func (s *ModifySmsTemplateResponseBody) SetRequestId(v string) *ModifySmsTemplateResponseBody { + s.RequestId = &v + return s +} + +func (s *ModifySmsTemplateResponseBody) SetTemplateCode(v string) *ModifySmsTemplateResponseBody { + s.TemplateCode = &v + return s +} + +type ModifySmsTemplateResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *ModifySmsTemplateResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s ModifySmsTemplateResponse) String() string { + return tea.Prettify(s) +} + +func (s ModifySmsTemplateResponse) GoString() string { + return s.String() +} + +func (s *ModifySmsTemplateResponse) SetHeaders(v map[string]*string) *ModifySmsTemplateResponse { + s.Headers = v + return s +} + +func (s *ModifySmsTemplateResponse) SetBody(v *ModifySmsTemplateResponseBody) *ModifySmsTemplateResponse { + s.Body = v + return s +} + +type QuerySendDetailsRequest struct { + BizId *string `json:"BizId,omitempty" xml:"BizId,omitempty"` + CurrentPage *int64 `json:"CurrentPage,omitempty" xml:"CurrentPage,omitempty"` + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PageSize *int64 `json:"PageSize,omitempty" xml:"PageSize,omitempty"` + PhoneNumber *string `json:"PhoneNumber,omitempty" xml:"PhoneNumber,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SendDate *string `json:"SendDate,omitempty" xml:"SendDate,omitempty"` +} + +func (s QuerySendDetailsRequest) String() string { + return tea.Prettify(s) +} + +func (s QuerySendDetailsRequest) GoString() string { + return s.String() +} + +func (s *QuerySendDetailsRequest) SetBizId(v string) *QuerySendDetailsRequest { + s.BizId = &v + return s +} + +func (s *QuerySendDetailsRequest) SetCurrentPage(v int64) *QuerySendDetailsRequest { + s.CurrentPage = &v + return s +} + +func (s *QuerySendDetailsRequest) SetOwnerId(v int64) *QuerySendDetailsRequest { + s.OwnerId = &v + return s +} + +func (s *QuerySendDetailsRequest) SetPageSize(v int64) *QuerySendDetailsRequest { + s.PageSize = &v + return s +} + +func (s *QuerySendDetailsRequest) SetPhoneNumber(v string) *QuerySendDetailsRequest { + s.PhoneNumber = &v + return s +} + +func (s *QuerySendDetailsRequest) SetResourceOwnerAccount(v string) *QuerySendDetailsRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QuerySendDetailsRequest) SetResourceOwnerId(v int64) *QuerySendDetailsRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *QuerySendDetailsRequest) SetSendDate(v string) *QuerySendDetailsRequest { + s.SendDate = &v + return s +} + +type QuerySendDetailsResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SmsSendDetailDTOs *QuerySendDetailsResponseBodySmsSendDetailDTOs `json:"SmsSendDetailDTOs,omitempty" xml:"SmsSendDetailDTOs,omitempty" type:"Struct"` + TotalCount *string `json:"TotalCount,omitempty" xml:"TotalCount,omitempty"` +} + +func (s QuerySendDetailsResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QuerySendDetailsResponseBody) GoString() string { + return s.String() +} + +func (s *QuerySendDetailsResponseBody) SetCode(v string) *QuerySendDetailsResponseBody { + s.Code = &v + return s +} + +func (s *QuerySendDetailsResponseBody) SetMessage(v string) *QuerySendDetailsResponseBody { + s.Message = &v + return s +} + +func (s *QuerySendDetailsResponseBody) SetRequestId(v string) *QuerySendDetailsResponseBody { + s.RequestId = &v + return s +} + +func (s *QuerySendDetailsResponseBody) SetSmsSendDetailDTOs(v *QuerySendDetailsResponseBodySmsSendDetailDTOs) *QuerySendDetailsResponseBody { + s.SmsSendDetailDTOs = v + return s +} + +func (s *QuerySendDetailsResponseBody) SetTotalCount(v string) *QuerySendDetailsResponseBody { + s.TotalCount = &v + return s +} + +type QuerySendDetailsResponseBodySmsSendDetailDTOs struct { + SmsSendDetailDTO []*QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO `json:"SmsSendDetailDTO,omitempty" xml:"SmsSendDetailDTO,omitempty" type:"Repeated"` +} + +func (s QuerySendDetailsResponseBodySmsSendDetailDTOs) String() string { + return tea.Prettify(s) +} + +func (s QuerySendDetailsResponseBodySmsSendDetailDTOs) GoString() string { + return s.String() +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOs) SetSmsSendDetailDTO(v []*QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) *QuerySendDetailsResponseBodySmsSendDetailDTOs { + s.SmsSendDetailDTO = v + return s +} + +type QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO struct { + Content *string `json:"Content,omitempty" xml:"Content,omitempty"` + ErrCode *string `json:"ErrCode,omitempty" xml:"ErrCode,omitempty"` + OutId *string `json:"OutId,omitempty" xml:"OutId,omitempty"` + PhoneNum *string `json:"PhoneNum,omitempty" xml:"PhoneNum,omitempty"` + ReceiveDate *string `json:"ReceiveDate,omitempty" xml:"ReceiveDate,omitempty"` + SendDate *string `json:"SendDate,omitempty" xml:"SendDate,omitempty"` + SendStatus *int64 `json:"SendStatus,omitempty" xml:"SendStatus,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` +} + +func (s QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) String() string { + return tea.Prettify(s) +} + +func (s QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) GoString() string { + return s.String() +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetContent(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.Content = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetErrCode(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.ErrCode = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetOutId(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.OutId = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetPhoneNum(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.PhoneNum = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetReceiveDate(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.ReceiveDate = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetSendDate(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.SendDate = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetSendStatus(v int64) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.SendStatus = &v + return s +} + +func (s *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO) SetTemplateCode(v string) *QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO { + s.TemplateCode = &v + return s +} + +type QuerySendDetailsResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QuerySendDetailsResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QuerySendDetailsResponse) String() string { + return tea.Prettify(s) +} + +func (s QuerySendDetailsResponse) GoString() string { + return s.String() +} + +func (s *QuerySendDetailsResponse) SetHeaders(v map[string]*string) *QuerySendDetailsResponse { + s.Headers = v + return s +} + +func (s *QuerySendDetailsResponse) SetBody(v *QuerySendDetailsResponseBody) *QuerySendDetailsResponse { + s.Body = v + return s +} + +type QuerySendStatisticsRequest struct { + EndDate *string `json:"EndDate,omitempty" xml:"EndDate,omitempty"` + IsGlobe *int32 `json:"IsGlobe,omitempty" xml:"IsGlobe,omitempty"` + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PageIndex *int32 `json:"PageIndex,omitempty" xml:"PageIndex,omitempty"` + PageSize *int32 `json:"PageSize,omitempty" xml:"PageSize,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + StartDate *string `json:"StartDate,omitempty" xml:"StartDate,omitempty"` +} + +func (s QuerySendStatisticsRequest) String() string { + return tea.Prettify(s) +} + +func (s QuerySendStatisticsRequest) GoString() string { + return s.String() +} + +func (s *QuerySendStatisticsRequest) SetEndDate(v string) *QuerySendStatisticsRequest { + s.EndDate = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetIsGlobe(v int32) *QuerySendStatisticsRequest { + s.IsGlobe = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetOwnerId(v int64) *QuerySendStatisticsRequest { + s.OwnerId = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetPageIndex(v int32) *QuerySendStatisticsRequest { + s.PageIndex = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetPageSize(v int32) *QuerySendStatisticsRequest { + s.PageSize = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetResourceOwnerAccount(v string) *QuerySendStatisticsRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetResourceOwnerId(v int64) *QuerySendStatisticsRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *QuerySendStatisticsRequest) SetStartDate(v string) *QuerySendStatisticsRequest { + s.StartDate = &v + return s +} + +type QuerySendStatisticsResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Data *QuerySendStatisticsResponseBodyData `json:"Data,omitempty" xml:"Data,omitempty" type:"Struct"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s QuerySendStatisticsResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QuerySendStatisticsResponseBody) GoString() string { + return s.String() +} + +func (s *QuerySendStatisticsResponseBody) SetCode(v string) *QuerySendStatisticsResponseBody { + s.Code = &v + return s +} + +func (s *QuerySendStatisticsResponseBody) SetData(v *QuerySendStatisticsResponseBodyData) *QuerySendStatisticsResponseBody { + s.Data = v + return s +} + +func (s *QuerySendStatisticsResponseBody) SetMessage(v string) *QuerySendStatisticsResponseBody { + s.Message = &v + return s +} + +func (s *QuerySendStatisticsResponseBody) SetRequestId(v string) *QuerySendStatisticsResponseBody { + s.RequestId = &v + return s +} + +type QuerySendStatisticsResponseBodyData struct { + TargetList []*QuerySendStatisticsResponseBodyDataTargetList `json:"TargetList,omitempty" xml:"TargetList,omitempty" type:"Repeated"` + TotalSize *int64 `json:"TotalSize,omitempty" xml:"TotalSize,omitempty"` +} + +func (s QuerySendStatisticsResponseBodyData) String() string { + return tea.Prettify(s) +} + +func (s QuerySendStatisticsResponseBodyData) GoString() string { + return s.String() +} + +func (s *QuerySendStatisticsResponseBodyData) SetTargetList(v []*QuerySendStatisticsResponseBodyDataTargetList) *QuerySendStatisticsResponseBodyData { + s.TargetList = v + return s +} + +func (s *QuerySendStatisticsResponseBodyData) SetTotalSize(v int64) *QuerySendStatisticsResponseBodyData { + s.TotalSize = &v + return s +} + +type QuerySendStatisticsResponseBodyDataTargetList struct { + NoRespondedCount *int64 `json:"NoRespondedCount,omitempty" xml:"NoRespondedCount,omitempty"` + RespondedFailCount *int64 `json:"RespondedFailCount,omitempty" xml:"RespondedFailCount,omitempty"` + RespondedSuccessCount *int64 `json:"RespondedSuccessCount,omitempty" xml:"RespondedSuccessCount,omitempty"` + SendDate *string `json:"SendDate,omitempty" xml:"SendDate,omitempty"` + TotalCount *int64 `json:"TotalCount,omitempty" xml:"TotalCount,omitempty"` +} + +func (s QuerySendStatisticsResponseBodyDataTargetList) String() string { + return tea.Prettify(s) +} + +func (s QuerySendStatisticsResponseBodyDataTargetList) GoString() string { + return s.String() +} + +func (s *QuerySendStatisticsResponseBodyDataTargetList) SetNoRespondedCount(v int64) *QuerySendStatisticsResponseBodyDataTargetList { + s.NoRespondedCount = &v + return s +} + +func (s *QuerySendStatisticsResponseBodyDataTargetList) SetRespondedFailCount(v int64) *QuerySendStatisticsResponseBodyDataTargetList { + s.RespondedFailCount = &v + return s +} + +func (s *QuerySendStatisticsResponseBodyDataTargetList) SetRespondedSuccessCount(v int64) *QuerySendStatisticsResponseBodyDataTargetList { + s.RespondedSuccessCount = &v + return s +} + +func (s *QuerySendStatisticsResponseBodyDataTargetList) SetSendDate(v string) *QuerySendStatisticsResponseBodyDataTargetList { + s.SendDate = &v + return s +} + +func (s *QuerySendStatisticsResponseBodyDataTargetList) SetTotalCount(v int64) *QuerySendStatisticsResponseBodyDataTargetList { + s.TotalCount = &v + return s +} + +type QuerySendStatisticsResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QuerySendStatisticsResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QuerySendStatisticsResponse) String() string { + return tea.Prettify(s) +} + +func (s QuerySendStatisticsResponse) GoString() string { + return s.String() +} + +func (s *QuerySendStatisticsResponse) SetHeaders(v map[string]*string) *QuerySendStatisticsResponse { + s.Headers = v + return s +} + +func (s *QuerySendStatisticsResponse) SetBody(v *QuerySendStatisticsResponseBody) *QuerySendStatisticsResponse { + s.Body = v + return s +} + +type QueryShortUrlRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + ShortUrl *string `json:"ShortUrl,omitempty" xml:"ShortUrl,omitempty"` +} + +func (s QueryShortUrlRequest) String() string { + return tea.Prettify(s) +} + +func (s QueryShortUrlRequest) GoString() string { + return s.String() +} + +func (s *QueryShortUrlRequest) SetOwnerId(v int64) *QueryShortUrlRequest { + s.OwnerId = &v + return s +} + +func (s *QueryShortUrlRequest) SetResourceOwnerAccount(v string) *QueryShortUrlRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QueryShortUrlRequest) SetResourceOwnerId(v int64) *QueryShortUrlRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *QueryShortUrlRequest) SetShortUrl(v string) *QueryShortUrlRequest { + s.ShortUrl = &v + return s +} + +type QueryShortUrlResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Data *QueryShortUrlResponseBodyData `json:"Data,omitempty" xml:"Data,omitempty" type:"Struct"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s QueryShortUrlResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QueryShortUrlResponseBody) GoString() string { + return s.String() +} + +func (s *QueryShortUrlResponseBody) SetCode(v string) *QueryShortUrlResponseBody { + s.Code = &v + return s +} + +func (s *QueryShortUrlResponseBody) SetData(v *QueryShortUrlResponseBodyData) *QueryShortUrlResponseBody { + s.Data = v + return s +} + +func (s *QueryShortUrlResponseBody) SetMessage(v string) *QueryShortUrlResponseBody { + s.Message = &v + return s +} + +func (s *QueryShortUrlResponseBody) SetRequestId(v string) *QueryShortUrlResponseBody { + s.RequestId = &v + return s +} + +type QueryShortUrlResponseBodyData struct { + CreateDate *string `json:"CreateDate,omitempty" xml:"CreateDate,omitempty"` + ExpireDate *string `json:"ExpireDate,omitempty" xml:"ExpireDate,omitempty"` + PageViewCount *string `json:"PageViewCount,omitempty" xml:"PageViewCount,omitempty"` + ShortUrl *string `json:"ShortUrl,omitempty" xml:"ShortUrl,omitempty"` + ShortUrlName *string `json:"ShortUrlName,omitempty" xml:"ShortUrlName,omitempty"` + ShortUrlStatus *string `json:"ShortUrlStatus,omitempty" xml:"ShortUrlStatus,omitempty"` + SourceUrl *string `json:"SourceUrl,omitempty" xml:"SourceUrl,omitempty"` + UniqueVisitorCount *string `json:"UniqueVisitorCount,omitempty" xml:"UniqueVisitorCount,omitempty"` +} + +func (s QueryShortUrlResponseBodyData) String() string { + return tea.Prettify(s) +} + +func (s QueryShortUrlResponseBodyData) GoString() string { + return s.String() +} + +func (s *QueryShortUrlResponseBodyData) SetCreateDate(v string) *QueryShortUrlResponseBodyData { + s.CreateDate = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetExpireDate(v string) *QueryShortUrlResponseBodyData { + s.ExpireDate = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetPageViewCount(v string) *QueryShortUrlResponseBodyData { + s.PageViewCount = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetShortUrl(v string) *QueryShortUrlResponseBodyData { + s.ShortUrl = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetShortUrlName(v string) *QueryShortUrlResponseBodyData { + s.ShortUrlName = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetShortUrlStatus(v string) *QueryShortUrlResponseBodyData { + s.ShortUrlStatus = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetSourceUrl(v string) *QueryShortUrlResponseBodyData { + s.SourceUrl = &v + return s +} + +func (s *QueryShortUrlResponseBodyData) SetUniqueVisitorCount(v string) *QueryShortUrlResponseBodyData { + s.UniqueVisitorCount = &v + return s +} + +type QueryShortUrlResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QueryShortUrlResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QueryShortUrlResponse) String() string { + return tea.Prettify(s) +} + +func (s QueryShortUrlResponse) GoString() string { + return s.String() +} + +func (s *QueryShortUrlResponse) SetHeaders(v map[string]*string) *QueryShortUrlResponse { + s.Headers = v + return s +} + +func (s *QueryShortUrlResponse) SetBody(v *QueryShortUrlResponseBody) *QueryShortUrlResponse { + s.Body = v + return s +} + +type QuerySmsSignRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` +} + +func (s QuerySmsSignRequest) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignRequest) GoString() string { + return s.String() +} + +func (s *QuerySmsSignRequest) SetOwnerId(v int64) *QuerySmsSignRequest { + s.OwnerId = &v + return s +} + +func (s *QuerySmsSignRequest) SetResourceOwnerAccount(v string) *QuerySmsSignRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QuerySmsSignRequest) SetResourceOwnerId(v int64) *QuerySmsSignRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *QuerySmsSignRequest) SetSignName(v string) *QuerySmsSignRequest { + s.SignName = &v + return s +} + +type QuerySmsSignResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + CreateDate *string `json:"CreateDate,omitempty" xml:"CreateDate,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + Reason *string `json:"Reason,omitempty" xml:"Reason,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` + SignStatus *int32 `json:"SignStatus,omitempty" xml:"SignStatus,omitempty"` +} + +func (s QuerySmsSignResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignResponseBody) GoString() string { + return s.String() +} + +func (s *QuerySmsSignResponseBody) SetCode(v string) *QuerySmsSignResponseBody { + s.Code = &v + return s +} + +func (s *QuerySmsSignResponseBody) SetCreateDate(v string) *QuerySmsSignResponseBody { + s.CreateDate = &v + return s +} + +func (s *QuerySmsSignResponseBody) SetMessage(v string) *QuerySmsSignResponseBody { + s.Message = &v + return s +} + +func (s *QuerySmsSignResponseBody) SetReason(v string) *QuerySmsSignResponseBody { + s.Reason = &v + return s +} + +func (s *QuerySmsSignResponseBody) SetRequestId(v string) *QuerySmsSignResponseBody { + s.RequestId = &v + return s +} + +func (s *QuerySmsSignResponseBody) SetSignName(v string) *QuerySmsSignResponseBody { + s.SignName = &v + return s +} + +func (s *QuerySmsSignResponseBody) SetSignStatus(v int32) *QuerySmsSignResponseBody { + s.SignStatus = &v + return s +} + +type QuerySmsSignResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QuerySmsSignResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QuerySmsSignResponse) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignResponse) GoString() string { + return s.String() +} + +func (s *QuerySmsSignResponse) SetHeaders(v map[string]*string) *QuerySmsSignResponse { + s.Headers = v + return s +} + +func (s *QuerySmsSignResponse) SetBody(v *QuerySmsSignResponseBody) *QuerySmsSignResponse { + s.Body = v + return s +} + +type QuerySmsSignListRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PageIndex *int32 `json:"PageIndex,omitempty" xml:"PageIndex,omitempty"` + PageSize *int32 `json:"PageSize,omitempty" xml:"PageSize,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` +} + +func (s QuerySmsSignListRequest) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignListRequest) GoString() string { + return s.String() +} + +func (s *QuerySmsSignListRequest) SetOwnerId(v int64) *QuerySmsSignListRequest { + s.OwnerId = &v + return s +} + +func (s *QuerySmsSignListRequest) SetPageIndex(v int32) *QuerySmsSignListRequest { + s.PageIndex = &v + return s +} + +func (s *QuerySmsSignListRequest) SetPageSize(v int32) *QuerySmsSignListRequest { + s.PageSize = &v + return s +} + +func (s *QuerySmsSignListRequest) SetResourceOwnerAccount(v string) *QuerySmsSignListRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QuerySmsSignListRequest) SetResourceOwnerId(v int64) *QuerySmsSignListRequest { + s.ResourceOwnerId = &v + return s +} + +type QuerySmsSignListResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SmsSignList []*QuerySmsSignListResponseBodySmsSignList `json:"SmsSignList,omitempty" xml:"SmsSignList,omitempty" type:"Repeated"` +} + +func (s QuerySmsSignListResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignListResponseBody) GoString() string { + return s.String() +} + +func (s *QuerySmsSignListResponseBody) SetCode(v string) *QuerySmsSignListResponseBody { + s.Code = &v + return s +} + +func (s *QuerySmsSignListResponseBody) SetMessage(v string) *QuerySmsSignListResponseBody { + s.Message = &v + return s +} + +func (s *QuerySmsSignListResponseBody) SetRequestId(v string) *QuerySmsSignListResponseBody { + s.RequestId = &v + return s +} + +func (s *QuerySmsSignListResponseBody) SetSmsSignList(v []*QuerySmsSignListResponseBodySmsSignList) *QuerySmsSignListResponseBody { + s.SmsSignList = v + return s +} + +type QuerySmsSignListResponseBodySmsSignList struct { + AuditStatus *string `json:"AuditStatus,omitempty" xml:"AuditStatus,omitempty"` + BusinessType *string `json:"BusinessType,omitempty" xml:"BusinessType,omitempty"` + CreateDate *string `json:"CreateDate,omitempty" xml:"CreateDate,omitempty"` + OrderId *string `json:"OrderId,omitempty" xml:"OrderId,omitempty"` + Reason *QuerySmsSignListResponseBodySmsSignListReason `json:"Reason,omitempty" xml:"Reason,omitempty" type:"Struct"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` +} + +func (s QuerySmsSignListResponseBodySmsSignList) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignListResponseBodySmsSignList) GoString() string { + return s.String() +} + +func (s *QuerySmsSignListResponseBodySmsSignList) SetAuditStatus(v string) *QuerySmsSignListResponseBodySmsSignList { + s.AuditStatus = &v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignList) SetBusinessType(v string) *QuerySmsSignListResponseBodySmsSignList { + s.BusinessType = &v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignList) SetCreateDate(v string) *QuerySmsSignListResponseBodySmsSignList { + s.CreateDate = &v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignList) SetOrderId(v string) *QuerySmsSignListResponseBodySmsSignList { + s.OrderId = &v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignList) SetReason(v *QuerySmsSignListResponseBodySmsSignListReason) *QuerySmsSignListResponseBodySmsSignList { + s.Reason = v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignList) SetSignName(v string) *QuerySmsSignListResponseBodySmsSignList { + s.SignName = &v + return s +} + +type QuerySmsSignListResponseBodySmsSignListReason struct { + RejectDate *string `json:"RejectDate,omitempty" xml:"RejectDate,omitempty"` + RejectInfo *string `json:"RejectInfo,omitempty" xml:"RejectInfo,omitempty"` + RejectSubInfo *string `json:"RejectSubInfo,omitempty" xml:"RejectSubInfo,omitempty"` +} + +func (s QuerySmsSignListResponseBodySmsSignListReason) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignListResponseBodySmsSignListReason) GoString() string { + return s.String() +} + +func (s *QuerySmsSignListResponseBodySmsSignListReason) SetRejectDate(v string) *QuerySmsSignListResponseBodySmsSignListReason { + s.RejectDate = &v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignListReason) SetRejectInfo(v string) *QuerySmsSignListResponseBodySmsSignListReason { + s.RejectInfo = &v + return s +} + +func (s *QuerySmsSignListResponseBodySmsSignListReason) SetRejectSubInfo(v string) *QuerySmsSignListResponseBodySmsSignListReason { + s.RejectSubInfo = &v + return s +} + +type QuerySmsSignListResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QuerySmsSignListResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QuerySmsSignListResponse) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsSignListResponse) GoString() string { + return s.String() +} + +func (s *QuerySmsSignListResponse) SetHeaders(v map[string]*string) *QuerySmsSignListResponse { + s.Headers = v + return s +} + +func (s *QuerySmsSignListResponse) SetBody(v *QuerySmsSignListResponseBody) *QuerySmsSignListResponse { + s.Body = v + return s +} + +type QuerySmsTemplateRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` +} + +func (s QuerySmsTemplateRequest) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateRequest) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateRequest) SetOwnerId(v int64) *QuerySmsTemplateRequest { + s.OwnerId = &v + return s +} + +func (s *QuerySmsTemplateRequest) SetResourceOwnerAccount(v string) *QuerySmsTemplateRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QuerySmsTemplateRequest) SetResourceOwnerId(v int64) *QuerySmsTemplateRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *QuerySmsTemplateRequest) SetTemplateCode(v string) *QuerySmsTemplateRequest { + s.TemplateCode = &v + return s +} + +type QuerySmsTemplateResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + CreateDate *string `json:"CreateDate,omitempty" xml:"CreateDate,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + Reason *string `json:"Reason,omitempty" xml:"Reason,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` + TemplateContent *string `json:"TemplateContent,omitempty" xml:"TemplateContent,omitempty"` + TemplateName *string `json:"TemplateName,omitempty" xml:"TemplateName,omitempty"` + TemplateStatus *int32 `json:"TemplateStatus,omitempty" xml:"TemplateStatus,omitempty"` + TemplateType *int32 `json:"TemplateType,omitempty" xml:"TemplateType,omitempty"` +} + +func (s QuerySmsTemplateResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateResponseBody) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateResponseBody) SetCode(v string) *QuerySmsTemplateResponseBody { + s.Code = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetCreateDate(v string) *QuerySmsTemplateResponseBody { + s.CreateDate = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetMessage(v string) *QuerySmsTemplateResponseBody { + s.Message = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetReason(v string) *QuerySmsTemplateResponseBody { + s.Reason = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetRequestId(v string) *QuerySmsTemplateResponseBody { + s.RequestId = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetTemplateCode(v string) *QuerySmsTemplateResponseBody { + s.TemplateCode = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetTemplateContent(v string) *QuerySmsTemplateResponseBody { + s.TemplateContent = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetTemplateName(v string) *QuerySmsTemplateResponseBody { + s.TemplateName = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetTemplateStatus(v int32) *QuerySmsTemplateResponseBody { + s.TemplateStatus = &v + return s +} + +func (s *QuerySmsTemplateResponseBody) SetTemplateType(v int32) *QuerySmsTemplateResponseBody { + s.TemplateType = &v + return s +} + +type QuerySmsTemplateResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QuerySmsTemplateResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QuerySmsTemplateResponse) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateResponse) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateResponse) SetHeaders(v map[string]*string) *QuerySmsTemplateResponse { + s.Headers = v + return s +} + +func (s *QuerySmsTemplateResponse) SetBody(v *QuerySmsTemplateResponseBody) *QuerySmsTemplateResponse { + s.Body = v + return s +} + +type QuerySmsTemplateListRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PageIndex *int32 `json:"PageIndex,omitempty" xml:"PageIndex,omitempty"` + PageSize *int32 `json:"PageSize,omitempty" xml:"PageSize,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` +} + +func (s QuerySmsTemplateListRequest) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateListRequest) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateListRequest) SetOwnerId(v int64) *QuerySmsTemplateListRequest { + s.OwnerId = &v + return s +} + +func (s *QuerySmsTemplateListRequest) SetPageIndex(v int32) *QuerySmsTemplateListRequest { + s.PageIndex = &v + return s +} + +func (s *QuerySmsTemplateListRequest) SetPageSize(v int32) *QuerySmsTemplateListRequest { + s.PageSize = &v + return s +} + +func (s *QuerySmsTemplateListRequest) SetResourceOwnerAccount(v string) *QuerySmsTemplateListRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *QuerySmsTemplateListRequest) SetResourceOwnerId(v int64) *QuerySmsTemplateListRequest { + s.ResourceOwnerId = &v + return s +} + +type QuerySmsTemplateListResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` + SmsTemplateList []*QuerySmsTemplateListResponseBodySmsTemplateList `json:"SmsTemplateList,omitempty" xml:"SmsTemplateList,omitempty" type:"Repeated"` +} + +func (s QuerySmsTemplateListResponseBody) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateListResponseBody) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateListResponseBody) SetCode(v string) *QuerySmsTemplateListResponseBody { + s.Code = &v + return s +} + +func (s *QuerySmsTemplateListResponseBody) SetMessage(v string) *QuerySmsTemplateListResponseBody { + s.Message = &v + return s +} + +func (s *QuerySmsTemplateListResponseBody) SetRequestId(v string) *QuerySmsTemplateListResponseBody { + s.RequestId = &v + return s +} + +func (s *QuerySmsTemplateListResponseBody) SetSmsTemplateList(v []*QuerySmsTemplateListResponseBodySmsTemplateList) *QuerySmsTemplateListResponseBody { + s.SmsTemplateList = v + return s +} + +type QuerySmsTemplateListResponseBodySmsTemplateList struct { + AuditStatus *string `json:"AuditStatus,omitempty" xml:"AuditStatus,omitempty"` + CreateDate *string `json:"CreateDate,omitempty" xml:"CreateDate,omitempty"` + OrderId *string `json:"OrderId,omitempty" xml:"OrderId,omitempty"` + Reason *QuerySmsTemplateListResponseBodySmsTemplateListReason `json:"Reason,omitempty" xml:"Reason,omitempty" type:"Struct"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` + TemplateContent *string `json:"TemplateContent,omitempty" xml:"TemplateContent,omitempty"` + TemplateName *string `json:"TemplateName,omitempty" xml:"TemplateName,omitempty"` + TemplateType *int32 `json:"TemplateType,omitempty" xml:"TemplateType,omitempty"` +} + +func (s QuerySmsTemplateListResponseBodySmsTemplateList) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateListResponseBodySmsTemplateList) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetAuditStatus(v string) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.AuditStatus = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetCreateDate(v string) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.CreateDate = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetOrderId(v string) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.OrderId = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetReason(v *QuerySmsTemplateListResponseBodySmsTemplateListReason) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.Reason = v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetTemplateCode(v string) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.TemplateCode = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetTemplateContent(v string) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.TemplateContent = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetTemplateName(v string) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.TemplateName = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateList) SetTemplateType(v int32) *QuerySmsTemplateListResponseBodySmsTemplateList { + s.TemplateType = &v + return s +} + +type QuerySmsTemplateListResponseBodySmsTemplateListReason struct { + RejectDate *string `json:"RejectDate,omitempty" xml:"RejectDate,omitempty"` + RejectInfo *string `json:"RejectInfo,omitempty" xml:"RejectInfo,omitempty"` + RejectSubInfo *string `json:"RejectSubInfo,omitempty" xml:"RejectSubInfo,omitempty"` +} + +func (s QuerySmsTemplateListResponseBodySmsTemplateListReason) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateListResponseBodySmsTemplateListReason) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateListReason) SetRejectDate(v string) *QuerySmsTemplateListResponseBodySmsTemplateListReason { + s.RejectDate = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateListReason) SetRejectInfo(v string) *QuerySmsTemplateListResponseBodySmsTemplateListReason { + s.RejectInfo = &v + return s +} + +func (s *QuerySmsTemplateListResponseBodySmsTemplateListReason) SetRejectSubInfo(v string) *QuerySmsTemplateListResponseBodySmsTemplateListReason { + s.RejectSubInfo = &v + return s +} + +type QuerySmsTemplateListResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *QuerySmsTemplateListResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s QuerySmsTemplateListResponse) String() string { + return tea.Prettify(s) +} + +func (s QuerySmsTemplateListResponse) GoString() string { + return s.String() +} + +func (s *QuerySmsTemplateListResponse) SetHeaders(v map[string]*string) *QuerySmsTemplateListResponse { + s.Headers = v + return s +} + +func (s *QuerySmsTemplateListResponse) SetBody(v *QuerySmsTemplateListResponseBody) *QuerySmsTemplateListResponse { + s.Body = v + return s +} + +type SendBatchSmsRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PhoneNumberJson *string `json:"PhoneNumberJson,omitempty" xml:"PhoneNumberJson,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SignNameJson *string `json:"SignNameJson,omitempty" xml:"SignNameJson,omitempty"` + SmsUpExtendCodeJson *string `json:"SmsUpExtendCodeJson,omitempty" xml:"SmsUpExtendCodeJson,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` + TemplateParamJson *string `json:"TemplateParamJson,omitempty" xml:"TemplateParamJson,omitempty"` +} + +func (s SendBatchSmsRequest) String() string { + return tea.Prettify(s) +} + +func (s SendBatchSmsRequest) GoString() string { + return s.String() +} + +func (s *SendBatchSmsRequest) SetOwnerId(v int64) *SendBatchSmsRequest { + s.OwnerId = &v + return s +} + +func (s *SendBatchSmsRequest) SetPhoneNumberJson(v string) *SendBatchSmsRequest { + s.PhoneNumberJson = &v + return s +} + +func (s *SendBatchSmsRequest) SetResourceOwnerAccount(v string) *SendBatchSmsRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *SendBatchSmsRequest) SetResourceOwnerId(v int64) *SendBatchSmsRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *SendBatchSmsRequest) SetSignNameJson(v string) *SendBatchSmsRequest { + s.SignNameJson = &v + return s +} + +func (s *SendBatchSmsRequest) SetSmsUpExtendCodeJson(v string) *SendBatchSmsRequest { + s.SmsUpExtendCodeJson = &v + return s +} + +func (s *SendBatchSmsRequest) SetTemplateCode(v string) *SendBatchSmsRequest { + s.TemplateCode = &v + return s +} + +func (s *SendBatchSmsRequest) SetTemplateParamJson(v string) *SendBatchSmsRequest { + s.TemplateParamJson = &v + return s +} + +type SendBatchSmsResponseBody struct { + BizId *string `json:"BizId,omitempty" xml:"BizId,omitempty"` + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s SendBatchSmsResponseBody) String() string { + return tea.Prettify(s) +} + +func (s SendBatchSmsResponseBody) GoString() string { + return s.String() +} + +func (s *SendBatchSmsResponseBody) SetBizId(v string) *SendBatchSmsResponseBody { + s.BizId = &v + return s +} + +func (s *SendBatchSmsResponseBody) SetCode(v string) *SendBatchSmsResponseBody { + s.Code = &v + return s +} + +func (s *SendBatchSmsResponseBody) SetMessage(v string) *SendBatchSmsResponseBody { + s.Message = &v + return s +} + +func (s *SendBatchSmsResponseBody) SetRequestId(v string) *SendBatchSmsResponseBody { + s.RequestId = &v + return s +} + +type SendBatchSmsResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *SendBatchSmsResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s SendBatchSmsResponse) String() string { + return tea.Prettify(s) +} + +func (s SendBatchSmsResponse) GoString() string { + return s.String() +} + +func (s *SendBatchSmsResponse) SetHeaders(v map[string]*string) *SendBatchSmsResponse { + s.Headers = v + return s +} + +func (s *SendBatchSmsResponse) SetBody(v *SendBatchSmsResponseBody) *SendBatchSmsResponse { + s.Body = v + return s +} + +type SendSmsRequest struct { + OutId *string `json:"OutId,omitempty" xml:"OutId,omitempty"` + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + PhoneNumbers *string `json:"PhoneNumbers,omitempty" xml:"PhoneNumbers,omitempty"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + SignName *string `json:"SignName,omitempty" xml:"SignName,omitempty"` + SmsUpExtendCode *string `json:"SmsUpExtendCode,omitempty" xml:"SmsUpExtendCode,omitempty"` + TemplateCode *string `json:"TemplateCode,omitempty" xml:"TemplateCode,omitempty"` + TemplateParam *string `json:"TemplateParam,omitempty" xml:"TemplateParam,omitempty"` +} + +func (s SendSmsRequest) String() string { + return tea.Prettify(s) +} + +func (s SendSmsRequest) GoString() string { + return s.String() +} + +func (s *SendSmsRequest) SetOutId(v string) *SendSmsRequest { + s.OutId = &v + return s +} + +func (s *SendSmsRequest) SetOwnerId(v int64) *SendSmsRequest { + s.OwnerId = &v + return s +} + +func (s *SendSmsRequest) SetPhoneNumbers(v string) *SendSmsRequest { + s.PhoneNumbers = &v + return s +} + +func (s *SendSmsRequest) SetResourceOwnerAccount(v string) *SendSmsRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *SendSmsRequest) SetResourceOwnerId(v int64) *SendSmsRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *SendSmsRequest) SetSignName(v string) *SendSmsRequest { + s.SignName = &v + return s +} + +func (s *SendSmsRequest) SetSmsUpExtendCode(v string) *SendSmsRequest { + s.SmsUpExtendCode = &v + return s +} + +func (s *SendSmsRequest) SetTemplateCode(v string) *SendSmsRequest { + s.TemplateCode = &v + return s +} + +func (s *SendSmsRequest) SetTemplateParam(v string) *SendSmsRequest { + s.TemplateParam = &v + return s +} + +type SendSmsResponseBody struct { + BizId *string `json:"BizId,omitempty" xml:"BizId,omitempty"` + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Message *string `json:"Message,omitempty" xml:"Message,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s SendSmsResponseBody) String() string { + return tea.Prettify(s) +} + +func (s SendSmsResponseBody) GoString() string { + return s.String() +} + +func (s *SendSmsResponseBody) SetBizId(v string) *SendSmsResponseBody { + s.BizId = &v + return s +} + +func (s *SendSmsResponseBody) SetCode(v string) *SendSmsResponseBody { + s.Code = &v + return s +} + +func (s *SendSmsResponseBody) SetMessage(v string) *SendSmsResponseBody { + s.Message = &v + return s +} + +func (s *SendSmsResponseBody) SetRequestId(v string) *SendSmsResponseBody { + s.RequestId = &v + return s +} + +type SendSmsResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *SendSmsResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s SendSmsResponse) String() string { + return tea.Prettify(s) +} + +func (s SendSmsResponse) GoString() string { + return s.String() +} + +func (s *SendSmsResponse) SetHeaders(v map[string]*string) *SendSmsResponse { + s.Headers = v + return s +} + +func (s *SendSmsResponse) SetBody(v *SendSmsResponseBody) *SendSmsResponse { + s.Body = v + return s +} + +type TagResourcesRequest struct { + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ProdCode *string `json:"ProdCode,omitempty" xml:"ProdCode,omitempty"` + RegionId *string `json:"RegionId,omitempty" xml:"RegionId,omitempty"` + ResourceId []*string `json:"ResourceId,omitempty" xml:"ResourceId,omitempty" type:"Repeated"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + ResourceType *string `json:"ResourceType,omitempty" xml:"ResourceType,omitempty"` + Tag []*TagResourcesRequestTag `json:"Tag,omitempty" xml:"Tag,omitempty" type:"Repeated"` +} + +func (s TagResourcesRequest) String() string { + return tea.Prettify(s) +} + +func (s TagResourcesRequest) GoString() string { + return s.String() +} + +func (s *TagResourcesRequest) SetOwnerId(v int64) *TagResourcesRequest { + s.OwnerId = &v + return s +} + +func (s *TagResourcesRequest) SetProdCode(v string) *TagResourcesRequest { + s.ProdCode = &v + return s +} + +func (s *TagResourcesRequest) SetRegionId(v string) *TagResourcesRequest { + s.RegionId = &v + return s +} + +func (s *TagResourcesRequest) SetResourceId(v []*string) *TagResourcesRequest { + s.ResourceId = v + return s +} + +func (s *TagResourcesRequest) SetResourceOwnerAccount(v string) *TagResourcesRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *TagResourcesRequest) SetResourceOwnerId(v int64) *TagResourcesRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *TagResourcesRequest) SetResourceType(v string) *TagResourcesRequest { + s.ResourceType = &v + return s +} + +func (s *TagResourcesRequest) SetTag(v []*TagResourcesRequestTag) *TagResourcesRequest { + s.Tag = v + return s +} + +type TagResourcesRequestTag struct { + Key *string `json:"Key,omitempty" xml:"Key,omitempty"` + Value *string `json:"Value,omitempty" xml:"Value,omitempty"` +} + +func (s TagResourcesRequestTag) String() string { + return tea.Prettify(s) +} + +func (s TagResourcesRequestTag) GoString() string { + return s.String() +} + +func (s *TagResourcesRequestTag) SetKey(v string) *TagResourcesRequestTag { + s.Key = &v + return s +} + +func (s *TagResourcesRequestTag) SetValue(v string) *TagResourcesRequestTag { + s.Value = &v + return s +} + +type TagResourcesResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Data *string `json:"Data,omitempty" xml:"Data,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s TagResourcesResponseBody) String() string { + return tea.Prettify(s) +} + +func (s TagResourcesResponseBody) GoString() string { + return s.String() +} + +func (s *TagResourcesResponseBody) SetCode(v string) *TagResourcesResponseBody { + s.Code = &v + return s +} + +func (s *TagResourcesResponseBody) SetData(v string) *TagResourcesResponseBody { + s.Data = &v + return s +} + +func (s *TagResourcesResponseBody) SetRequestId(v string) *TagResourcesResponseBody { + s.RequestId = &v + return s +} + +type TagResourcesResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *TagResourcesResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s TagResourcesResponse) String() string { + return tea.Prettify(s) +} + +func (s TagResourcesResponse) GoString() string { + return s.String() +} + +func (s *TagResourcesResponse) SetHeaders(v map[string]*string) *TagResourcesResponse { + s.Headers = v + return s +} + +func (s *TagResourcesResponse) SetBody(v *TagResourcesResponseBody) *TagResourcesResponse { + s.Body = v + return s +} + +type UntagResourcesRequest struct { + All *bool `json:"All,omitempty" xml:"All,omitempty"` + OwnerId *int64 `json:"OwnerId,omitempty" xml:"OwnerId,omitempty"` + ProdCode *string `json:"ProdCode,omitempty" xml:"ProdCode,omitempty"` + RegionId *string `json:"RegionId,omitempty" xml:"RegionId,omitempty"` + ResourceId []*string `json:"ResourceId,omitempty" xml:"ResourceId,omitempty" type:"Repeated"` + ResourceOwnerAccount *string `json:"ResourceOwnerAccount,omitempty" xml:"ResourceOwnerAccount,omitempty"` + ResourceOwnerId *int64 `json:"ResourceOwnerId,omitempty" xml:"ResourceOwnerId,omitempty"` + ResourceType *string `json:"ResourceType,omitempty" xml:"ResourceType,omitempty"` + TagKey []*string `json:"TagKey,omitempty" xml:"TagKey,omitempty" type:"Repeated"` +} + +func (s UntagResourcesRequest) String() string { + return tea.Prettify(s) +} + +func (s UntagResourcesRequest) GoString() string { + return s.String() +} + +func (s *UntagResourcesRequest) SetAll(v bool) *UntagResourcesRequest { + s.All = &v + return s +} + +func (s *UntagResourcesRequest) SetOwnerId(v int64) *UntagResourcesRequest { + s.OwnerId = &v + return s +} + +func (s *UntagResourcesRequest) SetProdCode(v string) *UntagResourcesRequest { + s.ProdCode = &v + return s +} + +func (s *UntagResourcesRequest) SetRegionId(v string) *UntagResourcesRequest { + s.RegionId = &v + return s +} + +func (s *UntagResourcesRequest) SetResourceId(v []*string) *UntagResourcesRequest { + s.ResourceId = v + return s +} + +func (s *UntagResourcesRequest) SetResourceOwnerAccount(v string) *UntagResourcesRequest { + s.ResourceOwnerAccount = &v + return s +} + +func (s *UntagResourcesRequest) SetResourceOwnerId(v int64) *UntagResourcesRequest { + s.ResourceOwnerId = &v + return s +} + +func (s *UntagResourcesRequest) SetResourceType(v string) *UntagResourcesRequest { + s.ResourceType = &v + return s +} + +func (s *UntagResourcesRequest) SetTagKey(v []*string) *UntagResourcesRequest { + s.TagKey = v + return s +} + +type UntagResourcesResponseBody struct { + Code *string `json:"Code,omitempty" xml:"Code,omitempty"` + Data *string `json:"Data,omitempty" xml:"Data,omitempty"` + RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"` +} + +func (s UntagResourcesResponseBody) String() string { + return tea.Prettify(s) +} + +func (s UntagResourcesResponseBody) GoString() string { + return s.String() +} + +func (s *UntagResourcesResponseBody) SetCode(v string) *UntagResourcesResponseBody { + s.Code = &v + return s +} + +func (s *UntagResourcesResponseBody) SetData(v string) *UntagResourcesResponseBody { + s.Data = &v + return s +} + +func (s *UntagResourcesResponseBody) SetRequestId(v string) *UntagResourcesResponseBody { + s.RequestId = &v + return s +} + +type UntagResourcesResponse struct { + Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"` + Body *UntagResourcesResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"` +} + +func (s UntagResourcesResponse) String() string { + return tea.Prettify(s) +} + +func (s UntagResourcesResponse) GoString() string { + return s.String() +} + +func (s *UntagResourcesResponse) SetHeaders(v map[string]*string) *UntagResourcesResponse { + s.Headers = v + return s +} + +func (s *UntagResourcesResponse) SetBody(v *UntagResourcesResponseBody) *UntagResourcesResponse { + s.Body = v + return s +} + +type Client struct { + openapi.Client +} + +func NewClient(config *openapi.Config) (*Client, error) { + client := new(Client) + err := client.Init(config) + return client, err +} + +func (client *Client) Init(config *openapi.Config) (_err error) { + _err = client.Client.Init(config) + if _err != nil { + return _err + } + client.EndpointRule = tea.String("central") + client.EndpointMap = map[string]*string{ + "ap-southeast-1": tea.String("dysmsapi.ap-southeast-1.aliyuncs.com"), + "ap-southeast-5": tea.String("dysmsapi-xman.ap-southeast-5.aliyuncs.com"), + "cn-beijing": tea.String("dysmsapi-proxy.cn-beijing.aliyuncs.com"), + "cn-hongkong": tea.String("dysmsapi-xman.cn-hongkong.aliyuncs.com"), + } + _err = client.CheckConfig(config) + if _err != nil { + return _err + } + client.Endpoint, _err = client.GetEndpoint(tea.String("dysmsapi"), client.RegionId, client.EndpointRule, client.Network, client.Suffix, client.EndpointMap, client.Endpoint) + if _err != nil { + return _err + } + + return nil +} + +func (client *Client) GetEndpoint(productId *string, regionId *string, endpointRule *string, network *string, suffix *string, endpointMap map[string]*string, endpoint *string) (_result *string, _err error) { + if !tea.BoolValue(util.Empty(endpoint)) { + _result = endpoint + return _result, _err + } + + if !tea.BoolValue(util.IsUnset(endpointMap)) && !tea.BoolValue(util.Empty(endpointMap[tea.StringValue(regionId)])) { + _result = endpointMap[tea.StringValue(regionId)] + return _result, _err + } + + _body, _err := endpointutil.GetEndpointRules(productId, regionId, endpointRule, network, suffix) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) AddShortUrlWithOptions(request *AddShortUrlRequest, runtime *util.RuntimeOptions) (_result *AddShortUrlResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + body := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.EffectiveDays)) { + body["EffectiveDays"] = request.EffectiveDays + } + + if !tea.BoolValue(util.IsUnset(request.ShortUrlName)) { + body["ShortUrlName"] = request.ShortUrlName + } + + if !tea.BoolValue(util.IsUnset(request.SourceUrl)) { + body["SourceUrl"] = request.SourceUrl + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + Body: openapiutil.ParseToMap(body), + } + params := &openapi.Params{ + Action: tea.String("AddShortUrl"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &AddShortUrlResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) AddShortUrl(request *AddShortUrlRequest) (_result *AddShortUrlResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &AddShortUrlResponse{} + _body, _err := client.AddShortUrlWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) AddSmsSignWithOptions(request *AddSmsSignRequest, runtime *util.RuntimeOptions) (_result *AddSmsSignResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.Remark)) { + query["Remark"] = request.Remark + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SignName)) { + query["SignName"] = request.SignName + } + + if !tea.BoolValue(util.IsUnset(request.SignSource)) { + query["SignSource"] = request.SignSource + } + + body := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.SignFileList)) { + body["SignFileList"] = request.SignFileList + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + Body: openapiutil.ParseToMap(body), + } + params := &openapi.Params{ + Action: tea.String("AddSmsSign"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &AddSmsSignResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) AddSmsSign(request *AddSmsSignRequest) (_result *AddSmsSignResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &AddSmsSignResponse{} + _body, _err := client.AddSmsSignWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) AddSmsTemplateWithOptions(request *AddSmsTemplateRequest, runtime *util.RuntimeOptions) (_result *AddSmsTemplateResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.Remark)) { + query["Remark"] = request.Remark + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.TemplateContent)) { + query["TemplateContent"] = request.TemplateContent + } + + if !tea.BoolValue(util.IsUnset(request.TemplateName)) { + query["TemplateName"] = request.TemplateName + } + + if !tea.BoolValue(util.IsUnset(request.TemplateType)) { + query["TemplateType"] = request.TemplateType + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("AddSmsTemplate"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &AddSmsTemplateResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) AddSmsTemplate(request *AddSmsTemplateRequest) (_result *AddSmsTemplateResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &AddSmsTemplateResponse{} + _body, _err := client.AddSmsTemplateWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) DeleteShortUrlWithOptions(request *DeleteShortUrlRequest, runtime *util.RuntimeOptions) (_result *DeleteShortUrlResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + body := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.SourceUrl)) { + body["SourceUrl"] = request.SourceUrl + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + Body: openapiutil.ParseToMap(body), + } + params := &openapi.Params{ + Action: tea.String("DeleteShortUrl"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &DeleteShortUrlResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) DeleteShortUrl(request *DeleteShortUrlRequest) (_result *DeleteShortUrlResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &DeleteShortUrlResponse{} + _body, _err := client.DeleteShortUrlWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) DeleteSmsSignWithOptions(request *DeleteSmsSignRequest, runtime *util.RuntimeOptions) (_result *DeleteSmsSignResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SignName)) { + query["SignName"] = request.SignName + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("DeleteSmsSign"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &DeleteSmsSignResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) DeleteSmsSign(request *DeleteSmsSignRequest) (_result *DeleteSmsSignResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &DeleteSmsSignResponse{} + _body, _err := client.DeleteSmsSignWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) DeleteSmsTemplateWithOptions(request *DeleteSmsTemplateRequest, runtime *util.RuntimeOptions) (_result *DeleteSmsTemplateResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.TemplateCode)) { + query["TemplateCode"] = request.TemplateCode + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("DeleteSmsTemplate"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &DeleteSmsTemplateResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) DeleteSmsTemplate(request *DeleteSmsTemplateRequest) (_result *DeleteSmsTemplateResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &DeleteSmsTemplateResponse{} + _body, _err := client.DeleteSmsTemplateWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) ListTagResourcesWithOptions(request *ListTagResourcesRequest, runtime *util.RuntimeOptions) (_result *ListTagResourcesResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.NextToken)) { + query["NextToken"] = request.NextToken + } + + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PageSize)) { + query["PageSize"] = request.PageSize + } + + if !tea.BoolValue(util.IsUnset(request.ProdCode)) { + query["ProdCode"] = request.ProdCode + } + + if !tea.BoolValue(util.IsUnset(request.RegionId)) { + query["RegionId"] = request.RegionId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceId)) { + query["ResourceId"] = request.ResourceId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceType)) { + query["ResourceType"] = request.ResourceType + } + + if !tea.BoolValue(util.IsUnset(request.Tag)) { + query["Tag"] = request.Tag + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("ListTagResources"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &ListTagResourcesResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) ListTagResources(request *ListTagResourcesRequest) (_result *ListTagResourcesResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &ListTagResourcesResponse{} + _body, _err := client.ListTagResourcesWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) ModifySmsSignWithOptions(request *ModifySmsSignRequest, runtime *util.RuntimeOptions) (_result *ModifySmsSignResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.Remark)) { + query["Remark"] = request.Remark + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SignName)) { + query["SignName"] = request.SignName + } + + if !tea.BoolValue(util.IsUnset(request.SignSource)) { + query["SignSource"] = request.SignSource + } + + body := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.SignFileList)) { + body["SignFileList"] = request.SignFileList + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + Body: openapiutil.ParseToMap(body), + } + params := &openapi.Params{ + Action: tea.String("ModifySmsSign"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &ModifySmsSignResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) ModifySmsSign(request *ModifySmsSignRequest) (_result *ModifySmsSignResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &ModifySmsSignResponse{} + _body, _err := client.ModifySmsSignWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) ModifySmsTemplateWithOptions(request *ModifySmsTemplateRequest, runtime *util.RuntimeOptions) (_result *ModifySmsTemplateResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.Remark)) { + query["Remark"] = request.Remark + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.TemplateCode)) { + query["TemplateCode"] = request.TemplateCode + } + + if !tea.BoolValue(util.IsUnset(request.TemplateContent)) { + query["TemplateContent"] = request.TemplateContent + } + + if !tea.BoolValue(util.IsUnset(request.TemplateName)) { + query["TemplateName"] = request.TemplateName + } + + if !tea.BoolValue(util.IsUnset(request.TemplateType)) { + query["TemplateType"] = request.TemplateType + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("ModifySmsTemplate"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &ModifySmsTemplateResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) ModifySmsTemplate(request *ModifySmsTemplateRequest) (_result *ModifySmsTemplateResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &ModifySmsTemplateResponse{} + _body, _err := client.ModifySmsTemplateWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QuerySendDetailsWithOptions(request *QuerySendDetailsRequest, runtime *util.RuntimeOptions) (_result *QuerySendDetailsResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.BizId)) { + query["BizId"] = request.BizId + } + + if !tea.BoolValue(util.IsUnset(request.CurrentPage)) { + query["CurrentPage"] = request.CurrentPage + } + + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PageSize)) { + query["PageSize"] = request.PageSize + } + + if !tea.BoolValue(util.IsUnset(request.PhoneNumber)) { + query["PhoneNumber"] = request.PhoneNumber + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SendDate)) { + query["SendDate"] = request.SendDate + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("QuerySendDetails"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QuerySendDetailsResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QuerySendDetails(request *QuerySendDetailsRequest) (_result *QuerySendDetailsResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QuerySendDetailsResponse{} + _body, _err := client.QuerySendDetailsWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QuerySendStatisticsWithOptions(request *QuerySendStatisticsRequest, runtime *util.RuntimeOptions) (_result *QuerySendStatisticsResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.EndDate)) { + query["EndDate"] = request.EndDate + } + + if !tea.BoolValue(util.IsUnset(request.IsGlobe)) { + query["IsGlobe"] = request.IsGlobe + } + + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PageIndex)) { + query["PageIndex"] = request.PageIndex + } + + if !tea.BoolValue(util.IsUnset(request.PageSize)) { + query["PageSize"] = request.PageSize + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.StartDate)) { + query["StartDate"] = request.StartDate + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("QuerySendStatistics"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QuerySendStatisticsResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QuerySendStatistics(request *QuerySendStatisticsRequest) (_result *QuerySendStatisticsResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QuerySendStatisticsResponse{} + _body, _err := client.QuerySendStatisticsWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QueryShortUrlWithOptions(request *QueryShortUrlRequest, runtime *util.RuntimeOptions) (_result *QueryShortUrlResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + body := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.ShortUrl)) { + body["ShortUrl"] = request.ShortUrl + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + Body: openapiutil.ParseToMap(body), + } + params := &openapi.Params{ + Action: tea.String("QueryShortUrl"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QueryShortUrlResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QueryShortUrl(request *QueryShortUrlRequest) (_result *QueryShortUrlResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QueryShortUrlResponse{} + _body, _err := client.QueryShortUrlWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QuerySmsSignWithOptions(request *QuerySmsSignRequest, runtime *util.RuntimeOptions) (_result *QuerySmsSignResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SignName)) { + query["SignName"] = request.SignName + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("QuerySmsSign"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QuerySmsSignResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QuerySmsSign(request *QuerySmsSignRequest) (_result *QuerySmsSignResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QuerySmsSignResponse{} + _body, _err := client.QuerySmsSignWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QuerySmsSignListWithOptions(request *QuerySmsSignListRequest, runtime *util.RuntimeOptions) (_result *QuerySmsSignListResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PageIndex)) { + query["PageIndex"] = request.PageIndex + } + + if !tea.BoolValue(util.IsUnset(request.PageSize)) { + query["PageSize"] = request.PageSize + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("QuerySmsSignList"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QuerySmsSignListResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QuerySmsSignList(request *QuerySmsSignListRequest) (_result *QuerySmsSignListResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QuerySmsSignListResponse{} + _body, _err := client.QuerySmsSignListWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QuerySmsTemplateWithOptions(request *QuerySmsTemplateRequest, runtime *util.RuntimeOptions) (_result *QuerySmsTemplateResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.TemplateCode)) { + query["TemplateCode"] = request.TemplateCode + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("QuerySmsTemplate"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QuerySmsTemplateResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QuerySmsTemplate(request *QuerySmsTemplateRequest) (_result *QuerySmsTemplateResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QuerySmsTemplateResponse{} + _body, _err := client.QuerySmsTemplateWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) QuerySmsTemplateListWithOptions(request *QuerySmsTemplateListRequest, runtime *util.RuntimeOptions) (_result *QuerySmsTemplateListResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PageIndex)) { + query["PageIndex"] = request.PageIndex + } + + if !tea.BoolValue(util.IsUnset(request.PageSize)) { + query["PageSize"] = request.PageSize + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("QuerySmsTemplateList"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &QuerySmsTemplateListResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) QuerySmsTemplateList(request *QuerySmsTemplateListRequest) (_result *QuerySmsTemplateListResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &QuerySmsTemplateListResponse{} + _body, _err := client.QuerySmsTemplateListWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) SendBatchSmsWithOptions(request *SendBatchSmsRequest, runtime *util.RuntimeOptions) (_result *SendBatchSmsResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PhoneNumberJson)) { + query["PhoneNumberJson"] = request.PhoneNumberJson + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SignNameJson)) { + query["SignNameJson"] = request.SignNameJson + } + + if !tea.BoolValue(util.IsUnset(request.SmsUpExtendCodeJson)) { + query["SmsUpExtendCodeJson"] = request.SmsUpExtendCodeJson + } + + if !tea.BoolValue(util.IsUnset(request.TemplateCode)) { + query["TemplateCode"] = request.TemplateCode + } + + if !tea.BoolValue(util.IsUnset(request.TemplateParamJson)) { + query["TemplateParamJson"] = request.TemplateParamJson + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("SendBatchSms"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &SendBatchSmsResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) SendBatchSms(request *SendBatchSmsRequest) (_result *SendBatchSmsResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &SendBatchSmsResponse{} + _body, _err := client.SendBatchSmsWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) SendSmsWithOptions(request *SendSmsRequest, runtime *util.RuntimeOptions) (_result *SendSmsResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OutId)) { + query["OutId"] = request.OutId + } + + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.PhoneNumbers)) { + query["PhoneNumbers"] = request.PhoneNumbers + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.SignName)) { + query["SignName"] = request.SignName + } + + if !tea.BoolValue(util.IsUnset(request.SmsUpExtendCode)) { + query["SmsUpExtendCode"] = request.SmsUpExtendCode + } + + if !tea.BoolValue(util.IsUnset(request.TemplateCode)) { + query["TemplateCode"] = request.TemplateCode + } + + if !tea.BoolValue(util.IsUnset(request.TemplateParam)) { + query["TemplateParam"] = request.TemplateParam + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("SendSms"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &SendSmsResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) SendSms(request *SendSmsRequest) (_result *SendSmsResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &SendSmsResponse{} + _body, _err := client.SendSmsWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) TagResourcesWithOptions(request *TagResourcesRequest, runtime *util.RuntimeOptions) (_result *TagResourcesResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ProdCode)) { + query["ProdCode"] = request.ProdCode + } + + if !tea.BoolValue(util.IsUnset(request.RegionId)) { + query["RegionId"] = request.RegionId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceId)) { + query["ResourceId"] = request.ResourceId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceType)) { + query["ResourceType"] = request.ResourceType + } + + if !tea.BoolValue(util.IsUnset(request.Tag)) { + query["Tag"] = request.Tag + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("TagResources"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &TagResourcesResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) TagResources(request *TagResourcesRequest) (_result *TagResourcesResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &TagResourcesResponse{} + _body, _err := client.TagResourcesWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} + +func (client *Client) UntagResourcesWithOptions(request *UntagResourcesRequest, runtime *util.RuntimeOptions) (_result *UntagResourcesResponse, _err error) { + _err = util.ValidateModel(request) + if _err != nil { + return _result, _err + } + query := map[string]interface{}{} + if !tea.BoolValue(util.IsUnset(request.All)) { + query["All"] = request.All + } + + if !tea.BoolValue(util.IsUnset(request.OwnerId)) { + query["OwnerId"] = request.OwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ProdCode)) { + query["ProdCode"] = request.ProdCode + } + + if !tea.BoolValue(util.IsUnset(request.RegionId)) { + query["RegionId"] = request.RegionId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceId)) { + query["ResourceId"] = request.ResourceId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerAccount)) { + query["ResourceOwnerAccount"] = request.ResourceOwnerAccount + } + + if !tea.BoolValue(util.IsUnset(request.ResourceOwnerId)) { + query["ResourceOwnerId"] = request.ResourceOwnerId + } + + if !tea.BoolValue(util.IsUnset(request.ResourceType)) { + query["ResourceType"] = request.ResourceType + } + + if !tea.BoolValue(util.IsUnset(request.TagKey)) { + query["TagKey"] = request.TagKey + } + + req := &openapi.OpenApiRequest{ + Query: openapiutil.Query(query), + } + params := &openapi.Params{ + Action: tea.String("UntagResources"), + Version: tea.String("2017-05-25"), + Protocol: tea.String("HTTPS"), + Pathname: tea.String("/"), + Method: tea.String("POST"), + AuthType: tea.String("AK"), + Style: tea.String("RPC"), + ReqBodyType: tea.String("formData"), + BodyType: tea.String("json"), + } + _result = &UntagResourcesResponse{} + _body, _err := client.CallApi(params, req, runtime) + if _err != nil { + return _result, _err + } + _err = tea.Convert(_body, &_result) + return _result, _err +} + +func (client *Client) UntagResources(request *UntagResourcesRequest) (_result *UntagResourcesResponse, _err error) { + runtime := &util.RuntimeOptions{} + _result = &UntagResourcesResponse{} + _body, _err := client.UntagResourcesWithOptions(request, runtime) + if _err != nil { + return _result, _err + } + _result = _body + return _result, _err +} diff --git a/vendor/github.com/alibabacloud-go/endpoint-util/service/service.go b/vendor/github.com/alibabacloud-go/endpoint-util/service/service.go new file mode 100644 index 000000000..85e5fda6e --- /dev/null +++ b/vendor/github.com/alibabacloud-go/endpoint-util/service/service.go @@ -0,0 +1,41 @@ +// This file is auto-generated, don't edit it. Thanks. +/** + * Get endpoint + * @return string + */ +package service + +import ( + "fmt" + "strings" + + "github.com/alibabacloud-go/tea/tea" +) + +func GetEndpointRules(product, regionId, endpointType, network, suffix *string) (_result *string, _err error) { + if tea.StringValue(endpointType) == "regional" { + if tea.StringValue(regionId) == "" { + _err = fmt.Errorf("RegionId is empty, please set a valid RegionId") + return tea.String(""), _err + } + _result = tea.String(strings.Replace("..aliyuncs.com", + "", tea.StringValue(regionId), 1)) + } else { + _result = tea.String(".aliyuncs.com") + } + _result = tea.String(strings.Replace(tea.StringValue(_result), + "", strings.ToLower(tea.StringValue(product)), 1)) + if tea.StringValue(network) == "" || tea.StringValue(network) == "public" { + _result = tea.String(strings.Replace(tea.StringValue(_result), "", "", 1)) + } else { + _result = tea.String(strings.Replace(tea.StringValue(_result), + "", "-"+tea.StringValue(network), 1)) + } + if tea.StringValue(suffix) == "" { + _result = tea.String(strings.Replace(tea.StringValue(_result), "", "", 1)) + } else { + _result = tea.String(strings.Replace(tea.StringValue(_result), + "", "-"+tea.StringValue(suffix), 1)) + } + return _result, nil +} diff --git a/vendor/github.com/alibabacloud-go/openapi-util/LICENSE b/vendor/github.com/alibabacloud-go/openapi-util/LICENSE new file mode 100644 index 000000000..0c44dcefe --- /dev/null +++ b/vendor/github.com/alibabacloud-go/openapi-util/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/alibabacloud-go/openapi-util/service/service.go b/vendor/github.com/alibabacloud-go/openapi-util/service/service.go new file mode 100644 index 000000000..245eeccb0 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/openapi-util/service/service.go @@ -0,0 +1,635 @@ +// This file is auto-generated, don't edit it. Thanks. +/** + * This is for OpenApi Util + */ +package service + +import ( + "bytes" + "crypto" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "hash" + "io" + "net/http" + "net/textproto" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" + + util "github.com/alibabacloud-go/tea-utils/service" + "github.com/alibabacloud-go/tea/tea" + "github.com/tjfoc/gmsm/sm3" +) + +const ( + PEM_BEGIN = "-----BEGIN RSA PRIVATE KEY-----\n" + PEM_END = "\n-----END RSA PRIVATE KEY-----" +) + +type Sorter struct { + Keys []string + Vals []string +} + +func newSorter(m map[string]string) *Sorter { + hs := &Sorter{ + Keys: make([]string, 0, len(m)), + Vals: make([]string, 0, len(m)), + } + + for k, v := range m { + hs.Keys = append(hs.Keys, k) + hs.Vals = append(hs.Vals, v) + } + return hs +} + +// Sort is an additional function for function SignHeader. +func (hs *Sorter) Sort() { + sort.Sort(hs) +} + +// Len is an additional function for function SignHeader. +func (hs *Sorter) Len() int { + return len(hs.Vals) +} + +// Less is an additional function for function SignHeader. +func (hs *Sorter) Less(i, j int) bool { + return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0 +} + +// Swap is an additional function for function SignHeader. +func (hs *Sorter) Swap(i, j int) { + hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i] + hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i] +} + +/** + * Convert all params of body other than type of readable into content + * @param body source Model + * @param content target Model + * @return void + */ +func Convert(body interface{}, content interface{}) { + res := make(map[string]interface{}) + val := reflect.ValueOf(body).Elem() + dataType := val.Type() + for i := 0; i < dataType.NumField(); i++ { + field := dataType.Field(i) + name, _ := field.Tag.Lookup("json") + name = strings.Split(name, ",omitempty")[0] + _, ok := val.Field(i).Interface().(io.Reader) + if !ok { + res[name] = val.Field(i).Interface() + } + } + byt, _ := json.Marshal(res) + json.Unmarshal(byt, content) +} + +/** + * Get the string to be signed according to request + * @param request which contains signed messages + * @return the signed string + */ +func GetStringToSign(request *tea.Request) (_result *string) { + return tea.String(getStringToSign(request)) +} + +func getStringToSign(request *tea.Request) string { + resource := tea.StringValue(request.Pathname) + queryParams := request.Query + // sort QueryParams by key + var queryKeys []string + for key := range queryParams { + queryKeys = append(queryKeys, key) + } + sort.Strings(queryKeys) + tmp := "" + for i := 0; i < len(queryKeys); i++ { + queryKey := queryKeys[i] + v := tea.StringValue(queryParams[queryKey]) + if v != "" { + tmp = tmp + "&" + queryKey + "=" + v + } else { + tmp = tmp + "&" + queryKey + } + } + if tmp != "" { + tmp = strings.TrimLeft(tmp, "&") + resource = resource + "?" + tmp + } + return getSignedStr(request, resource) +} + +func getSignedStr(req *tea.Request, canonicalizedResource string) string { + temp := make(map[string]string) + + for k, v := range req.Headers { + if strings.HasPrefix(strings.ToLower(k), "x-acs-") { + temp[strings.ToLower(k)] = tea.StringValue(v) + } + } + hs := newSorter(temp) + + // Sort the temp by the ascending order + hs.Sort() + + // Get the canonicalizedOSSHeaders + canonicalizedOSSHeaders := "" + for i := range hs.Keys { + canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" + } + + // Give other parameters values + // when sign URL, date is expires + date := tea.StringValue(req.Headers["date"]) + accept := tea.StringValue(req.Headers["accept"]) + contentType := tea.StringValue(req.Headers["content-type"]) + contentMd5 := tea.StringValue(req.Headers["content-md5"]) + + signStr := tea.StringValue(req.Method) + "\n" + accept + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource + return signStr +} + +/** + * Get signature according to stringToSign, secret + * @param stringToSign the signed string + * @param secret accesskey secret + * @return the signature + */ +func GetROASignature(stringToSign *string, secret *string) (_result *string) { + h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(tea.StringValue(secret))) + io.WriteString(h, tea.StringValue(stringToSign)) + signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) + return tea.String(signedStr) +} + +func GetEndpoint(endpoint *string, server *bool, endpointType *string) *string { + if tea.StringValue(endpointType) == "internal" { + strs := strings.Split(tea.StringValue(endpoint), ".") + strs[0] += "-internal" + endpoint = tea.String(strings.Join(strs, ".")) + } + if tea.BoolValue(server) && tea.StringValue(endpointType) == "accelerate" { + return tea.String("oss-accelerate.aliyuncs.com") + } + + return endpoint +} + +func HexEncode(raw []byte) *string { + return tea.String(hex.EncodeToString(raw)) +} + +func Hash(raw []byte, signatureAlgorithm *string) []byte { + signType := tea.StringValue(signatureAlgorithm) + if signType == "ACS3-HMAC-SHA256" || signType == "ACS3-RSA-SHA256" { + h := sha256.New() + h.Write(raw) + return h.Sum(nil) + } else if signType == "ACS3-HMAC-SM3" { + h := sm3.New() + h.Write(raw) + return h.Sum(nil) + } + return nil +} + +func GetEncodePath(path *string) *string { + uri := tea.StringValue(path) + strs := strings.Split(uri, "/") + for i, v := range strs { + strs[i] = url.QueryEscape(v) + } + uri = strings.Join(strs, "/") + uri = strings.Replace(uri, "+", "%20", -1) + uri = strings.Replace(uri, "*", "%2A", -1) + uri = strings.Replace(uri, "%7E", "~", -1) + return tea.String(uri) +} + +func GetEncodeParam(param *string) *string { + uri := tea.StringValue(param) + uri = url.QueryEscape(uri) + uri = strings.Replace(uri, "+", "%20", -1) + uri = strings.Replace(uri, "*", "%2A", -1) + uri = strings.Replace(uri, "%7E", "~", -1) + return tea.String(uri) +} + +func GetAuthorization(request *tea.Request, signatureAlgorithm, payload, acesskey, secret *string) *string { + canonicalURI := tea.StringValue(request.Pathname) + if canonicalURI == "" { + canonicalURI = "/" + } + + canonicalURI = strings.Replace(canonicalURI, "+", "%20", -1) + canonicalURI = strings.Replace(canonicalURI, "*", "%2A", -1) + canonicalURI = strings.Replace(canonicalURI, "%7E", "~", -1) + + method := tea.StringValue(request.Method) + canonicalQueryString := getCanonicalQueryString(request.Query) + canonicalheaders, signedHeaders := getCanonicalHeaders(request.Headers) + + canonicalRequest := method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalheaders + "\n" + + strings.Join(signedHeaders, ";") + "\n" + tea.StringValue(payload) + signType := tea.StringValue(signatureAlgorithm) + StringToSign := signType + "\n" + tea.StringValue(HexEncode(Hash([]byte(canonicalRequest), signatureAlgorithm))) + signature := tea.StringValue(HexEncode(SignatureMethod(tea.StringValue(secret), StringToSign, signType))) + auth := signType + " Credential=" + tea.StringValue(acesskey) + ",SignedHeaders=" + + strings.Join(signedHeaders, ";") + ",Signature=" + signature + return tea.String(auth) +} + +func SignatureMethod(secret, source, signatureAlgorithm string) []byte { + if signatureAlgorithm == "ACS3-HMAC-SHA256" { + h := hmac.New(sha256.New, []byte(secret)) + h.Write([]byte(source)) + return h.Sum(nil) + } else if signatureAlgorithm == "ACS3-HMAC-SM3" { + h := hmac.New(sm3.New, []byte(secret)) + h.Write([]byte(source)) + return h.Sum(nil) + } else if signatureAlgorithm == "ACS3-RSA-SHA256" { + return rsaSign(source, secret) + } + return nil +} + +func rsaSign(content, secret string) []byte { + h := crypto.SHA256.New() + h.Write([]byte(content)) + hashed := h.Sum(nil) + priv, err := parsePrivateKey(secret) + if err != nil { + return nil + } + sign, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed) + if err != nil { + return nil + } + return sign +} + +func parsePrivateKey(privateKey string) (*rsa.PrivateKey, error) { + privateKey = formatPrivateKey(privateKey) + block, _ := pem.Decode([]byte(privateKey)) + if block == nil { + return nil, errors.New("PrivateKey is invalid") + } + priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + switch priKey.(type) { + case *rsa.PrivateKey: + return priKey.(*rsa.PrivateKey), nil + default: + return nil, nil + } +} + +func formatPrivateKey(privateKey string) string { + if !strings.HasPrefix(privateKey, PEM_BEGIN) { + privateKey = PEM_BEGIN + privateKey + } + + if !strings.HasSuffix(privateKey, PEM_END) { + privateKey += PEM_END + } + return privateKey +} + +func getCanonicalHeaders(headers map[string]*string) (string, []string) { + tmp := make(map[string]string) + tmpHeader := http.Header{} + for k, v := range headers { + if strings.HasPrefix(strings.ToLower(k), "x-acs-") || strings.ToLower(k) == "host" || + strings.ToLower(k) == "content-type" { + tmp[strings.ToLower(k)] = strings.TrimSpace(tea.StringValue(v)) + tmpHeader.Add(strings.ToLower(k), strings.TrimSpace(tea.StringValue(v))) + } + } + hs := newSorter(tmp) + + // Sort the temp by the ascending order + hs.Sort() + canonicalheaders := "" + for _, key := range hs.Keys { + vals := tmpHeader[textproto.CanonicalMIMEHeaderKey(key)] + sort.Strings(vals) + canonicalheaders += key + ":" + strings.Join(vals, ",") + "\n" + } + + return canonicalheaders, hs.Keys +} + +func getCanonicalQueryString(query map[string]*string) string { + canonicalQueryString := "" + if tea.BoolValue(util.IsUnset(query)) { + return canonicalQueryString + } + tmp := make(map[string]string) + for k, v := range query { + tmp[k] = tea.StringValue(v) + } + + hs := newSorter(tmp) + + // Sort the temp by the ascending order + hs.Sort() + for i := range hs.Keys { + if hs.Vals[i] != "" { + canonicalQueryString += "&" + hs.Keys[i] + "=" + url.QueryEscape(hs.Vals[i]) + } else { + canonicalQueryString += "&" + hs.Keys[i] + "=" + } + } + canonicalQueryString = strings.Replace(canonicalQueryString, "+", "%20", -1) + canonicalQueryString = strings.Replace(canonicalQueryString, "*", "%2A", -1) + canonicalQueryString = strings.Replace(canonicalQueryString, "%7E", "~", -1) + + if canonicalQueryString != "" { + canonicalQueryString = strings.TrimLeft(canonicalQueryString, "&") + } + return canonicalQueryString +} + +/** + * Parse filter into a form string + * @param filter object + * @return the string + */ +func ToForm(filter map[string]interface{}) (_result *string) { + tmp := make(map[string]interface{}) + byt, _ := json.Marshal(filter) + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + _ = d.Decode(&tmp) + + result := make(map[string]*string) + for key, value := range tmp { + filterValue := reflect.ValueOf(value) + flatRepeatedList(filterValue, result, key) + } + + m := util.AnyifyMapValue(result) + return util.ToFormString(m) +} + +func flatRepeatedList(dataValue reflect.Value, result map[string]*string, prefix string) { + if !dataValue.IsValid() { + return + } + + dataType := dataValue.Type() + if dataType.Kind().String() == "slice" { + handleRepeatedParams(dataValue, result, prefix) + } else if dataType.Kind().String() == "map" { + handleMap(dataValue, result, prefix) + } else { + result[prefix] = tea.String(fmt.Sprintf("%v", dataValue.Interface())) + } +} + +func handleRepeatedParams(repeatedFieldValue reflect.Value, result map[string]*string, prefix string) { + if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() { + for m := 0; m < repeatedFieldValue.Len(); m++ { + elementValue := repeatedFieldValue.Index(m) + key := prefix + "." + strconv.Itoa(m+1) + fieldValue := reflect.ValueOf(elementValue.Interface()) + if fieldValue.Kind().String() == "map" { + handleMap(fieldValue, result, key) + } else { + result[key] = tea.String(fmt.Sprintf("%v", fieldValue.Interface())) + } + } + } +} + +func handleMap(valueField reflect.Value, result map[string]*string, prefix string) { + if valueField.IsValid() && valueField.String() != "" { + valueFieldType := valueField.Type() + if valueFieldType.Kind().String() == "map" { + var byt []byte + byt, _ = json.Marshal(valueField.Interface()) + cache := make(map[string]interface{}) + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + _ = d.Decode(&cache) + for key, value := range cache { + pre := "" + if prefix != "" { + pre = prefix + "." + key + } else { + pre = key + } + fieldValue := reflect.ValueOf(value) + flatRepeatedList(fieldValue, result, pre) + } + } + } +} + +/** + * Get timestamp + * @return the timestamp string + */ +func GetTimestamp() (_result *string) { + gmt := time.FixedZone("GMT", 0) + return tea.String(time.Now().In(gmt).Format("2006-01-02T15:04:05Z")) +} + +/** + * Parse filter into a object which's type is map[string]string + * @param filter query param + * @return the object + */ +func Query(filter interface{}) (_result map[string]*string) { + tmp := make(map[string]interface{}) + byt, _ := json.Marshal(filter) + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + _ = d.Decode(&tmp) + + result := make(map[string]*string) + for key, value := range tmp { + filterValue := reflect.ValueOf(value) + flatRepeatedList(filterValue, result, key) + } + + return result +} + +/** + * Get signature according to signedParams, method and secret + * @param signedParams params which need to be signed + * @param method http method e.g. GET + * @param secret AccessKeySecret + * @return the signature + */ +func GetRPCSignature(signedParams map[string]*string, method *string, secret *string) (_result *string) { + stringToSign := buildRpcStringToSign(signedParams, tea.StringValue(method)) + signature := sign(stringToSign, tea.StringValue(secret), "&") + return tea.String(signature) +} + +/** + * Parse array into a string with specified style + * @param array the array + * @param prefix the prefix string + * @style specified style e.g. repeatList + * @return the string + */ +func ArrayToStringWithSpecifiedStyle(array interface{}, prefix *string, style *string) (_result *string) { + if tea.BoolValue(util.IsUnset(array)) { + return tea.String("") + } + + sty := tea.StringValue(style) + if sty == "repeatList" { + tmp := map[string]interface{}{ + tea.StringValue(prefix): array, + } + return flatRepeatList(tmp) + } else if sty == "simple" || sty == "spaceDelimited" || sty == "pipeDelimited" { + return flatArray(array, sty) + } else if sty == "json" { + return util.ToJSONString(array) + } + return tea.String("") +} + +func ParseToMap(in interface{}) map[string]interface{} { + if tea.BoolValue(util.IsUnset(in)) { + return nil + } + + tmp := make(map[string]interface{}) + byt, _ := json.Marshal(in) + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + err := d.Decode(&tmp) + if err != nil { + return nil + } + return tmp +} + +func flatRepeatList(filter map[string]interface{}) (_result *string) { + tmp := make(map[string]interface{}) + byt, _ := json.Marshal(filter) + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + _ = d.Decode(&tmp) + + result := make(map[string]*string) + for key, value := range tmp { + filterValue := reflect.ValueOf(value) + flatRepeatedList(filterValue, result, key) + } + + res := make(map[string]string) + for k, v := range result { + res[k] = tea.StringValue(v) + } + hs := newSorter(res) + + hs.Sort() + + // Get the canonicalizedOSSHeaders + t := "" + for i := range hs.Keys { + if i == len(hs.Keys)-1 { + t += hs.Keys[i] + "=" + hs.Vals[i] + } else { + t += hs.Keys[i] + "=" + hs.Vals[i] + "&&" + } + } + return tea.String(t) +} + +func flatArray(array interface{}, sty string) *string { + t := reflect.ValueOf(array) + strs := make([]string, 0) + for i := 0; i < t.Len(); i++ { + tmp := t.Index(i) + if tmp.Kind() == reflect.Ptr || tmp.Kind() == reflect.Interface { + tmp = tmp.Elem() + } + + if tmp.Kind() == reflect.Ptr { + tmp = tmp.Elem() + } + if tmp.Kind() == reflect.String { + strs = append(strs, tmp.String()) + } else { + inter := tmp.Interface() + byt, _ := json.Marshal(inter) + strs = append(strs, string(byt)) + } + } + str := "" + if sty == "simple" { + str = strings.Join(strs, ",") + } else if sty == "spaceDelimited" { + str = strings.Join(strs, " ") + } else if sty == "pipeDelimited" { + str = strings.Join(strs, "|") + } + return tea.String(str) +} + +func buildRpcStringToSign(signedParam map[string]*string, method string) (stringToSign string) { + signParams := make(map[string]string) + for key, value := range signedParam { + signParams[key] = tea.StringValue(value) + } + + stringToSign = getUrlFormedMap(signParams) + stringToSign = strings.Replace(stringToSign, "+", "%20", -1) + stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) + stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) + stringToSign = url.QueryEscape(stringToSign) + stringToSign = method + "&%2F&" + stringToSign + return +} + +func getUrlFormedMap(source map[string]string) (urlEncoded string) { + urlEncoder := url.Values{} + for key, value := range source { + urlEncoder.Add(key, value) + } + urlEncoded = urlEncoder.Encode() + return +} + +func sign(stringToSign, accessKeySecret, secretSuffix string) string { + secret := accessKeySecret + secretSuffix + signedBytes := shaHmac1(stringToSign, secret) + signedString := base64.StdEncoding.EncodeToString(signedBytes) + return signedString +} + +func shaHmac1(source, secret string) []byte { + key := []byte(secret) + hmac := hmac.New(sha1.New, key) + hmac.Write([]byte(source)) + return hmac.Sum(nil) +} diff --git a/vendor/github.com/alibabacloud-go/tea-utils/service/service.go b/vendor/github.com/alibabacloud-go/tea-utils/service/service.go new file mode 100644 index 000000000..2b6935723 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea-utils/service/service.go @@ -0,0 +1,462 @@ +package service + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "runtime" + "strconv" + "strings" + "time" + + "github.com/alibabacloud-go/tea/tea" +) + +var defaultUserAgent = fmt.Sprintf("AlibabaCloud (%s; %s) Golang/%s Core/%s TeaDSL/1", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), "0.01") + +type RuntimeOptions struct { + Autoretry *bool `json:"autoretry" xml:"autoretry"` + IgnoreSSL *bool `json:"ignoreSSL" xml:"ignoreSSL"` + MaxAttempts *int `json:"maxAttempts" xml:"maxAttempts"` + BackoffPolicy *string `json:"backoffPolicy" xml:"backoffPolicy"` + BackoffPeriod *int `json:"backoffPeriod" xml:"backoffPeriod"` + ReadTimeout *int `json:"readTimeout" xml:"readTimeout"` + ConnectTimeout *int `json:"connectTimeout" xml:"connectTimeout"` + LocalAddr *string `json:"localAddr" xml:"localAddr"` + HttpProxy *string `json:"httpProxy" xml:"httpProxy"` + HttpsProxy *string `json:"httpsProxy" xml:"httpsProxy"` + NoProxy *string `json:"noProxy" xml:"noProxy"` + MaxIdleConns *int `json:"maxIdleConns" xml:"maxIdleConns"` + Socks5Proxy *string `json:"socks5Proxy" xml:"socks5Proxy"` + Socks5NetWork *string `json:"socks5NetWork" xml:"socks5NetWork"` +} + +func (s RuntimeOptions) String() string { + return tea.Prettify(s) +} + +func (s RuntimeOptions) GoString() string { + return s.String() +} + +func (s *RuntimeOptions) SetAutoretry(v bool) *RuntimeOptions { + s.Autoretry = &v + return s +} + +func (s *RuntimeOptions) SetIgnoreSSL(v bool) *RuntimeOptions { + s.IgnoreSSL = &v + return s +} + +func (s *RuntimeOptions) SetMaxAttempts(v int) *RuntimeOptions { + s.MaxAttempts = &v + return s +} + +func (s *RuntimeOptions) SetBackoffPolicy(v string) *RuntimeOptions { + s.BackoffPolicy = &v + return s +} + +func (s *RuntimeOptions) SetBackoffPeriod(v int) *RuntimeOptions { + s.BackoffPeriod = &v + return s +} + +func (s *RuntimeOptions) SetReadTimeout(v int) *RuntimeOptions { + s.ReadTimeout = &v + return s +} + +func (s *RuntimeOptions) SetConnectTimeout(v int) *RuntimeOptions { + s.ConnectTimeout = &v + return s +} + +func (s *RuntimeOptions) SetHttpProxy(v string) *RuntimeOptions { + s.HttpProxy = &v + return s +} + +func (s *RuntimeOptions) SetHttpsProxy(v string) *RuntimeOptions { + s.HttpsProxy = &v + return s +} + +func (s *RuntimeOptions) SetNoProxy(v string) *RuntimeOptions { + s.NoProxy = &v + return s +} + +func (s *RuntimeOptions) SetMaxIdleConns(v int) *RuntimeOptions { + s.MaxIdleConns = &v + return s +} + +func (s *RuntimeOptions) SetLocalAddr(v string) *RuntimeOptions { + s.LocalAddr = &v + return s +} + +func (s *RuntimeOptions) SetSocks5Proxy(v string) *RuntimeOptions { + s.Socks5Proxy = &v + return s +} + +func (s *RuntimeOptions) SetSocks5NetWork(v string) *RuntimeOptions { + s.Socks5NetWork = &v + return s +} + +func ReadAsString(body io.Reader) (*string, error) { + byt, err := ioutil.ReadAll(body) + if err != nil { + return tea.String(""), err + } + r, ok := body.(io.ReadCloser) + if ok { + r.Close() + } + return tea.String(string(byt)), nil +} + +func StringifyMapValue(a map[string]interface{}) map[string]*string { + res := make(map[string]*string) + for key, value := range a { + if value != nil { + switch value.(type) { + case string: + res[key] = tea.String(value.(string)) + default: + byt, _ := json.Marshal(value) + res[key] = tea.String(string(byt)) + } + } + } + return res +} + +func AnyifyMapValue(a map[string]*string) map[string]interface{} { + res := make(map[string]interface{}) + for key, value := range a { + res[key] = tea.StringValue(value) + } + return res +} + +func ReadAsBytes(body io.Reader) ([]byte, error) { + byt, err := ioutil.ReadAll(body) + if err != nil { + return nil, err + } + r, ok := body.(io.ReadCloser) + if ok { + r.Close() + } + return byt, nil +} + +func DefaultString(reaStr, defaultStr *string) *string { + if reaStr == nil { + return defaultStr + } + return reaStr +} + +func ToJSONString(a interface{}) *string { + switch v := a.(type) { + case *string: + return v + case string: + return tea.String(v) + case []byte: + return tea.String(string(v)) + case io.Reader: + byt, err := ioutil.ReadAll(v) + if err != nil { + return nil + } + return tea.String(string(byt)) + } + byt, err := json.Marshal(a) + if err != nil { + return nil + } + return tea.String(string(byt)) +} + +func DefaultNumber(reaNum, defaultNum *int) *int { + if reaNum == nil { + return defaultNum + } + return reaNum +} + +func ReadAsJSON(body io.Reader) (result interface{}, err error) { + byt, err := ioutil.ReadAll(body) + if err != nil { + return + } + if string(byt) == "" { + return + } + r, ok := body.(io.ReadCloser) + if ok { + r.Close() + } + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + err = d.Decode(&result) + return +} + +func GetNonce() *string { + return tea.String(getUUID()) +} + +func Empty(val *string) *bool { + return tea.Bool(val == nil || tea.StringValue(val) == "") +} + +func ValidateModel(a interface{}) error { + if a == nil { + return nil + } + err := tea.Validate(a) + return err +} + +func EqualString(val1, val2 *string) *bool { + return tea.Bool(tea.StringValue(val1) == tea.StringValue(val2)) +} + +func EqualNumber(val1, val2 *int) *bool { + return tea.Bool(tea.IntValue(val1) == tea.IntValue(val2)) +} + +func IsUnset(val interface{}) *bool { + if val == nil { + return tea.Bool(true) + } + + v := reflect.ValueOf(val) + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map { + return tea.Bool(v.IsNil()) + } + + valType := reflect.TypeOf(val) + valZero := reflect.Zero(valType) + return tea.Bool(valZero == v) +} + +func ToBytes(a *string) []byte { + return []byte(tea.StringValue(a)) +} + +func AssertAsMap(a interface{}) map[string]interface{} { + r := reflect.ValueOf(a) + if r.Kind().String() != "map" { + panic(fmt.Sprintf("%v is not a map[string]interface{}", a)) + } + + res := make(map[string]interface{}) + tmp := r.MapKeys() + for _, key := range tmp { + res[key.String()] = r.MapIndex(key).Interface() + } + + return res +} + +func AssertAsNumber(a interface{}) *int { + res := 0 + switch a.(type) { + case int: + tmp := a.(int) + res = tmp + case *int: + tmp := a.(*int) + res = tea.IntValue(tmp) + default: + panic(fmt.Sprintf("%v is not a int", a)) + } + + return tea.Int(res) +} + +func AssertAsBoolean(a interface{}) *bool { + res := false + switch a.(type) { + case bool: + tmp := a.(bool) + res = tmp + case *bool: + tmp := a.(*bool) + res = tea.BoolValue(tmp) + default: + panic(fmt.Sprintf("%v is not a bool", a)) + } + + return tea.Bool(res) +} + +func AssertAsString(a interface{}) *string { + res := "" + switch a.(type) { + case string: + tmp := a.(string) + res = tmp + case *string: + tmp := a.(*string) + res = tea.StringValue(tmp) + default: + panic(fmt.Sprintf("%v is not a string", a)) + } + + return tea.String(res) +} + +func AssertAsBytes(a interface{}) []byte { + res, ok := a.([]byte) + if !ok { + panic(fmt.Sprintf("%v is not []byte", a)) + } + return res +} + +func AssertAsReadable(a interface{}) io.Reader { + res, ok := a.(io.Reader) + if !ok { + panic(fmt.Sprintf("%v is not reader", a)) + } + return res +} + +func AssertAsArray(a interface{}) []interface{} { + r := reflect.ValueOf(a) + if r.Kind().String() != "array" && r.Kind().String() != "slice" { + panic(fmt.Sprintf("%v is not a [x]interface{}", a)) + } + aLen := r.Len() + res := make([]interface{}, 0) + for i := 0; i < aLen; i++ { + res = append(res, r.Index(i).Interface()) + } + return res +} + +func ParseJSON(a *string) interface{} { + mapTmp := make(map[string]interface{}) + d := json.NewDecoder(bytes.NewReader([]byte(tea.StringValue(a)))) + d.UseNumber() + err := d.Decode(&mapTmp) + if err == nil { + return mapTmp + } + + sliceTmp := make([]interface{}, 0) + d = json.NewDecoder(bytes.NewReader([]byte(tea.StringValue(a)))) + d.UseNumber() + err = d.Decode(&sliceTmp) + if err == nil { + return sliceTmp + } + + if num, err := strconv.Atoi(tea.StringValue(a)); err == nil { + return num + } + + if ok, err := strconv.ParseBool(tea.StringValue(a)); err == nil { + return ok + } + + if floa64tVal, err := strconv.ParseFloat(tea.StringValue(a), 64); err == nil { + return floa64tVal + } + return nil +} + +func ToString(a []byte) *string { + return tea.String(string(a)) +} + +func ToMap(in interface{}) map[string]interface{} { + if in == nil { + return nil + } + res := tea.ToMap(in) + return res +} + +func ToFormString(a map[string]interface{}) *string { + if a == nil { + return tea.String("") + } + res := "" + urlEncoder := url.Values{} + for key, value := range a { + v := fmt.Sprintf("%v", value) + urlEncoder.Add(key, v) + } + res = urlEncoder.Encode() + return tea.String(res) +} + +func GetDateUTCString() *string { + return tea.String(time.Now().UTC().Format(http.TimeFormat)) +} + +func GetUserAgent(userAgent *string) *string { + if userAgent != nil && tea.StringValue(userAgent) != "" { + return tea.String(defaultUserAgent + " " + tea.StringValue(userAgent)) + } + return tea.String(defaultUserAgent) +} + +func Is2xx(code *int) *bool { + tmp := tea.IntValue(code) + return tea.Bool(tmp >= 200 && tmp < 300) +} + +func Is3xx(code *int) *bool { + tmp := tea.IntValue(code) + return tea.Bool(tmp >= 300 && tmp < 400) +} + +func Is4xx(code *int) *bool { + tmp := tea.IntValue(code) + return tea.Bool(tmp >= 400 && tmp < 500) +} + +func Is5xx(code *int) *bool { + tmp := tea.IntValue(code) + return tea.Bool(tmp >= 500 && tmp < 600) +} + +func Sleep(millisecond *int) error { + ms := tea.IntValue(millisecond) + time.Sleep(time.Duration(ms) * time.Millisecond) + return nil +} + +func ToArray(in interface{}) []map[string]interface{} { + if tea.BoolValue(IsUnset(in)) { + return nil + } + + tmp := make([]map[string]interface{}, 0) + byt, _ := json.Marshal(in) + d := json.NewDecoder(bytes.NewReader(byt)) + d.UseNumber() + err := d.Decode(&tmp) + if err != nil { + return nil + } + return tmp +} diff --git a/vendor/github.com/alibabacloud-go/tea-utils/service/util.go b/vendor/github.com/alibabacloud-go/tea-utils/service/util.go new file mode 100644 index 000000000..a73cb5600 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea-utils/service/util.go @@ -0,0 +1,52 @@ +package service + +import ( + "crypto/md5" + "crypto/rand" + "encoding/hex" + "hash" + rand2 "math/rand" +) + +type UUID [16]byte + +const numBytes = "1234567890" + +func getUUID() (uuidHex string) { + uuid := newUUID() + uuidHex = hex.EncodeToString(uuid[:]) + return +} + +func randStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = numBytes[rand2.Intn(len(numBytes))] + } + return string(b) +} + +func newUUID() UUID { + ns := UUID{} + safeRandom(ns[:]) + u := newFromHash(md5.New(), ns, randStringBytes(16)) + u[6] = (u[6] & 0x0f) | (byte(2) << 4) + u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) + + return u +} + +func newFromHash(h hash.Hash, ns UUID, name string) UUID { + u := UUID{} + h.Write(ns[:]) + h.Write([]byte(name)) + copy(u[:], h.Sum(nil)) + + return u +} + +func safeRandom(dest []byte) { + if _, err := rand.Read(dest); err != nil { + panic(err) + } +} diff --git a/vendor/github.com/alibabacloud-go/tea-xml/service/service.go b/vendor/github.com/alibabacloud-go/tea-xml/service/service.go new file mode 100644 index 000000000..33139c74b --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea-xml/service/service.go @@ -0,0 +1,105 @@ +package service + +import ( + "bytes" + "encoding/xml" + "fmt" + "reflect" + "strings" + + "github.com/alibabacloud-go/tea/tea" + v2 "github.com/clbanning/mxj/v2" +) + +func ToXML(obj map[string]interface{}) *string { + return tea.String(mapToXML(obj)) +} + +func ParseXml(val *string, result interface{}) map[string]interface{} { + resp := make(map[string]interface{}) + + start := getStartElement([]byte(tea.StringValue(val))) + if result == nil { + vm, err := v2.NewMapXml([]byte(tea.StringValue(val))) + if err != nil { + return nil + } + return vm + } + out, err := xmlUnmarshal([]byte(tea.StringValue(val)), result) + if err != nil { + return resp + } + resp[start] = out + return resp +} + +func mapToXML(val map[string]interface{}) string { + res := "" + for key, value := range val { + switch value.(type) { + case []interface{}: + for _, v := range value.([]interface{}) { + switch v.(type) { + case map[string]interface{}: + res += `<` + key + `>` + res += mapToXML(v.(map[string]interface{})) + res += `` + default: + if fmt.Sprintf("%v", v) != `` { + res += `<` + key + `>` + res += fmt.Sprintf("%v", v) + res += `` + } + } + } + case map[string]interface{}: + res += `<` + key + `>` + res += mapToXML(value.(map[string]interface{})) + res += `` + default: + if fmt.Sprintf("%v", value) != `` { + res += `<` + key + `>` + res += fmt.Sprintf("%v", value) + res += `` + } + } + } + return res +} + +func getStartElement(body []byte) string { + d := xml.NewDecoder(bytes.NewReader(body)) + for { + tok, err := d.Token() + if err != nil { + return "" + } + if t, ok := tok.(xml.StartElement); ok { + return t.Name.Local + } + } +} + +func xmlUnmarshal(body []byte, result interface{}) (interface{}, error) { + start := getStartElement(body) + dataValue := reflect.ValueOf(result).Elem() + dataType := dataValue.Type() + for i := 0; i < dataType.NumField(); i++ { + field := dataType.Field(i) + name, containsNameTag := field.Tag.Lookup("xml") + name = strings.Replace(name, ",omitempty", "", -1) + if containsNameTag { + if name == start { + realType := dataValue.Field(i).Type() + realValue := reflect.New(realType).Interface() + err := xml.Unmarshal(body, realValue) + if err != nil { + return nil, err + } + return realValue, nil + } + } + } + return nil, nil +} diff --git a/vendor/github.com/alibabacloud-go/tea/LICENSE b/vendor/github.com/alibabacloud-go/tea/LICENSE new file mode 100644 index 000000000..0c44dcefe --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/alibabacloud-go/tea/tea/json_parser.go b/vendor/github.com/alibabacloud-go/tea/tea/json_parser.go new file mode 100644 index 000000000..b3f202243 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/tea/json_parser.go @@ -0,0 +1,333 @@ +package tea + +import ( + "encoding/json" + "io" + "math" + "reflect" + "strconv" + "strings" + "unsafe" + + jsoniter "github.com/json-iterator/go" + "github.com/modern-go/reflect2" +) + +const maxUint = ^uint(0) +const maxInt = int(maxUint >> 1) +const minInt = -maxInt - 1 + +var jsonParser jsoniter.API + +func init() { + jsonParser = jsoniter.Config{ + EscapeHTML: true, + SortMapKeys: true, + ValidateJsonRawMessage: true, + CaseSensitive: true, + }.Froze() + + jsonParser.RegisterExtension(newBetterFuzzyExtension()) +} + +func newBetterFuzzyExtension() jsoniter.DecoderExtension { + return jsoniter.DecoderExtension{ + reflect2.DefaultTypeOfKind(reflect.String): &nullableFuzzyStringDecoder{}, + reflect2.DefaultTypeOfKind(reflect.Bool): &fuzzyBoolDecoder{}, + reflect2.DefaultTypeOfKind(reflect.Float32): &nullableFuzzyFloat32Decoder{}, + reflect2.DefaultTypeOfKind(reflect.Float64): &nullableFuzzyFloat64Decoder{}, + reflect2.DefaultTypeOfKind(reflect.Int): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(maxInt) || val < float64(minInt) { + iter.ReportError("fuzzy decode int", "exceed range") + return + } + *((*int)(ptr)) = int(val) + } else { + *((*int)(ptr)) = iter.ReadInt() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Uint): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(maxUint) || val < 0 { + iter.ReportError("fuzzy decode uint", "exceed range") + return + } + *((*uint)(ptr)) = uint(val) + } else { + *((*uint)(ptr)) = iter.ReadUint() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Int8): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxInt8) || val < float64(math.MinInt8) { + iter.ReportError("fuzzy decode int8", "exceed range") + return + } + *((*int8)(ptr)) = int8(val) + } else { + *((*int8)(ptr)) = iter.ReadInt8() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Uint8): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxUint8) || val < 0 { + iter.ReportError("fuzzy decode uint8", "exceed range") + return + } + *((*uint8)(ptr)) = uint8(val) + } else { + *((*uint8)(ptr)) = iter.ReadUint8() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Int16): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxInt16) || val < float64(math.MinInt16) { + iter.ReportError("fuzzy decode int16", "exceed range") + return + } + *((*int16)(ptr)) = int16(val) + } else { + *((*int16)(ptr)) = iter.ReadInt16() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Uint16): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxUint16) || val < 0 { + iter.ReportError("fuzzy decode uint16", "exceed range") + return + } + *((*uint16)(ptr)) = uint16(val) + } else { + *((*uint16)(ptr)) = iter.ReadUint16() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Int32): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxInt32) || val < float64(math.MinInt32) { + iter.ReportError("fuzzy decode int32", "exceed range") + return + } + *((*int32)(ptr)) = int32(val) + } else { + *((*int32)(ptr)) = iter.ReadInt32() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Uint32): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxUint32) || val < 0 { + iter.ReportError("fuzzy decode uint32", "exceed range") + return + } + *((*uint32)(ptr)) = uint32(val) + } else { + *((*uint32)(ptr)) = iter.ReadUint32() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Int64): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxInt64) || val < float64(math.MinInt64) { + iter.ReportError("fuzzy decode int64", "exceed range") + return + } + *((*int64)(ptr)) = int64(val) + } else { + *((*int64)(ptr)) = iter.ReadInt64() + } + }}, + reflect2.DefaultTypeOfKind(reflect.Uint64): &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { + if isFloat { + val := iter.ReadFloat64() + if val > float64(math.MaxUint64) || val < 0 { + iter.ReportError("fuzzy decode uint64", "exceed range") + return + } + *((*uint64)(ptr)) = uint64(val) + } else { + *((*uint64)(ptr)) = iter.ReadUint64() + } + }}, + } +} + +type nullableFuzzyStringDecoder struct { +} + +func (decoder *nullableFuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + valueType := iter.WhatIsNext() + switch valueType { + case jsoniter.NumberValue: + var number json.Number + iter.ReadVal(&number) + *((*string)(ptr)) = string(number) + case jsoniter.StringValue: + *((*string)(ptr)) = iter.ReadString() + case jsoniter.BoolValue: + *((*string)(ptr)) = strconv.FormatBool(iter.ReadBool()) + case jsoniter.NilValue: + iter.ReadNil() + *((*string)(ptr)) = "" + default: + iter.ReportError("fuzzyStringDecoder", "not number or string or bool") + } +} + +type fuzzyBoolDecoder struct { +} + +func (decoder *fuzzyBoolDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + valueType := iter.WhatIsNext() + switch valueType { + case jsoniter.BoolValue: + *((*bool)(ptr)) = iter.ReadBool() + case jsoniter.NumberValue: + var number json.Number + iter.ReadVal(&number) + num, err := number.Int64() + if err != nil { + iter.ReportError("fuzzyBoolDecoder", "get value from json.number failed") + } + if num == 0 { + *((*bool)(ptr)) = false + } else { + *((*bool)(ptr)) = true + } + case jsoniter.StringValue: + strValue := strings.ToLower(iter.ReadString()) + if strValue == "true" { + *((*bool)(ptr)) = true + } else if strValue == "false" || strValue == "" { + *((*bool)(ptr)) = false + } else { + iter.ReportError("fuzzyBoolDecoder", "unsupported bool value: "+strValue) + } + case jsoniter.NilValue: + iter.ReadNil() + *((*bool)(ptr)) = false + default: + iter.ReportError("fuzzyBoolDecoder", "not number or string or nil") + } +} + +type nullableFuzzyIntegerDecoder struct { + fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) +} + +func (decoder *nullableFuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + valueType := iter.WhatIsNext() + var str string + switch valueType { + case jsoniter.NumberValue: + var number json.Number + iter.ReadVal(&number) + str = string(number) + case jsoniter.StringValue: + str = iter.ReadString() + // support empty string + if str == "" { + str = "0" + } + case jsoniter.BoolValue: + if iter.ReadBool() { + str = "1" + } else { + str = "0" + } + case jsoniter.NilValue: + iter.ReadNil() + str = "0" + default: + iter.ReportError("fuzzyIntegerDecoder", "not number or string") + } + newIter := iter.Pool().BorrowIterator([]byte(str)) + defer iter.Pool().ReturnIterator(newIter) + isFloat := strings.IndexByte(str, '.') != -1 + decoder.fun(isFloat, ptr, newIter) + if newIter.Error != nil && newIter.Error != io.EOF { + iter.Error = newIter.Error + } +} + +type nullableFuzzyFloat32Decoder struct { +} + +func (decoder *nullableFuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + valueType := iter.WhatIsNext() + var str string + switch valueType { + case jsoniter.NumberValue: + *((*float32)(ptr)) = iter.ReadFloat32() + case jsoniter.StringValue: + str = iter.ReadString() + // support empty string + if str == "" { + *((*float32)(ptr)) = 0 + return + } + newIter := iter.Pool().BorrowIterator([]byte(str)) + defer iter.Pool().ReturnIterator(newIter) + *((*float32)(ptr)) = newIter.ReadFloat32() + if newIter.Error != nil && newIter.Error != io.EOF { + iter.Error = newIter.Error + } + case jsoniter.BoolValue: + // support bool to float32 + if iter.ReadBool() { + *((*float32)(ptr)) = 1 + } else { + *((*float32)(ptr)) = 0 + } + case jsoniter.NilValue: + iter.ReadNil() + *((*float32)(ptr)) = 0 + default: + iter.ReportError("nullableFuzzyFloat32Decoder", "not number or string") + } +} + +type nullableFuzzyFloat64Decoder struct { +} + +func (decoder *nullableFuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { + valueType := iter.WhatIsNext() + var str string + switch valueType { + case jsoniter.NumberValue: + *((*float64)(ptr)) = iter.ReadFloat64() + case jsoniter.StringValue: + str = iter.ReadString() + // support empty string + if str == "" { + *((*float64)(ptr)) = 0 + return + } + newIter := iter.Pool().BorrowIterator([]byte(str)) + defer iter.Pool().ReturnIterator(newIter) + *((*float64)(ptr)) = newIter.ReadFloat64() + if newIter.Error != nil && newIter.Error != io.EOF { + iter.Error = newIter.Error + } + case jsoniter.BoolValue: + // support bool to float64 + if iter.ReadBool() { + *((*float64)(ptr)) = 1 + } else { + *((*float64)(ptr)) = 0 + } + case jsoniter.NilValue: + // support empty string + iter.ReadNil() + *((*float64)(ptr)) = 0 + default: + iter.ReportError("nullableFuzzyFloat64Decoder", "not number or string") + } +} diff --git a/vendor/github.com/alibabacloud-go/tea/tea/tea.go b/vendor/github.com/alibabacloud-go/tea/tea/tea.go new file mode 100644 index 000000000..ac5a7e684 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/tea/tea.go @@ -0,0 +1,1121 @@ +package tea + +import ( + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "math/rand" + "net" + "net/http" + "net/url" + "os" + "reflect" + "regexp" + "strconv" + "strings" + "sync" + "time" + + "github.com/alibabacloud-go/debug/debug" + "github.com/alibabacloud-go/tea/utils" + + "golang.org/x/net/proxy" +) + +var debugLog = debug.Init("tea") + +var hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) { + return fn +} + +var basicTypes = []string{ + "int", "int16", "int64", "int32", "float32", "float64", "string", "bool", "uint64", "uint32", "uint16", +} + +// Verify whether the parameters meet the requirements +var validateParams = []string{"require", "pattern", "maxLength", "minLength", "maximum", "minimum", "maxItems", "minItems"} + +// CastError is used for cast type fails +type CastError struct { + Message *string +} + +// Request is used wrap http request +type Request struct { + Protocol *string + Port *int + Method *string + Pathname *string + Domain *string + Headers map[string]*string + Query map[string]*string + Body io.Reader +} + +// Response is use d wrap http response +type Response struct { + Body io.ReadCloser + StatusCode *int + StatusMessage *string + Headers map[string]*string +} + +// SDKError struct is used save error code and message +type SDKError struct { + Code *string + StatusCode *int + Message *string + Data *string + Stack *string + errMsg *string +} + +// RuntimeObject is used for converting http configuration +type RuntimeObject struct { + IgnoreSSL *bool `json:"ignoreSSL" xml:"ignoreSSL"` + ReadTimeout *int `json:"readTimeout" xml:"readTimeout"` + ConnectTimeout *int `json:"connectTimeout" xml:"connectTimeout"` + LocalAddr *string `json:"localAddr" xml:"localAddr"` + HttpProxy *string `json:"httpProxy" xml:"httpProxy"` + HttpsProxy *string `json:"httpsProxy" xml:"httpsProxy"` + NoProxy *string `json:"noProxy" xml:"noProxy"` + MaxIdleConns *int `json:"maxIdleConns" xml:"maxIdleConns"` + Key *string `json:"key" xml:"key"` + Cert *string `json:"cert" xml:"cert"` + CA *string `json:"ca" xml:"ca"` + Socks5Proxy *string `json:"socks5Proxy" xml:"socks5Proxy"` + Socks5NetWork *string `json:"socks5NetWork" xml:"socks5NetWork"` + Listener utils.ProgressListener `json:"listener" xml:"listener"` + Tracker *utils.ReaderTracker `json:"tracker" xml:"tracker"` + Logger *utils.Logger `json:"logger" xml:"logger"` +} + +type teaClient struct { + sync.Mutex + httpClient *http.Client + ifInit bool +} + +var clientPool = &sync.Map{} + +func (r *RuntimeObject) getClientTag(domain string) string { + return strconv.FormatBool(BoolValue(r.IgnoreSSL)) + strconv.Itoa(IntValue(r.ReadTimeout)) + + strconv.Itoa(IntValue(r.ConnectTimeout)) + StringValue(r.LocalAddr) + StringValue(r.HttpProxy) + + StringValue(r.HttpsProxy) + StringValue(r.NoProxy) + StringValue(r.Socks5Proxy) + StringValue(r.Socks5NetWork) + domain +} + +// NewRuntimeObject is used for shortly create runtime object +func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject { + if runtime == nil { + return &RuntimeObject{} + } + + runtimeObject := &RuntimeObject{ + IgnoreSSL: TransInterfaceToBool(runtime["ignoreSSL"]), + ReadTimeout: TransInterfaceToInt(runtime["readTimeout"]), + ConnectTimeout: TransInterfaceToInt(runtime["connectTimeout"]), + LocalAddr: TransInterfaceToString(runtime["localAddr"]), + HttpProxy: TransInterfaceToString(runtime["httpProxy"]), + HttpsProxy: TransInterfaceToString(runtime["httpsProxy"]), + NoProxy: TransInterfaceToString(runtime["noProxy"]), + MaxIdleConns: TransInterfaceToInt(runtime["maxIdleConns"]), + Socks5Proxy: TransInterfaceToString(runtime["socks5Proxy"]), + Socks5NetWork: TransInterfaceToString(runtime["socks5NetWork"]), + Key: TransInterfaceToString(runtime["key"]), + Cert: TransInterfaceToString(runtime["cert"]), + CA: TransInterfaceToString(runtime["ca"]), + } + if runtime["listener"] != nil { + runtimeObject.Listener = runtime["listener"].(utils.ProgressListener) + } + if runtime["tracker"] != nil { + runtimeObject.Tracker = runtime["tracker"].(*utils.ReaderTracker) + } + if runtime["logger"] != nil { + runtimeObject.Logger = runtime["logger"].(*utils.Logger) + } + return runtimeObject +} + +// NewCastError is used for cast type fails +func NewCastError(message *string) (err error) { + return &CastError{ + Message: message, + } +} + +// NewRequest is used shortly create Request +func NewRequest() (req *Request) { + return &Request{ + Headers: map[string]*string{}, + Query: map[string]*string{}, + } +} + +// NewResponse is create response with http response +func NewResponse(httpResponse *http.Response) (res *Response) { + res = &Response{} + res.Body = httpResponse.Body + res.Headers = make(map[string]*string) + res.StatusCode = Int(httpResponse.StatusCode) + res.StatusMessage = String(httpResponse.Status) + return +} + +// NewSDKError is used for shortly create SDKError object +func NewSDKError(obj map[string]interface{}) *SDKError { + err := &SDKError{} + if val, ok := obj["code"].(int); ok { + err.Code = String(strconv.Itoa(val)) + } else if val, ok := obj["code"].(string); ok { + err.Code = String(val) + } + + if statusCode, ok := obj["statusCode"].(int); ok { + err.StatusCode = Int(statusCode) + } else if status, ok := obj["statusCode"].(string); ok { + statusCode, err2 := strconv.Atoi(status) + if err2 == nil { + err.StatusCode = Int(statusCode) + } + } + + if obj["message"] != nil { + err.Message = String(obj["message"].(string)) + } + if data := obj["data"]; data != nil { + byt, _ := json.Marshal(data) + err.Data = String(string(byt)) + } + return err +} + +// Set ErrMsg by msg +func (err *SDKError) SetErrMsg(msg string) { + err.errMsg = String(msg) +} + +func (err *SDKError) Error() string { + if err.errMsg == nil { + str := fmt.Sprintf("SDKError:\n StatusCode: %d\n Code: %s\n Message: %s\n Data: %s\n", + IntValue(err.StatusCode), StringValue(err.Code), StringValue(err.Message), StringValue(err.Data)) + err.SetErrMsg(str) + } + return StringValue(err.errMsg) +} + +// Return message of CastError +func (err *CastError) Error() string { + return StringValue(err.Message) +} + +// Convert is use convert map[string]interface object to struct +func Convert(in interface{}, out interface{}) error { + byt, _ := json.Marshal(in) + decoder := jsonParser.NewDecoder(bytes.NewReader(byt)) + decoder.UseNumber() + err := decoder.Decode(&out) + return err +} + +// Convert is use convert map[string]interface object to struct +func Recover(in interface{}) error { + if in == nil { + return nil + } + return errors.New(fmt.Sprint(in)) +} + +// ReadBody is used read response body +func (response *Response) ReadBody() (body []byte, err error) { + defer response.Body.Close() + var buffer [512]byte + result := bytes.NewBuffer(nil) + + for { + n, err := response.Body.Read(buffer[0:]) + result.Write(buffer[0:n]) + if err != nil && err == io.EOF { + break + } else if err != nil { + return nil, err + } + } + return result.Bytes(), nil +} + +func getTeaClient(tag string) *teaClient { + client, ok := clientPool.Load(tag) + if client == nil && !ok { + client = &teaClient{ + httpClient: &http.Client{}, + ifInit: false, + } + clientPool.Store(tag, client) + } + return client.(*teaClient) +} + +// DoRequest is used send request to server +func DoRequest(request *Request, requestRuntime map[string]interface{}) (response *Response, err error) { + runtimeObject := NewRuntimeObject(requestRuntime) + fieldMap := make(map[string]string) + utils.InitLogMsg(fieldMap) + defer func() { + if runtimeObject.Logger != nil { + runtimeObject.Logger.PrintLog(fieldMap, err) + } + }() + if request.Method == nil { + request.Method = String("GET") + } + + if request.Protocol == nil { + request.Protocol = String("http") + } else { + request.Protocol = String(strings.ToLower(StringValue(request.Protocol))) + } + + requestURL := "" + request.Domain = request.Headers["host"] + requestURL = fmt.Sprintf("%s://%s%s", StringValue(request.Protocol), StringValue(request.Domain), StringValue(request.Pathname)) + queryParams := request.Query + // sort QueryParams by key + q := url.Values{} + for key, value := range queryParams { + q.Add(key, StringValue(value)) + } + querystring := q.Encode() + if len(querystring) > 0 { + if strings.Contains(requestURL, "?") { + requestURL = fmt.Sprintf("%s&%s", requestURL, querystring) + } else { + requestURL = fmt.Sprintf("%s?%s", requestURL, querystring) + } + } + debugLog("> %s %s", StringValue(request.Method), requestURL) + + httpRequest, err := http.NewRequest(StringValue(request.Method), requestURL, request.Body) + if err != nil { + return + } + httpRequest.Host = StringValue(request.Domain) + + client := getTeaClient(runtimeObject.getClientTag(StringValue(request.Domain))) + client.Lock() + if !client.ifInit { + trans, err := getHttpTransport(request, runtimeObject) + if err != nil { + return nil, err + } + client.httpClient.Timeout = time.Duration(IntValue(runtimeObject.ReadTimeout)) * time.Millisecond + client.httpClient.Transport = trans + client.ifInit = true + } + client.Unlock() + for key, value := range request.Headers { + if value == nil || key == "content-length" { + continue + } else if key == "host" { + httpRequest.Header["Host"] = []string{*value} + delete(httpRequest.Header, "host") + } else if key == "user-agent" { + httpRequest.Header["User-Agent"] = []string{*value} + delete(httpRequest.Header, "user-agent") + } else { + httpRequest.Header[key] = []string{*value} + } + debugLog("> %s: %s", key, StringValue(value)) + } + contentlength, _ := strconv.Atoi(StringValue(request.Headers["content-length"])) + event := utils.NewProgressEvent(utils.TransferStartedEvent, 0, int64(contentlength), 0) + utils.PublishProgress(runtimeObject.Listener, event) + + putMsgToMap(fieldMap, httpRequest) + startTime := time.Now() + fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05") + res, err := hookDo(client.httpClient.Do)(httpRequest) + fieldMap["{cost}"] = time.Since(startTime).String() + completedBytes := int64(0) + if runtimeObject.Tracker != nil { + completedBytes = runtimeObject.Tracker.CompletedBytes + } + if err != nil { + event = utils.NewProgressEvent(utils.TransferFailedEvent, completedBytes, int64(contentlength), 0) + utils.PublishProgress(runtimeObject.Listener, event) + return + } + + event = utils.NewProgressEvent(utils.TransferCompletedEvent, completedBytes, int64(contentlength), 0) + utils.PublishProgress(runtimeObject.Listener, event) + + response = NewResponse(res) + fieldMap["{code}"] = strconv.Itoa(res.StatusCode) + fieldMap["{res_headers}"] = transToString(res.Header) + debugLog("< HTTP/1.1 %s", res.Status) + for key, value := range res.Header { + debugLog("< %s: %s", key, strings.Join(value, "")) + if len(value) != 0 { + response.Headers[strings.ToLower(key)] = String(value[0]) + } + } + return +} + +func getHttpTransport(req *Request, runtime *RuntimeObject) (*http.Transport, error) { + trans := new(http.Transport) + httpProxy, err := getHttpProxy(StringValue(req.Protocol), StringValue(req.Domain), runtime) + if err != nil { + return nil, err + } + if strings.ToLower(*req.Protocol) == "https" && + runtime.Key != nil && runtime.Cert != nil { + cert, err := tls.X509KeyPair([]byte(StringValue(runtime.Cert)), []byte(StringValue(runtime.Key))) + if err != nil { + return nil, err + } + + trans.TLSClientConfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + InsecureSkipVerify: BoolValue(runtime.IgnoreSSL), + } + if runtime.CA != nil { + clientCertPool := x509.NewCertPool() + ok := clientCertPool.AppendCertsFromPEM([]byte(StringValue(runtime.CA))) + if !ok { + return nil, errors.New("Failed to parse root certificate") + } + trans.TLSClientConfig.RootCAs = clientCertPool + } + } else { + trans.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: BoolValue(runtime.IgnoreSSL), + } + } + if httpProxy != nil { + trans.Proxy = http.ProxyURL(httpProxy) + if httpProxy.User != nil { + password, _ := httpProxy.User.Password() + auth := httpProxy.User.Username() + ":" + password + basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) + req.Headers["Proxy-Authorization"] = String(basic) + } + } + if runtime.Socks5Proxy != nil && StringValue(runtime.Socks5Proxy) != "" { + socks5Proxy, err := getSocks5Proxy(runtime) + if err != nil { + return nil, err + } + if socks5Proxy != nil { + var auth *proxy.Auth + if socks5Proxy.User != nil { + password, _ := socks5Proxy.User.Password() + auth = &proxy.Auth{ + User: socks5Proxy.User.Username(), + Password: password, + } + } + dialer, err := proxy.SOCKS5(strings.ToLower(StringValue(runtime.Socks5NetWork)), socks5Proxy.String(), auth, + &net.Dialer{ + Timeout: time.Duration(IntValue(runtime.ConnectTimeout)) * time.Millisecond, + DualStack: true, + LocalAddr: getLocalAddr(StringValue(runtime.LocalAddr)), + }) + if err != nil { + return nil, err + } + trans.Dial = dialer.Dial + } + } else { + trans.DialContext = setDialContext(runtime) + } + return trans, nil +} + +func transToString(object interface{}) string { + byt, _ := json.Marshal(object) + return string(byt) +} + +func putMsgToMap(fieldMap map[string]string, request *http.Request) { + fieldMap["{host}"] = request.Host + fieldMap["{method}"] = request.Method + fieldMap["{uri}"] = request.URL.RequestURI() + fieldMap["{pid}"] = strconv.Itoa(os.Getpid()) + fieldMap["{version}"] = strings.Split(request.Proto, "/")[1] + hostname, _ := os.Hostname() + fieldMap["{hostname}"] = hostname + fieldMap["{req_headers}"] = transToString(request.Header) + fieldMap["{target}"] = request.URL.Path + request.URL.RawQuery +} + +func getNoProxy(protocol string, runtime *RuntimeObject) []string { + var urls []string + if runtime.NoProxy != nil && StringValue(runtime.NoProxy) != "" { + urls = strings.Split(StringValue(runtime.NoProxy), ",") + } else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" { + urls = strings.Split(rawurl, ",") + } else if rawurl := os.Getenv("no_proxy"); rawurl != "" { + urls = strings.Split(rawurl, ",") + } + + return urls +} + +func ToReader(obj interface{}) io.Reader { + switch obj.(type) { + case *string: + tmp := obj.(*string) + return strings.NewReader(StringValue(tmp)) + case []byte: + return strings.NewReader(string(obj.([]byte))) + case io.Reader: + return obj.(io.Reader) + default: + panic("Invalid Body. Please set a valid Body.") + } +} + +func ToString(val interface{}) string { + return fmt.Sprintf("%v", val) +} + +func getHttpProxy(protocol, host string, runtime *RuntimeObject) (proxy *url.URL, err error) { + urls := getNoProxy(protocol, runtime) + for _, url := range urls { + if url == host { + return nil, nil + } + } + if protocol == "https" { + if runtime.HttpsProxy != nil && StringValue(runtime.HttpsProxy) != "" { + proxy, err = url.Parse(StringValue(runtime.HttpsProxy)) + } else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } else if rawurl := os.Getenv("https_proxy"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } + } else { + if runtime.HttpProxy != nil && StringValue(runtime.HttpProxy) != "" { + proxy, err = url.Parse(StringValue(runtime.HttpProxy)) + } else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } else if rawurl := os.Getenv("http_proxy"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } + } + + return proxy, err +} + +func getSocks5Proxy(runtime *RuntimeObject) (proxy *url.URL, err error) { + if runtime.Socks5Proxy != nil && StringValue(runtime.Socks5Proxy) != "" { + proxy, err = url.Parse(StringValue(runtime.Socks5Proxy)) + } + return proxy, err +} + +func getLocalAddr(localAddr string) (addr *net.TCPAddr) { + if localAddr != "" { + addr = &net.TCPAddr{ + IP: []byte(localAddr), + } + } + return addr +} + +func setDialContext(runtime *RuntimeObject) func(cxt context.Context, net, addr string) (c net.Conn, err error) { + return func(ctx context.Context, network, address string) (net.Conn, error) { + if runtime.LocalAddr != nil && StringValue(runtime.LocalAddr) != "" { + netAddr := &net.TCPAddr{ + IP: []byte(StringValue(runtime.LocalAddr)), + } + return (&net.Dialer{ + Timeout: time.Duration(IntValue(runtime.ConnectTimeout)) * time.Second, + DualStack: true, + LocalAddr: netAddr, + }).DialContext(ctx, network, address) + } + return (&net.Dialer{ + Timeout: time.Duration(IntValue(runtime.ConnectTimeout)) * time.Second, + DualStack: true, + }).DialContext(ctx, network, address) + } +} + +func ToObject(obj interface{}) map[string]interface{} { + result := make(map[string]interface{}) + byt, _ := json.Marshal(obj) + err := json.Unmarshal(byt, &result) + if err != nil { + return nil + } + return result +} + +func AllowRetry(retry interface{}, retryTimes *int) *bool { + if IntValue(retryTimes) == 0 { + return Bool(true) + } + retryMap, ok := retry.(map[string]interface{}) + if !ok { + return Bool(false) + } + retryable, ok := retryMap["retryable"].(bool) + if !ok || !retryable { + return Bool(false) + } + + maxAttempts, ok := retryMap["maxAttempts"].(int) + if !ok || maxAttempts < IntValue(retryTimes) { + return Bool(false) + } + return Bool(true) +} + +func Merge(args ...interface{}) map[string]*string { + finalArg := make(map[string]*string) + for _, obj := range args { + switch obj.(type) { + case map[string]*string: + arg := obj.(map[string]*string) + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + default: + byt, _ := json.Marshal(obj) + arg := make(map[string]string) + err := json.Unmarshal(byt, &arg) + if err != nil { + return finalArg + } + for key, value := range arg { + if value != "" { + finalArg[key] = String(value) + } + } + } + } + + return finalArg +} + +func isNil(a interface{}) bool { + defer func() { + recover() + }() + vi := reflect.ValueOf(a) + return vi.IsNil() +} + +func ToMap(args ...interface{}) map[string]interface{} { + isNotNil := false + finalArg := make(map[string]interface{}) + for _, obj := range args { + if obj == nil { + continue + } + + if isNil(obj) { + continue + } + isNotNil = true + + switch obj.(type) { + case map[string]*string: + arg := obj.(map[string]*string) + for key, value := range arg { + if value != nil { + finalArg[key] = StringValue(value) + } + } + case map[string]interface{}: + arg := obj.(map[string]interface{}) + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + case *string: + str := obj.(*string) + arg := make(map[string]interface{}) + err := json.Unmarshal([]byte(StringValue(str)), &arg) + if err == nil { + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + } + tmp := make(map[string]string) + err = json.Unmarshal([]byte(StringValue(str)), &tmp) + if err == nil { + for key, value := range arg { + if value != "" { + finalArg[key] = value + } + } + } + case []byte: + byt := obj.([]byte) + arg := make(map[string]interface{}) + err := json.Unmarshal(byt, &arg) + if err == nil { + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + break + } + default: + val := reflect.ValueOf(obj) + res := structToMap(val) + for key, value := range res { + if value != nil { + finalArg[key] = value + } + } + } + } + + if !isNotNil { + return nil + } + return finalArg +} + +func structToMap(dataValue reflect.Value) map[string]interface{} { + out := make(map[string]interface{}) + if !dataValue.IsValid() { + return out + } + if dataValue.Kind().String() == "ptr" { + if dataValue.IsNil() { + return out + } + dataValue = dataValue.Elem() + } + if !dataValue.IsValid() { + return out + } + dataType := dataValue.Type() + if dataType.Kind().String() != "struct" { + return out + } + for i := 0; i < dataType.NumField(); i++ { + field := dataType.Field(i) + name, containsNameTag := field.Tag.Lookup("json") + if !containsNameTag { + name = field.Name + } else { + strs := strings.Split(name, ",") + name = strs[0] + } + fieldValue := dataValue.FieldByName(field.Name) + if !fieldValue.IsValid() || fieldValue.IsNil() { + continue + } + if field.Type.String() == "io.Reader" || field.Type.String() == "io.Writer" { + continue + } else if field.Type.Kind().String() == "struct" { + out[name] = structToMap(fieldValue) + } else if field.Type.Kind().String() == "ptr" && + field.Type.Elem().Kind().String() == "struct" { + if fieldValue.Elem().IsValid() { + out[name] = structToMap(fieldValue) + } + } else if field.Type.Kind().String() == "ptr" { + if fieldValue.IsValid() && !fieldValue.IsNil() { + out[name] = fieldValue.Elem().Interface() + } + } else if field.Type.Kind().String() == "slice" { + tmp := make([]interface{}, 0) + num := fieldValue.Len() + for i := 0; i < num; i++ { + value := fieldValue.Index(i) + if !value.IsValid() { + continue + } + if value.Type().Kind().String() == "ptr" && + value.Type().Elem().Kind().String() == "struct" { + if value.IsValid() && !value.IsNil() { + tmp = append(tmp, structToMap(value)) + } + } else if value.Type().Kind().String() == "struct" { + tmp = append(tmp, structToMap(value)) + } else if value.Type().Kind().String() == "ptr" { + if value.IsValid() && !value.IsNil() { + tmp = append(tmp, value.Elem().Interface()) + } + } else { + tmp = append(tmp, value.Interface()) + } + } + if len(tmp) > 0 { + out[name] = tmp + } + } else { + out[name] = fieldValue.Interface() + } + + } + return out +} + +func Retryable(err error) *bool { + if err == nil { + return Bool(false) + } + if realErr, ok := err.(*SDKError); ok { + if realErr.StatusCode == nil { + return Bool(false) + } + code := IntValue(realErr.StatusCode) + return Bool(code >= http.StatusInternalServerError) + } + return Bool(true) +} + +func GetBackoffTime(backoff interface{}, retrytimes *int) *int { + backoffMap, ok := backoff.(map[string]interface{}) + if !ok { + return Int(0) + } + policy, ok := backoffMap["policy"].(string) + if !ok || policy == "no" { + return Int(0) + } + + period, ok := backoffMap["period"].(int) + if !ok || period == 0 { + return Int(0) + } + + maxTime := math.Pow(2.0, float64(IntValue(retrytimes))) + return Int(rand.Intn(int(maxTime-1)) * period) +} + +func Sleep(backoffTime *int) { + sleeptime := time.Duration(IntValue(backoffTime)) * time.Second + time.Sleep(sleeptime) +} + +func Validate(params interface{}) error { + if params == nil { + return nil + } + requestValue := reflect.ValueOf(params) + if requestValue.IsNil() { + return nil + } + err := validate(requestValue.Elem()) + return err +} + +// Verify whether the parameters meet the requirements +func validate(dataValue reflect.Value) error { + if strings.HasPrefix(dataValue.Type().String(), "*") { // Determines whether the input is a structure object or a pointer object + if dataValue.IsNil() { + return nil + } + dataValue = dataValue.Elem() + } + dataType := dataValue.Type() + for i := 0; i < dataType.NumField(); i++ { + field := dataType.Field(i) + valueField := dataValue.Field(i) + for _, value := range validateParams { + err := validateParam(field, valueField, value) + if err != nil { + return err + } + } + } + return nil +} + +func validateParam(field reflect.StructField, valueField reflect.Value, tagName string) error { + tag, containsTag := field.Tag.Lookup(tagName) // Take out the checked regular expression + if containsTag && tagName == "require" { + err := checkRequire(field, valueField) + if err != nil { + return err + } + } + if strings.HasPrefix(field.Type.String(), "[]") { // Verify the parameters of the array type + err := validateSlice(field, valueField, containsTag, tag, tagName) + if err != nil { + return err + } + } else if valueField.Kind() == reflect.Ptr { // Determines whether it is a pointer object + err := validatePtr(field, valueField, containsTag, tag, tagName) + if err != nil { + return err + } + } + return nil +} + +func validateSlice(field reflect.StructField, valueField reflect.Value, containsregexpTag bool, tag, tagName string) error { + if valueField.IsValid() && !valueField.IsNil() { // Determines whether the parameter has a value + if containsregexpTag { + if tagName == "maxItems" { + err := checkMaxItems(field, valueField, tag) + if err != nil { + return err + } + } + + if tagName == "minItems" { + err := checkMinItems(field, valueField, tag) + if err != nil { + return err + } + } + } + + for m := 0; m < valueField.Len(); m++ { + elementValue := valueField.Index(m) + if elementValue.Type().Kind() == reflect.Ptr { // Determines whether the child elements of an array are of a basic type + err := validatePtr(field, elementValue, containsregexpTag, tag, tagName) + if err != nil { + return err + } + } + } + } + return nil +} + +func validatePtr(field reflect.StructField, elementValue reflect.Value, containsregexpTag bool, tag, tagName string) error { + if elementValue.IsNil() { + return nil + } + if isFilterType(elementValue.Elem().Type().String(), basicTypes) { + if containsregexpTag { + if tagName == "pattern" { + err := checkPattern(field, elementValue.Elem(), tag) + if err != nil { + return err + } + } + + if tagName == "maxLength" { + err := checkMaxLength(field, elementValue.Elem(), tag) + if err != nil { + return err + } + } + + if tagName == "minLength" { + err := checkMinLength(field, elementValue.Elem(), tag) + if err != nil { + return err + } + } + + if tagName == "maximum" { + err := checkMaximum(field, elementValue.Elem(), tag) + if err != nil { + return err + } + } + + if tagName == "minimum" { + err := checkMinimum(field, elementValue.Elem(), tag) + if err != nil { + return err + } + } + } + } else { + err := validate(elementValue) + if err != nil { + return err + } + } + return nil +} + +func checkRequire(field reflect.StructField, valueField reflect.Value) error { + name, _ := field.Tag.Lookup("json") + strs := strings.Split(name, ",") + name = strs[0] + if !valueField.IsNil() && valueField.IsValid() { + return nil + } + return errors.New(name + " should be setted") +} + +func checkPattern(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + value := valueField.String() + r, _ := regexp.Compile("^" + tag + "$") + if match := r.MatchString(value); !match { // Determines whether the parameter value satisfies the regular expression or not, and throws an error + return errors.New(value + " is not matched " + tag) + } + } + return nil +} + +func checkMaxItems(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + maxItems, err := strconv.Atoi(tag) + if err != nil { + return err + } + length := valueField.Len() + if maxItems < length { + errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxItems) + return errors.New(errMsg) + } + } + return nil +} + +func checkMinItems(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() { + minItems, err := strconv.Atoi(tag) + if err != nil { + return err + } + length := valueField.Len() + if minItems > length { + errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minItems) + return errors.New(errMsg) + } + } + return nil +} + +func checkMaxLength(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + maxLength, err := strconv.Atoi(tag) + if err != nil { + return err + } + length := valueField.Len() + if valueField.Kind().String() == "string" { + length = strings.Count(valueField.String(), "") - 1 + } + if maxLength < length { + errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxLength) + return errors.New(errMsg) + } + } + return nil +} + +func checkMinLength(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() { + minLength, err := strconv.Atoi(tag) + if err != nil { + return err + } + length := valueField.Len() + if valueField.Kind().String() == "string" { + length = strings.Count(valueField.String(), "") - 1 + } + if minLength > length { + errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minLength) + return errors.New(errMsg) + } + } + return nil +} + +func checkMaximum(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + maximum, err := strconv.ParseFloat(tag, 64) + if err != nil { + return err + } + byt, _ := json.Marshal(valueField.Interface()) + num, err := strconv.ParseFloat(string(byt), 64) + if err != nil { + return err + } + if maximum < num { + errMsg := fmt.Sprintf("The size of %s is %f which is greater than %f", field.Name, num, maximum) + return errors.New(errMsg) + } + } + return nil +} + +func checkMinimum(field reflect.StructField, valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + minimum, err := strconv.ParseFloat(tag, 64) + if err != nil { + return err + } + + byt, _ := json.Marshal(valueField.Interface()) + num, err := strconv.ParseFloat(string(byt), 64) + if err != nil { + return err + } + if minimum > num { + errMsg := fmt.Sprintf("The size of %s is %f which is less than %f", field.Name, num, minimum) + return errors.New(errMsg) + } + } + return nil +} + +// Determines whether realType is in filterTypes +func isFilterType(realType string, filterTypes []string) bool { + for _, value := range filterTypes { + if value == realType { + return true + } + } + return false +} + +func TransInterfaceToBool(val interface{}) *bool { + if val == nil { + return nil + } + + return Bool(val.(bool)) +} + +func TransInterfaceToInt(val interface{}) *int { + if val == nil { + return nil + } + + return Int(val.(int)) +} + +func TransInterfaceToString(val interface{}) *string { + if val == nil { + return nil + } + + return String(val.(string)) +} + +func Prettify(i interface{}) string { + resp, _ := json.MarshalIndent(i, "", " ") + return string(resp) +} + +func ToInt(a *int32) *int { + return Int(int(Int32Value(a))) +} + +func ToInt32(a *int) *int32 { + return Int32(int32(IntValue(a))) +} diff --git a/vendor/github.com/alibabacloud-go/tea/tea/trans.go b/vendor/github.com/alibabacloud-go/tea/tea/trans.go new file mode 100644 index 000000000..ded1642fa --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/tea/trans.go @@ -0,0 +1,491 @@ +package tea + +func String(a string) *string { + return &a +} + +func StringValue(a *string) string { + if a == nil { + return "" + } + return *a +} + +func Int(a int) *int { + return &a +} + +func IntValue(a *int) int { + if a == nil { + return 0 + } + return *a +} + +func Int8(a int8) *int8 { + return &a +} + +func Int8Value(a *int8) int8 { + if a == nil { + return 0 + } + return *a +} + +func Int16(a int16) *int16 { + return &a +} + +func Int16Value(a *int16) int16 { + if a == nil { + return 0 + } + return *a +} + +func Int32(a int32) *int32 { + return &a +} + +func Int32Value(a *int32) int32 { + if a == nil { + return 0 + } + return *a +} + +func Int64(a int64) *int64 { + return &a +} + +func Int64Value(a *int64) int64 { + if a == nil { + return 0 + } + return *a +} + +func Bool(a bool) *bool { + return &a +} + +func BoolValue(a *bool) bool { + if a == nil { + return false + } + return *a +} + +func Uint(a uint) *uint { + return &a +} + +func UintValue(a *uint) uint { + if a == nil { + return 0 + } + return *a +} + +func Uint8(a uint8) *uint8 { + return &a +} + +func Uint8Value(a *uint8) uint8 { + if a == nil { + return 0 + } + return *a +} + +func Uint16(a uint16) *uint16 { + return &a +} + +func Uint16Value(a *uint16) uint16 { + if a == nil { + return 0 + } + return *a +} + +func Uint32(a uint32) *uint32 { + return &a +} + +func Uint32Value(a *uint32) uint32 { + if a == nil { + return 0 + } + return *a +} + +func Uint64(a uint64) *uint64 { + return &a +} + +func Uint64Value(a *uint64) uint64 { + if a == nil { + return 0 + } + return *a +} + +func Float32(a float32) *float32 { + return &a +} + +func Float32Value(a *float32) float32 { + if a == nil { + return 0 + } + return *a +} + +func Float64(a float64) *float64 { + return &a +} + +func Float64Value(a *float64) float64 { + if a == nil { + return 0 + } + return *a +} + +func IntSlice(a []int) []*int { + if a == nil { + return nil + } + res := make([]*int, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func IntValueSlice(a []*int) []int { + if a == nil { + return nil + } + res := make([]int, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Int8Slice(a []int8) []*int8 { + if a == nil { + return nil + } + res := make([]*int8, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Int8ValueSlice(a []*int8) []int8 { + if a == nil { + return nil + } + res := make([]int8, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Int16Slice(a []int16) []*int16 { + if a == nil { + return nil + } + res := make([]*int16, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Int16ValueSlice(a []*int16) []int16 { + if a == nil { + return nil + } + res := make([]int16, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Int32Slice(a []int32) []*int32 { + if a == nil { + return nil + } + res := make([]*int32, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Int32ValueSlice(a []*int32) []int32 { + if a == nil { + return nil + } + res := make([]int32, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Int64Slice(a []int64) []*int64 { + if a == nil { + return nil + } + res := make([]*int64, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Int64ValueSlice(a []*int64) []int64 { + if a == nil { + return nil + } + res := make([]int64, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func UintSlice(a []uint) []*uint { + if a == nil { + return nil + } + res := make([]*uint, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func UintValueSlice(a []*uint) []uint { + if a == nil { + return nil + } + res := make([]uint, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Uint8Slice(a []uint8) []*uint8 { + if a == nil { + return nil + } + res := make([]*uint8, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Uint8ValueSlice(a []*uint8) []uint8 { + if a == nil { + return nil + } + res := make([]uint8, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Uint16Slice(a []uint16) []*uint16 { + if a == nil { + return nil + } + res := make([]*uint16, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Uint16ValueSlice(a []*uint16) []uint16 { + if a == nil { + return nil + } + res := make([]uint16, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Uint32Slice(a []uint32) []*uint32 { + if a == nil { + return nil + } + res := make([]*uint32, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Uint32ValueSlice(a []*uint32) []uint32 { + if a == nil { + return nil + } + res := make([]uint32, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Uint64Slice(a []uint64) []*uint64 { + if a == nil { + return nil + } + res := make([]*uint64, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Uint64ValueSlice(a []*uint64) []uint64 { + if a == nil { + return nil + } + res := make([]uint64, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Float32Slice(a []float32) []*float32 { + if a == nil { + return nil + } + res := make([]*float32, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Float32ValueSlice(a []*float32) []float32 { + if a == nil { + return nil + } + res := make([]float32, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func Float64Slice(a []float64) []*float64 { + if a == nil { + return nil + } + res := make([]*float64, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func Float64ValueSlice(a []*float64) []float64 { + if a == nil { + return nil + } + res := make([]float64, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func StringSlice(a []string) []*string { + if a == nil { + return nil + } + res := make([]*string, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func StringSliceValue(a []*string) []string { + if a == nil { + return nil + } + res := make([]string, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} + +func BoolSlice(a []bool) []*bool { + if a == nil { + return nil + } + res := make([]*bool, len(a)) + for i := 0; i < len(a); i++ { + res[i] = &a[i] + } + return res +} + +func BoolSliceValue(a []*bool) []bool { + if a == nil { + return nil + } + res := make([]bool, len(a)) + for i := 0; i < len(a); i++ { + if a[i] != nil { + res[i] = *a[i] + } + } + return res +} diff --git a/vendor/github.com/alibabacloud-go/tea/utils/assert.go b/vendor/github.com/alibabacloud-go/tea/utils/assert.go new file mode 100644 index 000000000..7ae677501 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/utils/assert.go @@ -0,0 +1,64 @@ +package utils + +import ( + "reflect" + "strings" + "testing" +) + +func isNil(object interface{}) bool { + if object == nil { + return true + } + + value := reflect.ValueOf(object) + kind := value.Kind() + isNilableKind := containsKind( + []reflect.Kind{ + reflect.Chan, reflect.Func, + reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice}, + kind) + + if isNilableKind && value.IsNil() { + return true + } + + return false +} + +func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { + for i := 0; i < len(kinds); i++ { + if kind == kinds[i] { + return true + } + } + + return false +} + +func AssertEqual(t *testing.T, a, b interface{}) { + if !reflect.DeepEqual(a, b) { + t.Errorf("%v != %v", a, b) + } +} + +func AssertNil(t *testing.T, object interface{}) { + if !isNil(object) { + t.Errorf("%v is not nil", object) + } +} + +func AssertNotNil(t *testing.T, object interface{}) { + if isNil(object) { + t.Errorf("%v is nil", object) + } +} + +func AssertContains(t *testing.T, contains string, msgAndArgs ...string) { + for _, value := range msgAndArgs { + if ok := strings.Contains(contains, value); !ok { + t.Errorf("%s does not contain %s", contains, value) + } + } +} diff --git a/vendor/github.com/alibabacloud-go/tea/utils/logger.go b/vendor/github.com/alibabacloud-go/tea/utils/logger.go new file mode 100644 index 000000000..051366887 --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/utils/logger.go @@ -0,0 +1,109 @@ +package utils + +import ( + "io" + "log" + "strings" + "time" +) + +type Logger struct { + *log.Logger + formatTemplate string + isOpen bool + lastLogMsg string +} + +var defaultLoggerTemplate = `{time} {channel}: "{method} {uri} HTTP/{version}" {code} {cost} {hostname}` +var loggerParam = []string{"{time}", "{start_time}", "{ts}", "{channel}", "{pid}", "{host}", "{method}", "{uri}", "{version}", "{target}", "{hostname}", "{code}", "{error}", "{req_headers}", "{res_body}", "{res_headers}", "{cost}"} +var logChannel string + +func InitLogMsg(fieldMap map[string]string) { + for _, value := range loggerParam { + fieldMap[value] = "" + } +} + +func (logger *Logger) SetFormatTemplate(template string) { + logger.formatTemplate = template + +} + +func (logger *Logger) GetFormatTemplate() string { + return logger.formatTemplate + +} + +func NewLogger(level string, channel string, out io.Writer, template string) *Logger { + if level == "" { + level = "info" + } + + logChannel = "AlibabaCloud" + if channel != "" { + logChannel = channel + } + log := log.New(out, "["+strings.ToUpper(level)+"]", log.Lshortfile) + if template == "" { + template = defaultLoggerTemplate + } + + return &Logger{ + Logger: log, + formatTemplate: template, + isOpen: true, + } +} + +func (logger *Logger) OpenLogger() { + logger.isOpen = true +} + +func (logger *Logger) CloseLogger() { + logger.isOpen = false +} + +func (logger *Logger) SetIsopen(isopen bool) { + logger.isOpen = isopen +} + +func (logger *Logger) GetIsopen() bool { + return logger.isOpen +} + +func (logger *Logger) SetLastLogMsg(lastLogMsg string) { + logger.lastLogMsg = lastLogMsg +} + +func (logger *Logger) GetLastLogMsg() string { + return logger.lastLogMsg +} + +func SetLogChannel(channel string) { + logChannel = channel +} + +func (logger *Logger) PrintLog(fieldMap map[string]string, err error) { + if err != nil { + fieldMap["{error}"] = err.Error() + } + fieldMap["{time}"] = time.Now().Format("2006-01-02 15:04:05") + fieldMap["{ts}"] = getTimeInFormatISO8601() + fieldMap["{channel}"] = logChannel + if logger != nil { + logMsg := logger.formatTemplate + for key, value := range fieldMap { + logMsg = strings.Replace(logMsg, key, value, -1) + } + logger.lastLogMsg = logMsg + if logger.isOpen == true { + logger.Output(2, logMsg) + } + } +} + +func getTimeInFormatISO8601() (timeStr string) { + gmt := time.FixedZone("GMT", 0) + + return time.Now().In(gmt).Format("2006-01-02T15:04:05Z") +} diff --git a/vendor/github.com/alibabacloud-go/tea/utils/progress.go b/vendor/github.com/alibabacloud-go/tea/utils/progress.go new file mode 100644 index 000000000..2f5364aea --- /dev/null +++ b/vendor/github.com/alibabacloud-go/tea/utils/progress.go @@ -0,0 +1,60 @@ +package utils + +// ProgressEventType defines transfer progress event type +type ProgressEventType int + +const ( + // TransferStartedEvent transfer started, set TotalBytes + TransferStartedEvent ProgressEventType = 1 + iota + // TransferDataEvent transfer data, set ConsumedBytes anmd TotalBytes + TransferDataEvent + // TransferCompletedEvent transfer completed + TransferCompletedEvent + // TransferFailedEvent transfer encounters an error + TransferFailedEvent +) + +// ProgressEvent defines progress event +type ProgressEvent struct { + ConsumedBytes int64 + TotalBytes int64 + RwBytes int64 + EventType ProgressEventType +} + +// ProgressListener listens progress change +type ProgressListener interface { + ProgressChanged(event *ProgressEvent) +} + +// -------------------- Private -------------------- + +func NewProgressEvent(eventType ProgressEventType, consumed, total int64, rwBytes int64) *ProgressEvent { + return &ProgressEvent{ + ConsumedBytes: consumed, + TotalBytes: total, + RwBytes: rwBytes, + EventType: eventType} +} + +// publishProgress +func PublishProgress(listener ProgressListener, event *ProgressEvent) { + if listener != nil && event != nil { + listener.ProgressChanged(event) + } +} + +func GetProgressListener(obj interface{}) ProgressListener { + if obj == nil { + return nil + } + listener, ok := obj.(ProgressListener) + if !ok { + return nil + } + return listener +} + +type ReaderTracker struct { + CompletedBytes int64 +} diff --git a/vendor/github.com/aliyun/credentials-go/LICENSE b/vendor/github.com/aliyun/credentials-go/LICENSE new file mode 100644 index 000000000..0c44dcefe --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/aliyun/credentials-go/credentials/access_key_credential.go b/vendor/github.com/aliyun/credentials-go/credentials/access_key_credential.go new file mode 100644 index 000000000..7bcaa9740 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/access_key_credential.go @@ -0,0 +1,41 @@ +package credentials + +import "github.com/alibabacloud-go/tea/tea" + +// AccessKeyCredential is a kind of credential +type AccessKeyCredential struct { + AccessKeyId string + AccessKeySecret string +} + +func newAccessKeyCredential(accessKeyId, accessKeySecret string) *AccessKeyCredential { + return &AccessKeyCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + } +} + +// GetAccessKeyId reutrns AccessKeyCreential's AccessKeyId +func (a *AccessKeyCredential) GetAccessKeyId() (*string, error) { + return tea.String(a.AccessKeyId), nil +} + +// GetAccessSecret reutrns AccessKeyCreential's AccessKeySecret +func (a *AccessKeyCredential) GetAccessKeySecret() (*string, error) { + return tea.String(a.AccessKeySecret), nil +} + +// GetSecurityToken is useless for AccessKeyCreential +func (a *AccessKeyCredential) GetSecurityToken() (*string, error) { + return tea.String(""), nil +} + +// GetBearerToken is useless for AccessKeyCreential +func (a *AccessKeyCredential) GetBearerToken() *string { + return tea.String("") +} + +// GetType reutrns AccessKeyCreential's type +func (a *AccessKeyCredential) GetType() *string { + return tea.String("access_key") +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/bearer_token_credential.go b/vendor/github.com/aliyun/credentials-go/credentials/bearer_token_credential.go new file mode 100644 index 000000000..cca291621 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/bearer_token_credential.go @@ -0,0 +1,40 @@ +package credentials + +import "github.com/alibabacloud-go/tea/tea" + +// BearerTokenCredential is a kind of credential +type BearerTokenCredential struct { + BearerToken string +} + +// newBearerTokenCredential return a BearerTokenCredential object +func newBearerTokenCredential(token string) *BearerTokenCredential { + return &BearerTokenCredential{ + BearerToken: token, + } +} + +// GetAccessKeyId is useless for BearerTokenCredential +func (b *BearerTokenCredential) GetAccessKeyId() (*string, error) { + return tea.String(""), nil +} + +// GetAccessSecret is useless for BearerTokenCredential +func (b *BearerTokenCredential) GetAccessKeySecret() (*string, error) { + return tea.String(("")), nil +} + +// GetSecurityToken is useless for BearerTokenCredential +func (b *BearerTokenCredential) GetSecurityToken() (*string, error) { + return tea.String(""), nil +} + +// GetBearerToken reutrns BearerTokenCredential's BearerToken +func (b *BearerTokenCredential) GetBearerToken() *string { + return tea.String(b.BearerToken) +} + +// GetType reutrns BearerTokenCredential's type +func (b *BearerTokenCredential) GetType() *string { + return tea.String("bearer") +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/credential.go b/vendor/github.com/aliyun/credentials-go/credentials/credential.go new file mode 100644 index 000000000..92212e132 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/credential.go @@ -0,0 +1,349 @@ +package credentials + +import ( + "bufio" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "strings" + "time" + + "github.com/alibabacloud-go/debug/debug" + "github.com/alibabacloud-go/tea/tea" + "github.com/aliyun/credentials-go/credentials/request" + "github.com/aliyun/credentials-go/credentials/response" + "github.com/aliyun/credentials-go/credentials/utils" +) + +var debuglog = debug.Init("credential") + +var hookParse = func(err error) error { + return err +} + +// Credential is an interface for getting actual credential +type Credential interface { + GetAccessKeyId() (*string, error) + GetAccessKeySecret() (*string, error) + GetSecurityToken() (*string, error) + GetBearerToken() *string + GetType() *string +} + +// Config is important when call NewCredential +type Config struct { + Type *string `json:"type"` + AccessKeyId *string `json:"access_key_id"` + AccessKeySecret *string `json:"access_key_secret"` + RoleArn *string `json:"role_arn"` + RoleSessionName *string `json:"role_session_name"` + PublicKeyId *string `json:"public_key_id"` + RoleName *string `json:"role_name"` + SessionExpiration *int `json:"session_expiration"` + PrivateKeyFile *string `json:"private_key_file"` + BearerToken *string `json:"bearer_token"` + SecurityToken *string `json:"security_token"` + RoleSessionExpiration *int `json:"role_session_expiratioon"` + Policy *string `json:"policy"` + Host *string `json:"host"` + Timeout *int `json:"timeout"` + ConnectTimeout *int `json:"connect_timeout"` + Proxy *string `json:"proxy"` +} + +func (s Config) String() string { + return tea.Prettify(s) +} + +func (s Config) GoString() string { + return s.String() +} + +func (s *Config) SetAccessKeyId(v string) *Config { + s.AccessKeyId = &v + return s +} + +func (s *Config) SetAccessKeySecret(v string) *Config { + s.AccessKeySecret = &v + return s +} + +func (s *Config) SetSecurityToken(v string) *Config { + s.SecurityToken = &v + return s +} + +func (s *Config) SetRoleArn(v string) *Config { + s.RoleArn = &v + return s +} + +func (s *Config) SetRoleSessionName(v string) *Config { + s.RoleSessionName = &v + return s +} + +func (s *Config) SetPublicKeyId(v string) *Config { + s.PublicKeyId = &v + return s +} + +func (s *Config) SetRoleName(v string) *Config { + s.RoleName = &v + return s +} + +func (s *Config) SetSessionExpiration(v int) *Config { + s.SessionExpiration = &v + return s +} + +func (s *Config) SetPrivateKeyFile(v string) *Config { + s.PrivateKeyFile = &v + return s +} + +func (s *Config) SetBearerToken(v string) *Config { + s.BearerToken = &v + return s +} + +func (s *Config) SetRoleSessionExpiration(v int) *Config { + s.RoleSessionExpiration = &v + return s +} + +func (s *Config) SetPolicy(v string) *Config { + s.Policy = &v + return s +} + +func (s *Config) SetHost(v string) *Config { + s.Host = &v + return s +} + +func (s *Config) SetTimeout(v int) *Config { + s.Timeout = &v + return s +} + +func (s *Config) SetConnectTimeout(v int) *Config { + s.ConnectTimeout = &v + return s +} + +func (s *Config) SetProxy(v string) *Config { + s.Proxy = &v + return s +} + +func (s *Config) SetType(v string) *Config { + s.Type = &v + return s +} + +// NewCredential return a credential according to the type in config. +// if config is nil, the function will use default provider chain to get credential. +// please see README.md for detail. +func NewCredential(config *Config) (credential Credential, err error) { + if config == nil { + config, err = defaultChain.resolve() + if err != nil { + return + } + return NewCredential(config) + } + switch tea.StringValue(config.Type) { + case "access_key": + err = checkAccessKey(config) + if err != nil { + return + } + credential = newAccessKeyCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret)) + case "sts": + err = checkSTS(config) + if err != nil { + return + } + credential = newStsTokenCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.SecurityToken)) + case "ecs_ram_role": + checkEcsRAMRole(config) + runtime := &utils.Runtime{ + Host: tea.StringValue(config.Host), + Proxy: tea.StringValue(config.Proxy), + ReadTimeout: tea.IntValue(config.Timeout), + ConnectTimeout: tea.IntValue(config.ConnectTimeout), + } + credential = newEcsRAMRoleCredential(tea.StringValue(config.RoleName), runtime) + case "ram_role_arn": + err = checkRAMRoleArn(config) + if err != nil { + return + } + runtime := &utils.Runtime{ + Host: tea.StringValue(config.Host), + Proxy: tea.StringValue(config.Proxy), + ReadTimeout: tea.IntValue(config.Timeout), + ConnectTimeout: tea.IntValue(config.ConnectTimeout), + } + credential = newRAMRoleArnCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.RoleArn), tea.StringValue(config.RoleSessionName), tea.StringValue(config.Policy), tea.IntValue(config.RoleSessionExpiration), runtime) + case "rsa_key_pair": + err = checkRSAKeyPair(config) + if err != nil { + return + } + file, err1 := os.Open(tea.StringValue(config.PrivateKeyFile)) + if err1 != nil { + err = fmt.Errorf("InvalidPath: Can not open PrivateKeyFile, err is %s", err1.Error()) + return + } + defer file.Close() + var privateKey string + scan := bufio.NewScanner(file) + for scan.Scan() { + if strings.HasPrefix(scan.Text(), "----") { + continue + } + privateKey += scan.Text() + "\n" + } + runtime := &utils.Runtime{ + Host: tea.StringValue(config.Host), + Proxy: tea.StringValue(config.Proxy), + ReadTimeout: tea.IntValue(config.Timeout), + ConnectTimeout: tea.IntValue(config.ConnectTimeout), + } + credential = newRsaKeyPairCredential(privateKey, tea.StringValue(config.PublicKeyId), tea.IntValue(config.SessionExpiration), runtime) + case "bearer": + if tea.StringValue(config.BearerToken) == "" { + err = errors.New("BearerToken cannot be empty") + return + } + credential = newBearerTokenCredential(tea.StringValue(config.BearerToken)) + default: + err = errors.New("Invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair") + return + } + return credential, nil +} + +func checkRSAKeyPair(config *Config) (err error) { + if tea.StringValue(config.PrivateKeyFile) == "" { + err = errors.New("PrivateKeyFile cannot be empty") + return + } + if tea.StringValue(config.PublicKeyId) == "" { + err = errors.New("PublicKeyId cannot be empty") + return + } + return +} + +func checkRAMRoleArn(config *Config) (err error) { + if tea.StringValue(config.AccessKeySecret) == "" { + err = errors.New("AccessKeySecret cannot be empty") + return + } + if tea.StringValue(config.RoleArn) == "" { + err = errors.New("RoleArn cannot be empty") + return + } + if tea.StringValue(config.RoleSessionName) == "" { + err = errors.New("RoleSessionName cannot be empty") + return + } + if tea.StringValue(config.AccessKeyId) == "" { + err = errors.New("AccessKeyId cannot be empty") + return + } + return +} + +func checkEcsRAMRole(config *Config) (err error) { + return +} + +func checkSTS(config *Config) (err error) { + if tea.StringValue(config.AccessKeyId) == "" { + err = errors.New("AccessKeyId cannot be empty") + return + } + if tea.StringValue(config.AccessKeySecret) == "" { + err = errors.New("AccessKeySecret cannot be empty") + return + } + if tea.StringValue(config.SecurityToken) == "" { + err = errors.New("SecurityToken cannot be empty") + return + } + return +} + +func checkAccessKey(config *Config) (err error) { + if tea.StringValue(config.AccessKeyId) == "" { + err = errors.New("AccessKeyId cannot be empty") + return + } + if tea.StringValue(config.AccessKeySecret) == "" { + err = errors.New("AccessKeySecret cannot be empty") + return + } + return +} + +func doAction(request *request.CommonRequest, runtime *utils.Runtime) (content []byte, err error) { + httpRequest, err := http.NewRequest(request.Method, request.URL, strings.NewReader("")) + if err != nil { + return + } + httpRequest.Proto = "HTTP/1.1" + httpRequest.Host = request.Domain + debuglog("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto) + debuglog("> Host: %s", httpRequest.Host) + for key, value := range request.Headers { + if value != "" { + debuglog("> %s: %s", key, value) + httpRequest.Header[key] = []string{value} + } + } + debuglog(">") + httpClient := &http.Client{} + httpClient.Timeout = time.Duration(runtime.ReadTimeout) * time.Second + proxy := &url.URL{} + if runtime.Proxy != "" { + proxy, err = url.Parse(runtime.Proxy) + if err != nil { + return + } + } + trans := &http.Transport{} + if proxy != nil && runtime.Proxy != "" { + trans.Proxy = http.ProxyURL(proxy) + } + trans.DialContext = utils.Timeout(time.Duration(runtime.ConnectTimeout) * time.Second) + httpClient.Transport = trans + httpResponse, err := hookDo(httpClient.Do)(httpRequest) + if err != nil { + return + } + debuglog("< %s %s", httpResponse.Proto, httpResponse.Status) + for key, value := range httpResponse.Header { + debuglog("< %s: %v", key, strings.Join(value, "")) + } + debuglog("<") + + resp := &response.CommonResponse{} + err = hookParse(resp.ParseFromHTTPResponse(httpResponse)) + if err != nil { + return + } + debuglog("%s", resp.GetHTTPContentString()) + if resp.GetHTTPStatus() != http.StatusOK { + err = fmt.Errorf("httpStatus: %d, message = %s", resp.GetHTTPStatus(), resp.GetHTTPContentString()) + return + } + return resp.GetHTTPContentBytes(), nil +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/credential_updater.go b/vendor/github.com/aliyun/credentials-go/credentials/credential_updater.go new file mode 100644 index 000000000..8d4433b7e --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/credential_updater.go @@ -0,0 +1,25 @@ +package credentials + +import ( + "net/http" + "time" +) + +const defaultInAdvanceScale = 0.95 + +var hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) { + return fn +} + +type credentialUpdater struct { + credentialExpiration int + lastUpdateTimestamp int64 + inAdvanceScale float64 +} + +func (updater *credentialUpdater) needUpdateCredential() (result bool) { + if updater.inAdvanceScale == 0 { + updater.inAdvanceScale = defaultInAdvanceScale + } + return time.Now().Unix()-updater.lastUpdateTimestamp >= int64(float64(updater.credentialExpiration)*updater.inAdvanceScale) +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/ecs_ram_role.go b/vendor/github.com/aliyun/credentials-go/credentials/ecs_ram_role.go new file mode 100644 index 000000000..53abfe9da --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/ecs_ram_role.go @@ -0,0 +1,136 @@ +package credentials + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/alibabacloud-go/tea/tea" + "github.com/aliyun/credentials-go/credentials/request" + "github.com/aliyun/credentials-go/credentials/utils" +) + +var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/" + +// EcsRAMRoleCredential is a kind of credential +type EcsRAMRoleCredential struct { + *credentialUpdater + RoleName string + sessionCredential *sessionCredential + runtime *utils.Runtime +} + +type ecsRAMRoleResponse struct { + Code string `json:"Code" xml:"Code"` + AccessKeyId string `json:"AccessKeyId" xml:"AccessKeyId"` + AccessKeySecret string `json:"AccessKeySecret" xml:"AccessKeySecret"` + SecurityToken string `json:"SecurityToken" xml:"SecurityToken"` + Expiration string `json:"Expiration" xml:"Expiration"` +} + +func newEcsRAMRoleCredential(roleName string, runtime *utils.Runtime) *EcsRAMRoleCredential { + return &EcsRAMRoleCredential{ + RoleName: roleName, + credentialUpdater: new(credentialUpdater), + runtime: runtime, + } +} + +// GetAccessKeyId reutrns EcsRAMRoleCredential's AccessKeyId +// if AccessKeyId is not exist or out of date, the function will update it. +func (e *EcsRAMRoleCredential) GetAccessKeyId() (*string, error) { + if e.sessionCredential == nil || e.needUpdateCredential() { + err := e.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(e.sessionCredential.AccessKeyId), nil +} + +// GetAccessSecret reutrns EcsRAMRoleCredential's AccessKeySecret +// if AccessKeySecret is not exist or out of date, the function will update it. +func (e *EcsRAMRoleCredential) GetAccessKeySecret() (*string, error) { + if e.sessionCredential == nil || e.needUpdateCredential() { + err := e.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(e.sessionCredential.AccessKeySecret), nil +} + +// GetSecurityToken reutrns EcsRAMRoleCredential's SecurityToken +// if SecurityToken is not exist or out of date, the function will update it. +func (e *EcsRAMRoleCredential) GetSecurityToken() (*string, error) { + if e.sessionCredential == nil || e.needUpdateCredential() { + err := e.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(e.sessionCredential.SecurityToken), nil +} + +// GetBearerToken is useless for EcsRAMRoleCredential +func (e *EcsRAMRoleCredential) GetBearerToken() *string { + return tea.String("") +} + +// GetType reutrns EcsRAMRoleCredential's type +func (e *EcsRAMRoleCredential) GetType() *string { + return tea.String("ecs_ram_role") +} + +func getRoleName() (string, error) { + runtime := utils.NewRuntime(1, 1, "", "") + request := request.NewCommonRequest() + request.URL = securityCredURL + request.Method = "GET" + content, err := doAction(request, runtime) + if err != nil { + return "", err + } + return string(content), nil +} + +func (e *EcsRAMRoleCredential) updateCredential() (err error) { + if e.runtime == nil { + e.runtime = new(utils.Runtime) + } + request := request.NewCommonRequest() + if e.RoleName == "" { + e.RoleName, err = getRoleName() + if err != nil { + return fmt.Errorf("refresh Ecs sts token err: %s", err.Error()) + } + } + request.URL = securityCredURL + e.RoleName + request.Method = "GET" + content, err := doAction(request, e.runtime) + if err != nil { + return fmt.Errorf("refresh Ecs sts token err: %s", err.Error()) + } + var resp *ecsRAMRoleResponse + err = json.Unmarshal(content, &resp) + if err != nil { + return fmt.Errorf("refresh Ecs sts token err: Json Unmarshal fail: %s", err.Error()) + } + if resp.Code != "Success" { + return fmt.Errorf("refresh Ecs sts token err: Code is not Success") + } + if resp.AccessKeyId == "" || resp.AccessKeySecret == "" || resp.SecurityToken == "" || resp.Expiration == "" { + return fmt.Errorf("refresh Ecs sts token err: AccessKeyId: %s, AccessKeySecret: %s, SecurityToken: %s, Expiration: %s", resp.AccessKeyId, resp.AccessKeySecret, resp.SecurityToken, resp.Expiration) + } + + expirationTime, err := time.Parse("2006-01-02T15:04:05Z", resp.Expiration) + e.lastUpdateTimestamp = time.Now().Unix() + e.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix()) + e.sessionCredential = &sessionCredential{ + AccessKeyId: resp.AccessKeyId, + AccessKeySecret: resp.AccessKeySecret, + SecurityToken: resp.SecurityToken, + } + + return +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/env_provider.go b/vendor/github.com/aliyun/credentials-go/credentials/env_provider.go new file mode 100644 index 000000000..f3807bd2a --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/env_provider.go @@ -0,0 +1,43 @@ +package credentials + +import ( + "errors" + "os" + + "github.com/alibabacloud-go/tea/tea" +) + +type envProvider struct{} + +var providerEnv = new(envProvider) + +const ( + // EnvVarAccessKeyId is a name of ALIBABA_CLOUD_ACCESS_KEY_Id + EnvVarAccessKeyId = "ALIBABA_CLOUD_ACCESS_KEY_Id" + // EnvVarAccessKeySecret is a name of ALIBABA_CLOUD_ACCESS_KEY_SECRET + EnvVarAccessKeySecret = "ALIBABA_CLOUD_ACCESS_KEY_SECRET" +) + +func newEnvProvider() Provider { + return &envProvider{} +} + +func (p *envProvider) resolve() (*Config, error) { + accessKeyId, ok1 := os.LookupEnv(EnvVarAccessKeyId) + accessKeySecret, ok2 := os.LookupEnv(EnvVarAccessKeySecret) + if !ok1 || !ok2 { + return nil, nil + } + if accessKeyId == "" { + return nil, errors.New(EnvVarAccessKeyId + " cannot be empty") + } + if accessKeySecret == "" { + return nil, errors.New(EnvVarAccessKeySecret + " cannot be empty") + } + config := &Config{ + Type: tea.String("access_key"), + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + } + return config, nil +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/instance_provider.go b/vendor/github.com/aliyun/credentials-go/credentials/instance_provider.go new file mode 100644 index 000000000..7e2ea07bb --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/instance_provider.go @@ -0,0 +1,28 @@ +package credentials + +import ( + "os" + + "github.com/alibabacloud-go/tea/tea" +) + +type instanceCredentialsProvider struct{} + +var providerInstance = new(instanceCredentialsProvider) + +func newInstanceCredentialsProvider() Provider { + return &instanceCredentialsProvider{} +} + +func (p *instanceCredentialsProvider) resolve() (*Config, error) { + roleName, ok := os.LookupEnv(ENVEcsMetadata) + if !ok { + return nil, nil + } + + config := &Config{ + Type: tea.String("ecs_ram_role"), + RoleName: tea.String(roleName), + } + return config, nil +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/profile_provider.go b/vendor/github.com/aliyun/credentials-go/credentials/profile_provider.go new file mode 100644 index 000000000..d6292b035 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/profile_provider.go @@ -0,0 +1,350 @@ +package credentials + +import ( + "errors" + "fmt" + "os" + "runtime" + "strings" + + "github.com/alibabacloud-go/tea/tea" + ini "gopkg.in/ini.v1" +) + +type profileProvider struct { + Profile string +} + +var providerProfile = newProfileProvider() + +var hookOS = func(goos string) string { + return goos +} + +var hookState = func(info os.FileInfo, err error) (os.FileInfo, error) { + return info, err +} + +// NewProfileProvider receive zero or more parameters, +// when length of name is 0, the value of field Profile will be "default", +// and when there are multiple inputs, the function will take the +// first one and discard the other values. +func newProfileProvider(name ...string) Provider { + p := new(profileProvider) + if len(name) == 0 { + p.Profile = "default" + } else { + p.Profile = name[0] + } + return p +} + +// resolve implements the Provider interface +// when credential type is rsa_key_pair, the content of private_key file +// must be able to be parsed directly into the required string +// that NewRsaKeyPairCredential function needed +func (p *profileProvider) resolve() (*Config, error) { + path, ok := os.LookupEnv(ENVCredentialFile) + if !ok { + path, err := checkDefaultPath() + if err != nil { + return nil, err + } + if path == "" { + return nil, nil + } + } else if path == "" { + return nil, errors.New(ENVCredentialFile + " cannot be empty") + } + + value, section, err := getType(path, p.Profile) + if err != nil { + return nil, err + } + switch value.String() { + case "access_key": + config, err := getAccessKey(section) + if err != nil { + return nil, err + } + return config, nil + case "sts": + config, err := getSTS(section) + if err != nil { + return nil, err + } + return config, nil + case "bearer": + config, err := getBearerToken(section) + if err != nil { + return nil, err + } + return config, nil + case "ecs_ram_role": + config, err := getEcsRAMRole(section) + if err != nil { + return nil, err + } + return config, nil + case "ram_role_arn": + config, err := getRAMRoleArn(section) + if err != nil { + return nil, err + } + return config, nil + case "rsa_key_pair": + config, err := getRSAKeyPair(section) + if err != nil { + return nil, err + } + return config, nil + default: + return nil, errors.New("Invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair") + } +} + +func getRSAKeyPair(section *ini.Section) (*Config, error) { + publicKeyId, err := section.GetKey("public_key_id") + if err != nil { + return nil, errors.New("Missing required public_key_id option in profile for rsa_key_pair") + } + if publicKeyId.String() == "" { + return nil, errors.New("public_key_id cannot be empty") + } + privateKeyFile, err := section.GetKey("private_key_file") + if err != nil { + return nil, errors.New("Missing required private_key_file option in profile for rsa_key_pair") + } + if privateKeyFile.String() == "" { + return nil, errors.New("private_key_file cannot be empty") + } + sessionExpiration, _ := section.GetKey("session_expiration") + expiration := 0 + if sessionExpiration != nil { + expiration, err = sessionExpiration.Int() + if err != nil { + return nil, errors.New("session_expiration must be an int") + } + } + config := &Config{ + Type: tea.String("rsa_key_pair"), + PublicKeyId: tea.String(publicKeyId.String()), + PrivateKeyFile: tea.String(privateKeyFile.String()), + SessionExpiration: tea.Int(expiration), + } + err = setRuntimeToConfig(config, section) + if err != nil { + return nil, err + } + return config, nil +} + +func getRAMRoleArn(section *ini.Section) (*Config, error) { + accessKeyId, err := section.GetKey("access_key_id") + if err != nil { + return nil, errors.New("Missing required access_key_id option in profile for ram_role_arn") + } + if accessKeyId.String() == "" { + return nil, errors.New("access_key_id cannot be empty") + } + accessKeySecret, err := section.GetKey("access_key_secret") + if err != nil { + return nil, errors.New("Missing required access_key_secret option in profile for ram_role_arn") + } + if accessKeySecret.String() == "" { + return nil, errors.New("access_key_secret cannot be empty") + } + roleArn, err := section.GetKey("role_arn") + if err != nil { + return nil, errors.New("Missing required role_arn option in profile for ram_role_arn") + } + if roleArn.String() == "" { + return nil, errors.New("role_arn cannot be empty") + } + roleSessionName, err := section.GetKey("role_session_name") + if err != nil { + return nil, errors.New("Missing required role_session_name option in profile for ram_role_arn") + } + if roleSessionName.String() == "" { + return nil, errors.New("role_session_name cannot be empty") + } + roleSessionExpiration, _ := section.GetKey("role_session_expiration") + expiration := 0 + if roleSessionExpiration != nil { + expiration, err = roleSessionExpiration.Int() + if err != nil { + return nil, errors.New("role_session_expiration must be an int") + } + } + config := &Config{ + Type: tea.String("ram_role_arn"), + AccessKeyId: tea.String(accessKeyId.String()), + AccessKeySecret: tea.String(accessKeySecret.String()), + RoleArn: tea.String(roleArn.String()), + RoleSessionName: tea.String(roleSessionName.String()), + RoleSessionExpiration: tea.Int(expiration), + } + err = setRuntimeToConfig(config, section) + if err != nil { + return nil, err + } + return config, nil +} + +func getEcsRAMRole(section *ini.Section) (*Config, error) { + roleName, _ := section.GetKey("role_name") + config := &Config{ + Type: tea.String("ecs_ram_role"), + } + if roleName != nil { + config.RoleName = tea.String(roleName.String()) + } + err := setRuntimeToConfig(config, section) + if err != nil { + return nil, err + } + return config, nil +} + +func getBearerToken(section *ini.Section) (*Config, error) { + bearerToken, err := section.GetKey("bearer_token") + if err != nil { + return nil, errors.New("Missing required bearer_token option in profile for bearer") + } + if bearerToken.String() == "" { + return nil, errors.New("bearer_token cannot be empty") + } + config := &Config{ + Type: tea.String("bearer"), + BearerToken: tea.String(bearerToken.String()), + } + return config, nil +} + +func getSTS(section *ini.Section) (*Config, error) { + accesskeyid, err := section.GetKey("access_key_id") + if err != nil { + return nil, errors.New("Missing required access_key_id option in profile for sts") + } + if accesskeyid.String() == "" { + return nil, errors.New("access_key_id cannot be empty") + } + accessKeySecret, err := section.GetKey("access_key_secret") + if err != nil { + return nil, errors.New("Missing required access_key_secret option in profile for sts") + } + if accessKeySecret.String() == "" { + return nil, errors.New("access_key_secret cannot be empty") + } + securityToken, err := section.GetKey("security_token") + if err != nil { + return nil, errors.New("Missing required security_token option in profile for sts") + } + if securityToken.String() == "" { + return nil, errors.New("security_token cannot be empty") + } + config := &Config{ + Type: tea.String("sts"), + AccessKeyId: tea.String(accesskeyid.String()), + AccessKeySecret: tea.String(accessKeySecret.String()), + SecurityToken: tea.String(securityToken.String()), + } + return config, nil +} + +func getAccessKey(section *ini.Section) (*Config, error) { + accesskeyid, err := section.GetKey("access_key_id") + if err != nil { + return nil, errors.New("Missing required access_key_id option in profile for access_key") + } + if accesskeyid.String() == "" { + return nil, errors.New("access_key_id cannot be empty") + } + accessKeySecret, err := section.GetKey("access_key_secret") + if err != nil { + return nil, errors.New("Missing required access_key_secret option in profile for access_key") + } + if accessKeySecret.String() == "" { + return nil, errors.New("access_key_secret cannot be empty") + } + config := &Config{ + Type: tea.String("access_key"), + AccessKeyId: tea.String(accesskeyid.String()), + AccessKeySecret: tea.String(accessKeySecret.String()), + } + return config, nil +} + +func getType(path, profile string) (*ini.Key, *ini.Section, error) { + ini, err := ini.Load(path) + if err != nil { + return nil, nil, errors.New("ERROR: Can not open file " + err.Error()) + } + + section, err := ini.GetSection(profile) + if err != nil { + return nil, nil, errors.New("ERROR: Can not load section " + err.Error()) + } + + value, err := section.GetKey("type") + if err != nil { + return nil, nil, errors.New("Missing required type option " + err.Error()) + } + return value, section, nil +} + +func getHomePath() string { + if hookOS(runtime.GOOS) == "windows" { + path, ok := os.LookupEnv("USERPROFILE") + if !ok { + return "" + } + return path + } + path, ok := os.LookupEnv("HOME") + if !ok { + return "" + } + return path +} + +func checkDefaultPath() (path string, err error) { + path = getHomePath() + if path == "" { + return "", errors.New("The default credential file path is invalid") + } + path = strings.Replace("~/.alibabacloud/credentials", "~", path, 1) + _, err = hookState(os.Stat(path)) + if err != nil { + return "", nil + } + return path, nil +} + +func setRuntimeToConfig(config *Config, section *ini.Section) error { + rawTimeout, _ := section.GetKey("timeout") + rawConnectTimeout, _ := section.GetKey("connect_timeout") + rawProxy, _ := section.GetKey("proxy") + rawHost, _ := section.GetKey("host") + if rawProxy != nil { + config.Proxy = tea.String(rawProxy.String()) + } + if rawConnectTimeout != nil { + connectTimeout, err := rawConnectTimeout.Int() + if err != nil { + return fmt.Errorf("Please set connect_timeout with an int value") + } + config.ConnectTimeout = tea.Int(connectTimeout) + } + if rawTimeout != nil { + timeout, err := rawTimeout.Int() + if err != nil { + return fmt.Errorf("Please set timeout with an int value") + } + config.Timeout = tea.Int(timeout) + } + if rawHost != nil { + config.Host = tea.String(rawHost.String()) + } + return nil +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/provider.go b/vendor/github.com/aliyun/credentials-go/credentials/provider.go new file mode 100644 index 000000000..f9d4ae574 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/provider.go @@ -0,0 +1,13 @@ +package credentials + +//Environmental virables that may be used by the provider +const ( + ENVCredentialFile = "ALIBABA_CLOUD_CREDENTIALS_FILE" + ENVEcsMetadata = "ALIBABA_CLOUD_ECS_METADATA" + PATHCredentialFile = "~/.alibabacloud/credentials" +) + +// Provider will be implemented When you want to customize the provider. +type Provider interface { + resolve() (*Config, error) +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/provider_chain.go b/vendor/github.com/aliyun/credentials-go/credentials/provider_chain.go new file mode 100644 index 000000000..2764a701c --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/provider_chain.go @@ -0,0 +1,32 @@ +package credentials + +import ( + "errors" +) + +type providerChain struct { + Providers []Provider +} + +var defaultproviders = []Provider{providerEnv, providerProfile, providerInstance} +var defaultChain = newProviderChain(defaultproviders) + +func newProviderChain(providers []Provider) Provider { + return &providerChain{ + Providers: providers, + } +} + +func (p *providerChain) resolve() (*Config, error) { + for _, provider := range p.Providers { + config, err := provider.resolve() + if err != nil { + return nil, err + } else if config == nil { + continue + } + return config, err + } + return nil, errors.New("No credential found") + +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/request/common_request.go b/vendor/github.com/aliyun/credentials-go/credentials/request/common_request.go new file mode 100644 index 000000000..68b9681b3 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/request/common_request.go @@ -0,0 +1,59 @@ +package request + +import ( + "fmt" + "net/url" + "strings" + "time" + + "github.com/aliyun/credentials-go/credentials/utils" +) + +// CommonRequest is for requesting credential +type CommonRequest struct { + Scheme string + Method string + Domain string + RegionId string + URL string + ReadTimeout time.Duration + ConnectTimeout time.Duration + isInsecure *bool + + userAgent map[string]string + QueryParams map[string]string + Headers map[string]string + + queries string +} + +// NewCommonRequest returns a CommonRequest +func NewCommonRequest() *CommonRequest { + return &CommonRequest{ + QueryParams: make(map[string]string), + Headers: make(map[string]string), + } +} + +// BuildURL returns a url +func (request *CommonRequest) BuildURL() string { + url := fmt.Sprintf("%s://%s", strings.ToLower(request.Scheme), request.Domain) + request.queries = "/?" + utils.GetURLFormedMap(request.QueryParams) + return url + request.queries +} + +// BuildStringToSign returns BuildStringToSign +func (request *CommonRequest) BuildStringToSign() (stringToSign string) { + signParams := make(map[string]string) + for key, value := range request.QueryParams { + signParams[key] = value + } + + stringToSign = utils.GetURLFormedMap(signParams) + stringToSign = strings.Replace(stringToSign, "+", "%20", -1) + stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) + stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) + stringToSign = url.QueryEscape(stringToSign) + stringToSign = request.Method + "&%2F&" + stringToSign + return +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/response/common_response.go b/vendor/github.com/aliyun/credentials-go/credentials/response/common_response.go new file mode 100644 index 000000000..ef489c11d --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/response/common_response.go @@ -0,0 +1,53 @@ +package response + +import ( + "io" + "io/ioutil" + "net/http" +) + +var hookReadAll = func(fn func(r io.Reader) (b []byte, err error)) func(r io.Reader) (b []byte, err error) { + return fn +} + +// CommonResponse is for storing message of httpResponse +type CommonResponse struct { + httpStatus int + httpHeaders map[string][]string + httpContentString string + httpContentBytes []byte +} + +// ParseFromHTTPResponse assigns for CommonResponse, returns err when body is too large. +func (resp *CommonResponse) ParseFromHTTPResponse(httpResponse *http.Response) (err error) { + defer httpResponse.Body.Close() + body, err := hookReadAll(ioutil.ReadAll)(httpResponse.Body) + if err != nil { + return + } + resp.httpStatus = httpResponse.StatusCode + resp.httpHeaders = httpResponse.Header + resp.httpContentBytes = body + resp.httpContentString = string(body) + return +} + +// GetHTTPStatus returns httpStatus +func (resp *CommonResponse) GetHTTPStatus() int { + return resp.httpStatus +} + +// GetHTTPHeaders returns httpresponse's headers +func (resp *CommonResponse) GetHTTPHeaders() map[string][]string { + return resp.httpHeaders +} + +// GetHTTPContentString return body content as string +func (resp *CommonResponse) GetHTTPContentString() string { + return resp.httpContentString +} + +// GetHTTPContentBytes return body content as []byte +func (resp *CommonResponse) GetHTTPContentBytes() []byte { + return resp.httpContentBytes +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/rsa_key_pair_credential.go b/vendor/github.com/aliyun/credentials-go/credentials/rsa_key_pair_credential.go new file mode 100644 index 000000000..3e4310eca --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/rsa_key_pair_credential.go @@ -0,0 +1,145 @@ +package credentials + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "time" + + "github.com/alibabacloud-go/tea/tea" + "github.com/aliyun/credentials-go/credentials/request" + "github.com/aliyun/credentials-go/credentials/utils" +) + +// RsaKeyPairCredential is a kind of credentials +type RsaKeyPairCredential struct { + *credentialUpdater + PrivateKey string + PublicKeyId string + SessionExpiration int + sessionCredential *sessionCredential + runtime *utils.Runtime +} + +type rsaKeyPairResponse struct { + SessionAccessKey *sessionAccessKey `json:"SessionAccessKey" xml:"SessionAccessKey"` +} + +type sessionAccessKey struct { + SessionAccessKeyId string `json:"SessionAccessKeyId" xml:"SessionAccessKeyId"` + SessionAccessKeySecret string `json:"SessionAccessKeySecret" xml:"SessionAccessKeySecret"` + Expiration string `json:"Expiration" xml:"Expiration"` +} + +func newRsaKeyPairCredential(privateKey, publicKeyId string, sessionExpiration int, runtime *utils.Runtime) *RsaKeyPairCredential { + return &RsaKeyPairCredential{ + PrivateKey: privateKey, + PublicKeyId: publicKeyId, + SessionExpiration: sessionExpiration, + credentialUpdater: new(credentialUpdater), + runtime: runtime, + } +} + +// GetAccessKeyId reutrns RsaKeyPairCredential's AccessKeyId +// if AccessKeyId is not exist or out of date, the function will update it. +func (r *RsaKeyPairCredential) GetAccessKeyId() (*string, error) { + if r.sessionCredential == nil || r.needUpdateCredential() { + err := r.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(r.sessionCredential.AccessKeyId), nil +} + +// GetAccessSecret reutrns RsaKeyPairCredential's AccessKeySecret +// if AccessKeySecret is not exist or out of date, the function will update it. +func (r *RsaKeyPairCredential) GetAccessKeySecret() (*string, error) { + if r.sessionCredential == nil || r.needUpdateCredential() { + err := r.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(r.sessionCredential.AccessKeySecret), nil +} + +// GetSecurityToken is useless RsaKeyPairCredential +func (r *RsaKeyPairCredential) GetSecurityToken() (*string, error) { + return tea.String(""), nil +} + +// GetBearerToken is useless for RsaKeyPairCredential +func (r *RsaKeyPairCredential) GetBearerToken() *string { + return tea.String("") +} + +// GetType reutrns RsaKeyPairCredential's type +func (r *RsaKeyPairCredential) GetType() *string { + return tea.String("rsa_key_pair") +} + +func (r *RsaKeyPairCredential) updateCredential() (err error) { + if r.runtime == nil { + r.runtime = new(utils.Runtime) + } + request := request.NewCommonRequest() + request.Domain = "sts.aliyuncs.com" + if r.runtime.Host != "" { + request.Domain = r.runtime.Host + } + request.Scheme = "HTTPS" + request.Method = "GET" + request.QueryParams["AccessKeyId"] = r.PublicKeyId + request.QueryParams["Action"] = "GenerateSessionAccessKey" + request.QueryParams["Format"] = "JSON" + if r.SessionExpiration > 0 { + if r.SessionExpiration >= 900 && r.SessionExpiration <= 3600 { + request.QueryParams["DurationSeconds"] = strconv.Itoa(r.SessionExpiration) + } else { + err = errors.New("[InvalidParam]:Key Pair session duration should be in the range of 15min - 1Hr") + return + } + } else { + request.QueryParams["DurationSeconds"] = strconv.Itoa(defaultDurationSeconds) + } + request.QueryParams["SignatureMethod"] = "SHA256withRSA" + request.QueryParams["SignatureType"] = "PRIVATEKEY" + request.QueryParams["SignatureVersion"] = "1.0" + request.QueryParams["Version"] = "2015-04-01" + request.QueryParams["Timestamp"] = utils.GetTimeInFormatISO8601() + request.QueryParams["SignatureNonce"] = utils.GetUUID() + signature := utils.Sha256WithRsa(request.BuildStringToSign(), r.PrivateKey) + request.QueryParams["Signature"] = signature + request.Headers["Host"] = request.Domain + request.Headers["Accept-Encoding"] = "identity" + request.URL = request.BuildURL() + content, err := doAction(request, r.runtime) + if err != nil { + return fmt.Errorf("refresh KeyPair err: %s", err.Error()) + } + var resp *rsaKeyPairResponse + err = json.Unmarshal(content, &resp) + if err != nil { + return fmt.Errorf("refresh KeyPair err: Json Unmarshal fail: %s", err.Error()) + } + if resp == nil || resp.SessionAccessKey == nil { + return fmt.Errorf("refresh KeyPair err: SessionAccessKey is empty") + } + sessionAccessKey := resp.SessionAccessKey + if sessionAccessKey.SessionAccessKeyId == "" || sessionAccessKey.SessionAccessKeySecret == "" || sessionAccessKey.Expiration == "" { + return fmt.Errorf("refresh KeyPair err: SessionAccessKeyId: %v, SessionAccessKeySecret: %v, Expiration: %v", sessionAccessKey.SessionAccessKeyId, sessionAccessKey.SessionAccessKeySecret, sessionAccessKey.Expiration) + } + + expirationTime, err := time.Parse("2006-01-02T15:04:05Z", sessionAccessKey.Expiration) + r.lastUpdateTimestamp = time.Now().Unix() + r.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix()) + r.sessionCredential = &sessionCredential{ + AccessKeyId: sessionAccessKey.SessionAccessKeyId, + AccessKeySecret: sessionAccessKey.SessionAccessKeySecret, + } + + return +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/session_credential.go b/vendor/github.com/aliyun/credentials-go/credentials/session_credential.go new file mode 100644 index 000000000..dd48dc929 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/session_credential.go @@ -0,0 +1,7 @@ +package credentials + +type sessionCredential struct { + AccessKeyId string + AccessKeySecret string + SecurityToken string +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/sts_credential.go b/vendor/github.com/aliyun/credentials-go/credentials/sts_credential.go new file mode 100644 index 000000000..ba07dab49 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/sts_credential.go @@ -0,0 +1,43 @@ +package credentials + +import "github.com/alibabacloud-go/tea/tea" + +// StsTokenCredential is a kind of credentials +type StsTokenCredential struct { + AccessKeyId string + AccessKeySecret string + SecurityToken string +} + +func newStsTokenCredential(accessKeyId, accessKeySecret, securityToken string) *StsTokenCredential { + return &StsTokenCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + SecurityToken: securityToken, + } +} + +// GetAccessKeyId reutrns StsTokenCredential's AccessKeyId +func (s *StsTokenCredential) GetAccessKeyId() (*string, error) { + return tea.String(s.AccessKeyId), nil +} + +// GetAccessSecret reutrns StsTokenCredential's AccessKeySecret +func (s *StsTokenCredential) GetAccessKeySecret() (*string, error) { + return tea.String(s.AccessKeySecret), nil +} + +// GetSecurityToken reutrns StsTokenCredential's SecurityToken +func (s *StsTokenCredential) GetSecurityToken() (*string, error) { + return tea.String(s.SecurityToken), nil +} + +// GetBearerToken is useless StsTokenCredential +func (s *StsTokenCredential) GetBearerToken() *string { + return tea.String("") +} + +// GetType reutrns StsTokenCredential's type +func (s *StsTokenCredential) GetType() *string { + return tea.String("sts") +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/sts_role_arn_credential.go b/vendor/github.com/aliyun/credentials-go/credentials/sts_role_arn_credential.go new file mode 100644 index 000000000..f31ba1e32 --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/sts_role_arn_credential.go @@ -0,0 +1,163 @@ +package credentials + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "time" + + "github.com/alibabacloud-go/tea/tea" + "github.com/aliyun/credentials-go/credentials/request" + "github.com/aliyun/credentials-go/credentials/utils" +) + +const defaultDurationSeconds = 3600 + +// RAMRoleArnCredential is a kind of credentials +type RAMRoleArnCredential struct { + *credentialUpdater + AccessKeyId string + AccessKeySecret string + RoleArn string + RoleSessionName string + RoleSessionExpiration int + Policy string + sessionCredential *sessionCredential + runtime *utils.Runtime +} + +type ramRoleArnResponse struct { + Credentials *credentialsInResponse `json:"Credentials" xml:"Credentials"` +} + +type credentialsInResponse struct { + AccessKeyId string `json:"AccessKeyId" xml:"AccessKeyId"` + AccessKeySecret string `json:"AccessKeySecret" xml:"AccessKeySecret"` + SecurityToken string `json:"SecurityToken" xml:"SecurityToken"` + Expiration string `json:"Expiration" xml:"Expiration"` +} + +func newRAMRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy string, roleSessionExpiration int, runtime *utils.Runtime) *RAMRoleArnCredential { + return &RAMRoleArnCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + RoleArn: roleArn, + RoleSessionName: roleSessionName, + RoleSessionExpiration: roleSessionExpiration, + Policy: policy, + credentialUpdater: new(credentialUpdater), + runtime: runtime, + } +} + +// GetAccessKeyId reutrns RamRoleArnCredential's AccessKeyId +// if AccessKeyId is not exist or out of date, the function will update it. +func (r *RAMRoleArnCredential) GetAccessKeyId() (*string, error) { + if r.sessionCredential == nil || r.needUpdateCredential() { + err := r.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(r.sessionCredential.AccessKeyId), nil +} + +// GetAccessSecret reutrns RamRoleArnCredential's AccessKeySecret +// if AccessKeySecret is not exist or out of date, the function will update it. +func (r *RAMRoleArnCredential) GetAccessKeySecret() (*string, error) { + if r.sessionCredential == nil || r.needUpdateCredential() { + err := r.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(r.sessionCredential.AccessKeySecret), nil +} + +// GetSecurityToken reutrns RamRoleArnCredential's SecurityToken +// if SecurityToken is not exist or out of date, the function will update it. +func (r *RAMRoleArnCredential) GetSecurityToken() (*string, error) { + if r.sessionCredential == nil || r.needUpdateCredential() { + err := r.updateCredential() + if err != nil { + return tea.String(""), err + } + } + return tea.String(r.sessionCredential.SecurityToken), nil +} + +// GetBearerToken is useless RamRoleArnCredential +func (r *RAMRoleArnCredential) GetBearerToken() *string { + return tea.String("") +} + +// GetType reutrns RamRoleArnCredential's type +func (r *RAMRoleArnCredential) GetType() *string { + return tea.String("ram_role_arn") +} + +func (r *RAMRoleArnCredential) updateCredential() (err error) { + if r.runtime == nil { + r.runtime = new(utils.Runtime) + } + request := request.NewCommonRequest() + request.Domain = "sts.aliyuncs.com" + request.Scheme = "HTTPS" + request.Method = "GET" + request.QueryParams["AccessKeyId"] = r.AccessKeyId + request.QueryParams["Action"] = "AssumeRole" + request.QueryParams["Format"] = "JSON" + if r.RoleSessionExpiration > 0 { + if r.RoleSessionExpiration >= 900 && r.RoleSessionExpiration <= 3600 { + request.QueryParams["DurationSeconds"] = strconv.Itoa(r.RoleSessionExpiration) + } else { + err = errors.New("[InvalidParam]:Assume Role session duration should be in the range of 15min - 1Hr") + return + } + } else { + request.QueryParams["DurationSeconds"] = strconv.Itoa(defaultDurationSeconds) + } + request.QueryParams["RoleArn"] = r.RoleArn + if r.Policy != "" { + request.QueryParams["Policy"] = r.Policy + } + request.QueryParams["RoleSessionName"] = r.RoleSessionName + request.QueryParams["SignatureMethod"] = "HMAC-SHA1" + request.QueryParams["SignatureVersion"] = "1.0" + request.QueryParams["Version"] = "2015-04-01" + request.QueryParams["Timestamp"] = utils.GetTimeInFormatISO8601() + request.QueryParams["SignatureNonce"] = utils.GetUUID() + signature := utils.ShaHmac1(request.BuildStringToSign(), r.AccessKeySecret+"&") + request.QueryParams["Signature"] = signature + request.Headers["Host"] = request.Domain + request.Headers["Accept-Encoding"] = "identity" + request.URL = request.BuildURL() + content, err := doAction(request, r.runtime) + if err != nil { + return fmt.Errorf("refresh RoleArn sts token err: %s", err.Error()) + } + var resp *ramRoleArnResponse + err = json.Unmarshal(content, &resp) + if err != nil { + return fmt.Errorf("refresh RoleArn sts token err: Json.Unmarshal fail: %s", err.Error()) + } + if resp == nil || resp.Credentials == nil { + return fmt.Errorf("refresh RoleArn sts token err: Credentials is empty") + } + respCredentials := resp.Credentials + if respCredentials.AccessKeyId == "" || respCredentials.AccessKeySecret == "" || respCredentials.SecurityToken == "" || respCredentials.Expiration == "" { + return fmt.Errorf("refresh RoleArn sts token err: AccessKeyId: %s, AccessKeySecret: %s, SecurityToken: %s, Expiration: %s", respCredentials.AccessKeyId, respCredentials.AccessKeySecret, respCredentials.SecurityToken, respCredentials.Expiration) + } + + expirationTime, err := time.Parse("2006-01-02T15:04:05Z", respCredentials.Expiration) + r.lastUpdateTimestamp = time.Now().Unix() + r.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix()) + r.sessionCredential = &sessionCredential{ + AccessKeyId: respCredentials.AccessKeyId, + AccessKeySecret: respCredentials.AccessKeySecret, + SecurityToken: respCredentials.SecurityToken, + } + + return +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/utils/runtime.go b/vendor/github.com/aliyun/credentials-go/credentials/utils/runtime.go new file mode 100644 index 000000000..d4a27c9cd --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/utils/runtime.go @@ -0,0 +1,35 @@ +package utils + +import ( + "context" + "net" + "time" +) + +// Runtime is for setting timeout, proxy and host +type Runtime struct { + ReadTimeout int + ConnectTimeout int + Proxy string + Host string +} + +// NewRuntime returns a Runtime +func NewRuntime(readTimeout, connectTimeout int, proxy string, host string) *Runtime { + return &Runtime{ + ReadTimeout: readTimeout, + ConnectTimeout: connectTimeout, + Proxy: proxy, + Host: host, + } +} + +// Timeout is for connect Timeout +func Timeout(connectTimeout time.Duration) func(cxt context.Context, net, addr string) (c net.Conn, err error) { + return func(ctx context.Context, network, address string) (net.Conn, error) { + return (&net.Dialer{ + Timeout: connectTimeout, + DualStack: true, + }).DialContext(ctx, network, address) + } +} diff --git a/vendor/github.com/aliyun/credentials-go/credentials/utils/utils.go b/vendor/github.com/aliyun/credentials-go/credentials/utils/utils.go new file mode 100644 index 000000000..7468407fb --- /dev/null +++ b/vendor/github.com/aliyun/credentials-go/credentials/utils/utils.go @@ -0,0 +1,146 @@ +package utils + +import ( + "crypto" + "crypto/hmac" + "crypto/md5" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "hash" + "io" + rand2 "math/rand" + "net/url" + "time" +) + +type uuid [16]byte + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +var hookRead = func(fn func(p []byte) (n int, err error)) func(p []byte) (n int, err error) { + return fn +} + +var hookRSA = func(fn func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)) func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { + return fn +} + +// GetUUID returns a uuid +func GetUUID() (uuidHex string) { + uuid := newUUID() + uuidHex = hex.EncodeToString(uuid[:]) + return +} + +// RandStringBytes returns a rand string +func RandStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand2.Intn(len(letterBytes))] + } + return string(b) +} + +// ShaHmac1 return a string which has been hashed +func ShaHmac1(source, secret string) string { + key := []byte(secret) + hmac := hmac.New(sha1.New, key) + hmac.Write([]byte(source)) + signedBytes := hmac.Sum(nil) + signedString := base64.StdEncoding.EncodeToString(signedBytes) + return signedString +} + +// Sha256WithRsa return a string which has been hashed with Rsa +func Sha256WithRsa(source, secret string) string { + decodeString, err := base64.StdEncoding.DecodeString(secret) + if err != nil { + panic(err) + } + private, err := x509.ParsePKCS8PrivateKey(decodeString) + if err != nil { + panic(err) + } + + h := crypto.Hash.New(crypto.SHA256) + h.Write([]byte(source)) + hashed := h.Sum(nil) + signature, err := hookRSA(rsa.SignPKCS1v15)(rand.Reader, private.(*rsa.PrivateKey), + crypto.SHA256, hashed) + if err != nil { + panic(err) + } + + return base64.StdEncoding.EncodeToString(signature) +} + +// GetMD5Base64 returns a string which has been base64 +func GetMD5Base64(bytes []byte) (base64Value string) { + md5Ctx := md5.New() + md5Ctx.Write(bytes) + md5Value := md5Ctx.Sum(nil) + base64Value = base64.StdEncoding.EncodeToString(md5Value) + return +} + +// GetTimeInFormatISO8601 returns a time string +func GetTimeInFormatISO8601() (timeStr string) { + gmt := time.FixedZone("GMT", 0) + + return time.Now().In(gmt).Format("2006-01-02T15:04:05Z") +} + +// GetURLFormedMap returns a url encoded string +func GetURLFormedMap(source map[string]string) (urlEncoded string) { + urlEncoder := url.Values{} + for key, value := range source { + urlEncoder.Add(key, value) + } + urlEncoded = urlEncoder.Encode() + return +} + +func newUUID() uuid { + ns := uuid{} + safeRandom(ns[:]) + u := newFromHash(md5.New(), ns, RandStringBytes(16)) + u[6] = (u[6] & 0x0f) | (byte(2) << 4) + u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) + + return u +} + +func newFromHash(h hash.Hash, ns uuid, name string) uuid { + u := uuid{} + h.Write(ns[:]) + h.Write([]byte(name)) + copy(u[:], h.Sum(nil)) + + return u +} + +func safeRandom(dest []byte) { + if _, err := hookRead(rand.Read)(dest); err != nil { + panic(err) + } +} + +func (u uuid) String() string { + buf := make([]byte, 36) + + hex.Encode(buf[0:8], u[0:4]) + buf[8] = '-' + hex.Encode(buf[9:13], u[4:6]) + buf[13] = '-' + hex.Encode(buf[14:18], u[6:8]) + buf[18] = '-' + hex.Encode(buf[19:23], u[8:10]) + buf[23] = '-' + hex.Encode(buf[24:], u[10:]) + + return string(buf) +} diff --git a/vendor/github.com/clbanning/mxj/v2/.travis.yml b/vendor/github.com/clbanning/mxj/v2/.travis.yml new file mode 100644 index 000000000..9c8611554 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/.travis.yml @@ -0,0 +1,4 @@ +language: go + +go: +- 1.x \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/v2/LICENSE b/vendor/github.com/clbanning/mxj/v2/LICENSE new file mode 100644 index 000000000..1ada8807d --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012-2021 Charles Banning . All rights reserved. + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/clbanning/mxj/v2/anyxml.go b/vendor/github.com/clbanning/mxj/v2/anyxml.go new file mode 100644 index 000000000..63970ee24 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/anyxml.go @@ -0,0 +1,201 @@ +package mxj + +import ( + "bytes" + "encoding/xml" + "reflect" +) + +const ( + DefaultElementTag = "element" +) + +// Encode arbitrary value as XML. +// +// Note: unmarshaling the resultant +// XML may not return the original value, since tag labels may have been injected +// to create the XML representation of the value. +/* + Encode an arbitrary JSON object. + package main + + import ( + "encoding/json" + "fmt" + "github.com/clbanning/mxj" + ) + + func main() { + jsondata := []byte(`[ + { "somekey":"somevalue" }, + "string", + 3.14159265, + true + ]`) + var i interface{} + err := json.Unmarshal(jsondata, &i) + if err != nil { + // do something + } + x, err := mxj.AnyXmlIndent(i, "", " ", "mydoc") + if err != nil { + // do something else + } + fmt.Println(string(x)) + } + + output: + + somevalue + string + 3.14159265 + true + + +An extreme example is available in examples/goofy_map.go. +*/ +// Alternative values for DefaultRootTag and DefaultElementTag can be set as: +// AnyXml( v, myRootTag, myElementTag). +func AnyXml(v interface{}, tags ...string) ([]byte, error) { + var rt, et string + if len(tags) == 1 || len(tags) == 2 { + rt = tags[0] + } else { + rt = DefaultRootTag + } + if len(tags) == 2 { + et = tags[1] + } else { + et = DefaultElementTag + } + + if v == nil { + if useGoXmlEmptyElemSyntax { + return []byte("<" + rt + ">"), nil + } + return []byte("<" + rt + "/>"), nil + } + if reflect.TypeOf(v).Kind() == reflect.Struct { + return xml.Marshal(v) + } + + var err error + s := new(bytes.Buffer) + p := new(pretty) + + var b []byte + switch v.(type) { + case []interface{}: + if _, err = s.WriteString("<" + rt + ">"); err != nil { + return nil, err + } + for _, vv := range v.([]interface{}) { + switch vv.(type) { + case map[string]interface{}: + m := vv.(map[string]interface{}) + if len(m) == 1 { + for tag, val := range m { + err = marshalMapToXmlIndent(false, s, tag, val, p) + } + } else { + err = marshalMapToXmlIndent(false, s, et, vv, p) + } + default: + err = marshalMapToXmlIndent(false, s, et, vv, p) + } + if err != nil { + break + } + } + if _, err = s.WriteString(""); err != nil { + return nil, err + } + b = s.Bytes() + case map[string]interface{}: + m := Map(v.(map[string]interface{})) + b, err = m.Xml(rt) + default: + err = marshalMapToXmlIndent(false, s, rt, v, p) + b = s.Bytes() + } + + return b, err +} + +// Encode an arbitrary value as a pretty XML string. +// Alternative values for DefaultRootTag and DefaultElementTag can be set as: +// AnyXmlIndent( v, "", " ", myRootTag, myElementTag). +func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) { + var rt, et string + if len(tags) == 1 || len(tags) == 2 { + rt = tags[0] + } else { + rt = DefaultRootTag + } + if len(tags) == 2 { + et = tags[1] + } else { + et = DefaultElementTag + } + + if v == nil { + if useGoXmlEmptyElemSyntax { + return []byte(prefix + "<" + rt + ">"), nil + } + return []byte(prefix + "<" + rt + "/>"), nil + } + if reflect.TypeOf(v).Kind() == reflect.Struct { + return xml.MarshalIndent(v, prefix, indent) + } + + var err error + s := new(bytes.Buffer) + p := new(pretty) + p.indent = indent + p.padding = prefix + + var b []byte + switch v.(type) { + case []interface{}: + if _, err = s.WriteString("<" + rt + ">\n"); err != nil { + return nil, err + } + p.Indent() + for _, vv := range v.([]interface{}) { + switch vv.(type) { + case map[string]interface{}: + m := vv.(map[string]interface{}) + if len(m) == 1 { + for tag, val := range m { + err = marshalMapToXmlIndent(true, s, tag, val, p) + } + } else { + p.start = 1 // we 1 tag in + err = marshalMapToXmlIndent(true, s, et, vv, p) + // *s += "\n" + if _, err = s.WriteString("\n"); err != nil { + return nil, err + } + } + default: + p.start = 0 // in case trailing p.start = 1 + err = marshalMapToXmlIndent(true, s, et, vv, p) + } + if err != nil { + break + } + } + if _, err = s.WriteString(``); err != nil { + return nil, err + } + b = s.Bytes() + case map[string]interface{}: + m := Map(v.(map[string]interface{})) + b, err = m.XmlIndent(prefix, indent, rt) + default: + err = marshalMapToXmlIndent(true, s, rt, v, p) + b = s.Bytes() + } + + return b, err +} diff --git a/vendor/github.com/clbanning/mxj/v2/atomFeedString.xml b/vendor/github.com/clbanning/mxj/v2/atomFeedString.xml new file mode 100644 index 000000000..474575a41 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/atomFeedString.xml @@ -0,0 +1,54 @@ + +Code Review - My issueshttp://codereview.appspot.com/rietveld<>rietveld: an attempt at pubsubhubbub +2009-10-04T01:35:58+00:00email-address-removedurn:md5:134d9179c41f806be79b3a5f7877d19a + An attempt at adding pubsubhubbub support to Rietveld. +http://code.google.com/p/pubsubhubbub +http://code.google.com/p/rietveld/issues/detail?id=155 + +The server side of the protocol is trivial: + 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all + feeds that will be pubsubhubbubbed. + 2. every time one of those feeds changes, tell the hub + with a simple POST request. + +I have tested this by adding debug prints to a local hub +server and checking that the server got the right publish +requests. + +I can&#39;t quite get the server to work, but I think the bug +is not in my code. I think that the server expects to be +able to grab the feed and see the feed&#39;s actual URL in +the link rel=&quot;self&quot;, but the default value for that drops +the :port from the URL, and I cannot for the life of me +figure out how to get the Atom generator deep inside +django not to do that, or even where it is doing that, +or even what code is running to generate the Atom feed. +(I thought I knew but I added some assert False statements +and it kept running!) + +Ignoring that particular problem, I would appreciate +feedback on the right way to get the two values at +the top of feeds.py marked NOTE(rsc). + + +rietveld: correct tab handling +2009-10-03T23:02:17+00:00email-address-removedurn:md5:0a2a4f19bb815101f0ba2904aed7c35a + This fixes the buggy tab rendering that can be seen at +http://codereview.appspot.com/116075/diff/1/2 + +The fundamental problem was that the tab code was +not being told what column the text began in, so it +didn&#39;t know where to put the tab stops. Another problem +was that some of the code assumed that string byte +offsets were the same as column offsets, which is only +true if there are no tabs. + +In the process of fixing this, I cleaned up the arguments +to Fold and ExpandTabs and renamed them Break and +_ExpandTabs so that I could be sure that I found all the +call sites. I also wanted to verify that ExpandTabs was +not being used from outside intra_region_diff.py. + + + ` + diff --git a/vendor/github.com/clbanning/mxj/v2/doc.go b/vendor/github.com/clbanning/mxj/v2/doc.go new file mode 100644 index 000000000..bede31265 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/doc.go @@ -0,0 +1,138 @@ +// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. +// Copyright 2012-2019, Charles Banning. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file + +/* +Marshal/Unmarshal XML to/from map[string]interface{} values (and JSON); extract/modify values from maps by key or key-path, including wildcards. + +mxj supplants the legacy x2j and j2x packages. The subpackage x2j-wrapper is provided to facilitate migrating from the x2j package. The x2j and j2x subpackages provide similar functionality of the old packages but are not function-name compatible with them. + +Note: this library was designed for processing ad hoc anonymous messages. Bulk processing large data sets may be much more efficiently performed using the encoding/xml or encoding/json packages from Go's standard library directly. + +Related Packages: + checkxml: github.com/clbanning/checkxml provides functions for validating XML data. + +Notes: + 2020.05.01: v2.2 - optimize map to XML encoding for large XML docs. + 2019.07.04: v2.0 - remove unnecessary methods - mv.XmlWriterRaw, mv.XmlIndentWriterRaw - for Map and MapSeq. + 2019.07.04: Add MapSeq type and move associated functions and methods from Map to MapSeq. + 2019.01.21: DecodeSimpleValuesAsMap - decode to map[:map["#text":]] rather than map[:]. + 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc. + 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps. + 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package. + 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing. + 2017.02.21: github.com/clbanning/checkxml provides functions for validating XML data. + 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods. + 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag(). + 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc. + 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix(). + 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable. + 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars(). + 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf". + To cast them to float64, first set flag with CastNanInf(true). + 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure. + 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization. + 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM). + 2015-12-02: NewMapXmlSeq() with mv.XmlSeq() & co. will try to preserve structure of XML doc when re-encoding. + 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML. + +SUMMARY + + type Map map[string]interface{} + + Create a Map value, 'mv', from any map[string]interface{} value, 'v': + mv := Map(v) + + Unmarshal / marshal XML as a Map value, 'mv': + mv, err := NewMapXml(xmlValue) // unmarshal + xmlValue, err := mv.Xml() // marshal + + Unmarshal XML from an io.Reader as a Map value, 'mv': + mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream + mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded + + Marshal Map value, 'mv', to an XML Writer (io.Writer): + err := mv.XmlWriter(xmlWriter) + raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter + + Also, for prettified output: + xmlValue, err := mv.XmlIndent(prefix, indent, ...) + err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...) + raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...) + + Bulk process XML with error handling (note: handlers must return a boolean value): + err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error)) + err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte)) + + Converting XML to JSON: see Examples for NewMapXml and HandleXmlReader. + + There are comparable functions and methods for JSON processing. + + Arbitrary structure values can be decoded to / encoded from Map values: + mv, err := NewMapStruct(structVal) + err := mv.Struct(structPointer) + + To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON + or structure to a Map value, 'mv', or cast a map[string]interface{} value to a Map value, 'mv', then: + paths := mv.PathsForKey(key) + path := mv.PathForKeyShortest(key) + values, err := mv.ValuesForKey(key, subkeys) + values, err := mv.ValuesForPath(path, subkeys) // 'path' can be dot-notation with wildcards and indexed arrays. + count, err := mv.UpdateValuesForPath(newVal, path, subkeys) + + Get everything at once, irrespective of path depth: + leafnodes := mv.LeafNodes() + leafvalues := mv.LeafValues() + + A new Map with whatever keys are desired can be created from the current Map and then encoded in XML + or JSON. (Note: keys can use dot-notation. 'oldKey' can also use wildcards and indexed arrays.) + newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N") + newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go" + newXml, err := newMap.Xml() // for example + newJson, err := newMap.Json() // ditto + +XML PARSING CONVENTIONS + + Using NewMapXml() + + - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`, + to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or + `SetAttrPrefix()`.) + - If the element is a simple element and has attributes, the element value + is given the key `#text` for its `map[string]interface{}` representation. (See + the 'atomFeedString.xml' test data, below.) + - XML comments, directives, and process instructions are ignored. + - If CoerceKeysToLower() has been called, then the resultant keys will be lower case. + + Using NewMapXmlSeq() + + - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values + where the `` value has "#text" and "#seq" keys - the "#text" key holds the + value for ``. + - All elements, except for the root, have a "#seq" key. + - Comments, directives, and process instructions are unmarshalled into the Map using the + keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more + specifics.) + - Name space syntax is preserved: + - something parses to map["ns:key"]interface{}{"something"} + - xmlns:ns="http://myns.com/ns" parses to map["xmlns:ns"]interface{}{"http://myns.com/ns"} + + Both + + - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them + to be cast, set a flag to cast them using CastNanInf(true). + +XML ENCODING CONVENTIONS + + - 'nil' Map values, which may represent 'null' JSON values, are encoded as "". + NOTE: the operation is not symmetric as "" elements are decoded as 'tag:""' Map values, + which, then, encode in JSON as '"tag":""' values.. + - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go + randomizes the walk through map[string]interface{} values.) If you plan to re-encode the + Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and + mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when + working with the Map representation. + +*/ +package mxj diff --git a/vendor/github.com/clbanning/mxj/v2/escapechars.go b/vendor/github.com/clbanning/mxj/v2/escapechars.go new file mode 100644 index 000000000..eeb3d2501 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/escapechars.go @@ -0,0 +1,93 @@ +// Copyright 2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "bytes" +) + +var xmlEscapeChars bool + +// XMLEscapeChars(true) forces escaping invalid characters in attribute and element values. +// NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is +// then '&' will be re-escaped as '&amp;'. +// +/* + The values are: + " " + ' ' + < < + > > + & & +*/ +// +// Note: if XMLEscapeCharsDecoder(true) has been called - or the default, 'false,' value +// has been toggled to 'true' - then XMLEscapeChars(true) is ignored. If XMLEscapeChars(true) +// has already been called before XMLEscapeCharsDecoder(true), XMLEscapeChars(false) is called +// to turn escape encoding on mv.Xml, etc., to prevent double escaping ampersands, '&'. +func XMLEscapeChars(b ...bool) { + var bb bool + if len(b) == 0 { + bb = !xmlEscapeChars + } else { + bb = b[0] + } + if bb == true && xmlEscapeCharsDecoder == false { + xmlEscapeChars = true + } else { + xmlEscapeChars = false + } +} + +// Scan for '&' first, since 's' may contain "&" that is parsed to "&amp;" +// - or "<" that is parsed to "&lt;". +var escapechars = [][2][]byte{ + {[]byte(`&`), []byte(`&`)}, + {[]byte(`<`), []byte(`<`)}, + {[]byte(`>`), []byte(`>`)}, + {[]byte(`"`), []byte(`"`)}, + {[]byte(`'`), []byte(`'`)}, +} + +func escapeChars(s string) string { + if len(s) == 0 { + return s + } + + b := []byte(s) + for _, v := range escapechars { + n := bytes.Count(b, v[0]) + if n == 0 { + continue + } + b = bytes.Replace(b, v[0], v[1], n) + } + return string(b) +} + +// per issue #84, escape CharData values from xml.Decoder + +var xmlEscapeCharsDecoder bool + +// XMLEscapeCharsDecoder(b ...bool) escapes XML characters in xml.CharData values +// returned by Decoder.Token. Thus, the internal Map values will contain escaped +// values, and you do not need to set XMLEscapeChars for proper encoding. +// +// By default, the Map values have the non-escaped values returned by Decoder.Token. +// XMLEscapeCharsDecoder(true) - or, XMLEscapeCharsDecoder() - will toggle escape +// encoding 'on.' +// +// Note: if XMLEscapeCharDecoder(true) is call then XMLEscapeChars(false) is +// called to prevent re-escaping the values on encoding using mv.Xml, etc. +func XMLEscapeCharsDecoder(b ...bool) { + if len(b) == 0 { + xmlEscapeCharsDecoder = !xmlEscapeCharsDecoder + } else { + xmlEscapeCharsDecoder = b[0] + } + if xmlEscapeCharsDecoder == true && xmlEscapeChars == true { + xmlEscapeChars = false + } +} diff --git a/vendor/github.com/clbanning/mxj/v2/exists.go b/vendor/github.com/clbanning/mxj/v2/exists.go new file mode 100644 index 000000000..07aeda43f --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/exists.go @@ -0,0 +1,9 @@ +package mxj + +// Checks whether the path exists. If err != nil then 'false' is returned +// along with the error encountered parsing either the "path" or "subkeys" +// argument. +func (mv Map) Exists(path string, subkeys ...string) (bool, error) { + v, err := mv.ValuesForPath(path, subkeys...) + return (err == nil && len(v) > 0), err +} diff --git a/vendor/github.com/clbanning/mxj/v2/files.go b/vendor/github.com/clbanning/mxj/v2/files.go new file mode 100644 index 000000000..27e06e1e8 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files.go @@ -0,0 +1,287 @@ +package mxj + +import ( + "fmt" + "io" + "os" +) + +type Maps []Map + +func NewMaps() Maps { + return make(Maps, 0) +} + +type MapRaw struct { + M Map + R []byte +} + +// NewMapsFromXmlFile - creates an array from a file of JSON values. +func NewMapsFromJsonFile(name string) (Maps, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]Map, 0) + for { + m, raw, err := NewMapJsonReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw)) + } + if len(m) > 0 { + am = append(am, m) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// ReadMapsFromJsonFileRaw - creates an array of MapRaw from a file of JSON values. +func NewMapsFromJsonFileRaw(name string) ([]MapRaw, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]MapRaw, 0) + for { + mr := new(MapRaw) + mr.M, mr.R, err = NewMapJsonReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R)) + } + if len(mr.M) > 0 { + am = append(am, *mr) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// NewMapsFromXmlFile - creates an array from a file of XML values. +func NewMapsFromXmlFile(name string) (Maps, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]Map, 0) + for { + m, raw, err := NewMapXmlReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw)) + } + if len(m) > 0 { + am = append(am, m) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// NewMapsFromXmlFileRaw - creates an array of MapRaw from a file of XML values. +// NOTE: the slice with the raw XML is clean with no extra capacity - unlike NewMapXmlReaderRaw(). +// It is slow at parsing a file from disk and is intended for relatively small utility files. +func NewMapsFromXmlFileRaw(name string) ([]MapRaw, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]MapRaw, 0) + for { + mr := new(MapRaw) + mr.M, mr.R, err = NewMapXmlReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R)) + } + if len(mr.M) > 0 { + am = append(am, *mr) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// ------------------------ Maps writing ------------------------- +// These are handy-dandy methods for dumping configuration data, etc. + +// JsonString - analogous to mv.Json() +func (mvs Maps) JsonString(safeEncoding ...bool) (string, error) { + var s string + for _, v := range mvs { + j, err := v.Json() + if err != nil { + return s, err + } + s += string(j) + } + return s, nil +} + +// JsonStringIndent - analogous to mv.JsonIndent() +func (mvs Maps) JsonStringIndent(prefix, indent string, safeEncoding ...bool) (string, error) { + var s string + var haveFirst bool + for _, v := range mvs { + j, err := v.JsonIndent(prefix, indent) + if err != nil { + return s, err + } + if haveFirst { + s += "\n" + } else { + haveFirst = true + } + s += string(j) + } + return s, nil +} + +// XmlString - analogous to mv.Xml() +func (mvs Maps) XmlString() (string, error) { + var s string + for _, v := range mvs { + x, err := v.Xml() + if err != nil { + return s, err + } + s += string(x) + } + return s, nil +} + +// XmlStringIndent - analogous to mv.XmlIndent() +func (mvs Maps) XmlStringIndent(prefix, indent string) (string, error) { + var s string + for _, v := range mvs { + x, err := v.XmlIndent(prefix, indent) + if err != nil { + return s, err + } + s += string(x) + } + return s, nil +} + +// JsonFile - write Maps to named file as JSON +// Note: the file will be created, if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use JsonWriter method. +func (mvs Maps) JsonFile(file string, safeEncoding ...bool) error { + var encoding bool + if len(safeEncoding) == 1 { + encoding = safeEncoding[0] + } + s, err := mvs.JsonString(encoding) + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} + +// JsonFileIndent - write Maps to named file as pretty JSON +// Note: the file will be created, if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use JsonIndentWriter method. +func (mvs Maps) JsonFileIndent(file, prefix, indent string, safeEncoding ...bool) error { + var encoding bool + if len(safeEncoding) == 1 { + encoding = safeEncoding[0] + } + s, err := mvs.JsonStringIndent(prefix, indent, encoding) + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} + +// XmlFile - write Maps to named file as XML +// Note: the file will be created, if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use XmlWriter method. +func (mvs Maps) XmlFile(file string) error { + s, err := mvs.XmlString() + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} + +// XmlFileIndent - write Maps to named file as pretty XML +// Note: the file will be created,if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use XmlIndentWriter method. +func (mvs Maps) XmlFileIndent(file, prefix, indent string) error { + s, err := mvs.XmlStringIndent(prefix, indent) + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} diff --git a/vendor/github.com/clbanning/mxj/v2/files_test.badjson b/vendor/github.com/clbanning/mxj/v2/files_test.badjson new file mode 100644 index 000000000..d18720044 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test.badjson @@ -0,0 +1,2 @@ +{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" } +{ "with":"some", "bad":JSON, "in":"it" } diff --git a/vendor/github.com/clbanning/mxj/v2/files_test.badxml b/vendor/github.com/clbanning/mxj/v2/files_test.badxml new file mode 100644 index 000000000..4736ef973 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test.badxml @@ -0,0 +1,9 @@ + + test + for files.go + + + some + doc + test case + diff --git a/vendor/github.com/clbanning/mxj/v2/files_test.json b/vendor/github.com/clbanning/mxj/v2/files_test.json new file mode 100644 index 000000000..e9a3ddf40 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test.json @@ -0,0 +1,2 @@ +{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" } +{ "with":"just", "two":2, "JSON":"values", "true":true } diff --git a/vendor/github.com/clbanning/mxj/v2/files_test.xml b/vendor/github.com/clbanning/mxj/v2/files_test.xml new file mode 100644 index 000000000..65cf021fb --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test.xml @@ -0,0 +1,9 @@ + + test + for files.go + + + some + doc + test case + diff --git a/vendor/github.com/clbanning/mxj/v2/files_test_dup.json b/vendor/github.com/clbanning/mxj/v2/files_test_dup.json new file mode 100644 index 000000000..2becb6a45 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test_dup.json @@ -0,0 +1 @@ +{"a":"test","file":"for","files_test.go":"case","this":"is"}{"JSON":"values","true":true,"two":2,"with":"just"} \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/v2/files_test_dup.xml b/vendor/github.com/clbanning/mxj/v2/files_test_dup.xml new file mode 100644 index 000000000..f68d22e28 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test_dup.xml @@ -0,0 +1 @@ +for files.gotestdoctest casesome \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/v2/files_test_indent.json b/vendor/github.com/clbanning/mxj/v2/files_test_indent.json new file mode 100644 index 000000000..6fde15634 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test_indent.json @@ -0,0 +1,12 @@ +{ + "a": "test", + "file": "for", + "files_test.go": "case", + "this": "is" +} +{ + "JSON": "values", + "true": true, + "two": 2, + "with": "just" +} \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/v2/files_test_indent.xml b/vendor/github.com/clbanning/mxj/v2/files_test_indent.xml new file mode 100644 index 000000000..8c91a1dc2 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/files_test_indent.xml @@ -0,0 +1,8 @@ + + for files.go + test + + doc + test case + some + \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/v2/go.mod b/vendor/github.com/clbanning/mxj/v2/go.mod new file mode 100644 index 000000000..7bd84fe62 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/go.mod @@ -0,0 +1,3 @@ +module github.com/clbanning/mxj/v2 + +go 1.15 diff --git a/vendor/github.com/clbanning/mxj/v2/gob.go b/vendor/github.com/clbanning/mxj/v2/gob.go new file mode 100644 index 000000000..d56c2fd6f --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/gob.go @@ -0,0 +1,35 @@ +// gob.go - Encode/Decode a Map into a gob object. + +package mxj + +import ( + "bytes" + "encoding/gob" +) + +// NewMapGob returns a Map value for a gob object that has been +// encoded from a map[string]interface{} (or compatible type) value. +// It is intended to provide symmetric handling of Maps that have +// been encoded using mv.Gob. +func NewMapGob(gobj []byte) (Map, error) { + m := make(map[string]interface{}, 0) + if len(gobj) == 0 { + return m, nil + } + r := bytes.NewReader(gobj) + dec := gob.NewDecoder(r) + if err := dec.Decode(&m); err != nil { + return m, err + } + return m, nil +} + +// Gob returns a gob-encoded value for the Map 'mv'. +func (mv Map) Gob() ([]byte, error) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + if err := enc.Encode(map[string]interface{}(mv)); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/clbanning/mxj/v2/json.go b/vendor/github.com/clbanning/mxj/v2/json.go new file mode 100644 index 000000000..eb2c05a18 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/json.go @@ -0,0 +1,323 @@ +// Copyright 2012-2014 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "time" +) + +// ------------------------------ write JSON ----------------------- + +// Just a wrapper on json.Marshal. +// If option safeEncoding is'true' then safe encoding of '<', '>' and '&' +// is preserved. (see encoding/json#Marshal, encoding/json#Encode) +func (mv Map) Json(safeEncoding ...bool) ([]byte, error) { + var s bool + if len(safeEncoding) == 1 { + s = safeEncoding[0] + } + + b, err := json.Marshal(mv) + + if !s { + b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1) + b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1) + b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1) + } + return b, err +} + +// Just a wrapper on json.MarshalIndent. +// If option safeEncoding is'true' then safe encoding of '<' , '>' and '&' +// is preserved. (see encoding/json#Marshal, encoding/json#Encode) +func (mv Map) JsonIndent(prefix, indent string, safeEncoding ...bool) ([]byte, error) { + var s bool + if len(safeEncoding) == 1 { + s = safeEncoding[0] + } + + b, err := json.MarshalIndent(mv, prefix, indent) + if !s { + b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1) + b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1) + b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1) + } + return b, err +} + +// The following implementation is provided for symmetry with NewMapJsonReader[Raw] +// The names will also provide a key for the number of return arguments. + +// Writes the Map as JSON on the Writer. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonWriter(jsonWriter io.Writer, safeEncoding ...bool) error { + b, err := mv.Json(safeEncoding...) + if err != nil { + return err + } + + _, err = jsonWriter.Write(b) + return err +} + +// Writes the Map as JSON on the Writer. []byte is the raw JSON that was written. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonWriterRaw(jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) { + b, err := mv.Json(safeEncoding...) + if err != nil { + return b, err + } + + _, err = jsonWriter.Write(b) + return b, err +} + +// Writes the Map as pretty JSON on the Writer. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonIndentWriter(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) error { + b, err := mv.JsonIndent(prefix, indent, safeEncoding...) + if err != nil { + return err + } + + _, err = jsonWriter.Write(b) + return err +} + +// Writes the Map as pretty JSON on the Writer. []byte is the raw JSON that was written. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonIndentWriterRaw(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) ([]byte, error) { + b, err := mv.JsonIndent(prefix, indent, safeEncoding...) + if err != nil { + return b, err + } + + _, err = jsonWriter.Write(b) + return b, err +} + +// --------------------------- read JSON ----------------------------- + +// Decode numericvalues as json.Number type Map values - see encoding/json#Number. +// NOTE: this is for decoding JSON into a Map with NewMapJson(), NewMapJsonReader(), +// etc.; it does not affect NewMapXml(), etc. The XML encoders mv.Xml() and mv.XmlIndent() +// do recognize json.Number types; a JSON object can be decoded to a Map with json.Number +// value types and the resulting Map can be correctly encoded into a XML object. +var JsonUseNumber bool + +// Just a wrapper on json.Unmarshal +// Converting JSON to XML is a simple as: +// ... +// mapVal, merr := mxj.NewMapJson(jsonVal) +// if merr != nil { +// // handle error +// } +// xmlVal, xerr := mapVal.Xml() +// if xerr != nil { +// // handle error +// } +// NOTE: as a special case, passing a list, e.g., [{"some-null-value":"", "a-non-null-value":"bar"}], +// will be interpreted as having the root key 'object' prepended - {"object":[ ... ]} - to unmarshal to a Map. +// See mxj/j2x/j2x_test.go. +func NewMapJson(jsonVal []byte) (Map, error) { + // empty or nil begets empty + if len(jsonVal) == 0 { + m := make(map[string]interface{}, 0) + return m, nil + } + // handle a goofy case ... + if jsonVal[0] == '[' { + jsonVal = []byte(`{"object":` + string(jsonVal) + `}`) + } + m := make(map[string]interface{}) + // err := json.Unmarshal(jsonVal, &m) + buf := bytes.NewReader(jsonVal) + dec := json.NewDecoder(buf) + if JsonUseNumber { + dec.UseNumber() + } + err := dec.Decode(&m) + return m, err +} + +// Retrieve a Map value from an io.Reader. +// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an +// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte +// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal +// a JSON object. +func NewMapJsonReader(jsonReader io.Reader) (Map, error) { + jb, err := getJson(jsonReader) + if err != nil || len(*jb) == 0 { + return nil, err + } + + // Unmarshal the 'presumed' JSON string + return NewMapJson(*jb) +} + +// Retrieve a Map value and raw JSON - []byte - from an io.Reader. +// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an +// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte +// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal +// a JSON object and retrieve the raw JSON in a single call. +func NewMapJsonReaderRaw(jsonReader io.Reader) (Map, []byte, error) { + jb, err := getJson(jsonReader) + if err != nil || len(*jb) == 0 { + return nil, *jb, err + } + + // Unmarshal the 'presumed' JSON string + m, merr := NewMapJson(*jb) + return m, *jb, merr +} + +// Pull the next JSON string off the stream: just read from first '{' to its closing '}'. +// Returning a pointer to the slice saves 16 bytes - maybe unnecessary, but internal to package. +func getJson(rdr io.Reader) (*[]byte, error) { + bval := make([]byte, 1) + jb := make([]byte, 0) + var inQuote, inJson bool + var parenCnt int + var previous byte + + // scan the input for a matched set of {...} + // json.Unmarshal will handle syntax checking. + for { + _, err := rdr.Read(bval) + if err != nil { + if err == io.EOF && inJson && parenCnt > 0 { + return &jb, fmt.Errorf("no closing } for JSON string: %s", string(jb)) + } + return &jb, err + } + switch bval[0] { + case '{': + if !inQuote { + parenCnt++ + inJson = true + } + case '}': + if !inQuote { + parenCnt-- + } + if parenCnt < 0 { + return nil, fmt.Errorf("closing } without opening {: %s", string(jb)) + } + case '"': + if inQuote { + if previous == '\\' { + break + } + inQuote = false + } else { + inQuote = true + } + case '\n', '\r', '\t', ' ': + if !inQuote { + continue + } + } + if inJson { + jb = append(jb, bval[0]) + if parenCnt == 0 { + break + } + } + previous = bval[0] + } + + return &jb, nil +} + +// ------------------------------- JSON Reader handler via Map values ----------------------- + +// Default poll delay to keep Handler from spinning on an open stream +// like sitting on os.Stdin waiting for imput. +var jhandlerPollInterval = time.Duration(1e6) + +// While unnecessary, we make HandleJsonReader() have the same signature as HandleXmlReader(). +// This avoids treating one or other as a special case and discussing the underlying stdlib logic. + +// Bulk process JSON using handlers that process a Map value. +// 'rdr' is an io.Reader for the JSON (stream). +// 'mapHandler' is the Map processing handler. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'. +func HandleJsonReader(jsonReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error { + var n int + for { + m, merr := NewMapJsonReader(jsonReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m); !ok { + break + } + } else if merr != io.EOF { + <-time.After(jhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} + +// Bulk process JSON using handlers that process a Map value and the raw JSON. +// 'rdr' is an io.Reader for the JSON (stream). +// 'mapHandler' is the Map and raw JSON - []byte - processor. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error and raw JSON processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'. +func HandleJsonReaderRaw(jsonReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error { + var n int + for { + m, raw, merr := NewMapJsonReaderRaw(jsonReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr, raw); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m, raw); !ok { + break + } + } else if merr != io.EOF { + <-time.After(jhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} diff --git a/vendor/github.com/clbanning/mxj/v2/keyvalues.go b/vendor/github.com/clbanning/mxj/v2/keyvalues.go new file mode 100644 index 000000000..55620ca22 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/keyvalues.go @@ -0,0 +1,668 @@ +// Copyright 2012-2014 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// keyvalues.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters. + +package mxj + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +// ----------------------------- get everything FOR a single key ------------------------- + +const ( + minArraySize = 32 +) + +var defaultArraySize int = minArraySize + +// SetArraySize adjust the buffers for expected number of values to return from ValuesForKey() and ValuesForPath(). +// This can have the effect of significantly reducing memory allocation-copy functions for large data sets. +// Returns the initial buffer size. +func SetArraySize(size int) int { + if size > minArraySize { + defaultArraySize = size + } else { + defaultArraySize = minArraySize + } + return defaultArraySize +} + +// ValuesForKey return all values in Map, 'mv', associated with a 'key'. If len(returned_values) == 0, then no match. +// On error, the returned slice is 'nil'. NOTE: 'key' can be wildcard, "*". +// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list. +// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them. +// - For attributes prefix the label with the attribute prefix character, by default a +// hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.) +// - If the 'key' refers to a list, then "key:value" could select a list member of the list. +// - The subkey can be wildcarded - "key:*" - to require that it's there with some value. +// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an +// exclusion critera - e.g., "!author:William T. Gaddis". +// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|". +func (mv Map) ValuesForKey(key string, subkeys ...string) ([]interface{}, error) { + m := map[string]interface{}(mv) + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return nil, err + } + } + + ret := make([]interface{}, 0, defaultArraySize) + var cnt int + hasKey(m, key, &ret, &cnt, subKeyMap) + return ret[:cnt], nil +} + +var KeyNotExistError = errors.New("Key does not exist") + +// ValueForKey is a wrapper on ValuesForKey. It returns the first member of []interface{}, if any. +// If there is no value, "nil, nil" is returned. +func (mv Map) ValueForKey(key string, subkeys ...string) (interface{}, error) { + vals, err := mv.ValuesForKey(key, subkeys...) + if err != nil { + return nil, err + } + if len(vals) == 0 { + return nil, KeyNotExistError + } + return vals[0], nil +} + +// hasKey - if the map 'key' exists append it to array +// if it doesn't do nothing except scan array and map values +func hasKey(iv interface{}, key string, ret *[]interface{}, cnt *int, subkeys map[string]interface{}) { + // func hasKey(iv interface{}, key string, ret *[]interface{}, subkeys map[string]interface{}) { + switch iv.(type) { + case map[string]interface{}: + vv := iv.(map[string]interface{}) + // see if the current value is of interest + if v, ok := vv[key]; ok { + switch v.(type) { + case map[string]interface{}: + if hasSubKeys(v, subkeys) { + *ret = append(*ret, v) + *cnt++ + } + case []interface{}: + for _, av := range v.([]interface{}) { + if hasSubKeys(av, subkeys) { + *ret = append(*ret, av) + *cnt++ + } + } + default: + if len(subkeys) == 0 { + *ret = append(*ret, v) + *cnt++ + } + } + } + + // wildcard case + if key == "*" { + for _, v := range vv { + switch v.(type) { + case map[string]interface{}: + if hasSubKeys(v, subkeys) { + *ret = append(*ret, v) + *cnt++ + } + case []interface{}: + for _, av := range v.([]interface{}) { + if hasSubKeys(av, subkeys) { + *ret = append(*ret, av) + *cnt++ + } + } + default: + if len(subkeys) == 0 { + *ret = append(*ret, v) + *cnt++ + } + } + } + } + + // scan the rest + for _, v := range vv { + hasKey(v, key, ret, cnt, subkeys) + } + case []interface{}: + for _, v := range iv.([]interface{}) { + hasKey(v, key, ret, cnt, subkeys) + } + } +} + +// ----------------------- get everything for a node in the Map --------------------------- + +// Allow indexed arrays in "path" specification. (Request from Abhijit Kadam - abhijitk100@gmail.com.) +// 2014.04.28 - implementation note. +// Implemented as a wrapper of (old)ValuesForPath() because we need look-ahead logic to handle expansion +// of wildcards and unindexed arrays. Embedding such logic into valuesForKeyPath() would have made the +// code much more complicated; this wrapper is straightforward, easy to debug, and doesn't add significant overhead. + +// ValuesForPatb retrieves all values for a path from the Map. If len(returned_values) == 0, then no match. +// On error, the returned array is 'nil'. +// 'path' is a dot-separated path of key values. +// - If a node in the path is '*', then everything beyond is walked. +// - 'path' can contain indexed array references, such as, "*.data[1]" and "msgs[2].data[0].field" - +// even "*[2].*[0].field". +// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list. +// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them. +// - For attributes prefix the label with the attribute prefix character, by default a +// hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.) +// - If the 'path' refers to a list, then "tag:value" would return member of the list. +// - The subkey can be wildcarded - "key:*" - to require that it's there with some value. +// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an +// exclusion critera - e.g., "!author:William T. Gaddis". +// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|". +func (mv Map) ValuesForPath(path string, subkeys ...string) ([]interface{}, error) { + // If there are no array indexes in path, use legacy ValuesForPath() logic. + if strings.Index(path, "[") < 0 { + return mv.oldValuesForPath(path, subkeys...) + } + + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return nil, err + } + } + + keys, kerr := parsePath(path) + if kerr != nil { + return nil, kerr + } + + vals, verr := valuesForArray(keys, mv) + if verr != nil { + return nil, verr // Vals may be nil, but return empty array. + } + + // Need to handle subkeys ... only return members of vals that satisfy conditions. + retvals := make([]interface{}, 0) + for _, v := range vals { + if hasSubKeys(v, subKeyMap) { + retvals = append(retvals, v) + } + } + return retvals, nil +} + +func valuesForArray(keys []*key, m Map) ([]interface{}, error) { + var tmppath string + var haveFirst bool + var vals []interface{} + var verr error + + lastkey := len(keys) - 1 + for i := 0; i <= lastkey; i++ { + if !haveFirst { + tmppath = keys[i].name + haveFirst = true + } else { + tmppath += "." + keys[i].name + } + + // Look-ahead: explode wildcards and unindexed arrays. + // Need to handle un-indexed list recursively: + // e.g., path is "stuff.data[0]" rather than "stuff[0].data[0]". + // Need to treat it as "stuff[0].data[0]", "stuff[1].data[0]", ... + if !keys[i].isArray && i < lastkey && keys[i+1].isArray { + // Can't pass subkeys because we may not be at literal end of path. + vv, vverr := m.oldValuesForPath(tmppath) + if vverr != nil { + return nil, vverr + } + for _, v := range vv { + // See if we can walk the value. + am, ok := v.(map[string]interface{}) + if !ok { + continue + } + // Work the backend. + nvals, nvalserr := valuesForArray(keys[i+1:], Map(am)) + if nvalserr != nil { + return nil, nvalserr + } + vals = append(vals, nvals...) + } + break // have recursed the whole path - return + } + + if keys[i].isArray || i == lastkey { + // Don't pass subkeys because may not be at literal end of path. + vals, verr = m.oldValuesForPath(tmppath) + } else { + continue + } + if verr != nil { + return nil, verr + } + + if i == lastkey && !keys[i].isArray { + break + } + + // Now we're looking at an array - supposedly. + // Is index in range of vals? + if len(vals) <= keys[i].position { + vals = nil + break + } + + // Return the array member of interest, if at end of path. + if i == lastkey { + vals = vals[keys[i].position:(keys[i].position + 1)] + break + } + + // Extract the array member of interest. + am := vals[keys[i].position:(keys[i].position + 1)] + + // must be a map[string]interface{} value so we can keep walking the path + amm, ok := am[0].(map[string]interface{}) + if !ok { + vals = nil + break + } + + m = Map(amm) + haveFirst = false + } + + return vals, nil +} + +type key struct { + name string + isArray bool + position int +} + +func parsePath(s string) ([]*key, error) { + keys := strings.Split(s, ".") + + ret := make([]*key, 0) + + for i := 0; i < len(keys); i++ { + if keys[i] == "" { + continue + } + + newkey := new(key) + if strings.Index(keys[i], "[") < 0 { + newkey.name = keys[i] + ret = append(ret, newkey) + continue + } + + p := strings.Split(keys[i], "[") + newkey.name = p[0] + p = strings.Split(p[1], "]") + if p[0] == "" { // no right bracket + return nil, fmt.Errorf("no right bracket on key index: %s", keys[i]) + } + // convert p[0] to a int value + pos, nerr := strconv.ParseInt(p[0], 10, 32) + if nerr != nil { + return nil, fmt.Errorf("cannot convert index to int value: %s", p[0]) + } + newkey.position = int(pos) + newkey.isArray = true + ret = append(ret, newkey) + } + + return ret, nil +} + +// legacy ValuesForPath() - now wrapped to handle special case of indexed arrays in 'path'. +func (mv Map) oldValuesForPath(path string, subkeys ...string) ([]interface{}, error) { + m := map[string]interface{}(mv) + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return nil, err + } + } + + keys := strings.Split(path, ".") + if keys[len(keys)-1] == "" { + keys = keys[:len(keys)-1] + } + ivals := make([]interface{}, 0, defaultArraySize) + var cnt int + valuesForKeyPath(&ivals, &cnt, m, keys, subKeyMap) + return ivals[:cnt], nil +} + +func valuesForKeyPath(ret *[]interface{}, cnt *int, m interface{}, keys []string, subkeys map[string]interface{}) { + lenKeys := len(keys) + + // load 'm' values into 'ret' + // expand any lists + if lenKeys == 0 { + switch m.(type) { + case map[string]interface{}: + if subkeys != nil { + if ok := hasSubKeys(m, subkeys); !ok { + return + } + } + *ret = append(*ret, m) + *cnt++ + case []interface{}: + for i, v := range m.([]interface{}) { + if subkeys != nil { + if ok := hasSubKeys(v, subkeys); !ok { + continue // only load list members with subkeys + } + } + *ret = append(*ret, (m.([]interface{}))[i]) + *cnt++ + } + default: + if subkeys != nil { + return // must be map[string]interface{} if there are subkeys + } + *ret = append(*ret, m) + *cnt++ + } + return + } + + // key of interest + key := keys[0] + switch key { + case "*": // wildcard - scan all values + switch m.(type) { + case map[string]interface{}: + for _, v := range m.(map[string]interface{}) { + // valuesForKeyPath(ret, v, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) + } + case []interface{}: + for _, v := range m.([]interface{}) { + switch v.(type) { + // flatten out a list of maps - keys are processed + case map[string]interface{}: + for _, vv := range v.(map[string]interface{}) { + // valuesForKeyPath(ret, vv, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys) + } + default: + // valuesForKeyPath(ret, v, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) + } + } + } + default: // key - must be map[string]interface{} + switch m.(type) { + case map[string]interface{}: + if v, ok := m.(map[string]interface{})[key]; ok { + // valuesForKeyPath(ret, v, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) + } + case []interface{}: // may be buried in list + for _, v := range m.([]interface{}) { + switch v.(type) { + case map[string]interface{}: + if vv, ok := v.(map[string]interface{})[key]; ok { + // valuesForKeyPath(ret, vv, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys) + } + } + } + } + } +} + +// hasSubKeys() - interface{} equality works for string, float64, bool +// 'v' must be a map[string]interface{} value to have subkeys +// 'a' can have k:v pairs with v.(string) == "*", which is treated like a wildcard. +func hasSubKeys(v interface{}, subkeys map[string]interface{}) bool { + if len(subkeys) == 0 { + return true + } + + switch v.(type) { + case map[string]interface{}: + // do all subKey name:value pairs match? + mv := v.(map[string]interface{}) + for skey, sval := range subkeys { + isNotKey := false + if skey[:1] == "!" { // a NOT-key + skey = skey[1:] + isNotKey = true + } + vv, ok := mv[skey] + if !ok { // key doesn't exist + if isNotKey { // key not there, but that's what we want + if kv, ok := sval.(string); ok && kv == "*" { + continue + } + } + return false + } + // wildcard check + if kv, ok := sval.(string); ok && kv == "*" { + if isNotKey { // key is there, and we don't want it + return false + } + continue + } + switch sval.(type) { + case string: + if s, ok := vv.(string); ok && s == sval.(string) { + if isNotKey { + return false + } + continue + } + case bool: + if b, ok := vv.(bool); ok && b == sval.(bool) { + if isNotKey { + return false + } + continue + } + case float64: + if f, ok := vv.(float64); ok && f == sval.(float64) { + if isNotKey { + return false + } + continue + } + } + // key there but didn't match subkey value + if isNotKey { // that's what we want + continue + } + return false + } + // all subkeys matched + return true + } + + // not a map[string]interface{} value, can't have subkeys + return false +} + +// Generate map of key:value entries as map[string]string. +// 'kv' arguments are "name:value" pairs: attribute keys are designated with prepended hyphen, '-'. +// If len(kv) == 0, the return is (nil, nil). +func getSubKeyMap(kv ...string) (map[string]interface{}, error) { + if len(kv) == 0 { + return nil, nil + } + m := make(map[string]interface{}, 0) + for _, v := range kv { + vv := strings.Split(v, fieldSep) + switch len(vv) { + case 2: + m[vv[0]] = interface{}(vv[1]) + case 3: + switch vv[2] { + case "string", "char", "text": + m[vv[0]] = interface{}(vv[1]) + case "bool", "boolean": + // ParseBool treats "1"==true & "0"==false + b, err := strconv.ParseBool(vv[1]) + if err != nil { + return nil, fmt.Errorf("can't convert subkey value to bool: %s", vv[1]) + } + m[vv[0]] = interface{}(b) + case "float", "float64", "num", "number", "numeric": + f, err := strconv.ParseFloat(vv[1], 64) + if err != nil { + return nil, fmt.Errorf("can't convert subkey value to float: %s", vv[1]) + } + m[vv[0]] = interface{}(f) + default: + return nil, fmt.Errorf("unknown subkey conversion spec: %s", v) + } + default: + return nil, fmt.Errorf("unknown subkey spec: %s", v) + } + } + return m, nil +} + +// ------------------------------- END of valuesFor ... ---------------------------- + +// ----------------------- locate where a key value is in the tree ------------------- + +//----------------------------- find all paths to a key -------------------------------- + +// PathsForKey returns all paths through Map, 'mv', (in dot-notation) that terminate with the specified key. +// Results can be used with ValuesForPath. +func (mv Map) PathsForKey(key string) []string { + m := map[string]interface{}(mv) + breadbasket := make(map[string]bool, 0) + breadcrumbs := "" + + hasKeyPath(breadcrumbs, m, key, breadbasket) + if len(breadbasket) == 0 { + return nil + } + + // unpack map keys to return + res := make([]string, len(breadbasket)) + var i int + for k := range breadbasket { + res[i] = k + i++ + } + + return res +} + +// PathForKeyShortest extracts the shortest path from all possible paths - from PathsForKey() - in Map, 'mv'.. +// Paths are strings using dot-notation. +func (mv Map) PathForKeyShortest(key string) string { + paths := mv.PathsForKey(key) + + lp := len(paths) + if lp == 0 { + return "" + } + if lp == 1 { + return paths[0] + } + + shortest := paths[0] + shortestLen := len(strings.Split(shortest, ".")) + + for i := 1; i < len(paths); i++ { + vlen := len(strings.Split(paths[i], ".")) + if vlen < shortestLen { + shortest = paths[i] + shortestLen = vlen + } + } + + return shortest +} + +// hasKeyPath - if the map 'key' exists append it to KeyPath.path and increment KeyPath.depth +// This is really just a breadcrumber that saves all trails that hit the prescribed 'key'. +func hasKeyPath(crumbs string, iv interface{}, key string, basket map[string]bool) { + switch iv.(type) { + case map[string]interface{}: + vv := iv.(map[string]interface{}) + if _, ok := vv[key]; ok { + // create a new breadcrumb, intialized with the one we have + var nbc string + if crumbs == "" { + nbc = key + } else { + nbc = crumbs + "." + key + } + basket[nbc] = true + } + // walk on down the path, key could occur again at deeper node + for k, v := range vv { + // create a new breadcrumb, intialized with the one we have + var nbc string + if crumbs == "" { + nbc = k + } else { + nbc = crumbs + "." + k + } + hasKeyPath(nbc, v, key, basket) + } + case []interface{}: + // crumb-trail doesn't change, pass it on + for _, v := range iv.([]interface{}) { + hasKeyPath(crumbs, v, key, basket) + } + } +} + +var PathNotExistError = errors.New("Path does not exist") + +// ValueForPath wraps ValuesFor Path and returns the first value returned. +// If no value is found it returns 'nil' and PathNotExistError. +func (mv Map) ValueForPath(path string) (interface{}, error) { + vals, err := mv.ValuesForPath(path) + if err != nil { + return nil, err + } + if len(vals) == 0 { + return nil, PathNotExistError + } + return vals[0], nil +} + +// ValuesForPathString returns the first found value for the path as a string. +func (mv Map) ValueForPathString(path string) (string, error) { + vals, err := mv.ValuesForPath(path) + if err != nil { + return "", err + } + if len(vals) == 0 { + return "", errors.New("ValueForPath: path not found") + } + val := vals[0] + return fmt.Sprintf("%v", val), nil +} + +// ValueOrEmptyForPathString returns the first found value for the path as a string. +// If the path is not found then it returns an empty string. +func (mv Map) ValueOrEmptyForPathString(path string) string { + str, _ := mv.ValueForPathString(path) + return str +} diff --git a/vendor/github.com/clbanning/mxj/v2/leafnode.go b/vendor/github.com/clbanning/mxj/v2/leafnode.go new file mode 100644 index 000000000..cf413ebdd --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/leafnode.go @@ -0,0 +1,112 @@ +package mxj + +// leafnode.go - return leaf nodes with paths and values for the Map +// inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw + +import ( + "strconv" + "strings" +) + +const ( + NoAttributes = true // suppress LeafNode values that are attributes +) + +// LeafNode - a terminal path value in a Map. +// For XML Map values it represents an attribute or simple element value - of type +// string unless Map was created using Cast flag. For JSON Map values it represents +// a string, numeric, boolean, or null value. +type LeafNode struct { + Path string // a dot-notation representation of the path with array subscripting + Value interface{} // the value at the path termination +} + +// LeafNodes - returns an array of all LeafNode values for the Map. +// The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-') +// as well as the "#text" key for the associated simple element value. +// +// PrependAttrWithHypen(false) will result in attributes having .attr-name as +// terminal node in 'path' while the path for the element value, itself, will be +// the base path w/o "#text". +// +// LeafUseDotNotation(true) causes list members to be identified using ".N" syntax +// rather than "[N]" syntax. +func (mv Map) LeafNodes(no_attr ...bool) []LeafNode { + var a bool + if len(no_attr) == 1 { + a = no_attr[0] + } + + l := make([]LeafNode, 0) + getLeafNodes("", "", map[string]interface{}(mv), &l, a) + return l +} + +func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) { + // if stripping attributes, then also strip "#text" key + if !noattr || node != "#text" { + if path != "" && node[:1] != "[" { + path += "." + } + path += node + } + switch mv.(type) { + case map[string]interface{}: + for k, v := range mv.(map[string]interface{}) { + // if noattr && k[:1] == "-" { + if noattr && len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 { + continue + } + getLeafNodes(path, k, v, l, noattr) + } + case []interface{}: + for i, v := range mv.([]interface{}) { + if useDotNotation { + getLeafNodes(path, strconv.Itoa(i), v, l, noattr) + } else { + getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr) + } + } + default: + // can't walk any further, so create leaf + n := LeafNode{path, mv} + *l = append(*l, n) + } +} + +// LeafPaths - all paths that terminate in LeafNode values. +func (mv Map) LeafPaths(no_attr ...bool) []string { + ln := mv.LeafNodes() + ss := make([]string, len(ln)) + for i := 0; i < len(ln); i++ { + ss[i] = ln[i].Path + } + return ss +} + +// LeafValues - all terminal values in the Map. +func (mv Map) LeafValues(no_attr ...bool) []interface{} { + ln := mv.LeafNodes() + vv := make([]interface{}, len(ln)) + for i := 0; i < len(ln); i++ { + vv[i] = ln[i].Value + } + return vv +} + +// ====================== utilities ====================== + +// https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I +var useDotNotation bool + +// LeafUseDotNotation sets a flag that list members in LeafNode paths +// should be identified using ".N" syntax rather than the default "[N]" +// syntax. Calling LeafUseDotNotation with no arguments toggles the +// flag on/off; otherwise, the argument sets the flag value 'true'/'false'. +func LeafUseDotNotation(b ...bool) { + if len(b) == 0 { + useDotNotation = !useDotNotation + return + } + useDotNotation = b[0] +} diff --git a/vendor/github.com/clbanning/mxj/v2/misc.go b/vendor/github.com/clbanning/mxj/v2/misc.go new file mode 100644 index 000000000..5b4fab216 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/misc.go @@ -0,0 +1,86 @@ +// Copyright 2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// misc.go - mimic functions (+others) called out in: +// https://groups.google.com/forum/#!topic/golang-nuts/jm_aGsJNbdQ +// Primarily these methods let you retrive XML structure information. + +package mxj + +import ( + "fmt" + "sort" + "strings" +) + +// Return the root element of the Map. If there is not a single key in Map, +// then an error is returned. +func (mv Map) Root() (string, error) { + mm := map[string]interface{}(mv) + if len(mm) != 1 { + return "", fmt.Errorf("Map does not have singleton root. Len: %d.", len(mm)) + } + for k, _ := range mm { + return k, nil + } + return "", nil +} + +// If the path is an element with sub-elements, return a list of the sub-element +// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are prefixed with +// '-', a hyphen, are considered attributes; see m.Attributes(path). +func (mv Map) Elements(path string) ([]string, error) { + e, err := mv.ValueForPath(path) + if err != nil { + return nil, err + } + switch e.(type) { + case map[string]interface{}: + ee := e.(map[string]interface{}) + elems := make([]string, len(ee)) + var i int + for k, _ := range ee { + if len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 { + continue // skip attributes + } + elems[i] = k + i++ + } + elems = elems[:i] + // alphabetic sort keeps things tidy + sort.Strings(elems) + return elems, nil + } + return nil, fmt.Errorf("no elements for path: %s", path) +} + +// If the path is an element with attributes, return a list of the attribute +// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are not prefixed with +// '-', a hyphen, are not treated as attributes; see m.Elements(path). Also, if the +// attribute prefix is "" - SetAttrPrefix("") or PrependAttrWithHyphen(false) - then +// there are no identifiable attributes. +func (mv Map) Attributes(path string) ([]string, error) { + a, err := mv.ValueForPath(path) + if err != nil { + return nil, err + } + switch a.(type) { + case map[string]interface{}: + aa := a.(map[string]interface{}) + attrs := make([]string, len(aa)) + var i int + for k, _ := range aa { + if len(attrPrefix) == 0 || strings.Index(k, attrPrefix) != 0 { + continue // skip non-attributes + } + attrs[i] = k[len(attrPrefix):] + i++ + } + attrs = attrs[:i] + // alphabetic sort keeps things tidy + sort.Strings(attrs) + return attrs, nil + } + return nil, fmt.Errorf("no attributes for path: %s", path) +} diff --git a/vendor/github.com/clbanning/mxj/v2/mxj.go b/vendor/github.com/clbanning/mxj/v2/mxj.go new file mode 100644 index 000000000..f0592f06c --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/mxj.go @@ -0,0 +1,128 @@ +// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. +// Copyright 2012-2014 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "fmt" + "sort" +) + +const ( + Cast = true // for clarity - e.g., mxj.NewMapXml(doc, mxj.Cast) + SafeEncoding = true // ditto - e.g., mv.Json(mxj.SafeEncoding) +) + +type Map map[string]interface{} + +// Allocate a Map. +func New() Map { + m := make(map[string]interface{}, 0) + return m +} + +// Cast a Map to map[string]interface{} +func (mv Map) Old() map[string]interface{} { + return mv +} + +// Return a copy of mv as a newly allocated Map. If the Map only contains string, +// numeric, map[string]interface{}, and []interface{} values, then it can be thought +// of as a "deep copy." Copying a structure (or structure reference) value is subject +// to the noted restrictions. +// NOTE: If 'mv' includes structure values with, possibly, JSON encoding tags +// then only public fields of the structure are in the new Map - and with +// keys that conform to any encoding tag instructions. The structure itself will +// be represented as a map[string]interface{} value. +func (mv Map) Copy() (Map, error) { + // this is the poor-man's deep copy + // not efficient, but it works + j, jerr := mv.Json() + // must handle, we don't know how mv got built + if jerr != nil { + return nil, jerr + } + return NewMapJson(j) +} + +// --------------- StringIndent ... from x2j.WriteMap ------------- + +// Pretty print a Map. +func (mv Map) StringIndent(offset ...int) string { + return writeMap(map[string]interface{}(mv), true, true, offset...) +} + +// Pretty print a Map without the value type information - just key:value entries. +func (mv Map) StringIndentNoTypeInfo(offset ...int) string { + return writeMap(map[string]interface{}(mv), false, true, offset...) +} + +// writeMap - dumps the map[string]interface{} for examination. +// 'typeInfo' causes value type to be printed. +// 'offset' is initial indentation count; typically: Write(m). +func writeMap(m interface{}, typeInfo, root bool, offset ...int) string { + var indent int + if len(offset) == 1 { + indent = offset[0] + } + + var s string + switch m.(type) { + case []interface{}: + if typeInfo { + s += "[[]interface{}]" + } + for _, v := range m.([]interface{}) { + s += "\n" + for i := 0; i < indent; i++ { + s += " " + } + s += writeMap(v, typeInfo, false, indent+1) + } + case map[string]interface{}: + list := make([][2]string, len(m.(map[string]interface{}))) + var n int + for k, v := range m.(map[string]interface{}) { + list[n][0] = k + list[n][1] = writeMap(v, typeInfo, false, indent+1) + n++ + } + sort.Sort(mapList(list)) + for _, v := range list { + if root { + root = false + } else { + s += "\n" + } + for i := 0; i < indent; i++ { + s += " " + } + s += v[0] + " : " + v[1] + } + default: + if typeInfo { + s += fmt.Sprintf("[%T] %+v", m, m) + } else { + s += fmt.Sprintf("%+v", m) + } + } + return s +} + +// ======================== utility =============== + +type mapList [][2]string + +func (ml mapList) Len() int { + return len(ml) +} + +func (ml mapList) Swap(i, j int) { + ml[i], ml[j] = ml[j], ml[i] +} + +func (ml mapList) Less(i, j int) bool { + return ml[i][0] <= ml[j][0] +} diff --git a/vendor/github.com/clbanning/mxj/v2/newmap.go b/vendor/github.com/clbanning/mxj/v2/newmap.go new file mode 100644 index 000000000..b29394905 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/newmap.go @@ -0,0 +1,184 @@ +// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. +// Copyright 2012-2014, 2018 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// remap.go - build a new Map from the current Map based on keyOld:keyNew mapppings +// keys can use dot-notation, keyOld can use wildcard, '*' +// +// Computational strategy - +// Using the key path - []string - traverse a new map[string]interface{} and +// insert the oldVal as the newVal when we arrive at the end of the path. +// If the type at the end is nil, then that is newVal +// If the type at the end is a singleton (string, float64, bool) an array is created. +// If the type at the end is an array, newVal is just appended. +// If the type at the end is a map, it is inserted if possible or the map value +// is converted into an array if necessary. + +package mxj + +import ( + "errors" + "strings" +) + +// (Map)NewMap - create a new Map from data in the current Map. +// 'keypairs' are key mappings "oldKey:newKey" and specify that the current value of 'oldKey' +// should be the value for 'newKey' in the returned Map. +// - 'oldKey' supports dot-notation as described for (Map)ValuesForPath() +// - 'newKey' supports dot-notation but with no wildcards, '*', or indexed arrays +// - "oldKey" is shorthand for the keypair value "oldKey:oldKey" +// - "oldKey:" and ":newKey" are invalid keypair values +// - if 'oldKey' does not exist in the current Map, it is not written to the new Map. +// "null" is not supported unless it is the current Map. +// - see newmap_test.go for several syntax examples +// - mv.NewMap() == mxj.New() +// +// NOTE: "examples/partial.go" shows how to create arbitrary sub-docs of an XML doc. +func (mv Map) NewMap(keypairs ...string) (Map, error) { + n := make(map[string]interface{}, 0) + if len(keypairs) == 0 { + return n, nil + } + + // loop through the pairs + var oldKey, newKey string + var path []string + for _, v := range keypairs { + if len(v) == 0 { + continue // just skip over empty keypair arguments + } + + // initialize oldKey, newKey and check + vv := strings.Split(v, ":") + if len(vv) > 2 { + return n, errors.New("oldKey:newKey keypair value not valid - " + v) + } + if len(vv) == 1 { + oldKey, newKey = vv[0], vv[0] + } else { + oldKey, newKey = vv[0], vv[1] + } + strings.TrimSpace(oldKey) + strings.TrimSpace(newKey) + if i := strings.Index(newKey, "*"); i > -1 { + return n, errors.New("newKey value cannot contain wildcard character - " + v) + } + if i := strings.Index(newKey, "["); i > -1 { + return n, errors.New("newKey value cannot contain indexed arrays - " + v) + } + if oldKey == "" || newKey == "" { + return n, errors.New("oldKey or newKey is not specified - " + v) + } + + // get oldKey value + oldVal, err := mv.ValuesForPath(oldKey) + if err != nil { + return n, err + } + if len(oldVal) == 0 { + continue // oldKey has no value, may not exist in mv + } + + // break down path + path = strings.Split(newKey, ".") + if path[len(path)-1] == "" { // ignore a trailing dot in newKey spec + path = path[:len(path)-1] + } + + addNewVal(&n, path, oldVal) + } + + return n, nil +} + +// navigate 'n' to end of path and add val +func addNewVal(n *map[string]interface{}, path []string, val []interface{}) { + // newVal - either singleton or array + var newVal interface{} + if len(val) == 1 { + newVal = val[0] // is type interface{} + } else { + newVal = interface{}(val) + } + + // walk to the position of interest, create it if necessary + m := (*n) // initialize map walker + var k string // key for m + lp := len(path) - 1 // when to stop looking + for i := 0; i < len(path); i++ { + k = path[i] + if i == lp { + break + } + var nm map[string]interface{} // holds position of next-map + switch m[k].(type) { + case nil: // need a map for next node in path, so go there + nm = make(map[string]interface{}, 0) + m[k] = interface{}(nm) + m = m[k].(map[string]interface{}) + case map[string]interface{}: + // OK - got somewhere to walk to, go there + m = m[k].(map[string]interface{}) + case []interface{}: + // add a map and nm points to new map unless there's already + // a map in the array, then nm points there + // The placement of the next value in the array is dependent + // on the sequence of members - could land on a map or a nil + // value first. TODO: how to test this. + a := make([]interface{}, 0) + var foundmap bool + for _, vv := range m[k].([]interface{}) { + switch vv.(type) { + case nil: // doesn't appear that this occurs, need a test case + if foundmap { // use the first one in array + a = append(a, vv) + continue + } + nm = make(map[string]interface{}, 0) + a = append(a, interface{}(nm)) + foundmap = true + case map[string]interface{}: + if foundmap { // use the first one in array + a = append(a, vv) + continue + } + nm = vv.(map[string]interface{}) + a = append(a, vv) + foundmap = true + default: + a = append(a, vv) + } + } + // no map found in array + if !foundmap { + nm = make(map[string]interface{}, 0) + a = append(a, interface{}(nm)) + } + m[k] = interface{}(a) // must insert in map + m = nm + default: // it's a string, float, bool, etc. + aa := make([]interface{}, 0) + nm = make(map[string]interface{}, 0) + aa = append(aa, m[k], nm) + m[k] = interface{}(aa) + m = nm + } + } + + // value is nil, array or a singleton of some kind + // initially m.(type) == map[string]interface{} + v := m[k] + switch v.(type) { + case nil: // initialized + m[k] = newVal + case []interface{}: + a := m[k].([]interface{}) + a = append(a, newVal) + m[k] = interface{}(a) + default: // v exists:string, float64, bool, map[string]interface, etc. + a := make([]interface{}, 0) + a = append(a, v, newVal) + m[k] = interface{}(a) + } +} diff --git a/vendor/github.com/clbanning/mxj/v2/readme.md b/vendor/github.com/clbanning/mxj/v2/readme.md new file mode 100644 index 000000000..323a747d4 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/readme.md @@ -0,0 +1,207 @@ +

mxj - to/from maps, XML and JSON

+Decode/encode XML to/from map[string]interface{} (or JSON) values, and extract/modify values from maps by key or key-path, including wildcards. + +mxj supplants the legacy x2j and j2x packages. If you want the old syntax, use mxj/x2j and mxj/j2x packages. + +

Installation

+Using go.mod: +
+go get github.com/clbanning/mxj/v2@v2.3.2
+
+ +
+import "github.com/clbanning/mxj/v2"
+
+ +... or just vendor the package. + +

Related Packages

+ +https://github.com/clbanning/checkxml provides functions for validating XML data. + +

Refactor Encoder - 2020.05.01

+Issue #70 highlighted that encoding large maps does not scale well, since the original logic used string appends operations. Using bytes.Buffer results in linear scaling for very large XML docs. (Metrics based on MacBook Pro i7 w/ 16 GB.) + + Nodes m.XML() time + 54809 12.53708ms + 109780 32.403183ms + 164678 59.826412ms + 482598 109.358007ms + +

Refactor Decoder - 2015.11.15

+For over a year I've wanted to refactor the XML-to-map[string]interface{} decoder to make it more performant. I recently took the time to do that, since we were using github.com/clbanning/mxj in a production system that could be deployed on a Raspberry Pi. Now the decoder is comparable to the stdlib JSON-to-map[string]interface{} decoder in terms of its additional processing overhead relative to decoding to a structure value. As shown by: + + BenchmarkNewMapXml-4 100000 18043 ns/op + BenchmarkNewStructXml-4 100000 14892 ns/op + BenchmarkNewMapJson-4 300000 4633 ns/op + BenchmarkNewStructJson-4 300000 3427 ns/op + BenchmarkNewMapXmlBooks-4 20000 82850 ns/op + BenchmarkNewStructXmlBooks-4 20000 67822 ns/op + BenchmarkNewMapJsonBooks-4 100000 17222 ns/op + BenchmarkNewStructJsonBooks-4 100000 15309 ns/op + +

Notices

+ + 2021.02.02: v2.5 - add XmlCheckIsValid toggle to force checking that the encoded XML is valid + 2020.12.14: v2.4 - add XMLEscapeCharsDecoder to preserve XML escaped characters in Map values + 2020.10.28: v2.3 - add TrimWhiteSpace option + 2020.05.01: v2.2 - optimize map to XML encoding for large XML docs. + 2019.07.04: v2.0 - remove unnecessary methods - mv.XmlWriterRaw, mv.XmlIndentWriterRaw - for Map and MapSeq. + 2019.07.04: Add MapSeq type and move associated functions and methods from Map to MapSeq. + 2019.01.21: DecodeSimpleValuesAsMap - decode to map[:map["#text":]] rather than map[:] + 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc. + 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps. + 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package. + 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing. + 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods. + 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag(). + 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc. + 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix(). + 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable. + 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars(). + 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf". + To cast them to float64, first set flag with CastNanInf(true). + 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure. + 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization. + 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM). + 2015.12.02: XML decoding/encoding that preserves original structure of document. See NewMapXmlSeq() + and mv.XmlSeq() / mv.XmlSeqIndent(). + 2015-05-20: New: mv.StringIndentNoTypeInfo(). + Also, alphabetically sort map[string]interface{} values by key to prettify output for mv.Xml(), + mv.XmlIndent(), mv.StringIndent(), mv.StringIndentNoTypeInfo(). + 2014-11-09: IncludeTagSeqNum() adds "_seq" key with XML doc positional information. + (NOTE: PreserveXmlList() is similar and will be here soon.) + 2014-09-18: inspired by NYTimes fork, added PrependAttrWithHyphen() to allow stripping hyphen from attribute tag. + 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML. + 2014-04-28: ValuesForPath() and NewMap() now accept path with indexed array references. + +

Basic Unmarshal XML to map[string]interface{}

+
type Map map[string]interface{}
+ +Create a `Map` value, 'mv', from any `map[string]interface{}` value, 'v': +
mv := Map(v)
+ +Unmarshal / marshal XML as a `Map` value, 'mv': +
mv, err := NewMapXml(xmlValue) // unmarshal
+xmlValue, err := mv.Xml()      // marshal
+ +Unmarshal XML from an `io.Reader` as a `Map` value, 'mv': +
mv, err := NewMapXmlReader(xmlReader)         // repeated calls, as with an os.File Reader, will process stream
+mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
+ +Marshal `Map` value, 'mv', to an XML Writer (`io.Writer`): +
err := mv.XmlWriter(xmlWriter)
+raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
+ +Also, for prettified output: +
xmlValue, err := mv.XmlIndent(prefix, indent, ...)
+err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...)
+raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
+ +Bulk process XML with error handling (note: handlers must return a boolean value): +
err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
+err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
+ +Converting XML to JSON: see Examples for `NewMapXml` and `HandleXmlReader`. + +There are comparable functions and methods for JSON processing. + +Arbitrary structure values can be decoded to / encoded from `Map` values: +
mv, err := NewMapStruct(structVal)
+err := mv.Struct(structPointer)
+ +

Extract / modify Map values

+To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON +or structure to a `Map` value, 'mv', or cast a `map[string]interface{}` value to a `Map` value, 'mv', then: +
paths := mv.PathsForKey(key)
+path := mv.PathForKeyShortest(key)
+values, err := mv.ValuesForKey(key, subkeys)
+values, err := mv.ValuesForPath(path, subkeys)
+count, err := mv.UpdateValuesForPath(newVal, path, subkeys)
+ +Get everything at once, irrespective of path depth: +
leafnodes := mv.LeafNodes()
+leafvalues := mv.LeafValues()
+ +A new `Map` with whatever keys are desired can be created from the current `Map` and then encoded in XML +or JSON. (Note: keys can use dot-notation.) +
newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
+newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
+newXml, err := newMap.Xml()   // for example
+newJson, err := newMap.Json() // ditto
+ +

Usage

+ +The package is fairly well [self-documented with examples](http://godoc.org/github.com/clbanning/mxj). + +Also, the subdirectory "examples" contains a wide range of examples, several taken from golang-nuts discussions. + +

XML parsing conventions

+ +Using NewMapXml() + + - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`, + to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or + `SetAttrPrefix()`.) + - If the element is a simple element and has attributes, the element value + is given the key `#text` for its `map[string]interface{}` representation. (See + the 'atomFeedString.xml' test data, below.) + - XML comments, directives, and process instructions are ignored. + - If CoerceKeysToLower() has been called, then the resultant keys will be lower case. + +Using NewMapXmlSeq() + + - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values + where the `` value has "#text" and "#seq" keys - the "#text" key holds the + value for ``. + - All elements, except for the root, have a "#seq" key. + - Comments, directives, and process instructions are unmarshalled into the Map using the + keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more + specifics.) + - Name space syntax is preserved: + - `something` parses to `map["ns:key"]interface{}{"something"}` + - `xmlns:ns="http://myns.com/ns"` parses to `map["xmlns:ns"]interface{}{"http://myns.com/ns"}` + +Both + + - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them + to be cast, set a flag to cast them using CastNanInf(true). + +

XML encoding conventions

+ + - 'nil' `Map` values, which may represent 'null' JSON values, are encoded as ``. + NOTE: the operation is not symmetric as `` elements are decoded as `tag:""` `Map` values, + which, then, encode in JSON as `"tag":""` values. + - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go + randomizes the walk through map[string]interface{} values.) If you plan to re-encode the + Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and + mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when + working with the Map representation. + +

Running "go test"

+ +Because there are no guarantees on the sequence map elements are retrieved, the tests have been +written for visual verification in most cases. One advantage is that you can easily use the +output from running "go test" as examples of calling the various functions and methods. + +

Motivation

+ +I make extensive use of JSON for messaging and typically unmarshal the messages into +`map[string]interface{}` values. This is easily done using `json.Unmarshal` from the +standard Go libraries. Unfortunately, many legacy solutions use structured +XML messages; in those environments the applications would have to be refactored to +interoperate with my components. + +The better solution is to just provide an alternative HTTP handler that receives +XML messages and parses it into a `map[string]interface{}` value and then reuse +all the JSON-based code. The Go `xml.Unmarshal()` function does not provide the same +option of unmarshaling XML messages into `map[string]interface{}` values. So I wrote +a couple of small functions to fill this gap and released them as the x2j package. + +Over the next year and a half additional features were added, and the companion j2x +package was released to address XML encoding of arbitrary JSON and `map[string]interface{}` +values. As part of a refactoring of our production system and looking at how we had been +using the x2j and j2x packages we found that we rarely performed direct XML-to-JSON or +JSON-to_XML conversion and that working with the XML or JSON as `map[string]interface{}` +values was the primary value. Thus, everything was refactored into the mxj package. + diff --git a/vendor/github.com/clbanning/mxj/v2/remove.go b/vendor/github.com/clbanning/mxj/v2/remove.go new file mode 100644 index 000000000..8362ab17f --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/remove.go @@ -0,0 +1,37 @@ +package mxj + +import "strings" + +// Removes the path. +func (mv Map) Remove(path string) error { + m := map[string]interface{}(mv) + return remove(m, path) +} + +func remove(m interface{}, path string) error { + val, err := prevValueByPath(m, path) + if err != nil { + return err + } + + lastKey := lastKey(path) + delete(val, lastKey) + + return nil +} + +// returns the last key of the path. +// lastKey("a.b.c") would had returned "c" +func lastKey(path string) string { + keys := strings.Split(path, ".") + key := keys[len(keys)-1] + return key +} + +// returns the path without the last key +// parentPath("a.b.c") whould had returned "a.b" +func parentPath(path string) string { + keys := strings.Split(path, ".") + parentPath := strings.Join(keys[0:len(keys)-1], ".") + return parentPath +} diff --git a/vendor/github.com/clbanning/mxj/v2/rename.go b/vendor/github.com/clbanning/mxj/v2/rename.go new file mode 100644 index 000000000..4c655ed5d --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/rename.go @@ -0,0 +1,61 @@ +package mxj + +import ( + "errors" + "strings" +) + +// RenameKey renames a key in a Map. +// It works only for nested maps. +// It doesn't work for cases when the key is in a list. +func (mv Map) RenameKey(path string, newName string) error { + var v bool + var err error + if v, err = mv.Exists(path); err == nil && !v { + return errors.New("RenameKey: path not found: " + path) + } else if err != nil { + return err + } + if v, err = mv.Exists(parentPath(path) + "." + newName); err == nil && v { + return errors.New("RenameKey: key already exists: " + newName) + } else if err != nil { + return err + } + + m := map[string]interface{}(mv) + return renameKey(m, path, newName) +} + +func renameKey(m interface{}, path string, newName string) error { + val, err := prevValueByPath(m, path) + if err != nil { + return err + } + + oldName := lastKey(path) + val[newName] = val[oldName] + delete(val, oldName) + + return nil +} + +// returns a value which contains a last key in the path +// For example: prevValueByPath("a.b.c", {a{b{c: 3}}}) returns {c: 3} +func prevValueByPath(m interface{}, path string) (map[string]interface{}, error) { + keys := strings.Split(path, ".") + + switch mValue := m.(type) { + case map[string]interface{}: + for key, value := range mValue { + if key == keys[0] { + if len(keys) == 1 { + return mValue, nil + } else { + // keep looking for the full path to the key + return prevValueByPath(value, strings.Join(keys[1:], ".")) + } + } + } + } + return nil, errors.New("prevValueByPath: didn't find path – " + path) +} diff --git a/vendor/github.com/clbanning/mxj/v2/set.go b/vendor/github.com/clbanning/mxj/v2/set.go new file mode 100644 index 000000000..a297fc388 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/set.go @@ -0,0 +1,26 @@ +package mxj + +import ( + "strings" +) + +// Sets the value for the path +func (mv Map) SetValueForPath(value interface{}, path string) error { + pathAry := strings.Split(path, ".") + parentPathAry := pathAry[0 : len(pathAry)-1] + parentPath := strings.Join(parentPathAry, ".") + + val, err := mv.ValueForPath(parentPath) + if err != nil { + return err + } + if val == nil { + return nil // we just ignore the request if there's no val + } + + key := pathAry[len(pathAry)-1] + cVal := val.(map[string]interface{}) + cVal[key] = value + + return nil +} diff --git a/vendor/github.com/clbanning/mxj/v2/setfieldsep.go b/vendor/github.com/clbanning/mxj/v2/setfieldsep.go new file mode 100644 index 000000000..b70715ebc --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/setfieldsep.go @@ -0,0 +1,20 @@ +package mxj + +// Per: https://github.com/clbanning/mxj/issues/37#issuecomment-278651862 +var fieldSep string = ":" + +// SetFieldSeparator changes the default field separator, ":", for the +// newVal argument in mv.UpdateValuesForPath and the optional 'subkey' arguments +// in mv.ValuesForKey and mv.ValuesForPath. +// +// E.g., if the newVal value is "http://blah/blah", setting the field separator +// to "|" will allow the newVal specification, "|http://blah/blah" to parse +// properly. If called with no argument or an empty string value, the field +// separator is set to the default, ":". +func SetFieldSeparator(s ...string) { + if len(s) == 0 || s[0] == "" { + fieldSep = ":" // the default + return + } + fieldSep = s[0] +} diff --git a/vendor/github.com/clbanning/mxj/v2/songtext.xml b/vendor/github.com/clbanning/mxj/v2/songtext.xml new file mode 100644 index 000000000..8c0f2becb --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/songtext.xml @@ -0,0 +1,29 @@ + + help me! + + + + Henry was a renegade + Didn't like to play it safe + One component at a time + There's got to be a better way + Oh, people came from miles around + Searching for a steady job + Welcome to the Motor Town + Booming like an atom bomb + + + Oh, Henry was the end of the story + Then everything went wrong + And we'll return it to its former glory + But it just takes so long + + + + It's going to take a long time + It's going to take it, but we'll make it one day + It's going to take a long time + It's going to take it, but we'll make it one day + + + diff --git a/vendor/github.com/clbanning/mxj/v2/strict.go b/vendor/github.com/clbanning/mxj/v2/strict.go new file mode 100644 index 000000000..1e769560b --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/strict.go @@ -0,0 +1,30 @@ +// Copyright 2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// strict.go actually addresses setting xml.Decoder attribute +// values. This'll let you parse non-standard XML. + +package mxj + +import ( + "encoding/xml" +) + +// CustomDecoder can be used to specify xml.Decoder attribute +// values, e.g., Strict:false, to be used. By default CustomDecoder +// is nil. If CustomeDecoder != nil, then mxj.XmlCharsetReader variable is +// ignored and must be set as part of the CustomDecoder value, if needed. +// Usage: +// mxj.CustomDecoder = &xml.Decoder{Strict:false} +var CustomDecoder *xml.Decoder + +// useCustomDecoder copy over public attributes from customDecoder +func useCustomDecoder(d *xml.Decoder) { + d.Strict = CustomDecoder.Strict + d.AutoClose = CustomDecoder.AutoClose + d.Entity = CustomDecoder.Entity + d.CharsetReader = CustomDecoder.CharsetReader + d.DefaultSpace = CustomDecoder.DefaultSpace +} + diff --git a/vendor/github.com/clbanning/mxj/v2/struct.go b/vendor/github.com/clbanning/mxj/v2/struct.go new file mode 100644 index 000000000..9be636cdc --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/struct.go @@ -0,0 +1,54 @@ +// Copyright 2012-2017 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "encoding/json" + "errors" + "reflect" + + // "github.com/fatih/structs" +) + +// Create a new Map value from a structure. Error returned if argument is not a structure. +// Only public structure fields are decoded in the Map value. See github.com/fatih/structs#Map +// for handling of "structs" tags. + +// DEPRECATED - import github.com/fatih/structs and cast result of structs.Map to mxj.Map. +// import "github.com/fatih/structs" +// ... +// sm, err := structs.Map() +// if err != nil { +// // handle error +// } +// m := mxj.Map(sm) +// Alernatively uncomment the old source and import in struct.go. +func NewMapStruct(structVal interface{}) (Map, error) { + return nil, errors.New("deprecated - see package documentation") + /* + if !structs.IsStruct(structVal) { + return nil, errors.New("NewMapStruct() error: argument is not type Struct") + } + return structs.Map(structVal), nil + */ +} + +// Marshal a map[string]interface{} into a structure referenced by 'structPtr'. Error returned +// if argument is not a pointer or if json.Unmarshal returns an error. +// json.Unmarshal structure encoding rules are followed to encode public structure fields. +func (mv Map) Struct(structPtr interface{}) error { + // should check that we're getting a pointer. + if reflect.ValueOf(structPtr).Kind() != reflect.Ptr { + return errors.New("mv.Struct() error: argument is not type Ptr") + } + + m := map[string]interface{}(mv) + j, err := json.Marshal(m) + if err != nil { + return err + } + + return json.Unmarshal(j, structPtr) +} diff --git a/vendor/github.com/clbanning/mxj/v2/updatevalues.go b/vendor/github.com/clbanning/mxj/v2/updatevalues.go new file mode 100644 index 000000000..9e10d84e8 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/updatevalues.go @@ -0,0 +1,258 @@ +// Copyright 2012-2014, 2017 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// updatevalues.go - modify a value based on path and possibly sub-keys +// TODO(clb): handle simple elements with attributes and NewMapXmlSeq Map values. + +package mxj + +import ( + "fmt" + "strconv" + "strings" +) + +// Update value based on path and possible sub-key values. +// A count of the number of values changed and any error are returned. +// If the count == 0, then no path (and subkeys) matched. +// 'newVal' can be a Map or map[string]interface{} value with a single 'key' that is the key to be modified +// or a string value "key:value[:type]" where type is "bool" or "num" to cast the value. +// 'path' is dot-notation list of keys to traverse; last key in path can be newVal key +// NOTE: 'path' spec does not currently support indexed array references. +// 'subkeys' are "key:value[:type]" entries that must match for path node +// - For attributes prefix the label with the attribute prefix character, by default a +// hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.) +// - The subkey can be wildcarded - "key:*" - to require that it's there with some value. +// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an +// exclusion critera - e.g., "!author:William T. Gaddis". +// +// NOTES: +// 1. Simple elements with attributes need a path terminated as ".#text" to modify the actual value. +// 2. Values in Maps created using NewMapXmlSeq are map[string]interface{} values with a "#text" key. +// 3. If values in 'newVal' or 'subkeys' args contain ":", use SetFieldSeparator to an unused symbol, +// perhaps "|". +func (mv Map) UpdateValuesForPath(newVal interface{}, path string, subkeys ...string) (int, error) { + m := map[string]interface{}(mv) + + // extract the subkeys + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return 0, err + } + } + + // extract key and value from newVal + var key string + var val interface{} + switch newVal.(type) { + case map[string]interface{}, Map: + switch newVal.(type) { // "fallthrough is not permitted in type switch" (Spec) + case Map: + newVal = newVal.(Map).Old() + } + if len(newVal.(map[string]interface{})) != 1 { + return 0, fmt.Errorf("newVal map can only have len == 1 - %+v", newVal) + } + for key, val = range newVal.(map[string]interface{}) { + } + case string: // split it as a key:value pair + ss := strings.Split(newVal.(string), fieldSep) + n := len(ss) + if n < 2 || n > 3 { + return 0, fmt.Errorf("unknown newVal spec - %+v", newVal) + } + key = ss[0] + if n == 2 { + val = interface{}(ss[1]) + } else if n == 3 { + switch ss[2] { + case "bool", "boolean": + nv, err := strconv.ParseBool(ss[1]) + if err != nil { + return 0, fmt.Errorf("can't convert newVal to bool - %+v", newVal) + } + val = interface{}(nv) + case "num", "numeric", "float", "int": + nv, err := strconv.ParseFloat(ss[1], 64) + if err != nil { + return 0, fmt.Errorf("can't convert newVal to float64 - %+v", newVal) + } + val = interface{}(nv) + default: + return 0, fmt.Errorf("unknown type for newVal value - %+v", newVal) + } + } + default: + return 0, fmt.Errorf("invalid newVal type - %+v", newVal) + } + + // parse path + keys := strings.Split(path, ".") + + var count int + updateValuesForKeyPath(key, val, m, keys, subKeyMap, &count) + + return count, nil +} + +// navigate the path +func updateValuesForKeyPath(key string, value interface{}, m interface{}, keys []string, subkeys map[string]interface{}, cnt *int) { + // ----- at end node: looking at possible node to get 'key' ---- + if len(keys) == 1 { + updateValue(key, value, m, keys[0], subkeys, cnt) + return + } + + // ----- here we are navigating the path thru the penultimate node -------- + // key of interest is keys[0] - the next in the path + switch keys[0] { + case "*": // wildcard - scan all values + switch m.(type) { + case map[string]interface{}: + for _, v := range m.(map[string]interface{}) { + updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) + } + case []interface{}: + for _, v := range m.([]interface{}) { + switch v.(type) { + // flatten out a list of maps - keys are processed + case map[string]interface{}: + for _, vv := range v.(map[string]interface{}) { + updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt) + } + default: + updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) + } + } + } + default: // key - must be map[string]interface{} + switch m.(type) { + case map[string]interface{}: + if v, ok := m.(map[string]interface{})[keys[0]]; ok { + updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) + } + case []interface{}: // may be buried in list + for _, v := range m.([]interface{}) { + switch v.(type) { + case map[string]interface{}: + if vv, ok := v.(map[string]interface{})[keys[0]]; ok { + updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt) + } + } + } + } + } +} + +// change value if key and subkeys are present +func updateValue(key string, value interface{}, m interface{}, keys0 string, subkeys map[string]interface{}, cnt *int) { + // there are two possible options for the value of 'keys0': map[string]interface, []interface{} + // and 'key' is a key in the map or is a key in a map in a list. + switch m.(type) { + case map[string]interface{}: // gotta have the last key + if keys0 == "*" { + for k := range m.(map[string]interface{}) { + updateValue(key, value, m, k, subkeys, cnt) + } + return + } + endVal, _ := m.(map[string]interface{})[keys0] + + // if newV key is the end of path, replace the value for path-end + // may be []interface{} - means replace just an entry w/ subkeys + // otherwise replace the keys0 value if subkeys are there + // NOTE: this will replace the subkeys, also + if key == keys0 { + switch endVal.(type) { + case map[string]interface{}: + if hasSubKeys(m, subkeys) { + (m.(map[string]interface{}))[keys0] = value + (*cnt)++ + } + case []interface{}: + // without subkeys can't select list member to modify + // so key:value spec is it ... + if hasSubKeys(m, subkeys) { + (m.(map[string]interface{}))[keys0] = value + (*cnt)++ + break + } + nv := make([]interface{}, 0) + var valmodified bool + for _, v := range endVal.([]interface{}) { + // check entry subkeys + if hasSubKeys(v, subkeys) { + // replace v with value + nv = append(nv, value) + valmodified = true + (*cnt)++ + continue + } + nv = append(nv, v) + } + if valmodified { + (m.(map[string]interface{}))[keys0] = interface{}(nv) + } + default: // anything else is a strict replacement + if hasSubKeys(m, subkeys) { + (m.(map[string]interface{}))[keys0] = value + (*cnt)++ + } + } + return + } + + // so value is for an element of endVal + // if endVal is a map then 'key' must be there w/ subkeys + // if endVal is a list then 'key' must be in a list member w/ subkeys + switch endVal.(type) { + case map[string]interface{}: + if !hasSubKeys(endVal, subkeys) { + return + } + if _, ok := (endVal.(map[string]interface{}))[key]; ok { + (endVal.(map[string]interface{}))[key] = value + (*cnt)++ + } + case []interface{}: // keys0 points to a list, check subkeys + for _, v := range endVal.([]interface{}) { + // got to be a map so we can replace value for 'key' + vv, vok := v.(map[string]interface{}) + if !vok { + continue + } + if _, ok := vv[key]; !ok { + continue + } + if !hasSubKeys(vv, subkeys) { + continue + } + vv[key] = value + (*cnt)++ + } + } + case []interface{}: // key may be in a list member + // don't need to handle keys0 == "*"; we're looking at everything, anyway. + for _, v := range m.([]interface{}) { + // only map values - we're looking for 'key' + mm, ok := v.(map[string]interface{}) + if !ok { + continue + } + if _, ok := mm[key]; !ok { + continue + } + if !hasSubKeys(mm, subkeys) { + continue + } + mm[key] = value + (*cnt)++ + } + } + + // return +} diff --git a/vendor/github.com/clbanning/mxj/v2/xml.go b/vendor/github.com/clbanning/mxj/v2/xml.go new file mode 100644 index 000000000..9aa042339 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/xml.go @@ -0,0 +1,1410 @@ +// Copyright 2012-2016, 2018-2019 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// xml.go - basically the core of X2j for map[string]interface{} values. +// NewMapXml, NewMapXmlReader, mv.Xml, mv.XmlWriter +// see x2j and j2x for wrappers to provide end-to-end transformation of XML and JSON messages. + +package mxj + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "reflect" + "sort" + "strconv" + "strings" + "time" +) + +// ------------------- NewMapXml & NewMapXmlReader ... ------------------------- + +// If XmlCharsetReader != nil, it will be used to decode the XML, if required. +// Note: if CustomDecoder != nil, then XmlCharsetReader is ignored; +// set the CustomDecoder attribute instead. +// import ( +// charset "code.google.com/p/go-charset/charset" +// github.com/clbanning/mxj +// ) +// ... +// mxj.XmlCharsetReader = charset.NewReader +// m, merr := mxj.NewMapXml(xmlValue) +var XmlCharsetReader func(charset string, input io.Reader) (io.Reader, error) + +// NewMapXml - convert a XML doc into a Map +// (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().) +// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible. +// +// Converting XML to JSON is a simple as: +// ... +// mapVal, merr := mxj.NewMapXml(xmlVal) +// if merr != nil { +// // handle error +// } +// jsonVal, jerr := mapVal.Json() +// if jerr != nil { +// // handle error +// } +// +// NOTES: +// 1. Declarations, directives, process instructions and comments are NOT parsed. +// 2. The 'xmlVal' will be parsed looking for an xml.StartElement, so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 3. If CoerceKeysToLower() has been called, then all key values will be lower case. +// 4. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +// 5. If DisableTrimWhiteSpace(b bool) has been called, then all values will be trimmed or not. 'true' by default. +func NewMapXml(xmlVal []byte, cast ...bool) (Map, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + return xmlToMap(xmlVal, r) +} + +// Get next XML doc from an io.Reader as a Map value. Returns Map value. +// NOTES: +// 1. Declarations, directives, process instructions and comments are NOT parsed. +// 2. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 3. If CoerceKeysToLower() has been called, then all key values will be lower case. +// 4. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXmlReader(xmlReader io.Reader, cast ...bool) (Map, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + + // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder + // will wrap it in a bufio.Reader and seek on the file beyond where the + // xml.Decoder parses! + if _, ok := xmlReader.(io.ByteReader); !ok { + xmlReader = myByteReader(xmlReader) // see code at EOF + } + + // build the map + return xmlReaderToMap(xmlReader, r) +} + +// Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML. +// NOTES: +// 1. Declarations, directives, process instructions and comments are NOT parsed. +// 2. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte +// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact. +// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large +// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body +// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call. +// 3. The 'raw' return value may be larger than the XML text value. +// 4. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 5. If CoerceKeysToLower() has been called, then all key values will be lower case. +// 6. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXmlReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + // create TeeReader so we can retrieve raw XML + buf := make([]byte, 0) + wb := bytes.NewBuffer(buf) + trdr := myTeeReader(xmlReader, wb) // see code at EOF + + m, err := xmlReaderToMap(trdr, r) + + // retrieve the raw XML that was decoded + b := wb.Bytes() + + if err != nil { + return nil, b, err + } + + return m, b, nil +} + +// xmlReaderToMap() - parse a XML io.Reader to a map[string]interface{} value +func xmlReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) { + // parse the Reader + p := xml.NewDecoder(rdr) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlToMapParser("", nil, p, r) +} + +// xmlToMap - convert a XML doc into map[string]interface{} value +func xmlToMap(doc []byte, r bool) (map[string]interface{}, error) { + b := bytes.NewReader(doc) + p := xml.NewDecoder(b) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlToMapParser("", nil, p, r) +} + +// ===================================== where the work happens ============================= + +// PrependAttrWithHyphen. Prepend attribute tags with a hyphen. +// Default is 'true'. (Not applicable to NewMapXmlSeq(), mv.XmlSeq(), etc.) +// Note: +// If 'false', unmarshaling and marshaling is not symmetric. Attributes will be +// marshal'd as attr and may be part of a list. +func PrependAttrWithHyphen(v bool) { + if v { + attrPrefix = "-" + lenAttrPrefix = len(attrPrefix) + return + } + attrPrefix = "" + lenAttrPrefix = len(attrPrefix) +} + +// Include sequence id with inner tags. - per Sean Murphy, murphysean84@gmail.com. +var includeTagSeqNum bool + +// IncludeTagSeqNum - include a "_seq":N key:value pair with each inner tag, denoting +// its position when parsed. This is of limited usefulness, since list values cannot +// be tagged with "_seq" without changing their depth in the Map. +// So THIS SHOULD BE USED WITH CAUTION - see the test cases. Here's a sample of what +// you get. +/* + + + + + hello + + + parses as: + + { + Obj:{ + "-c":"la", + "-h":"da", + "-x":"dee", + "intObj":[ + { + "-id"="3", + "_seq":"0" // if mxj.Cast is passed, then: "_seq":0 + }, + { + "-id"="2", + "_seq":"2" + }], + "intObj1":{ + "-id":"1", + "_seq":"1" + }, + "StrObj":{ + "#text":"hello", // simple element value gets "#text" tag + "_seq":"3" + } + } + } +*/ +func IncludeTagSeqNum(b ...bool) { + if len(b) == 0 { + includeTagSeqNum = !includeTagSeqNum + } else if len(b) == 1 { + includeTagSeqNum = b[0] + } +} + +// all keys will be "lower case" +var lowerCase bool + +// Coerce all tag values to keys in lower case. This is useful if you've got sources with variable +// tag capitalization, and you want to use m.ValuesForKeys(), etc., with the key or path spec +// in lower case. +// CoerceKeysToLower() will toggle the coercion flag true|false - on|off +// CoerceKeysToLower(true|false) will set the coercion flag on|off +// +// NOTE: only recognized by NewMapXml, NewMapXmlReader, and NewMapXmlReaderRaw functions as well as +// the associated HandleXmlReader and HandleXmlReaderRaw. +func CoerceKeysToLower(b ...bool) { + if len(b) == 0 { + lowerCase = !lowerCase + } else if len(b) == 1 { + lowerCase = b[0] + } +} + +// disableTrimWhiteSpace sets if the white space should be removed or not +var disableTrimWhiteSpace bool +var trimRunes = "\t\r\b\n " + +// DisableTrimWhiteSpace set if the white space should be trimmed or not. By default white space is always trimmed. If +// no argument is provided, trim white space will be disabled. +func DisableTrimWhiteSpace(b ...bool) { + if len(b) == 0 { + disableTrimWhiteSpace = true + } else { + disableTrimWhiteSpace = b[0] + } + + if disableTrimWhiteSpace { + trimRunes = "\t\r\b\n" + } else { + trimRunes = "\t\r\b\n " + } +} + +// 25jun16: Allow user to specify the "prefix" character for XML attribute key labels. +// We do this by replacing '`' constant with attrPrefix var, replacing useHyphen with attrPrefix = "", +// and adding a SetAttrPrefix(s string) function. + +var attrPrefix string = `-` // the default +var lenAttrPrefix int = 1 // the default + +// SetAttrPrefix changes the default, "-", to the specified value, s. +// SetAttrPrefix("") is the same as PrependAttrWithHyphen(false). +// (Not applicable for NewMapXmlSeq(), mv.XmlSeq(), etc.) +func SetAttrPrefix(s string) { + attrPrefix = s + lenAttrPrefix = len(attrPrefix) +} + +// 18jan17: Allows user to specify if the map keys should be in snake case instead +// of the default hyphenated notation. +var snakeCaseKeys bool + +// CoerceKeysToSnakeCase changes the default, false, to the specified value, b. +// Note: the attribute prefix will be a hyphen, '-', or what ever string value has +// been specified using SetAttrPrefix. +func CoerceKeysToSnakeCase(b ...bool) { + if len(b) == 0 { + snakeCaseKeys = !snakeCaseKeys + } else if len(b) == 1 { + snakeCaseKeys = b[0] + } +} + +// 10jan19: use of pull request #57 should be conditional - legacy code assumes +// numeric values are float64. +var castToInt bool + +// CastValuesToInt tries to coerce numeric valus to int64 or uint64 instead of the +// default float64. Repeated calls with no argument will toggle this on/off, or this +// handling will be set with the value of 'b'. +func CastValuesToInt(b ...bool) { + if len(b) == 0 { + castToInt = !castToInt + } else if len(b) == 1 { + castToInt = b[0] + } +} + +// 05feb17: support processing XMPP streams (issue #36) +var handleXMPPStreamTag bool + +// HandleXMPPStreamTag causes decoder to parse XMPP elements. +// If called with no argument, XMPP stream element handling is toggled on/off. +// (See xmppStream_test.go for example.) +// If called with NewMapXml, NewMapXmlReader, New MapXmlReaderRaw the "stream" +// element will be returned as: +// map["stream"]interface{}{map[-]interface{}}. +// If called with NewMapSeq, NewMapSeqReader, NewMapSeqReaderRaw the "stream" +// element will be returned as: +// map["stream:stream"]interface{}{map["#attr"]interface{}{map[string]interface{}}} +// where the "#attr" values have "#text" and "#seq" keys. (See NewMapXmlSeq.) +func HandleXMPPStreamTag(b ...bool) { + if len(b) == 0 { + handleXMPPStreamTag = !handleXMPPStreamTag + } else if len(b) == 1 { + handleXMPPStreamTag = b[0] + } +} + +// 21jan18 - decode all values as map["#text":value] (issue #56) +var decodeSimpleValuesAsMap bool + +// DecodeSimpleValuesAsMap forces all values to be decoded as map["#text":]. +// If called with no argument, the decoding is toggled on/off. +// +// By default the NewMapXml functions decode simple values without attributes as +// map[:]. This function causes simple values without attributes to be +// decoded the same as simple values with attributes - map[:map["#text":]]. +func DecodeSimpleValuesAsMap(b ...bool) { + if len(b) == 0 { + decodeSimpleValuesAsMap = !decodeSimpleValuesAsMap + } else if len(b) == 1 { + decodeSimpleValuesAsMap = b[0] + } +} + +// xmlToMapParser (2015.11.12) - load a 'clean' XML doc into a map[string]interface{} directly. +// A refactoring of xmlToTreeParser(), markDuplicate() and treeToMap() - here, all-in-one. +// We've removed the intermediate *node tree with the allocation and subsequent rescanning. +func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) { + if lowerCase { + skey = strings.ToLower(skey) + } + if snakeCaseKeys { + skey = strings.Replace(skey, "-", "_", -1) + } + + // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'. + // Unless 'skey' is a simple element w/o attributes, in which case the xml.CharData value is the value. + var n, na map[string]interface{} + var seq int // for includeTagSeqNum + + // Allocate maps and load attributes, if any. + // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through + // to get StartElement then recurse with skey==xml.StartElement.Name.Local + // where we begin allocating map[string]interface{} values 'n' and 'na'. + if skey != "" { + n = make(map[string]interface{}) // old n + na = make(map[string]interface{}) // old n.nodes + if len(a) > 0 { + for _, v := range a { + if snakeCaseKeys { + v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1) + } + var key string + key = attrPrefix + v.Name.Local + if lowerCase { + key = strings.ToLower(key) + } + if xmlEscapeCharsDecoder { // per issue#84 + v.Value = escapeChars(v.Value) + } + na[key] = cast(v.Value, r, key) + } + } + } + // Return XMPP message. + if handleXMPPStreamTag && skey == "stream" { + n[skey] = na + return n, nil + } + + for { + t, err := p.Token() + if err != nil { + if err != io.EOF { + return nil, errors.New("xml.Decoder.Token() - " + err.Error()) + } + return nil, err + } + switch t.(type) { + case xml.StartElement: + tt := t.(xml.StartElement) + + // First call to xmlToMapParser() doesn't pass xml.StartElement - the map key. + // So when the loop is first entered, the first token is the root tag along + // with any attributes, which we process here. + // + // Subsequent calls to xmlToMapParser() will pass in tag+attributes for + // processing before getting the next token which is the element value, + // which is done above. + if skey == "" { + return xmlToMapParser(tt.Name.Local, tt.Attr, p, r) + } + + // If not initializing the map, parse the element. + // len(nn) == 1, necessarily - it is just an 'n'. + nn, err := xmlToMapParser(tt.Name.Local, tt.Attr, p, r) + if err != nil { + return nil, err + } + + // The nn map[string]interface{} value is a na[nn_key] value. + // We need to see if nn_key already exists - means we're parsing a list. + // This may require converting na[nn_key] value into []interface{} type. + // First, extract the key:val for the map - it's a singleton. + // Note: + // * if CoerceKeysToLower() called, then key will be lower case. + // * if CoerceKeysToSnakeCase() called, then key will be converted to snake case. + var key string + var val interface{} + for key, val = range nn { + break + } + + // IncludeTagSeqNum requests that the element be augmented with a "_seq" sub-element. + // In theory, we don't need this if len(na) == 1. But, we don't know what might + // come next - we're only parsing forward. So if you ask for 'includeTagSeqNum' you + // get it on every element. (Personally, I never liked this, but I added it on request + // and did get a $50 Amazon gift card in return - now we support it for backwards compatibility!) + if includeTagSeqNum { + switch val.(type) { + case []interface{}: + // noop - There's no clean way to handle this w/o changing message structure. + case map[string]interface{}: + val.(map[string]interface{})["_seq"] = seq // will overwrite an "_seq" XML tag + seq++ + case interface{}: // a non-nil simple element: string, float64, bool + v := map[string]interface{}{"#text": val} + v["_seq"] = seq + seq++ + val = v + } + } + + // 'na' holding sub-elements of n. + // See if 'key' already exists. + // If 'key' exists, then this is a list, if not just add key:val to na. + if v, ok := na[key]; ok { + var a []interface{} + switch v.(type) { + case []interface{}: + a = v.([]interface{}) + default: // anything else - note: v.(type) != nil + a = []interface{}{v} + } + a = append(a, val) + na[key] = a + } else { + na[key] = val // save it as a singleton + } + case xml.EndElement: + // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case. + if len(n) == 0 { + // If len(na)==0 we have an empty element == ""; + // it has no xml.Attr nor xml.CharData. + // Note: in original node-tree parser, val defaulted to ""; + // so we always had the default if len(node.nodes) == 0. + if len(na) > 0 { + n[skey] = na + } else { + n[skey] = "" // empty element + } + } else if len(n) == 1 && len(na) > 0 { + // it's a simple element w/ no attributes w/ subelements + for _, v := range n { + na["#text"] = v + } + n[skey] = na + } + return n, nil + case xml.CharData: + // clean up possible noise + tt := strings.Trim(string(t.(xml.CharData)), trimRunes) + if xmlEscapeCharsDecoder { // issue#84 + tt = escapeChars(tt) + } + if len(tt) > 0 { + if len(na) > 0 || decodeSimpleValuesAsMap { + na["#text"] = cast(tt, r, "#text") + } else if skey != "" { + n[skey] = cast(tt, r, skey) + } else { + // per Adrian (http://www.adrianlungu.com/) catch stray text + // in decoder stream - + // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374 + // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get + // a p.Token() decoding error when the BOM is UTF-16 or UTF-32. + continue + } + } + default: + // noop + } + } +} + +var castNanInf bool + +// Cast "Nan", "Inf", "-Inf" XML values to 'float64'. +// By default, these values will be decoded as 'string'. +func CastNanInf(b ...bool) { + if len(b) == 0 { + castNanInf = !castNanInf + } else if len(b) == 1 { + castNanInf = b[0] + } +} + +// cast - try to cast string values to bool or float64 +// 't' is the tag key that can be checked for 'not-casting' +func cast(s string, r bool, t string) interface{} { + if checkTagToSkip != nil && t != "" && checkTagToSkip(t) { + // call the check-function here with 't[0]' + // if 'true' return s + return s + } + + if r { + // handle nan and inf + if !castNanInf { + switch strings.ToLower(s) { + case "nan", "inf", "-inf": + return s + } + } + + // handle numeric strings ahead of boolean + if castToInt { + if f, err := strconv.ParseInt(s, 10, 64); err == nil { + return f + } + if f, err := strconv.ParseUint(s, 10, 64); err == nil { + return f + } + } + + if castToFloat { + if f, err := strconv.ParseFloat(s, 64); err == nil { + return f + } + } + + // ParseBool treats "1"==true & "0"==false, we've already scanned those + // values as float64. See if value has 't' or 'f' as initial screen to + // minimize calls to ParseBool; also, see if len(s) < 6. + if castToBool { + if len(s) > 0 && len(s) < 6 { + switch s[:1] { + case "t", "T", "f", "F": + if b, err := strconv.ParseBool(s); err == nil { + return b + } + } + } + } + } + return s +} + +// pull request, #59 +var castToFloat = true + +// CastValuesToFloat can be used to skip casting to float64 when +// "cast" argument is 'true' in NewMapXml, etc. +// Default is true. +func CastValuesToFloat(b ...bool) { + if len(b) == 0 { + castToFloat = !castToFloat + } else if len(b) == 1 { + castToFloat = b[0] + } +} + +var castToBool = true + +// CastValuesToBool can be used to skip casting to bool when +// "cast" argument is 'true' in NewMapXml, etc. +// Default is true. +func CastValuesToBool(b ...bool) { + if len(b) == 0 { + castToBool = !castToBool + } else if len(b) == 1 { + castToBool = b[0] + } +} + +// checkTagToSkip - switch to address Issue #58 + +var checkTagToSkip func(string) bool + +// SetCheckTagToSkipFunc registers function to test whether the value +// for a tag should be cast to bool or float64 when "cast" argument is 'true'. +// (Dot tag path notation is not supported.) +// NOTE: key may be "#text" if it's a simple element with attributes +// or "decodeSimpleValuesAsMap == true". +// NOTE: does not apply to NewMapXmlSeq... functions. +func SetCheckTagToSkipFunc(fn func(string) bool) { + checkTagToSkip = fn +} + +// ------------------ END: NewMapXml & NewMapXmlReader ------------------------- + +// ------------------ mv.Xml & mv.XmlWriter - from j2x ------------------------ + +const ( + DefaultRootTag = "doc" +) + +var useGoXmlEmptyElemSyntax bool + +// XmlGoEmptyElemSyntax() - rather than . +// Go's encoding/xml package marshals empty XML elements as . By default this package +// encodes empty elements as . If you're marshaling Map values that include structures +// (which are passed to xml.Marshal for encoding), this will let you conform to the standard package. +func XmlGoEmptyElemSyntax() { + useGoXmlEmptyElemSyntax = true +} + +// XmlDefaultEmptyElemSyntax() - rather than . +// Return XML encoding for empty elements to the default package setting. +// Reverses effect of XmlGoEmptyElemSyntax(). +func XmlDefaultEmptyElemSyntax() { + useGoXmlEmptyElemSyntax = false +} + +// ------- issue #88 ---------- +// xmlCheckIsValid set switch to force decoding the encoded XML to +// see if it is valid XML. +var xmlCheckIsValid bool + +// XmlCheckIsValid forces the encoded XML to be checked for validity. +func XmlCheckIsValid(b ...bool) { + if len(b) == 1 { + xmlCheckIsValid = b[0] + return + } + xmlCheckIsValid = !xmlCheckIsValid +} + +// Encode a Map as XML. The companion of NewMapXml(). +// The following rules apply. +// - The key label "#text" is treated as the value for a simple element with attributes. +// - Map keys that begin with a hyphen, '-', are interpreted as attributes. +// It is an error if the attribute doesn't have a []byte, string, number, or boolean value. +// - Map value type encoding: +// > string, bool, float64, int, int32, int64, float32: per "%v" formating +// > []bool, []uint8: by casting to string +// > structures, etc.: handed to xml.Marshal() - if there is an error, the element +// value is "UNKNOWN" +// - Elements with only attribute values or are null are terminated using "/>". +// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible. +// Thus, `{ "key":"value" }` encodes as "value". +// - To encode empty elements in a syntax consistent with encoding/xml call UseGoXmlEmptyElementSyntax(). +// The attributes tag=value pairs are alphabetized by "tag". Also, when encoding map[string]interface{} values - +// complex elements, etc. - the key:value pairs are alphabetized by key so the resulting tags will appear sorted. +func (mv Map) Xml(rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + var err error + b := new(bytes.Buffer) + p := new(pretty) // just a stub + + if len(m) == 1 && len(rootTag) == 0 { + for key, value := range m { + // if it an array, see if all values are map[string]interface{} + // we force a new root tag if we'll end up with no key:value in the list + // so: key:[string_val, bool:true] --> string_valtrue + switch value.(type) { + case []interface{}: + for _, v := range value.([]interface{}) { + switch v.(type) { + case map[string]interface{}: // noop + default: // anything else + err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p) + goto done + } + } + } + err = marshalMapToXmlIndent(false, b, key, value, p) + } + } else if len(rootTag) == 1 { + err = marshalMapToXmlIndent(false, b, rootTag[0], m, p) + } else { + err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p) + } +done: + if xmlCheckIsValid { + d := xml.NewDecoder(bytes.NewReader(b.Bytes())) + for { + _, err = d.Token() + if err == io.EOF { + err = nil + break + } else if err != nil { + return nil, err + } + } + } + return b.Bytes(), err +} + +// The following implementation is provided only for symmetry with NewMapXmlReader[Raw] +// The names will also provide a key for the number of return arguments. + +// Writes the Map as XML on the Writer. +// See Xml() for encoding rules. +func (mv Map) XmlWriter(xmlWriter io.Writer, rootTag ...string) error { + x, err := mv.Xml(rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// Writes the Map as XML on the Writer. []byte is the raw XML that was written. +// See Xml() for encoding rules. +/* +func (mv Map) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) { + x, err := mv.Xml(rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} +*/ + +// Writes the Map as pretty XML on the Writer. +// See Xml() for encoding rules. +func (mv Map) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error { + x, err := mv.XmlIndent(prefix, indent, rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written. +// See Xml() for encoding rules. +/* +func (mv Map) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) { + x, err := mv.XmlIndent(prefix, indent, rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} +*/ + +// -------------------- END: mv.Xml & mv.XmlWriter ------------------------------- + +// -------------- Handle XML stream by processing Map value -------------------- + +// Default poll delay to keep Handler from spinning on an open stream +// like sitting on os.Stdin waiting for imput. +var xhandlerPollInterval = time.Millisecond + +// Bulk process XML using handlers that process a Map value. +// 'rdr' is an io.Reader for XML (stream) +// 'mapHandler' is the Map processor. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'. +func HandleXmlReader(xmlReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error { + var n int + for { + m, merr := NewMapXmlReader(xmlReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m); !ok { + break + } + } else if merr != io.EOF { + time.Sleep(xhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} + +// Bulk process XML using handlers that process a Map value and the raw XML. +// 'rdr' is an io.Reader for XML (stream) +// 'mapHandler' is the Map and raw XML - []byte - processor. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error and raw XML processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'. +// See NewMapXmlReaderRaw for comment on performance associated with retrieving raw XML from a Reader. +func HandleXmlReaderRaw(xmlReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error { + var n int + for { + m, raw, merr := NewMapXmlReaderRaw(xmlReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr, raw); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m, raw); !ok { + break + } + } else if merr != io.EOF { + time.Sleep(xhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} + +// ----------------- END: Handle XML stream by processing Map value -------------- + +// -------- a hack of io.TeeReader ... need one that's an io.ByteReader for xml.NewDecoder() ---------- + +// This is a clone of io.TeeReader with the additional method t.ReadByte(). +// Thus, this TeeReader is also an io.ByteReader. +// This is necessary because xml.NewDecoder uses a ByteReader not a Reader. It appears to have been written +// with bufio.Reader or bytes.Reader in mind ... not a generic io.Reader, which doesn't have to have ReadByte().. +// If NewDecoder is passed a Reader that does not satisfy ByteReader() it wraps the Reader with +// bufio.NewReader and uses ReadByte rather than Read that runs the TeeReader pipe logic. + +type teeReader struct { + r io.Reader + w io.Writer + b []byte +} + +func myTeeReader(r io.Reader, w io.Writer) io.Reader { + b := make([]byte, 1) + return &teeReader{r, w, b} +} + +// need for io.Reader - but we don't use it ... +func (t *teeReader) Read(p []byte) (int, error) { + return 0, nil +} + +func (t *teeReader) ReadByte() (byte, error) { + n, err := t.r.Read(t.b) + if n > 0 { + if _, err := t.w.Write(t.b[:1]); err != nil { + return t.b[0], err + } + } + return t.b[0], err +} + +// For use with NewMapXmlReader & NewMapXmlSeqReader. +type byteReader struct { + r io.Reader + b []byte +} + +func myByteReader(r io.Reader) io.Reader { + b := make([]byte, 1) + return &byteReader{r, b} +} + +// Need for io.Reader interface ... +// Needed if reading a malformed http.Request.Body - issue #38. +func (b *byteReader) Read(p []byte) (int, error) { + return b.r.Read(p) +} + +func (b *byteReader) ReadByte() (byte, error) { + _, err := b.r.Read(b.b) + if len(b.b) > 0 { + return b.b[0], nil + } + var c byte + return c, err +} + +// ----------------------- END: io.TeeReader hack ----------------------------------- + +// ---------------------- XmlIndent - from j2x package ---------------------------- + +// Encode a map[string]interface{} as a pretty XML string. +// See Xml for encoding rules. +func (mv Map) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + + var err error + b := new(bytes.Buffer) + p := new(pretty) + p.indent = indent + p.padding = prefix + + if len(m) == 1 && len(rootTag) == 0 { + // this can extract the key for the single map element + // use it if it isn't a key for a list + for key, value := range m { + if _, ok := value.([]interface{}); ok { + err = marshalMapToXmlIndent(true, b, DefaultRootTag, m, p) + } else { + err = marshalMapToXmlIndent(true, b, key, value, p) + } + } + } else if len(rootTag) == 1 { + err = marshalMapToXmlIndent(true, b, rootTag[0], m, p) + } else { + err = marshalMapToXmlIndent(true, b, DefaultRootTag, m, p) + } + if xmlCheckIsValid { + d := xml.NewDecoder(bytes.NewReader(b.Bytes())) + for { + _, err = d.Token() + if err == io.EOF { + err = nil + break + } else if err != nil { + return nil, err + } + } + } + return b.Bytes(), err +} + +type pretty struct { + indent string + cnt int + padding string + mapDepth int + start int +} + +func (p *pretty) Indent() { + p.padding += p.indent + p.cnt++ +} + +func (p *pretty) Outdent() { + if p.cnt > 0 { + p.padding = p.padding[:len(p.padding)-len(p.indent)] + p.cnt-- + } +} + +// where the work actually happens +// returns an error if an attribute is not atomic +// NOTE: 01may20 - replaces mapToXmlIndent(); uses bytes.Buffer instead for string appends. +func marshalMapToXmlIndent(doIndent bool, b *bytes.Buffer, key string, value interface{}, pp *pretty) error { + var err error + var endTag bool + var isSimple bool + var elen int + p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start} + + // per issue #48, 18apr18 - try and coerce maps to map[string]interface{} + // Don't need for mapToXmlSeqIndent, since maps there are decoded by NewMapXmlSeq(). + if reflect.ValueOf(value).Kind() == reflect.Map { + switch value.(type) { + case map[string]interface{}: + default: + val := make(map[string]interface{}) + vv := reflect.ValueOf(value) + keys := vv.MapKeys() + for _, k := range keys { + val[fmt.Sprint(k)] = vv.MapIndex(k).Interface() + } + value = val + } + } + + // 14jul20. The following block of code has become something of a catch all for odd stuff + // that might be passed in as a result of casting an arbitrary map[] to an mxj.Map + // value and then call m.Xml or m.XmlIndent. See issue #71 (and #73) for such edge cases. + switch value.(type) { + // these types are handled during encoding + case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32, json.Number: + case []map[string]interface{}, []string, []float64, []bool, []int, []int32, []int64, []float32, []json.Number: + case []interface{}: + case nil: + value = "" + default: + // see if value is a struct, if so marshal using encoding/xml package + if reflect.ValueOf(value).Kind() == reflect.Struct { + if v, err := xml.Marshal(value); err != nil { + return err + } else { + value = string(v) + } + } else { + // coerce eveything else into a string value + value = fmt.Sprint(value) + } + } + + // start the XML tag with required indentaton and padding + if doIndent { + if _, err = b.WriteString(p.padding); err != nil { + return err + } + } + switch value.(type) { + case []interface{}: + default: + if _, err = b.WriteString(`<` + key); err != nil { + return err + } + } + + switch value.(type) { + case map[string]interface{}: + vv := value.(map[string]interface{}) + lenvv := len(vv) + // scan out attributes - attribute keys have prepended attrPrefix + attrlist := make([][2]string, len(vv)) + var n int + var ss string + for k, v := range vv { + if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix { + switch v.(type) { + case string: + if xmlEscapeChars { + ss = escapeChars(v.(string)) + } else { + ss = v.(string) + } + attrlist[n][0] = k[lenAttrPrefix:] + attrlist[n][1] = ss + case float64, bool, int, int32, int64, float32, json.Number: + attrlist[n][0] = k[lenAttrPrefix:] + attrlist[n][1] = fmt.Sprintf("%v", v) + case []byte: + if xmlEscapeChars { + ss = escapeChars(string(v.([]byte))) + } else { + ss = string(v.([]byte)) + } + attrlist[n][0] = k[lenAttrPrefix:] + attrlist[n][1] = ss + default: + return fmt.Errorf("invalid attribute value for: %s:<%T>", k, v) + } + n++ + } + } + if n > 0 { + attrlist = attrlist[:n] + sort.Sort(attrList(attrlist)) + for _, v := range attrlist { + if _, err = b.WriteString(` ` + v[0] + `="` + v[1] + `"`); err != nil { + return err + } + } + } + // only attributes? + if n == lenvv { + if useGoXmlEmptyElemSyntax { + if _, err = b.WriteString(`"); err != nil { + return err + } + } else { + if _, err = b.WriteString(`/>`); err != nil { + return err + } + } + break + } + + // simple element? Note: '#text" is an invalid XML tag. + isComplex := false + if v, ok := vv["#text"]; ok && n+1 == lenvv { + // just the value and attributes + switch v.(type) { + case string: + if xmlEscapeChars { + v = escapeChars(v.(string)) + } else { + v = v.(string) + } + case []byte: + if xmlEscapeChars { + v = escapeChars(string(v.([]byte))) + } else { + v = string(v.([]byte)) + } + } + if _, err = b.WriteString(">" + fmt.Sprintf("%v", v)); err != nil { + return err + } + endTag = true + elen = 1 + isSimple = true + break + } else if ok { + // need to handle when there are subelements in addition to the simple element value + // issue #90 + switch v.(type) { + case string: + if xmlEscapeChars { + v = escapeChars(v.(string)) + } else { + v = v.(string) + } + case []byte: + if xmlEscapeChars { + v = escapeChars(string(v.([]byte))) + } else { + v = string(v.([]byte)) + } + } + if _, err = b.WriteString(">" + fmt.Sprintf("%v", v)); err != nil { + return err + } + isComplex = true + } + + // close tag with possible attributes + if !isComplex { + if _, err = b.WriteString(">"); err != nil { + return err + } + } + if doIndent { + // *s += "\n" + if _, err = b.WriteString("\n"); err != nil { + return err + } + } + // something more complex + p.mapDepth++ + // extract the map k:v pairs and sort on key + elemlist := make([][2]interface{}, len(vv)) + n = 0 + for k, v := range vv { + if k == "#text" { + // simple element handled above + continue + } + if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix { + continue + } + elemlist[n][0] = k + elemlist[n][1] = v + n++ + } + elemlist = elemlist[:n] + sort.Sort(elemList(elemlist)) + var i int + for _, v := range elemlist { + switch v[1].(type) { + case []interface{}: + default: + if i == 0 && doIndent { + p.Indent() + } + } + i++ + if err := marshalMapToXmlIndent(doIndent, b, v[0].(string), v[1], p); err != nil { + return err + } + switch v[1].(type) { + case []interface{}: // handled in []interface{} case + default: + if doIndent { + p.Outdent() + } + } + i-- + } + p.mapDepth-- + endTag = true + elen = 1 // we do have some content ... + case []interface{}: + // special case - found during implementing Issue #23 + if len(value.([]interface{})) == 0 { + if doIndent { + if _, err = b.WriteString(p.padding + p.indent); err != nil { + return err + } + } + if _, err = b.WriteString("<" + key); err != nil { + return err + } + elen = 0 + endTag = true + break + } + for _, v := range value.([]interface{}) { + if doIndent { + p.Indent() + } + if err := marshalMapToXmlIndent(doIndent, b, key, v, p); err != nil { + return err + } + if doIndent { + p.Outdent() + } + } + return nil + case []string: + // This was added by https://github.com/slotix ... not a type that + // would be encountered if mv generated from NewMapXml, NewMapJson. + // Could be encountered in AnyXml(), so we'll let it stay, though + // it should be merged with case []interface{}, above. + //quick fix for []string type + //[]string should be treated exaclty as []interface{} + if len(value.([]string)) == 0 { + if doIndent { + if _, err = b.WriteString(p.padding + p.indent); err != nil { + return err + } + } + if _, err = b.WriteString("<" + key); err != nil { + return err + } + elen = 0 + endTag = true + break + } + for _, v := range value.([]string) { + if doIndent { + p.Indent() + } + if err := marshalMapToXmlIndent(doIndent, b, key, v, p); err != nil { + return err + } + if doIndent { + p.Outdent() + } + } + return nil + case nil: + // terminate the tag + if doIndent { + // *s += p.padding + if _, err = b.WriteString(p.padding); err != nil { + return err + } + } + if _, err = b.WriteString("<" + key); err != nil { + return err + } + endTag, isSimple = true, true + break + default: // handle anything - even goofy stuff + elen = 0 + switch value.(type) { + case string: + v := value.(string) + if xmlEscapeChars { + v = escapeChars(v) + } + elen = len(v) + if elen > 0 { + // *s += ">" + v + if _, err = b.WriteString(">" + v); err != nil { + return err + } + } + case float64, bool, int, int32, int64, float32, json.Number: + v := fmt.Sprintf("%v", value) + elen = len(v) // always > 0 + if _, err = b.WriteString(">" + v); err != nil { + return err + } + case []byte: // NOTE: byte is just an alias for uint8 + // similar to how xml.Marshal handles []byte structure members + v := string(value.([]byte)) + if xmlEscapeChars { + v = escapeChars(v) + } + elen = len(v) + if elen > 0 { + // *s += ">" + v + if _, err = b.WriteString(">" + v); err != nil { + return err + } + } + default: + if _, err = b.WriteString(">"); err != nil { + return err + } + var v []byte + var err error + if doIndent { + v, err = xml.MarshalIndent(value, p.padding, p.indent) + } else { + v, err = xml.Marshal(value) + } + if err != nil { + if _, err = b.WriteString(">UNKNOWN"); err != nil { + return err + } + } else { + elen = len(v) + if elen > 0 { + if _, err = b.Write(v); err != nil { + return err + } + } + } + } + isSimple = true + endTag = true + } + if endTag { + if doIndent { + if !isSimple { + if _, err = b.WriteString(p.padding); err != nil { + return err + } + } + } + if elen > 0 || useGoXmlEmptyElemSyntax { + if elen == 0 { + if _, err = b.WriteString(">"); err != nil { + return err + } + } + if _, err = b.WriteString(`"); err != nil { + return err + } + } else { + if _, err = b.WriteString(`/>`); err != nil { + return err + } + } + } + if doIndent { + if p.cnt > p.start { + if _, err = b.WriteString("\n"); err != nil { + return err + } + } + p.Outdent() + } + + return nil +} + +// ============================ sort interface implementation ================= + +type attrList [][2]string + +func (a attrList) Len() int { + return len(a) +} + +func (a attrList) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a attrList) Less(i, j int) bool { + return a[i][0] <= a[j][0] +} + +type elemList [][2]interface{} + +func (e elemList) Len() int { + return len(e) +} + +func (e elemList) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e elemList) Less(i, j int) bool { + return e[i][0].(string) <= e[j][0].(string) +} diff --git a/vendor/github.com/clbanning/mxj/v2/xmlseq.go b/vendor/github.com/clbanning/mxj/v2/xmlseq.go new file mode 100644 index 000000000..80632bd3c --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/xmlseq.go @@ -0,0 +1,877 @@ +// Copyright 2012-2016, 2019 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// xmlseq.go - version of xml.go with sequence # injection on Decoding and sorting on Encoding. +// Also, handles comments, directives and process instructions. + +package mxj + +import ( + "bytes" + "encoding/xml" + "errors" + "fmt" + "io" + "sort" + "strings" +) + +// MapSeq is like Map but contains seqencing indices to allow recovering the original order of +// the XML elements when the map[string]interface{} is marshaled. Element attributes are +// stored as a map["#attr"]map[]map[string]interface{}{"#text":"", "#seq":} +// value instead of denoting the keys with a prefix character. Also, comments, directives and +// process instructions are preserved. +type MapSeq map[string]interface{} + +// NoRoot is returned by NewXmlSeq, etc., when a comment, directive or procinstr element is parsed +// in the XML data stream and the element is not contained in an XML object with a root element. +var NoRoot = errors.New("no root key") +var NO_ROOT = NoRoot // maintain backwards compatibility + +// ------------------- NewMapXmlSeq & NewMapXmlSeqReader ... ------------------------- + +// NewMapXmlSeq converts a XML doc into a MapSeq value with elements id'd with decoding sequence key represented +// as map["#seq"]. +// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible. +// NOTE: "#seq" key/value pairs are removed on encoding with msv.Xml() / msv.XmlIndent(). +// • attributes are a map - map["#attr"]map["attr_key"]map[string]interface{}{"#text":, "#seq":} +// • all simple elements are decoded as map["#text"]interface{} with a "#seq" k:v pair, as well. +// • lists always decode as map["list_tag"][]map[string]interface{} where the array elements are maps that +// include a "#seq" k:v pair based on sequence they are decoded. Thus, XML like: +// +// value 1 +// value 2 +// value 3 +// +// is decoded as: +// doc : +// ltag :[[]interface{}] +// [item: 0] +// #seq :[int] 0 +// #text :[string] value 1 +// [item: 1] +// #seq :[int] 2 +// #text :[string] value 3 +// newtag : +// #seq :[int] 1 +// #text :[string] value 2 +// It will encode in proper sequence even though the MapSeq representation merges all "ltag" elements in an array. +// • comments - "" - are decoded as map["#comment"]map["#text"]"cmnt_text" with a "#seq" k:v pair. +// • directives - "" - are decoded as map["#directive"]map[#text"]"directive_text" with a "#seq" k:v pair. +// • process instructions - "" - are decoded as map["#procinst"]interface{} where the #procinst value +// is of map[string]interface{} type with the following keys: #target, #inst, and #seq. +// • comments, directives, and procinsts that are NOT part of a document with a root key will be returned as +// map[string]interface{} and the error value 'NoRoot'. +// • note: ": tag preserve the +// ":" notation rather than stripping it as with NewMapXml(). +// 2. Attribute keys for name space prefix declarations preserve "xmlns:" notation. +// +// ERRORS: +// 1. If a NoRoot error, "no root key," is returned, check the initial map key for a "#comment", +// "#directive" or #procinst" key. +func NewMapXmlSeq(xmlVal []byte, cast ...bool) (MapSeq, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + return xmlSeqToMap(xmlVal, r) +} + +// NewMpaXmlSeqReader returns next XML doc from an io.Reader as a MapSeq value. +// NOTES: +// 1. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 2. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to +// re-encode the message in its original structure. +// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +// +// ERRORS: +// 1. If a NoRoot error, "no root key," is returned, check the initial map key for a "#comment", +// "#directive" or #procinst" key. +func NewMapXmlSeqReader(xmlReader io.Reader, cast ...bool) (MapSeq, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + + // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder + // will wrap it in a bufio.Reader and seek on the file beyond where the + // xml.Decoder parses! + if _, ok := xmlReader.(io.ByteReader); !ok { + xmlReader = myByteReader(xmlReader) // see code at EOF + } + + // build the map + return xmlSeqReaderToMap(xmlReader, r) +} + +// NewMapXmlSeqReaderRaw returns the next XML doc from an io.Reader as a MapSeq value. +// Returns MapSeq value, slice with the raw XML, and any error. +// NOTES: +// 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte +// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact. +// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large +// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body +// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call. +// 2. The 'raw' return value may be larger than the XML text value. +// 3. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 4. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to +// re-encode the message in its original structure. +// 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +// +// ERRORS: +// 1. If a NoRoot error, "no root key," is returned, check if the initial map key is "#comment", +// "#directive" or #procinst" key. +func NewMapXmlSeqReaderRaw(xmlReader io.Reader, cast ...bool) (MapSeq, []byte, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + // create TeeReader so we can retrieve raw XML + buf := make([]byte, 0) + wb := bytes.NewBuffer(buf) + trdr := myTeeReader(xmlReader, wb) + + m, err := xmlSeqReaderToMap(trdr, r) + + // retrieve the raw XML that was decoded + b := wb.Bytes() + + // err may be NoRoot + return m, b, err +} + +// xmlSeqReaderToMap() - parse a XML io.Reader to a map[string]interface{} value +func xmlSeqReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) { + // parse the Reader + p := xml.NewDecoder(rdr) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlSeqToMapParser("", nil, p, r) +} + +// xmlSeqToMap - convert a XML doc into map[string]interface{} value +func xmlSeqToMap(doc []byte, r bool) (map[string]interface{}, error) { + b := bytes.NewReader(doc) + p := xml.NewDecoder(b) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlSeqToMapParser("", nil, p, r) +} + +// ===================================== where the work happens ============================= + +// xmlSeqToMapParser - load a 'clean' XML doc into a map[string]interface{} directly. +// Add #seq tag value for each element decoded - to be used for Encoding later. +func xmlSeqToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) { + if snakeCaseKeys { + skey = strings.Replace(skey, "-", "_", -1) + } + + // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'. + var n, na map[string]interface{} + var seq int // for including seq num when decoding + + // Allocate maps and load attributes, if any. + // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through + // to get StartElement then recurse with skey==xml.StartElement.Name.Local + // where we begin allocating map[string]interface{} values 'n' and 'na'. + if skey != "" { + // 'n' only needs one slot - save call to runtime•hashGrow() + // 'na' we don't know + n = make(map[string]interface{}, 1) + na = make(map[string]interface{}) + if len(a) > 0 { + // xml.Attr is decoded into: map["#attr"]map[]interface{} + // where interface{} is map[string]interface{}{"#text":, "#seq":} + aa := make(map[string]interface{}, len(a)) + for i, v := range a { + if snakeCaseKeys { + v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1) + } + if xmlEscapeCharsDecoder { // per issue#84 + v.Value = escapeChars(v.Value) + } + if len(v.Name.Space) > 0 { + aa[v.Name.Space+`:`+v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r, ""), "#seq": i} + } else { + aa[v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r, ""), "#seq": i} + } + } + na["#attr"] = aa + } + } + + // Return XMPP message. + if handleXMPPStreamTag && skey == "stream:stream" { + n[skey] = na + return n, nil + } + + for { + t, err := p.RawToken() + if err != nil { + if err != io.EOF { + return nil, errors.New("xml.Decoder.Token() - " + err.Error()) + } + return nil, err + } + switch t.(type) { + case xml.StartElement: + tt := t.(xml.StartElement) + + // First call to xmlSeqToMapParser() doesn't pass xml.StartElement - the map key. + // So when the loop is first entered, the first token is the root tag along + // with any attributes, which we process here. + // + // Subsequent calls to xmlSeqToMapParser() will pass in tag+attributes for + // processing before getting the next token which is the element value, + // which is done above. + if skey == "" { + if len(tt.Name.Space) > 0 { + return xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r) + } else { + return xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r) + } + } + + // If not initializing the map, parse the element. + // len(nn) == 1, necessarily - it is just an 'n'. + var nn map[string]interface{} + if len(tt.Name.Space) > 0 { + nn, err = xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r) + } else { + nn, err = xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r) + } + if err != nil { + return nil, err + } + + // The nn map[string]interface{} value is a na[nn_key] value. + // We need to see if nn_key already exists - means we're parsing a list. + // This may require converting na[nn_key] value into []interface{} type. + // First, extract the key:val for the map - it's a singleton. + var key string + var val interface{} + for key, val = range nn { + break + } + + // add "#seq" k:v pair - + // Sequence number included even in list elements - this should allow us + // to properly resequence even something goofy like: + // item 1 + // item 2 + // item 3 + // where all the "list" subelements are decoded into an array. + switch val.(type) { + case map[string]interface{}: + val.(map[string]interface{})["#seq"] = seq + seq++ + case interface{}: // a non-nil simple element: string, float64, bool + v := map[string]interface{}{"#text": val, "#seq": seq} + seq++ + val = v + } + + // 'na' holding sub-elements of n. + // See if 'key' already exists. + // If 'key' exists, then this is a list, if not just add key:val to na. + if v, ok := na[key]; ok { + var a []interface{} + switch v.(type) { + case []interface{}: + a = v.([]interface{}) + default: // anything else - note: v.(type) != nil + a = []interface{}{v} + } + a = append(a, val) + na[key] = a + } else { + na[key] = val // save it as a singleton + } + case xml.EndElement: + if skey != "" { + tt := t.(xml.EndElement) + if snakeCaseKeys { + tt.Name.Local = strings.Replace(tt.Name.Local, "-", "_", -1) + } + var name string + if len(tt.Name.Space) > 0 { + name = tt.Name.Space + `:` + tt.Name.Local + } else { + name = tt.Name.Local + } + if skey != name { + return nil, fmt.Errorf("element %s not properly terminated, got %s at #%d", + skey, name, p.InputOffset()) + } + } + // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case. + if len(n) == 0 { + // If len(na)==0 we have an empty element == ""; + // it has no xml.Attr nor xml.CharData. + // Empty element content will be map["etag"]map["#text"]"" + // after #seq injection - map["etag"]map["#seq"]seq - after return. + if len(na) > 0 { + n[skey] = na + } else { + n[skey] = "" // empty element + } + } + return n, nil + case xml.CharData: + // clean up possible noise + tt := strings.Trim(string(t.(xml.CharData)), trimRunes) + if xmlEscapeCharsDecoder { // issue#84 + tt = escapeChars(tt) + } + if skey == "" { + // per Adrian (http://www.adrianlungu.com/) catch stray text + // in decoder stream - + // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374 + // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get + // a p.Token() decoding error when the BOM is UTF-16 or UTF-32. + continue + } + if len(tt) > 0 { + // every simple element is a #text and has #seq associated with it + na["#text"] = cast(tt, r, "") + na["#seq"] = seq + seq++ + } + case xml.Comment: + if n == nil { // no root 'key' + n = map[string]interface{}{"#comment": string(t.(xml.Comment))} + return n, NoRoot + } + cm := make(map[string]interface{}, 2) + cm["#text"] = string(t.(xml.Comment)) + cm["#seq"] = seq + seq++ + na["#comment"] = cm + case xml.Directive: + if n == nil { // no root 'key' + n = map[string]interface{}{"#directive": string(t.(xml.Directive))} + return n, NoRoot + } + dm := make(map[string]interface{}, 2) + dm["#text"] = string(t.(xml.Directive)) + dm["#seq"] = seq + seq++ + na["#directive"] = dm + case xml.ProcInst: + if n == nil { + na = map[string]interface{}{"#target": t.(xml.ProcInst).Target, "#inst": string(t.(xml.ProcInst).Inst)} + n = map[string]interface{}{"#procinst": na} + return n, NoRoot + } + pm := make(map[string]interface{}, 3) + pm["#target"] = t.(xml.ProcInst).Target + pm["#inst"] = string(t.(xml.ProcInst).Inst) + pm["#seq"] = seq + seq++ + na["#procinst"] = pm + default: + // noop - shouldn't ever get here, now, since we handle all token types + } + } +} + +// ------------------ END: NewMapXml & NewMapXmlReader ------------------------- + +// --------------------- mv.XmlSeq & mv.XmlSeqWriter ------------------------- + +// Xml encodes a MapSeq as XML with elements sorted on #seq. The companion of NewMapXmlSeq(). +// The following rules apply. +// - The "#seq" key value is used to seqence the subelements or attributes only. +// - The "#attr" map key identifies the map of attribute map[string]interface{} values with "#text" key. +// - The "#comment" map key identifies a comment in the value "#text" map entry - . +// - The "#directive" map key identifies a directive in the value "#text" map entry - . +// - The "#procinst" map key identifies a process instruction in the value "#target" and "#inst" +// map entries - . +// - Value type encoding: +// > string, bool, float64, int, int32, int64, float32: per "%v" formating +// > []bool, []uint8: by casting to string +// > structures, etc.: handed to xml.Marshal() - if there is an error, the element +// value is "UNKNOWN" +// - Elements with only attribute values or are null are terminated using "/>" unless XmlGoEmptyElemSystax() called. +// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible. +// Thus, `{ "key":"value" }` encodes as "value". +func (mv MapSeq) Xml(rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + var err error + s := new(string) + p := new(pretty) // just a stub + + if len(m) == 1 && len(rootTag) == 0 { + for key, value := range m { + // if it's an array, see if all values are map[string]interface{} + // we force a new root tag if we'll end up with no key:value in the list + // so: key:[string_val, bool:true] --> string_valtrue + switch value.(type) { + case []interface{}: + for _, v := range value.([]interface{}) { + switch v.(type) { + case map[string]interface{}: // noop + default: // anything else + err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p) + goto done + } + } + } + err = mapToXmlSeqIndent(false, s, key, value, p) + } + } else if len(rootTag) == 1 { + err = mapToXmlSeqIndent(false, s, rootTag[0], m, p) + } else { + err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p) + } +done: + if xmlCheckIsValid { + d := xml.NewDecoder(bytes.NewReader([]byte(*s))) + for { + _, err = d.Token() + if err == io.EOF { + err = nil + break + } else if err != nil { + return nil, err + } + } + } + return []byte(*s), err +} + +// The following implementation is provided only for symmetry with NewMapXmlReader[Raw] +// The names will also provide a key for the number of return arguments. + +// XmlWriter Writes the MapSeq value as XML on the Writer. +// See MapSeq.Xml() for encoding rules. +func (mv MapSeq) XmlWriter(xmlWriter io.Writer, rootTag ...string) error { + x, err := mv.Xml(rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// XmlWriteRaw writes the MapSeq value as XML on the Writer. []byte is the raw XML that was written. +// See Map.XmlSeq() for encoding rules. +/* +func (mv MapSeq) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) { + x, err := mv.Xml(rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} +*/ + +// XmlIndentWriter writes the MapSeq value as pretty XML on the Writer. +// See MapSeq.Xml() for encoding rules. +func (mv MapSeq) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error { + x, err := mv.XmlIndent(prefix, indent, rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// XmlIndentWriterRaw writes the Map as pretty XML on the Writer. []byte is the raw XML that was written. +// See Map.XmlSeq() for encoding rules. +/* +func (mv MapSeq) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) { + x, err := mv.XmlSeqIndent(prefix, indent, rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} +*/ + +// -------------------- END: mv.Xml & mv.XmlWriter ------------------------------- + +// ---------------------- XmlSeqIndent ---------------------------- + +// XmlIndent encodes a map[string]interface{} as a pretty XML string. +// See MapSeq.XmlSeq() for encoding rules. +func (mv MapSeq) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + + var err error + s := new(string) + p := new(pretty) + p.indent = indent + p.padding = prefix + + if len(m) == 1 && len(rootTag) == 0 { + // this can extract the key for the single map element + // use it if it isn't a key for a list + for key, value := range m { + if _, ok := value.([]interface{}); ok { + err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p) + } else { + err = mapToXmlSeqIndent(true, s, key, value, p) + } + } + } else if len(rootTag) == 1 { + err = mapToXmlSeqIndent(true, s, rootTag[0], m, p) + } else { + err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p) + } + if xmlCheckIsValid { + if _, err = NewMapXml([]byte(*s)); err != nil { + return nil, err + } + d := xml.NewDecoder(bytes.NewReader([]byte(*s))) + for { + _, err = d.Token() + if err == io.EOF { + err = nil + break + } else if err != nil { + return nil, err + } + } + } + return []byte(*s), err +} + +// where the work actually happens +// returns an error if an attribute is not atomic +func mapToXmlSeqIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error { + var endTag bool + var isSimple bool + var noEndTag bool + var elen int + var ss string + p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start} + + switch value.(type) { + case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32: + if doIndent { + *s += p.padding + } + if key != "#comment" && key != "#directive" && key != "#procinst" { + *s += `<` + key + } + } + switch value.(type) { + case map[string]interface{}: + val := value.(map[string]interface{}) + + if key == "#comment" { + *s += `` + noEndTag = true + break + } + + if key == "#directive" { + *s += `` + noEndTag = true + break + } + + if key == "#procinst" { + *s += `` + noEndTag = true + break + } + + haveAttrs := false + // process attributes first + if v, ok := val["#attr"].(map[string]interface{}); ok { + // First, unroll the map[string]interface{} into a []keyval array. + // Then sequence it. + kv := make([]keyval, len(v)) + n := 0 + for ak, av := range v { + kv[n] = keyval{ak, av} + n++ + } + sort.Sort(elemListSeq(kv)) + // Now encode the attributes in original decoding sequence, using keyval array. + for _, a := range kv { + vv := a.v.(map[string]interface{}) + switch vv["#text"].(type) { + case string: + if xmlEscapeChars { + ss = escapeChars(vv["#text"].(string)) + } else { + ss = vv["#text"].(string) + } + *s += ` ` + a.k + `="` + ss + `"` + case float64, bool, int, int32, int64, float32: + *s += ` ` + a.k + `="` + fmt.Sprintf("%v", vv["#text"]) + `"` + case []byte: + if xmlEscapeChars { + ss = escapeChars(string(vv["#text"].([]byte))) + } else { + ss = string(vv["#text"].([]byte)) + } + *s += ` ` + a.k + `="` + ss + `"` + default: + return fmt.Errorf("invalid attribute value for: %s", a.k) + } + } + haveAttrs = true + } + + // simple element? + // every map value has, at least, "#seq" and, perhaps, "#text" and/or "#attr" + _, seqOK := val["#seq"] // have key + if v, ok := val["#text"]; ok && ((len(val) == 3 && haveAttrs) || (len(val) == 2 && !haveAttrs)) && seqOK { + if stmp, ok := v.(string); ok && stmp != "" { + if xmlEscapeChars { + stmp = escapeChars(stmp) + } + *s += ">" + stmp + endTag = true + elen = 1 + } + isSimple = true + break + } else if !ok && ((len(val) == 2 && haveAttrs) || (len(val) == 1 && !haveAttrs)) && seqOK { + // here no #text but have #seq or #seq+#attr + endTag = false + break + } + + // we now need to sequence everything except attributes + // 'kv' will hold everything that needs to be written + kv := make([]keyval, 0) + for k, v := range val { + if k == "#attr" { // already processed + continue + } + if k == "#seq" { // ignore - just for sorting + continue + } + switch v.(type) { + case []interface{}: + // unwind the array as separate entries + for _, vv := range v.([]interface{}) { + kv = append(kv, keyval{k, vv}) + } + default: + kv = append(kv, keyval{k, v}) + } + } + + // close tag with possible attributes + *s += ">" + if doIndent { + *s += "\n" + } + // something more complex + p.mapDepth++ + sort.Sort(elemListSeq(kv)) + i := 0 + for _, v := range kv { + switch v.v.(type) { + case []interface{}: + default: + if i == 0 && doIndent { + p.Indent() + } + } + i++ + if err := mapToXmlSeqIndent(doIndent, s, v.k, v.v, p); err != nil { + return err + } + switch v.v.(type) { + case []interface{}: // handled in []interface{} case + default: + if doIndent { + p.Outdent() + } + } + i-- + } + p.mapDepth-- + endTag = true + elen = 1 // we do have some content other than attrs + case []interface{}: + for _, v := range value.([]interface{}) { + if doIndent { + p.Indent() + } + if err := mapToXmlSeqIndent(doIndent, s, key, v, p); err != nil { + return err + } + if doIndent { + p.Outdent() + } + } + return nil + case nil: + // terminate the tag + if doIndent { + *s += p.padding + } + *s += "<" + key + endTag, isSimple = true, true + break + default: // handle anything - even goofy stuff + elen = 0 + switch value.(type) { + case string: + if xmlEscapeChars { + ss = escapeChars(value.(string)) + } else { + ss = value.(string) + } + elen = len(ss) + if elen > 0 { + *s += ">" + ss + } + case float64, bool, int, int32, int64, float32: + v := fmt.Sprintf("%v", value) + elen = len(v) + if elen > 0 { + *s += ">" + v + } + case []byte: // NOTE: byte is just an alias for uint8 + // similar to how xml.Marshal handles []byte structure members + if xmlEscapeChars { + ss = escapeChars(string(value.([]byte))) + } else { + ss = string(value.([]byte)) + } + elen = len(ss) + if elen > 0 { + *s += ">" + ss + } + default: + var v []byte + var err error + if doIndent { + v, err = xml.MarshalIndent(value, p.padding, p.indent) + } else { + v, err = xml.Marshal(value) + } + if err != nil { + *s += ">UNKNOWN" + } else { + elen = len(v) + if elen > 0 { + *s += string(v) + } + } + } + isSimple = true + endTag = true + } + if endTag && !noEndTag { + if doIndent { + if !isSimple { + *s += p.padding + } + } + switch value.(type) { + case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32: + if elen > 0 || useGoXmlEmptyElemSyntax { + if elen == 0 { + *s += ">" + } + *s += `" + } else { + *s += `/>` + } + } + } else if !noEndTag { + if useGoXmlEmptyElemSyntax { + *s += `" + // *s += ">" + } else { + *s += "/>" + } + } + if doIndent { + if p.cnt > p.start { + *s += "\n" + } + p.Outdent() + } + + return nil +} + +// the element sort implementation + +type keyval struct { + k string + v interface{} +} +type elemListSeq []keyval + +func (e elemListSeq) Len() int { + return len(e) +} + +func (e elemListSeq) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e elemListSeq) Less(i, j int) bool { + var iseq, jseq int + var fiseq, fjseq float64 + var ok bool + if iseq, ok = e[i].v.(map[string]interface{})["#seq"].(int); !ok { + if fiseq, ok = e[i].v.(map[string]interface{})["#seq"].(float64); ok { + iseq = int(fiseq) + } else { + iseq = 9999999 + } + } + + if jseq, ok = e[j].v.(map[string]interface{})["#seq"].(int); !ok { + if fjseq, ok = e[j].v.(map[string]interface{})["#seq"].(float64); ok { + jseq = int(fjseq) + } else { + jseq = 9999999 + } + } + + return iseq <= jseq +} + +// =============== https://groups.google.com/forum/#!topic/golang-nuts/lHPOHD-8qio + +// BeautifyXml (re)formats an XML doc similar to Map.XmlIndent(). +// It preserves comments, directives and process instructions, +func BeautifyXml(b []byte, prefix, indent string) ([]byte, error) { + x, err := NewMapXmlSeq(b) + if err != nil { + return nil, err + } + return x.XmlIndent(prefix, indent) +} diff --git a/vendor/github.com/clbanning/mxj/v2/xmlseq2.go b/vendor/github.com/clbanning/mxj/v2/xmlseq2.go new file mode 100644 index 000000000..467fd0769 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/v2/xmlseq2.go @@ -0,0 +1,18 @@ +// Copyright 2012-2016, 2019 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +// ---------------- expose Map methods to MapSeq type --------------------------- + +// Pretty print a Map. +func (msv MapSeq) StringIndent(offset ...int) string { + return writeMap(map[string]interface{}(msv), true, true, offset...) +} + +// Pretty print a Map without the value type information - just key:value entries. +func (msv MapSeq) StringIndentNoTypeInfo(offset ...int) string { + return writeMap(map[string]interface{}(msv), false, true, offset...) +} + diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md index 50d56ffbf..52b111d5f 100644 --- a/vendor/github.com/json-iterator/go/README.md +++ b/vendor/github.com/json-iterator/go/README.md @@ -1,5 +1,5 @@ [![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) -[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/json-iterator/go) [![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) [![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) [![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) @@ -18,16 +18,16 @@ Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/githu Raw Result (easyjson requires static code generation) -| | ns/op | allocation bytes | allocation times | -| --- | --- | --- | --- | -| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | -| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | -| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | -| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | -| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | -| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | +| | ns/op | allocation bytes | allocation times | +| --------------- | ----------- | ---------------- | ---------------- | +| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | +| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | +| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | +| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | +| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | +| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | -Always benchmark with your own workload. +Always benchmark with your own workload. The result depends heavily on the data input. # Usage @@ -41,10 +41,10 @@ import "encoding/json" json.Marshal(&data) ``` -with +with ```go -import "github.com/json-iterator/go" +import jsoniter "github.com/json-iterator/go" var json = jsoniter.ConfigCompatibleWithStandardLibrary json.Marshal(&data) @@ -60,7 +60,7 @@ json.Unmarshal(input, &data) with ```go -import "github.com/json-iterator/go" +import jsoniter "github.com/json-iterator/go" var json = jsoniter.ConfigCompatibleWithStandardLibrary json.Unmarshal(input, &data) @@ -78,10 +78,10 @@ go get github.com/json-iterator/go Contributors -* [thockin](https://github.com/thockin) -* [mattn](https://github.com/mattn) -* [cch123](https://github.com/cch123) -* [Oleg Shaldybin](https://github.com/olegshaldybin) -* [Jason Toffaletti](https://github.com/toffaletti) +- [thockin](https://github.com/thockin) +- [mattn](https://github.com/mattn) +- [cch123](https://github.com/cch123) +- [Oleg Shaldybin](https://github.com/olegshaldybin) +- [Jason Toffaletti](https://github.com/toffaletti) Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) diff --git a/vendor/github.com/json-iterator/go/any_str.go b/vendor/github.com/json-iterator/go/any_str.go index a4b93c78c..1f12f6612 100644 --- a/vendor/github.com/json-iterator/go/any_str.go +++ b/vendor/github.com/json-iterator/go/any_str.go @@ -64,7 +64,6 @@ func (any *stringAny) ToInt64() int64 { flag := 1 startPos := 0 - endPos := 0 if any.val[0] == '+' || any.val[0] == '-' { startPos = 1 } @@ -73,6 +72,7 @@ func (any *stringAny) ToInt64() int64 { flag = -1 } + endPos := startPos for i := startPos; i < len(any.val); i++ { if any.val[i] >= '0' && any.val[i] <= '9' { endPos = i + 1 @@ -98,7 +98,6 @@ func (any *stringAny) ToUint64() uint64 { } startPos := 0 - endPos := 0 if any.val[0] == '-' { return 0 @@ -107,6 +106,7 @@ func (any *stringAny) ToUint64() uint64 { startPos = 1 } + endPos := startPos for i := startPos; i < len(any.val); i++ { if any.val[i] >= '0' && any.val[i] <= '9' { endPos = i + 1 diff --git a/vendor/github.com/json-iterator/go/config.go b/vendor/github.com/json-iterator/go/config.go index 8c58fcba5..2adcdc3b7 100644 --- a/vendor/github.com/json-iterator/go/config.go +++ b/vendor/github.com/json-iterator/go/config.go @@ -183,11 +183,11 @@ func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) { encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { rawMessage := *(*json.RawMessage)(ptr) iter := cfg.BorrowIterator([]byte(rawMessage)) + defer cfg.ReturnIterator(iter) iter.Read() - if iter.Error != nil { + if iter.Error != nil && iter.Error != io.EOF { stream.WriteRaw("null") } else { - cfg.ReturnIterator(iter) stream.WriteRaw(string(rawMessage)) } }, func(ptr unsafe.Pointer) bool { diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go index b65137114..58ee89c84 100644 --- a/vendor/github.com/json-iterator/go/iter_object.go +++ b/vendor/github.com/json-iterator/go/iter_object.go @@ -150,7 +150,7 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { if c == '}' { return iter.decrementDepth() } - iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c})) + iter.ReportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c})) iter.decrementDepth() return false } @@ -206,7 +206,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { if c == '}' { return iter.decrementDepth() } - iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) + iter.ReportError("ReadMapCB", `expect " after {, but found `+string([]byte{c})) iter.decrementDepth() return false } diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go index 80320cd64..74a97bfe5 100644 --- a/vendor/github.com/json-iterator/go/reflect_extension.go +++ b/vendor/github.com/json-iterator/go/reflect_extension.go @@ -475,7 +475,7 @@ func calcFieldNames(originalFieldName string, tagProvidedFieldName string, whole fieldNames = []string{tagProvidedFieldName} } // private? - isNotExported := unicode.IsLower(rune(originalFieldName[0])) + isNotExported := unicode.IsLower(rune(originalFieldName[0])) || originalFieldName[0] == '_' if isNotExported { fieldNames = []string{} } diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go index 9e2b623fe..582967130 100644 --- a/vendor/github.com/json-iterator/go/reflect_map.go +++ b/vendor/github.com/json-iterator/go/reflect_map.go @@ -49,6 +49,33 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { return decoder } } + + ptrType := reflect2.PtrTo(typ) + if ptrType.Implements(unmarshalerType) { + return &referenceDecoder{ + &unmarshalerDecoder{ + valType: ptrType, + }, + } + } + if typ.Implements(unmarshalerType) { + return &unmarshalerDecoder{ + valType: typ, + } + } + if ptrType.Implements(textUnmarshalerType) { + return &referenceDecoder{ + &textUnmarshalerDecoder{ + valType: ptrType, + }, + } + } + if typ.Implements(textUnmarshalerType) { + return &textUnmarshalerDecoder{ + valType: typ, + } + } + switch typ.Kind() { case reflect.String: return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) @@ -63,31 +90,6 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { typ = reflect2.DefaultTypeOfKind(typ.Kind()) return &numericMapKeyDecoder{decoderOfType(ctx, typ)} default: - ptrType := reflect2.PtrTo(typ) - if ptrType.Implements(unmarshalerType) { - return &referenceDecoder{ - &unmarshalerDecoder{ - valType: ptrType, - }, - } - } - if typ.Implements(unmarshalerType) { - return &unmarshalerDecoder{ - valType: typ, - } - } - if ptrType.Implements(textUnmarshalerType) { - return &referenceDecoder{ - &textUnmarshalerDecoder{ - valType: ptrType, - }, - } - } - if typ.Implements(textUnmarshalerType) { - return &textUnmarshalerDecoder{ - valType: typ, - } - } return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} } } @@ -103,6 +105,19 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { return encoder } } + + if typ == textMarshalerType { + return &directTextMarshalerEncoder{ + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + } + if typ.Implements(textMarshalerType) { + return &textMarshalerEncoder{ + valType: typ, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + } + switch typ.Kind() { case reflect.String: return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) @@ -117,17 +132,6 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { typ = reflect2.DefaultTypeOfKind(typ.Kind()) return &numericMapKeyEncoder{encoderOfType(ctx, typ)} default: - if typ == textMarshalerType { - return &directTextMarshalerEncoder{ - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - } - if typ.Implements(textMarshalerType) { - return &textMarshalerEncoder{ - valType: typ, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - } if typ.Kind() == reflect.Interface { return &dynamicMapKeyEncoder{ctx, typ} } @@ -163,10 +167,6 @@ func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { if c == '}' { return } - if c != '"' { - iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) - return - } iter.unreadByte() key := decoder.keyType.UnsafeNew() decoder.keyDecoder.Decode(key, iter) diff --git a/vendor/github.com/json-iterator/go/reflect_optional.go b/vendor/github.com/json-iterator/go/reflect_optional.go index 43ec71d6d..fa71f4748 100644 --- a/vendor/github.com/json-iterator/go/reflect_optional.go +++ b/vendor/github.com/json-iterator/go/reflect_optional.go @@ -2,7 +2,6 @@ package jsoniter import ( "github.com/modern-go/reflect2" - "reflect" "unsafe" ) @@ -10,9 +9,6 @@ func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { ptrType := typ.(*reflect2.UnsafePtrType) elemType := ptrType.Elem() decoder := decoderOfType(ctx, elemType) - if ctx.prefix == "" && elemType.Kind() == reflect.Ptr { - return &dereferenceDecoder{elemType, decoder} - } return &OptionalDecoder{elemType, decoder} } diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go index 5ad5cc561..d7eb0eb5c 100644 --- a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go +++ b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go @@ -507,7 +507,7 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) for c = ','; c == ','; c = iter.nextToken() { decoder.decodeOneField(ptr, iter) } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } if c != '}' { @@ -588,7 +588,7 @@ func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -622,7 +622,7 @@ func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -660,7 +660,7 @@ func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -702,7 +702,7 @@ func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -748,7 +748,7 @@ func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -798,7 +798,7 @@ func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -852,7 +852,7 @@ func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -910,7 +910,7 @@ func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -972,7 +972,7 @@ func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() @@ -1038,7 +1038,7 @@ func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator break } } - if iter.Error != nil && iter.Error != io.EOF { + if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) } iter.decrementDepth() diff --git a/vendor/github.com/json-iterator/go/stream.go b/vendor/github.com/json-iterator/go/stream.go index 17662fded..23d8a3ad6 100644 --- a/vendor/github.com/json-iterator/go/stream.go +++ b/vendor/github.com/json-iterator/go/stream.go @@ -103,14 +103,14 @@ func (stream *Stream) Flush() error { if stream.Error != nil { return stream.Error } - n, err := stream.out.Write(stream.buf) + _, err := stream.out.Write(stream.buf) if err != nil { if stream.Error == nil { stream.Error = err } return err } - stream.buf = stream.buf[n:] + stream.buf = stream.buf[:0] return nil } @@ -177,7 +177,6 @@ func (stream *Stream) WriteEmptyObject() { func (stream *Stream) WriteMore() { stream.writeByte(',') stream.writeIndention(0) - stream.Flush() } // WriteArrayStart write [ with possible indention diff --git a/vendor/github.com/tjfoc/gmsm/LICENSE b/vendor/github.com/tjfoc/gmsm/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/github.com/tjfoc/gmsm/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/tjfoc/gmsm/sm3/sm3.go b/vendor/github.com/tjfoc/gmsm/sm3/sm3.go new file mode 100644 index 000000000..1a610b993 --- /dev/null +++ b/vendor/github.com/tjfoc/gmsm/sm3/sm3.go @@ -0,0 +1,260 @@ +/* +Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sm3 + +import ( + "encoding/binary" + "hash" +) + +type SM3 struct { + digest [8]uint32 // digest represents the partial evaluation of V + length uint64 // length of the message + unhandleMsg []byte // uint8 // +} + +func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z } + +func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) } + +func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z } + +func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) } + +func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) } + +func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) } + +func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return (x<<(i%32) | x>>(32-i%32)) } + +func (sm3 *SM3) pad() []byte { + msg := sm3.unhandleMsg + msg = append(msg, 0x80) // Append '1' + blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512) + for len(msg)%blockSize != 56 { + msg = append(msg, 0x00) + } + // append message length + msg = append(msg, uint8(sm3.length>>56&0xff)) + msg = append(msg, uint8(sm3.length>>48&0xff)) + msg = append(msg, uint8(sm3.length>>40&0xff)) + msg = append(msg, uint8(sm3.length>>32&0xff)) + msg = append(msg, uint8(sm3.length>>24&0xff)) + msg = append(msg, uint8(sm3.length>>16&0xff)) + msg = append(msg, uint8(sm3.length>>8&0xff)) + msg = append(msg, uint8(sm3.length>>0&0xff)) + + if len(msg)%64 != 0 { + panic("------SM3 Pad: error msgLen =") + } + return msg +} + +func (sm3 *SM3) update(msg []byte, nblocks int) { + var w [68]uint32 + var w1 [64]uint32 + + a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] + for len(msg) >= 64 { + for i := 0; i < 16; i++ { + w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) + } + for i := 16; i < 68; i++ { + w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6] + } + for i := 0; i < 64; i++ { + w1[i] = w[i] ^ w[i+4] + } + A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h + for i := 0; i < 16; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + for i := 16; i < 64; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + a ^= A + b ^= B + c ^= C + d ^= D + e ^= E + f ^= F + g ^= G + h ^= H + msg = msg[64:] + } + sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h +} +func (sm3 *SM3) update2(msg []byte, nblocks int)([8]uint32){ + var w [68]uint32 + var w1 [64]uint32 + + a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] + for len(msg) >= 64 { + for i := 0; i < 16; i++ { + w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) + } + for i := 16; i < 68; i++ { + w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6] + } + for i := 0; i < 64; i++ { + w1[i] = w[i] ^ w[i+4] + } + A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h + for i := 0; i < 16; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + for i := 16; i < 64; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + a ^= A + b ^= B + c ^= C + d ^= D + e ^= E + f ^= F + g ^= G + h ^= H + msg = msg[64:] + } + var digest [8]uint32 + digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7] = a, b, c, d, e, f, g, h + return digest +} +func New() hash.Hash { + var sm3 SM3 + + sm3.Reset() + return &sm3 +} + +// BlockSize, required by the hash.Hash interface. +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (sm3 *SM3) BlockSize() int { return 64 } + +// Size, required by the hash.Hash interface. +// Size returns the number of bytes Sum will return. +func (sm3 *SM3) Size() int { return 32 } + +// Reset clears the internal state by zeroing bytes in the state buffer. +// This can be skipped for a newly-created hash state; the default zero-allocated state is correct. +func (sm3 *SM3) Reset() { + // Reset digest + sm3.digest[0] = 0x7380166f + sm3.digest[1] = 0x4914b2b9 + sm3.digest[2] = 0x172442d7 + sm3.digest[3] = 0xda8a0600 + sm3.digest[4] = 0xa96f30bc + sm3.digest[5] = 0x163138aa + sm3.digest[6] = 0xe38dee4d + sm3.digest[7] = 0xb0fb0e4e + + sm3.length = 0 // Reset numberic states + sm3.unhandleMsg = []byte{} +} + +// Write, required by the hash.Hash interface. +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (sm3 *SM3) Write(p []byte) (int, error) { + toWrite := len(p) + sm3.length += uint64(len(p) * 8) + msg := append(sm3.unhandleMsg, p...) + nblocks := len(msg) / sm3.BlockSize() + sm3.update(msg, nblocks) + // Update unhandleMsg + sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():] + + return toWrite, nil +} + +// Sum, required by the hash.Hash interface. +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (sm3 *SM3) Sum(in []byte) []byte { + sm3.Write(in) + msg := sm3.pad() + //Finialize + digest:=sm3.update2(msg, len(msg)/sm3.BlockSize()) + + // save hash to in + needed := sm3.Size() + if cap(in)-len(in) < needed { + newIn := make([]byte, len(in), len(in)+needed) + copy(newIn, in) + in = newIn + } + out := in[len(in) : len(in)+needed] + for i := 0; i < 8; i++ { + binary.BigEndian.PutUint32(out[i*4:], digest[i]) + } + return out + +} + +func Sm3Sum(data []byte) []byte { + var sm3 SM3 + + sm3.Reset() + sm3.Write(data) + return sm3.Sum(nil) +} diff --git a/vendor/github.com/yuin/goldmark/extension/typographer.go b/vendor/github.com/yuin/goldmark/extension/typographer.go index fc4040209..c3b975109 100644 --- a/vendor/github.com/yuin/goldmark/extension/typographer.go +++ b/vendor/github.com/yuin/goldmark/extension/typographer.go @@ -197,7 +197,10 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser if s.Substitutions[Apostrophe] != nil { // Handle decade abbrevations such as '90s if d.CanOpen && !d.CanClose && len(line) > 3 && util.IsNumeric(line[1]) && util.IsNumeric(line[2]) && line[3] == 's' { - after := util.ToRune(line, 4) + after := rune(' ') + if len(line) > 4 { + after = util.ToRune(line, 4) + } if len(line) == 3 || unicode.IsSpace(after) || unicode.IsPunct(after) { node := gast.NewString(s.Substitutions[Apostrophe]) node.SetCode(true) @@ -207,7 +210,7 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser } // Convert normal apostrophes. This is probably more flexible than necessary but // converts any apostrophe in between two alphanumerics. - if len(line) > 1 && (unicode.IsDigit(before) || unicode.IsLetter(before)) && (util.IsAlphaNumeric(line[1])) { + if len(line) > 1 && (unicode.IsDigit(before) || unicode.IsLetter(before)) && (unicode.IsLetter(util.ToRune(line, 1))) { node := gast.NewString(s.Substitutions[Apostrophe]) node.SetCode(true) block.Advance(1) diff --git a/vendor/github.com/yuin/goldmark/parser/atx_heading.go b/vendor/github.com/yuin/goldmark/parser/atx_heading.go index 0b63fabc0..a631e0b1f 100644 --- a/vendor/github.com/yuin/goldmark/parser/atx_heading.go +++ b/vendor/github.com/yuin/goldmark/parser/atx_heading.go @@ -232,7 +232,7 @@ func parseLastLineAttributes(node ast.Node, reader text.Reader, pc Context) { } lr.Advance(1) } - if ok && util.IsBlank(line[end.Stop:]) { + if ok && util.IsBlank(line[end.Start:]) { for _, attr := range attrs { node.SetAttribute(attr.Name, attr.Value) } diff --git a/vendor/golang.org/x/sync/semaphore/semaphore.go b/vendor/golang.org/x/sync/semaphore/semaphore.go index 7f096fef0..30f632c57 100644 --- a/vendor/golang.org/x/sync/semaphore/semaphore.go +++ b/vendor/golang.org/x/sync/semaphore/semaphore.go @@ -67,7 +67,12 @@ func (s *Weighted) Acquire(ctx context.Context, n int64) error { // fix up the queue, just pretend we didn't notice the cancelation. err = nil default: + isFront := s.waiters.Front() == elem s.waiters.Remove(elem) + // If we're at the front and there're extra tokens left, notify other waiters. + if isFront && s.size > s.cur { + s.notifyWaiters() + } } s.mu.Unlock() return err @@ -97,6 +102,11 @@ func (s *Weighted) Release(n int64) { s.mu.Unlock() panic("semaphore: released more than held") } + s.notifyWaiters() + s.mu.Unlock() +} + +func (s *Weighted) notifyWaiters() { for { next := s.waiters.Front() if next == nil { @@ -123,5 +133,4 @@ func (s *Weighted) Release(n int64) { s.waiters.Remove(next) close(w.ready) } - s.mu.Unlock() } diff --git a/vendor/gopkg.in/ini.v1/Makefile b/vendor/gopkg.in/ini.v1/Makefile index af27ff076..f3b0dae2d 100644 --- a/vendor/gopkg.in/ini.v1/Makefile +++ b/vendor/gopkg.in/ini.v1/Makefile @@ -6,7 +6,7 @@ test: go test -v -cover -race bench: - go test -v -cover -race -test.bench=. -test.benchmem + go test -v -cover -test.bench=. -test.benchmem vet: go vet diff --git a/vendor/gopkg.in/ini.v1/README.md b/vendor/gopkg.in/ini.v1/README.md index 3d6d3cfc0..5d65658b2 100644 --- a/vendor/gopkg.in/ini.v1/README.md +++ b/vendor/gopkg.in/ini.v1/README.md @@ -1,6 +1,9 @@ # INI -[![Build Status](https://img.shields.io/travis/go-ini/ini/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/go-ini/ini) [![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-ini/ini) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-ini/ini/Go?logo=github&style=for-the-badge)](https://github.com/go-ini/ini/actions?query=workflow%3AGo) +[![codecov](https://img.shields.io/codecov/c/github/go-ini/ini/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-ini/ini) +[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/go-ini/ini?tab=doc) +[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-ini/ini) ![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) @@ -8,7 +11,7 @@ Package ini provides INI file read and write functionality in Go. ## Features -- Load from multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites. +- Load from multiple data sources(file, `[]byte`, `io.Reader` and `io.ReadCloser`) with overwrites. - Read with recursion values. - Read with parent-child sections. - Read with auto-increment key names. @@ -33,6 +36,7 @@ Please add `-u` flag to update in the future. - [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) - [API Documentation](https://gowalker.org/gopkg.in/ini.v1) +- 中国大陆镜像:https://ini.unknwon.cn ## License diff --git a/vendor/gopkg.in/ini.v1/codecov.yml b/vendor/gopkg.in/ini.v1/codecov.yml new file mode 100644 index 000000000..fc947f230 --- /dev/null +++ b/vendor/gopkg.in/ini.v1/codecov.yml @@ -0,0 +1,9 @@ +coverage: + range: "60...95" + status: + project: + default: + threshold: 1% + +comment: + layout: 'diff, files' diff --git a/vendor/gopkg.in/ini.v1/data_source.go b/vendor/gopkg.in/ini.v1/data_source.go index dc0277ec6..c3a541f1d 100644 --- a/vendor/gopkg.in/ini.v1/data_source.go +++ b/vendor/gopkg.in/ini.v1/data_source.go @@ -68,6 +68,8 @@ func parseDataSource(source interface{}) (dataSource, error) { return &sourceData{s}, nil case io.ReadCloser: return &sourceReadCloser{s}, nil + case io.Reader: + return &sourceReadCloser{ioutil.NopCloser(s)}, nil default: return nil, fmt.Errorf("error parsing data source: unknown type %q", s) } diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/gopkg.in/ini.v1/file.go index 017b77c8b..f95606f90 100644 --- a/vendor/gopkg.in/ini.v1/file.go +++ b/vendor/gopkg.in/ini.v1/file.go @@ -25,7 +25,7 @@ import ( "sync" ) -// File represents a combination of a or more INI file(s) in memory. +// File represents a combination of one or more INI files in memory. type File struct { options LoadOptions dataSources []dataSource @@ -36,8 +36,12 @@ type File struct { // To keep data in order. sectionList []string + // To keep track of the index of a section with same name. + // This meta list is only used with non-unique section names are allowed. + sectionIndexes []int + // Actual data is stored here. - sections map[string]*Section + sections map[string][]*Section NameMapper ValueMapper @@ -48,27 +52,37 @@ func newFile(dataSources []dataSource, opts LoadOptions) *File { if len(opts.KeyValueDelimiters) == 0 { opts.KeyValueDelimiters = "=:" } + if len(opts.KeyValueDelimiterOnWrite) == 0 { + opts.KeyValueDelimiterOnWrite = "=" + } + return &File{ BlockMode: true, dataSources: dataSources, - sections: make(map[string]*Section), - sectionList: make([]string, 0, 10), + sections: make(map[string][]*Section), options: opts, } } // Empty returns an empty file object. -func Empty() *File { - // Ignore error here, we sure our data is good. - f, _ := Load([]byte("")) +func Empty(opts ...LoadOptions) *File { + var opt LoadOptions + if len(opts) > 0 { + opt = opts[0] + } + + // Ignore error here, we are sure our data is good. + f, _ := LoadSources(opt, []byte("")) return f } // NewSection creates a new section. func (f *File) NewSection(name string) (*Section, error) { if len(name) == 0 { - return nil, errors.New("error creating new section: empty section name") - } else if f.options.Insensitive && name != DefaultSection { + return nil, errors.New("empty section name") + } + + if f.options.Insensitive && name != DefaultSection { name = strings.ToLower(name) } @@ -77,13 +91,20 @@ func (f *File) NewSection(name string) (*Section, error) { defer f.lock.Unlock() } - if inSlice(name, f.sectionList) { - return f.sections[name], nil + if !f.options.AllowNonUniqueSections && inSlice(name, f.sectionList) { + return f.sections[name][0], nil } f.sectionList = append(f.sectionList, name) - f.sections[name] = newSection(f, name) - return f.sections[name], nil + + // NOTE: Append to indexes must happen before appending to sections, + // otherwise index will have off-by-one problem. + f.sectionIndexes = append(f.sectionIndexes, len(f.sections[name])) + + sec := newSection(f, name) + f.sections[name] = append(f.sections[name], sec) + + return sec, nil } // NewRawSection creates a new section with an unparseable body. @@ -110,6 +131,16 @@ func (f *File) NewSections(names ...string) (err error) { // GetSection returns section by given name. func (f *File) GetSection(name string) (*Section, error) { + secs, err := f.SectionsByName(name) + if err != nil { + return nil, err + } + + return secs[0], err +} + +// SectionsByName returns all sections with given name. +func (f *File) SectionsByName(name string) ([]*Section, error) { if len(name) == 0 { name = DefaultSection } @@ -122,11 +153,12 @@ func (f *File) GetSection(name string) (*Section, error) { defer f.lock.RUnlock() } - sec := f.sections[name] - if sec == nil { - return nil, fmt.Errorf("section '%s' does not exist", name) + secs := f.sections[name] + if len(secs) == 0 { + return nil, fmt.Errorf("section %q does not exist", name) } - return sec, nil + + return secs, nil } // Section assumes named section exists and returns a zero-value when not. @@ -141,6 +173,19 @@ func (f *File) Section(name string) *Section { return sec } +// SectionWithIndex assumes named section exists and returns a new section when not. +func (f *File) SectionWithIndex(name string, index int) *Section { + secs, err := f.SectionsByName(name) + if err != nil || len(secs) <= index { + // NOTE: It's OK here because the only possible error is empty section name, + // but if it's empty, this piece of code won't be executed. + newSec, _ := f.NewSection(name) + return newSec + } + + return secs[index] +} + // Sections returns a list of Section stored in the current instance. func (f *File) Sections() []*Section { if f.BlockMode { @@ -150,7 +195,7 @@ func (f *File) Sections() []*Section { sections := make([]*Section, len(f.sectionList)) for i, name := range f.sectionList { - sections[i] = f.sections[name] + sections[i] = f.sections[name][f.sectionIndexes[i]] } return sections } @@ -167,24 +212,70 @@ func (f *File) SectionStrings() []string { return list } -// DeleteSection deletes a section. +// DeleteSection deletes a section or all sections with given name. func (f *File) DeleteSection(name string) { - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() + secs, err := f.SectionsByName(name) + if err != nil { + return + } + + for i := 0; i < len(secs); i++ { + // For non-unique sections, it is always needed to remove the first one so + // in the next iteration, the subsequent section continue having index 0. + // Ignoring the error as index 0 never returns an error. + _ = f.DeleteSectionWithIndex(name, 0) + } +} + +// DeleteSectionWithIndex deletes a section with given name and index. +func (f *File) DeleteSectionWithIndex(name string, index int) error { + if !f.options.AllowNonUniqueSections && index != 0 { + return fmt.Errorf("delete section with non-zero index is only allowed when non-unique sections is enabled") } if len(name) == 0 { name = DefaultSection } + if f.options.Insensitive { + name = strings.ToLower(name) + } + + if f.BlockMode { + f.lock.Lock() + defer f.lock.Unlock() + } + + // Count occurrences of the sections + occurrences := 0 + + sectionListCopy := make([]string, len(f.sectionList)) + copy(sectionListCopy, f.sectionList) + + for i, s := range sectionListCopy { + if s != name { + continue + } - for i, s := range f.sectionList { - if s == name { + if occurrences == index { + if len(f.sections[name]) <= 1 { + delete(f.sections, name) // The last one in the map + } else { + f.sections[name] = append(f.sections[name][:index], f.sections[name][index+1:]...) + } + + // Fix section lists f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) - delete(f.sections, name) - return + f.sectionIndexes = append(f.sectionIndexes[:i], f.sectionIndexes[i+1:]...) + + } else if occurrences > index { + // Fix the indices of all following sections with this name. + f.sectionIndexes[i-1]-- } + + occurrences++ } + + return nil } func (f *File) reload(s dataSource) error { @@ -203,7 +294,7 @@ func (f *File) Reload() (err error) { if err = f.reload(s); err != nil { // In loose mode, we create an empty default section for nonexistent files. if os.IsNotExist(err) && f.options.Loose { - f.parse(bytes.NewBuffer(nil)) + _ = f.parse(bytes.NewBuffer(nil)) continue } return err @@ -230,16 +321,16 @@ func (f *File) Append(source interface{}, others ...interface{}) error { } func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { - equalSign := DefaultFormatLeft + "=" + DefaultFormatRight + equalSign := DefaultFormatLeft + f.options.KeyValueDelimiterOnWrite + DefaultFormatRight if PrettyFormat || PrettyEqual { - equalSign = " = " + equalSign = fmt.Sprintf(" %s ", f.options.KeyValueDelimiterOnWrite) } // Use buffer to make sure target is safe until finish encoding. buf := bytes.NewBuffer(nil) for i, sname := range f.sectionList { - sec := f.Section(sname) + sec := f.SectionWithIndex(sname, f.sectionIndexes[i]) if len(sec.Comment) > 0 { // Support multiline comments lines := strings.Split(sec.Comment, LineBreak) @@ -282,7 +373,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { } // Count and generate alignment length and buffer spaces using the - // longest key. Keys may be modifed if they contain certain characters so + // longest key. Keys may be modified if they contain certain characters so // we need to take that into account in our calculation. alignLength := 0 if PrettyFormat { diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go index fe913a0fd..2961543f9 100644 --- a/vendor/gopkg.in/ini.v1/ini.go +++ b/vendor/gopkg.in/ini.v1/ini.go @@ -18,8 +18,10 @@ package ini import ( + "os" "regexp" "runtime" + "strings" ) const ( @@ -29,14 +31,8 @@ const ( // Maximum allowed depth when recursively substituing variable names. depthValues = 99 - version = "1.52.0" ) -// Version returns current package version literal. -func Version() string { - return version -} - var ( // LineBreak is the delimiter to determine or compose a new line. // This variable will be changed to "\r\n" automatically on Windows at package init time. @@ -61,8 +57,10 @@ var ( DefaultFormatRight = "" ) +var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") + func init() { - if runtime.GOOS == "windows" { + if runtime.GOOS == "windows" && !inTest { LineBreak = "\r\n" } } @@ -109,12 +107,16 @@ type LoadOptions struct { UnparseableSections []string // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". KeyValueDelimiters string + // KeyValueDelimiters is the delimiter that are used to separate key and value output. By default, it is "=". + KeyValueDelimiterOnWrite string // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). PreserveSurroundedQuote bool // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values). DebugFunc DebugFunc // ReaderBufferSize is the buffer size of the reader in bytes. ReaderBufferSize int + // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. + AllowNonUniqueSections bool } // DebugFunc is the type of function called to log parse events. diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/gopkg.in/ini.v1/key.go index 3c197410f..8baafd9ea 100644 --- a/vendor/gopkg.in/ini.v1/key.go +++ b/vendor/gopkg.in/ini.v1/key.go @@ -686,99 +686,127 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) { // parseBools transforms strings to bools. func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) { vals := make([]bool, 0, len(strs)) - for _, str := range strs { + parser := func(str string) (interface{}, error) { val, err := parseBool(str) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(bool)) } } - return vals, nil + return vals, err } // parseFloat64s transforms strings to float64s. func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { vals := make([]float64, 0, len(strs)) - for _, str := range strs { + parser := func(str string) (interface{}, error) { val, err := strconv.ParseFloat(str, 64) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(float64)) } } - return vals, nil + return vals, err } // parseInts transforms strings to ints. func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { vals := make([]int, 0, len(strs)) - for _, str := range strs { - valInt64, err := strconv.ParseInt(str, 0, 64) - val := int(valInt64) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseInt(str, 0, 64) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, int(val.(int64))) } } - return vals, nil + return vals, err } // parseInt64s transforms strings to int64s. func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { vals := make([]int64, 0, len(strs)) - for _, str := range strs { + parser := func(str string) (interface{}, error) { val, err := strconv.ParseInt(str, 0, 64) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) + return val, err + } + + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(int64)) } } - return vals, nil + return vals, err } // parseUints transforms strings to uints. func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { vals := make([]uint, 0, len(strs)) - for _, str := range strs { - val, err := strconv.ParseUint(str, 0, 0) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, uint(val)) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseUint(str, 0, 64) + return val, err + } + + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, uint(val.(uint64))) } } - return vals, nil + return vals, err } // parseUint64s transforms strings to uint64s. func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { vals := make([]uint64, 0, len(strs)) - for _, str := range strs { + parser := func(str string) (interface{}, error) { val, err := strconv.ParseUint(str, 0, 64) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(uint64)) } } - return vals, nil + return vals, err } + +type Parser func(str string) (interface{}, error) + + // parseTimesFormat transforms strings to times in given format. func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { vals := make([]time.Time, 0, len(strs)) - for _, str := range strs { + parser := func(str string) (interface{}, error) { val, err := time.Parse(format, str) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(time.Time)) + } + } + return vals, err +} + + +// doParse transforms strings to different types +func (k *Key) doParse(strs []string, addInvalid, returnOnInvalid bool, parser Parser) ([]interface{}, error) { + vals := make([]interface{}, 0, len(strs)) + for _, str := range strs { + val, err := parser(str) if err != nil && returnOnInvalid { return nil, err } diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go index c0a93a62a..ea6c08b02 100644 --- a/vendor/gopkg.in/ini.v1/parser.go +++ b/vendor/gopkg.in/ini.v1/parser.go @@ -84,7 +84,10 @@ func (p *parser) BOM() error { case mask[0] == 254 && mask[1] == 255: fallthrough case mask[0] == 255 && mask[1] == 254: - p.buf.Read(mask) + _, err = p.buf.Read(mask) + if err != nil { + return err + } case mask[0] == 239 && mask[1] == 187: mask, err := p.buf.Peek(3) if err != nil && err != io.EOF { @@ -93,7 +96,10 @@ func (p *parser) BOM() error { return nil } if mask[2] == 191 { - p.buf.Read(mask) + _, err = p.buf.Read(mask) + if err != nil { + return err + } } } return nil @@ -135,7 +141,7 @@ func readKeyName(delimiters string, in []byte) (string, int, error) { } // Get out key name - endIdx := -1 + var endIdx int if len(keyQuote) > 0 { startIdx := len(keyQuote) // FIXME: fail case -> """"""name"""=value @@ -181,7 +187,7 @@ func (p *parser) readMultilines(line, val, valQuote string) (string, error) { } val += next if p.isEOF { - return "", fmt.Errorf("missing closing key quote from '%s' to '%s'", line, next) + return "", fmt.Errorf("missing closing key quote from %q to %q", line, next) } } return val, nil @@ -413,7 +419,10 @@ func (f *File) parse(reader io.Reader) (err error) { if f.options.AllowNestedValues && isLastValueEmpty && len(line) > 0 { if line[0] == ' ' || line[0] == '\t' { - lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) + err = lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) + if err != nil { + return err + } continue } } @@ -460,7 +469,7 @@ func (f *File) parse(reader io.Reader) (err error) { inUnparseableSection = false for i := range f.options.UnparseableSections { if f.options.UnparseableSections[i] == name || - (f.options.Insensitive && strings.ToLower(f.options.UnparseableSections[i]) == strings.ToLower(name)) { + (f.options.Insensitive && strings.EqualFold(f.options.UnparseableSections[i], name)) { inUnparseableSection = true continue } diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go index 0bd3e1301..6ba5ac290 100644 --- a/vendor/gopkg.in/ini.v1/section.go +++ b/vendor/gopkg.in/ini.v1/section.go @@ -131,7 +131,7 @@ func (s *Section) GetKey(name string) (*Key, error) { } break } - return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name) + return nil, fmt.Errorf("error when getting key of section %q: key %q not exists", s.name, name) } return key, nil } @@ -249,7 +249,7 @@ func (s *Section) ChildSections() []*Section { children := make([]*Section, 0, 3) for _, name := range s.f.sectionList { if strings.HasPrefix(name, prefix) { - children = append(children, s.f.sections[name]) + children = append(children, s.f.sections[name]...) } } return children diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go index a0c3ad5a4..1df547190 100644 --- a/vendor/gopkg.in/ini.v1/struct.go +++ b/vendor/gopkg.in/ini.v1/struct.go @@ -258,13 +258,13 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri case reflect.Slice: return setSliceWithProperType(key, field, delim, allowShadow, isStrict) default: - return fmt.Errorf("unsupported type '%s'", t) + return fmt.Errorf("unsupported type %q", t) } return nil } -func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { - opts := strings.SplitN(tag, ",", 3) +func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool) { + opts := strings.SplitN(tag, ",", 4) rawName = opts[0] if len(opts) > 1 { omitEmpty = opts[1] == "omitempty" @@ -272,10 +272,13 @@ func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bo if len(opts) > 2 { allowShadow = opts[2] == "allowshadow" } - return rawName, omitEmpty, allowShadow + if len(opts) > 3 { + allowNonUnique = opts[3] == "nonunique" + } + return rawName, omitEmpty, allowShadow, allowNonUnique } -func (s *Section) mapTo(val reflect.Value, isStrict bool) error { +func (s *Section) mapToField(val reflect.Value, isStrict bool) error { if val.Kind() == reflect.Ptr { val = val.Elem() } @@ -290,7 +293,7 @@ func (s *Section) mapTo(val reflect.Value, isStrict bool) error { continue } - rawName, _, allowShadow := parseTagOptions(tag) + rawName, _, allowShadow, allowNonUnique := parseTagOptions(tag) fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue @@ -310,49 +313,87 @@ func (s *Section) mapTo(val reflect.Value, isStrict bool) error { if isStructPtr && field.IsNil() { field.Set(reflect.New(tpField.Type.Elem())) } - if err = sec.mapTo(field, isStrict); err != nil { - return fmt.Errorf("error mapping field %q: %v", fieldName, err) + if err = sec.mapToField(field, isStrict); err != nil { + return fmt.Errorf("map to field %q: %v", fieldName, err) } continue } } + + // Map non-unique sections + if allowNonUnique && tpField.Type.Kind() == reflect.Slice { + newField, err := s.mapToSlice(fieldName, field, isStrict) + if err != nil { + return fmt.Errorf("map to slice %q: %v", fieldName, err) + } + + field.Set(newField) + continue + } + if key, err := s.GetKey(fieldName); err == nil { delim := parseDelim(tpField.Tag.Get("delim")) if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { - return fmt.Errorf("error mapping field %q: %v", fieldName, err) + return fmt.Errorf("set field %q: %v", fieldName, err) } } } return nil } -// MapTo maps section to given struct. -func (s *Section) MapTo(v interface{}) error { +// mapToSlice maps all sections with the same name and returns the new value. +// The type of the Value must be a slice. +func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (reflect.Value, error) { + secs, err := s.f.SectionsByName(secName) + if err != nil { + return reflect.Value{}, err + } + + typ := val.Type().Elem() + for _, sec := range secs { + elem := reflect.New(typ) + if err = sec.mapToField(elem, isStrict); err != nil { + return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err) + } + + val = reflect.Append(val, elem.Elem()) + } + return val, nil +} + +// mapTo maps a section to object v. +func (s *Section) mapTo(v interface{}, isStrict bool) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } else { - return errors.New("cannot map to non-pointer struct") + return errors.New("not a pointer to a struct") } - return s.mapTo(val, false) + if typ.Kind() == reflect.Slice { + newField, err := s.mapToSlice(s.name, val, isStrict) + if err != nil { + return err + } + + val.Set(newField) + return nil + } + + return s.mapToField(val, isStrict) +} + +// MapTo maps section to given struct. +func (s *Section) MapTo(v interface{}) error { + return s.mapTo(v, false) } // StrictMapTo maps section to given struct in strict mode, // which returns all possible error including value parsing error. func (s *Section) StrictMapTo(v interface{}) error { - typ := reflect.TypeOf(v) - val := reflect.ValueOf(v) - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - val = val.Elem() - } else { - return errors.New("cannot map to non-pointer struct") - } - - return s.mapTo(val, true) + return s.mapTo(v, true) } // MapTo maps file to given struct. @@ -430,7 +471,7 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, all if i == 0 { keyWithShadows = newKey(key.s, key.name, val) } else { - keyWithShadows.AddShadow(val) + _ = keyWithShadows.AddShadow(val) } } key = keyWithShadows @@ -483,7 +524,7 @@ func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow) } default: - return fmt.Errorf("unsupported type '%s'", t) + return fmt.Errorf("unsupported type %q", t) } return nil } @@ -523,6 +564,10 @@ func (s *Section) reflectFrom(val reflect.Value) error { typ := val.Type() for i := 0; i < typ.NumField(); i++ { + if !val.Field(i).CanInterface() { + continue + } + field := val.Field(i) tpField := typ.Field(i) @@ -531,7 +576,7 @@ func (s *Section) reflectFrom(val reflect.Value) error { continue } - rawName, omitEmpty, allowShadow := parseTagOptions(tag) + rawName, omitEmpty, allowShadow, allowNonUnique := parseTagOptions(tag) if omitEmpty && isEmptyValue(field) { continue } @@ -560,11 +605,41 @@ func (s *Section) reflectFrom(val reflect.Value) error { } if err = sec.reflectFrom(field); err != nil { - return fmt.Errorf("error reflecting field %q: %v", fieldName, err) + return fmt.Errorf("reflect from field %q: %v", fieldName, err) + } + continue + } + + if allowNonUnique && tpField.Type.Kind() == reflect.Slice { + slice := field.Slice(0, field.Len()) + if field.Len() == 0 { + return nil + } + sliceOf := field.Type().Elem().Kind() + + for i := 0; i < field.Len(); i++ { + if sliceOf != reflect.Struct && sliceOf != reflect.Ptr { + return fmt.Errorf("field %q is not a slice of pointer or struct", fieldName) + } + + sec, err := s.f.NewSection(fieldName) + if err != nil { + return err + } + + // Add comment from comment tag + if len(sec.Comment) == 0 { + sec.Comment = tpField.Tag.Get("comment") + } + + if err := sec.reflectFrom(slice.Index(i)); err != nil { + return fmt.Errorf("reflect from field %q: %v", fieldName, err) + } } continue } + // Note: Same reason as section. key, err := s.GetKey(fieldName) if err != nil { key, _ = s.NewKey(fieldName, "") @@ -577,22 +652,56 @@ func (s *Section) reflectFrom(val reflect.Value) error { delim := parseDelim(tpField.Tag.Get("delim")) if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { - return fmt.Errorf("error reflecting field %q: %v", fieldName, err) + return fmt.Errorf("reflect field %q: %v", fieldName, err) } } return nil } -// ReflectFrom reflects secion from given struct. +// ReflectFrom reflects section from given struct. It overwrites existing ones. func (s *Section) ReflectFrom(v interface{}) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) + + if s.name != DefaultSection && s.f.options.AllowNonUniqueSections && + (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr) { + // Clear sections to make sure none exists before adding the new ones + s.f.DeleteSection(s.name) + + if typ.Kind() == reflect.Ptr { + sec, err := s.f.NewSection(s.name) + if err != nil { + return err + } + return sec.reflectFrom(val.Elem()) + } + + slice := val.Slice(0, val.Len()) + sliceOf := val.Type().Elem().Kind() + if sliceOf != reflect.Ptr { + return fmt.Errorf("not a slice of pointers") + } + + for i := 0; i < slice.Len(); i++ { + sec, err := s.f.NewSection(s.name) + if err != nil { + return err + } + + err = sec.reflectFrom(slice.Index(i)) + if err != nil { + return fmt.Errorf("reflect from %dth field: %v", i, err) + } + } + + return nil + } + if typ.Kind() == reflect.Ptr { - typ = typ.Elem() val = val.Elem() } else { - return errors.New("cannot reflect from non-pointer struct") + return errors.New("not a pointer to a struct") } return s.reflectFrom(val) diff --git a/vendor/modules.txt b/vendor/modules.txt index 343224c59..383109df4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -100,6 +100,34 @@ github.com/RichardKnop/redsync # github.com/RoaringBitmap/roaring v0.4.23 ## explicit github.com/RoaringBitmap/roaring +# github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 +github.com/alibabacloud-go/alibabacloud-gateway-spi/client +# github.com/alibabacloud-go/darabonba-openapi v0.1.18 +## explicit +github.com/alibabacloud-go/darabonba-openapi/client +# github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 +github.com/alibabacloud-go/debug/debug +# github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 +## explicit +github.com/alibabacloud-go/dysmsapi-20170525/v2/client +# github.com/alibabacloud-go/endpoint-util v1.1.0 +github.com/alibabacloud-go/endpoint-util/service +# github.com/alibabacloud-go/openapi-util v0.0.11 +github.com/alibabacloud-go/openapi-util/service +# github.com/alibabacloud-go/tea v1.1.17 +## explicit +github.com/alibabacloud-go/tea/tea +github.com/alibabacloud-go/tea/utils +# github.com/alibabacloud-go/tea-utils v1.4.3 +github.com/alibabacloud-go/tea-utils/service +# github.com/alibabacloud-go/tea-xml v1.1.2 +## explicit +github.com/alibabacloud-go/tea-xml/service +# github.com/aliyun/credentials-go v1.1.2 +github.com/aliyun/credentials-go/credentials +github.com/aliyun/credentials-go/credentials/request +github.com/aliyun/credentials-go/credentials/response +github.com/aliyun/credentials-go/credentials/utils # github.com/andybalholm/cascadia v1.0.0 github.com/andybalholm/cascadia # github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 @@ -214,6 +242,9 @@ github.com/boombuler/barcode/utils github.com/bradfitz/gomemcache/memcache # github.com/chris-ramon/douceur v0.2.0 github.com/chris-ramon/douceur/parser +# github.com/clbanning/mxj/v2 v2.5.5 +## explicit +github.com/clbanning/mxj/v2 # github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 ## explicit github.com/couchbase/gomemcached @@ -515,7 +546,7 @@ github.com/jmespath/go-jmespath ## explicit # github.com/joho/godotenv v1.3.0 ## explicit -# github.com/json-iterator/go v1.1.9 +# github.com/json-iterator/go v1.1.10 github.com/json-iterator/go # github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 ## explicit @@ -778,6 +809,8 @@ github.com/syndtr/goleveldb/leveldb/util # github.com/tinylib/msgp v1.1.2 ## explicit github.com/tinylib/msgp/msgp +# github.com/tjfoc/gmsm v1.3.2 +github.com/tjfoc/gmsm/sm3 # github.com/toqueteos/trie v1.0.0 github.com/toqueteos/trie # github.com/toqueteos/webbrowser v1.2.0 @@ -815,7 +848,7 @@ github.com/xdg/stringprep # github.com/yohcop/openid-go v1.0.0 ## explicit github.com/yohcop/openid-go -# github.com/yuin/goldmark v1.1.27 +# github.com/yuin/goldmark v1.1.30 ## explicit github.com/yuin/goldmark github.com/yuin/goldmark/ast @@ -878,7 +911,7 @@ go.opencensus.io/trace go.opencensus.io/trace/internal go.opencensus.io/trace/propagation go.opencensus.io/trace/tracestate -# golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 +# golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 ## explicit golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert @@ -933,7 +966,7 @@ golang.org/x/oauth2/google golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e +# golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a golang.org/x/sync/errgroup golang.org/x/sync/semaphore # golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f @@ -1118,7 +1151,7 @@ gopkg.in/asn1-ber.v1 # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ## explicit gopkg.in/gomail.v2 -# gopkg.in/ini.v1 v1.52.0 +# gopkg.in/ini.v1 v1.56.0 ## explicit gopkg.in/ini.v1 # gopkg.in/ldap.v3 v3.0.2 From 55970e9dbc9f9885baa08989d451b97bc5f5f0e6 Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 30 May 2022 11:12:24 +0800 Subject: [PATCH 002/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- models/cloudbrain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/cloudbrain.go b/models/cloudbrain.go index 480350c8d..db91875ef 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -1300,7 +1300,7 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { builder.Eq{"repo_id": repoId}, ) cond = cond.And( - builder.Eq{"Status": "COMPLETED"}, + builder.In("Status", "COMPLETED", "SUCCEEDED"), ) cond = cond.And( builder.Eq{"job_type": "TRAIN"}, From 8bc64ef9eed90df35c53d27756833fe23fbd2ed0 Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 30 May 2022 11:13:31 +0800 Subject: [PATCH 003/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0GPU=E8=AE=AD=E7=BB=83=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=A8=A1=E5=9E=8B=E9=80=89=E6=8B=A9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- models/cloudbrain.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/cloudbrain.go b/models/cloudbrain.go index db91875ef..9f517b51d 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -1279,7 +1279,8 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) builder.Eq{"cloudbrain.job_id": jobId}, ) cond = cond.And( - builder.Eq{"cloudbrain.Status": "COMPLETED"}, + builder.In("cloudbrain.Status", "COMPLETED", "SUCCEEDED"), + //builder.Eq{"cloudbrain.Status": "COMPLETED"}, ) sess.OrderBy("cloudbrain.created_unix DESC") From 90558a4c611bd6c909e89ef1fea7be8a2f5ab64e Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 30 May 2022 14:22:22 +0800 Subject: [PATCH 004/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- modules/storage/minio_ext.go | 33 +++++++++++++++++++++++++++++++++ routers/repo/ai_model_manage.go | 17 +++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/modules/storage/minio_ext.go b/modules/storage/minio_ext.go index 167cd0488..9e9c91573 100755 --- a/modules/storage/minio_ext.go +++ b/modules/storage/minio_ext.go @@ -116,6 +116,39 @@ func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSiz } +func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { + _, core, err := getClients() + var count int64 + count = 0 + if err != nil { + log.Error("getClients failed:", err.Error()) + return count, err + } + delimiter := "" + marker := "" + for { + output, err := core.ListObjects(bucketName, srcPath, marker, delimiter, 1000) + if err == nil { + for _, val := range output.Contents { + srcObjectName := val.Key + destObjectName := destPath + srcObjectName[len(srcPath):] + log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName) + core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, val.UserMetadata) + count++ + } + if output.IsTruncated { + marker = output.NextMarker + } else { + break + } + } else { + log.Info("list error." + err.Error()) + return 0, err + } + } + return count, nil +} + func NewMultiPartUpload(uuid string) (string, error) { _, core, err := getClients() if err != nil { diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index e2040e0d2..ed882ffd7 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -39,7 +39,6 @@ func saveModelByParameters(jobId string, versionName string, name string, versio modelPath := id var lastNewModelId string var modelSize int64 - cloudType := models.TypeCloudBrainTwo log.Info("find task name:" + aiTask.JobName) aimodels := models.QueryModelByName(name, aiTask.RepoID) @@ -53,7 +52,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio } } } - cloudType = aiTask.Type + cloudType := aiTask.Type //download model zip //train type if cloudType == models.TypeCloudBrainTwo { modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl) @@ -61,6 +60,8 @@ func saveModelByParameters(jobId string, versionName string, name string, versio log.Info("download model from CloudBrainTwo faild." + err.Error()) return err } + } else if cloudType == models.TypeCloudBrainOne { + } accuracy := make(map[string]string) accuracy["F1"] = "" @@ -199,6 +200,18 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir return dataActualPath, size, nil } +func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { + modelActualPath := storage.GetMinioPath(jobName, "/model/") + destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" + size, err := storage.MinioPathCopy(setting.Bucket, modelActualPath, destKeyNamePrefix) + if err == nil { + dataActualPath := setting.Bucket + "/" + destKeyNamePrefix + return dataActualPath, size, nil + } else { + return "", 0, nil + } +} + func DeleteModel(ctx *context.Context) { log.Info("delete model start.") id := ctx.Query("ID") From f067782abb33f415975995b93eb513da8935e437 Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 30 May 2022 15:08:38 +0800 Subject: [PATCH 005/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_manage.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index ed882ffd7..78d2e1327 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -61,7 +61,11 @@ func saveModelByParameters(jobId string, versionName string, name string, versio return err } } else if cloudType == models.TypeCloudBrainOne { - + modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl) + if err != nil { + log.Info("download model from CloudBrainOne faild." + err.Error()) + return err + } } accuracy := make(map[string]string) accuracy["F1"] = "" @@ -290,7 +294,15 @@ func DownloadMultiModelFile(ctx *context.Context) { } path := Model_prefix + models.AttachmentRelativePath(id) + "/" + if task.Type == models.TypeCloudBrainTwo { + + } else if task.Type == models.TypeCloudBrainOne { + + } + +} +func downloadFromCloudBrainTwo(path string, task *models.AiModelManage, ctx *context.Context, id string) { allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) if err == nil { //count++ From 3075b8c23fc1826bce888c805e691c092ef31c8e Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 30 May 2022 15:41:20 +0800 Subject: [PATCH 006/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- modules/storage/minio_ext.go | 101 ++++++++++++++++++++++++++++++++++++++++ routers/repo/ai_model_manage.go | 58 +++++++++++++++++++++-- 2 files changed, 156 insertions(+), 3 deletions(-) diff --git a/modules/storage/minio_ext.go b/modules/storage/minio_ext.go index 9e9c91573..6aeaec623 100755 --- a/modules/storage/minio_ext.go +++ b/modules/storage/minio_ext.go @@ -116,6 +116,107 @@ func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSiz } +func GetAllObjectByBucketAndPrefixMinio(bucket string, prefix string) ([]FileInfo, error) { + _, core, err := getClients() + if err != nil { + log.Error("getClients failed:", err.Error()) + return nil, err + } + prefixLen := len(prefix) + delimiter := "" + marker := "" + index := 1 + fileInfoList := FileInfoList{} + for { + output, err := core.ListObjects(bucket, prefix, marker, delimiter, 1000) + if err == nil { + log.Info("Page:%d\n", index) + index++ + for _, val := range output.Contents { + var isDir bool + if prefixLen == len(val.Key) { + continue + } + if strings.HasSuffix(val.Key, "/") { + isDir = true + } else { + isDir = false + } + fileInfo := FileInfo{ + ModTime: val.LastModified.Format("2006-01-02 15:04:05"), + FileName: val.Key[prefixLen:], + Size: val.Size, + IsDir: isDir, + ParenDir: "", + } + fileInfoList = append(fileInfoList, fileInfo) + } + if output.IsTruncated { + marker = output.NextMarker + } else { + break + } + } else { + log.Info("list error." + err.Error()) + return nil, err + } + } + sort.Sort(fileInfoList) + return fileInfoList, nil +} + +func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, relativePath string) ([]FileInfo, error) { + _, core, err := getClients() + if err != nil { + log.Error("getClients failed:", err.Error()) + return nil, err + } + + Prefix := prefixRootPath + relativePath + if !strings.HasSuffix(Prefix, "/") { + Prefix += "/" + } + output, err := core.ListObjects(bucket, Prefix, "", "", 1000) + fileInfos := make([]FileInfo, 0) + prefixLen := len(Prefix) + if err == nil { + for _, val := range output.Contents { + log.Info("val key=" + val.Key) + var isDir bool + var fileName string + if val.Key == Prefix { + continue + } + if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { + continue + } + if strings.HasSuffix(val.Key, "/") { + isDir = true + fileName = val.Key[prefixLen : len(val.Key)-1] + relativePath += val.Key[prefixLen:] + } else { + isDir = false + fileName = val.Key[prefixLen:] + } + fileInfo := FileInfo{ + ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), + FileName: fileName, + Size: val.Size, + IsDir: isDir, + ParenDir: relativePath, + } + fileInfos = append(fileInfos, fileInfo) + } + return fileInfos, err + } else { + + log.Error("Message:%s", err.Error()) + + return nil, err + } + +} + func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { _, core, err := getClients() var count int64 diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 78d2e1327..53030949e 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "net/url" "path" "strings" @@ -295,13 +296,64 @@ func DownloadMultiModelFile(ctx *context.Context) { path := Model_prefix + models.AttachmentRelativePath(id) + "/" if task.Type == models.TypeCloudBrainTwo { - + downloadFromCloudBrainTwo(path, task, ctx, id) } else if task.Type == models.TypeCloudBrainOne { - + downloadFromCloudBrainOne(path, task, ctx, id) } } +func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *context.Context, id string) { + allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) + if err == nil { + //count++ + models.ModifyModelDownloadCount(id) + + returnFileName := task.Name + "_" + task.Version + ".zip" + ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName)) + ctx.Resp.Header().Set("Content-Type", "application/octet-stream") + w := zip.NewWriter(ctx.Resp) + defer w.Close() + for _, oneFile := range allFile { + if oneFile.IsDir { + log.Info("zip dir name:" + oneFile.FileName) + } else { + log.Info("zip file name:" + oneFile.FileName) + fDest, err := w.Create(oneFile.FileName) + if err != nil { + log.Info("create zip entry error, download file failed: %s\n", err.Error()) + ctx.ServerError("download file failed:", err) + return + } + body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) + if err != nil { + log.Info("download file failed: %s\n", err.Error()) + ctx.ServerError("download file failed:", err) + return + } else { + defer body.Close() + p := make([]byte, 1024) + var readErr error + var readCount int + // 读取对象内容 + for { + readCount, readErr = body.Read(p) + if readCount > 0 { + fDest.Write(p[:readCount]) + } + if readErr != nil { + break + } + } + } + } + } + } else { + log.Info("error,msg=" + err.Error()) + ctx.ServerError("no file to download.", err) + } +} + func downloadFromCloudBrainTwo(path string, task *models.AiModelManage, ctx *context.Context, id string) { allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) if err == nil { @@ -309,7 +361,7 @@ func downloadFromCloudBrainTwo(path string, task *models.AiModelManage, ctx *con models.ModifyModelDownloadCount(id) returnFileName := task.Name + "_" + task.Version + ".zip" - ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+returnFileName) + ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName)) ctx.Resp.Header().Set("Content-Type", "application/octet-stream") w := zip.NewWriter(ctx.Resp) defer w.Close() From bcb5f69d0377e36ca01e2cfd8184da355703c111 Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 30 May 2022 17:54:35 +0800 Subject: [PATCH 007/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E5=AF=B9minio=E6=A8=A1=E5=9E=8B=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- modules/storage/minio.go | 10 ++++++++++ modules/storage/minio_ext.go | 1 - routers/repo/ai_model_manage.go | 21 +++++++++++---------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 7b914817d..47f70e12d 100755 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -59,6 +59,16 @@ func (m *MinioStorage) buildMinioPath(p string) string { return strings.TrimPrefix(path.Join(m.basePath, p), "/") } +func (m *MinioStorage) DownloadAFile(bucket string, objectName string) (io.ReadCloser, error) { + + var opts = minio.GetObjectOptions{} + object, err := m.client.GetObject(m.bucket, objectName, opts) + if err != nil { + return nil, err + } + return object, nil +} + // Open open a file func (m *MinioStorage) Open(path string) (io.ReadCloser, error) { var opts = minio.GetObjectOptions{} diff --git a/modules/storage/minio_ext.go b/modules/storage/minio_ext.go index 6aeaec623..82efcc710 100755 --- a/modules/storage/minio_ext.go +++ b/modules/storage/minio_ext.go @@ -113,7 +113,6 @@ func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSiz objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/") return minioClient.GenUploadPartSignedUrl(uploadId, bucketName, objectName, partNumber, partSize, PresignedUploadPartUrlExpireTime, setting.Attachment.Minio.Location) - } func GetAllObjectByBucketAndPrefixMinio(bucket string, prefix string) ([]FileInfo, error) { diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 53030949e..ef8c4b754 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -207,14 +207,15 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { modelActualPath := storage.GetMinioPath(jobName, "/model/") - destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" - size, err := storage.MinioPathCopy(setting.Bucket, modelActualPath, destKeyNamePrefix) - if err == nil { - dataActualPath := setting.Bucket + "/" + destKeyNamePrefix - return dataActualPath, size, nil - } else { - return "", 0, nil - } + log.Info("modelActualPath=" + modelActualPath) + //destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" + //size, err := storage.MinioPathCopy(setting.Bucket, modelActualPath, destKeyNamePrefix) + //if err == nil { + // dataActualPath := setting.Bucket + "/" + destKeyNamePrefix + // return dataActualPath, size, nil + //} else { + return "", 0, nil + //} } func DeleteModel(ctx *context.Context) { @@ -304,7 +305,7 @@ func DownloadMultiModelFile(ctx *context.Context) { } func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *context.Context, id string) { - allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) + allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path) if err == nil { //count++ models.ModifyModelDownloadCount(id) @@ -325,7 +326,7 @@ func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *con ctx.ServerError("download file failed:", err) return } - body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) + body, err := storage.Attachments.Open(oneFile.FileName) if err != nil { log.Info("download file failed: %s\n", err.Error()) ctx.ServerError("download file failed:", err) From 6ac80be14ce1353f025088ef1bba15902499bf2e Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 09:29:16 +0800 Subject: [PATCH 008/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- templates/repo/modelmanage/index.tmpl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/repo/modelmanage/index.tmpl b/templates/repo/modelmanage/index.tmpl index 73baa6c93..e65fbf004 100644 --- a/templates/repo/modelmanage/index.tmpl +++ b/templates/repo/modelmanage/index.tmpl @@ -248,8 +248,12 @@ if(data.length){ $("#job-version").append(train_html) $(".ui.dropdown.selection.search.width70").removeClass("loading") - $('#choice_version .default.text').text(data[0].VersionName) - $('#choice_version input[name="VersionName"]').val(data[0].VersionName) + var versionName = data[0].VersionName; + if(versionName==null || versionName==""){ + versionName="V0001"; + } + $('#choice_version .default.text').text(versionName) + $('#choice_version input[name="VersionName"]').val(versionName) } }) From 0bae82764609658bb01edf122b212e886f667f3f Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 09:43:09 +0800 Subject: [PATCH 009/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_manage.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index ef8c4b754..375bbaaa6 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -31,10 +31,14 @@ const ( func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error { aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName) if err != nil { - log.Info("query task error." + err.Error()) - return err + aiTask, err = models.GetRepoCloudBrainByJobID(ctx.Repo.Repository.ID, jobId) + if err != nil { + log.Info("query task error." + err.Error()) + return err + } else { + log.Info("query gpu train task.") + } } - uuid := uuid.NewV4() id := uuid.String() modelPath := id From 0866da75780cd32d65a118f77f22a519f47de97c Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 09:53:22 +0800 Subject: [PATCH 010/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_manage.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 375bbaaa6..173966742 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -212,14 +212,16 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { modelActualPath := storage.GetMinioPath(jobName, "/model/") log.Info("modelActualPath=" + modelActualPath) - //destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" - //size, err := storage.MinioPathCopy(setting.Bucket, modelActualPath, destKeyNamePrefix) - //if err == nil { - // dataActualPath := setting.Bucket + "/" + destKeyNamePrefix - // return dataActualPath, size, nil - //} else { - return "", 0, nil - //} + modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" + destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" + log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix) + size, err := storage.MinioPathCopy(setting.Bucket, modelSrcPrefix, destKeyNamePrefix) + if err == nil { + dataActualPath := setting.Bucket + "/" + destKeyNamePrefix + return dataActualPath, size, nil + } else { + return "", 0, nil + } } func DeleteModel(ctx *context.Context) { From 8ffdd2113ba898a21b9511db6828fd34a849ef77 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 10:05:40 +0800 Subject: [PATCH 011/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_manage.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 173966742..e7ce72e11 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -214,10 +214,11 @@ func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir log.Info("modelActualPath=" + modelActualPath) modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" - log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix) - size, err := storage.MinioPathCopy(setting.Bucket, modelSrcPrefix, destKeyNamePrefix) + bucketName := setting.Attachment.Minio.Bucket + log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName) + size, err := storage.MinioPathCopy(bucketName, modelSrcPrefix, destKeyNamePrefix) if err == nil { - dataActualPath := setting.Bucket + "/" + destKeyNamePrefix + dataActualPath := bucketName + "/" + destKeyNamePrefix return dataActualPath, size, nil } else { return "", 0, nil From 086c12b9604d6c86cf6a41f936122e74c7c1a0c4 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 10:18:34 +0800 Subject: [PATCH 012/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_manage.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index e7ce72e11..a3a49af3a 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -774,9 +774,11 @@ func QueryModelFileForPredict(ctx *context.Context) { ctx.ServerError("no such model:", err) return } - prefix := model.Path[len(setting.Bucket)+1:] - fileinfos, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix) - ctx.JSON(http.StatusOK, fileinfos) + if model.Type == models.TypeCloudBrainTwo { + prefix := model.Path[len(setting.Bucket)+1:] + fileinfos, _ := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix) + ctx.JSON(http.StatusOK, fileinfos) + } } func QueryOneLevelModelFile(ctx *context.Context) { @@ -788,7 +790,14 @@ func QueryOneLevelModelFile(ctx *context.Context) { ctx.ServerError("no such model:", err) return } - prefix := model.Path[len(setting.Bucket)+1:] - fileinfos, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir) - ctx.JSON(http.StatusOK, fileinfos) + if model.Type == models.TypeCloudBrainTwo { + prefix := model.Path[len(setting.Bucket)+1:] + fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir) + ctx.JSON(http.StatusOK, fileinfos) + } else if model.Type == models.TypeCloudBrainOne { + prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] + fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir) + ctx.JSON(http.StatusOK, fileinfos) + } + } From 7206faf1c7212b9a62c966ac2e612076060639b7 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 10:23:36 +0800 Subject: [PATCH 013/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- modules/storage/minio_ext.go | 1 + routers/repo/ai_model_manage.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/modules/storage/minio_ext.go b/modules/storage/minio_ext.go index 82efcc710..cbbc0179b 100755 --- a/modules/storage/minio_ext.go +++ b/modules/storage/minio_ext.go @@ -175,6 +175,7 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel if !strings.HasSuffix(Prefix, "/") { Prefix += "/" } + log.Info("bucket=" + bucket + " Prefix=" + Prefix) output, err := core.ListObjects(bucket, Prefix, "", "", 1000) fileInfos := make([]FileInfo, 0) prefixLen := len(Prefix) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index a3a49af3a..4bc54bf5f 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -791,10 +791,12 @@ func QueryOneLevelModelFile(ctx *context.Context) { return } if model.Type == models.TypeCloudBrainTwo { + log.Info("TypeCloudBrainTwo list model file.") prefix := model.Path[len(setting.Bucket)+1:] fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir) ctx.JSON(http.StatusOK, fileinfos) } else if model.Type == models.TypeCloudBrainOne { + log.Info("TypeCloudBrainOne list model file.") prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir) ctx.JSON(http.StatusOK, fileinfos) From cf23e013ee02695416709c42967d7142902cb529 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 10:40:29 +0800 Subject: [PATCH 014/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_manage.go | 65 ++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 4bc54bf5f..7a02a5322 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -459,42 +459,55 @@ func DownloadSingleModelFile(ctx *context.Context) { ctx.NotFound(ctx.Req.URL.RequestURI(), nil) return } - if setting.PROXYURL != "" { - body, err := storage.ObsDownloadAFile(setting.Bucket, path) - if err != nil { - log.Info("download error.") + if task.Type == models.TypeCloudBrainTwo { + if setting.PROXYURL != "" { + body, err := storage.ObsDownloadAFile(setting.Bucket, path) + if err != nil { + log.Info("download error.") + } else { + //count++ + models.ModifyModelDownloadCount(id) + defer body.Close() + ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName) + ctx.Resp.Header().Set("Content-Type", "application/octet-stream") + p := make([]byte, 1024) + var readErr error + var readCount int + // 读取对象内容 + for { + readCount, readErr = body.Read(p) + if readCount > 0 { + ctx.Resp.Write(p[:readCount]) + //fmt.Printf("%s", p[:readCount]) + } + if readErr != nil { + break + } + } + } } else { + url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) + if err != nil { + log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("GetObsCreateSignedUrl", err) + return + } //count++ models.ModifyModelDownloadCount(id) - defer body.Close() - ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName) - ctx.Resp.Header().Set("Content-Type", "application/octet-stream") - p := make([]byte, 1024) - var readErr error - var readCount int - // 读取对象内容 - for { - readCount, readErr = body.Read(p) - if readCount > 0 { - ctx.Resp.Write(p[:readCount]) - //fmt.Printf("%s", p[:readCount]) - } - if readErr != nil { - break - } - } + http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) } - } else { - url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) + } else if task.Type == models.TypeCloudBrainOne { + log.Info("start to down load minio file.") + url, err := storage.Attachments.PresignedGetURL(path, fileName) if err != nil { - log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) - ctx.ServerError("GetObsCreateSignedUrl", err) + log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("Get minio get SignedUrl failed", err) return } - //count++ models.ModifyModelDownloadCount(id) http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) } + } func ShowModelInfo(ctx *context.Context) { From 788764a51fe8bec061f62ff3bb2e29090bb3d158 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 10:46:23 +0800 Subject: [PATCH 015/562] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- modules/storage/minio_ext.go | 10 +++++----- routers/repo/ai_model_manage.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/storage/minio_ext.go b/modules/storage/minio_ext.go index cbbc0179b..514ac7204 100755 --- a/modules/storage/minio_ext.go +++ b/modules/storage/minio_ext.go @@ -219,11 +219,11 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { _, core, err := getClients() - var count int64 - count = 0 + var fileTotalSize int64 + fileTotalSize = 0 if err != nil { log.Error("getClients failed:", err.Error()) - return count, err + return fileTotalSize, err } delimiter := "" marker := "" @@ -235,7 +235,7 @@ func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, e destObjectName := destPath + srcObjectName[len(srcPath):] log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName) core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, val.UserMetadata) - count++ + fileTotalSize += val.Size } if output.IsTruncated { marker = output.NextMarker @@ -247,7 +247,7 @@ func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, e return 0, err } } - return count, nil + return fileTotalSize, nil } func NewMultiPartUpload(uuid string) (string, error) { diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 7a02a5322..a13095d52 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -333,7 +333,7 @@ func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *con ctx.ServerError("download file failed:", err) return } - body, err := storage.Attachments.Open(oneFile.FileName) + body, err := storage.Attachments.Open(path + oneFile.FileName) if err != nil { log.Info("download file failed: %s\n", err.Error()) ctx.ServerError("download file failed:", err) From 87375ce6cc68818c4b8d389742d6041cab755051 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 16:15:02 +0800 Subject: [PATCH 016/562] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E4=BB=BB=E5=8A=A1=E7=95=8C=E9=9D=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- models/ai_model_manage.go | 110 ++++++++++- models/models.go | 1 + options/locale/locale_en-US.ini | 3 + options/locale/locale_zh-CN.ini | 3 + routers/repo/ai_model_manage.go | 21 +- routers/routes/routes.go | 1 + templates/repo/modelmanage/convertIndex.tmpl | 285 +++++++++++++++++++++++++++ templates/repo/modelmanage/index.tmpl | 7 +- 8 files changed, 421 insertions(+), 10 deletions(-) create mode 100644 templates/repo/modelmanage/convertIndex.tmpl diff --git a/models/ai_model_manage.go b/models/ai_model_manage.go index ed696fcf0..ac4aed302 100644 --- a/models/ai_model_manage.go +++ b/models/ai_model_manage.go @@ -39,6 +39,29 @@ type AiModelManage struct { IsCanDelete bool } +type AiModelManageConvert struct { + ID string `xorm:"pk"` + Name string `xorm:"INDEX NOT NULL"` + Status int `xorm:"NOT NULL DEFAULT 0"` + SrcEngine int `xorm:"NOT NULL DEFAULT 0"` + RepoId int64 `xorm:"INDEX NULL"` + ModelId string `xorm:"NOT NULL"` + ModelVersion string `xorm:"NOT NULL"` + DestFormat int `xorm:"NOT NULL DEFAULT 0"` + NetOutputFormat int `xorm:"NULL"` + UserId int64 `xorm:"NOT NULL"` + RunTime int64 `xorm:"NULL"` + InputShape string `xorm:"varchar(2000)"` + InputDataFormat string `xorm:"NOT NULL"` + Description string `xorm:"varchar(2000)"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` + UpdatedUnix timeutil.TimeStamp `xorm:"updated"` + UserName string + UserRelAvatarLink string + IsCanOper bool + IsCanDelete bool +} + type AiModelQueryOptions struct { ListOptions RepoID int64 // include all repos if empty @@ -47,7 +70,20 @@ type AiModelQueryOptions struct { SortType string New int // JobStatus CloudbrainStatus - Type int + Type int + Status int +} + +func SaveModelConvert(modelConvert *AiModelManageConvert) error { + sess := x.NewSession() + defer sess.Close() + re, err := sess.Insert(modelConvert) + if err != nil { + log.Info("insert modelConvert error." + err.Error()) + return err + } + log.Info("success to save modelConvert db.re=" + fmt.Sprint((re))) + return nil } func SaveModelToDb(model *AiModelManage) error { @@ -63,6 +99,20 @@ func SaveModelToDb(model *AiModelManage) error { return nil } +func QueryModelConvertById(id string) (*AiModelManageConvert, error) { + sess := x.NewSession() + defer sess.Close() + sess.Select("*").Table(new(AiModelManageConvert)).Where("id='" + id + "'") + aiModelManageConvertList := make([]*AiModelManageConvert, 0) + err := sess.Find(&aiModelManageConvertList) + if err == nil { + if len(aiModelManageConvertList) == 1 { + return aiModelManageConvertList[0], nil + } + } + return nil, err +} + func QueryModelById(id string) (*AiModelManage, error) { sess := x.NewSession() defer sess.Close() @@ -78,10 +128,22 @@ func QueryModelById(id string) (*AiModelManage, error) { return nil, err } -func DeleteModelById(id string) error { +func DeleteModelConvertById(id string) error { sess := x.NewSession() defer sess.Close() + re, err := sess.Delete(&AiModelManageConvert{ + ID: id, + }) + if err != nil { + return err + } + log.Info("success to delete AiModelManageConvert from db.re=" + fmt.Sprint((re))) + return nil +} +func DeleteModelById(id string) error { + sess := x.NewSession() + defer sess.Close() re, err := sess.Delete(&AiModelManage{ ID: id, }) @@ -90,7 +152,6 @@ func DeleteModelById(id string) error { } log.Info("success to delete from db.re=" + fmt.Sprint((re))) return nil - } func ModifyModelDescription(id string, description string) error { @@ -201,3 +262,46 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { return aiModelManages, count, nil } + +func QueryModelConvert(opts *AiModelQueryOptions) ([]*AiModelManageConvert, int64, error) { + sess := x.NewSession() + defer sess.Close() + var cond = builder.NewCond() + if opts.RepoID > 0 { + cond = cond.And( + builder.Eq{"ai_model_manage_convert.repo_id": opts.RepoID}, + ) + } + if opts.UserID > 0 { + cond = cond.And( + builder.Eq{"ai_model_manage_convert.user_id": opts.UserID}, + ) + } + if (opts.Status) >= 0 { + cond = cond.And( + builder.Eq{"ai_model_manage_convert.status": opts.Status}, + ) + } + count, err := sess.Where(cond).Count(new(AiModelManageConvert)) + if err != nil { + return nil, 0, fmt.Errorf("Count: %v", err) + } + + if opts.Page >= 0 && opts.PageSize > 0 { + var start int + if opts.Page == 0 { + start = 0 + } else { + start = (opts.Page - 1) * opts.PageSize + } + sess.Limit(opts.PageSize, start) + } + sess.OrderBy("ai_model_manage_convert.created_unix DESC") + aiModelManageConvert := make([]*AiModelManageConvert, 0, setting.UI.IssuePagingNum) + if err := sess.Table(new(AiModelManageConvert)).Where(cond). + Find(&aiModelManageConvert); err != nil { + return nil, 0, fmt.Errorf("Find: %v", err) + } + + return aiModelManageConvert, count, nil +} diff --git a/models/models.go b/models/models.go index 2a2e119fb..962cb3ce9 100755 --- a/models/models.go +++ b/models/models.go @@ -144,6 +144,7 @@ func init() { new(WechatBindLog), new(OrgStatistic), new(SearchRecord), + new(AiModelManageConvert), ) tablesStatistic = append(tablesStatistic, diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 735525efb..7bc41e910 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1145,6 +1145,9 @@ model.manage.Recall = Recall model.manage.sava_model = Sava Model model.manage.model_manage = ModelManage model.manage.model_accuracy = Model Accuracy +model.convert=Model Transformation +model.list=Model List +model.manage.create_new_convert_task=Create Model Transformation Task template.items = Template Items template.git_content = Git Content (Default Branch) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 483ddde6c..260c24e49 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1156,6 +1156,9 @@ model.manage.Recall = 召回率 model.manage.sava_model = 保存模型 model.manage.model_manage = 模型管理 model.manage.model_accuracy = 模型精度 +model.convert=模型转换任务 +model.list=模型列表 +model.manage.create_new_convert_task=创建模型转换任务 template.items=模板选项 template.git_content=Git数据(默认分支) diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index a13095d52..4db546180 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -20,12 +20,13 @@ import ( ) const ( - Model_prefix = "aimodels/" - tplModelManageIndex = "repo/modelmanage/index" - tplModelManageDownload = "repo/modelmanage/download" - tplModelInfo = "repo/modelmanage/showinfo" - MODEL_LATEST = 1 - MODEL_NOT_LATEST = 0 + Model_prefix = "aimodels/" + tplModelManageIndex = "repo/modelmanage/index" + tplModelManageConvertIndex = "repo/modelmanage/convertIndex" + tplModelManageDownload = "repo/modelmanage/download" + tplModelInfo = "repo/modelmanage/showinfo" + MODEL_LATEST = 1 + MODEL_NOT_LATEST = 0 ) func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error { @@ -617,6 +618,14 @@ func ShowModelTemplate(ctx *context.Context) { ctx.HTML(200, tplModelManageIndex) } +func ConvertModelTemplate(ctx *context.Context) { + ctx.Data["isModelManage"] = true + ctx.Data["MODEL_COUNT"] = 0 + ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage) + ctx.Data["TRAIN_COUNT"] = 0 + ctx.HTML(200, tplModelManageConvertIndex) +} + func isQueryRight(ctx *context.Context) bool { if ctx.Repo.Repository.IsPrivate { if ctx.Repo.CanRead(models.UnitTypeModelManage) || ctx.User.IsAdmin || ctx.Repo.IsAdmin() || ctx.Repo.IsOwner() { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 1e1a862ff..12447b96b 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -1081,6 +1081,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Delete("/delete_model", repo.DeleteModel) m.Put("/modify_model", repo.ModifyModelInfo) m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) + m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate) m.Get("/show_model_info", repo.ShowModelInfo) m.Get("/show_model_info_api", repo.ShowSingleModel) m.Get("/show_model_api", repo.ShowModelPageInfo) diff --git a/templates/repo/modelmanage/convertIndex.tmpl b/templates/repo/modelmanage/convertIndex.tmpl new file mode 100644 index 000000000..4230cfd05 --- /dev/null +++ b/templates/repo/modelmanage/convertIndex.tmpl @@ -0,0 +1,285 @@ + +{{template "base/head" .}} + +
+
+
+
+
+
+
+
+
+{{$repository := .Repository.ID}} + +
+ +
+ {{template "repo/header" .}} + +
+ {{template "base/alert" .}} + + + + +
+ +
+ + + + + + + +
+ +
+
+ + + +{{template "base/footer" .}} + + + diff --git a/templates/repo/modelmanage/index.tmpl b/templates/repo/modelmanage/index.tmpl index e65fbf004..5f3936ff6 100644 --- a/templates/repo/modelmanage/index.tmpl +++ b/templates/repo/modelmanage/index.tmpl @@ -20,7 +20,12 @@
{{template "base/alert" .}}
-
+
{{$.i18n.Tr "repo.model.manage.import_new_model"}} From 1a7eb69d939dd6999bdee04024f405cb4cfe4318 Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 16:17:48 +0800 Subject: [PATCH 017/562] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E4=BB=BB=E5=8A=A1=E7=95=8C=E9=9D=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- templates/repo/modelmanage/convertIndex.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/modelmanage/convertIndex.tmpl b/templates/repo/modelmanage/convertIndex.tmpl index 4230cfd05..b72feb9db 100644 --- a/templates/repo/modelmanage/convertIndex.tmpl +++ b/templates/repo/modelmanage/convertIndex.tmpl @@ -37,7 +37,7 @@
-
+
From 7ca7d93905ba62a96e3a649db9e2139cab82934b Mon Sep 17 00:00:00 2001 From: zouap Date: Tue, 31 May 2022 16:35:38 +0800 Subject: [PATCH 018/562] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E4=BB=BB=E5=8A=A1=E7=95=8C=E9=9D=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- templates/repo/modelmanage/convertIndex.tmpl | 54 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/templates/repo/modelmanage/convertIndex.tmpl b/templates/repo/modelmanage/convertIndex.tmpl index b72feb9db..e9b7e2016 100644 --- a/templates/repo/modelmanage/convertIndex.tmpl +++ b/templates/repo/modelmanage/convertIndex.tmpl @@ -33,12 +33,12 @@
-
@@ -562,122 +562,7 @@ e.cancelBubble = true; //ie兼容 } } - function loadModelFile(version_name, parents, filename, init) { - parents = parents || '' - filename = filename || '' - init = init || '' - console.log("start") - $.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/inference-job/${jobID}/result_list?version_name=${version_name}&parentDir=${parents}`, (data) => { - $(`#dir_list${version_name}`).empty() - renderDir(data, version_name) - if (init === "init") { - $(`input[name=model${version_name}]`).val("") - $(`input[name=modelback${version_name}]`).val(version_name) - $(`#file_breadcrumb${version_name}`).empty() - let htmlBread = "" - htmlBread += `
${version_name}
` - htmlBread += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBread) - } else { - renderBrend(version_name, parents, filename, init) - } - }).fail(function (err) { - console.log(err, version_name); - }); - - } - function renderBrend(version_name, parents, filename, init) { - if (init == "folder") { - let htmlBrend = "" - let sectionName = $(`#file_breadcrumb${version_name} .active.section`).text() - let parents1 = $(`input[name=model${version_name}]`).val() - let filename1 = $(`input[name=modelback${version_name}]`).val() - if (parents1 === "") { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } else { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } - - htmlBrend += `
${filename}
` - htmlBrend += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBrend) - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - } else { - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`
${filename}
`) - $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("
/
") - } - - } - function renderDir(data, version_name) { - let html = "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "" - html += '' - // html += "" - for (let i = 0; i < data.Dirs.length; i++) { - let dirs_size = renderSize(data.Dirs[i].Size) - html += "" - html += "" - html += "" - - html += "" - html += "" - - } - html += "" - html += "
" - html += "" - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += `` - html += "" + data.Dirs[i].FileName + "" - } else { - if (downlaodFlag) { - html += `` - } - else { - html += `` - } - html += "" + data.Dirs[i].FileName + "" - } - html += '' - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += "" - } else { - html += "" + `${dirs_size}` + "" - } - html += "" - html += "" + data.Dirs[i].ModTime + "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "
" - $(`#dir_list${version_name}`).append(html) - } - function renderSize(value) { - if (null == value || value == '') { - return "0 Bytes"; - } - var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); - var index = 0; - var srcsize = parseFloat(value); - index = Math.floor(Math.log(srcsize) / Math.log(1024)); - var size = srcsize / Math.pow(1024, index); - size = size.toFixed(0);//保留的小数位数 - return size + unitArr[index]; - } function refreshStatus(version_name) { $.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${taskID}?version_name=${versionname}`, (data) => { diff --git a/templates/repo/cloudbrain/trainjob/show.tmpl b/templates/repo/cloudbrain/trainjob/show.tmpl index 05d678016..3f66de0a3 100644 --- a/templates/repo/cloudbrain/trainjob/show.tmpl +++ b/templates/repo/cloudbrain/trainjob/show.tmpl @@ -264,8 +264,7 @@ onclick="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}} {{$.i18n.Tr "repo.modelarts.log"}} - {{$.i18n.Tr "repo.model_download"}} + {{$.i18n.Tr "repo.model_download"}}
@@ -554,122 +553,6 @@ document.getElementById("mask").style.display = "none" }); } - function loadModelFile(version_name, parents, filename, init) { - parents = parents || '' - filename = filename || '' - init = init || '' - console.log("start") - $.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { - $(`#dir_list${version_name}`).empty() - renderDir(data, version_name) - if (init === "init") { - $(`input[name=model${version_name}]`).val("") - $(`input[name=modelback${version_name}]`).val(version_name) - $(`#file_breadcrumb${version_name}`).empty() - let htmlBread = "" - htmlBread += `
${version_name}
` - htmlBread += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBread) - } else { - renderBrend(version_name, parents, filename, init) - } - }).fail(function (err) { - console.log(err, version_name); - }); - - } - function renderBrend(version_name, parents, filename, init) { - if (init == "folder") { - let htmlBrend = "" - let sectionName = $(`#file_breadcrumb${version_name} .active.section`).text() - let parents1 = $(`input[name=model${version_name}]`).val() - let filename1 = $(`input[name=modelback${version_name}]`).val() - if (parents1 === "") { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } else { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } - - htmlBrend += `
${filename}
` - htmlBrend += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBrend) - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - } else { - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`
${filename}
`) - $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("
/
") - } - - } - function renderDir(data, version_name) { - let html = "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "" - html += '' - // html += "" - for (let i = 0; i < data.Dirs.length; i++) { - let dirs_size = renderSize(data.Dirs[i].Size) - html += "" - html += "" - html += "" - - html += "" - html += "" - - } - html += "" - html += "
" - html += "" - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += `` - html += "" + data.Dirs[i].FileName + "" - } else { - if (downlaodFlag) { - html += `` - } - else { - html += `` - } - html += "" + data.Dirs[i].FileName + "" - } - html += '' - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += "" - } else { - html += "" + `${dirs_size}` + "" - } - - html += "" - html += "" + data.Dirs[i].ModTime + "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "
" - $(`#dir_list${version_name}`).append(html) - } - function renderSize(value) { - if (null == value || value == '') { - return "0 Bytes"; - } - var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); - var index = 0; - var srcsize = parseFloat(value); - index = Math.floor(Math.log(srcsize) / Math.log(1024)); - var size = srcsize / Math.pow(1024, index); - size = size.toFixed(0);//保留的小数位数 - return size + unitArr[index]; - } function refreshStatus(version_name) { $.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${taskID}?version_name=${versionname}`, (data) => { diff --git a/templates/repo/grampus/trainjob/show.tmpl b/templates/repo/grampus/trainjob/show.tmpl index 579e83693..e017fd4a0 100755 --- a/templates/repo/grampus/trainjob/show.tmpl +++ b/templates/repo/grampus/trainjob/show.tmpl @@ -273,8 +273,7 @@ data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}} {{$.i18n.Tr "repo.modelarts.log"}} - {{$.i18n.Tr "repo.model_download"}} + {{$.i18n.Tr "repo.model_download"}}
@@ -658,18 +657,6 @@ $('#name').val(modelName) $('#version').val("0.0.1") } - function renderSize(value) { - if (null == value || value == '') { - return "0 Bytes"; - } - var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); - var index = 0; - var srcsize = parseFloat(value); - index = Math.floor(Math.log(srcsize) / Math.log(1024)); - var size = srcsize / Math.pow(1024, index); - size = size.toFixed(0);//保留的小数位数 - return size + unitArr[index]; - } function refreshStatus(version_name) { $.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}?version_name=${version_name}`, (data) => { // header status and duration @@ -740,243 +727,4 @@ console.log(err); }); } - function loadModelFile(version_name, parents, filename, init) { - parents = parents || '' - filename = filename || '' - init = init || '' - $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { - $(`#dir_list${version_name}`).empty() - renderDir(data, version_name) - if (init === "init") { - $(`input[name=model${version_name}]`).val("") - $(`input[name=modelback${version_name}]`).val(version_name) - $(`#file_breadcrumb${version_name}`).empty() - let htmlBread = "" - htmlBread += `
${version_name}
` - htmlBread += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBread) - } else { - renderBrend(version_name, parents, filename, init) - } - }).fail(function (err) { - console.log(err, version_name); - }); - - } - function renderBrend(version_name, parents, filename, init) { - if (init == "folder") { - let htmlBrend = "" - let sectionName = $(`#file_breadcrumb${version_name} .active.section`).text() - let parents1 = $(`input[name=model${version_name}]`).val() - let filename1 = $(`input[name=modelback${version_name}]`).val() - if (parents1 === "") { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } else { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } - - htmlBrend += `
${filename}
` - htmlBrend += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBrend) - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - } else { - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`
${filename}
`) - $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("
/
") - } - - } - function renderDir(data, version_name) { - let html = "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "" - html += '' - // html += "" - for (let i = 0; i < data.Dirs.length; i++) { - let dirs_size = renderSize(data.Dirs[i].Size) - html += "" - html += "" - html += "" - - html += "" - html += "" - - } - html += "" - html += "
" - html += "" - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += `` - html += "" + data.Dirs[i].FileName + "" - } else { - if (downlaodFlag) { - html += `` - } - else { - html += `` - } - html += "" + data.Dirs[i].FileName + "" - } - html += '' - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += "" - } else { - html += "" + `${dirs_size}` + "" - } - - html += "" - html += "" + data.Dirs[i].ModTime + "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "
" - $(`#dir_list${version_name}`).append(html) - } - function debounce(fn, delay) { - let timer; - return (...args) => { - // 判断定时器是否存在,清除定时器 - if (timer) { - clearTimeout(timer); - } - - // 重新调用setTimeout - timer = setTimeout(() => { - fn.apply(this, args); - }, delay); - }; - } - const fn = debounce(logScroll, 500) - function logScroll(version_name) { - let container = document.querySelector(`#log${version_name}`) - let scrollTop = container.scrollTop - let scrollHeight = container.scrollHeight - let clientHeight = container.clientHeight - let scrollLeft = container.scrollLeft - if (((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight + 1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight)) && parseInt(scrollTop) !== 0 && scrollLeft == 0) { - let end_line = $(`#log${version_name} input[name=end_line]`).val() - $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { - if (data.Lines == 0) { - $(`.message${version_name} #header`).text('您已翻阅至日志底部') - $(`.message${version_name}`).css('display', 'block') - setTimeout(function () { - $(`.message${version_name}`).css('display', 'none') - }, 1000) - } else { - if (end_line === data.EndLine) { - return - } - else { - $(`#log${version_name} input[name=end_line]`).val(data.EndLine) - $(`#log${version_name}`).append('
' + data.Content)
-                    }
-
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-        }
-        if ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].includes(scrollTop) && scrollLeft == 0) {
-            let start_line = $(`#log${version_name} input[name=start_line]`).val()
-            $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => {
-                if (data.Lines == 0) {
-                    $(`.message${version_name} #header`).text('您已翻阅至日志顶部')
-                    $(`.message${version_name}`).css('display', 'block')
-                    setTimeout(function () {
-                        $(`.message${version_name}`).css('display', 'none')
-                    }, 1000)
-                } else {
-                    $(`#log${version_name} input[name=start_line]`).val(data.StartLine)   //如果变动就改变所对应的值
-                    $(`#log${version_name}`).prepend('
' + data.Content)
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-        }
-    }
-    function scrollAnimation(dom, currentY, targetY, currentX) {
-        let needScrollTop = targetY - currentY;
-        let _currentY = currentY;
-        setTimeout(() => {
-            // 一次调用滑动帧数,每次调用会不一样
-            //取总距离的十分之一
-            const dist = Math.ceil(needScrollTop / 10);
-            _currentY += dist;
-            //移动一个十分之一
-            dom.scrollTo(currentX || 0, _currentY, 'smooth');
-            // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
-            if (needScrollTop > 10 || needScrollTop < -10) {
-                scrollAnimation(dom, _currentY, targetY)
-            } else {
-                dom.scrollTo(0, targetY, 'smooth')
-            }
-        }, 1)
-    }
-
-    $('.log_top').click(function () {
-        // let logContentDom = document.querySelector('.log')
-        // if(!logContentDom)
-        //     return
-        // let version_name = $('.log_top').data('version')
-        let version_name = $(this).data('version')
-        let logContentDom = document.querySelector(`#log${version_name}`)
-
-        $(`#log_file${version_name}`).siblings('pre').remove()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`, (data) => {
-
-            $(`#log${version_name} input[name=end_line]`).val(data.EndLine)   //如果变动就改变所对应的值
-            $(`#log${version_name} input[name=start_line]`).val(data.StartLine)
-            $(`#log${version_name}`).prepend('
' + data.Content)
-            $(`.message${version_name} #header`).text('您已翻阅至日志顶部')
-            $(`.message${version_name}`).css('display', 'block')
-            setTimeout(function () {
-                $(`.message${version_name}`).css('display', 'none')
-            }, 1000)
-            scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
-        })
-
-    })
-    $('.log_bottom').click(function (e) {
-        let version_name = $(this).data('version')
-        let logContentDom = document.querySelector(`#log${version_name}`)
-        $(`#log_file${version_name}`).siblings('pre').remove()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`, (data) => {
-
-            $(`#log${version_name} input[name=end_line]`).val(data.EndLine)   //如果变动就改变所对应的值
-            $(`#log${version_name} input[name=start_line]`).val(data.StartLine)
-            $(`#log${version_name}`).append('
' + data.Content)
-            $.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`, (data) => {
-                if (data.Lines == 0) {
-                    $(`.message${version_name} #header`).text('您已翻阅至日志底部')
-                    $(`.message${version_name}`).css('display', 'block')
-                    setTimeout(function () {
-                        $(`.message${version_name}`).css('display', 'none')
-                    }, 1000)
-                } else {
-                    if (end_line === data.EndLine) {
-                        return
-                    }
-                    else {
-                        $(`#log${version_name} input[name=end_line]`).val(data.EndLine)
-                        $(`#log${version_name}`).append('
' + data.Content)
-                    }
-
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-            scrollAnimation(logContentDom, logContentDom.scrollTop + 1, logContentDom.scrollHeight - logContentDom.clientHeight);
-        })
-    })
 
\ No newline at end of file
diff --git a/templates/repo/modelarts/inferencejob/show.tmpl b/templates/repo/modelarts/inferencejob/show.tmpl
index b5aadca95..116c464e3 100644
--- a/templates/repo/modelarts/inferencejob/show.tmpl
+++ b/templates/repo/modelarts/inferencejob/show.tmpl
@@ -183,7 +183,7 @@ td, th {
 
                     {{$.i18n.Tr "repo.modelarts.train_job.config"}}
                     {{$.i18n.Tr "repo.modelarts.log"}}
-                    {{$.i18n.Tr "repo.model_download"}}
+                    {{$.i18n.Tr "repo.model_download"}}
                 
@@ -440,7 +440,7 @@ td, th { -
+

@@ -516,241 +516,4 @@ function loadLog(version_name){
         console.log(err);
     });
 }
-function logScroll(version_name) {
-
-    let container = document.querySelector(`#log${version_name}`)
-    let scrollTop = container.scrollTop
-    let scrollHeight = container.scrollHeight
-    let clientHeight = container.clientHeight
-    let scrollLeft = container.scrollLeft
-    if((parseInt(scrollTop)  + clientHeight == scrollHeight || parseInt(scrollTop)  + clientHeight +1 == scrollHeight || parseInt(scrollTop)  + clientHeight - 1 == scrollHeight) && (scrollLeft===0)){
-        let end_line = $(`#log${version_name} input[name=end_line]`).val()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => {
-            if (data.Lines == 0){
-                $(`.message${version_name} #header`).text('您已翻阅至日志底部')
-                $(`.message${version_name}`).css('display', 'block')
-                setTimeout(function(){
-                    $(`.message${version_name}`).css('display', 'none')
-                }, 1000)
-            }else{
-                if(end_line===data.EndLine){
-                    return
-                }
-                else{
-                    $(`#log${version_name} input[name=end_line]`).val(data.EndLine)
-                    $(`#log${version_name}`).append('
' + data.Content)
-                }
-
-            }
-        }).fail(function(err) {
-            console.log(err);
-        });
-    }
-    if(scrollTop == 0 && scrollLeft==0){
-        let start_line = $(`#log${version_name} input[name=start_line]`).val()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => {
-            if (data.Lines == 0){
-                $(`.message${version_name} #header`).text('您已翻阅至日志顶部')
-                $(`.message${version_name}`).css('display', 'block')
-                setTimeout(function(){
-                    $(`.message${version_name}`).css('display', 'none')
-                }, 1000)
-            }else{
-                $(`#log${version_name} input[name=start_line]`).val(data.StartLine)   //如果变动就改变所对应的值
-                $(`#log${version_name}`).prepend('
' + data.Content)
-            }
-        }).fail(function(err) {
-            console.log(err);
-        });
-    }
-}
-function renderSize(value){
-    if(null==value||value==''){
-        return "0 Bytes";
-    }
-    var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
-    var index=0;
-    var srcsize = parseFloat(value);
-    index=Math.floor(Math.log(srcsize)/Math.log(1024));
-    var size =srcsize/Math.pow(1024,index);
-    size=size.toFixed(0);//保留的小数位数
-    return size+unitArr[index];
-}
-function loadModelFile(version_name,parents,filename,init){
-    parents = parents || ''
-    filename = filename || ''
-    init = init || ''
-    $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/result_list?version_name=${version_name}&parentDir=${parents}`, (data) => {
-            $(`#dir_list${version_name}`).empty()
-            renderDir(data,version_name)
-            if(init==="init"){
-                $(`input[name=model${version_name}]`).val("")
-                $(`input[name=modelback${version_name}]`).val(version_name)
-                $(`#file_breadcrumb${version_name}`).empty()
-                let htmlBread = ""
-                htmlBread += `
result
` - htmlBread += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBread) - }else{ - renderBrend(version_name,parents,filename,init) - } - }).fail(function(err) { - console.log(err,version_name); - }); - -} -function renderBrend(version_name,parents,filename,init){ - if(init=="folder"){ - let htmlBrend = "" - let sectionName=$(`#file_breadcrumb${version_name} .active.section`).text() - let parents1 = $(`input[name=model${version_name}]`).val() - let filename1 = $(`input[name=modelback${version_name}]`).val() - if(parents1===""){ - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - }else{ - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } - - htmlBrend += `
${filename}
` - htmlBrend += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBrend) - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - }else{ - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`
${filename}
`) - $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("
/
") - } - -} -function renderDir(data,version_name){ - let html="" - html += "
" - html += "
" - html += "
" - html += "
" - html += "" - html += '' - // html += "" - for(let i=0;i` - html += "" + data.Dirs[i].FileName + "" - }else{ - if(downlaodFlag){ - html += `` - } - else{ - html += `` - } - html += "" + data.Dirs[i].FileName + "" - } - html += '' - html += "" - html += "" - html += "" - - html += "" - html += "" - - } - html += "" - html += "
" - if(data.Dirs[i].IsDir){ - html += "" - }else{ - html += ""+ `${dirs_size}` + "" - } - - html += "" - html += "" + data.Dirs[i].ModTime + "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "
" - $(`#dir_list${version_name}`).append(html) -} -function scrollAnimation(dom, currentY, targetY, currentX) { - let needScrollTop = targetY - currentY; - let _currentY = currentY; - setTimeout(() => { - // 一次调用滑动帧数,每次调用会不一样 - //取总距离的十分之一 - const dist = Math.ceil(needScrollTop / 10); - _currentY += dist; - //移动一个十分之一 - dom.scrollTo(currentX || 0, _currentY, 'smooth'); - // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果 - if (needScrollTop > 10 || needScrollTop < -10) { - scrollAnimation(dom, _currentY, targetY) - } else { - dom.scrollTo(0, targetY, 'smooth') - } - }, 1) - } - - $('.log_top').click(function () { - // let logContentDom = document.querySelector('.log') - // if(!logContentDom) - // return - // let version_name = $('.log_top').data('version') - let version_name = $(this).data('version') - let logContentDom = document.querySelector(`#log${version_name}`) - - $(`#log_file${version_name}`).siblings('pre').remove() - $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`, (data) => { - - $(`#log${version_name} input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值 - $(`#log${version_name} input[name=start_line]`).val(data.StartLine) - $(`#log${version_name}`).prepend('
' + data.Content)
-            $(`.message${version_name} #header`).text('您已翻阅至日志顶部')
-            $(`.message${version_name}`).css('display', 'block')
-            setTimeout(function () {
-                $(`.message${version_name}`).css('display', 'none')
-            }, 1000)
-            scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
-        })
-
-    })
-    $('.log_bottom').click(function (e) {
-        let version_name = $(this).data('version')
-        let logContentDom = document.querySelector(`#log${version_name}`)
-        $(`#log_file${version_name}`).siblings('pre').remove()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`, (data) => {
-
-            $(`#log${version_name} input[name=end_line]`).val(data.EndLine)   //如果变动就改变所对应的值
-            $(`#log${version_name} input[name=start_line]`).val(data.StartLine)
-            $(`#log${version_name}`).append('
' + data.Content)
-            $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`, (data) => {
-                if (data.Lines == 0) {
-                    $(`.message${version_name} #header`).text('您已翻阅至日志底部')
-                    $(`.message${version_name}`).css('display', 'block')
-                    setTimeout(function () {
-                        $(`.message${version_name}`).css('display', 'none')
-                    }, 1000)
-                } else {
-                    if (end_line === data.EndLine) {
-                        return
-                    }
-                    else {
-                        $(`#log${version_name} input[name=end_line]`).val(data.EndLine)
-                        $(`#log${version_name}`).append('
' + data.Content)
-                    }
-
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-            scrollAnimation(logContentDom, logContentDom.scrollTop + 1, logContentDom.scrollHeight - logContentDom.clientHeight);
-        })
-    })
 
diff --git a/templates/repo/modelarts/trainjob/show.tmpl b/templates/repo/modelarts/trainjob/show.tmpl
index 615fc3030..cd8fc88de 100755
--- a/templates/repo/modelarts/trainjob/show.tmpl
+++ b/templates/repo/modelarts/trainjob/show.tmpl
@@ -313,8 +313,7 @@
                         {{$.i18n.Tr "repo.modelarts.log"}}
                         资源占用情况
-                        {{$.i18n.Tr "repo.model_download"}}
+                        {{$.i18n.Tr "repo.model_download"}}
                     
@@ -509,7 +508,7 @@ -
@@ -727,18 +726,6 @@ $('#name').val(modelName) $('#version').val("0.0.1") } - function renderSize(value) { - if (null == value || value == '') { - return "0 Bytes"; - } - var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); - var index = 0; - var srcsize = parseFloat(value); - index = Math.floor(Math.log(srcsize) / Math.log(1024)); - var size = srcsize / Math.pow(1024, index); - size = size.toFixed(0);//保留的小数位数 - return size + unitArr[index]; - } function refreshStatus(version_name) { $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}?version_name=${version_name}`, (data) => { // header status and duration @@ -811,243 +798,5 @@ console.log(err); }); } - function loadModelFile(version_name, parents, filename, init) { - parents = parents || '' - filename = filename || '' - init = init || '' - $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { - $(`#dir_list${version_name}`).empty() - renderDir(data, version_name) - if (init === "init") { - $(`input[name=model${version_name}]`).val("") - $(`input[name=modelback${version_name}]`).val(version_name) - $(`#file_breadcrumb${version_name}`).empty() - let htmlBread = "" - htmlBread += `
${version_name}
` - htmlBread += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBread) - } else { - renderBrend(version_name, parents, filename, init) - } - }).fail(function (err) { - console.log(err, version_name); - }); - - } - function renderBrend(version_name, parents, filename, init) { - if (init == "folder") { - let htmlBrend = "" - let sectionName = $(`#file_breadcrumb${version_name} .active.section`).text() - let parents1 = $(`input[name=model${version_name}]`).val() - let filename1 = $(`input[name=modelback${version_name}]`).val() - if (parents1 === "") { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } else { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } - - htmlBrend += `
${filename}
` - htmlBrend += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBrend) - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - } else { - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`
${filename}
`) - $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("
/
") - } - - } - function renderDir(data, version_name) { - let html = "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "" - html += '' - // html += "" - for (let i = 0; i < data.Dirs.length; i++) { - let dirs_size = renderSize(data.Dirs[i].Size) - html += "" - html += "" - html += "" - - html += "" - html += "" - - } - html += "" - html += "
" - html += "" - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += `` - html += "" + data.Dirs[i].FileName + "" - } else { - if (downlaodFlag) { - html += `` - } - else { - html += `` - } - html += "" + data.Dirs[i].FileName + "" - } - html += '' - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += "" - } else { - html += "" + `${dirs_size}` + "" - } - - html += "" - html += "" + data.Dirs[i].ModTime + "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "
" - $(`#dir_list${version_name}`).append(html) - } - function debounce(fn, delay) { - let timer; - return (...args) => { - // 判断定时器是否存在,清除定时器 - if (timer) { - clearTimeout(timer); - } - - // 重新调用setTimeout - timer = setTimeout(() => { - fn.apply(this, args); - }, delay); - }; - } - const fn = debounce(logScroll, 500) - function logScroll(version_name) { - let container = document.querySelector(`#log${version_name}`) - let scrollTop = container.scrollTop - let scrollHeight = container.scrollHeight - let clientHeight = container.clientHeight - let scrollLeft = container.scrollLeft - if (((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight + 1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight)) && parseInt(scrollTop) !== 0 && scrollLeft == 0) { - let end_line = $(`#log${version_name} input[name=end_line]`).val() - $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { - if (data.Lines == 0) { - $(`.message${version_name} #header`).text('您已翻阅至日志底部') - $(`.message${version_name}`).css('display', 'block') - setTimeout(function () { - $(`.message${version_name}`).css('display', 'none') - }, 1000) - } else { - if (end_line === data.EndLine) { - return - } - else { - $(`#log${version_name} input[name=end_line]`).val(data.EndLine) - $(`#log${version_name}`).append('
' + data.Content)
-                    }
-
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-        }
-        if ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].includes(scrollTop) && scrollLeft == 0) {
-            let start_line = $(`#log${version_name} input[name=start_line]`).val()
-            $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => {
-                if (data.Lines == 0) {
-                    $(`.message${version_name} #header`).text('您已翻阅至日志顶部')
-                    $(`.message${version_name}`).css('display', 'block')
-                    setTimeout(function () {
-                        $(`.message${version_name}`).css('display', 'none')
-                    }, 1000)
-                } else {
-                    $(`#log${version_name} input[name=start_line]`).val(data.StartLine)   //如果变动就改变所对应的值
-                    $(`#log${version_name}`).prepend('
' + data.Content)
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-        }
-    }
-    function scrollAnimation(dom, currentY, targetY, currentX) {
-        let needScrollTop = targetY - currentY;
-        let _currentY = currentY;
-        setTimeout(() => {
-            // 一次调用滑动帧数,每次调用会不一样
-            //取总距离的十分之一
-            const dist = Math.ceil(needScrollTop / 10);
-            _currentY += dist;
-            //移动一个十分之一
-            dom.scrollTo(currentX || 0, _currentY, 'smooth');
-            // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
-            if (needScrollTop > 10 || needScrollTop < -10) {
-                scrollAnimation(dom, _currentY, targetY)
-            } else {
-                dom.scrollTo(0, targetY, 'smooth')
-            }
-        }, 1)
-    }
-
-    $('.log_top').click(function () {
-        // let logContentDom = document.querySelector('.log')
-        // if(!logContentDom)
-        //     return
-        // let version_name = $('.log_top').data('version')
-        let version_name = $(this).data('version')
-        let logContentDom = document.querySelector(`#log${version_name}`)
-
-        $(`#log_file${version_name}`).siblings('pre').remove()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`, (data) => {
-
-            $(`#log${version_name} input[name=end_line]`).val(data.EndLine)   //如果变动就改变所对应的值
-            $(`#log${version_name} input[name=start_line]`).val(data.StartLine)
-            $(`#log${version_name}`).prepend('
' + data.Content)
-            $(`.message${version_name} #header`).text('您已翻阅至日志顶部')
-            $(`.message${version_name}`).css('display', 'block')
-            setTimeout(function () {
-                $(`.message${version_name}`).css('display', 'none')
-            }, 1000)
-            scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
-        })
-
-    })
-    $('.log_bottom').click(function (e) {
-        let version_name = $(this).data('version')
-        let logContentDom = document.querySelector(`#log${version_name}`)
-        $(`#log_file${version_name}`).siblings('pre').remove()
-        $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`, (data) => {
-
-            $(`#log${version_name} input[name=end_line]`).val(data.EndLine)   //如果变动就改变所对应的值
-            $(`#log${version_name} input[name=start_line]`).val(data.StartLine)
-            $(`#log${version_name}`).append('
' + data.Content)
-            $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`, (data) => {
-                if (data.Lines == 0) {
-                    $(`.message${version_name} #header`).text('您已翻阅至日志底部')
-                    $(`.message${version_name}`).css('display', 'block')
-                    setTimeout(function () {
-                        $(`.message${version_name}`).css('display', 'none')
-                    }, 1000)
-                } else {
-                    if (end_line === data.EndLine) {
-                        return
-                    }
-                    else {
-                        $(`#log${version_name} input[name=end_line]`).val(data.EndLine)
-                        $(`#log${version_name}`).append('
' + data.Content)
-                    }
-
-                }
-            }).fail(function (err) {
-                console.log(err);
-            });
-            scrollAnimation(logContentDom, logContentDom.scrollTop + 1, logContentDom.scrollHeight - logContentDom.clientHeight);
-        })
-    })
+    
 
\ No newline at end of file
diff --git a/web_src/js/features/cloudbrainShow.js b/web_src/js/features/cloudbrainShow.js
new file mode 100644
index 000000000..864ea345f
--- /dev/null
+++ b/web_src/js/features/cloudbrainShow.js
@@ -0,0 +1,309 @@
+export default async function initCloudrainSow() {
+  function debounce(fn, delay) {
+    let timer;
+    return (...args) => {
+      // 判断定时器是否存在,清除定时器
+      if (timer) {
+        clearTimeout(timer);
+      }
+
+      // 重新调用setTimeout
+      timer = setTimeout(() => {
+        fn.apply(this, args);
+      }, delay);
+    };
+  }
+
+  function logScroll(version_name) {
+    let container = document.querySelector(`#log${version_name}`);
+    let scrollTop = container.scrollTop;
+    let scrollHeight = container.scrollHeight;
+    let clientHeight = container.clientHeight;
+    let scrollLeft = container.scrollLeft;
+    if (
+      (parseInt(scrollTop) + clientHeight == scrollHeight ||
+        parseInt(scrollTop) + clientHeight + 1 == scrollHeight ||
+        parseInt(scrollTop) + clientHeight - 1 == scrollHeight) &&
+      scrollLeft === 0
+    ) {
+      let end_line = $(`#log${version_name} input[name=end_line]`).val();
+      $.get(
+        `/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`,
+        (data) => {
+          if (data.Lines == 0) {
+            $(`.message${version_name} #header`).text("您已翻阅至日志底部");
+            $(`.message${version_name}`).css("display", "block");
+            setTimeout(function () {
+              $(`.message${version_name}`).css("display", "none");
+            }, 1000);
+          } else {
+            if (end_line === data.EndLine) {
+              return;
+            } else {
+              $(`#log${version_name} input[name=end_line]`).val(data.EndLine);
+              $(`#log${version_name}`).append("
" + data.Content);
+            }
+          }
+        }
+      ).fail(function (err) {
+        console.log(err);
+      });
+    }
+    if (scrollTop == 0 && scrollLeft == 0) {
+      let start_line = $(`#log${version_name} input[name=start_line]`).val();
+      $.get(
+        `/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`,
+        (data) => {
+          if (data.Lines == 0) {
+            $(`.message${version_name} #header`).text("您已翻阅至日志顶部");
+            $(`.message${version_name}`).css("display", "block");
+            setTimeout(function () {
+              $(`.message${version_name}`).css("display", "none");
+            }, 1000);
+          } else {
+            $(`#log${version_name} input[name=start_line]`).val(data.StartLine); //如果变动就改变所对应的值
+            $(`#log${version_name}`).prepend("
" + data.Content);
+          }
+        }
+      ).fail(function (err) {
+        console.log(err);
+      });
+    }
+  }
+  const fn = debounce(logScroll, 500);
+  $(".log-scroll").scroll(function () {
+    let version_name = $(this).data("version");
+    fn(version_name);
+  });
+  function scrollAnimation(dom, currentY, targetY, currentX) {
+    let needScrollTop = targetY - currentY;
+    let _currentY = currentY;
+    setTimeout(() => {
+      // 一次调用滑动帧数,每次调用会不一样
+      //取总距离的十分之一
+      const dist = Math.ceil(needScrollTop / 10);
+      _currentY += dist;
+      //移动一个十分之一
+      dom.scrollTo(currentX || 0, _currentY, "smooth");
+      // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
+      if (needScrollTop > 10 || needScrollTop < -10) {
+        scrollAnimation(dom, _currentY, targetY);
+      } else {
+        dom.scrollTo(0, targetY, "smooth");
+      }
+    }, 1);
+  }
+
+  $(".log_top").click(function () {
+    // let logContentDom = document.querySelector('.log')
+    // if(!logContentDom)
+    //     return
+    // let version_name = $('.log_top').data('version')
+    let version_name = $(this).data("version");
+    let logContentDom = document.querySelector(`#log${version_name}`);
+
+    $(`#log_file${version_name}`).siblings("pre").remove();
+    $.get(
+      `/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`,
+      (data) => {
+        $(`#log${version_name} input[name=end_line]`).val(data.EndLine); //如果变动就改变所对应的值
+        $(`#log${version_name} input[name=start_line]`).val(data.StartLine);
+        $(`#log${version_name}`).prepend("
" + data.Content);
+        $(`.message${version_name} #header`).text("您已翻阅至日志顶部");
+        $(`.message${version_name}`).css("display", "block");
+        setTimeout(function () {
+          $(`.message${version_name}`).css("display", "none");
+        }, 1000);
+        scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
+      }
+    );
+  });
+  $(".log_bottom").click(function (e) {
+    let version_name = $(this).data("version");
+    let logContentDom = document.querySelector(`#log${version_name}`);
+    $(`#log_file${version_name}`).siblings("pre").remove();
+    $.get(
+      `/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`,
+      (data) => {
+        $(`#log${version_name} input[name=end_line]`).val(data.EndLine); //如果变动就改变所对应的值
+        $(`#log${version_name} input[name=start_line]`).val(data.StartLine);
+        $(`#log${version_name}`).append("
" + data.Content);
+        $.get(
+          `/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`,
+          (data) => {
+            if (data.Lines == 0) {
+              $(`.message${version_name} #header`).text("您已翻阅至日志底部");
+              $(`.message${version_name}`).css("display", "block");
+              setTimeout(function () {
+                $(`.message${version_name}`).css("display", "none");
+              }, 1000);
+            } else {
+              if (end_line === data.EndLine) {
+                return;
+              } else {
+                $(`#log${version_name} input[name=end_line]`).val(data.EndLine);
+                $(`#log${version_name}`).append("
" + data.Content);
+              }
+            }
+          }
+        ).fail(function (err) {
+          console.log(err);
+        });
+        scrollAnimation(
+          logContentDom,
+          logContentDom.scrollTop + 1,
+          logContentDom.scrollHeight - logContentDom.clientHeight
+        );
+      }
+    );
+  });
+
+  //
+  $(".content-pad").on("click", ".load-model-file", function () {
+    console.log("11111111111");
+    let version_name = $(this).data("version");
+    let parents = $(this).data("parents") || "";
+    let filename = $(this).data("filename") || "";
+    let init = $(this).data("init") || "";
+    let path = $(this).data("path");
+    let url = `/api/v1/repos${path}?version_name=${version_name}&parentDir=${parents}`;
+    console.log(url);
+    $.get(url, (data) => {
+      $(`#dir_list${version_name}`).empty();
+      renderDir(path, data, version_name);
+      if (init === "init") {
+        $(`input[name=model${version_name}]`).val("");
+        $(`input[name=modelback${version_name}]`).val(version_name);
+        $(`#file_breadcrumb${version_name}`).empty();
+        let htmlBread = "";
+        htmlBread += `
${version_name}
`; + htmlBread += "
/
"; + $(`#file_breadcrumb${version_name}`).append(htmlBread); + } else { + renderBrend(path, version_name, parents, filename, init); + } + }).fail(function (err) { + console.log(err, version_name); + }); + }); + function renderSize(value) { + if (null == value || value == "") { + return "0 Bytes"; + } + var unitArr = new Array( + "Bytes", + "KB", + "MB", + "GB", + "TB", + "PB", + "EB", + "ZB", + "YB" + ); + var index = 0; + var srcsize = parseFloat(value); + index = Math.floor(Math.log(srcsize) / Math.log(1024)); + var size = srcsize / Math.pow(1024, index); + size = size.toFixed(0); //保留的小数位数 + return size + unitArr[index]; + } + function renderBrend(path, version_name, parents, filename, init) { + if (init == "folder") { + let htmlBrend = ""; + let sectionName = $( + `#file_breadcrumb${version_name} .active.section` + ).text(); + let parents1 = $(`input[name=model${version_name}]`).val(); + let filename1 = $(`input[name=modelback${version_name}]`).val(); + if (parents1 === "") { + $(`#file_breadcrumb${version_name} .active.section`).replaceWith( + `${sectionName}` + ); + } else { + $(`#file_breadcrumb${version_name} .active.section`).replaceWith( + `${sectionName}` + ); + } + + htmlBrend += `
${filename}
`; + htmlBrend += "
/
"; + $(`#file_breadcrumb${version_name}`).append(htmlBrend); + $(`input[name=model${version_name}]`).val(parents); + $(`input[name=modelback${version_name}]`).val(filename); + } else { + $(`input[name=model${version_name}]`).val(parents); + $(`input[name=modelback${version_name}]`).val(filename); + $(`#file_breadcrumb${version_name} a.section:contains(${filename})`) + .nextAll() + .remove(); + $( + `#file_breadcrumb${version_name} a.section:contains(${filename})` + ).replaceWith(`
${filename}
`); + $( + `#file_breadcrumb${version_name} div.section:contains(${filename})` + ).append("
/
"); + } + } + + function renderDir(path, data, version_name) { + let html = ""; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + html += ""; + html += ""; + // html += "" + for (let i = 0; i < data.Dirs.length; i++) { + let dirs_size = renderSize(data.Dirs[i].Size); + html += ""; + html += ""; + html += ""; + + html += ""; + html += ""; + } + html += ""; + html += "
"; + html += ""; + html += ""; + html += ""; + if (data.Dirs[i].IsDir) { + html += ``; + html += + "" + + data.Dirs[i].FileName + + ""; + } else { + if (downlaodFlag) { + html += ``; + } else { + html += ``; + } + html += + "" + + data.Dirs[i].FileName + + ""; + } + html += ""; + html += ""; + html += ""; + if (data.Dirs[i].IsDir) { + html += ""; + } else { + html += + "" + `${dirs_size}` + ""; + } + + html += ""; + html += + "" + data.Dirs[i].ModTime + ""; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + $(`#dir_list${version_name}`).append(html); + } +} diff --git a/web_src/js/index.js b/web_src/js/index.js index 754d6ca76..53dba8a88 100755 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -43,6 +43,7 @@ import Contributors from "./components/Contributors.vue"; import Model from "./components/Model.vue"; import WxAutorize from "./components/WxAutorize.vue"; import initCloudrain from "./features/cloudrbanin.js"; +import initCloudrainSow from "./features/cloudbrainShow.js"; import initImage from "./features/images.js"; import selectDataset from "./components/dataset/selectDataset.vue"; // import $ from 'jquery.js' @@ -2917,6 +2918,7 @@ $(document).ready(async () => { initTribute(); initDropDown(); initCloudrain(); + initCloudrainSow(); initImage(); initContextMenu(); @@ -3711,9 +3713,9 @@ function initVueDataset() { if (!el) { return; } - let link = $('#square-link').data('link') - let repolink = $('.dataset-repolink').data('repolink') - let datasetType = $('.dataset-repolink').data('dataset-type') + let link = $("#square-link").data("link"); + let repolink = $(".dataset-repolink").data("repolink"); + let datasetType = $(".dataset-repolink").data("dataset-type"); const clearBtn = document.getElementsByClassName("clear_dataset_value"); const params = new URLSearchParams(location.search); for (let i = 0; i < clearBtn.length; i++) { @@ -3873,10 +3875,10 @@ function initVueDataset() { mounted() { this.getTypeList(); - if (!!document.getElementById('dataset-repolink-init')) { + if (!!document.getElementById("dataset-repolink-init")) { // this.datasetType = location.href.indexOf('cloudbrain') !== -1 ? 0 : 1 - this.datasetType = $('#dataset-repolink-init').data("dataset-type") - this.getCurrentRepoDataset(this.repolink, this.datasetType) + this.datasetType = $("#dataset-repolink-init").data("dataset-type"); + this.getCurrentRepoDataset(this.repolink, this.datasetType); } const params = new URLSearchParams(location.search); @@ -3897,13 +3899,13 @@ function initVueDataset() { this.ruleForm1 = ruleForm; // this.getEditInit() - this.starItems = starItems - this.starActives = starActives - this.taskLists = taskLists - this.licenseLists = licenseLists - this.descfile = dataset_file_desc - this.repolink = repolink - this.datasetType = datasetType + this.starItems = starItems; + this.starActives = starActives; + this.taskLists = taskLists; + this.licenseLists = licenseLists; + this.descfile = dataset_file_desc; + this.repolink = repolink; + this.datasetType = datasetType; }, methods: { copyUrl(url) { @@ -3924,18 +3926,18 @@ function initVueDataset() { handleCurrentChange(val) { this.page = val; switch (this.activeName) { - case 'first': - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.getStarDataset(this.repolink, this.datasetType); + break; } }, handleCheckedChange(val) { @@ -4276,18 +4278,18 @@ function initVueDataset() { }, refreshStatusDataset() { switch (this.activeName) { - case 'first': - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.getStarDataset(this.repolink, this.datasetType); + break; } }, getCurrentRepoDataset(repoLink, type) { @@ -4398,44 +4400,44 @@ function initVueDataset() { }, searchDataset() { switch (this.activeName) { - case 'first': - this.page = 1 - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.page = 1 - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.page = 1 - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.page = 1 - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.page = 1; + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.page = 1; + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.page = 1; + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.page = 1; + this.getStarDataset(this.repolink, this.datasetType); + break; } }, }, watch: { searchDataItem() { switch (this.activeName) { - case 'first': - this.page = 1 - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.page = 1 - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.page = 1 - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.page = 1 - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.page = 1; + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.page = 1; + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.page = 1; + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.page = 1; + this.getStarDataset(this.repolink, this.datasetType); + break; } }, }, From 000cde79e54abc26a4aa5cb23e57f59746c870d3 Mon Sep 17 00:00:00 2001 From: zhoupzh Date: Mon, 11 Jul 2022 15:59:53 +0800 Subject: [PATCH 418/562] fix issue --- templates/repo/cloudbrain/inference/show.tmpl | 2 +- templates/repo/cloudbrain/trainjob/show.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/cloudbrain/inference/show.tmpl b/templates/repo/cloudbrain/inference/show.tmpl index b02c9694b..380a59d16 100644 --- a/templates/repo/cloudbrain/inference/show.tmpl +++ b/templates/repo/cloudbrain/inference/show.tmpl @@ -492,7 +492,7 @@ diff --git a/templates/repo/cloudbrain/trainjob/show.tmpl b/templates/repo/cloudbrain/trainjob/show.tmpl index 3f66de0a3..ede7f322d 100644 --- a/templates/repo/cloudbrain/trainjob/show.tmpl +++ b/templates/repo/cloudbrain/trainjob/show.tmpl @@ -466,7 +466,7 @@ From 574a02c16123452d8aec81bbcf028ea20f41a855 Mon Sep 17 00:00:00 2001 From: zhoupzh Date: Mon, 11 Jul 2022 16:22:35 +0800 Subject: [PATCH 419/562] fix issue --- web_src/js/features/cloudbrainShow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/cloudbrainShow.js b/web_src/js/features/cloudbrainShow.js index 864ea345f..3e556280f 100644 --- a/web_src/js/features/cloudbrainShow.js +++ b/web_src/js/features/cloudbrainShow.js @@ -161,7 +161,7 @@ export default async function initCloudrainSow() { // $(".content-pad").on("click", ".load-model-file", function () { console.log("11111111111"); - let version_name = $(this).data("version"); + let version_name = $(this).data("version") || "result"; let parents = $(this).data("parents") || ""; let filename = $(this).data("filename") || ""; let init = $(this).data("init") || ""; From 7f1cffd7f1a9e3c118eebc3bc33cc028abf07168 Mon Sep 17 00:00:00 2001 From: zhoupzh Date: Mon, 11 Jul 2022 16:54:18 +0800 Subject: [PATCH 420/562] fix issue --- templates/custom/wait_count_train.tmpl | 20 ++++++++++++++++---- web_src/js/features/cloudbrainShow.js | 8 ++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/templates/custom/wait_count_train.tmpl b/templates/custom/wait_count_train.tmpl index 085fa173f..661eb268d 100644 --- a/templates/custom/wait_count_train.tmpl +++ b/templates/custom/wait_count_train.tmpl @@ -1,4 +1,16 @@ -
- - {{.i18n.Tr "repo.wait_count_start"}}{{.WaitCount}}{{.i18n.Tr "repo.wait_count_end"}} -
\ No newline at end of file +
+ + {{.QueuesDetail}} + {{.i18n.Tr "repo.wait_count_start"}} + {{if .QueuesDetail}} + {{.QueuesDetail.a100}} + {{else}} + {{.WaitCount}} + {{ end }} + {{.i18n.Tr "repo.wait_count_end"}} +
diff --git a/web_src/js/features/cloudbrainShow.js b/web_src/js/features/cloudbrainShow.js index 3e556280f..b0f6f0ad7 100644 --- a/web_src/js/features/cloudbrainShow.js +++ b/web_src/js/features/cloudbrainShow.js @@ -161,7 +161,7 @@ export default async function initCloudrainSow() { // $(".content-pad").on("click", ".load-model-file", function () { console.log("11111111111"); - let version_name = $(this).data("version") || "result"; + let version_name = $(this).data("version"); let parents = $(this).data("parents") || ""; let filename = $(this).data("filename") || ""; let init = $(this).data("init") || ""; @@ -176,7 +176,11 @@ export default async function initCloudrainSow() { $(`input[name=modelback${version_name}]`).val(version_name); $(`#file_breadcrumb${version_name}`).empty(); let htmlBread = ""; - htmlBread += `
${version_name}
`; + if (version_name) { + htmlBread += `
${version_name}
`; + } else { + htmlBread += `
result
`; + } htmlBread += "
/
"; $(`#file_breadcrumb${version_name}`).append(htmlBread); } else { From c5dbae173137eaec3497fe2e261d526a8339553b Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 11 Jul 2022 17:00:16 +0800 Subject: [PATCH 421/562] =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E7=95=8C=E9=9D=A2=E4=BF=AE=E6=94=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- routers/repo/ai_model_convert.go | 4 ++-- templates/repo/modelmanage/convertIndex.tmpl | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/routers/repo/ai_model_convert.go b/routers/repo/ai_model_convert.go index 5129d7eb7..b7ce6cbed 100644 --- a/routers/repo/ai_model_convert.go +++ b/routers/repo/ai_model_convert.go @@ -585,9 +585,8 @@ func ShowModelConvertInfo(ctx *context.Context) { func ConvertModelTemplate(ctx *context.Context) { ctx.Data["isModelManage"] = true - ctx.Data["MODEL_COUNT"] = 0 + SetModelCount(ctx) ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage) - ctx.Data["TRAIN_COUNT"] = 0 ShowModelConvertPageInfo(ctx) ctx.HTML(200, tplModelManageConvertIndex) } @@ -620,6 +619,7 @@ func ShowModelConvertPageInfo(ctx *context.Context) { ctx.ServerError("Cloudbrain", err) return } + ctx.Data["MODEL_CONVERT_COUNT"] = 0 userIds := make([]int64, len(modelResult)) for i, model := range modelResult { model.IsCanOper = isOper(ctx, model.UserId) diff --git a/templates/repo/modelmanage/convertIndex.tmpl b/templates/repo/modelmanage/convertIndex.tmpl index ae680d775..3765b5961 100644 --- a/templates/repo/modelmanage/convertIndex.tmpl +++ b/templates/repo/modelmanage/convertIndex.tmpl @@ -40,7 +40,20 @@ {{$.i18n.Tr "repo.model.manage.create_new_convert_task"}}
- + {{if eq $.MODEL_CONVERT_COUNT 0}} +
+
+
未创建过模型转换任务
+
+ {{if eq $.MODEL_COUNT 0}} +
请您先导入模型,然后再对其进行转换。
+ {{end}} +
使用说明:可以参考启智AI协作平台小白训练营课程。
+ +
+
+ {{else}}
@@ -153,6 +166,7 @@
+ {{end}}
From 176dfff4c2d2cb9b3e6a732f56c7799ec8978a11 Mon Sep 17 00:00:00 2001 From: zouap Date: Mon, 11 Jul 2022 17:39:29 +0800 Subject: [PATCH 422/562] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=95=8C=E9=9D=A2Bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zouap --- templates/repo/grampus/trainjob/show.tmpl | 1 + templates/repo/modelmanage/index.tmpl | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/templates/repo/grampus/trainjob/show.tmpl b/templates/repo/grampus/trainjob/show.tmpl index a607221f9..3f3f39cfc 100755 --- a/templates/repo/grampus/trainjob/show.tmpl +++ b/templates/repo/grampus/trainjob/show.tmpl @@ -572,6 +572,7 @@