diff --git a/date_util.go b/date_util.go new file mode 100644 index 0000000..285a059 --- /dev/null +++ b/date_util.go @@ -0,0 +1,41 @@ +package webutility + +import ( + "fmt" + "time" +) + +const ( + YYYYMMDD_sl = "2006/01/02" + YYYYMMDD_ds = "2006-01-02" + YYYYMMDD_dt = "2006.01.02." + + DDMMYYYY_sl = "02/01/2006" + DDMMYYYY_ds = "02-01-2006" + DDMMYYYY_dt = "02.01.2006." + + YYYYMMDD_HHMMSS_sl = "2006/01/02 15:04:05" + YYYYMMDD_HHMMSS_ds = "2006-01-02 15:04:05" + YYYYMMDD_HHMMSS_dt = "2006.01.02. 15:04:05" + + DDMMYYYY_HHMMSS_sl = "02/01/2006 15:04:05" + DDMMYYYY_HHMMSS_ds = "02-01-2006 15:04:05" + DDMMYYYY_HHMMSS_dt = "02.01.2006. 15:04:05" +) + +func Systime() int64 { + return time.Now().Unix() +} + +func DateToEpoch(date, format string) int64 { + t, err := time.Parse(format, date) + if err != nil { + fmt.Println(err.Error()) + return 0 + } + return t.Unix() +} + +func EpochToDate(e int64, format string) string { + return time.Unix(e, 0).Format(format) +} diff --git a/filtering.go b/filtering.go index 2fe650d..41a4504 100644 --- a/filtering.go +++ b/filtering.go @@ -1,7 +1,6 @@ package webutility import ( - "fmt" "net/http" "net/url" "strings" @@ -37,7 +36,7 @@ func (f Filter) ValueAt(val string, index int) string { return "" } -func (f Filter) validate(validFilters []string) (Filter, bool) { +func (f Filter) Validate(validFilters []string) (Filter, bool) { goodFilters := make(Filter) cnt, len := 0, 0 for fi := range f { @@ -82,53 +81,3 @@ func ParseFilters(req *http.Request, header string) (filters Filter) { return filters } - -// MakeFilterString is very dodgy, needs more robustness. -// TODO(marko) -func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) { - if prefix != "" { - prefix += "." - } - - if filters.Count() == 0 { - return "", true - } - - filters, ok = filters.validate(validFilters) - if !ok { - return "", false - } - - first := true - for k, filter := range filters { - symbol := "=" - - if first { - res += " where " - first = false - } else { - res += " and " - } - - res += "(" - for i, f := range filter { - if strings.HasPrefix(f, "<") || strings.HasPrefix(f, ">") || strings.HasPrefix(f, "!") { - symbol = string(f[0]) - f = strings.TrimLeft(f, "<>!") - if strings.HasPrefix(f, "=") { - f = strings.TrimLeft(f, "=") - symbol += "=" - } - } - - res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, f) - - if i < len(filter)-1 { - res += " or " - } - } - res += ")" - } - - return res, ok -} diff --git a/float_util.go b/float_util.go new file mode 100644 index 0000000..851e210 --- /dev/null +++ b/float_util.go @@ -0,0 +1,59 @@ +package webutility + +import ( + "fmt" + "math" + "math/big" +) + +func RoundFloat64(f float64, dec int) float64 { + p := math.Pow(10, float64(dec)) + return math.Round(f*p) / p +} + +func NewBF(f float64, prec uint) *big.Float { + x := big.NewFloat(f) + x.SetPrec(prec) + return x +} + +func AddBF(x, y *big.Float) *big.Float { + z := big.NewFloat(0.0) + z.SetPrec(x.Prec()) + z.Add(x, y) + return z +} + +func SubBF(x, y *big.Float) *big.Float { + z := big.NewFloat(0.0) + z.SetPrec(x.Prec()) + + yneg := big.NewFloat(0.0) + yneg.Neg(y) + + z.Add(x, yneg) + return z +} + +func MulBF(x, y *big.Float) *big.Float { + z := big.NewFloat(0.0) + z.SetPrec(x.Prec()) + z.Mul(x, y) + return z +} + +func DivBF(x, y *big.Float) *big.Float { + z := big.NewFloat(0.0) + z.SetPrec(x.Prec()) + z.Quo(x, y) + return z +} + +func BFtoFloat(f *big.Float) float64 { + v, _ := f.Float64() + return v +} + +func Float64ToString(f float64) string { + return fmt.Sprintf("%.2f", f) +} diff --git a/int_util.go b/int_util.go index 39eea76..bf0d5bd 100644 --- a/int_util.go +++ b/int_util.go @@ -2,7 +2,6 @@ package webutility import ( "fmt" - "strconv" ) // ClampInt64 ... @@ -21,18 +20,6 @@ func InRangeInt64(v, min, max int64) bool { return (v >= min && v <= max) } -// StringToInt64 ... -func StringToInt64(s string) int64 { - i, _ := strconv.ParseInt(s, 10, 64) - return i -} - -// StringToFloat64 ... -func StringToFloat64(s string) float64 { - f, _ := strconv.ParseFloat(s, 64) - return f -} - // Int64ToString ... func Int64ToString(i int64) string { return fmt.Sprintf("%d", i) @@ -51,10 +38,11 @@ func Int64ToBool(i int64) bool { return i != 0 } -func StringToValidInt64(s string) (int64, bool) { - i, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return i, false +func MaxInt(vars ...int) (max int) { + for _, v := range vars { + if v > max { + max = v + } } - return i, true + return max } diff --git a/middleware/main.go b/middleware/main.go index be51d77..d505a2f 100644 --- a/middleware/main.go +++ b/middleware/main.go @@ -4,6 +4,8 @@ import ( "fmt" "io/ioutil" "net/http" + "os" + "strings" web "git.to-net.rs/marko.tikvic/webutility" ) @@ -27,54 +29,103 @@ func LogTraffic(h http.HandlerFunc) http.HandlerFunc { func TrafficLogsHandler(w http.ResponseWriter, req *http.Request) { switch req.Method { case "GET": - files, err := ioutil.ReadDir(httpLogger.GetOutDir() + "/") - if err != nil { - web.InternalServerError(w, req, err.Error()) - return - } + logfile := req.FormValue("logfile") + if logfile == "" { + files, err := ioutil.ReadDir(httpLogger.GetOutDir() + "/") + if err != nil { + web.InternalServerError(w, req, err.Error()) + return + } - web.SetContentType(w, "text/html; charset=utf-8") - web.SetResponseStatus(w, http.StatusOK) - - web.WriteResponse(w, []byte("")) - inputForm := ` -
-
- Username:
-
- Password:
-
- Log:
-
- -
-
` - web.WriteResponse(w, []byte(inputForm)) - - web.WriteResponse(w, []byte("")) - web.WriteResponse(w, []byte("")) - for i := range files { - name := files[i].Name() - size := files[i].Size() - div := fmt.Sprintf(``, name, size) - web.WriteResponse(w, []byte(div)) - } - web.WriteResponse(w, []byte("
NameSize
%s%dB
")) + errorLogs := make([]os.FileInfo, 0) + httpLogs := make([]os.FileInfo, 0) - case "POST": - web.SetContentType(w, "text/html; charset=utf-8") + var errorLogsCount, httpLogsCount int + for _, f := range files { + if strings.HasPrefix(f.Name(), "err") { + errorLogs = append(errorLogs, f) + errorLogsCount++ + } else if strings.HasPrefix(f.Name(), "http") { + httpLogs = append(httpLogs, f) + httpLogsCount++ + } + } - logfile := req.FormValue("logfile") - content, err := web.ReadFileContent(httpLogger.GetOutDir() + "/" + logfile) - if err != nil { - web.InternalServerError(w, req, err.Error()) - return + web.SetContentType(w, "text/html; charset=utf-8") + web.SetResponseStatus(w, http.StatusOK) + + web.WriteResponse(w, []byte(` + + + + + + + `)) + + var ( + div, name string + size int64 + ) + + max := errorLogsCount + if httpLogsCount > errorLogsCount { + max = httpLogsCount + } + + for i := 0; i < max; i++ { + div = "" + + if i < errorLogsCount { + name = errorLogs[i].Name() + size = errorLogs[i].Size() + div += fmt.Sprintf(` + + `, + name, name, size, + ) + } else { + div += fmt.Sprintf(``) + } + + div += "" + + if i < httpLogsCount { + name := httpLogs[i].Name() + size := httpLogs[i].Size() + div += fmt.Sprintf(` + + `, + name, name, size, + ) + } else { + div += fmt.Sprintf(``) + } + + div += "" + web.WriteResponse(w, []byte(div)) + } + web.WriteResponse(w, []byte("
Error logs Traffic logs
+ %s + + %dB + %s + %dB
")) + } else { + content, err := web.ReadFileContent(httpLogger.GetOutDir() + "/" + logfile) + if err != nil { + web.InternalServerError(w, req, err.Error()) + return + } + web.SetResponseStatus(w, http.StatusOK) + web.WriteResponse(w, []byte("")) + web.WriteResponse(w, []byte("
"))
+			web.WriteResponse(w, content)
+			web.WriteResponse(w, []byte("
")) } - web.SetResponseStatus(w, http.StatusOK) - web.WriteResponse(w, []byte("")) - web.WriteResponse(w, []byte("
"))
-		web.WriteResponse(w, content)
-		web.WriteResponse(w, []byte("
")) - return } } diff --git a/nullables.go b/nullables.go index a6b2a19..681ff43 100644 --- a/nullables.go +++ b/nullables.go @@ -123,6 +123,14 @@ func (ni *NullInt64) Scan(value interface{}) error { return nil } +// ScanPtr ... +func (ni *NullInt64) ScanPtr(v interface{}) error { + if ip, ok := v.(*int64); ok && ip != nil { + return ni.Scan(*ip) + } + return nil +} + // Value ... func (ni *NullInt64) Value() (driver.Value, error) { if !ni.Valid { @@ -173,6 +181,14 @@ func (nf *NullFloat64) Scan(value interface{}) error { return nil } +// ScanPtr ... +func (nf *NullFloat64) ScanPtr(v interface{}) error { + if fp, ok := v.(*float64); ok && fp != nil { + return nf.Scan(*fp) + } + return nil +} + // Value ... func (nf *NullFloat64) Value() (driver.Value, error) { if !nf.Valid { diff --git a/payload.go b/payload.go index 784d900..24863a8 100644 --- a/payload.go +++ b/payload.go @@ -51,13 +51,13 @@ type Translation struct { // Payload ... type Payload struct { Method string `json:"method"` - Params map[string]string `json:"params"` - Lang []Translation `json:"lang"` - Fields []Field `json:"fields"` - Correlations []CorrelationField `json:"correlationFields"` - IDField string `json:"idField"` + Params map[string]string `json:"params,omitempty"` + Lang []Translation `json:"lang,omitempty"` + Fields []Field `json:"fields,omitempty"` + Correlations []CorrelationField `json:"correlationFields,omitempty"` + IDField string `json:"idField,omitempty"` - Links PaginationLinks `json:"_links"` + Links PaginationLinks `json:"_links,omitempty"` // Data holds JSON payload. It can't be used for itteration. Data interface{} `json:"data"` diff --git a/quicksort.go b/quicksort.go index ba627fb..f1f2964 100644 --- a/quicksort.go +++ b/quicksort.go @@ -3,8 +3,8 @@ package webutility type QSortDirection int const ( - QSortAscending = 0 - QSortDescending = 1 + QSortAscending QSortDirection = iota + QSortDescending ) // QuickSortable is an interface for quicksorting slices. @@ -30,19 +30,22 @@ func Quicksort(que QuickSortable, low, high int, dir QSortDirection) { } func partition(que QuickSortable, low, high int, dir QSortDirection) int { + swap := 0 + // -1 -> i > j + // 1 -> i < j + if dir == QSortDescending { + swap = -1 + } else { + swap = 1 + } + i := low - 1 for j := low; j <= high-1; j++ { - if dir == QSortAscending { - if que.Compare(j, high) == -1 { - i++ - que.Swap(i, j) - } - } else if dir == QSortDescending { - if que.Compare(j, high) == 1 { - i++ - que.Swap(i, j) - } + if que.Compare(j, high) == swap { + i++ + que.Swap(i, j) } + continue } que.Swap(i+1, high) return i + 1 diff --git a/string_util.go b/string_util.go index 32d5117..cf9b555 100644 --- a/string_util.go +++ b/string_util.go @@ -22,13 +22,14 @@ func IsWrappedWith(src, begin, end string) bool { // ParseInt64Arr ... func ParseInt64Arr(s, sep string) (arr []int64) { s = strings.TrimSpace(s) - if s != "" { - parts := strings.Split(s, sep) - arr = make([]int64, len(parts)) - for i, p := range parts { - num := StringToInt64(p) - arr[i] = num - } + if s == "" { + return + } + parts := strings.Split(s, sep) + arr = make([]int64, len(parts)) + for i, p := range parts { + num := StringToInt64(p) + arr[i] = num } return arr @@ -174,6 +175,14 @@ func LimitMSWordTextWithThreeDots(txt string, maxLen int) string { return txt[:maxLen] + "..." } +func ThreeDots(txt string, maxLen int) string { + if len(txt) <= maxLen { + return txt + } + + return txt[:maxLen] + "..." +} + // SplitStringAtWholeWords ... func SplitStringAtWholeWords(s string, maxLen int) (res []string) { parts := strings.Split(s, " ") @@ -197,3 +206,23 @@ func SplitStringAtWholeWords(s string, maxLen int) (res []string) { return res } + +// StringToInt64 ... +func StringToInt64(s string) int64 { + i, _ := strconv.ParseInt(s, 10, 64) + return i +} + +// StringToFloat64 ... +func StringToFloat64(s string) float64 { + f, _ := strconv.ParseFloat(s, 64) + return f +} + +func StringToValidInt64(s string) (int64, bool) { + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return i, false + } + return i, true +}