1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-17 03:02:28 +08:00

Compare commits

...

5 Commits

Author SHA1 Message Date
dudaodong
921f218ef7 test: run test cases on rc branch 2024-10-18 16:40:20 +08:00
dudaodong
0a2cc9c928 doc: update doc for RandNumberOfLength and GetExeOrDllVersion 2024-10-18 16:38:39 +08:00
今晚打打
ed93aae970 feat:add GetExeDllVersion for fileutil,random,package (#257)
* 增加GetExeDllVersion函数获取exe,dll版本号

* 多打文字

* 定位忘记...

* 单独剥离出来一个为windows的,增加RandNumLen为取指定长度随机数.

* ....

* 增加test测试
2024-10-18 16:17:14 +08:00
BoWen Qiu
1671f7856a feat(netutil): add async http request for http client (#256)
* fix(algorithm): fix bug of lrucache in issue #251

* feat(netutil): add async send request for HttpClient
2024-10-18 15:14:52 +08:00
燕归来
1008dd4956 fix: fix compile error (#255) (#258) 2024-10-18 15:09:28 +08:00
16 changed files with 357 additions and 71 deletions

View File

@@ -1,51 +1,51 @@
-----BEGIN rsa private key-----
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
-----END rsa private key-----

View File

@@ -1,14 +1,14 @@
-----BEGIN rsa public key-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs+rfCwwvBb9JplwDAaNt
pEPCm1DoS8PkqzwSSxfA7JHSMYdYUMq92vbSqEKomNgyksaGIiqDHop+9pHjYI1A
ftd6mbZJwRtQxo+5eYGh88FzPqemmNubZk7SxGq0MEz1XmZ9viQyp3GxAJjeSdAG
9GRdstNcczSy9Ij9YGJ8ehLhL/png4ZsLUtwDbYsilJDx28qDX/jJ/nbopaHWk2X
TSu8KK3zXBjppTU4uKKicOswaJ6kfk9J6ItkQ15uS+z2eHsxpa8K++gIt2swJkiE
RlqUzwiC75w92JH1nQPXqEqaaEx0izdHUmFF33cgGb6gw5tJePzOmYs8KLJcOhfJ
QcqjW4MjCfnaw4tB/cpi3zYKzDoC7mzwitrkBO1MG11luzR1m9uMfWczL2hK2zMH
I51vayC1d1T0gc56vS/SAdicl5OqcD6oc6Dmym3rguF/pauTIOrvGtipeYk/Mbb4
qj2CI33QFTZc3G55yHVB6vDWIpMSWF60HHHqv7Ens4MIPIev0WS893vsNscg4Ph3
QxXDNjOc3kEK17TnDGXmL7C+Ykfq9brm32IrOMZ4KR3NJ+aO83yLewPoQAy8QCC3
2b1O3c1nAgSY9sIwJV8ikAdNDBhLnkXFrYE2ZFl/Kl5HXd0LCz/BQu3Ey0RsZfXI
pD7KUcdNq3QRloTATntE9U0CAwEAAQ==
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsZoYOi7lxZ3zk4zTa/nv
lQzPeXNBthaUpAJmC1b2/ldmglZ8ARGoVv45VCjG1yKO47SiN8ijcA///o/EawGZ
8mJHv8WsPUBxzUF2OQHSZ/kHlbi1vZsbGXLcM9siBU79uqudbyqUm/9OkgnTPCUU
zOlaFtKGeyoDM4TBAX7ec8G8LWBdBAgNAaK/vP+iXuPHxLdKNMDDel67nLNYJ30K
C/fUbwHixn5yQLx4zVLF+rv3pUbQuTeEvS+N19Cg1/+5/xzGK+YYdO1ZH4qgubNB
u9C90wH0FhIuDDfswh8liZbjHcXsJ82QPdaxjbz1bSb8OToackMMocvJVI9ToxSB
dGvGoBk1mnLJRSab6nOD56+iRoGJmy6GTpD2I1ie1PHV1Y2TIjUESnxjgPigaYA5
i/MkXlD/1CtrDW6hsc0/WgCSD7ZGjNTduUwdwmd2es1XIqnamht+QJE1JTbBFLd9
r5zXQY/5W5nRQHBmWP5fVHy7a/wmF9N2ZpI/DYMarCRIVBsiMdsE62mq63haB6yw
jkVk+78TXtmXTTE8ts6XImt+m+0RY4lAd+UfHvyOe3dH2y5nGSHG4C8CXB264YdA
pZZjjvVZy5K3lsmmBB+4Kje1Rux36F76qEOvjZ2QvpJDTXSXOk1POu6aZc8N+XRu
vG7hmEPdF3xD68VPSZ5/gfcCAwEAAQ==
-----END rsa public key-----

View File

@@ -52,6 +52,7 @@ import (
- [ReadFile](#ReadFile)
- [ChunkRead](#ChunkRead)
- [ParallelChunkRead](#ParallelChunkRead)
- [GetExeOrDllVersion](#GetExeOrDllVersion)
<div STYLE="page-break-after: always;"></div>
@@ -1076,4 +1077,34 @@ func main() {
// Jim,21,male
// 2
}
```
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
<p>返回exe,dll文件版本号(仅Window平台).</p>
<b>函数签名:</b>
```go
func GetExeOrDllVersion(filePath string) (string, error)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
if err != nil {
panic(err)
}
fmt.Println(v)
// Output:
// 3.9.10.19
}
```

View File

@@ -40,6 +40,7 @@ import (
- [RandStringSlice](#RandStringSlice)
- [RandBool](#RandBool)
- [RandBoolSlice](#RandBoolSlice)
- [RandNumberOfLength](#RandNumberOfLength)
<div STYLE="page-break-after: always;"></div>
@@ -522,4 +523,29 @@ func main() {
result := random.RandBoolSlice(2)
fmt.Println(result) // [true false] (random)
}
```
### <span id="RandNumberOfLength">RandNumberOfLength</span>
<p>生成指定长度的随机数</p>
<b>函数签名:</b>
```go
func RandNumberOfLength(len int) int
```
<b>实例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
i := random.RandNumberOfLength(2)
fmt.Println(i) // 21 (random number of length 2)
}
```

View File

@@ -52,6 +52,7 @@ import (
- [ReadFile](#ReadFile)
- [ChunkRead](#ChunkRead)
- [ParallelChunkRead](#ParallelChunkRead)
- [GetExeOrDllVersion](#GetExeOrDllVersion)
<div STYLE="page-break-after: always;"></div>
@@ -1074,4 +1075,37 @@ func main() {
// Jim,21,male
// 2
}
```
### <span id="GetExeOrDllVersion">GetExeOrDllVersion</span>
<p>Get the version of exe or dll file on windows.</p>
<b>Signature:</b>
```go
func GetExeOrDllVersion(filePath string) (string, error)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
v, err := fileutil.GetExeOrDllVersion(`C:\Program Files\Tencent\WeChat\WeChat.exe`)
if err != nil {
panic(err)
}
fmt.Println(v)
// Output:
// 3.9.10.19
}
```

View File

@@ -40,6 +40,7 @@ import (
- [RandStringSlice](#RandStringSlice)
- [RandBool](#RandBool)
- [RandBoolSlice](#RandBoolSlice)
- [RandNumberOfLength](#RandNumberOfLength)
<div STYLE="page-break-after: always;"></div>
@@ -523,4 +524,30 @@ func main() {
result := random.RandBoolSlice(2)
fmt.Println(result) // [true false] (random)
}
```
### <span id="RandNumberOfLength">RandNumberOfLength</span>
<p>Generates a random int number of specified length.</p>
<b>Signature:</b>
```go
func RandNumberOfLength(len int) int
```
<b>Signature:<span style="float:right;display:inline-block;">[Run](todo)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
i := random.RandNumberOfLength(2)
fmt.Println(i) // 21 (random number of length 2)
}
```

View File

@@ -14,6 +14,7 @@ import (
"encoding/csv"
"errors"
"fmt"
"github.com/duke-git/lancet/v2/validator"
"io"
"io/fs"
"net/http"
@@ -23,8 +24,6 @@ import (
"sort"
"strings"
"sync"
"github.com/duke-git/lancet/v2/validator"
)
// FileReader is a reader supporting offset seeking and reading one

83
fileutil/file_windows.go Normal file
View File

@@ -0,0 +1,83 @@
//go:build windows
package fileutil
import (
"fmt"
"syscall"
"unsafe"
)
// tagVS_FIXEDFILEINFO 参考结构体https://learn.microsoft.com/zh-cn/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
type tagVS_FIXEDFILEINFO struct {
Signature uint32
StructVersion uint32
FileVersionMS uint32
FileVersionLS uint32
ProductVersionMS uint32
ProductVersionLS uint32
FileFlagsMask uint32
FileFlags uint32
FileOS uint32
FileType uint32
FileSubtype uint32
FileDateMS uint32
FileDateLS uint32
}
// GetExeOrDllVersion get the version of exe or dll file on windows.
// Play: todo
func GetExeOrDllVersion(filePath string) (string, error) {
// 加载系统dll
versionDLL := syscall.NewLazyDLL("version.dll")
getFileVersionInfoSize := versionDLL.NewProc("GetFileVersionInfoSizeW")
getFileVersionInfo := versionDLL.NewProc("GetFileVersionInfoW")
verQueryValue := versionDLL.NewProc("VerQueryValueW")
// 转换路径为UTF-16
filePathPtr, err := syscall.UTF16PtrFromString(filePath)
if err != nil {
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
}
// 获取version信息大小
size, _, err := getFileVersionInfoSize.Call(
uintptr(unsafe.Pointer(filePathPtr)),
0,
)
if size == 0 {
return "", fmt.Errorf("unable to obtain version information size: %v", err)
}
// 加载version信息
data := make([]byte, size)
ret, _, err := getFileVersionInfo.Call(uintptr(unsafe.Pointer(filePathPtr)), 0, size, uintptr(unsafe.Pointer(&data[0])))
if ret == 0 {
return "", fmt.Errorf("unable to obtain version information: %v", err)
}
// 查询version信息
var fixedInfo *tagVS_FIXEDFILEINFO
var fixedInfoLen uint32
u16, err := syscall.UTF16PtrFromString(`\`)
if err != nil {
return "", fmt.Errorf("unable to convert file path to UTF-16: %w", err)
}
ret, _, err = verQueryValue.Call(
uintptr(unsafe.Pointer(&data[0])),
uintptr(unsafe.Pointer(u16)),
uintptr(unsafe.Pointer(&fixedInfo)),
uintptr(unsafe.Pointer(&fixedInfoLen)),
)
if ret == 0 {
return "", fmt.Errorf("unable to query version information: %v", err)
}
// 转换结构体
major := fixedInfo.FileVersionMS >> 16
minor := fixedInfo.FileVersionMS & 0xFFFF
build := fixedInfo.FileVersionLS >> 16
revision := fixedInfo.FileVersionLS & 0xFFFF
return fmt.Sprintf("%d.%d.%d.%d", major, minor, build, revision), nil
}

View File

@@ -0,0 +1,13 @@
//go:build windows
package fileutil
import "testing"
func TestGetExeOrDllVersion(t *testing.T) {
v, err := GetExeOrDllVersion(`C:\Windows\System32\cmd.exe`)
if err != nil {
t.Error(err)
}
t.Log(v)
}

2
go.sum
View File

@@ -1,6 +1,4 @@
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=

View File

@@ -221,6 +221,22 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
return resp, nil
}
// AsyncSendRequest send http request with goroutine, pop response and error to channels
func (client *HttpClient) AsyncSendRequest(request *HttpRequest, respChan chan *http.Response, errChan chan error) {
go func() {
defer func() {
if err := recover(); err != nil {
errChan <- fmt.Errorf("%v", err)
}
}()
resp, err := client.SendRequest(request)
if err != nil {
errChan <- err
}
respChan <- resp
}()
}
// DecodeResponse decode response into target object.
// Play: https://go.dev/play/p/jUSgynekH7G
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {

View File

@@ -373,6 +373,45 @@ func TestSendRequestWithFilePath(t *testing.T) {
}
}
func TestHttpClient_AsyncSendRequest(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHttpClient_Get")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := NewHttpClient()
respCh := make(chan *http.Response, 20)
errCh := make(chan error, 20)
for i := 0; i < 50; i++ {
httpClient.AsyncSendRequest(request, respCh, errCh)
}
for i := 0; i < 50; i++ {
select {
case resp := <-respCh:
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
err := httpClient.DecodeResponse(resp, &todo)
if err != nil {
t.FailNow()
}
assert.Equal(1, todo.Id)
case err := <-errCh:
if err != nil {
t.Log("net error: ", err.Error())
}
}
}
}
func TestProxy(t *testing.T) {
config := &HttpClientConfig{
HandshakeTimeout: 20 * time.Second,

View File

@@ -327,3 +327,13 @@ func UUIdV4() (string, error) {
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}
// RandNumberOfLength 生成一个长度为len的随机数
// Play: todo
func RandNumberOfLength(len int) int {
m := int(math.Pow10(len) - 1)
i := int(math.Pow10(len - 1))
ret := rand.Intn(m-i+1) + i
return ret
}

View File

@@ -3,6 +3,7 @@ package random
import (
"reflect"
"regexp"
"strconv"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -361,3 +362,9 @@ func TestRandBoolSlice(t *testing.T) {
}
})
}
func TestRandNumberOfLength(t *testing.T) {
t.Parallel()
randi := RandNumberOfLength(6)
assert := internal.NewAssert(t, "TestRandNumberOfLength")
assert.Equal(6, len(strconv.Itoa(randi)))
}

View File

@@ -195,18 +195,14 @@ func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T
chunks = append(chunks, slice[i:end])
}
type resultChunk struct {
index int
data []T
}
resultCh := make(chan resultChunk, numThreads)
resultCh := make(chan resultChunk[T], numThreads)
var wg sync.WaitGroup
for i, chunk := range chunks {
wg.Add(1)
go func(index int, chunk []T) {
defer wg.Done()
resultCh <- resultChunk{index, removeDuplicate(chunk, comparator)}
resultCh <- resultChunk[T]{index, removeDuplicate(chunk, comparator)}
}(i, chunk)
}

View File

@@ -7,6 +7,13 @@ import (
"golang.org/x/exp/constraints"
)
// resultChunk is used to store the intermediate results of UniqueByConcurrent.
// It is defined separately to be compatible with versions of go up to 1.20.
type resultChunk[T comparable] struct {
index int
data []T
}
// sliceValue return the reflect value of a slice
func sliceValue(slice any) reflect.Value {
v := reflect.ValueOf(slice)