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 := `
-
-
-
`
- web.WriteResponse(w, []byte(inputForm))
-
- web.WriteResponse(w, []byte(""))
- web.WriteResponse(w, []byte("Name | Size |
"))
- for i := range files {
- name := files[i].Name()
- size := files[i].Size()
- div := fmt.Sprintf(`%s | %dB |
`, name, size)
- web.WriteResponse(w, []byte(div))
- }
- web.WriteResponse(w, []byte("
"))
+ 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(`
+
+
+
+ Error logs | | |
+ Traffic logs | |
+
+ `))
+
+ 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(`
+
+ %s
+
+ |
+ %dB | `,
+ name, name, size,
+ )
+ } else {
+ div += fmt.Sprintf(` | | `)
+ }
+
+ div += " | "
+
+ if i < httpLogsCount {
+ name := httpLogs[i].Name()
+ size := httpLogs[i].Size()
+ div += fmt.Sprintf(`
+
+ %s
+ |
+ %dB | `,
+ name, name, size,
+ )
+ } else {
+ div += fmt.Sprintf(` | | `)
+ }
+
+ div += "
"
+ web.WriteResponse(w, []byte(div))
+ }
+ web.WriteResponse(w, []byte("
"))
+ } 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
+}