Compare commits
2 Commits
2302aa7ff8
...
1286338af0
Author | SHA1 | Date | |
---|---|---|---|
1286338af0 | |||
21a4ff3b3e |
|
@ -2,11 +2,17 @@ package reload
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/fthvgb1/wp-go/helper/number"
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/slice"
|
||||||
"github.com/fthvgb1/wp-go/safety"
|
"github.com/fthvgb1/wp-go/safety"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var calls []func()
|
type queue struct {
|
||||||
|
fn func()
|
||||||
|
order float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var calls []queue
|
||||||
|
|
||||||
var anyMap = safety.NewMap[string, any]()
|
var anyMap = safety.NewMap[string, any]()
|
||||||
|
|
||||||
|
@ -47,7 +53,7 @@ func GetAnyMapFnBys[K comparable, V, A any](namespace string, fn func(A) V) func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func safetyMapFn[K comparable, V, A any](namespace string) *safetyMap[K, V, A] {
|
func safetyMapFn[K comparable, V, A any](namespace string, order ...float64) *safetyMap[K, V, A] {
|
||||||
vv, ok := safetyMaps.Load(namespace)
|
vv, ok := safetyMaps.Load(namespace)
|
||||||
var m *safetyMap[K, V, A]
|
var m *safetyMap[K, V, A]
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -61,7 +67,7 @@ func safetyMapFn[K comparable, V, A any](namespace string) *safetyMap[K, V, A] {
|
||||||
m = &safetyMap[K, V, A]{safety.NewMap[K, V](), sync.Mutex{}}
|
m = &safetyMap[K, V, A]{safety.NewMap[K, V](), sync.Mutex{}}
|
||||||
Push(func() {
|
Push(func() {
|
||||||
m.val.Flush()
|
m.val.Flush()
|
||||||
})
|
}, order...)
|
||||||
safetyMaps.Store(namespace, m)
|
safetyMaps.Store(namespace, m)
|
||||||
}
|
}
|
||||||
safetyMapLock.Unlock()
|
safetyMapLock.Unlock()
|
||||||
|
@ -69,8 +75,8 @@ func safetyMapFn[K comparable, V, A any](namespace string) *safetyMap[K, V, A] {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn func(A) V) V {
|
func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn func(A) V, order ...float64) V {
|
||||||
m := safetyMapFn[K, V, A](namespace)
|
m := safetyMapFn[K, V, A](namespace, order...)
|
||||||
v, ok := m.val.Load(key)
|
v, ok := m.val.Load(key)
|
||||||
if ok {
|
if ok {
|
||||||
return v
|
return v
|
||||||
|
@ -87,7 +93,7 @@ func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn fun
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func anyVal[T, A any](namespace string, counter bool) *safetyVar[T, A] {
|
func anyVal[T, A any](namespace string, counter bool, order ...float64) *safetyVar[T, A] {
|
||||||
var vv *safetyVar[T, A]
|
var vv *safetyVar[T, A]
|
||||||
vvv, ok := safetyMaps.Load(namespace)
|
vvv, ok := safetyMaps.Load(namespace)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -105,7 +111,7 @@ func anyVal[T, A any](namespace string, counter bool) *safetyVar[T, A] {
|
||||||
vv = &safetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
|
vv = &safetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
|
||||||
Push(func() {
|
Push(func() {
|
||||||
vv.Val.Flush()
|
vv.Val.Flush()
|
||||||
})
|
}, getOrder(order...))
|
||||||
safetyMaps.Store(namespace, vv)
|
safetyMaps.Store(namespace, vv)
|
||||||
}
|
}
|
||||||
safetyMapLock.Unlock()
|
safetyMapLock.Unlock()
|
||||||
|
@ -113,8 +119,8 @@ func anyVal[T, A any](namespace string, counter bool) *safetyVar[T, A] {
|
||||||
return vv
|
return vv
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnyValBy[T, A any](namespace string, tryTimes int, a A, fn func(A) (T, bool)) T {
|
func GetAnyValBy[T, A any](namespace string, tryTimes int, a A, fn func(A) (T, bool), order ...float64) T {
|
||||||
var vv = anyVal[T, A](namespace, true)
|
var vv = anyVal[T, A](namespace, true, order...)
|
||||||
var ok bool
|
var ok bool
|
||||||
v := vv.Val.Load()
|
v := vv.Val.Load()
|
||||||
if v.ok {
|
if v.ok {
|
||||||
|
@ -136,8 +142,8 @@ func GetAnyValBy[T, A any](namespace string, tryTimes int, a A, fn func(A) (T, b
|
||||||
return v.v
|
return v.v
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) T) T {
|
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) T, order ...float64) T {
|
||||||
var vv = anyVal[T, A](namespace, false)
|
var vv = anyVal[T, A](namespace, false, order...)
|
||||||
v := vv.Val.Load()
|
v := vv.Val.Load()
|
||||||
if v.ok {
|
if v.ok {
|
||||||
return v.v
|
return v.v
|
||||||
|
@ -155,49 +161,69 @@ func GetAnyValBys[T, A any](namespace string, a A, fn func(A) T) T {
|
||||||
return v.v
|
return v.v
|
||||||
}
|
}
|
||||||
|
|
||||||
func Vars[T any](defaults T) *safety.Var[T] {
|
func Vars[T any](defaults T, order ...float64) *safety.Var[T] {
|
||||||
ss := safety.NewVar(defaults)
|
ss := safety.NewVar(defaults)
|
||||||
calls = append(calls, func() {
|
ord := getOrder(order...)
|
||||||
|
calls = append(calls, queue{func() {
|
||||||
ss.Store(defaults)
|
ss.Store(defaults)
|
||||||
})
|
}, ord})
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
func VarsBy[T any](fn func() T) *safety.Var[T] {
|
|
||||||
|
func getOrder(order ...float64) float64 {
|
||||||
|
var ord float64
|
||||||
|
if len(order) > 0 {
|
||||||
|
ord = order[0]
|
||||||
|
}
|
||||||
|
return ord
|
||||||
|
}
|
||||||
|
func VarsBy[T any](fn func() T, order ...float64) *safety.Var[T] {
|
||||||
ss := safety.NewVar(fn())
|
ss := safety.NewVar(fn())
|
||||||
calls = append(calls, func() {
|
ord := getOrder(order...)
|
||||||
ss.Store(fn())
|
calls = append(calls, queue{
|
||||||
|
func() {
|
||||||
|
ss.Store(fn())
|
||||||
|
}, ord,
|
||||||
})
|
})
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
func MapBy[K comparable, T any](fn func(*safety.Map[K, T])) *safety.Map[K, T] {
|
func MapBy[K comparable, T any](fn func(*safety.Map[K, T]), order ...float64) *safety.Map[K, T] {
|
||||||
m := safety.NewMap[K, T]()
|
m := safety.NewMap[K, T]()
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
fn(m)
|
fn(m)
|
||||||
}
|
}
|
||||||
calls = append(calls, func() {
|
ord := getOrder(order...)
|
||||||
m.Flush()
|
calls = append(calls, queue{
|
||||||
if fn != nil {
|
func() {
|
||||||
fn(m)
|
m.Flush()
|
||||||
}
|
if fn != nil {
|
||||||
|
fn(m)
|
||||||
|
}
|
||||||
|
}, ord,
|
||||||
})
|
})
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func SafeMap[K comparable, T any]() *safety.Map[K, T] {
|
func SafeMap[K comparable, T any](order ...float64) *safety.Map[K, T] {
|
||||||
m := safety.NewMap[K, T]()
|
m := safety.NewMap[K, T]()
|
||||||
calls = append(calls, func() {
|
ord := getOrder(order...)
|
||||||
|
calls = append(calls, queue{func() {
|
||||||
m.Flush()
|
m.Flush()
|
||||||
})
|
}, ord})
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func Push(fn ...func()) {
|
func Push(fn func(), order ...float64) {
|
||||||
calls = append(calls, fn...)
|
ord := getOrder(order...)
|
||||||
|
calls = append(calls, queue{fn, ord})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Reload() {
|
func Reload() {
|
||||||
|
slice.Sort(calls, func(i, j queue) bool {
|
||||||
|
return i.order > j.order
|
||||||
|
})
|
||||||
for _, call := range calls {
|
for _, call := range calls {
|
||||||
call()
|
call.fn()
|
||||||
}
|
}
|
||||||
anyMap.Flush()
|
anyMap.Flush()
|
||||||
safetyMaps.Flush()
|
safetyMaps.Flush()
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
var digestCache *cache.MapCache[uint64, string]
|
var digestCache *cache.MapCache[uint64, string]
|
||||||
|
@ -52,6 +53,10 @@ func Digests(content string, id uint64, limit int, fn func(id uint64, content, c
|
||||||
tag = "<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>"
|
tag = "<a><b><blockquote><br><cite><code><dd><del><div><dl><dt><em><h1><h2><h3><h4><h5><h6><i><img><li><ol><p><pre><span><strong><ul>"
|
||||||
}
|
}
|
||||||
content = digest.StripTags(content, tag)
|
content = digest.StripTags(content, tag)
|
||||||
|
length := utf8.RuneCountInString(content) + 1
|
||||||
|
if length <= limit {
|
||||||
|
return content
|
||||||
|
}
|
||||||
content, closeTag = digest.Html(content, limit)
|
content, closeTag = digest.Html(content, limit)
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
return PostsMore(id, content, closeTag)
|
return PostsMore(id, content, closeTag)
|
||||||
|
|
|
@ -126,3 +126,11 @@ func FileExist(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAnyVal[T any](v any, defaults T) T {
|
||||||
|
vv, ok := v.(T)
|
||||||
|
if !ok {
|
||||||
|
return defaults
|
||||||
|
}
|
||||||
|
return vv
|
||||||
|
}
|
||||||
|
|
|
@ -267,3 +267,16 @@ func TestGetValFromContext(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAnyVal(t *testing.T) {
|
||||||
|
t.Run("string", func(t *testing.T) {
|
||||||
|
want := "string"
|
||||||
|
if got := GetAnyVal(any("string"), "s"); !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetAnyVal() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
want = "s"
|
||||||
|
if got := GetAnyVal(any(1), "s"); !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetAnyVal() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
348
helper/httptool/http.go
Normal file
348
helper/httptool/http.go
Normal file
|
@ -0,0 +1,348 @@
|
||||||
|
package httptool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/maps"
|
||||||
|
"github.com/fthvgb1/wp-go/helper/number"
|
||||||
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetString(u string, q map[string]any, a ...any) (r string, code int, err error) {
|
||||||
|
res, err := Get(u, q, a...)
|
||||||
|
if res != nil {
|
||||||
|
code = res.StatusCode
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", code, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
rr, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", code, err
|
||||||
|
}
|
||||||
|
r = string(rr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Get(u string, q map[string]any, a ...any) (res *http.Response, err error) {
|
||||||
|
cli, req, err := GetClient(u, q, a...)
|
||||||
|
res, err = cli.Do(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetToJsonAny[T any](u string, q map[string]any, a ...any) (r T, code int, err error) {
|
||||||
|
rr, err := Get(u, q, a...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
code = rr.StatusCode
|
||||||
|
b, err := io.ReadAll(rr.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rr.Body.Close()
|
||||||
|
err = json.Unmarshal(b, &r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostWwwString(u string, form map[string]any, a ...any) (r string, code int, err error) {
|
||||||
|
rr, err := Post(u, 1, form, a...)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
code = rr.StatusCode
|
||||||
|
rs, err := io.ReadAll(rr.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", code, err
|
||||||
|
}
|
||||||
|
rr.Body.Close()
|
||||||
|
r = string(rs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func PostFormDataString(u string, form map[string]any, a ...any) (r string, code int, err error) {
|
||||||
|
rr, err := Post(u, 2, form, a...)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
code = rr.StatusCode
|
||||||
|
rs, err := io.ReadAll(rr.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", code, err
|
||||||
|
}
|
||||||
|
rr.Body.Close()
|
||||||
|
r = string(rs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetClient(u string, q map[string]any, a ...any) (res *http.Client, req *http.Request, err error) {
|
||||||
|
parse, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
cli := http.Client{}
|
||||||
|
values := parse.Query()
|
||||||
|
setValue(q, values)
|
||||||
|
parse.RawQuery = values.Encode()
|
||||||
|
req = &http.Request{
|
||||||
|
Method: "GET",
|
||||||
|
URL: parse,
|
||||||
|
}
|
||||||
|
setArgs(&cli, req, a...)
|
||||||
|
return &cli, req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post request
|
||||||
|
//
|
||||||
|
// u url
|
||||||
|
//
|
||||||
|
// types 1 x-www-form-urlencoded, 2 form-data, 3 json, 4 binary
|
||||||
|
func Post(u string, types int, form map[string]any, a ...any) (res *http.Response, err error) {
|
||||||
|
cli, req, err := PostClient(u, types, form, a...)
|
||||||
|
res, err = cli.Do(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostClient(u string, types int, form map[string]any, a ...any) (cli *http.Client, req *http.Request, err error) {
|
||||||
|
parse, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cli = &http.Client{}
|
||||||
|
req = &http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: parse,
|
||||||
|
Header: http.Header{},
|
||||||
|
}
|
||||||
|
switch types {
|
||||||
|
case 1:
|
||||||
|
values := url.Values{}
|
||||||
|
setValue(form, values)
|
||||||
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
b := strings.NewReader(values.Encode())
|
||||||
|
req.Body = io.NopCloser(b)
|
||||||
|
case 2:
|
||||||
|
payload := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(payload)
|
||||||
|
err = setFormData(form, writer)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Body = io.NopCloser(payload)
|
||||||
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
|
case 3:
|
||||||
|
fo, err := json.Marshal(form)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
b := bytes.NewReader(fo)
|
||||||
|
req.Body = io.NopCloser(b)
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
case 4:
|
||||||
|
b, ok := maps.GetStrAnyVal[[]byte](form, "binary")
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, errors.New("no binary value")
|
||||||
|
}
|
||||||
|
req.Body = io.NopCloser(bytes.NewReader(b))
|
||||||
|
req.Header.Add("Content-Type", "application/octet-stream")
|
||||||
|
}
|
||||||
|
setArgs(cli, req, a...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostToJsonAny[T any](u string, types int, form map[string]any, a ...any) (r T, code int, err error) {
|
||||||
|
rr, err := Post(u, types, form, a...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
code = rr.StatusCode
|
||||||
|
b, err := io.ReadAll(rr.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rr.Body.Close()
|
||||||
|
err = json.Unmarshal(b, &r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func setArgs(cli *http.Client, req *http.Request, a ...any) {
|
||||||
|
if len(a) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, arg := range a {
|
||||||
|
h, ok := arg.(map[string]string)
|
||||||
|
if ok && len(h) > 0 {
|
||||||
|
for k, v := range h {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hh, ok := arg.(http.Header)
|
||||||
|
if ok {
|
||||||
|
req.Header = hh
|
||||||
|
}
|
||||||
|
t, ok := arg.(time.Duration)
|
||||||
|
if ok {
|
||||||
|
cli.Timeout = t
|
||||||
|
}
|
||||||
|
checkRedirect, ok := arg.(func(req *http.Request, via []*http.Request) error)
|
||||||
|
if ok {
|
||||||
|
cli.CheckRedirect = checkRedirect
|
||||||
|
}
|
||||||
|
jar, ok := arg.(http.CookieJar)
|
||||||
|
if ok {
|
||||||
|
cli.Jar = jar
|
||||||
|
}
|
||||||
|
c, ok := arg.(string)
|
||||||
|
if ok && c != "" {
|
||||||
|
req.Header.Add("cookie", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func set[T constraints.Integer | constraints.Float](a []T, k string, values url.Values) {
|
||||||
|
if !strings.Contains(k, "[]") {
|
||||||
|
k = str.Join(k, "[]")
|
||||||
|
}
|
||||||
|
for _, vv := range a {
|
||||||
|
values.Add(k, number.ToString(vv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFormData(m map[string]any, values *multipart.Writer) (err error) {
|
||||||
|
for k, v := range m {
|
||||||
|
switch v.(type) {
|
||||||
|
case *os.File:
|
||||||
|
f := v.(*os.File)
|
||||||
|
if f == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ff, err := values.CreateFormFile(k, f.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(ff, f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
err = values.WriteField(k, v.(string))
|
||||||
|
case int64, int, int8, int32, int16, uint64, uint, uint8, uint32, uint16, float32, float64:
|
||||||
|
err = values.WriteField(k, fmt.Sprintf("%v", v))
|
||||||
|
case []string:
|
||||||
|
if !strings.Contains(k, "[]") {
|
||||||
|
k = str.Join(k, "[]")
|
||||||
|
}
|
||||||
|
for _, vv := range v.([]string) {
|
||||||
|
err = values.WriteField(k, vv)
|
||||||
|
}
|
||||||
|
case *[]string:
|
||||||
|
if !strings.Contains(k, "[]") {
|
||||||
|
k = str.Join(k, "[]")
|
||||||
|
}
|
||||||
|
for _, vv := range *(v.(*[]string)) {
|
||||||
|
err = values.WriteField(k, vv)
|
||||||
|
}
|
||||||
|
case []int64:
|
||||||
|
err = sets(v.([]int64), k, values)
|
||||||
|
case []int:
|
||||||
|
err = sets(v.([]int), k, values)
|
||||||
|
case []int8:
|
||||||
|
err = sets(v.([]int8), k, values)
|
||||||
|
case []int16:
|
||||||
|
err = sets(v.([]int16), k, values)
|
||||||
|
case []int32:
|
||||||
|
err = sets(v.([]int32), k, values)
|
||||||
|
case []uint64:
|
||||||
|
err = sets(v.([]uint64), k, values)
|
||||||
|
case []uint:
|
||||||
|
err = sets(v.([]uint), k, values)
|
||||||
|
case []uint8:
|
||||||
|
err = sets(v.([]uint8), k, values)
|
||||||
|
case []uint16:
|
||||||
|
err = sets(v.([]uint16), k, values)
|
||||||
|
case []uint32:
|
||||||
|
err = sets(v.([]uint32), k, values)
|
||||||
|
case []float32:
|
||||||
|
err = sets(v.([]float32), k, values)
|
||||||
|
case []float64:
|
||||||
|
err = sets(v.([]float64), k, values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sets[T constraints.Integer | constraints.Float](a []T, k string, values *multipart.Writer) error {
|
||||||
|
if !strings.Contains(k, "[]") {
|
||||||
|
k = str.Join(k, "[]")
|
||||||
|
}
|
||||||
|
for _, vv := range a {
|
||||||
|
err := values.WriteField(k, number.ToString(vv))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setValue(m map[string]any, values url.Values) {
|
||||||
|
for k, v := range m {
|
||||||
|
switch v.(type) {
|
||||||
|
case string:
|
||||||
|
values.Add(k, v.(string))
|
||||||
|
case int64, int, int8, int32, int16, uint64, uint, uint8, uint32, uint16, float32, float64:
|
||||||
|
values.Add(k, fmt.Sprintf("%v", v))
|
||||||
|
case []string:
|
||||||
|
if !strings.Contains(k, "[]") {
|
||||||
|
k = str.Join(k, "[]")
|
||||||
|
}
|
||||||
|
for _, vv := range v.([]string) {
|
||||||
|
values.Add(k, vv)
|
||||||
|
}
|
||||||
|
case *[]string:
|
||||||
|
if !strings.Contains(k, "[]") {
|
||||||
|
k = str.Join(k, "[]")
|
||||||
|
}
|
||||||
|
for _, vv := range *(v.(*[]string)) {
|
||||||
|
values.Add(k, vv)
|
||||||
|
}
|
||||||
|
case []int64:
|
||||||
|
set(v.([]int64), k, values)
|
||||||
|
case []int:
|
||||||
|
set(v.([]int), k, values)
|
||||||
|
case []int8:
|
||||||
|
set(v.([]int8), k, values)
|
||||||
|
case []int16:
|
||||||
|
set(v.([]int16), k, values)
|
||||||
|
case []int32:
|
||||||
|
set(v.([]int32), k, values)
|
||||||
|
case []uint64:
|
||||||
|
set(v.([]uint64), k, values)
|
||||||
|
case []uint:
|
||||||
|
set(v.([]uint), k, values)
|
||||||
|
case []uint8:
|
||||||
|
set(v.([]uint8), k, values)
|
||||||
|
case []uint16:
|
||||||
|
set(v.([]uint16), k, values)
|
||||||
|
case []uint32:
|
||||||
|
set(v.([]uint32), k, values)
|
||||||
|
case []float32:
|
||||||
|
set(v.([]float32), k, values)
|
||||||
|
case []float64:
|
||||||
|
set(v.([]float64), k, values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
255
helper/httptool/http_test.go
Normal file
255
helper/httptool/http_test.go
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
package httptool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetString(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
|
q map[string]any
|
||||||
|
timeout int64
|
||||||
|
a []any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantR string
|
||||||
|
wantCode int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "wp.test",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test",
|
||||||
|
q: map[string]any{
|
||||||
|
"p": "2",
|
||||||
|
"XDEBUG_SESSION_START": "34343",
|
||||||
|
"a": []int{2, 3},
|
||||||
|
},
|
||||||
|
timeout: 3,
|
||||||
|
},
|
||||||
|
wantR: `{"XDEBUG_SESSION_START":"34343","p":"2"}`,
|
||||||
|
wantCode: 200,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotR, gotCode, err := GetString(tt.args.u, tt.args.q, tt.args.a...)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetString() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotR != tt.wantR {
|
||||||
|
t.Errorf("GetString() gotR = %v, want %v", gotR, tt.wantR)
|
||||||
|
}
|
||||||
|
if gotCode != tt.wantCode {
|
||||||
|
t.Errorf("GetString() gotCode = %v, want %v", gotCode, tt.wantCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostWwwString(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
|
form map[string]any
|
||||||
|
timeout int64
|
||||||
|
a []any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantRes string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test?XDEBUG_SESSION_START=34244",
|
||||||
|
form: map[string]any{
|
||||||
|
"aa": "bb",
|
||||||
|
"bb[]": []int{1, 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotRes, _, err := PostWwwString(tt.args.u, tt.args.form, tt.args.a...)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Post() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotRes, tt.wantRes) {
|
||||||
|
t.Errorf("Post() gotRes = %v, want %v", gotRes, tt.wantRes)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPost(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
|
types int
|
||||||
|
form map[string]any
|
||||||
|
timeout int64
|
||||||
|
a []any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantRes *http.Response
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "form-data",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test?XDEBUG_SESSION_START=3424",
|
||||||
|
types: 3,
|
||||||
|
form: map[string]any{
|
||||||
|
"ff": "xxxff",
|
||||||
|
},
|
||||||
|
timeout: 0,
|
||||||
|
a: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "raw-json",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test?XDEBUG_SESSION_START=3424",
|
||||||
|
types: 3,
|
||||||
|
form: map[string]any{
|
||||||
|
"ff": "xxxff",
|
||||||
|
"kk": 1,
|
||||||
|
},
|
||||||
|
timeout: 0,
|
||||||
|
a: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "binary",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test?XDEBUG_SESSION_START=3424",
|
||||||
|
types: 4,
|
||||||
|
form: map[string]any{
|
||||||
|
"binary": []byte("ssssskkkkkk"),
|
||||||
|
},
|
||||||
|
a: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotRes, err := Post(tt.args.u, tt.args.types, tt.args.form, tt.args.a...)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Post() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotRes, tt.wantRes) {
|
||||||
|
t.Errorf("Post() gotRes = %v, want %v", gotRes, tt.wantRes)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type res struct {
|
||||||
|
Code int `json:"Code,omitempty"`
|
||||||
|
Message string `json:"Message" json:"Message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostToJsonAny(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
|
types int
|
||||||
|
form map[string]any
|
||||||
|
a []any
|
||||||
|
}
|
||||||
|
type testCase[T any] struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantR T
|
||||||
|
wantCode int
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []testCase[res]{
|
||||||
|
{
|
||||||
|
name: "res",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test?XDEBUG_SESSION_START=3424",
|
||||||
|
types: 1,
|
||||||
|
a: []any{3 * time.Second, map[string]string{"user-agent": "httptool"}},
|
||||||
|
},
|
||||||
|
wantR: res{
|
||||||
|
200, "ok",
|
||||||
|
},
|
||||||
|
wantCode: 200,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotR, gotCode, err := PostToJsonAny[res](tt.args.u, tt.args.types, tt.args.form, tt.args.a...)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("PostToJsonAny() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotR, tt.wantR) {
|
||||||
|
t.Errorf("PostToJsonAny() gotR = %v, want %v", gotR, tt.wantR)
|
||||||
|
}
|
||||||
|
if gotCode != tt.wantCode {
|
||||||
|
t.Errorf("PostToJsonAny() gotCode = %v, want %v", gotCode, tt.wantCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetToJsonAny(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
|
q map[string]any
|
||||||
|
a []any
|
||||||
|
}
|
||||||
|
type testCase[T any] struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantR T
|
||||||
|
wantCode int
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
tests := []testCase[res]{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args{
|
||||||
|
u: "http://wp.test?XDEBUG_SESSION_START=3424",
|
||||||
|
q: map[string]any{
|
||||||
|
"jjj": "ssss",
|
||||||
|
"fff": []int{1, 2, 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantR: res{
|
||||||
|
200, "ok",
|
||||||
|
},
|
||||||
|
wantCode: 200,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotR, gotCode, err := GetToJsonAny[res](tt.args.u, tt.args.q, tt.args.a...)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetToJsonAny() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotR, tt.wantR) {
|
||||||
|
t.Errorf("GetToJsonAny() gotR = %v, want %v", gotR, tt.wantR)
|
||||||
|
}
|
||||||
|
if gotCode != tt.wantCode {
|
||||||
|
t.Errorf("GetToJsonAny() gotCode = %v, want %v", gotCode, tt.wantCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ func (r anyArr[T]) Less(i, j int) bool {
|
||||||
return r.fn(r.data[i], r.data[j])
|
return r.fn(r.data[i], r.data[j])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort fn 中i>j 为降序,反之为升序
|
// Sort fn i>j 为降序 desc,反之为升序 asc
|
||||||
func Sort[T any](arr []T, fn func(i, j T) bool) {
|
func Sort[T any](arr []T, fn func(i, j T) bool) {
|
||||||
slice := anyArr[T]{
|
slice := anyArr[T]{
|
||||||
data: arr,
|
data: arr,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user