diff --git a/go.mod b/go.mod index 9bda4bffe..942a9326f 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/google/uuid v1.1.2-0.20190416172445-c2e93f3ae59f github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 github.com/hashicorp/vault/api v1.0.4 - github.com/hexonet/go-sdk v1.2.1 + github.com/hexonet/go-sdk v2.2.3+incompatible github.com/jarcoal/httpmock v1.0.4 // indirect github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29 // indirect github.com/kr/pretty v0.1.0 // indirect diff --git a/go.sum b/go.sum index 3877ba6e4..c030e6485 100644 --- a/go.sum +++ b/go.sum @@ -149,8 +149,8 @@ github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0 github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hexonet/go-sdk v1.2.1 h1:UpoeqZQt2y2pypiQOW/+uBUk6DfyEnOzwJaW2LIerVQ= -github.com/hexonet/go-sdk v1.2.1/go.mod h1:B0oC4YZT3P2o0DHTm5SH0WCItW3N+r16nCTOykJZF1c= +github.com/hexonet/go-sdk v2.2.3+incompatible h1:V4FVWC11TXdUtxakyhnr6+ttf1e9ah9AQzZsP4u4R24= +github.com/hexonet/go-sdk v2.2.3+incompatible/go.mod h1:B0oC4YZT3P2o0DHTm5SH0WCItW3N+r16nCTOykJZF1c= github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index d38c50483..85948aebc 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -457,7 +457,7 @@ func makeTests(t *testing.T) []*TestCase { tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")), tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")), ) - if *providerToRun == "NAMEDOTCOM" { + if *providerToRun == "NAMEDOTCOM" || *providerToRun == "HEXONET" { t.Log("Skipping SRV Null Target test because provider does not support them") } else { tests = append(tests, tc("Null Target", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "."))) diff --git a/providers/hexonet/domains.go b/providers/hexonet/domains.go index 23f841cad..3bd133730 100644 --- a/providers/hexonet/domains.go +++ b/providers/hexonet/domains.go @@ -8,7 +8,7 @@ func (n *HXClient) EnsureDomainExists(domain string) error { "COMMAND": "StatusDNSZone", "DNSZONE": domain + ".", }) - code := r.Code() + code := r.GetCode() if code == 545 { r = n.client.Request(map[string]string{ "COMMAND": "CreateDNSZone", diff --git a/providers/hexonet/error.go b/providers/hexonet/error.go index a7d4ed3d2..9ec73598e 100644 --- a/providers/hexonet/error.go +++ b/providers/hexonet/error.go @@ -3,10 +3,10 @@ package hexonet import ( "fmt" - lr "github.com/hexonet/go-sdk/response/listresponse" + "github.com/hexonet/go-sdk/response" ) // GetHXApiError returns an error including API error code and error description. -func (n *HXClient) GetHXApiError(format string, objectid string, r *lr.ListResponse) error { - return fmt.Errorf(format+" %s. [%s %s]", objectid, r.Code(), r.Description()) +func (n *HXClient) GetHXApiError(format string, objectid string, r *response.Response) error { + return fmt.Errorf(format+" %s. [%s %s]", objectid, r.GetCode(), r.GetDescription()) } diff --git a/providers/hexonet/hexonetProvider.go b/providers/hexonet/hexonetProvider.go index 3cb530f5d..7dbbba5a8 100644 --- a/providers/hexonet/hexonetProvider.go +++ b/providers/hexonet/hexonetProvider.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/StackExchange/dnscontrol/v2/providers" - hxcl "github.com/hexonet/go-sdk/client" + hxcl "github.com/hexonet/go-sdk/apiclient" ) // HXClient describes a connection to the hexonet API. @@ -14,7 +14,7 @@ type HXClient struct { APILogin string APIPassword string APIEntity string - client *hxcl.Client + client *hxcl.APIClient } var features = providers.DocumentationNotes{ @@ -34,14 +34,14 @@ var features = providers.DocumentationNotes{ func newProvider(conf map[string]string) (*HXClient, error) { api := &HXClient{ - client: hxcl.NewClient(), + client: hxcl.NewAPIClient(), } api.APILogin, api.APIPassword, api.APIEntity = conf["apilogin"], conf["apipassword"], conf["apientity"] if conf["debugmode"] == "1" { api.client.EnableDebugMode() } if len(conf["ipaddress"]) > 0 { - api.client.SetIPAddress(conf["ipaddress"]) + api.client.SetRemoteIPAddress(conf["ipaddress"]) } if api.APIEntity != "OTE" && api.APIEntity != "LIVE" { return nil, fmt.Errorf("wrong api system entity used. use \"OTE\" for OT&E system or \"LIVE\" for Live system") @@ -52,7 +52,7 @@ func newProvider(conf map[string]string) (*HXClient, error) { if api.APILogin == "" || api.APIPassword == "" { return nil, fmt.Errorf("missing login credentials apilogin or apipassword") } - api.client.SetCredentials(api.APILogin, api.APIPassword, "") + api.client.SetCredentials(api.APILogin, api.APIPassword) return api, nil } diff --git a/providers/hexonet/nameservers.go b/providers/hexonet/nameservers.go index e2a14325a..c34fc4550 100644 --- a/providers/hexonet/nameservers.go +++ b/providers/hexonet/nameservers.go @@ -45,11 +45,15 @@ func (n *HXClient) getNameserversRaw(domain string) ([]string, error) { "COMMAND": "StatusDomain", "DOMAIN": domain, }) - code := r.Code() + code := r.GetCode() if code != 200 { return nil, n.GetHXApiError("Could not get status for domain", domain, r) } - ns := r.GetColumn("NAMESERVER") + nsColumn := r.GetColumn("NAMESERVER") + if nsColumn == nil { + return nil, fmt.Errorf("Error getting NAMESERVER column for domain: %s", domain) + } + ns := nsColumn.GetData() sort.Strings(ns) return ns, nil } @@ -91,9 +95,9 @@ func (n *HXClient) updateNameservers(ns []string, domain string) func() error { cmd[fmt.Sprintf("NAMESERVER%d", idx)] = ns } response := n.client.Request(cmd) - code := response.Code() + code := response.GetCode() if code != 200 { - return fmt.Errorf(fmt.Sprintf("%d %s", code, response.Description())) + return fmt.Errorf("%d %s", code, response.GetDescription()) } return nil } diff --git a/providers/hexonet/records.go b/providers/hexonet/records.go index ed3c21870..1b38ec0f3 100644 --- a/providers/hexonet/records.go +++ b/providers/hexonet/records.go @@ -80,7 +80,11 @@ func (n *HXClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corr changes = true fmt.Fprintln(buf, cre) rec := cre.Desired - params[fmt.Sprintf("ADDRR%d", addrridx)] = n.createRecordString(rec, dc.Name) + recordString, err := n.createRecordString(rec, dc.Name) + if err != nil { + return corrections, err + } + params[fmt.Sprintf("ADDRR%d", addrridx)] = recordString addrridx++ } for _, d := range del { @@ -96,7 +100,11 @@ func (n *HXClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corr old := chng.Existing.Original.(*HXRecord) new := chng.Desired params[fmt.Sprintf("DELRR%d", delrridx)] = n.deleteRecordString(old, dc.Name) - params[fmt.Sprintf("ADDRR%d", addrridx)] = n.createRecordString(new, dc.Name) + newRecordString, err := n.createRecordString(new, dc.Name) + if err != nil { + return corrections, err + } + params[fmt.Sprintf("ADDRR%d", addrridx)] = newRecordString addrridx++ delrridx++ } @@ -178,12 +186,16 @@ func (n *HXClient) getRecords(domain string) ([]*HXRecord, error) { } r := n.client.Request(cmd) if !r.IsSuccess() { - if r.Code() == 545 { + if r.GetCode() == 545 { return nil, n.GetHXApiError("Use `dnscontrol create-domains` to create not-existing zone", domain, r) } return nil, n.GetHXApiError("Failed loading resource records for zone", domain, r) } - rrs := r.GetColumn("RR") + rrColumn := r.GetColumn("RR") + if rrColumn == nil { + return nil, fmt.Errorf("Error getting RR column for domain: %s", domain) + } + rrs := rrColumn.GetData() for _, rr := range rrs { spl := strings.Split(rr, " ") if spl[3] != "SOA" { @@ -212,7 +224,7 @@ func (n *HXClient) getRecords(domain string) ([]*HXRecord, error) { return records, nil } -func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) string { +func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (string, error) { record := &HXRecord{ DomainName: domain, Host: rc.GetLabel(), @@ -231,10 +243,13 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) st case "TXT": record.Answer = encodeTxt(rc.TxtStrings) case "SRV": + if rc.GetTargetField() == "." { + return "", fmt.Errorf("SRV records with empty targets are not supported (as of 2020-02-27, the API returns 'Invalid attribute value syntax')") + } record.Answer = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, record.Answer) record.Priority = uint32(rc.SrvPriority) default: - panic(fmt.Sprintf("createRecord rtype %v unimplemented", rc.Type)) + panic(fmt.Sprintf("createRecordString rtype %v unimplemented", rc.Type)) // We panic so that we quickly find any switch statements // that have not been updated for a new RR type. } @@ -244,7 +259,7 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) st str += fmt.Sprint(record.Priority) + " " } str += record.Answer - return str + return str, nil } func (n *HXClient) deleteRecordString(record *HXRecord, domain string) string { diff --git a/vendor/github.com/hexonet/go-sdk/apiclient/apiclient.go b/vendor/github.com/hexonet/go-sdk/apiclient/apiclient.go new file mode 100644 index 000000000..122192179 --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/apiclient/apiclient.go @@ -0,0 +1,404 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package apiclient contains all you need to communicate with the insanely fast HEXONET backend API. +package apiclient + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "runtime" + "sort" + "strings" + "time" + + R "github.com/hexonet/go-sdk/response" + RTM "github.com/hexonet/go-sdk/responsetemplatemanager" + SC "github.com/hexonet/go-sdk/socketconfig" +) + +var rtm = RTM.GetInstance() + +// APIClient is the entry point class for communicating with the insanely fast HEXONET backend api. +// It allows two ways of communication: +// * session based communication +// * sessionless communication +// +// A session based communication makes sense in case you use it to +// build your own frontend on top. It allows also to use 2FA +// (2 Factor Auth) by providing "otp" in the config parameter of +// the login method. +// A sessionless communication makes sense in case you do not need +// to care about the above and you have just to request some commands. +// +// Possible commands can be found at https://github.com/hexonet/hexonet-api-documentation/tree/master/API +type APIClient struct { + socketTimeout time.Duration + socketURL string + socketConfig *SC.SocketConfig + debugMode bool + ua string +} + +// NewAPIClient represents the constructor for struct APIClient. +func NewAPIClient() *APIClient { + cl := &APIClient{ + debugMode: false, + socketTimeout: 300 * time.Second, + socketURL: "https://api.ispapi.net/api/call.cgi", + socketConfig: SC.NewSocketConfig(), + ua: "", + } + cl.UseLIVESystem() + return cl +} + +// EnableDebugMode method to enable Debug Output to logger +func (cl *APIClient) EnableDebugMode() *APIClient { + cl.debugMode = true + return cl +} + +// DisableDebugMode method to disable Debug Output to logger +func (cl *APIClient) DisableDebugMode() *APIClient { + cl.debugMode = false + return cl +} + +// GetPOSTData method to Serialize given command for POST request +// including connection configuration data +func (cl *APIClient) GetPOSTData(cmd map[string]string) string { + data := cl.socketConfig.GetPOSTData() + var tmp strings.Builder + keys := []string{} + for key := range cmd { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + val := cmd[key] + tmp.WriteString(key) + tmp.WriteString("=") + val = strings.Replace(val, "\r", "", -1) + val = strings.Replace(val, "\n", "", -1) + tmp.WriteString(val) + tmp.WriteString("\n") + } + str := tmp.String() + str = str[:len(str)-1] //remove \n at end + return strings.Join([]string{ + data, + url.QueryEscape("s_command"), + "=", + url.QueryEscape(str), + }, "") +} + +// GetSession method to get the API Session that is currently set +func (cl *APIClient) GetSession() (string, error) { + sessid := cl.socketConfig.GetSession() + if len(sessid) == 0 { + return "", errors.New("Could not find an active session") + } + return sessid, nil +} + +// GetURL method to get the API connection url that is currently set +func (cl *APIClient) GetURL() string { + return cl.socketURL +} + +// SetUserAgent method to customize user-agent header (useful for tools that use our SDK) +func (cl *APIClient) SetUserAgent(str string, rv string) *APIClient { + cl.ua = str + " (" + runtime.GOOS + "; " + runtime.GOARCH + "; rv:" + rv + ") go-sdk/" + cl.GetVersion() + " go/" + runtime.Version() + return cl +} + +// GetUserAgent method to return the user agent string +func (cl *APIClient) GetUserAgent() string { + if len(cl.ua) == 0 { + cl.ua = "GO-SDK (" + runtime.GOOS + "; " + runtime.GOARCH + "; rv:" + cl.GetVersion() + ") go/" + runtime.Version() + } + return cl.ua +} + +// GetVersion method to get current module version +func (cl *APIClient) GetVersion() string { + return "2.2.3" +} + +// SaveSession method to apply data to a session for later reuse +// Please save/update that map into user session +func (cl *APIClient) SaveSession(sessionobj map[string]interface{}) *APIClient { + sessionobj["socketcfg"] = map[string]string{ + "entity": cl.socketConfig.GetSystemEntity(), + "session": cl.socketConfig.GetSession(), + } + return cl +} + +// ReuseSession method to reuse given configuration out of a user session +// to rebuild and reuse connection settings +func (cl *APIClient) ReuseSession(sessionobj map[string]interface{}) *APIClient { + cfg := sessionobj["socketcfg"].(map[string]string) + cl.socketConfig.SetSystemEntity(cfg["entity"]) + cl.SetSession(cfg["session"]) + return cl +} + +// SetURL method to set another connection url to be used for API communication +func (cl *APIClient) SetURL(value string) *APIClient { + cl.socketURL = value + return cl +} + +// SetOTP method to set one time password to be used for API communication +func (cl *APIClient) SetOTP(value string) *APIClient { + cl.socketConfig.SetOTP(value) + return cl +} + +// SetSession method to set an API session id to be used for API communication +func (cl *APIClient) SetSession(value string) *APIClient { + cl.socketConfig.SetSession(value) + return cl +} + +// SetRemoteIPAddress method to set an Remote IP Address to be used for API communication +func (cl *APIClient) SetRemoteIPAddress(value string) *APIClient { + cl.socketConfig.SetRemoteAddress(value) + return cl +} + +// SetCredentials method to set Credentials to be used for API communication +func (cl *APIClient) SetCredentials(uid string, pw string) *APIClient { + cl.socketConfig.SetLogin(uid) + cl.socketConfig.SetPassword(pw) + return cl +} + +// SetRoleCredentials method to set Role User Credentials to be used for API communication +func (cl *APIClient) SetRoleCredentials(uid string, role string, pw string) *APIClient { + if len(role) > 0 { + return cl.SetCredentials(uid+"!"+role, pw) + } + return cl.SetCredentials(uid, pw) +} + +// Login method to perform API login to start session-based communication +// 1st parameter: one time password +func (cl *APIClient) Login(params ...string) *R.Response { + otp := "" + if len(params) > 0 { + otp = params[0] + } + cl.SetOTP(otp) + rr := cl.Request(map[string]string{"COMMAND": "StartSession"}) + if rr.IsSuccess() { + col := rr.GetColumn("SESSION") + if col != nil { + cl.SetSession(col.GetData()[0]) + } else { + cl.SetSession("") + } + } + return rr +} + +// LoginExtended method to perform API login to start session-based communication. +// 1st parameter: map of additional command parameters +// 2nd parameter: one time password +func (cl *APIClient) LoginExtended(params ...interface{}) *R.Response { + otp := "" + parameters := map[string]string{} + if len(params) == 2 { + otp = params[1].(string) + } + cl.SetOTP(otp) + if len(params) > 0 { + parameters = params[0].(map[string]string) + } + cmd := map[string]string{ + "COMMAND": "StartSession", + } + for k, v := range parameters { + cmd[k] = v + } + rr := cl.Request(cmd) + if rr.IsSuccess() { + col := rr.GetColumn("SESSION") + if col != nil { + cl.SetSession(col.GetData()[0]) + } else { + cl.SetSession("") + } + } + return rr +} + +// Logout method to perform API logout to close API session in use +func (cl *APIClient) Logout() *R.Response { + rr := cl.Request(map[string]string{ + "COMMAND": "EndSession", + }) + if rr.IsSuccess() { + cl.SetSession("") + } + return rr +} + +// Request method to perform API request using the given command +func (cl *APIClient) Request(cmd map[string]string) *R.Response { + data := cl.GetPOSTData(cmd) + + client := &http.Client{ + Timeout: cl.socketTimeout, + } + req, err := http.NewRequest("POST", cl.socketURL, strings.NewReader(data)) + if err != nil { + tpl := rtm.GetTemplate("httperror").GetPlain() + r := R.NewResponse(tpl, cmd) + if cl.debugMode { + j, _ := json.Marshal(cmd) + fmt.Printf("%s\n", j) + fmt.Println("POST: " + data) + fmt.Println("HTTP communication failed: " + err.Error()) + fmt.Println(r.GetPlain()) + } + return r + } + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Expect", "") + req.Header.Add("User-Agent", cl.GetUserAgent()) + resp, err2 := client.Do(req) + if err2 != nil { + tpl := rtm.GetTemplate("httperror").GetPlain() + r := R.NewResponse(tpl, cmd) + if cl.debugMode { + j, _ := json.Marshal(cmd) + fmt.Printf("%s\n", j) + fmt.Println("POST: " + data) + fmt.Println("HTTP communication failed: " + err2.Error()) + fmt.Println(r.GetPlain()) + } + return r + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusOK { + response, err := ioutil.ReadAll(resp.Body) + if err != nil { + tpl := rtm.GetTemplate("httperror").GetPlain() + r := R.NewResponse(tpl, cmd) + if cl.debugMode { + j, _ := json.Marshal(cmd) + fmt.Printf("%s\n", j) + fmt.Println("POST: " + data) + fmt.Println("HTTP communication failed: " + err.Error()) + fmt.Println(r.GetPlain()) + } + return r + } + r := R.NewResponse(string(response), cmd) + if cl.debugMode { + j, _ := json.Marshal(cmd) + fmt.Printf("%s\n", j) + fmt.Println("POST: " + data) + fmt.Println(r.GetPlain()) + } + return r + } + tpl := rtm.GetTemplate("httperror").GetPlain() + r := R.NewResponse(tpl, cmd) + if cl.debugMode { + j, _ := json.Marshal(cmd) + fmt.Printf("%s\n", j) + fmt.Println("POST: " + data) + fmt.Println(r.GetPlain()) + } + return r +} + +// RequestNextResponsePage method to request the next page of list entries for the current list query +// Useful for lists +func (cl *APIClient) RequestNextResponsePage(rr *R.Response) (*R.Response, error) { + mycmd := cl.toUpperCaseKeys(rr.GetCommand()) + if _, ok := mycmd["LAST"]; ok { + return nil, errors.New("Parameter LAST in use. Please remove it to avoid issues in requestNextPage") + } + first := 0 + if v, ok := mycmd["FIRST"]; ok { + first, _ = fmt.Sscan("%s", v) + } + total := rr.GetRecordsTotalCount() + limit := rr.GetRecordsLimitation() + first += limit + if first < total { + mycmd["FIRST"] = fmt.Sprintf("%d", first) + mycmd["LIMIT"] = fmt.Sprintf("%d", limit) + return cl.Request(mycmd), nil + } + return nil, errors.New("Could not find further existing pages") +} + +// RequestAllResponsePages method to request all pages/entries for the given query command +// Use this method with caution as it requests all list data until done. +func (cl *APIClient) RequestAllResponsePages(cmd map[string]string) []R.Response { + var err error + responses := []R.Response{} + mycmd := map[string]string{ + "FIRST": "0", + } + for k, v := range cmd { + mycmd[k] = v + } + rr := cl.Request(mycmd) + tmp := rr + for { + responses = append(responses, *tmp) + tmp, err = cl.RequestNextResponsePage(tmp) + if err != nil { + break + } + } + return responses +} + +// SetUserView method to set a data view to a given subuser +func (cl *APIClient) SetUserView(uid string) *APIClient { + cl.socketConfig.SetUser(uid) + return cl +} + +// ResetUserView method to reset data view back from subuser to user +func (cl *APIClient) ResetUserView() *APIClient { + cl.socketConfig.SetUser("") + return cl +} + +// UseOTESystem method to set OT&E System for API communication +func (cl *APIClient) UseOTESystem() *APIClient { + cl.socketConfig.SetSystemEntity("1234") + return cl +} + +// UseLIVESystem method to set LIVE System for API communication +// Usage of LIVE System is active by default. +func (cl *APIClient) UseLIVESystem() *APIClient { + cl.socketConfig.SetSystemEntity("54cd") + return cl +} + +// toUpperCaseKeys method to translate all command parameter names to uppercase +func (cl *APIClient) toUpperCaseKeys(cmd map[string]string) map[string]string { + newcmd := map[string]string{} + for k, v := range cmd { + newcmd[strings.ToUpper(k)] = v + } + return newcmd +} diff --git a/vendor/github.com/hexonet/go-sdk/client/client.go b/vendor/github.com/hexonet/go-sdk/client/client.go deleted file mode 100644 index 35fa73a83..000000000 --- a/vendor/github.com/hexonet/go-sdk/client/client.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (c) 2018 Kai Schwarz (1API GmbH). All rights reserved. -// -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE.md file. - -// Package client contains all you need to communicate with the insanely fast 1API backend API. -package client - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "regexp" - "strconv" - "strings" - - "github.com/hexonet/go-sdk/client/socketcfg" - "github.com/hexonet/go-sdk/response/hashresponse" - "github.com/hexonet/go-sdk/response/listresponse" -) - -// Client is the entry point class for communicating with the insanely fast 1API backend api. -// It allows two ways of communication: -// * session based communication -// * sessionless communication -// -// A session based communication makes sense in case you use it to -// build your own frontend on top. It allows also to use 2FA -// (2 Factor Auth) by providing "otp" in the config parameter of -// the login method. -// A sessionless communication makes sense in case you do not need -// to care about the above and you have just to request some commands. -// -// Possible commands can be found at https://github.com/hexonet/hexonet-api-documentation/tree/master/API -type Client struct { - debugMode bool - socketTimeout int - apiurl string - socketcfg.Socketcfg -} - -// NewClient represents the constructor for struct Client. -// The client is by default set to communicate with the LIVE system. Use method UseOTESystem to switch to the OT&E system instance. -func NewClient() *Client { - cl := &Client{ - debugMode: false, - socketTimeout: 300000, - apiurl: "https://coreapi.1api.net/api/call.cgi", - Socketcfg: socketcfg.Socketcfg{}, - } - cl.UseLiveSystem() - return cl -} - -// EncodeData method to use to encode provided data (socket configuration and api command) before sending it to the API server -// It returns the encoded data ready to use within POST request of type "application/x-www-form-urlencoded" -func (c *Client) EncodeData(cfg *socketcfg.Socketcfg, cmd map[string]string) string { - var tmp, data strings.Builder - tmp.WriteString(cfg.EncodeData()) - tmp.WriteString(url.QueryEscape("s_command")) - tmp.WriteString("=") - - for k, v := range cmd { - re := regexp.MustCompile(`\r?\n`) - v = re.ReplaceAllString(v, "") - if len(v) > 0 { - data.WriteString(k) - data.WriteString("=") - data.WriteString(v) - data.WriteString("\n") - } - } - tmp.WriteString(url.QueryEscape(data.String())) - return tmp.String() -} - -// Getapiurl is the getter method for apiurl property -func (c *Client) Getapiurl() string { - return c.apiurl -} - -// Setapiurl is the setter method for apiurl -func (c *Client) Setapiurl(url string) { - c.apiurl = url -} - -// SetCredentials method to set username and password and otp code to use for api communication -// set otp code to empty string, if you do not use 2FA -func (c *Client) SetCredentials(username string, password string, otpcode string) { - c.Socketcfg.SetCredentials(username, password, otpcode) -} - -// SetIPAddress method to set api client to submit this ip address in api communication -func (c *Client) SetIPAddress(ip string) { - c.Socketcfg.SetIPAddress(ip) -} - -// SetSubuserView method to activate the use of a subuser account as data view -func (c *Client) SetSubuserView(username string) { - c.Socketcfg.SetUser(username) -} - -// ResetSubuserView method to deactivate the use of a subuser account as data view -func (c *Client) ResetSubuserView() { - c.Socketcfg.SetUser("") -} - -// UseLiveSystem method to set api client to communicate with the LIVE backend API -func (c *Client) UseLiveSystem() { - c.Socketcfg.SetEntity("54cd") -} - -// UseOTESystem method to set api client to communicate with the OT&E backend API -func (c *Client) UseOTESystem() { - c.Socketcfg.SetEntity("1234") -} - -// EnableDebugMode method to enable debugMode for debug output -func (c *Client) EnableDebugMode() { - c.debugMode = true -} - -// DisableDebugMode method to disable debugMode for debug output -func (c *Client) DisableDebugMode() { - c.debugMode = false -} - -// Request method requests the given command to the api server and returns the response as ListResponse. -func (c *Client) Request(cmd map[string]string) *listresponse.ListResponse { - if c.Socketcfg == (socketcfg.Socketcfg{}) { - return listresponse.NewListResponse(hashresponse.NewTemplates().Get("expired")) - } - return c.dorequest(cmd, &c.Socketcfg) -} - -// debugRequest method used to trigger debug output in case debugMode is activated -func (c *Client) debugRequest(cmd map[string]string, data string, r *listresponse.ListResponse) { - if c.debugMode { - j, _ := json.Marshal(cmd) - fmt.Printf("%s\n", j) - fmt.Println("POST: " + data) - fmt.Println(strconv.Itoa(r.Code()) + " " + r.Description() + "\n") - } -} - -// RequestAll method requests ALL entries matching the request criteria by the given command from api server. -// So useful for client-side lists. Finally it returns the response as ListResponse. -func (c *Client) RequestAll(cmd map[string]string) *listresponse.ListResponse { - if c.Socketcfg == (socketcfg.Socketcfg{}) { - return listresponse.NewListResponse(hashresponse.NewTemplates().Get("expired")) - } - cmd["LIMIT"] = "1" - cmd["FIRST"] = "0" - r := c.dorequest(cmd, &c.Socketcfg) - if r.IsSuccess() { - cmd["LIMIT"] = strconv.Itoa(r.Total()) - cmd["FIRST"] = "0" - r = c.dorequest(cmd, &c.Socketcfg) - } - return r -} - -// request the given command to the api server by using the provided socket configuration and return the response as ListResponse. -func (c *Client) dorequest(cmd map[string]string, cfg *socketcfg.Socketcfg) *listresponse.ListResponse { - data := c.EncodeData(cfg, cmd) - client := &http.Client{} - req, err := http.NewRequest("POST", c.apiurl, strings.NewReader(data)) - if err != nil { - tpl := hashresponse.NewTemplates().Get("commonerror") - tpl = strings.Replace(tpl, "####ERRMSG####", err.Error(), 1) - r := listresponse.NewListResponse(tpl) - c.debugRequest(cmd, data, r) - return r - } - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - req.Header.Add("Expect", "") - resp, err2 := client.Do(req) - if err2 != nil { - tpl := hashresponse.NewTemplates().Get("commonerror") - tpl = strings.Replace(tpl, "####ERRMSG####", err2.Error(), 1) - r := listresponse.NewListResponse(tpl) - c.debugRequest(cmd, data, r) - return r - } - defer resp.Body.Close() - if resp.StatusCode == http.StatusOK { - response, err := ioutil.ReadAll(resp.Body) - if err != nil { - tpl := hashresponse.NewTemplates().Get("commonerror") - tpl = strings.Replace(tpl, "####ERRMSG####", err.Error(), 1) - r := listresponse.NewListResponse(tpl) - c.debugRequest(cmd, data, r) - return r - } - r := listresponse.NewListResponse(string(response)) - c.debugRequest(cmd, data, r) - return r - } - tpl := hashresponse.NewTemplates().Get("commonerror") - tpl = strings.Replace(tpl, "####ERRMSG####", string(resp.StatusCode)+resp.Status, 1) - r := listresponse.NewListResponse(tpl) - c.debugRequest(cmd, data, r) - return r -} - -// Login method to use as entry point for session based communication. -// Response is returned as ListResponse. -func (c *Client) Login() *listresponse.ListResponse { - return c.dologin(map[string]string{"COMMAND": "StartSession"}) -} - -// LoginExtended method to use as entry point for session based communication. -// This method allows to provide further command parameters for startsession command. -// Response is returned as ListResponse. -func (c *Client) LoginExtended(cmdparams map[string]string) *listresponse.ListResponse { - cmd := map[string]string{"COMMAND": "StartSession"} - for k, v := range cmdparams { - cmd[k] = v - } - return c.dologin(cmd) -} - -// dologin method used internally to perform a login using the given command. -// Response is returned as ListResponse. -func (c *Client) dologin(cmd map[string]string) *listresponse.ListResponse { - r := c.dorequest(cmd, &c.Socketcfg) - if r.Code() == 200 { - sessid, _ := r.GetColumnIndex("SESSION", 0) - c.Socketcfg.SetSession(sessid) - } - return r -} - -// Logout method to use for session based communication. -// This method logs you out and destroys the api session. -// Response is returned as ListResponse. -func (c *Client) Logout() *listresponse.ListResponse { - cmd := map[string]string{"COMMAND": "EndSession"} - return c.dorequest(cmd, &c.Socketcfg) -} diff --git a/vendor/github.com/hexonet/go-sdk/column/column.go b/vendor/github.com/hexonet/go-sdk/column/column.go new file mode 100644 index 000000000..e68fdac8b --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/column/column.go @@ -0,0 +1,49 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package column provides column functionality to cover API response data +package column + +import "errors" + +// Column is a struct representing column covering API response data. +type Column struct { + Length int + key string + data []string +} + +// NewColumn represents the constructor for struct Column. +func NewColumn(key string, data []string) *Column { + sc := &Column{ + Length: len(data), + key: key, + data: data, + } + return sc +} + +// GetKey method to return the column name +func (c *Column) GetKey() string { + return c.key +} + +// GetData method to return the column data +func (c *Column) GetData() []string { + return c.data +} + +// GetDataByIndex method to return the column data at the provided index +func (c *Column) GetDataByIndex(idx int) (string, error) { + if c.hasDataIndex(idx) { + return c.data[idx], nil + } + return "", errors.New("Index not found") +} + +// hasDataIndex method to check if the given data index exists +func (c *Column) hasDataIndex(idx int) bool { + return (idx >= 0 && idx < c.Length) +} diff --git a/vendor/github.com/hexonet/go-sdk/record/record.go b/vendor/github.com/hexonet/go-sdk/record/record.go new file mode 100644 index 000000000..c656d5a1d --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/record/record.go @@ -0,0 +1,43 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package record provides record functionality to cover API response data +package record + +import "errors" + +// Record is a struct representing record/row covering API response data. +type Record struct { + data map[string]string +} + +// NewRecord represents the constructor for struct Column. +func NewRecord(data map[string]string) *Record { + r := &Record{ + data: data, + } + return r +} + +// GetData method to return the column data +func (c *Record) GetData() map[string]string { + return c.data +} + +// GetDataByKey method to return the column data at the provided index +func (c *Record) GetDataByKey(key string) (string, error) { + if c.hasData(key) { + return c.data[key], nil + } + return "", errors.New("column name not found in record") +} + +// hasData method to check if the given data index exists +func (c *Record) hasData(key string) bool { + if _, ok := c.data[key]; ok { + return true + } + return false +} diff --git a/vendor/github.com/hexonet/go-sdk/response/hashresponse/hashresponse.go b/vendor/github.com/hexonet/go-sdk/response/hashresponse/hashresponse.go deleted file mode 100644 index 14d23838a..000000000 --- a/vendor/github.com/hexonet/go-sdk/response/hashresponse/hashresponse.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) 2018 Kai Schwarz (1API GmbH). All rights reserved. -// -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE.md file. - -// Package hashresponse covers all functionality to handle an API response in hash format and provides access to a response template manager -// to cover http error cases etc. with API response format. -package hashresponse - -import ( - "errors" - "fmt" - "math" - "regexp" - "strconv" - "strings" -) - -// HashResponse class provides basic functionality to work with API responses. -type HashResponse struct { - // represents the parsed API response data - hash map[string]interface{} - // represents the raw API response data - raw string - // represents the pattern to match columns used for pagination - pagerRegexp regexp.Regexp - // represents the column filter pattern - columnFilterRegexp regexp.Regexp - // represents an flag to turn column filter on/off - columnFilterActive bool -} - -// NewHashResponse represents the constructor for struct HashResponse. -// Provide the raw api response string as parameter. -func NewHashResponse(r string) *HashResponse { - res := r - if len(res) == 0 { - res = NewTemplates().Get("empty") - } - hr := &HashResponse{ - raw: res, - columnFilterActive: false, - pagerRegexp: *regexp.MustCompile("^(TOTAL|FIRST|LAST|LIMIT|COUNT)$"), - } - hr.hash = hr.Parse(hr.raw) - return hr -} - -// GetRaw method to return the api raw (but filtered - in case of useColRegexp) response data -func (hr *HashResponse) GetRaw() string { - return hr.GetRawByFilter(false) -} - -// GetRawByFilter method to return the api raw response data. -// Use noColumnFilter parameter to explicitly suppress a current active column filter. -func (hr *HashResponse) GetRawByFilter(noColumnFilter bool) string { - if noColumnFilter || !hr.columnFilterActive { - return hr.raw - } - return hr.Serialize(hr.GetHash()) -} - -// GetHash method to return the parsed api response -func (hr *HashResponse) GetHash() map[string]interface{} { - if hr.columnFilterActive { - var h = make(map[string]interface{}) - for k, v := range hr.hash { - h[k] = v - } - properties := hr.hash["PROPERTY"] - if properties != nil { - d := make(map[string][]string) - for k, v := range properties.(map[string][]string) { - if hr.columnFilterRegexp.MatchString(k) { - d[k] = v - } - } - h["PROPERTY"] = d - } - return h - } - return hr.hash -} - -// DisableColumnFilter method to turn of column filter -func (hr *HashResponse) DisableColumnFilter() { - hr.columnFilterActive = false - // hr.columnFilterRegexp = nil -} - -// EnableColumnFilter method to set a column filter -func (hr *HashResponse) EnableColumnFilter(pattern string) { - hr.columnFilterActive = true - hr.columnFilterRegexp = *regexp.MustCompile(pattern) -} - -// Code method to access the api response code -func (hr *HashResponse) Code() int { - var x int - fmt.Sscanf(hr.hash["CODE"].(string), "%d", &x) - return x -} - -// Description method to access the api response description -func (hr *HashResponse) Description() string { - return hr.hash["DESCRIPTION"].(string) -} - -// Runtime method to access the api response runtime -func (hr *HashResponse) Runtime() float64 { - s, _ := strconv.ParseFloat(hr.hash["RUNTIME"].(string), 64) - return s -} - -// Queuetime method to access the api response queuetime -func (hr *HashResponse) Queuetime() float64 { - s, _ := strconv.ParseFloat(hr.hash["QUEUETIME"].(string), 64) - return s -} - -// First method to access the pagination data "first". -// Represents the row index of 1st row of the current response of the whole result set -func (hr *HashResponse) First() int { - val, _ := hr.GetColumnIndex("FIRST", 0) - if len(val) == 0 { - return 0 - } - var x int - fmt.Sscanf(val, "%d", &x) - return x -} - -// Count method to access the pagination data "count" -// Represents the count of rows returned in the current response -func (hr *HashResponse) Count() int { - val, _ := hr.GetColumnIndex("COUNT", 0) - if len(val) != 0 { - var x int - fmt.Sscanf(val, "%d", &x) - return x - } - c := 0 - max := 0 - cols := hr.GetColumnKeys() - for _, el := range cols { - col := hr.GetColumn(el) - c = len(col) - if c > max { - max = c - } - } - return c -} - -// Last method to access the pagination data "last" -// Represents the row index of last row of the current response of the whole result set -func (hr *HashResponse) Last() int { - val, _ := hr.GetColumnIndex("LAST", 0) - if len(val) == 0 { - return hr.Count() - 1 - } - var x int - fmt.Sscanf(val, "%d", &x) - return x -} - -// Limit method to access the pagination data "limit" -// represents the limited amount of rows requested to be returned -func (hr *HashResponse) Limit() int { - val, _ := hr.GetColumnIndex("LIMIT", 0) - if len(val) == 0 { - return hr.Count() - } - var x int - fmt.Sscanf(val, "%d", &x) - return x -} - -// Total method to access the pagination data "total" -// represents the total amount of rows available in the whole result set -func (hr *HashResponse) Total() int { - val, _ := hr.GetColumnIndex("TOTAL", 0) - if len(val) == 0 { - return hr.Count() - } - var x int - fmt.Sscanf(val, "%d", &x) - return x -} - -// Pages method to return the amount of pages of the current result set -func (hr *HashResponse) Pages() int { - t := hr.Total() - if t > 0 { - return int(math.Ceil(float64(t) / float64(hr.Limit()))) - } - return 1 -} - -// Page method to return the number of the current page -func (hr *HashResponse) Page() int { - if hr.Count() > 0 { - // limit cannot be 0 as this.count() will cover this, no worries - d := float64(hr.First()) / float64(hr.Limit()) - return int(math.Floor(d)) + 1 - } - return 1 -} - -// Prevpage method to get the previous page number -func (hr *HashResponse) Prevpage() int { - p := hr.Page() - 1 - if p > 0 { - return p - } - return 1 -} - -// Nextpage method to get the next page number -func (hr *HashResponse) Nextpage() int { - p := hr.Page() + 1 - pages := hr.Pages() - if p <= pages { - return p - } - return pages -} - -// GetPagination method to return all pagination data at once -func (hr *HashResponse) GetPagination() map[string]int { - pagination := make(map[string]int) - pagination["FIRST"] = hr.First() - pagination["LAST"] = hr.Last() - pagination["COUNT"] = hr.Count() - pagination["TOTAL"] = hr.Total() - pagination["LIMIT"] = hr.Limit() - pagination["PAGES"] = hr.Pages() - pagination["PAGE"] = hr.Page() - pagination["PAGENEXT"] = hr.Nextpage() - pagination["PAGEPREV"] = hr.Prevpage() - return pagination -} - -// IsSuccess method to check if the api response represents a success case -func (hr *HashResponse) IsSuccess() bool { - code := hr.Code() - return (code >= 200 && code < 300) -} - -// IsTmpError method to check if the api response represents a temporary error case -func (hr *HashResponse) IsTmpError() bool { - code := hr.Code() - return (code >= 400 && code < 500) -} - -// IsError method to check if the api response represents an error case -func (hr *HashResponse) IsError() bool { - code := hr.Code() - return (code >= 500 && code <= 600) -} - -// GetColumnKeys method to get a full list available columns in api response -func (hr *HashResponse) GetColumnKeys() []string { - var columns []string - if hr.hash == nil { - return columns - } - property := hr.hash["PROPERTY"] - if property == nil { - return columns - } - for k := range property.(map[string][]string) { - if !hr.pagerRegexp.MatchString(k) { - columns = append(columns, k) - } - } - return columns -} - -// GetColumn method to get the full column data for the given column id -func (hr *HashResponse) GetColumn(columnid string) []string { - if hr.hash == nil || hr.hash["PROPERTY"] == nil { - return nil - } - return hr.hash["PROPERTY"].(map[string][]string)[columnid] -} - -// GetColumnIndex method to get a response data field by column id and index -func (hr *HashResponse) GetColumnIndex(columnid string, index int) (string, error) { - if hr.hash == nil || hr.hash["PROPERTY"] == nil { - return "", errors.New("column not found") - } - column := hr.hash["PROPERTY"].(map[string][]string)[columnid] - if column == nil || len(column) <= index { - return "", errors.New("index not found") - } - return column[index], nil -} - -// Serialize method to stringify a parsed api response -func (hr *HashResponse) Serialize(hash map[string]interface{}) string { - var plain strings.Builder - plain.WriteString("[RESPONSE]") - for k := range hash { - if strings.Compare(k, "PROPERTY") == 0 { - for k2, v2 := range hash[k].(map[string][]string) { - for i, v3 := range v2 { - plain.WriteString("\r\nPROPERTY[") - plain.WriteString(k2) - plain.WriteString("][") - plain.WriteString(fmt.Sprintf("%d", i)) - plain.WriteString("]=") - plain.WriteString(v3) - } - } - } else { - tmp := hash[k].(string) - if len(tmp) > 0 { - plain.WriteString("\r\n") - plain.WriteString(k) - plain.WriteString("=") - plain.WriteString(tmp) - } - } - } - plain.WriteString("\r\nEOF\r\n") - return plain.String() -} - -// Parse method to parse the given raw api response -func (hr *HashResponse) Parse(r string) map[string]interface{} { - hash := make(map[string]interface{}) - tmp := strings.Split(strings.Replace(r, "\r", "", -1), "\n") - p1 := regexp.MustCompile("^([^\\=]*[^\\t\\= ])[\\t ]*=[\\t ]*(.*)$") - p2 := regexp.MustCompile("(?i)^property\\[([^\\]]*)\\]\\[([0-9]+)\\]") - properties := make(map[string][]string) - for _, row := range tmp { - m := p1.MatchString(row) - if m { - groups := p1.FindStringSubmatch(row) - property := strings.ToUpper(groups[1]) - mm := p2.MatchString(property) - if mm { - groups2 := p2.FindStringSubmatch(property) - key := strings.Replace(strings.ToUpper(groups2[1]), "\\s", "", -1) - // idx2 := strconv.Atoi(groups2[2]) - list := make([]string, len(properties[key])) - copy(list, properties[key]) - pat := regexp.MustCompile("[\\t ]*$") - rep1 := "${1}$2" - list = append(list, pat.ReplaceAllString(groups[2], rep1)) - properties[key] = list - } else { - val := groups[2] - if len(val) > 0 { - pat := regexp.MustCompile("[\\t ]*$") - hash[property] = pat.ReplaceAllString(val, "") - } - } - } - } - if len(properties) > 0 { - hash["PROPERTY"] = properties - } - return hash -} diff --git a/vendor/github.com/hexonet/go-sdk/response/hashresponse/templates.go b/vendor/github.com/hexonet/go-sdk/response/hashresponse/templates.go deleted file mode 100644 index 6c9c60faa..000000000 --- a/vendor/github.com/hexonet/go-sdk/response/hashresponse/templates.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2018 Kai Schwarz (1API GmbH). All rights reserved. -// -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE.md file. - -package hashresponse - -import ( - "strings" -) - -// Templates class manages default api response templates to be used for different reasons. -// It also provides functionality to compare a response against a template. -// -// Basically used to provide custom response templates that are used in error cases to have a useful way to responds to the client. -type Templates struct { - // represents the template container - templates map[string]string -} - -// NewTemplates represents the constructor for struct Templates. -func NewTemplates() *Templates { - tpls := make(map[string]string) - tpls["empty"] = "[RESPONSE]\r\ncode=423\r\ndescription=Empty API response\r\nEOF\r\n" - tpls["error"] = "[RESPONSE]\r\ncode=421\r\ndescription=Command failed due to server error. Client should try again\r\nEOF\r\n" - tpls["expired"] = "[RESPONSE]\r\ncode=530\r\ndescription=SESSION NOT FOUND\r\nEOF\r\n" - tpls["commonerror"] = "[RESPONSE]\r\nDESCRIPTION=Command failed;####ERRMSG####;\r\nCODE=500\r\nQUEUETIME=0\r\nRUNTIME=0\r\nEOF" - return &Templates{ - templates: tpls, - } -} - -// GetAll method to get all available response templates -func (dr *Templates) GetAll() map[string]string { - return dr.templates -} - -// GetParsed method to get a parsed response template by given template id. -func (dr *Templates) GetParsed(templateid string) map[string]interface{} { - hr := NewHashResponse(dr.Get(templateid)) - return hr.GetHash() -} - -// Get method to get a raw response template by given template id. -func (dr *Templates) Get(templateid string) string { - return dr.templates[templateid] -} - -// Set method to set a response template by given template id and content -func (dr *Templates) Set(templateid string, templatecontent string) { - dr.templates[templateid] = templatecontent -} - -// SetParsed method to set a response template by given template id and parsed content -func (dr *Templates) SetParsed(templateid string, templatecontent map[string]interface{}) { - hr := NewHashResponse("") - dr.templates[templateid] = hr.Serialize(templatecontent) -} - -// Match method to compare a given raw api response with a response template identfied by id. -// It compares CODE and DESCRIPTION. -func (dr *Templates) Match(r string, templateid string) bool { - tpl := NewHashResponse(dr.Get(templateid)) - rr := NewHashResponse(r) - return (tpl.Code() == rr.Code() && strings.Compare(tpl.Description(), rr.Description()) == 0) -} - -// MatchParsed method to compare a given parsed api response with a response template identified by id. -// It compares CODE and DESCRIPTION. -func (dr *Templates) MatchParsed(r map[string]interface{}, templateid string) bool { - tpl := dr.GetParsed(templateid) - return (strings.Compare(tpl["CODE"].(string), r["CODE"].(string)) == 0 && - strings.Compare(tpl["DESCRIPTION"].(string), r["DESCRIPTION"].(string)) == 0) -} diff --git a/vendor/github.com/hexonet/go-sdk/response/listresponse/listresponse.go b/vendor/github.com/hexonet/go-sdk/response/listresponse/listresponse.go deleted file mode 100644 index c047e87df..000000000 --- a/vendor/github.com/hexonet/go-sdk/response/listresponse/listresponse.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2018 Kai Schwarz (1API GmbH). All rights reserved. -// -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE.md file. - -// Package listresponse covers all functionality to handle an API response in list format, but as well provides access to the hash format -package listresponse - -import ( - "github.com/hexonet/go-sdk/response/hashresponse" -) - -// ListResponse class provides extra functionality to work with API responses. -// It provides methods that are useful for data representation in table format. -// In general the apiconnector Client always returns this type of response to be as flexible as possible. -type ListResponse struct { - *hashresponse.HashResponse - currentIndex int - rows [][]string -} - -// NewListResponse represents the constructor for struct ListResponse -func NewListResponse(r string) *ListResponse { - lr := &ListResponse{ - rows: [][]string{}, - currentIndex: 0, - } - lr.HashResponse = hashresponse.NewHashResponse(r) - rows := lr.rows - h := lr.GetHash() - cols := lr.GetColumnKeys() - if lr.IsSuccess() && h["PROPERTY"] != nil { - size := len(cols) - cc := lr.Count() - for i := 0; i < cc; i++ { //loop over amount of rows/indexes - var row []string - for c := 0; c < size; c++ { //loop over all columns - colkey := cols[c] - values := lr.GetColumn(colkey) - if values != nil && len(values) > i { - row = append(row, values[i]) - } - } - rows = append(rows, row) - } - } - lr.rows = rows - return lr -} - -// GetList method to return the list of available rows -func (lr *ListResponse) GetList() [][]string { - return lr.rows -} - -// HasNext method to check if there's a further row after current row -func (lr *ListResponse) HasNext() bool { - len := len(lr.rows) - if len == 0 || lr.currentIndex+1 >= len { - return false - } - return true -} - -// Next method to access next row. -// Use HasNext method before. -func (lr *ListResponse) Next() []string { - lr.currentIndex++ - return lr.rows[lr.currentIndex] -} - -// HasPrevious method to check if there is a row available before current row. -func (lr *ListResponse) HasPrevious() bool { - if lr.currentIndex == 0 { - return false - } - return true -} - -// Previous method to access previous row. -// Use HasPrevious method before. -func (lr *ListResponse) Previous() []string { - lr.currentIndex-- - return lr.rows[lr.currentIndex] -} - -// Current method to return current row -func (lr *ListResponse) Current() []string { - if len(lr.rows) == 0 { - return nil - } - return lr.rows[lr.currentIndex] -} - -// Rewind method to reset the iterator index -func (lr *ListResponse) Rewind() { - lr.currentIndex = 0 -} diff --git a/vendor/github.com/hexonet/go-sdk/response/response.go b/vendor/github.com/hexonet/go-sdk/response/response.go new file mode 100644 index 000000000..5c46d2bdc --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/response/response.go @@ -0,0 +1,381 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package response provides extended functionality to handle API response data +package response + +import ( + "errors" + "math" + "strconv" + + "github.com/hexonet/go-sdk/column" + "github.com/hexonet/go-sdk/record" + rt "github.com/hexonet/go-sdk/responsetemplate" +) + +// Response is a struct used to cover basic functionality to work with +// API response data (or hardcoded API response data). +type Response struct { + *rt.ResponseTemplate + command map[string]string + columnkeys []string + columns []column.Column + recordIndex int + records []record.Record +} + +// NewResponse represents the constructor for struct Response. +func NewResponse(raw string, cmd map[string]string) *Response { + r := &Response{ + command: cmd, + columnkeys: []string{}, + columns: []column.Column{}, + recordIndex: 0, + records: []record.Record{}, + } + r.ResponseTemplate = rt.NewResponseTemplate(raw) + + h := r.ResponseTemplate.GetHash() + if p, ok := h["PROPERTY"]; ok { + prop := p.(map[string][]string) + colKeys := []string{} + for key := range prop { + colKeys = append(colKeys, key) + } + count := 0 + for _, c := range colKeys { + if d, ok := prop[c]; ok { + r.AddColumn(c, d) + tlen := len(d) + if tlen > count { + count = tlen + } + } + } + for i := 0; i < count; i++ { + d := map[string]string{} + for _, k := range colKeys { + col := r.GetColumn(k) + if col != nil { + v, err := col.GetDataByIndex(i) + if err == nil { + d[k] = v + } + } + } + r.AddRecord(d) + } + } + return r +} + +// AddColumn method to add a Column to the column list +func (r *Response) AddColumn(key string, data []string) *Response { + col := column.NewColumn(key, data) + r.columns = append(r.columns, *col) + r.columnkeys = append(r.columnkeys, key) + return r +} + +// AddRecord method to add a record to the record list +func (r *Response) AddRecord(h map[string]string) *Response { + rec := record.NewRecord(h) + r.records = append(r.records, *rec) + return r +} + +// GetColumn method to get column by column name +func (r *Response) GetColumn(key string) *column.Column { + if idx, ok := r.hasColumn(key); ok { + return &r.columns[idx] + } + return nil +} + +// GetColumnIndex method to get data by column name and index +func (r *Response) GetColumnIndex(key string, index int) (string, error) { + col := r.GetColumn(key) + if col != nil { + d, err := col.GetDataByIndex(index) + if err == nil { + return d, nil + } + } + return "", errors.New("Column Data Index does not exist") +} + +// GetColumnKeys method to get the list of column names +func (r *Response) GetColumnKeys() []string { + return r.columnkeys +} + +// GetColumns method to get the list of columns +func (r *Response) GetColumns() []column.Column { + return r.columns +} + +// GetCommand method to get the underlying API command +func (r *Response) GetCommand() map[string]string { + return r.command +} + +// GetCurrentPageNumber method to get the page number of current list query +func (r *Response) GetCurrentPageNumber() (int, error) { + first, ferr := r.GetFirstRecordIndex() + limit := r.GetRecordsLimitation() + if ferr == nil && limit > 0 { + return int(math.Floor(float64(first)/float64(limit))) + 1, nil + } + return 0, errors.New("Could not find current page number") +} + +// GetCurrentRecord method to get record of current record index +func (r *Response) GetCurrentRecord() *record.Record { + if r.hasCurrentRecord() { + return &r.records[r.recordIndex] + } + return nil +} + +// GetFirstRecordIndex method to get index of first row +func (r *Response) GetFirstRecordIndex() (int, error) { + col := r.GetColumn("FIRST") + if col != nil { + f, err := col.GetDataByIndex(0) + if err == nil { + idx, _ := strconv.Atoi(f) + return idx, nil + } + } + if len(r.records) > 1 { + return 0, nil + } + return 0, errors.New("Could not find first record index") +} + +// GetLastRecordIndex method to get last record index of the current list query +func (r *Response) GetLastRecordIndex() (int, error) { + col := r.GetColumn("LAST") + if col != nil { + l, err := col.GetDataByIndex(0) + if err == nil { + idx, _ := strconv.Atoi(l) + return idx, nil + } + } + len := r.GetRecordsCount() + if len > 0 { + return (len - 1), nil + } + return 0, errors.New("Could not find last record index") +} + +// GetListHash method to get Response as List Hash including useful meta data for tables +func (r *Response) GetListHash() map[string]interface{} { + var lh []map[string]string + recs := r.GetRecords() + for _, rec := range recs { + lh = append(lh, rec.GetData()) + } + return map[string]interface{}{ + "LIST": lh, + "meta": map[string]interface{}{ + "columns": r.GetColumnKeys(), + "pg": r.GetPagination(), + }, + } +} + +// GetNextRecord method to get next record in record list +func (r *Response) GetNextRecord() *record.Record { + if r.hasNextRecord() { + r.recordIndex++ + return &r.records[r.recordIndex] + } + return nil +} + +// GetNextPageNumber method to get Page Number of next list query +func (r *Response) GetNextPageNumber() (int, error) { + cp, err := r.GetCurrentPageNumber() + if err != nil { + return 0, errors.New("Could not find next page number") + } + page := cp + 1 + pages := r.GetNumberOfPages() + if page <= pages { + return page, nil + } + return pages, nil +} + +// GetNumberOfPages method to get the number of pages available for this list query +func (r *Response) GetNumberOfPages() int { + t := r.GetRecordsTotalCount() + limit := r.GetRecordsLimitation() + if t > 0 && limit > 0 { + return int(math.Ceil(float64(t) / float64(limit))) + } + return 0 +} + +// GetPagination method to get pagination data; useful for table pagination +func (r *Response) GetPagination() map[string]interface{} { + cp, err := r.GetCurrentPageNumber() + if err != nil { + return nil + } + fr, err := r.GetFirstRecordIndex() + if err != nil { + return nil + } + lr, err := r.GetLastRecordIndex() + if err != nil { + return nil + } + np, err := r.GetNextPageNumber() + if err != nil { + np = cp + } + pp, err := r.GetPreviousPageNumber() + if err != nil { + pp = cp + } + return map[string]interface{}{ + "COUNT": r.GetRecordsCount(), + "CURRENTPAGE": cp, + "FIRST": fr, + "LAST": lr, + "LIMIT": r.GetRecordsLimitation(), + "NEXTPAGE": np, + "PAGES": r.GetNumberOfPages(), + "PREVIOUSPAGE": pp, + "TOTAL": r.GetRecordsTotalCount(), + } +} + +// GetPreviousPageNumber method to get Page Number of previous list query +func (r *Response) GetPreviousPageNumber() (int, error) { + cp, err := r.GetCurrentPageNumber() + if err != nil { + return 0, err + } + pp := cp - 1 + if pp < 1 { + return 0, errors.New("Could not find previous page number") + } + return pp, nil +} + +// GetPreviousRecord method to get previous record in record list +func (r *Response) GetPreviousRecord() *record.Record { + if r.hasPreviousRecord() { + r.recordIndex-- + return &r.records[r.recordIndex] + } + return nil +} + +// GetRecord method to get Record at given index +func (r *Response) GetRecord(idx int) *record.Record { + if idx >= 0 && len(r.records) > idx { + return &r.records[idx] + } + return nil +} + +// GetRecords method to get all records +func (r *Response) GetRecords() []record.Record { + return r.records +} + +// GetRecordsCount method to get count of rows in this response +func (r *Response) GetRecordsCount() int { + return len(r.records) +} + +// GetRecordsTotalCount method to get total count of records available for the list query +func (r *Response) GetRecordsTotalCount() int { + col := r.GetColumn("TOTAL") + if col != nil { + t, err := col.GetDataByIndex(0) + if err == nil { + c, _ := strconv.Atoi(t) + return c + } + } + return r.GetRecordsCount() +} + +// GetRecordsLimitation method to get limit(ation) setting of the current list query +func (r *Response) GetRecordsLimitation() int { + col := r.GetColumn("LIMIT") + if col != nil { + l, err := col.GetDataByIndex(0) + if err == nil { + lt, _ := strconv.Atoi(l) + return lt + } + } + return r.GetRecordsCount() +} + +// HasNextPage method to check if this list query has a next page +func (r *Response) HasNextPage() bool { + cp, err := r.GetCurrentPageNumber() + if err != nil { + return false + } + np := cp + 1 + return (np <= r.GetNumberOfPages()) +} + +// HasPreviousPage method to check if this list query has a previous page +func (r *Response) HasPreviousPage() bool { + cp, err := r.GetCurrentPageNumber() + if err != nil { + return false + } + pp := cp - 1 + return (pp > 0) +} + +// RewindRecordList method to reset index in record list back to zero +func (r *Response) RewindRecordList() *Response { + r.recordIndex = 0 + return r +} + +// hasColumn method to check if the given column exists in column list +func (r *Response) hasColumn(key string) (int, bool) { + for i, k := range r.columnkeys { + if k == key { + return i, true + } + } + return 0, false +} + +// hasCurrentRecord method to check if the record on current record index exists +func (r *Response) hasCurrentRecord() bool { + tlen := len(r.records) + return (tlen > 0 && + r.recordIndex >= 0 && + r.recordIndex < tlen) +} + +// hasNextRecord method to check if the record list contains a next record for the +// current record index in use +func (r *Response) hasNextRecord() bool { + next := r.recordIndex + 1 + return (r.hasCurrentRecord() && (next < len(r.records))) +} + +// hasPreviousRecord method to check if the record list contains a previous record +// for the current record index in use +func (r *Response) hasPreviousRecord() bool { + return (r.recordIndex > 0 && r.hasCurrentRecord()) +} diff --git a/vendor/github.com/hexonet/go-sdk/responseparser/responseparser.go b/vendor/github.com/hexonet/go-sdk/responseparser/responseparser.go new file mode 100644 index 000000000..7dad46779 --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/responseparser/responseparser.go @@ -0,0 +1,98 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package responseparser provides functionality to cover API response +// data parsing and serializing. +package responseparser + +import ( + "fmt" + "regexp" + "sort" + "strings" +) + +// Parse method to return plain API response parsed into hash format +func Parse(r string) map[string]interface{} { + hash := make(map[string]interface{}) + tmp := strings.Split(strings.Replace(r, "\r", "", -1), "\n") + p1 := regexp.MustCompile("^([^\\=]*[^\\t\\= ])[\\t ]*=[\\t ]*(.*)$") + p2 := regexp.MustCompile("(?i)^property\\[([^\\]]*)\\]\\[([0-9]+)\\]") + properties := make(map[string][]string) + for _, row := range tmp { + m := p1.MatchString(row) + if m { + groups := p1.FindStringSubmatch(row) + property := strings.ToUpper(groups[1]) + mm := p2.MatchString(property) + if mm { + groups2 := p2.FindStringSubmatch(property) + key := strings.Replace(strings.ToUpper(groups2[1]), "\\s", "", -1) + // idx2 := strconv.Atoi(groups2[2]) + list := make([]string, len(properties[key])) + copy(list, properties[key]) + pat := regexp.MustCompile("[\\t ]*$") + rep1 := "${1}$2" + list = append(list, pat.ReplaceAllString(groups[2], rep1)) + properties[key] = list + } else { + val := groups[2] + if len(val) > 0 { + pat := regexp.MustCompile("[\\t ]*$") + hash[property] = pat.ReplaceAllString(val, "") + } + } + } + } + if len(properties) > 0 { + hash["PROPERTY"] = properties + } + if _, ok := hash["DESCRIPTION"]; !ok { + hash["DESCRIPTION"] = "" + } + return hash +} + +// Serialize method to serialize API response hash format back to string +func Serialize(hash map[string]interface{}) string { + var plain strings.Builder + plain.WriteString("[RESPONSE]") + keys := []string{} + for k := range hash { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + if strings.Compare(k, "PROPERTY") == 0 { + p := hash[k].(map[string][]string) + keys2 := []string{} + for k2 := range p { + keys2 = append(keys2, k2) + } + sort.Strings(keys2) + for _, k2 := range keys2 { + v2 := p[k2] + for i, v3 := range v2 { + plain.WriteString("\r\nPROPERTY[") + plain.WriteString(k2) + plain.WriteString("][") + plain.WriteString(fmt.Sprintf("%d", i)) + plain.WriteString("]=") + plain.WriteString(v3) + } + } + } else { + tmp := hash[k].(string) + if len(tmp) > 0 { + plain.WriteString("\r\n") + plain.WriteString(k) + plain.WriteString("=") + plain.WriteString(tmp) + } + } + } + plain.WriteString("\r\nEOF\r\n") + return plain.String() +} diff --git a/vendor/github.com/hexonet/go-sdk/responsetemplate/responsetemplate.go b/vendor/github.com/hexonet/go-sdk/responsetemplate/responsetemplate.go new file mode 100644 index 000000000..b0210326e --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/responsetemplate/responsetemplate.go @@ -0,0 +1,104 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package responsetemplate provides basic functionality to handle API response data +package responsetemplate + +import ( + "strconv" + + rp "github.com/hexonet/go-sdk/responseparser" +) + +// ResponseTemplate is a struct used to cover basic functionality to work with +// API response data (or hardcoded API response data). +type ResponseTemplate struct { + Raw string + Hash map[string]interface{} +} + +// NewResponseTemplate represents the constructor for struct ResponseTemplate. +func NewResponseTemplate(raw string) *ResponseTemplate { + if len(raw) == 0 { + raw = "[RESPONSE]\r\nCODE=423\r\nDESCRIPTION=Empty API response. Probably unreachable API end point\r\nEOF\r\n" + } + rt := &ResponseTemplate{ + Raw: raw, + Hash: rp.Parse(raw), + } + return rt +} + +// GetCode method to return the API response code +func (rt *ResponseTemplate) GetCode() int { + h := rt.GetHash() + c, _ := strconv.Atoi(h["CODE"].(string)) + return c +} + +// GetDescription method to return the API response description +func (rt *ResponseTemplate) GetDescription() string { + h := rt.GetHash() + return h["DESCRIPTION"].(string) +} + +// GetPlain method to return raw API response +func (rt *ResponseTemplate) GetPlain() string { + return rt.Raw +} + +// GetQueuetime method to return API response queuetime +func (rt *ResponseTemplate) GetQueuetime() float64 { + h := rt.GetHash() + if val, ok := h["QUEUETIME"]; ok { + f, _ := strconv.ParseFloat(val.(string), 64) + return f + } + return 0.00 +} + +// GetHash method to return API response in hash format +func (rt *ResponseTemplate) GetHash() map[string]interface{} { + return rt.Hash +} + +// GetRuntime method to return API response runtime +func (rt *ResponseTemplate) GetRuntime() float64 { + h := rt.GetHash() + if val, ok := h["RUNTIME"]; ok { + f, _ := strconv.ParseFloat(val.(string), 64) + return f + } + return 0.00 +} + +// IsError method to check if API response represents an error case +func (rt *ResponseTemplate) IsError() bool { + c := rt.GetCode() + return (c >= 500 && c <= 599) +} + +// IsSuccess method to check if API response represents a success case +func (rt *ResponseTemplate) IsSuccess() bool { + c := rt.GetCode() + return (c >= 200 && c <= 299) +} + +//IsTmpError method to check if current API response represents a temporary error case +func (rt *ResponseTemplate) IsTmpError() bool { + c := rt.GetCode() + return (c >= 400 && c <= 499) +} + +//IsPending method to check if current operation is returned as pending +func (rt *ResponseTemplate) IsPending() bool { + h := rt.GetHash() + if val, ok := h["PENDING"]; ok { + if val.(string) == "1" { + return true + } + } + return false +} diff --git a/vendor/github.com/hexonet/go-sdk/responsetemplatemanager/responsetemplatemanager.go b/vendor/github.com/hexonet/go-sdk/responsetemplatemanager/responsetemplatemanager.go new file mode 100644 index 000000000..4ae55e935 --- /dev/null +++ b/vendor/github.com/hexonet/go-sdk/responsetemplatemanager/responsetemplatemanager.go @@ -0,0 +1,108 @@ +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. +// +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE.md file. + +// Package responsetemplatemanager provides basic functionality to handle API response data +package responsetemplatemanager + +import ( + "strings" + "sync" + + rp "github.com/hexonet/go-sdk/responseparser" + rt "github.com/hexonet/go-sdk/responsetemplate" +) + +// ResponseTemplateManager is a struct used to cover basic functionality to work with +// API response templates. +type ResponseTemplateManager struct { + templates map[string]string +} + +var instance *ResponseTemplateManager +var once sync.Once + +// GetInstance method to return the responsetemplatemanager singleton instance +func GetInstance() *ResponseTemplateManager { + once.Do(func() { + instance = &ResponseTemplateManager{ + templates: map[string]string{ + "404": generateTemplate("421", "Page not found"), + "500": generateTemplate("500", "Internal server error"), + "empty": generateTemplate("423", "Empty API response. Probably unreachable API end point"), + "error": generateTemplate("421", "Command failed due to server error. Client should try again"), + "expired": generateTemplate("530", "SESSION NOT FOUND"), + "httperror": generateTemplate("421", "Command failed due to HTTP communication error"), + "unauthorized": generateTemplate("530", "Unauthorized"), + }, + } + }) + return instance +} + +// generateTemplate method to generate API a response template string +// for given code and description +func generateTemplate(code string, description string) string { + var tmp strings.Builder + tmp.WriteString("[RESPONSE]\r\nCODE=") + tmp.WriteString(code) + tmp.WriteString("\r\nDESCRIPTION=") + tmp.WriteString(description) + tmp.WriteString("\r\nEOF\r\n") + return tmp.String() +} + +// GenerateTemplate method to generate API a response template string +// for given code and description +func (rtm *ResponseTemplateManager) GenerateTemplate(code string, description string) string { + return generateTemplate(code, description) +} + +// AddTemplate method to add a template to the templates container +func (rtm *ResponseTemplateManager) AddTemplate(id string, plain string) *ResponseTemplateManager { + rtm.templates[id] = plain + return rtm +} + +// GetTemplate method to get a ResponseTemplate from templates container +func (rtm *ResponseTemplateManager) GetTemplate(id string) *rt.ResponseTemplate { + if rtm.HasTemplate(id) { + return rt.NewResponseTemplate(rtm.templates[id]) + } + return rt.NewResponseTemplate(generateTemplate("500", "Response Template not found")) +} + +// GetTemplates method to return a map covering all available response templates +func (rtm *ResponseTemplateManager) GetTemplates() map[string]rt.ResponseTemplate { + tpls := map[string]rt.ResponseTemplate{} + for key := range rtm.templates { + tpls[key] = *rt.NewResponseTemplate(rtm.templates[key]) + } + return tpls +} + +// HasTemplate method to check if given template id exists in template container +func (rtm *ResponseTemplateManager) HasTemplate(id string) bool { + if _, ok := rtm.templates[id]; ok { + return true + } + return false +} + +// IsTemplateMatchHash method to check if given API response hash matches a given +// template by code and description +func (rtm *ResponseTemplateManager) IsTemplateMatchHash(tpl2 map[string]interface{}, id string) bool { + h := rtm.GetTemplate(id).GetHash() + return ((h["CODE"] == tpl2["CODE"].(string)) && + (h["DESCRIPTION"] == tpl2["DESCRIPTION"].(string))) +} + +// IsTemplateMatchPlain method to check if given API plain response matches a given +// template by code and description +func (rtm *ResponseTemplateManager) IsTemplateMatchPlain(plain string, id string) bool { + h := rtm.GetTemplate(id).GetHash() + tpl2 := rp.Parse(plain) + return ((h["CODE"] == tpl2["CODE"].(string)) && + (h["DESCRIPTION"] == tpl2["DESCRIPTION"].(string))) +} diff --git a/vendor/github.com/hexonet/go-sdk/client/socketcfg/socketcfg.go b/vendor/github.com/hexonet/go-sdk/socketconfig/socketconfig.go similarity index 50% rename from vendor/github.com/hexonet/go-sdk/client/socketcfg/socketcfg.go rename to vendor/github.com/hexonet/go-sdk/socketconfig/socketconfig.go index 963fab36c..2f2c39bce 100644 --- a/vendor/github.com/hexonet/go-sdk/client/socketcfg/socketcfg.go +++ b/vendor/github.com/hexonet/go-sdk/socketconfig/socketconfig.go @@ -1,71 +1,63 @@ -// Copyright (c) 2018 Kai Schwarz (1API GmbH). All rights reserved. +// Copyright (c) 2018 Kai Schwarz (HEXONET GmbH). All rights reserved. // // Use of this source code is governed by the MIT // license that can be found in the LICENSE.md file. -// Package socketcfg provides apiconnector client connection settings -package socketcfg +// Package socketconfig provides apiconnector client connection settings +package socketconfig import ( "net/url" "strings" ) -// Socketcfg is a struct representing connection settings used as POST data for http request against the insanely fast 1API backend API. -type Socketcfg struct { +// SocketConfig is a struct representing connection settings used as POST data for http request against the insanely fast HEXONET backend API. +type SocketConfig struct { + entity string login string + otp string pw string remoteaddr string - entity string session string user string - otp string } -// SetIPAddress method to set remote ip address to be submitted to the HEXONET API. -// This ip address is being considered when you have ip filter settings activated. -// To reset this, simply provide an empty string as parameter. -func (s *Socketcfg) SetIPAddress(ip string) { - s.remoteaddr = ip +// NewSocketConfig represents the constructor for struct SocketConfig. +func NewSocketConfig() *SocketConfig { + sc := &SocketConfig{ + entity: "", + login: "", + otp: "", + pw: "", + remoteaddr: "", + session: "", + user: "", + } + return sc } -// SetCredentials method to set username and password to use for api communication -func (s *Socketcfg) SetCredentials(username string, password string, otpcode string) { - s.login = username - s.pw = password - s.otp = otpcode -} - -// SetEntity method to set the system entity id used to communicate with -// "1234" -> OT&E system, "54cd" -> LIVE system -func (s *Socketcfg) SetEntity(entityid string) { - s.entity = entityid -} - -// SetSession method to set a API session id to use for api communication instead of credentials -// which is basically required in case you plan to use session based communication or if you want to use 2FA -func (s *Socketcfg) SetSession(sessionid string) { - s.login = "" - s.pw = "" - s.otp = "" - s.session = sessionid -} - -// SetUser method to set an user account (must be subuser account of your login user) to use for API communication -// use this if you want to make changes on that subuser account or if you want to have his data view -func (s *Socketcfg) SetUser(username string) { - s.user = username -} - -// EncodeData method to return the struct data ready to submit within POST request of type "application/x-www-form-urlencoded" -func (s *Socketcfg) EncodeData() string { +// GetPOSTData method to return the struct data ready to submit within +// POST request of type "application/x-www-form-urlencoded" +func (s *SocketConfig) GetPOSTData() string { var tmp strings.Builder + if len(s.entity) > 0 { + tmp.WriteString(url.QueryEscape("s_entity")) + tmp.WriteString("=") + tmp.WriteString(url.QueryEscape(s.entity)) + tmp.WriteString("&") + } if len(s.login) > 0 { tmp.WriteString(url.QueryEscape("s_login")) tmp.WriteString("=") tmp.WriteString(url.QueryEscape(s.login)) tmp.WriteString("&") } + if len(s.otp) > 0 { + tmp.WriteString(url.QueryEscape("s_otp")) + tmp.WriteString("=") + tmp.WriteString(url.QueryEscape(s.otp)) + tmp.WriteString("&") + } if len(s.pw) > 0 { tmp.WriteString(url.QueryEscape("s_pw")) tmp.WriteString("=") @@ -78,12 +70,6 @@ func (s *Socketcfg) EncodeData() string { tmp.WriteString(url.QueryEscape(s.remoteaddr)) tmp.WriteString("&") } - if len(s.entity) > 0 { - tmp.WriteString(url.QueryEscape("s_entity")) - tmp.WriteString("=") - tmp.WriteString(url.QueryEscape(s.entity)) - tmp.WriteString("&") - } if len(s.session) > 0 { tmp.WriteString(url.QueryEscape("s_session")) tmp.WriteString("=") @@ -96,11 +82,67 @@ func (s *Socketcfg) EncodeData() string { tmp.WriteString(url.QueryEscape(s.user)) tmp.WriteString("&") } - if len(s.otp) > 0 { - tmp.WriteString(url.QueryEscape("s_otp")) - tmp.WriteString("=") - tmp.WriteString(url.QueryEscape(s.otp)) - tmp.WriteString("&") - } return tmp.String() } + +// GetSession method to return the session id currently in use. +func (s *SocketConfig) GetSession() string { + return s.session +} + +// GetSystemEntity method to return the API system entity currently in use. +func (s *SocketConfig) GetSystemEntity() string { + return s.entity +} + +// SetLogin method to set username to use for api communication +func (s *SocketConfig) SetLogin(value string) *SocketConfig { + s.session = "" + s.login = value + return s +} + +// SetOTP method to set one time password to use for api communication +func (s *SocketConfig) SetOTP(value string) *SocketConfig { + s.session = "" + s.otp = value + return s +} + +// SetPassword method to set password to use for api communication +func (s *SocketConfig) SetPassword(value string) *SocketConfig { + s.session = "" + s.pw = value + return s +} + +// SetRemoteAddress method to set remote ip address to be submitted to the HEXONET API. +// This ip address is being considered when you have ip filter settings activated. +// To reset this, simply provide an empty string as parameter. +func (s *SocketConfig) SetRemoteAddress(value string) *SocketConfig { + s.remoteaddr = value + return s +} + +// SetSession method to set a API session id to use for api communication instead of credentials +// which is basically required in case you plan to use session based communication or if you want to use 2FA +func (s *SocketConfig) SetSession(sessionid string) *SocketConfig { + s.login = "" + s.pw = "" + s.otp = "" + s.session = sessionid + return s +} + +// SetSystemEntity method to set the system to use e.g. 1234 -> OT&E System, 54cd -> LIVE System +func (s *SocketConfig) SetSystemEntity(value string) *SocketConfig { + s.entity = value + return s +} + +// SetUser method to set an user account (must be subuser account of your login user) to use for API communication +// use this if you want to make changes on that subuser account or if you want to have his data view +func (s *SocketConfig) SetUser(username string) *SocketConfig { + s.user = username + return s +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 66ea385a8..9a8d00914 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -162,11 +162,15 @@ github.com/hashicorp/vault/sdk/helper/hclutil github.com/hashicorp/vault/sdk/helper/jsonutil github.com/hashicorp/vault/sdk/helper/parseutil github.com/hashicorp/vault/sdk/helper/strutil -# github.com/hexonet/go-sdk v1.2.1 -github.com/hexonet/go-sdk/client -github.com/hexonet/go-sdk/client/socketcfg -github.com/hexonet/go-sdk/response/hashresponse -github.com/hexonet/go-sdk/response/listresponse +# github.com/hexonet/go-sdk v2.2.3+incompatible +github.com/hexonet/go-sdk/apiclient +github.com/hexonet/go-sdk/column +github.com/hexonet/go-sdk/record +github.com/hexonet/go-sdk/response +github.com/hexonet/go-sdk/responseparser +github.com/hexonet/go-sdk/responsetemplate +github.com/hexonet/go-sdk/responsetemplatemanager +github.com/hexonet/go-sdk/socketconfig # github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af github.com/jmespath/go-jmespath # github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29