1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00
Files
stackexchange-dnscontrol/vendor/github.com/hexonet/go-sdk/response/hashresponse/hashresponse.go
2018-08-30 08:54:42 -04:00

367 lines
9.8 KiB
Go

// 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
}