-
Notifications
You must be signed in to change notification settings - Fork 0
<feature>[rest]: add go-sdk generator for zsv #3401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: zsv_5.0.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| // Copyright (c) ZStack.io, Inc. | ||
|
|
||
| package param | ||
|
|
||
| import "time" | ||
|
|
||
| var _ = time.Now // avoid unused import | ||
|
|
||
| type DeleteMode string | ||
|
|
||
| const ( | ||
| DeleteModePermissive DeleteMode = "Permissive" | ||
| DeleteModeEnforcing DeleteMode = "Enforcing" | ||
| ) | ||
|
|
||
| type BaseParam struct { | ||
| SystemTags []string `json:"systemTags,omitempty"` // System tags | ||
| UserTags []string `json:"userTags,omitempty"` // User tags | ||
| RequestIp string `json:"requestIp,omitempty"` // Request IP | ||
| } | ||
|
|
||
| type HqlParam struct { | ||
| OperationName string `json:"operationName"` // Request name | ||
| Query string `json:"query"` // Query statement | ||
| Variables Variables `json:"variables"` // Parameters for the statement | ||
| } | ||
|
|
||
| type Variables struct { | ||
| Conditions []Condition `json:"conditions"` // Conditions | ||
| ExtraConditions []Condition `json:"extraConditions"` // Extra conditions | ||
| Input map[string]interface{} `json:"input"` // Input parameters | ||
| PageVar `json:",inline,omitempty"` | ||
| Type string `json:"type"` // Type | ||
| } | ||
|
|
||
| type Condition struct { | ||
| Key string `json:"key"` // Key | ||
| Op string `json:"op"` // Operator | ||
| Value string `json:"value"` // Value | ||
| } | ||
|
|
||
| type PageVar struct { | ||
| Start int `json:"start,omitempty"` // Start page | ||
| Limit int `json:"limit,omitempty"` // Limit per page | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| // Copyright (c) ZStack.io, Inc. | ||
|
|
||
| package param | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "net/url" | ||
| "reflect" | ||
| "strings" | ||
|
|
||
| "github.com/fatih/structs" | ||
| ) | ||
|
|
||
| type QueryParam struct { | ||
| url.Values | ||
| } | ||
|
|
||
| func NewQueryParam() QueryParam { | ||
| return QueryParam{ | ||
| Values: make(url.Values), | ||
| } | ||
| } | ||
|
|
||
| // AddQ adds a query condition, similar to a MySQL database query. | ||
| // Omitting this field will return all records, with the number of returned records limited by the 'limit' field. | ||
| func (params *QueryParam) AddQ(q string) *QueryParam { | ||
| if params.Get("q") == "" { | ||
| params.Set("q", q) | ||
| } else { | ||
| params.Add("q", q) | ||
| } | ||
| return params | ||
| } | ||
|
|
||
| // Limit sets the maximum number of records to return, similar to MySQL's 'limit'. Default value is 1000. | ||
| func (params *QueryParam) Limit(limit int) *QueryParam { | ||
| params.Set("limit", fmt.Sprintf("%d", limit)) | ||
| return params | ||
| } | ||
|
|
||
| // Start sets the starting position for the query, similar to MySQL's 'offset'. Used with 'limit' for pagination. | ||
| func (params *QueryParam) Start(start int) *QueryParam { | ||
| params.Set("start", fmt.Sprintf("%d", start)) | ||
| return params | ||
| } | ||
|
|
||
| // Count sets the query to return the count of records that match the query conditions, similar to MySQL's 'count()' function. | ||
| func (params *QueryParam) Count(count bool) *QueryParam { | ||
| params.Set("count", fmt.Sprintf("%t", count)) | ||
| return params | ||
| } | ||
|
|
||
| // GroupBy groups the results by a specified field, similar to MySQL's 'group by' keyword. | ||
| func (params *QueryParam) GroupBy(groupBy string) *QueryParam { | ||
| params.Set("groupBy", groupBy) | ||
| return params | ||
| } | ||
|
|
||
| // ReplyWithCount, when set to true, includes the total count of records that match the query in the response. | ||
| func (params *QueryParam) ReplyWithCount(replyWithCount bool) *QueryParam { | ||
| params.Set("replyWithCount", fmt.Sprintf("%t", replyWithCount)) | ||
| return params | ||
| } | ||
|
|
||
| // FilterName sets a filter name, functionality is unknown from ZStack Java SDK (sdk-4.4.0.jar). | ||
| func (params *QueryParam) FilterName(filterName string) *QueryParam { | ||
| params.Set("filterName", filterName) | ||
| return params | ||
| } | ||
|
|
||
| // Sort sorts the results by a specified field, similar to MySQL's 'sort by' keyword. | ||
| // Use '+' for ascending order and '-' for descending order, followed by the field name. | ||
| func (params *QueryParam) Sort(sort string) *QueryParam { | ||
| params.Set("sort", sort) | ||
| return params | ||
| } | ||
|
|
||
| // Fields specifies the fields to return, similar to MySQL's 'select' fields functionality. | ||
| func (params *QueryParam) Fields(fields []string) *QueryParam { | ||
| params.Set("fields", strings.Join(fields, ",")) | ||
| return params | ||
| } | ||
|
|
||
| // ConvertStruct2UrlValues converts a struct to url.Values. | ||
| func ConvertStruct2UrlValues(param interface{}) (url.Values, error) { | ||
| if reflect.Ptr != reflect.TypeOf(param).Kind() { | ||
| return nil, errors.New("model should be pointer kind") | ||
| } | ||
| result := url.Values{} | ||
| if param == nil || reflect.ValueOf(param).IsNil() { | ||
| return nil, errors.New("param is nil") | ||
| } | ||
|
|
||
| s := structs.New(param) | ||
| s.TagName = "json" | ||
| mappedOpts := s.Map() | ||
| for k, v := range mappedOpts { | ||
| result.Set(k, fmt.Sprintf("%v", v)) | ||
| } | ||
| return result, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,232 @@ | ||||||||||||||||||||||||||||
| // Copyright (c) ZStack.io, Inc. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| package client | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||
| "crypto/sha512" | ||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||
| "net/http" | ||||||||||||||||||||||||||||
| "net/url" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| "github.com/kataras/golog" | ||||||||||||||||||||||||||||
| "github.com/terraform-zstack-modules/zsphere-sdk-go-v2/pkg/errors" | ||||||||||||||||||||||||||||
| "github.com/terraform-zstack-modules/zsphere-sdk-go-v2/pkg/param" | ||||||||||||||||||||||||||||
| "github.com/terraform-zstack-modules/zsphere-sdk-go-v2/pkg/view" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| type ZSClient struct { | ||||||||||||||||||||||||||||
| *ZSHttpClient | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func NewZSClient(config *ZSConfig) *ZSClient { | ||||||||||||||||||||||||||||
| return &ZSClient{ | ||||||||||||||||||||||||||||
| ZSHttpClient: NewZSHttpClient(config), | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) Login(ctx context.Context) (*view.SessionInventoryView, error) { | ||||||||||||||||||||||||||||
| if cli.authType != AuthTypeAccountUser && cli.authType != AuthTypeAccount { | ||||||||||||||||||||||||||||
| return nil, errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| var sessionView *view.SessionInventoryView | ||||||||||||||||||||||||||||
| var err error | ||||||||||||||||||||||||||||
| if cli.authType == AuthTypeAccountUser { | ||||||||||||||||||||||||||||
| sessionView, err = cli.logInByAccountUser(ctx) | ||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||
| sessionView, err = cli.logInByAccount(ctx) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| golog.Errorf("ZSClient.Login error:%v", err) | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cli.LoadSession(sessionView.Uuid) | ||||||||||||||||||||||||||||
| return sessionView, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) logInByAccountUser(ctx context.Context) (*view.SessionInventoryView, error) { | ||||||||||||||||||||||||||||
| if cli.authType != AuthTypeAccountUser { | ||||||||||||||||||||||||||||
| return nil, errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if len(cli.accountName) == 0 || len(cli.accountUserName) == 0 || len(cli.password) == 0 { | ||||||||||||||||||||||||||||
| return nil, errors.ErrParameter | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| params := param.LogInByUserParam{ | ||||||||||||||||||||||||||||
| LogInByUser: param.LogInByUserDetailParam{ | ||||||||||||||||||||||||||||
| AccountName: cli.accountName, | ||||||||||||||||||||||||||||
| UserName: cli.accountUserName, | ||||||||||||||||||||||||||||
| Password: fmt.Sprintf("%x", sha512.Sum512([]byte(cli.password))), | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| sessionView := view.SessionInventoryView{} | ||||||||||||||||||||||||||||
| err := cli.Put(ctx, "v1/accounts/users/login", "", params, &sessionView) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| golog.Errorf("ZSClient.logInByAccountUser Account[%s] User[%s] error:%v", | ||||||||||||||||||||||||||||
| cli.accountName, cli.accountUserName, err) | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return &sessionView, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) logInByAccount(ctx context.Context) (*view.SessionInventoryView, error) { | ||||||||||||||||||||||||||||
| if cli.authType != AuthTypeAccount { | ||||||||||||||||||||||||||||
| return nil, errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if len(cli.accountName) == 0 || len(cli.password) == 0 { | ||||||||||||||||||||||||||||
| return nil, errors.ErrParameter | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| params := param.LoginByAccountParam{ | ||||||||||||||||||||||||||||
| LoginByAccount: param.LoginByAccountDetailParam{ | ||||||||||||||||||||||||||||
| AccountName: cli.accountName, | ||||||||||||||||||||||||||||
| Password: fmt.Sprintf("%x", sha512.Sum512([]byte(cli.password))), | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| sessionView := view.SessionInventoryView{} | ||||||||||||||||||||||||||||
| err := cli.Put(ctx, "v1/accounts/login", "", params, &sessionView) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| golog.Errorf("ZSClient.logInByAccount Account[%s] error:%v", cli.accountName, err) | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return &sessionView, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) ValidateSession(ctx context.Context) (map[string]bool, error) { | ||||||||||||||||||||||||||||
| if cli.authType != AuthTypeAccountUser && cli.authType != AuthTypeAccount { | ||||||||||||||||||||||||||||
| return nil, errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if len(cli.sessionId) == 0 { | ||||||||||||||||||||||||||||
| return nil, errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return cli.ValidateSessionId(ctx, cli.sessionId) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) ValidateSessionId(ctx context.Context, sessionId string) (map[string]bool, error) { | ||||||||||||||||||||||||||||
| validSession := make(map[string]bool) | ||||||||||||||||||||||||||||
| err := cli.GetWithSpec(ctx, "v1/accounts/sessions", sessionId, "valid", "", nil, &validSession) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| golog.Errorf("ZSClient.ValidateSession sessionId[%s] error:%v", sessionId, err) | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| golog.Debugf("ZSClient.ValidateSession sessionId[%s]:%v", sessionId, validSession) | ||||||||||||||||||||||||||||
| return validSession, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) Logout(ctx context.Context) error { | ||||||||||||||||||||||||||||
| if cli.authType != AuthTypeAccountUser && cli.authType != AuthTypeAccount { | ||||||||||||||||||||||||||||
| return errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if len(cli.sessionId) == 0 { | ||||||||||||||||||||||||||||
| return errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| err := cli.Delete(ctx, "v1/accounts/sessions", cli.sessionId, "") | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| golog.Errorf("ZSClient.Logout sessionId[%s] error:%v", cli.sessionId, err) | ||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cli.unloadSession() | ||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) WebLogin(ctx context.Context) (*view.WebUISessionView, error) { | ||||||||||||||||||||||||||||
| if cli.authType != AuthTypeAccountUser && cli.authType != AuthTypeAccount { | ||||||||||||||||||||||||||||
| return nil, errors.ErrNotSupported | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| var operationName, username, loginType, query string | ||||||||||||||||||||||||||||
| var input map[string]interface{} | ||||||||||||||||||||||||||||
| if cli.authType == AuthTypeAccount { | ||||||||||||||||||||||||||||
| operationName, username, loginType = "loginByAccount", cli.accountName, "iam1" | ||||||||||||||||||||||||||||
| input = map[string]interface{}{ | ||||||||||||||||||||||||||||
| "accountName": cli.accountName, | ||||||||||||||||||||||||||||
| "password": fmt.Sprintf("%x", sha512.Sum512([]byte(cli.password))), | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| query = `mutation loginByAccount($input:LoginByAccountInput!) { | ||||||||||||||||||||||||||||
| loginByAccount(input: $input) { | ||||||||||||||||||||||||||||
| sessionId, | ||||||||||||||||||||||||||||
| accountUuid, | ||||||||||||||||||||||||||||
| userUuid, | ||||||||||||||||||||||||||||
| currentIdentity | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }` | ||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||
| operationName, username, loginType = "loginIAM2VirtualID", cli.accountUserName, "iam2" | ||||||||||||||||||||||||||||
| input = map[string]interface{}{ | ||||||||||||||||||||||||||||
| "name": cli.accountUserName, | ||||||||||||||||||||||||||||
| "password": fmt.Sprintf("%x", sha512.Sum512([]byte(cli.password))), | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| query = `mutation loginIAM2VirtualID($input:LoginIAM2VirtualIDInput!) { | ||||||||||||||||||||||||||||
| loginIAM2VirtualID(input: $input) { | ||||||||||||||||||||||||||||
| sessionId, | ||||||||||||||||||||||||||||
| accountUuid, | ||||||||||||||||||||||||||||
| userUuid, | ||||||||||||||||||||||||||||
| currentIdentity | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }` | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| result := new(view.WebUISessionView) | ||||||||||||||||||||||||||||
| params := param.HqlParam{ | ||||||||||||||||||||||||||||
| OperationName: operationName, | ||||||||||||||||||||||||||||
| Query: query, | ||||||||||||||||||||||||||||
| Variables: param.Variables{ | ||||||||||||||||||||||||||||
| Input: input, | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| respHeader, err := cli.hql(ctx, params, result, responseKeyData, operationName) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| result.UserName = username | ||||||||||||||||||||||||||||
| result.LoginType = loginType | ||||||||||||||||||||||||||||
| result.ZSVersion = respHeader.Get("Zs-Version") | ||||||||||||||||||||||||||||
| return result, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) hql(ctx context.Context, params param.HqlParam, retVal interface{}, unMarshalKeys ...string) (http.Header, error) { | ||||||||||||||||||||||||||||
| urlStr := fmt.Sprintf("http://%s:%d/graphql", cli.hostname, WebZStackPort) | ||||||||||||||||||||||||||||
| _, respHeader, resp, err := cli.httpPost(ctx, urlStr, jsonMarshal(params), false) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if retVal == nil { | ||||||||||||||||||||||||||||
| return nil, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return respHeader, resp.Unmarshal(retVal, unMarshalKeys...) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+206
to
+212
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
当 if retVal == nil {
- return nil, nil
+ return respHeader, nil
}同样的问题也存在于第 223-225 行的 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func (cli *ZSClient) Zql(ctx context.Context, querySt string, retVal interface{}, unMarshalKeys ...string) (http.Header, error) { | ||||||||||||||||||||||||||||
| encodedQuery := url.QueryEscape(querySt) | ||||||||||||||||||||||||||||
| baseUrl := cli.getRequestURL("v1/zql") | ||||||||||||||||||||||||||||
| urlStr := fmt.Sprintf("%s?zql=%s", baseUrl, encodedQuery) | ||||||||||||||||||||||||||||
| _, respHeader, resp, err := cli.httpGet(ctx, urlStr, false) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if retVal == nil { | ||||||||||||||||||||||||||||
| return nil, nil | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return respHeader, resp.Unmarshal(retVal, unMarshalKeys...) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const ( | ||||||||||||||||||||||||||||
| AuthTypeLogin AuthType = "login" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: MatheMatrix/zstack
Length of output: 232
🏁 Script executed:
Repository: MatheMatrix/zstack
Length of output: 127
🏁 Script executed:
Repository: MatheMatrix/zstack
Length of output: 603
🏁 Script executed:
Repository: MatheMatrix/zstack
Length of output: 556
ConvertStruct2UrlValues在param == nil时会 panic第 87 行在判空之前调用
reflect.TypeOf(param).Kind()会导致异常。当param == nil时,reflect.TypeOf(nil)返回 nil,对 nil 调用.Kind()会触发 panic。需要先判空再进行反射操作,同时补充对指向 struct 的指针的验证。建议修复
func ConvertStruct2UrlValues(param interface{}) (url.Values, error) { - if reflect.Ptr != reflect.TypeOf(param).Kind() { - return nil, errors.New("model should be pointer kind") - } - result := url.Values{} - if param == nil || reflect.ValueOf(param).IsNil() { + if param == nil { return nil, errors.New("param is nil") } + t := reflect.TypeOf(param) + v := reflect.ValueOf(param) + if t.Kind() != reflect.Ptr || v.IsNil() { + return nil, errors.New("param should be a non-nil pointer") + } + if t.Elem().Kind() != reflect.Struct { + return nil, errors.New("param should point to a struct") + } + result := url.Values{} s := structs.New(param)📝 Committable suggestion
🤖 Prompt for AI Agents