1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-15 10:12:29 +08:00

Compare commits

..

16 Commits

Author SHA1 Message Date
dudaodong
068c878d1e release v2.1.2 2022-07-13 10:40:03 +08:00
dudaodong
47b2402345 docs: update readme file add new functions 2022-07-13 10:32:03 +08:00
dudaodong
a245716f99 docs: add doc for new function: ToChannel ToMap MapToSlice 2022-07-13 10:26:49 +08:00
dudaodong
71c85bb8f0 docs: add doc for functions GetRequestPublicIp and IsInternalIP 2022-07-13 10:09:23 +08:00
dudaodong
5edafec393 Merge branch 'main' into v2 2022-07-13 09:55:04 +08:00
tangqiu0205
957878dd98 feat: add func GetRequestPublicIp and IsInternalIP (#40)
* add: add func GetRequestPublicIp and IsInternalIP

* fix: fix test fileutil fail

Co-authored-by: zhanghu <305835360@qq.com>
2022-07-13 09:52:35 +08:00
dudaodong
12e979cf3c feat: add ToMapToSlice function 2022-07-11 11:28:46 +08:00
dudaodong
ded42f8ff5 feat: add ToChannel function 2022-07-11 11:11:16 +08:00
dudaodong
d06cde3fcf feat: add ToMap function 2022-07-11 10:27:38 +08:00
dudaodong
9cd8bfb8e0 docs: compress log png 2022-07-08 10:52:53 +08:00
dudaodong
51c9877224 docs: update change param type to for some slice functions 2022-07-07 17:47:02 +08:00
dudaodong
f7f6427919 merge main branch 2022-07-07 16:35:46 +08:00
tangqiu0205
56b6844a2d update: update type constraint any -> Comparable. (#37)
* update: update type constraint any -> Comparable.

* update: update type constraint any -> Comparable.

Co-authored-by: zhanghu <305835360@qq.com>
2022-07-07 16:31:48 +08:00
dudaodong
cce56f0479 docs: update query string type in http request 2022-07-07 11:21:16 +08:00
dudaodong
3dbd7d8980 fix: sending post request with header multipart/form-data support query string type is map[string]string 2022-07-07 10:23:15 +08:00
dudaodong
3625921912 fix: fix missused function ToSlice -> ToSlicePointer 2022-07-06 11:31:11 +08:00
18 changed files with 602 additions and 74 deletions

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.1-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -118,12 +118,15 @@ import "github.com/duke-git/lancet/v2/convertor"
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChar)
- [ToChannel](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToChannel)
- [ToFloat](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToFloat)
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToJson)
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToMap)
- [ToPointer](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToPointer)
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#MapToSlice)
### 4. Cryptor package is for data encryption and decryption.
@@ -324,7 +327,9 @@ import "github.com/duke-git/lancet/v2/netutil"
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo)
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetRequestPublicIp)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.1-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -117,13 +117,15 @@ import "github.com/duke-git/lancet/v2/convertor"
- [ToBool](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBool)
- [ToBytes](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToBytes)
- [ToChar](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChar)
- [ToChannel](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToChannel)
- [ToFloat](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToFloat)
- [ToInt](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInt)
- [ToJson](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToJson)
- [ToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToMap)
- [ToPointer](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToPointer)
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#MapToSlice)
### 4. cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
```go
@@ -321,7 +323,9 @@ import "github.com/duke-git/lancet/v2/netutil"
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetPublicIpInfo)
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetRequestPublicIp)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)

View File

@@ -74,6 +74,20 @@ func ToChar(s string) []string {
return c
}
// ToChannel convert a array of elements to a read-only channels
func ToChannel[T any](array []T) <-chan T {
ch := make(chan T)
go func() {
for _, item := range array {
ch <- item
}
close(ch)
}()
return ch
}
// ToString convert value to string
func ToString(value any) string {
res := ""
@@ -175,6 +189,17 @@ func ToPointer[T any](value T) *T {
return &value
}
// ToMap convert a slice or an array of structs to a map based on iteratee function
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
res := make(map[K]V, len(array))
for _, item := range array {
k, v := iteratee(item)
res[k] = v
}
return res
}
// StructToMap convert struct to map, only convert exported struct field
// map key is specified same as struct field tag `json` value
func StructToMap(value any) (map[string]any, error) {
@@ -205,6 +230,17 @@ func StructToMap(value any) (map[string]any, error) {
return res, nil
}
// MapToSlice convert a map to a slice based on iteratee function
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
res := make([]T, 0, len(aMap))
for k, v := range aMap {
res = append(res, iteratee(k, v))
}
return res
}
// ColorHexToRGB convert hex color to rgb color
func ColorHexToRGB(colorHex string) (red, green, blue int) {
colorHex = strings.TrimPrefix(colorHex, "#")

View File

@@ -2,6 +2,7 @@ package convertor
import (
"fmt"
"strconv"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -21,6 +22,23 @@ func TestToChar(t *testing.T) {
}
}
func TestToChannel(t *testing.T) {
assert := internal.NewAssert(t, "TestToChannel")
ch := ToChannel([]int{1, 2, 3})
val1, _ := <-ch
assert.Equal(1, val1)
val2, _ := <-ch
assert.Equal(2, val2)
val3, _ := <-ch
assert.Equal(3, val3)
_, ok := <-ch
assert.Equal(false, ok)
}
func TestToBool(t *testing.T) {
assert := internal.NewAssert(t, "TestToBool")
@@ -142,6 +160,25 @@ func TestToJson(t *testing.T) {
assert.Equal("{\"Name\":\"TestStruct\"}", structJsonStr)
}
func TestToMap(t *testing.T) {
assert := internal.NewAssert(t, "TestToMap")
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
expected := map[int]string{100: "Hello", 101: "Hi"}
assert.Equal(expected, result)
}
func TestStructToMap(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToMap")
@@ -154,10 +191,22 @@ func TestStructToMap(t *testing.T) {
100,
}
pm, _ := StructToMap(p)
var expected = map[string]any{"name": "test"}
expected := map[string]any{"name": "test"}
assert.Equal(expected, pm)
}
func TestMapToSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestMapToSlice")
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
assert.Equal([]string{"a:1", "b:2", "c:3"}, result)
}
func TestColorHexToRGB(t *testing.T) {
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)

View File

@@ -24,13 +24,16 @@ import (
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToMap](#ToMap)
- [ToPointer](#ToPointer)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
<div STYLE="page-break-after: always;"></div>
@@ -194,6 +197,43 @@ func main() {
```
### <span id="ToChannel">ToChannel</span>
<p>Convert a collection of elements to a read-only channels.</p>
<b>Signature:</b>
```go
func ToChannel[T any](array []T) <-chan T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
val1, _ := <-ch
fmt.Println(val1) //1
val2, _ := <-ch
fmt.Println(val2) //2
val3, _ := <-ch
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
}
```
### <span id="ToFloat">ToFloat</span>
@@ -289,14 +329,14 @@ func main() {
### <span id="ToJson">ToJson</span>
### <span id="ToMap">ToMap</span>
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
<p>Convert a slice or an array of structs to a map based on iteratee function. </p>
<b>Signature:</b>
```go
func ToJson(value any) (string, error)
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
```
<b>Example:</b>
@@ -309,9 +349,19 @@ import (
)
func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
fmt.Println(result) //{100: "Hello", 101: "Hi"}
}
```
@@ -376,4 +426,35 @@ func main() {
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```
### <span id="MapToSlice">MapToSlice</span>
<p>Convert a map to a slice based on iteratee function.</p>
<b>Signature:</b>
```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
fmt.Println(result) //[]string{"a:1", "b:2", "c:3"}
}
```

View File

@@ -26,13 +26,16 @@ import (
- [ToBool](#ToBool)
- [ToBytes](#ToBytes)
- [ToChar](#ToChar)
- [ToChannel](#ToChannel)
- [ToFloat](#ToFloat)
- [ToInt](#ToInt)
- [ToJson](#ToJson)
- [ToMap](#ToMap)
- [ToPointer](#ToPointer)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
<div STYLE="page-break-after: always;"></div>
@@ -197,6 +200,44 @@ func main() {
### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel</p>
<b>函数签名:</b>
```go
func ToChannel[T any](array []T) <-chan T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
ch := convertor.ToChannel([]int{1, 2, 3})
val1, _ := <-ch
fmt.Println(val1) //1
val2, _ := <-ch
fmt.Println(val2) //2
val3, _ := <-ch
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
}
```
### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型如果参数无法转换会返回0和error</p>
@@ -291,6 +332,44 @@ func main() {
### <span id="ToMap">ToMap</span>
<p>将切片转为map</p>
<b>函数签名:</b>
```go
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
type Message struct {
name string
code int
}
messages := []Message{
{name: "Hello", code: 100},
{name: "Hi", code: 101},
}
result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name
})
fmt.Println(result) //{100: "Hello", 101: "Hi"}
}
```
### <span id="ToPointer">ToPointer</span>
<p>返回传入值的指针</p>
@@ -378,4 +457,35 @@ func main() {
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
}
```
### <span id="MapToSlice">MapToSlice</span>
<p>map中key和value执行函数iteratee后转为切片</p>
<b>函数签名:</b>
```go
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
result := MapToSlice(aMap, func(key string, value int) string {
return key + ":" + strconv.Itoa(value)
})
fmt.Println(result) //[]string{"a:1", "b:2", "c:3"}
}
```

View File

@@ -26,7 +26,9 @@ import (
- [GetIps](#GetIps)
- [GetMacAddrs](#GetMacAddrs)
- [GetPublicIpInfo](#GetPublicIpInfo)
- [GetRequestPublicIp](#GetRequestPublicIp)
- [IsPublicIP](#IsPublicIP)
- [IsInternalIP](#IsInternalIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
@@ -199,8 +201,51 @@ func main() {
### <span id="GetRequestPublicIp">GetRequestPublicIp</span>
<p>Get http request public ip.</p>
<b>Signature:</b>
```go
func GetRequestPublicIp(req *http.Request) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip := "36.112.24.10"
request1 := http.Request{
Method: "GET",
Header: http.Header{
"X-Forwarded-For": {ip},
},
}
publicIp1 := netutil.GetRequestPublicIp(&request1)
fmt.Println(publicIp1) //36.112.24.10
request2 := http.Request{
Method: "GET",
Header: http.Header{
"X-Real-Ip": {ip},
},
}
publicIp2 := netutil.GetRequestPublicIp(&request2)
fmt.Println(publicIp2) //36.112.24.10
}
```
### <span id="IsPublicIP">IsPublicIP</span>
<p>Checks if a ip is public or not.</p>
<p>Checks if an ip is public or not.</p>
<b>Signature:</b>
@@ -230,6 +275,36 @@ func main() {
### <span id="IsInternalIP">IsInternalIP</span>
<p>Checks if an ip is intranet or not.</p>
<b>Signature:</b>
```go
func IsInternalIP(IP net.IP) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip1 := net.ParseIP("127.0.0.1")
ip2 := net.ParseIP("36.112.24.10")
fmt.Println(netutil.IsInternalIP(ip1)) //true
fmt.Println(netutil.IsInternalIP(ip2)) //false
}
```
### <span id="HttpGet">HttpGet</span>
<p>Send http get request.</p>
@@ -237,7 +312,7 @@ func main() {
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpGet(url string, params ...any) (*http.Response, error)
@@ -279,7 +354,7 @@ func main() {
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPost(url string, params ...any) (*http.Response, error)
@@ -328,7 +403,7 @@ func main() {
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPut(url string, params ...any) (*http.Response, error)
@@ -378,7 +453,7 @@ func main() {
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpDelete(url string, params ...any) (*http.Response, error)
@@ -417,7 +492,7 @@ func main() {
```go
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any,
// params[1] is query param which type should be url.Values or map[string]string,
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
func HttpPatch(url string, params ...any) (*http.Response, error)

View File

@@ -25,12 +25,14 @@ import (
- [GetIps](#GetIps)
- [GetMacAddrs](#GetMacAddrs)
- [GetPublicIpInfo](#GetPublicIpInfo)
- [GetRequestPublicIp](#GetRequestPublicIp)
- [IsPublicIP](#IsPublicIP)
- [IsInternalIP](#IsInternalIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
@@ -197,6 +199,50 @@ func main() {
### <span id="GetRequestPublicIp">GetRequestPublicIp</span>
<p>获取http请求ip</p>
<b>函数签名:</b>
```go
func GetRequestPublicIp(req *http.Request) string
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip := "36.112.24.10"
request1 := http.Request{
Method: "GET",
Header: http.Header{
"X-Forwarded-For": {ip},
},
}
publicIp1 := netutil.GetRequestPublicIp(&request1)
fmt.Println(publicIp1) //36.112.24.10
request2 := http.Request{
Method: "GET",
Header: http.Header{
"X-Real-Ip": {ip},
},
}
publicIp2 := netutil.GetRequestPublicIp(&request2)
fmt.Println(publicIp2) //36.112.24.10
}
```
### <span id="IsPublicIP">IsPublicIP</span>
<p>判断ip是否是公共ip</p>
@@ -227,6 +273,35 @@ func main() {
### <span id="IsInternalIP">IsInternalIP</span>
<p>判断ip是否是局域网ip.</p>
<b>函数签名:</b>
```go
func IsInternalIP(IP net.IP) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
ip1 := net.ParseIP("127.0.0.1")
ip2 := net.ParseIP("36.112.24.10")
fmt.Println(netutil.IsInternalIP(ip1)) //true
fmt.Println(netutil.IsInternalIP(ip2)) //false
}
```
### <span id="HttpGet">HttpGet</span>
<p>发送http get请求</p>
@@ -235,7 +310,7 @@ func main() {
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpGet(url string, params ...any) (*http.Response, error)
@@ -277,7 +352,7 @@ func main() {
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPost(url string, params ...any) (*http.Response, error)
@@ -326,7 +401,7 @@ func main() {
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPut(url string, params ...any) (*http.Response, error)
@@ -376,7 +451,7 @@ func main() {
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpDelete(url string, params ...any) (*http.Response, error)
@@ -415,7 +490,7 @@ func main() {
```go
// params[0] http请求header类型必须是http.Header或者map[string]string
// params[1] http查询字符串类型必须是url.Values或者map[string]any
// params[1] http查询字符串类型必须是url.Values或者map[string]string
// params[2] post请求体类型必须是[]byte
// params[3] http client类型必须是http.Client
func HttpPatch(url string, params ...any) (*http.Response, error)

View File

@@ -72,7 +72,7 @@ import (
<b>Signature:</b>
```go
func Contain[T any](slice []T, value T) bool
func Contain[T comparable](slice []T, value T) bool
```
<b>Example:</b>
@@ -95,7 +95,7 @@ func main() {
<b>Signature:</b>
```go
func ContainSubSlice[T any](slice, subslice []T) bool
func ContainSubSlice[T comparable](slice, subslice []T) bool
```
<b>Example:</b>
@@ -253,7 +253,7 @@ func main() {
<b>Signature:</b>
```go
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T
```
<b>Example:</b>
@@ -719,7 +719,7 @@ func main() {
<b>Signature:</b>
```go
func Intersection[T any](slices ...[]T) []T
func Intersection[T comparable](slices ...[]T) []T
```
<b>Example:</b>
@@ -777,7 +777,7 @@ func main() {
<b>Signature:</b>
```go
func IndexOf[T any](slice []T, value T) int
func IndexOf[T comparable](slice []T, value T) int
```
<b>Example:</b>
@@ -805,7 +805,7 @@ func main() {
<b>Signature:</b>
```go
func LastIndexOf[T any](slice []T, value T) int
func LastIndexOf[T comparable](slice []T, value T) int
```
<b>Example:</b>
@@ -1040,7 +1040,7 @@ func main() {
<b>Signature:</b>
```go
func SymmetricDifference[T any](slices ...[]T) []T
func SymmetricDifference[T comparable](slices ...[]T) []T
```
<b>Example:</b>
@@ -1106,7 +1106,7 @@ import (
func main() {
str1 := "a"
str2 := "b"
res := slice.ToSlice(str1, str2)
res := slice.ToSlicePointer(str1, str2)
fmt.Println(res) // res -> []*string{&str1, &str2}
}
```
@@ -1118,7 +1118,7 @@ func main() {
<b>Signature:</b>
```go
func Unique[T any](slice []T) []T
func Unique[T comparable](slice []T) []T
```
<b>Example:</b>
@@ -1142,7 +1142,7 @@ func main() {
<b>Signature:</b>
```go
func UniqueBy[T any](slice []T, iteratee func(item T) T) []T
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T
```
<b>Example:</b>
@@ -1168,7 +1168,7 @@ func main() {
<b>Signature:</b>
```go
func Union[T any](slices ...[]T) []T
func Union[T comparable](slices ...[]T) []T
```
<b>Example:</b>
@@ -1222,7 +1222,7 @@ func main() {
<b>Signature:</b>
```go
func Without[T any](slice []T, values ...T) []T
func Without[T comparable](slice []T, values ...T) []T
```
<b>Example:</b>

View File

@@ -74,7 +74,7 @@ import (
<b>函数签名:</b>
```go
func Contain[T any](slice []T, value T) bool
func Contain[T comparable](slice []T, value T) bool
```
<b>例子:</b>
@@ -97,7 +97,7 @@ func main() {
<b>函数签名:</b>
```go
func ContainSubSlice[T any](slice, subslice []T) bool
func ContainSubSlice[T comparable](slice, subslice []T) bool
```
<b>例子:</b>
@@ -255,7 +255,7 @@ func main() {
<b>函数签名:</b>
```go
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T
```
<b>例子:</b>
@@ -722,7 +722,7 @@ func main() {
<b>函数签名:</b>
```go
func Intersection[T any](slices ...[]T) []T
func Intersection[T comparable](slices ...[]T) []T
```
<b>例子:</b>
@@ -780,7 +780,7 @@ func main() {
<b>函数签名:</b>
```go
func IndexOf[T any](slice []T, value T) int
func IndexOf[T comparable](slice []T, value T) int
```
<b>例子:</b>
@@ -808,7 +808,7 @@ func main() {
<b>函数签名:</b>
```go
func LastIndexOf[T any](slice []T, value T) int
func LastIndexOf[T comparable](slice []T, value T) int
```
<b>例子:</b>
@@ -1042,7 +1042,7 @@ func main() {
<b>函数签名:</b>
```go
func SymmetricDifference[T any](slices ...[]T) []T
func SymmetricDifference[T comparable](slices ...[]T) []T
```
<b>例子:</b>
@@ -1107,7 +1107,7 @@ import (
func main() {
str1 := "a"
str2 := "b"
res := slice.ToSlice(str1, str2)
res := slice.ToSlicePointer(str1, str2)
fmt.Println(res) // res -> []*string{&str1, &str2}
}
```
@@ -1120,7 +1120,7 @@ func main() {
<b>函数签名:</b>
```go
func Unique[T any](slice []T) []T
func Unique[T comparable](slice []T) []T
```
<b>例子:</b>
@@ -1144,7 +1144,7 @@ func main() {
<b>函数签名:</b>
```go
func UniqueBy[T any](slice []T, iteratee func(item T) T) []T
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T
```
<b>例子:</b>
@@ -1170,7 +1170,7 @@ func main() {
<b>函数签名:</b>
```go
func Union[T any](slices ...[]T) []T
func Union[T comparable](slices ...[]T) []T
```
<b>例子:</b>
@@ -1224,7 +1224,7 @@ func main() {
<b>函数签名:</b>
```go
func Without[T any](slice []T, values ...T) []T
func Without[T comparable](slice []T, values ...T) []T
```
<b>例子:</b>

View File

@@ -25,6 +25,7 @@ func TestCreateFile(t *testing.T) {
f := "./text.txt"
if CreateFile(f) {
file, err := os.Open(f)
defer file.Close()
assert.IsNil(err)
assert.Equal(f, file.Name())
} else {
@@ -111,6 +112,7 @@ func TestReadFileToString(t *testing.T) {
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello world")
content, _ := ReadFileToString(path)
@@ -218,6 +220,7 @@ func TestMiMeType(t *testing.T) {
assert := internal.NewAssert(t, "TestMiMeType")
f, _ := os.Open("./file.go")
defer f.Close()
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
}

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -6,8 +6,8 @@
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `url` is required.
// HttpGet, HttpPost, HttpDelete, HttpPut, HttpPatch, function param `params` is variable, the order is:
// params[0] is header which type should be http.Header or map[string]string,
// params[1] is query param which type should be url.Values or map[string]any, when content-type header is
// multipart/form-data or application/x-www-form-urlencoded, params[1] should be url.Values
// params[1] is query string param which type should be url.Values or map[string]string, when content-type header is
// multipart/form-data or application/x-www-form-urlencoded
// params[2] is post body which type should be []byte.
// params[3] is http client which type should be http.Client.
package netutil

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"io/ioutil"
"log"
"net/url"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -57,9 +56,13 @@ func TestHttpPostFormData(t *testing.T) {
UserId int `json:"userId"`
Title string `json:"title"`
}
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "TestAddToDo")
// postData := url.Values{}
// postData.Add("userId", "1")
// postData.Add("title", "TestAddToDo")
postData := make(map[string]string)
postData["userId"] = "1"
postData["title"] = "title"
resp, err := HttpPost(apiUrl, header, postData, nil)
if err != nil {

View File

@@ -5,6 +5,7 @@ import (
"io/ioutil"
"net"
"net/http"
"strings"
)
// GetInternalIp return internal ipv4
@@ -24,6 +25,26 @@ func GetInternalIp() string {
return ""
}
// GetRequestPublicIp return the requested public ip
func GetRequestPublicIp(req *http.Request) string {
var ip string
for _, ip = range strings.Split(req.Header.Get("X-Forwarded-For"), ",") {
if ip = strings.TrimSpace(ip); ip != "" && !IsInternalIP(net.ParseIP(ip)) {
return ip
}
}
if ip = strings.TrimSpace(req.Header.Get("X-Real-Ip")); ip != "" && !IsInternalIP(net.ParseIP(ip)) {
return ip
}
if ip, _, _ = net.SplitHostPort(req.RemoteAddr); !IsInternalIP(net.ParseIP(ip)) {
return ip
}
return ip
}
// GetPublicIpInfo return public ip information
// return the PublicIpInfo struct
func GetPublicIpInfo() (*PublicIpInfo, error) {
@@ -122,3 +143,17 @@ func IsPublicIP(IP net.IP) bool {
}
return false
}
// IsInternalIP verify an ip is intranet or not
func IsInternalIP(IP net.IP) bool {
if IP.IsLoopback() {
return true
}
if ip4 := IP.To4(); ip4 != nil {
return ip4[0] == 10 ||
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) ||
(ip4[0] == 169 && ip4[1] == 254) ||
(ip4[0] == 192 && ip4[1] == 168)
}
return false
}

View File

@@ -3,7 +3,6 @@ package netutil
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
@@ -81,9 +80,18 @@ func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryPar
if err != nil {
return err
}
if req.Header.Get("Content-Type") == "multipart/form-data" || req.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
formData := queryParam.(url.Values)
err = setBodyByte(req, []byte(formData.Encode()))
if strings.Contains(req.Header.Get("Content-Type"), "multipart/form-data") || req.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
if formData, ok := queryParam.(url.Values); ok {
err = setBodyByte(req, []byte(formData.Encode()))
}
if formData, ok := queryParam.(map[string]string); ok {
postData := url.Values{}
for k, v := range formData {
postData.Set(k, v)
}
err = setBodyByte(req, []byte(postData.Encode()))
}
} else {
err = setBodyByte(req, body)
}
@@ -132,15 +140,15 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam any) error {
var values url.Values
if queryParam != nil {
switch v := queryParam.(type) {
case map[string]any:
case map[string]string:
values = url.Values{}
for k := range v {
values.Set(k, fmt.Sprintf("%v", v[k]))
values.Set(k, v[k])
}
case url.Values:
values = v
default:
return errors.New("query params type should be url.Values or map[string]any")
return errors.New("query string params type should be url.Values or map[string]string")
}
}

View File

@@ -2,6 +2,7 @@ package netutil
import (
"net"
"net/http"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -15,6 +16,30 @@ func TestGetInternalIp(t *testing.T) {
assert.IsNotNil(ip)
}
func TestGetRequestPublicIp(t *testing.T) {
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
ip := "36.112.24.10"
request := http.Request{
Method: "GET",
Header: http.Header{
"X-Forwarded-For": {ip},
},
}
publicIp := GetRequestPublicIp(&request)
assert.Equal(publicIp, ip)
request = http.Request{
Method: "GET",
Header: http.Header{
"X-Real-Ip": {ip},
},
}
publicIp = GetRequestPublicIp(&request)
assert.Equal(publicIp, ip)
}
func TestGetPublicIpInfo(t *testing.T) {
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
@@ -43,6 +68,25 @@ func TestIsPublicIP(t *testing.T) {
}
}
func TestIsInternalIP(t *testing.T) {
assert := internal.NewAssert(t, "TestIsInternalIP")
ips := []net.IP{
net.ParseIP("127.0.0.1"),
net.ParseIP("192.168.0.1"),
net.ParseIP("10.91.210.131"),
net.ParseIP("172.20.16.1"),
net.ParseIP("36.112.24.10"),
}
expected := []bool{true, true, true, true, false}
for i := 0; i < len(ips); i++ {
actual := IsInternalIP(ips[i])
assert.Equal(expected[i], actual)
}
}
func TestGetIps(t *testing.T) {
ips := GetIps()
t.Log(ips)

View File

@@ -13,9 +13,9 @@ import (
)
// Contain check if the value is in the slice or not
func Contain[T any](slice []T, value T) bool {
func Contain[T comparable](slice []T, value T) bool {
for _, v := range slice {
if reflect.DeepEqual(v, value) {
if v == value {
return true
}
}
@@ -24,7 +24,7 @@ func Contain[T any](slice []T, value T) bool {
}
// ContainSubSlice check if the slice contain subslice or not
func ContainSubSlice[T any](slice, subslice []T) bool {
func ContainSubSlice[T comparable](slice, subslice []T) bool {
for _, v := range subslice {
if !Contain(slice, v) {
return false
@@ -108,7 +108,7 @@ func Difference[T comparable](slice, comparedSlice []T) []T {
// DifferenceBy it accepts iteratee which is invoked for each element of slice
// and values to generate the criterion by which they're compared.
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy,
func DifferenceBy[T any](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
orginSliceAfterMap := Map(slice, iteratee)
comparedSliceAfterMap := Map(comparedSlice, iteratee)
@@ -558,7 +558,7 @@ func UpdateAt[T any](slice []T, index int, value T) []T {
}
// Unique remove duplicate elements in slice.
func Unique[T any](slice []T) []T {
func Unique[T comparable](slice []T) []T {
if len(slice) == 0 {
return []T{}
}
@@ -569,7 +569,7 @@ func Unique[T any](slice []T) []T {
v := slice[i]
skip := true
for j := range res {
if reflect.DeepEqual(v, res[j]) {
if v == res[j] {
skip = false
break
}
@@ -583,7 +583,7 @@ func Unique[T any](slice []T) []T {
}
// UniqueBy call iteratee func with every item of slice, then remove duplicated.
func UniqueBy[T any](slice []T, iteratee func(item T) T) []T {
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
if len(slice) == 0 {
return []T{}
}
@@ -598,7 +598,7 @@ func UniqueBy[T any](slice []T, iteratee func(item T) T) []T {
}
// Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons.
func Union[T any](slices ...[]T) []T {
func Union[T comparable](slices ...[]T) []T {
if len(slices) == 0 {
return []T{}
}
@@ -616,7 +616,7 @@ func Union[T any](slices ...[]T) []T {
}
// Intersection creates a slice of unique values that included by all slices.
func Intersection[T any](slices ...[]T) []T {
func Intersection[T comparable](slices ...[]T) []T {
if len(slices) == 0 {
return []T{}
}
@@ -649,7 +649,7 @@ func Intersection[T any](slices ...[]T) []T {
}
// SymmetricDifference oppoiste operation of intersection function
func SymmetricDifference[T any](slices ...[]T) []T {
func SymmetricDifference[T comparable](slices ...[]T) []T {
if len(slices) == 0 {
return []T{}
}
@@ -765,7 +765,7 @@ func SortByField(slice any, field string, sortType ...string) error {
}
// Without creates a slice excluding all given values
func Without[T any](slice []T, values ...T) []T {
func Without[T comparable](slice []T, values ...T) []T {
if len(values) == 0 || len(slice) == 0 {
return slice
}
@@ -782,9 +782,9 @@ func Without[T any](slice []T, values ...T) []T {
// IndexOf returns the index at which the first occurrence of a value is found in a slice or return -1
// if the value cannot be found.
func IndexOf[T any](slice []T, value T) int {
func IndexOf[T comparable](slice []T, value T) int {
for i, v := range slice {
if reflect.DeepEqual(v, value) {
if v == value {
return i
}
}
@@ -794,9 +794,9 @@ func IndexOf[T any](slice []T, value T) int {
// LastIndexOf returns the index at which the last occurrence of a value is found in a slice or return -1
// if the value cannot be found.
func LastIndexOf[T any](slice []T, value T) int {
func LastIndexOf[T comparable](slice []T, value T) int {
for i := len(slice) - 1; i > 0; i-- {
if reflect.DeepEqual(value, slice[i]) {
if value == slice[i] {
return i
}
}