commit 1bd1a66cfe8804bdac107c648ec3c370e2b7e659 Author: yuxh Date: Tue Feb 21 20:46:05 2023 +0800 fork from gaore-common-sdk-go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..173454b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e31110 --- /dev/null +++ b/README.md @@ -0,0 +1,179 @@ +# gaore-common-sdk-go + +### 1.目录架构 +``` +├── README.md +├── sdk +│   ├── auth `认证类` +│   ├── client.go `客户端主入口类` +│   ├── config.go +│   ├── requests `请求类` +│   ├── responses `响应类` +│   └── utils `工具类` +└── services + └── jedi +``` +### 2.引入 +```go +go get -u golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk +``` +或 Go Module +```go +import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" +``` + +### 3.服务端认证及返回处理 + +调用 `auth.UnSign` 方法,提供`*http.Request`请求实例,以及`signer.Signer` 签名器(签名器需要包括凭据) +即可完成整个验签过程 + +这里以`beego`为例 : +```go +package applications + +import ( + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/signers" + "golib.gaore.com/GaoreGo/grlogs" +) + +func init() { + // 过滤器 + beego.InsertFilter("/api/*", beego.BeforeRouter, func(context *context.Context) { + httpRequest := context.Request + err := auth.UnSign(httpRequest, signers.NewAccessKeySigner(&credentials.AccessKeyCredential{ + AccessKeyId: "aaaaaa", + AccessKeySecret: "bbbbbb", + AccessKeyFrom: context.Input.Param("access_from"), + })) + + if err != nil { + resp := response.NewJsonByDefaultFailed() + resp.Msg = err.Error() + resp.Code = 10086 + + var ( + hasIndent = beego.BConfig.RunMode != beego.PROD + ) + context.Output.Status = 500 + context.Output.JSON(resp, hasIndent, false) + } + }) +} +``` +服务端返回的响应体为以下结构的json字符流, `code`,`status`,`msg` 这三个字段*最好*要包含且数据类型要一致 , `data` 部分为业务内容,自行定义 +```json +{ + "code": 1001, + "msg": "不能为空", + "status": false, + "data": { + ... + } +} +``` + +### 4.sdk编写 + +在`services`目录下以服务归类新建文件夹, 如`jedi`为短信服务,以 `RpcRequest` 和 `BaseResponse` 以基类写好请求子类和响应子类。一个请求接口对应一对请求和响应类。 + +```go +import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + +const ( + HOST = "jedi" // 如果非全域名会自动补全.gaore.com , 如jedi 会自动补全jedi.goare.com, 也可以打全域名 test.uu89.com + VERSION = "2020-08-04" +) + + +type Client struct { + sdk.Client +} + +func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAccessKey(accesskey, secrect, source) + return +} + +func (c *Client) Test(req *DemoTestRequest) (response *DemoTestResponse, err error) { + response = CreateDemoTestResponse() + err = c.DoAction(req, response) + return +} +``` + +请求类,对参数用标签解释, 如 `position:"Query" field:"param_1" default:""` , 有三个字段 `position` , `field`, `default` + +- `position` 为标志该参数为请求体对应的位置, `Query` query参数, `Body` post请求体参数, `Head`请求头参数 + +- `field` 解释成参数实际名称 + +- `default` 默认值 + +```go +type DemoTestRequest struct { + *requests.RpcRequest + Param1 string `position:"Query" field:"param_1" default:"" ` + Param2 int `position:"Query" field:"param_2" default:"10086" ` + Param3 bool `position:"Query" field:"param_3" default:"false" ` +} +``` +对应解释成http请求为: +```go +GET param_1=111¶m_2=10086¶m_3=false +``` + +完整示例: +```go +package jedi + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +// 定义请求体 +type DemoTestRequest struct { + *requests.RpcRequest + Param1 string `position:"Query" field:"param_1" default:"" ` + Param2 int `position:"Query" field:"param_2" default:"10086" ` + Param3 bool `position:"Query" field:"param_3" default:"false" ` +} + +func CreateDemoTestRequest() (req *DemoTestRequest) { + req = &DemoTestRequest{RpcRequest: &requests.RpcRequest{}} + // InitWithApiInfo 初始化请求,有三个参数,域名,版本,和路径 + // 域名参数如果非全域名会自动补全.gaore.com , 如jedi 会自动补全jedi.goare.com, 也可以打全域名 test.uu89.com + req.InitWithApiInfo(HOST, VERSION, "/api/sms/Index") + // 定义 请求方法 POST 或 GET + req.Method = requests.GET + return +} + +// 定义响应体 +type DemoTestResponse struct { + *responses.BaseResponse + Data DemoTestResponseData `json:"data"` +} + +type DemoTestResponseData struct { + Account string `json:"account"` + Total int `json:"total"` +} + +func CreateDemoTestResponse() *DemoTestResponse { + return &DemoTestResponse{ + BaseResponse: &responses.BaseResponse{}, + } +} + +``` + +终端调试打开方式, 需要在系统环境变量上加入(三选一): +``` +DEBUG=sdk,signer,request +``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1f68921 --- /dev/null +++ b/go.mod @@ -0,0 +1 @@ +module golib.gaore.com/GaoreGo/haiwai-common-sdk-go diff --git a/sdk/auth/credentials/access_key_credential.go b/sdk/auth/credentials/access_key_credential.go new file mode 100644 index 0000000..b691502 --- /dev/null +++ b/sdk/auth/credentials/access_key_credential.go @@ -0,0 +1,21 @@ +package credentials + +type BaseCredential struct { + AccessKeyId string `json:"access_key_id" yaml:"access_key_id"` + AccessKeySecret string `json:"access_key_secret" yaml:"access_key_secret"` + AccessKeyFrom string `json:"access_key_from" yaml:"access_key_from"` +} + +type AccessKeyCredential struct { + AccessKeyId string `json:"access_key_id" yaml:"access_key_id"` + AccessKeySecret string `json:"access_key_secret" yaml:"access_key_secret"` + AccessKeyFrom string `json:"access_key_from" yaml:"access_key_from"` +} + +func (baseCred *BaseCredential) ToAccessKeyCredential() *AccessKeyCredential { + return &AccessKeyCredential{ + AccessKeyId: baseCred.AccessKeyId, + AccessKeySecret: baseCred.AccessKeySecret, + AccessKeyFrom: baseCred.AccessKeyFrom, + } +} diff --git a/sdk/auth/credentials/ali_appcode_credential.go b/sdk/auth/credentials/ali_appcode_credential.go new file mode 100644 index 0000000..a6a227a --- /dev/null +++ b/sdk/auth/credentials/ali_appcode_credential.go @@ -0,0 +1,13 @@ +package credentials + +type AliAppcodeCredential struct { + AccessKeyId string `json:"access_key_id" yaml:"access_key_id"` + AccessKeySecret string `json:"access_key_secret" yaml:"access_key_secret"` +} + +func NewAliAppcodeCredential(accessKeyId, accessKeySecret string) *AliAppcodeCredential { + return &AliAppcodeCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + } +} diff --git a/sdk/auth/credentials/sts_token_credential.go b/sdk/auth/credentials/sts_token_credential.go new file mode 100644 index 0000000..0fac16b --- /dev/null +++ b/sdk/auth/credentials/sts_token_credential.go @@ -0,0 +1,15 @@ +package credentials + +type StdTokenCredential struct { + AccessKeyId string `json:"access_key_id" yaml:"access_key_id"` + AccessKeySecret string `json:"access_key_secret" yaml:"access_key_secret"` + AccessKeyFrom string `json:"access_key_from" yaml:"access_key_from"` +} + +func NewStsTokenCredential(accessKeyId, accessKeySecret, accessFrom string) *StdTokenCredential { + return &StdTokenCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + AccessKeyFrom: accessFrom, + } +} diff --git a/sdk/auth/crediantial.go b/sdk/auth/crediantial.go new file mode 100644 index 0000000..4fd6cbe --- /dev/null +++ b/sdk/auth/crediantial.go @@ -0,0 +1,12 @@ +package auth + +import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + +var debug utils.Debug + +func init() { + debug = utils.Init("signer") +} + +type Credential interface { +} diff --git a/sdk/auth/rali_signature_composer.go b/sdk/auth/rali_signature_composer.go new file mode 100644 index 0000000..37cd3d1 --- /dev/null +++ b/sdk/auth/rali_signature_composer.go @@ -0,0 +1,160 @@ +package auth + +import ( + "bytes" + "errors" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "net/http" + "net/url" + "sort" + "strconv" + "strings" + "time" +) + +func signRaliRequest(request requests.AcsRequest, signer Signer) (err error) { + err = completeRaliSignParams(request, signer) + if err != nil { + return + } + + stringToSign := buildRaliStringToSign(request) + request.SetStringToSign(stringToSign) + signature := signer.Sign(stringToSign, "") + request.GetHeaders()["X-Ca-Signature"] = signature + + debug("GrSdk sign: %s", signature) + debug("GrSdk sign string: %s", strings.ReplaceAll(stringToSign, "\n", "#")) + debug("GrSdk sign: \r\n") + return +} + +func completeRaliSignParams(request requests.AcsRequest, signer Signer) (err error) { + + request.GetHeaders()["X-Ca-Timestamp"] = fmt.Sprintf("%d", time.Now().Unix()*1000) + request.GetHeaders()["X-Ca-Signature-Method"] = signer.GetName() + request.GetHeaders()["X-Ca-Nonce"] = utils.GetUUID() + request.GetHeaders()["X-Ca-Key"], err = signer.GetAccessKeyId() + + if request.GetEnv() != "" { + request.GetHeaders()["X-Ca-Stage"] = request.GetEnv() + } + + if request.GetMethod() == requests.POST { + request.GetHeaders()["Content-type"] = requests.Form + } + + formString := utils.GetUrlFormedMap(request.GetFormParams()) + request.SetContent(bytes.NewBufferString(formString).Bytes()) + return +} + +func buildRaliSignHeader(request requests.AcsRequest) (str1, str2 string) { + + headParams := make(map[string]string) + signatureHeaders := make([]string, 0) + + for key, val := range request.GetHeaders() { + headParams[key] = val + } + + delete(headParams, "X-Ca-Signature") + delete(headParams, "X-Ca-Signature-Headers") + delete(headParams, "Accept") + delete(headParams, "Content-MD5") + delete(headParams, "Content-Type") + delete(headParams, "Date") + + for key, _ := range headParams { + signatureHeaders = append(signatureHeaders, key) + } + + sort.Strings(signatureHeaders) + + for _, key := range signatureHeaders { + str1 += fmt.Sprintf("%s:%s\n", key, headParams[key]) + } + + return strings.TrimRight(str1, "\n"), strings.Join(signatureHeaders, ",") +} + +func buildRaliStringToSign(request requests.AcsRequest) (stringToSign string) { + signParams := make(map[string]string) + for key, value := range request.GetQueryParams() { + signParams[key] = value + } + + if strings.ToUpper(request.GetMethod()) == requests.POST { + for key, value := range request.GetFormParams() { + signParams[key] = value + } + } + + str1, str2 := buildRaliSignHeader(request) + + stringToSign = request.GetMethod() + "\n" + stringToSign += request.GetHeaders()["Accept"] + "\n\n" + stringToSign += request.GetHeaders()["Content-type"] + "\n\n" + stringToSign += str1 + "\n" + stringToSign += request.GetActionName() + "?" + utils.GetUrlByKeySort(signParams) + request.GetHeaders()["X-Ca-Signature-Headers"] = str2 + + //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.GetMethod() + "&%2F&" + stringToSign + return +} + +func unsignRaliRequest(request *http.Request, signer Signer) (err error) { + signParams := make(map[string]string) + for key, value := range request.URL.Query() { + signParams[key] = value[0] + } + + if strings.ToUpper(request.Method) == requests.POST { + for key, value := range request.Form { + signParams[key] = value[0] + } + } + + if accessKey, err := signer.GetAccessKeyId(); err != nil { + return err + } else if accessKey == "" { + return errors.New("access key is not allow empty") + } else if accessKey != signParams["access_key"] { + return errors.New("illegal access key") + } + + signValue, ok := signParams["sign"] + if !ok { + return errors.New("sign value is not exists") + } else { + delete(signParams, "sign") + } + + 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 + debug("GrSdk sign: %s", stringToSign) + + if timestamp, err := strconv.ParseInt(signParams["access_time"], 10, 64); err != nil { + return err + } else { + if time.Unix(timestamp, 0).Before(time.Now().Add(-5 * time.Minute)) { + err = errors.New("sign timeout 5 minute") + } + } + + if signer.Sign(stringToSign, "&") != signValue { + return errors.New("sign string is not correct") + } + return +} diff --git a/sdk/auth/roa_signature_composer.go b/sdk/auth/roa_signature_composer.go new file mode 100644 index 0000000..342e99d --- /dev/null +++ b/sdk/auth/roa_signature_composer.go @@ -0,0 +1,128 @@ +package auth + +import ( + "bytes" + "errors" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +func signRoaRequest(request requests.AcsRequest, signer Signer) (err error) { + err = completeRoaSignParams(request, signer) + if err != nil { + return + } + if _, isContainsSign := request.GetQueryParams()["sign"]; isContainsSign { + delete(request.GetQueryParams(), "sign") + } + + stringToSign := buildRoaStringToSign(request) + request.SetStringToSign(stringToSign) + signature := signer.Sign(stringToSign, "&") + request.GetQueryParams()["sign"] = signature + debug("GrSdk sign: %s", signature) + debug("GrSdk sign string: %s", stringToSign) + debug("GrSdk sign: \r\n") + return +} + +func completeRoaSignParams(request requests.AcsRequest, signer Signer) (err error) { + + var accessKeyFrom string + if accessKeyFrom, err = signer.GetAccessKeyFrom(); err != nil { + return + } + + queryParams := request.GetQueryParams() + queryParams["access_time"] = fmt.Sprintf("%d", time.Now().Unix()) + queryParams["access_key"], err = signer.GetAccessKeyId() + queryParams["access_from"] = accessKeyFrom + + if err != nil { + return + } + + if request.GetMethod() == requests.POST { + request.GetHeaders()["Content-type"] = requests.Form + } + request.GetHeaders()["Gr-Sdk-From"] = accessKeyFrom + formString := utils.GetUrlFormedMap(request.GetFormParams()) + request.SetContent(bytes.NewBufferString(formString).Bytes()) + return +} + +func buildRoaStringToSign(request requests.AcsRequest) (stringToSign string) { + signParams := make(map[string]string) + for key, value := range request.GetQueryParams() { + signParams[key] = value + } + + if strings.ToUpper(request.GetMethod()) == requests.POST { + for key, value := range request.GetFormParams() { + 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.GetMethod() + "&%2F&" + stringToSign + return +} + +func unsignRoaRequest(request *http.Request, signer Signer) (err error) { + signParams := make(map[string]string) + for key, value := range request.URL.Query() { + signParams[key] = value[0] + } + + if strings.ToUpper(request.Method) == requests.POST { + for key, value := range request.Form { + signParams[key] = value[0] + } + } + + if accessKey, err := signer.GetAccessKeyId(); err != nil { + return err + } else if accessKey == "" { + return errors.New("access key is not allow empty") + } else if accessKey != signParams["access_key"] { + return errors.New("illegal access key") + } + + signValue, ok := signParams["sign"] + if !ok { + return errors.New("sign value is not exists") + } else { + delete(signParams, "sign") + } + + 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 + debug("GrSdk sign: %s", stringToSign) + + if timestamp, err := strconv.ParseInt(signParams["access_time"], 10, 64); err != nil { + return err + } else { + if time.Unix(timestamp, 0).Before(time.Now().Add(-5 * time.Minute)) { + err = errors.New("sign timeout 5 minute") + } + } + + if signer.Sign(stringToSign, "&") != signValue { + return errors.New("sign string is not correct") + } + return +} diff --git a/sdk/auth/rpc_signature_composer.go b/sdk/auth/rpc_signature_composer.go new file mode 100644 index 0000000..049f80f --- /dev/null +++ b/sdk/auth/rpc_signature_composer.go @@ -0,0 +1,126 @@ +package auth + +import ( + "bytes" + "errors" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +func signRpcRequest(request requests.AcsRequest, signer Signer) (err error) { + err = completeRpcSignParams(request, signer) + if err != nil { + return + } + if _, isContainsSign := request.GetQueryParams()["sign"]; isContainsSign { + delete(request.GetQueryParams(), "sign") + } + + stringToSign := buildRpcStringToSign(request) + request.SetStringToSign(stringToSign) + signature := signer.Sign(stringToSign, "&") + request.GetQueryParams()["sign"] = signature + debug("GrSdk sign: %s", signature) + debug("GrSdk sign string: %s", stringToSign) + debug("GrSdk sign: \r\n") + return +} + +func completeRpcSignParams(request requests.AcsRequest, signer Signer) (err error) { + + var accessKeyFrom string + if accessKeyFrom, err = signer.GetAccessKeyFrom(); err != nil { + return + } + + queryParams := request.GetQueryParams() + queryParams["access_time"] = fmt.Sprintf("%d", time.Now().Unix()) + queryParams["access_key"], err = signer.GetAccessKeyId() + queryParams["access_from"] = accessKeyFrom + + if err != nil { + return + } + + request.GetHeaders()["Content-type"] = requests.Form + request.GetHeaders()["Gr-Sdk-From"] = accessKeyFrom + formString := utils.GetUrlFormedMap(request.GetFormParams()) + request.SetContent(bytes.NewBufferString(formString).Bytes()) + return +} + +func buildRpcStringToSign(request requests.AcsRequest) (stringToSign string) { + signParams := make(map[string]string) + for key, value := range request.GetQueryParams() { + signParams[key] = value + } + + if strings.ToUpper(request.GetMethod()) == requests.POST { + for key, value := range request.GetFormParams() { + 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.GetMethod() + "&%2F&" + stringToSign + return +} + +func unsignRpcRequest(request *http.Request, signer Signer) (err error) { + signParams := make(map[string]string) + for key, value := range request.URL.Query() { + signParams[key] = value[0] + } + + if strings.ToUpper(request.Method) == requests.POST { + for key, value := range request.Form { + signParams[key] = value[0] + } + } + + if accessKey, err := signer.GetAccessKeyId(); err != nil { + return err + } else if accessKey == "" { + return errors.New("access key is not allow empty") + } else if accessKey != signParams["access_key"] { + return errors.New("illegal access key") + } + + signValue, ok := signParams["sign"] + if !ok { + return errors.New("sign value is not exists") + } else { + delete(signParams, "sign") + } + + 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 + debug("GrSdk sign: %s", stringToSign) + + if timestamp, err := strconv.ParseInt(signParams["access_time"], 10, 64); err != nil { + return err + } else { + if time.Unix(timestamp, 0).Before(time.Now().Add(-5 * time.Minute)) { + err = errors.New("sign timeout 5 minute") + } + } + + if signer.Sign(stringToSign, "&") != signValue { + return errors.New("sign string is not correct") + } + return +} diff --git a/sdk/auth/signer.go b/sdk/auth/signer.go new file mode 100644 index 0000000..71f262b --- /dev/null +++ b/sdk/auth/signer.go @@ -0,0 +1,56 @@ +package auth + +import ( + "errors" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/signers" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" + "net/http" +) + +type Signer interface { + GetName() string + GetAccessKeyId() (string, error) + GetAccessKeyFrom() (string, error) + Sign(stringToSign, secretSuffix string) string +} + +func NewSignerWithCredential(credential Credential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer Signer, err error) { + switch instance := credential.(type) { + case *credentials.AccessKeyCredential: + signer = signers.NewAccessKeySigner(instance) + case *credentials.BaseCredential: + signer = signers.NewAccessKeySigner(instance.ToAccessKeyCredential()) + case *credentials.StdTokenCredential: + signer = signers.NewStsTokenSigner(instance) + case *credentials.AliAppcodeCredential: + signer = signers.NewAliAppcodeSigner(instance) + default: + err = errors.New("UnsupportedCredentialErrorCode = SDK.UnsupportedCredential") + } + return +} + +func Sign(request requests.AcsRequest, signer Signer) (err error) { + switch signer.(type) { + case *signers.AliAppcodeSigner: + err = signRaliRequest(request, signer) + return + } + + //TODO 根据rpc和roa两种风格签名,自行选择 + switch request.GetStyle() { + case requests.RPC: + err = signRpcRequest(request, signer) + case requests.ROA: + err = signRoaRequest(request, signer) + } + return +} + +func UnSign(request *http.Request, signer Signer) (err error) { + //TODO 根据rpc和roa两种风格签名,自行选择 + err = unsignRpcRequest(request, signer) + return +} diff --git a/sdk/auth/signers/access_key_siginer.go b/sdk/auth/signers/access_key_siginer.go new file mode 100644 index 0000000..2ba1619 --- /dev/null +++ b/sdk/auth/signers/access_key_siginer.go @@ -0,0 +1,44 @@ +package signers + +import ( + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" +) + +type AccessKeySigner struct { + credential *credentials.AccessKeyCredential +} + +func (signer *AccessKeySigner) GetAccessKeyId() (string, error) { + return signer.credential.AccessKeyId, nil +} + +func (signer *AccessKeySigner) GetAccessKeyFrom() (string, error) { + return signer.credential.AccessKeyFrom, nil +} + +func (*AccessKeySigner) GetName() string { + return "HMAC-SHA1" +} + +func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string { + secret := signer.credential.AccessKeySecret + secretSuffix + return ShaHmac1(stringToSign, secret) +} + +func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner { + return &AccessKeySigner{ + credential: credential, + } +} + +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 +} diff --git a/sdk/auth/signers/ali_appcode_signer.go b/sdk/auth/signers/ali_appcode_signer.go new file mode 100644 index 0000000..2ec4c50 --- /dev/null +++ b/sdk/auth/signers/ali_appcode_signer.go @@ -0,0 +1,43 @@ +package signers + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" +) + +type AliAppcodeSigner struct { + credential *credentials.AliAppcodeCredential +} + +func (signer *AliAppcodeSigner) GetName() string { + return "HmacSHA256" +} + +func (signer *AliAppcodeSigner) GetAccessKeyId() (string, error) { + return signer.credential.AccessKeyId, nil +} + +func (signer *AliAppcodeSigner) GetAccessKeyFrom() (string, error) { + return "", nil +} + +func (signer *AliAppcodeSigner) Sign(stringToSign, secretSuffix string) string { + secret := signer.credential.AccessKeySecret + secretSuffix + return ShaHmac256(stringToSign, secret) +} + +func NewAliAppcodeSigner(credential *credentials.AliAppcodeCredential) *AliAppcodeSigner { + return &AliAppcodeSigner{ + credential: credential, + } +} + +func ShaHmac256(source, secret string) string { + key := []byte(secret) + hmac1 := hmac.New(sha256.New, key) + hmac1.Write([]byte(source)) + signedString := base64.StdEncoding.EncodeToString(hmac1.Sum(nil)) + return signedString +} diff --git a/sdk/auth/signers/sts_token_signer.go b/sdk/auth/signers/sts_token_signer.go new file mode 100644 index 0000000..c4bc69b --- /dev/null +++ b/sdk/auth/signers/sts_token_signer.go @@ -0,0 +1,41 @@ +package signers + +import ( + "crypto/md5" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" +) + +type StsTokenSigner struct { + credential *credentials.StdTokenCredential +} + +func (signer *StsTokenSigner) GetAccessKeyId() (string, error) { + return signer.credential.AccessKeyId, nil +} + +func (signer *StsTokenSigner) GetAccessKeyFrom() (string, error) { + return signer.credential.AccessKeyFrom, nil +} + +func (*StsTokenSigner) GetName() string { + return "MD5" +} + +func (signer *StsTokenSigner) Sign(stringToSign, secretSuffix string) string { + secret := signer.credential.AccessKeySecret + secretSuffix + return Md5(stringToSign, secret) +} + +func NewStsTokenSigner(credential *credentials.StdTokenCredential) *StsTokenSigner { + return &StsTokenSigner{ + credential: credential, + } +} + +func Md5(source, secret string) string { + data := []byte(fmt.Sprintf("%s##%s", secret, source)) + has := md5.Sum(data) + md5str := fmt.Sprintf("%x", has) + return md5str +} diff --git a/sdk/client.go b/sdk/client.go new file mode 100644 index 0000000..0e2add5 --- /dev/null +++ b/sdk/client.go @@ -0,0 +1,357 @@ +package sdk + +import ( + "bytes" + "context" + "crypto/tls" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "net" + "net/http" + "net/http/httputil" + "net/url" + "os" + "regexp" + "runtime" + "strings" + "time" +) + +var Version = "0.0.1" +var defaultConnectTimeout = 5 * time.Second +var defaultReadTimeout = 10 * time.Second +var defaultDomain = ".gaore.com" +var DefaultUserAgent = fmt.Sprintf("GaoreGoSdk (%s;%s) Golang/%s Core/%s", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), Version) + +var debug utils.Debug + +func init() { + debug = utils.Init("sdk") +} + +type Client struct { + Host string + httpClient *http.Client + isInsecure bool + signer auth.Signer + readTimeout time.Duration + connectTimeout time.Duration + config *Config + httpProxy string + httpsProxy string + noProxy string +} + +func (client *Client) GetNoProxy() string { + return client.noProxy +} + +func (client *Client) SetNoProxy(noProxy string) { + client.noProxy = noProxy +} + +func (client *Client) GetHttpsProxy() string { + return client.httpsProxy +} + +func (client *Client) SetHttpsProxy(httpsProxy string) { + client.httpsProxy = httpsProxy +} + +func (client *Client) SetHttpProxy(httpProxy string) { + client.httpProxy = httpProxy +} + +func (client *Client) GetHttpProxy() string { + return client.httpProxy +} + +func (client *Client) GetHTTPSInsecure() bool { + return client.isInsecure +} + +func (client *Client) InitClientConfig() (config *Config) { + if client.config != nil { + return client.config + } else { + return NewConfig() + } + +} + +func (client *Client) InitWithAccessKey(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) { + config := client.InitWithConfig() + credential := &credentials.BaseCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + AccessKeyFrom: accessKeyFrom, + } + return client.InitWithOptions(config, credential) +} + +func (client *Client) InitWithAliAppcode(accessKeyId, accessKeySecret string, env ...string) (err error) { + config := client.InitWithConfig() + credential := credentials.NewAliAppcodeCredential(accessKeyId, accessKeySecret) + + if len(env) > 0 { + config.Env = env[0] + } + + return client.InitWithOptions(config, credential) +} + +func (client *Client) InitWithStsToken(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) { + config := client.InitWithConfig() + credential := &credentials.StdTokenCredential{ + AccessKeyId: accessKeyId, + AccessKeySecret: accessKeySecret, + AccessKeyFrom: accessKeyFrom, + } + return client.InitWithOptions(config, credential) +} + +func (client *Client) InitWithOptions(config *Config, credential auth.Credential) (err error) { + client.httpClient = &http.Client{} + client.config = config + + if config.Transport != nil { + client.httpClient.Transport = config.Transport + } else if config.HttpTransport != nil { + client.httpClient.Transport = config.HttpTransport + } + + if config.Timeout > 0 { + client.httpClient.Timeout = config.Timeout + } + + client.signer, err = auth.NewSignerWithCredential(credential, client.ProcessCommonRequestWithSigner) + return +} + +func (client *Client) InitWithConfig() (config *Config) { + if client.config != nil { + return client.config + } else { + return NewConfig() + } +} + +func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonRequest, signerInterface interface{}) (response *responses.CommonResponse, err error) { + if signer, isSigner := signerInterface.(auth.Signer); isSigner { + response = responses.NewCommonResponse() + err = client.DoActionWithSigner(request, response, signer) + return + } + panic("should not be here") +} + +func Timeout(connectTimeout time.Duration) func(ctx context.Context, net, addr string) (c net.Conn, err error) { + return func(ctx context.Context, network, address string) (c net.Conn, err error) { + return (&net.Dialer{ + Timeout: connectTimeout, + DualStack: true, + }).DialContext(ctx, network, address) + } +} + +func (client *Client) setTimeOut(request requests.AcsRequest) { + readTimeout, connectTimeout := client.getTimeOut(request) + client.httpClient.Timeout = readTimeout + if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil { + trans.DialContext = Timeout(connectTimeout) + client.httpClient.Transport = trans + } else if client.httpClient.Transport == nil { + client.httpClient.Transport = &http.Transport{ + DialContext: Timeout(connectTimeout), + } + } +} + +func (client *Client) getTimeOut(request requests.AcsRequest) (time.Duration, time.Duration) { + readTimeOut := defaultReadTimeout + connectTimeOut := defaultConnectTimeout + + reqReadTimeout := request.GetReadTimeout() + reqConnectTimeout := request.GetConnectTimeout() + if reqReadTimeout != 0*time.Millisecond { + readTimeOut = reqReadTimeout + } else if client.readTimeout != 0*time.Microsecond { + readTimeOut = client.readTimeout + } else if client.httpClient.Timeout != 0 { + readTimeOut = client.httpClient.Timeout + } + + if reqConnectTimeout != 0*time.Microsecond { + connectTimeOut = reqConnectTimeout + } else if client.connectTimeout != 0*time.Millisecond { + connectTimeOut = client.connectTimeout + } + return readTimeOut, connectTimeOut +} + +func (client *Client) getHTTPSInsecure(request requests.AcsRequest) (insecure bool) { + if request.GetHTTPSInsecure() != nil { + insecure = *request.GetHTTPSInsecure() + } else { + insecure = client.GetHTTPSInsecure() + } + return +} + +func (client *Client) DoAction(request requests.AcsRequest, response responses.AcsResponse) (err error) { + return client.DoActionWithSigner(request, response, nil) +} + +func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) { + + httpRequest, err := client.buildRequestWithSigner(request, signer) + if err != nil { + return err + } + + client.setTimeOut(request) + proxy, err := client.getHttpProxy(httpRequest.URL.Scheme) + if err != nil { + return err + } + noProxy := client.getNoProxy(httpRequest.URL.Scheme) + var flag bool + for _, value := range noProxy { + if strings.HasPrefix(value, "*") { + value = fmt.Sprint(".%s", value) + } + noProxyReg, err := regexp.Compile(value) + if err != nil { + return err + } + if noProxyReg.MatchString(httpRequest.Host) { + flag = true + break + } + } + + if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil { + if trans.TLSClientConfig != nil { + trans.TLSClientConfig.InsecureSkipVerify = client.getHTTPSInsecure(request) + } else { + trans.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: client.getHTTPSInsecure(request), + } + } + + if proxy != nil && !flag { + trans.Proxy = http.ProxyURL(proxy) + } + + client.httpClient.Transport = trans + } + + dump, err := httputil.DumpRequest(httpRequest, true) + debug("client %s", bytes.NewBuffer(dump).String()) + + var httpResponse *http.Response + httpResponse, err = hookDo(client.httpClient.Do)(httpRequest) + if err != nil { + return + } + + err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat()) + return +} + +func (client *Client) buildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (httpRequest *http.Request, err error) { + // init param + domain := request.GetDomain() + if strings.Index(domain.Default, ".") < 0 { + domain.Default += defaultDomain + request.SetDomain(domain) + } + + if request.GetScheme() == "" { + request.SetScheme(client.config.Scheme) + } + + if request.GetEnv() == "" && client.config.Env != "" { + request.SetEnv(client.config.Env) + } + + err = requests.InitParam(request) + if err != nil { + return + } + // build signature + var finalSigner auth.Signer + if signer != nil { + finalSigner = signer + } else { + finalSigner = client.signer + } + err = auth.Sign(request, finalSigner) + if err != nil { + return + } + + // build request + requestMethod := request.GetMethod() + requestUrl := request.BuildUrl() + body := request.GetBodyReader() + httpRequest, err = http.NewRequest(requestMethod, requestUrl, body) + if err != nil { + return + } + + for key, val := range request.GetHeaders() { + httpRequest.Header[key] = []string{val} + } + + if host, isContainsHost := request.GetHeaders()["host"]; isContainsHost { + httpRequest.Host = host + } + + userAgent := DefaultUserAgent + httpRequest.Header.Set("User-Agent", userAgent) + + return +} + +func (client *Client) getHttpProxy(scheme string) (proxy *url.URL, err error) { + switch scheme { + case "https": + if client.GetHttpsProxy() != "" { + proxy, err = url.Parse(client.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) + } + default: + if client.GetHttpProxy() != "" { + proxy, err = url.Parse(client.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 +} + +func (client *Client) getNoProxy(scheme string) []string { + var urls []string + if client.GetNoProxy() != "" { + urls = strings.Split(client.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 hookDo(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) { + return fn +} diff --git a/sdk/config.go b/sdk/config.go new file mode 100644 index 0000000..ae79f51 --- /dev/null +++ b/sdk/config.go @@ -0,0 +1,24 @@ +package sdk + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "net/http" + "time" +) + +type Config struct { + Debug bool `default:"false"` + HttpTransport *http.Transport `default:""` + Transport http.RoundTripper `default:""` + GoRoutinePoolSize int `default:"0"` + UserAgent string `default:""` + Scheme string `default:"HTTP"` + Timeout time.Duration `default:"5"` + Env string `default:""` +} + +func NewConfig() *Config { + config := &Config{} + utils.InitStructWithDefaultTag(config) + return config +} diff --git a/sdk/requests/common_request.go b/sdk/requests/common_request.go new file mode 100644 index 0000000..74fea83 --- /dev/null +++ b/sdk/requests/common_request.go @@ -0,0 +1,36 @@ +package requests + +import "io" + +type CommonRequest struct { + *baseRequest + Product string + Ontology AcsRequest +} + +func (request *CommonRequest) TransToAscRequest() { + rpcRequest := &RpcRequest{} + rpcRequest.baseRequest = request.baseRequest + rpcRequest.product = request.Product + request.Ontology = rpcRequest +} + +func (request *CommonRequest) BuildUrl() string { + return request.Ontology.BuildUrl() +} + +func (request *CommonRequest) BuildQueries() string { + return request.Ontology.BuildQueries() +} + +func (request *CommonRequest) GetBodyReader() io.Reader { + return request.Ontology.GetBodyReader() +} + +func (request *CommonRequest) GetStyle() string { + return request.Ontology.GetStyle() +} + +func (request *CommonRequest) InitWithApiInfo(domain Host, version, urlPath string) { + request.Ontology.InitWithApiInfo(domain, version, urlPath) +} diff --git a/sdk/requests/request.go b/sdk/requests/request.go new file mode 100644 index 0000000..551cc79 --- /dev/null +++ b/sdk/requests/request.go @@ -0,0 +1,314 @@ +package requests + +import ( + "errors" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "io" + "math/cmplx" + "reflect" + "strconv" + "time" +) + +const ( + RPC = "RPC" + ROA = "ROA" + + HTTP = "HTTP" + HTTPS = "HTTPS" + + JSON = "JSON" + XML = "XML" + + DefaultHttpPort = "80" + + GET = "GET" + PUT = "PUT" + POST = "POST" + DELETE = "DELETE" + PATCH = "PATCH" + HEAD = "HEAD" + OPTIONS = "OPTIONS" + + Json = "application/json" + Xml = "application/xml" + Raw = "application/octet-stream" + Form = "application/x-www-form-urlencoded" + + Header = "Header" + Query = "Query" + Body = "Body" + Path = "Path" + + TEST = "TEST" + PRE = "PRE" + RELEASE = "RELEASE" + + HeaderSeparator = "\n" +) + +type Host struct { + Default string + Func func(string) string +} + +var debug utils.Debug + +func init() { + debug = utils.Init("request") +} + +type AcsRequest interface { + GetReadTimeout() time.Duration + GetConnectTimeout() time.Duration + SetReadTimeout(readTimeOut time.Duration) + SetConnectTimeout(connectTimeOut time.Duration) + SetHTTPSInsecure(isInsecure bool) + GetHTTPSInsecure() *bool + GetQueryParams() map[string]string + GetFormParams() map[string]string + GetMethod() string + GetScheme() string + GetDomain() Host + SetDomain(host Host) + GetActionName() string + GetAcceptFormat() string + GetAccept() string + GetHeaders() map[string]string + GetStyle() string + InitWithApiInfo(domain Host, version, urlPath string) + GetEnv() string + SetEnv(string) + + BuildUrl() string + BuildQueries() string + + SetScheme(scheme string) + SetContent(content []byte) + + SetStringToSign(stringToSign string) + GetStringToSign() string + GetBodyReader() io.Reader + + AddHeaderParam(key, value string) + addQueryParam(key, value string) + addFormParam(key, value string) +} + +type baseRequest struct { + Scheme string + Method string + Port string + Domain Host + From string + ReadTimeout time.Duration + ConnectTimeout time.Duration + isInsecure *bool + Env string + + AcceptFormat string + actionName string + + userAgent map[string]string + product string + version string + + QueryParams map[string]string + Headers map[string]string + FormParams map[string]string + Content []byte + + queries string + stringToSign string +} + +func (request *baseRequest) GetEnv() string { + return request.Env +} + +func (request *baseRequest) SetEnv(e string) { + request.Env = e +} + +func (request *baseRequest) GetStringToSign() string { + return request.stringToSign +} + +func (request *baseRequest) SetContent(content []byte) { + request.Content = content +} + +func (request *baseRequest) GetAcceptFormat() string { + return request.AcceptFormat +} + +func (request *baseRequest) GetAccept() string { + switch request.GetAcceptFormat() { + case JSON: + return Json + case XML: + return Xml + } + return "" +} + +func (request *baseRequest) GetHeaders() map[string]string { + return request.Headers +} + +func (request *baseRequest) GetActionName() string { + return request.actionName +} + +func (request *baseRequest) SetScheme(scheme string) { + request.Scheme = scheme +} + +func (request *baseRequest) SetDomain(host Host) { + request.Domain = host +} + +func (request *baseRequest) GetScheme() string { + return request.Scheme +} + +func (request *baseRequest) GetDomain() Host { + return request.Domain +} + +func (request *baseRequest) GetMethod() string { + return request.Method +} + +func (request *baseRequest) GetFormParams() map[string]string { + return request.FormParams +} + +func (request *baseRequest) GetQueryParams() map[string]string { + return request.QueryParams +} + +func (request *baseRequest) SetHTTPSInsecure(isInsecure bool) { + request.isInsecure = &isInsecure +} + +func (request *baseRequest) GetHTTPSInsecure() *bool { + return request.isInsecure +} + +func (request *baseRequest) GetReadTimeout() time.Duration { + return request.ReadTimeout +} + +func (request *baseRequest) GetConnectTimeout() time.Duration { + return request.ConnectTimeout +} + +func (request *baseRequest) SetReadTimeout(readTimeOut time.Duration) { + request.ReadTimeout = readTimeOut +} + +func (request *baseRequest) SetConnectTimeout(connectTimeOut time.Duration) { + request.ConnectTimeout = connectTimeOut +} + +func (request *baseRequest) SetStringToSign(stringToSign string) { + request.stringToSign = stringToSign +} + +func (request *baseRequest) AddHeaderParam(key, val string) { + request.Headers[key] = val +} + +func (request *baseRequest) addQueryParam(key, val string) { + request.QueryParams[key] = val +} + +func (request *baseRequest) addFormParam(key, val string) { + request.FormParams[key] = val +} + +func defaultBaseRequest() (request *baseRequest) { + request = &baseRequest{ + Scheme: HTTP, + AcceptFormat: JSON, + Method: GET, + QueryParams: make(map[string]string), + Headers: map[string]string{ + "Gr-Sdk-Client": "golang/1.14", + "Gr-Sdk-Invoke-Type": "normal", + "Accept-Encoding": Json, + }, + FormParams: make(map[string]string), + } + return +} + +func InitParam(request AcsRequest) (err error) { + reflectValue := reflect.ValueOf(request).Elem() + err = flatRepeatedList(reflectValue, request, "") + return nil +} + +func flatRepeatedList(reflectValue reflect.Value, request AcsRequest, position string) (err error) { + reflectType := reflectValue.Type() + for i := 0; i < reflectType.NumField(); i++ { + field := reflectType.Field(i) + name, isContiansNameTag := field.Tag.Lookup("field") + + fieldPosition := position + if fieldPosition == "" { + fieldPosition, _ = field.Tag.Lookup("position") + } + + fieldDefault, _ := field.Tag.Lookup("default") + debug("%s %s %s", name, fieldPosition, fieldDefault) + if isContiansNameTag { + var value string + switch field.Type.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + value = strconv.FormatInt(reflectValue.Field(i).Int(), 10) + case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + value = strconv.FormatUint(reflectValue.Field(i).Uint(), 10) + case reflect.Float32, reflect.Float64: + value = strconv.FormatFloat(reflectValue.Field(i).Float(), 'E', -1, 64) + case reflect.Bool: + value = strconv.FormatBool(reflectValue.Field(i).Bool()) + case reflect.Complex64, reflect.Complex128: + value = fmt.Sprint(cmplx.Sqrt(reflectValue.Field(i).Complex())) + default: + value = reflectValue.Field(i).String() + } + + if len(value) == 0 { + value = fieldDefault + } + + if value == "0" && fieldDefault != "" && fieldDefault != "0" { + value = fieldDefault + } + + err = addParam(request, fieldPosition, name, value) + } + } + + return +} + +func addParam(request AcsRequest, position, key, value string) (err error) { + if len(value) > 0 { + switch position { + case Header: + request.AddHeaderParam(key, value) + case Query: + request.addQueryParam(key, value) + case Body: + request.addFormParam(key, value) + default: + errmsg := fmt.Sprintf("unsupport positions add param `%s`", position) + err = errors.New(errmsg) + } + } + return +} diff --git a/sdk/requests/rpc_request.go b/sdk/requests/rpc_request.go new file mode 100644 index 0000000..55e763c --- /dev/null +++ b/sdk/requests/rpc_request.go @@ -0,0 +1,63 @@ +package requests + +import ( + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" + "io" + "strings" +) + +type RpcRequest struct { + *baseRequest +} + +func (request *RpcRequest) init() { + request.baseRequest = defaultBaseRequest() + request.Method = POST +} + +func (request *RpcRequest) BuildUrl() string { + + var hostname string + if request.Domain.Func == nil { + hostname = request.Domain.Default + } else if hostname = request.Domain.Func(request.GetEnv()); hostname == "" { + hostname = request.Domain.Default + } + + url := fmt.Sprintf("%s://%s", strings.ToLower(request.Scheme), hostname) + if len(request.Port) > 0 { + url = fmt.Sprintf("%s:%s", url, request.Port) + } + return url + request.BuildQueries() +} + +func (request *RpcRequest) GetStyle() string { + return RPC +} + +func (request *RpcRequest) BuildQueries() string { + path := strings.TrimLeft(strings.TrimSpace(request.GetActionName()), "/") + request.queries = "/" + path + "?" + utils.GetUrlFormedMap(request.QueryParams) + return request.queries +} + +func (request *RpcRequest) GetActionName() string { + return request.actionName +} + +func (request *RpcRequest) InitWithApiInfo(domain Host, version, urlPath string) { + request.init() + request.SetDomain(domain) + request.version = version + request.actionName = urlPath +} + +func (request *RpcRequest) GetBodyReader() io.Reader { + if request.FormParams != nil && len(request.FormParams) > 0 { + formString := utils.GetUrlFormedMap(request.FormParams) + return strings.NewReader(formString) + } else { + return strings.NewReader("") + } +} diff --git a/sdk/requests/types.go b/sdk/requests/types.go new file mode 100644 index 0000000..68e2130 --- /dev/null +++ b/sdk/requests/types.go @@ -0,0 +1,10 @@ +package requests + +import "strconv" + +type Interger string + +func (i Interger) ToInt() int { + a, _ := strconv.ParseInt(string(i), 10, 64) + return int(a) +} diff --git a/sdk/responses/response.go b/sdk/responses/response.go new file mode 100644 index 0000000..7125546 --- /dev/null +++ b/sdk/responses/response.go @@ -0,0 +1,117 @@ +package responses + +import ( + "encoding/json" + "errors" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "io/ioutil" + "net/http" + "strings" +) + +type AcsResponse interface { + IsSuccess() bool + GetHttpStatus() int + GetHttpHeaders() map[string][]string + GetHttpContentString() string + GetHttpContentBytes() []byte + GetOriginHttpResponse() *http.Response + parseFromHttpResponse(httpResponse *http.Response) error +} + +type BaseResponse struct { + httpStatus int + httpHeaders map[string][]string + httpContentString string + httpContentBytes []byte + originHttpResponse *http.Response + + Code int `json:"code"` + Status bool `json:"status"` + Msg string `json:"msg"` +} + +func (baseResponse *BaseResponse) GetHttpStatus() int { + return baseResponse.httpStatus +} + +func (baseResponse *BaseResponse) GetHttpHeaders() map[string][]string { + return baseResponse.httpHeaders +} + +func (baseResponse *BaseResponse) GetHttpContentString() string { + return baseResponse.httpContentString +} + +func (baseResponse *BaseResponse) GetHttpContentBytes() []byte { + return baseResponse.httpContentBytes +} + +func (baseResponse *BaseResponse) GetOriginHttpResponse() *http.Response { + return baseResponse.originHttpResponse +} + +func (baseResponse *BaseResponse) IsSuccess() bool { + if baseResponse.GetHttpStatus() >= 200 && baseResponse.GetHttpStatus() < 300 { + return true + } + return false +} + +func (baseResponse *BaseResponse) parseFromHttpResponse(httpResponse *http.Response) (err error) { + defer httpResponse.Body.Close() + body, err := ioutil.ReadAll(httpResponse.Body) + if err != nil { + return + } + baseResponse.httpStatus = httpResponse.StatusCode + baseResponse.httpHeaders = httpResponse.Header + baseResponse.httpContentBytes = body + baseResponse.httpContentString = string(body) + baseResponse.originHttpResponse = httpResponse + return +} + +type CommonResponse struct { + *BaseResponse +} + +func NewCommonResponse() (response *CommonResponse) { + return &CommonResponse{ + BaseResponse: &BaseResponse{}, + } +} + +func Unmarshal(response AcsResponse, httpResponse *http.Response, format string) (err error) { + err = response.parseFromHttpResponse(httpResponse) + if err != nil { + return + } + + if _, isCommonResponse := response.(CommonResponse); isCommonResponse { + return + } + + if !response.IsSuccess() { + if contentType, ok := response.GetHttpHeaders()["Content-Type"]; ok { + for _, v := range contentType { + if strings.Contains(v, requests.Json) { + json.Unmarshal(response.GetHttpContentBytes(), response) + break + } + } + } + + err = errors.New(fmt.Sprintf("%d %s", response.GetHttpStatus(), response.GetHttpContentString())) + return + } + + if format != "xml" { + err = json.Unmarshal(response.GetHttpContentBytes(), response) + if err != nil { + return errors.New("json Unmarshal:" + err.Error()) + } + } + return +} diff --git a/sdk/utils/debug.go b/sdk/utils/debug.go new file mode 100644 index 0000000..9e3a48b --- /dev/null +++ b/sdk/utils/debug.go @@ -0,0 +1,36 @@ +package utils + +import ( + "fmt" + "os" + "strings" +) + +type Debug func(format string, v ...interface{}) + +var hookPrint = func(input string) { + fmt.Println(input) +} + +var hookGetEnv = func() string { + return os.Getenv("DEBUG") +} + +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/sdk/utils/utils.go b/sdk/utils/utils.go new file mode 100644 index 0000000..c655962 --- /dev/null +++ b/sdk/utils/utils.go @@ -0,0 +1,111 @@ +package utils + +import ( + "crypto/md5" + "crypto/rand" + "encoding/hex" + "fmt" + "hash" + rand2 "math/rand" + "net/url" + "reflect" + "sort" + "strconv" + "strings" + "time" +) + +type UUID [16]byte + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func GetUUID() (uuidHex string) { + uuid := NewUUID() + uuidHex = hex.EncodeToString(uuid[:]) + 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 RandStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand2.Intn(len(letterBytes))] + } + return string(b) +} + +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) + } +} + +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 GetUrlByKeySort(source map[string]string) (url string) { + keys := make([]string, 0, len(source)) + for k := range source { + keys = append(keys, k) + } + sort.Strings(keys) + for _, key := range keys { + url += fmt.Sprintf("%s=%s&", key, source[key]) + } + return strings.TrimRight(url, "&") +} + +func InitStructWithDefaultTag(bean interface{}) { + beantype := reflect.TypeOf(bean) + for i := 0; i < beantype.Elem().NumField(); i++ { + field := beantype.Elem().Field(i) + defaultValue := strings.TrimSpace(field.Tag.Get("default")) + if defaultValue == "" || defaultValue == "-" { + continue + } + setter := reflect.ValueOf(bean).Elem().Field(i) + fieldTypeName := field.Type.String() + switch fieldTypeName { + case "int", "int64", "int32", "int8", "int16": + intval, _ := strconv.ParseInt(defaultValue, 10, 64) + setter.SetInt(intval) + case "uint", "uint8", "uint16", "uint32", "uint64", "uintptr": + uintval, _ := strconv.ParseUint(defaultValue, 10, 64) + setter.SetUint(uintval) + case "string": + setter.SetString(defaultValue) + case "time.Duration": + intval, _ := strconv.ParseInt(defaultValue, 10, 64) + setter.SetInt(intval * int64(time.Second)) + case "bool": + boolval, _ := strconv.ParseBool(defaultValue) + setter.SetBool(boolval) + default: + fmt.Println(field.Type.String(), field.Name) + } + } +} diff --git a/sdk/utils/utils_test.go b/sdk/utils/utils_test.go new file mode 100644 index 0000000..96fcf22 --- /dev/null +++ b/sdk/utils/utils_test.go @@ -0,0 +1,25 @@ +package utils + +import ( + "fmt" + "net/http" + "testing" + "time" +) + +type TestCase struct { + Debug bool `default:"false"` + HttpTransport *http.Transport `default:""` + Transport http.RoundTripper `default:""` + GoRoutinePoolSize int `default:"5"` + UserAgent string `default:""` + Scheme string `default:"HTTP"` + Haha uintptr `default:"232"` + Timeout time.Duration `default:"5"` +} + +func TestInitStructWithDefaultTag(t *testing.T) { + testcase := &TestCase{} + InitStructWithDefaultTag(testcase) + fmt.Printf("%+v", testcase) +} diff --git a/services/apk/add_apk.go b/services/apk/add_apk.go new file mode 100644 index 0000000..e656dcb --- /dev/null +++ b/services/apk/add_apk.go @@ -0,0 +1,37 @@ +package apk + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type AddApkRequest struct { + *requests.RpcRequest + List string `position:"Body" field:"list" default:"[]" ` +} + +type AddApkResponse struct { + *responses.BaseResponse + Code int `json:"code"` + Status bool `json:"status"` + Msg string `json:"msg"` + Data struct { + Count int `json:"count"` + } `json:"data"` +} + +func CreateAddApkRequest() (req *AddApkRequest) { + req = &AddApkRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/apk/add") + req.Method = requests.POST + return +} + +func CreateAddApkResponse() (response *AddApkResponse) { + response = &AddApkResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/apk/add_top.go b/services/apk/add_top.go new file mode 100644 index 0000000..732b613 --- /dev/null +++ b/services/apk/add_top.go @@ -0,0 +1,36 @@ +package apk + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type AddTopRequest struct { + *requests.RpcRequest + Id int `position:"Body" field:"id" default:"0" ` + Ids string `position:"Body" field:"ids" default:"" ` + Top int `position:"Body" field:"top" default:"0"` +} + +type AddTopResponse struct { + *responses.BaseResponse + Code int `json:"code"` + Status bool `json:"status"` + Msg string `json:"msg"` +} + +func CreateAddTopRequest() (req *AddTopRequest) { + req = &AddTopRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/apk/AddTop") + req.Method = requests.POST + return +} + +func CreateAddTopResponse() (response *AddTopResponse) { + response = &AddTopResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/apk/client.go b/services/apk/client.go new file mode 100644 index 0000000..46c6d60 --- /dev/null +++ b/services/apk/client.go @@ -0,0 +1,66 @@ +package apk + +import ( + "encoding/json" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" +) + +const ( + VERSION = "2021-07-30" +) + +var HOST requests.Host = requests.Host{ + Default: "c.api.gaore.com", + Func: func(s string) string { + var a = map[string]string{ + requests.RELEASE: "c.api.gaore.com", + requests.PRE: "c.api.gaore.com", + requests.TEST: "c.api.gaore.com", + } + return a[s] + }, +} + +type Client struct { + sdk.Client +} + +func NewClient() (client *Client) { + client = &Client{} + client.InitWithAccessKey("", "", "") + return +} + +// 打包任务添加优先级 +func (c *Client) AddApkTop(req *AddTopRequest) (response *AddTopResponse, err error) { + response = CreateAddTopResponse() + err = c.DoAction(req, response) + return +} + +// 添加打包任务 +func (c *Client) AddApk(req *AddApkRequest) (response *AddApkResponse, err error) { + response = CreateAddApkResponse() + err = c.DoAction(req, response) + return +} + +// 清除cdn +func (c *Client) RefreshApkR(req *RefreshApkRequest) (response *RefreshApkResponse, err error) { + response = CreateRefreshApkResponse() + if len(req.CdnUrlArray) > 0 { + cdnurls, _ := json.Marshal(req.CdnUrlArray) + req.cdnUrls = string(cdnurls) + } + err = c.DoAction(req, response) + return +} + +// 获取打包日志 +func (c *Client) SearchApk(req *SearchApkRequest) (response *SearchApkResponse, err error) { + response = CreateSearchApkResponse() + + err = c.DoAction(req, response) + return +} diff --git a/services/apk/client_test.go b/services/apk/client_test.go new file mode 100644 index 0000000..5682b98 --- /dev/null +++ b/services/apk/client_test.go @@ -0,0 +1,21 @@ +package apk + +import ( + "fmt" + "testing" + "time" +) + +func TestClient_GetUserInfo(t *testing.T) { + c := NewClient() + req := CreateSearchApkRequest() + req.GameIds = "3503" + req.Ver = "1.0.0" + req.SetReadTimeout(60 * time.Second) + resp, err := c.SearchApk(req) + + fmt.Println(req) + fmt.Println(resp.GetHttpContentString()) + fmt.Println(err) + +} diff --git a/services/apk/refresh_apk.go b/services/apk/refresh_apk.go new file mode 100644 index 0000000..05e841b --- /dev/null +++ b/services/apk/refresh_apk.go @@ -0,0 +1,36 @@ +package apk + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type RefreshApkRequest struct { + *requests.RpcRequest + cdnUrls string `position:"Body" field:"cdn_urls" default:"[]" ` + CdnUrlArray []string +} + +type RefreshApkResponse struct { + *responses.BaseResponse + Code int `json:"code"` + Status bool `json:"status"` + Msg string `json:"msg"` + Data map[string]string `json:"data"` +} + +func CreateRefreshApkRequest() (req *RefreshApkRequest) { + req = &RefreshApkRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/apk/refresh") + req.Method = requests.POST + return +} + +func CreateRefreshApkResponse() (response *RefreshApkResponse) { + response = &RefreshApkResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/apk/search_apk.go b/services/apk/search_apk.go new file mode 100644 index 0000000..1e6cf5d --- /dev/null +++ b/services/apk/search_apk.go @@ -0,0 +1,74 @@ +package apk + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" + "time" +) + +type SearchApkRequest struct { + *requests.RpcRequest + StartTime string `position:"Body" field:"startTime" default:"" ` + EndTime string `position:"Body" field:"endTime" default:"" ` + State string `position:"Body" field:"state" default:"" ` + SiteIds string `position:"Body" field:"siteIds" default:"" ` + Ver string `position:"Body" field:"ver" default:"" ` + SiteId int `position:"Body" field:"siteId" default:"" ` + AgentId int `position:"Body" field:"agentId" default:"" ` + Top int `position:"Body" field:"top" default:"" ` + GameIds string `position:"Body" field:"gameIds" default:"" ` + Autor string `position:"Body" field:"autor" default:"" ` + Page int `position:"Body" field:"page" default:"1" ` + Pagesize int `position:"Body" field:"pagesize" default:"20" ` + Order string `position:"Body" field:"order" default:"" ` +} + +type ApkLog struct { + ID int `json:"Id"` + GameID int `json:"GameId"` + GameName string `json:"GameName"` + Ver string `json:"Ver"` + Top int `json:"Top"` + AgentID int `json:"AgentId"` + SiteID int `json:"SiteId"` + Addtime time.Time `json:"Addtime"` + Edittime time.Time `json:"Edittime"` + State int `json:"State"` + Times int `json:"Times"` + ReleaseTime int `json:"ReleaseTime"` + Env int `json:"Env"` + AliOss int `json:"AliOss"` + NeedCdn bool `json:"NeedCdn"` + Autor string `json:"Autor"` + Ext string `json:"Ext"` + IsAugment bool `json:"IsAugment"` +} + +type SearchApkResponse struct { + *responses.BaseResponse + Code int `json:"code"` + Status bool `json:"status"` + Msg string `json:"msg"` + Data struct { + Page int `json:"Page"` + PageSize int `json:"PageSize"` + Total int `json:"Total"` + List []ApkLog `json:"List"` + } `json:"data"` +} + +func CreateSearchApkRequest() (req *SearchApkRequest) { + req = &SearchApkRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/apk/list") + req.Method = requests.POST + return +} + +func CreateSearchApkResponse() (response *SearchApkResponse) { + response = &SearchApkResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/callback/client.go b/services/callback/client.go new file mode 100644 index 0000000..de57c0d --- /dev/null +++ b/services/callback/client.go @@ -0,0 +1,48 @@ +package callback + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" +) + +const ( + VERSION = "2021-11-30" +) + +var HOST requests.Host = requests.Host{ + Default: "callback.api.gaore.com", + Func: func(s string) string { + var a = map[string]string{ + requests.RELEASE: "callback.api.gaore.com", + requests.PRE: "callback.api.gaore.com", + requests.TEST: "callback.api.gaore.com", + } + return a[s] + }, +} + +type Client struct { + sdk.Client +} + +func NewClient() (client *Client) { + client = &Client{} + client.InitWithAccessKey("", "", "") + return +} + +// 上报关键行为 +func (c *Client) SendAction(req *SendActionRequest) (response *SendActionResponse, err error) { + response = CreateSendActionResponse() + err = c.DoAction(req, response) + return +} + +// 上报激活 +func (c *Client) SendActive() { + +} + +// 上报付费 + +// 上报注册 diff --git a/services/callback/send_action.go b/services/callback/send_action.go new file mode 100644 index 0000000..07b8fc5 --- /dev/null +++ b/services/callback/send_action.go @@ -0,0 +1,49 @@ +package callback + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +const OS_ANDROID = 2 + +const OS_IOS = 1 + +type SendActionRequest struct { + *requests.RpcRequest + GameId int64 `position:"Query" field:"game_id" default:"" ` + AgentId int64 `position:"Query" field:"agent_id" default:"" ` + SiteId int64 `position:"Query" field:"site_id" default:"" ` + Imei string `position:"Query" field:"imei" default:"" ` + Oaid string `position:"Query" field:"oaid" default:"" ` + Ip string `position:"Query" field:"ip" default:"" ` + Ua string `position:"Query" field:"ua" default:"" ` + Os int `position:"Query" field:"os" default:"" ` + ParamsArray []string +} + +type SendActionResponseData struct { + Account string `json:"account"` + Total int `json:"total"` +} + +type SendActionResponse struct { + *responses.BaseResponse + Data SendActionResponseData `json:"data"` +} + +func CreateSendActionRequest() (req *SendActionRequest) { + req = &SendActionRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/callback/ads_callback/sendAction") + req.Method = requests.GET + return +} + +func CreateSendActionResponse() (response *SendActionResponse) { + response = &SendActionResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/jedi/README.md b/services/jedi/README.md new file mode 100644 index 0000000..3f24bbd --- /dev/null +++ b/services/jedi/README.md @@ -0,0 +1,29 @@ + + +### 发送短信调用示例 +```go +import ( + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/services/jedi" +) + +func main() { + c, err := jedi.NewClientWithAccessKey("accessKeyId", "accessKeySecret", "xxx.xxx.com") + if err != nil { + return + } + + req := jedi.CreateSendSmsRequest() + // sso统一用户名uid, 多个用户用逗句隔开 + req.User = "liangzy,liaoks" + // 公共模板的代码模板 + req.Code = "d7kt5IwP" + // 模板参数,模板里有多少个模板参数就传入几个替换字符串, + req.ParamsArray = []string{"www", "线上", "好人"} + if resp, err := c.SendSms(req); err == nil { + grlogs.Informational(fmt.Sprintf("%+v", resp.GetHttpContentString())) + } else { + grlogs.Error(err) + } +} +``` \ No newline at end of file diff --git a/services/jedi/client.go b/services/jedi/client.go new file mode 100644 index 0000000..9906351 --- /dev/null +++ b/services/jedi/client.go @@ -0,0 +1,48 @@ +package jedi + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "strings" +) + +const ( + VERSION = "2020-09-24" +) + +var HOST requests.Host = requests.Host{ + Default: "jedi.api.gaore.com", + Func: func(s string) string { + var a = map[string]string{ + requests.RELEASE: "jedi.api.gaore.com", + requests.PRE: "jedi.api.gaore.com", + requests.TEST: "jedi.oapi.gaore.com", + } + return a[s] + }, +} + +type Client struct { + sdk.Client +} + +func (c *Client) SendSms(req *SendSmsRequest) (response *SendSmsResponse, err error) { + if req.ParamsArray != nil && len(req.ParamsArray) > 0 { + req.Params = strings.Join(req.ParamsArray, ",,,") + } + response = CreateSendSmsResponse() + err = c.DoAction(req, response) + return +} + +func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAccessKey(accesskey, secrect, source) + return +} + +func NewClientWithAliAppcode(accesskey, secrect string, env ...string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAliAppcode(accesskey, secrect, env...) + return +} diff --git a/services/jedi/send_sms.go b/services/jedi/send_sms.go new file mode 100644 index 0000000..d9c1c87 --- /dev/null +++ b/services/jedi/send_sms.go @@ -0,0 +1,40 @@ +package jedi + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type SendSmsRequest struct { + *requests.RpcRequest + User string `position:"Body" field:"user" default:"" ` + Code string `position:"Body" field:"code" default:"" ` + Params string `position:"Body" field:"params" default:"" ` + ParamsArray []string +} + +type SendSmsResponseData struct { + Account string `json:"account"` + Total int `json:"total"` +} + +type SendSmsResponse struct { + *responses.BaseResponse + Data SendSmsResponseData `json:"data"` +} + +func CreateSendSmsRequest() (req *SendSmsRequest) { + req = &SendSmsRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/sms/send") + req.Method = requests.POST + return +} + +func CreateSendSmsResponse() (response *SendSmsResponse) { + response = &SendSmsResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/mail/client.go b/services/mail/client.go new file mode 100644 index 0000000..7059b64 --- /dev/null +++ b/services/mail/client.go @@ -0,0 +1,50 @@ +package mail + +import ( + "crypto/md5" + "fmt" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "time" +) + +const ( + VERSION = "2021-09-27" +) + +var HOST requests.Host = requests.Host{ + Default: "mail.gaore.com", + Func: func(s string) string { + var a = map[string]string{ + requests.RELEASE: "mail.gaore.com", + requests.PRE: "mail.gaore.com", + requests.TEST: "mail.gaore.com", + } + return a[s] + }, +} + +type Client struct { + sdk.Client +} + +func NewClient() (client *Client) { + client = &Client{} + client.InitWithAccessKey("", "", "") + return +} + +func (c *Client) SendEmail(req *PostEmailRequest) (response *PostEmailResponse, err error) { + + now := time.Now().Second() + key := "04573fc4c8e01999a0909ab9c00bca5a" + signstr := fmt.Sprintf("%d%s", now, key) + data := []byte(signstr) + has := md5.Sum(data) + sign := fmt.Sprintf("%x", has) + req.Time = now + req.Sign = sign + response = CreatePostEmailResponse() + err = c.DoAction(req, response) + return +} diff --git a/services/mail/client_test.go b/services/mail/client_test.go new file mode 100644 index 0000000..e18fc11 --- /dev/null +++ b/services/mail/client_test.go @@ -0,0 +1,22 @@ +package mail + +import ( + "fmt" + "testing" + "time" +) + +func TestClient_GetUserInfo(t *testing.T) { + c := NewClient() + req := CreatePostEmailRequest() + req.Addresses = "3002467428@qq.com" + req.Body = "1111" + req.FromName = "213123121" + req.SetReadTimeout(60 * time.Second) + resp, err := c.SendEmail(req) + + fmt.Println(req) + fmt.Println(resp.GetHttpContentString()) + fmt.Println(err) + +} diff --git a/services/mail/end_email.go b/services/mail/end_email.go new file mode 100644 index 0000000..a45ad36 --- /dev/null +++ b/services/mail/end_email.go @@ -0,0 +1,36 @@ +package mail + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type PostEmailRequest struct { + *requests.RpcRequest + Addresses string `position:"Body" field:"addresses" default:"" ` + Subject string `position:"Body" field:"subject" default:"" ` + Body string `position:"Body" field:"body" default:""` + FromName string `position:"Body" field:"fromName" default:""` + Time int `position:"Body" field:"time" default:""` + Sign string `position:"Body" field:"sign" default:""` +} + +type PostEmailResponse struct { + *responses.BaseResponse +} + +func CreatePostEmailRequest() (req *PostEmailRequest) { + req = &PostEmailRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/email/post_email.php") + req.Method = requests.POST + return +} + +func CreatePostEmailResponse() (response *PostEmailResponse) { + response = &PostEmailResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/mkt/client.go b/services/mkt/client.go new file mode 100644 index 0000000..53023b7 --- /dev/null +++ b/services/mkt/client.go @@ -0,0 +1,31 @@ +package mkt + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" +) + +const ( + VERSION = "2020-11-16" +) + +var HOST = requests.Host{ + Default: "mkt", +} + +type Client struct { + sdk.Client +} + +// PkgNotice 打包通知 +func (c *Client) PkgNotice(req *PkgNoticeRequest) (response *PkgNoticeResponse, err error) { + response = CreatePkgNoticeResponse() + err = c.DoAction(req, response) + return +} + +func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAccessKey(accesskey, secrect, source) + return +} diff --git a/services/mkt/pkg_notice.go b/services/mkt/pkg_notice.go new file mode 100644 index 0000000..ac2f13c --- /dev/null +++ b/services/mkt/pkg_notice.go @@ -0,0 +1,36 @@ +package mkt + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +// PkgNoticeRequest 打包通知请求信息 +type PkgNoticeRequest struct { + *requests.RpcRequest + SiteID int64 `position:"Body" field:"site_id"` // 广告位ID + Status int `position:"Body" field:"status"` // 打包状态(0:失败 1:成功) +} + +// PkgNoticeResponse 打包通知响应信息 +type PkgNoticeResponse struct { + *responses.BaseResponse +} + +// CreatePkgNoticeRequest 创建通知接口 +func CreatePkgNoticeRequest() (req *PkgNoticeRequest) { + req = &PkgNoticeRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/game/pkgnotice") + req.Method = requests.POST + return +} + +// CreatePkgNoticeResponse 创建通知响应 +func CreatePkgNoticeResponse() (response *PkgNoticeResponse) { + response = &PkgNoticeResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/sso/client.go b/services/sso/client.go new file mode 100644 index 0000000..3e726fe --- /dev/null +++ b/services/sso/client.go @@ -0,0 +1,48 @@ +package sso + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" +) + +const ( + VERSION = "2020-08-07" +) + +var HOST = requests.Host{ + Default: "sso", +} + +type Client struct { + sdk.Client +} + +func (c *Client) CodeAuth(req *CodeAuthRequest) (response *CodeAuthResponse, err error) { + response = CreateCodeAuthResponse() + err = c.DoAction(req, response) + return +} + +func (c *Client) GetUserInfo(req *GetUserInfoRequest) (response *GetUserInfoResponse, err error) { + response = CreateGetUserInfoResponse() + err = c.DoAction(req, response) + return +} + +func (c *Client) RefreshToken(req *RefreshTokenRequest) (response *RefreshTokenResponse, err error) { + response = CreateRefreshTokenResponse() + err = c.DoAction(req, response) + return +} + +func (c *Client) SearchUser(req *SearchUserRequest) (response *SearchUserResponse, err error) { + response = CreateSearchUserResponse() + err = c.DoAction(req, response) + return +} + +func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAccessKey(accesskey, secrect, source) + return +} diff --git a/services/sso/code_auth.go b/services/sso/code_auth.go new file mode 100644 index 0000000..8080cb1 --- /dev/null +++ b/services/sso/code_auth.go @@ -0,0 +1,39 @@ +package sso + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type CodeAuthRequest struct { + *requests.RpcRequest + OauthCode string `position:"Body" field:"oauthCode" default:"" ` + Ident string `position:"Body" field:"ident" default:"" ` +} + +type CodeAuthResponseData struct { + RefreshToken string `json:"refreshToken"` + RefreshTokenExpires int64 `json:"refreshTokenExpires"` + Token string `json:"token"` + TokenExpires int64 `json:"tokenExpires"` + User User `json:"user"` +} + +type CodeAuthResponse struct { + *responses.BaseResponse + Data CodeAuthResponseData `json:"data"` +} + +func CreateCodeAuthRequest() (req *CodeAuthRequest) { + req = &CodeAuthRequest{RpcRequest: &requests.RpcRequest{}} + req.InitWithApiInfo(HOST, VERSION, "/api/userSess/codeAuth") + req.Method = requests.POST + return +} + +func CreateCodeAuthResponse() (response *CodeAuthResponse) { + response = &CodeAuthResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/sso/get_user.go b/services/sso/get_user.go new file mode 100644 index 0000000..e69183d --- /dev/null +++ b/services/sso/get_user.go @@ -0,0 +1,35 @@ +package sso + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type GetUserInfoRequest struct { + *requests.RpcRequest + Token string `position:"Body" field:"token" default:"" ` + Ident string `position:"Body" field:"ident" default:"" ` +} + +type GetUserInfoResponseData struct { + User User `json:"user"` +} + +type GetUserInfoResponse struct { + *responses.BaseResponse + Data GetUserInfoResponseData `json:"data"` +} + +func CreateGetUserInfoRequest() (req *GetUserInfoRequest) { + req = &GetUserInfoRequest{RpcRequest: &requests.RpcRequest{}} + req.InitWithApiInfo(HOST, VERSION, "/api/userSess/getUserInfo") + req.Method = requests.POST + return +} + +func CreateGetUserInfoResponse() (response *GetUserInfoResponse) { + response = &GetUserInfoResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/sso/refresh_token.go b/services/sso/refresh_token.go new file mode 100644 index 0000000..bfa0d5c --- /dev/null +++ b/services/sso/refresh_token.go @@ -0,0 +1,37 @@ +package sso + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type RefreshTokenRequest struct { + *requests.RpcRequest + RefreshToken string `position:"Body" field:"refreshToken" default:"" ` + Ident string `position:"Body" field:"ident" default:"" ` +} + +type RefreshTokenResponseData struct { + Token string `json:"token"` + TokenExpires int64 `json:"tokenExpires"` + User User `json:"user"` +} + +type RefreshTokenResponse struct { + *responses.BaseResponse + Data GetUserInfoResponseData `json:"data"` +} + +func CreateRefreshTokenRequest() (req *RefreshTokenRequest) { + req = &RefreshTokenRequest{RpcRequest: &requests.RpcRequest{}} + req.InitWithApiInfo(HOST, VERSION, "/api/userSess/refreshToken") + req.Method = requests.POST + return +} + +func CreateRefreshTokenResponse() (response *RefreshTokenResponse) { + response = &RefreshTokenResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/sso/search_user.go b/services/sso/search_user.go new file mode 100644 index 0000000..07450a1 --- /dev/null +++ b/services/sso/search_user.go @@ -0,0 +1,34 @@ +package sso + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type SearchUserRequest struct { + *requests.RpcRequest + Uid string `position:"Body" field:"uid" default:"" ` +} + +type SearchUserResponseData struct { + User User `json:"user"` +} + +type SearchUserResponse struct { + *responses.BaseResponse + Data SearchUserResponseData `json:"data"` +} + +func CreateSearchUserRequest() (req *SearchUserRequest) { + req = &SearchUserRequest{RpcRequest: &requests.RpcRequest{}} + req.InitWithApiInfo(HOST, VERSION, "/api/user/search") + req.Method = requests.POST + return +} + +func CreateSearchUserResponse() (response *SearchUserResponse) { + response = &SearchUserResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/sso/struct.go b/services/sso/struct.go new file mode 100644 index 0000000..2a493da --- /dev/null +++ b/services/sso/struct.go @@ -0,0 +1,27 @@ +package sso + +type User struct { + Uid string `json:"uid"` + UidNumber string `json:"uidNumber"` + Name string `json:"name"` + FirstName string `json:"firstname"` + LastName string `json:"lastname"` + RealName string `json:"realname"` + Mobile string `json:"mobile"` + Mail string `json:"mail"` + Department Department `json:"department"` + Roles []Role `json:"roles"` + Domains []string `json:"domains"` +} + +type Department struct { + Gid string `json:"gid"` + Name string `json:"name"` + Abbr string `json:"abbr"` +} + +type Role struct { + Name string `json:"name"` + Domains []string `json:"domains"` + Abbr string `json:"abbr"` +} diff --git a/services/www/client.go b/services/www/client.go new file mode 100644 index 0000000..51f6dfa --- /dev/null +++ b/services/www/client.go @@ -0,0 +1,44 @@ +package www + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" +) + +const ( + VERSION = "2020-09-24" +) + +var HOST requests.Host = requests.Host{ + Default: "apisdk.9ooo.cn", + Func: func(s string) string { + var a = map[string]string{ + requests.RELEASE: "apisdk.9ooo.cn", + requests.PRE: "apisdk.9ooo.cn", + requests.TEST: "apisdk.9ooo.cn", + } + return a[s] + }, +} + +type Client struct { + sdk.Client +} + +func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAccessKey(accesskey, secrect, source) + return +} + +func NewClientWithAliAppcode(accesskey, secrect string, env ...string) (client *Client, err error) { + client = &Client{} + err = client.InitWithAliAppcode(accesskey, secrect, env...) + return +} + +func (c *Client) GetUserInfo(req *GetPwdRequest) (response *GetPwdResponse, err error) { + response = CreateGetPwdResponse() + err = c.DoAction(req, response) + return +} diff --git a/services/www/client_test.go b/services/www/client_test.go new file mode 100644 index 0000000..7cc4864 --- /dev/null +++ b/services/www/client_test.go @@ -0,0 +1,25 @@ +package www + +import ( + "fmt" + "log" + "testing" +) + +func TestClient_GetUserInfo(t *testing.T) { + + c, err := NewClientWithAliAppcode("203874304", "9e5489a82dd641729186cdad166d81a3") + if err != nil { + t.Error(err) + } + + req := CreateGetPwdRequest() + req.UserName = "ttom666" + + resp, err := c.GetUserInfo(req) + if err != nil { + log.Fatalln(err) + } + fmt.Println(resp.GetHttpContentString()) + fmt.Println(resp.GetHttpHeaders()) +} diff --git a/services/www/get_pwd.go b/services/www/get_pwd.go new file mode 100644 index 0000000..b135f5b --- /dev/null +++ b/services/www/get_pwd.go @@ -0,0 +1,38 @@ +package www + +import ( + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" + "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" +) + +type GetPwdRequest struct { + *requests.RpcRequest + UserName string `position:"Query" field:"user_name" default:"-" ` + Uid int64 `position:"Query" field:"uid" default:"0"` +} + +type GetPwdResponse struct { + *responses.BaseResponse + Ret int `json:"ret"` + Msg string `json:"msg"` + Data struct { + UserName string `json:"user_name"` + UserPwd string `json:"user_pwd"` + } `json:"data"` +} + +func CreateGetPwdRequest() (req *GetPwdRequest) { + req = &GetPwdRequest{ + RpcRequest: &requests.RpcRequest{}, + } + req.InitWithApiInfo(HOST, VERSION, "/api/limit/getPwd.php") + req.Method = requests.GET + return +} + +func CreateGetPwdResponse() (response *GetPwdResponse) { + response = &GetPwdResponse{ + BaseResponse: &responses.BaseResponse{}, + } + return +} diff --git a/services/www/get_token.go b/services/www/get_token.go new file mode 100644 index 0000000..0da909b --- /dev/null +++ b/services/www/get_token.go @@ -0,0 +1 @@ +package www