Skip to content

Commit 833ea64

Browse files
committed
add stringutil & netutil
1 parent fb37ddc commit 833ea64

File tree

9 files changed

+524
-0
lines changed

9 files changed

+524
-0
lines changed

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
module github.com/chennqqi/goutils
22

33
go 1.13
4+
5+
require (
6+
github.com/shirou/gopsutil v3.21.11+incompatible
7+
github.com/stretchr/testify v1.8.4 // indirect
8+
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
9+
github.com/yusufpapurcu/wmi v1.2.3 // indirect
10+
golang.org/x/sys v0.10.0 // indirect
11+
)

go.sum

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
5+
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
6+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
7+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
8+
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
9+
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
10+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
11+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
12+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
13+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
14+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
15+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
16+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
17+
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
18+
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
19+
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
20+
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
21+
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
22+
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
23+
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
24+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
25+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
26+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
27+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

netutil/dsn.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package netutil
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
type Dsn struct {
9+
Scheme string
10+
Source string
11+
}
12+
13+
func ParseDsn(dsn string) (Dsn, error) {
14+
params := strings.Split(dsn, "://")
15+
if len(params) != 2 {
16+
return Dsn{}, fmt.Errorf("bad dsn string")
17+
}
18+
return Dsn{
19+
params[0], params[1],
20+
}, nil
21+
}

netutil/dsn_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package netutil
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestParseDsn(t *testing.T) {
9+
type args struct {
10+
dsn string
11+
}
12+
tests := []struct {
13+
name string
14+
args args
15+
want Dsn
16+
wantErr bool
17+
}{
18+
// Add test cases.、
19+
{name: "test0", args: args{dsn: "mysql://root:z!guwrBhH7p>(127.0.0.1:3306)/cloudscan?charset=utf8mb4&parseTime=True&loc=Local"}, want: Dsn{Scheme: "mysql", Source: "root:z!guwrBhH7p>(127.0.0.1:3306)/cloudscan?charset=utf8mb4&parseTime=True&loc=Local"}, wantErr: false},
20+
{name: "test1", args: args{dsn: ""}, want: Dsn{Scheme: "", Source: ""}, wantErr: true},
21+
{name: "test2", args: args{dsn: "mongodb://testuser:[email protected]:27017"}, want: Dsn{Scheme: "mongodb", Source: "testuser:[email protected]:27017"}, wantErr: false},
22+
{name: "test3", args: args{dsn: "mongodb://192.168.102.153:27017"}, want: Dsn{Scheme: "mongodb", Source: "192.168.102.153:27017"}, wantErr: false},
23+
}
24+
for _, tt := range tests {
25+
t.Run(tt.name, func(t *testing.T) {
26+
got, err := ParseDsn(tt.args.dsn)
27+
if (err != nil) != tt.wantErr {
28+
t.Errorf("ParseDsn() error = %v, wantErr %v", err, tt.wantErr)
29+
return
30+
}
31+
if !reflect.DeepEqual(got, tt.want) {
32+
t.Errorf("ParseDsn() got = %v, want %v", got, tt.want)
33+
}
34+
})
35+
}
36+
}

netutil/net.go

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package netutil
2+
3+
import (
4+
"errors"
5+
"io/ioutil"
6+
"mime/multipart"
7+
"net"
8+
"net/http"
9+
"os"
10+
"strconv"
11+
"strings"
12+
13+
gnet "github.com/shirou/gopsutil/net"
14+
"github.com/tomasen/realip"
15+
)
16+
17+
// 获取文件大小的接口
18+
type Size interface {
19+
Size() int64
20+
}
21+
22+
// 获取文件信息的接口
23+
type Stat interface {
24+
Stat() (os.FileInfo, error)
25+
}
26+
27+
// 返回公网出口IP
28+
func GetExternalIP() (string, error) {
29+
resp, err := http.Get("http://ipaddr.site")
30+
if err != nil {
31+
return "", err
32+
}
33+
34+
defer resp.Body.Close()
35+
txt, err := ioutil.ReadAll(resp.Body)
36+
if err != nil {
37+
return "", err
38+
}
39+
return string(txt), nil
40+
}
41+
42+
func Inet_ntoa(ipnr int64) net.IP {
43+
var bytes [4]byte
44+
bytes[0] = byte(ipnr & 0xFF)
45+
bytes[1] = byte((ipnr >> 8) & 0xFF)
46+
bytes[2] = byte((ipnr >> 16) & 0xFF)
47+
bytes[3] = byte((ipnr >> 24) & 0xFF)
48+
49+
return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
50+
}
51+
52+
func Inet_aton(ipnr net.IP) int64 {
53+
bits := strings.Split(ipnr.String(), ".")
54+
55+
b0, _ := strconv.Atoi(bits[0])
56+
b1, _ := strconv.Atoi(bits[1])
57+
b2, _ := strconv.Atoi(bits[2])
58+
b3, _ := strconv.Atoi(bits[3])
59+
60+
var sum int64
61+
62+
sum += int64(b0) << 24
63+
sum += int64(b1) << 16
64+
sum += int64(b2) << 8
65+
sum += int64(b3)
66+
67+
return sum
68+
}
69+
70+
func IsPublicIP(IP net.IP) bool {
71+
if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
72+
return false
73+
}
74+
if ip4 := IP.To4(); ip4 != nil {
75+
switch true {
76+
case ip4[0] == 10:
77+
return false
78+
case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
79+
return false
80+
case ip4[0] == 192 && ip4[1] == 168:
81+
return false
82+
default:
83+
return true
84+
}
85+
}
86+
return false
87+
}
88+
89+
// 返回主机HOST IP
90+
func GetHostIP() (string, error) {
91+
host, err := os.Hostname()
92+
if err != nil {
93+
return "", err
94+
}
95+
addr, err := net.ResolveIPAddr("ip", host)
96+
if err != nil {
97+
return "", err
98+
}
99+
100+
return addr.String(), nil
101+
}
102+
103+
// 返回主机内部IP(顺序第一个)
104+
func GetInternalIP() (string, error) {
105+
addrs, err := net.InterfaceAddrs()
106+
if err != nil {
107+
return "", err
108+
}
109+
for _, a := range addrs {
110+
if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
111+
ipv4str := ipnet.IP.To4()
112+
if ipv4str != nil {
113+
return ipv4str.String(), nil
114+
}
115+
}
116+
}
117+
return "", nil
118+
}
119+
120+
// 返回HTTP请求IP,优先级(X-Real-IP>X-Forwarded-For>Proxy-Client-IP>WL-Proxy-Client-IP")
121+
func GetRequestIP(r *http.Request) string {
122+
if r.Header.Get("X-Real-IP") != "" {
123+
return r.Header.Get("X-Real-IP")
124+
}
125+
if r.Header.Get("X-Forwarded-For") != "" {
126+
return r.Header.Get("X-Forwarded-For")
127+
}
128+
if r.Header.Get("Proxy-Client-IP") != "" {
129+
return r.Header.Get("Proxy-Client-IP")
130+
}
131+
if r.Header.Get("WL-Proxy-Client-IP") != "" {
132+
return r.Header.Get("WL-Proxy-Client-IP")
133+
}
134+
return realip.FromRequest(r)
135+
}
136+
137+
// 根据网卡设备名称返回内部IP
138+
func GetInternalIPByDevName(dev string) ([]string, error) {
139+
addrs, err := gnet.Interfaces()
140+
if err != nil {
141+
return []string{}, err
142+
}
143+
for _, a := range addrs {
144+
if a.Name == dev {
145+
var retIPs []string
146+
for _, addr := range a.Addrs {
147+
retIPs = append(retIPs, addr.String())
148+
}
149+
return retIPs, nil
150+
}
151+
}
152+
return []string{}, errors.New("not found dev or ip addr")
153+
}
154+
155+
// 返回HTTP upload文件的大小
156+
func GetUploadFileSize(upfile multipart.File) (int64, error) {
157+
if statInterface, ok := upfile.(Stat); ok {
158+
fileInfo, _ := statInterface.Stat()
159+
return fileInfo.Size(), nil
160+
}
161+
if sizeInterface, ok := upfile.(Size); ok {
162+
fsize := sizeInterface.Size()
163+
return fsize, nil
164+
}
165+
return 0, errors.New("not found stat and size interface")
166+
}
167+
168+
// 在主机拥有多个IP地址时,返回能够连通对端网络的自身主机IP
169+
func GetLocalConnectIP(proto string, addr string) (string, error) {
170+
if proto == "" {
171+
proto = "tcp"
172+
}
173+
conn, err := net.Dial(proto, addr)
174+
if err != nil {
175+
return "", nil
176+
}
177+
defer conn.Close()
178+
laddr := conn.LocalAddr().String()
179+
var rip string
180+
v := strings.Split(laddr, ":")
181+
if len(v) > 1 {
182+
rip = v[0]
183+
}
184+
return rip, nil
185+
}

netutil/net_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package netutil
2+
3+
import (
4+
"fmt"
5+
"net"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestGetConnectIP(t *testing.T) {
12+
type test struct {
13+
Proto string
14+
Addr string
15+
Expect string
16+
}
17+
var tests [4]test
18+
ip, err := GetHostIP()
19+
assert.Nil(t, err)
20+
assert.NotEqual(t, "", ip)
21+
t.Log("HOST IP:", ip)
22+
23+
tip := fmt.Sprintf("%v:0", ip)
24+
conn0, err := net.Listen("tcp", tip)
25+
assert.Nil(t, err)
26+
defer conn0.Close()
27+
tests[0].Proto = "tcp"
28+
tests[0].Addr = conn0.Addr().String()
29+
tests[0].Expect = ip
30+
31+
tip1 := fmt.Sprintf("%v:8081", ip)
32+
conn1, err := net.ListenPacket("udp", tip1)
33+
fmt.Println("tip1", tip1, err)
34+
assert.Nil(t, err)
35+
defer conn1.Close()
36+
tests[1].Proto = "udp"
37+
tests[1].Addr = conn1.LocalAddr().String()
38+
tests[1].Expect = ip
39+
40+
conn2, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:0"))
41+
assert.Nil(t, err)
42+
defer conn2.Close()
43+
tests[2].Proto = "udp"
44+
tests[2].Addr = conn2.Addr().String()
45+
tests[2].Expect = "127.0.0.1"
46+
47+
conn3, err := net.ListenPacket("udp", fmt.Sprintf("127.0.0.1:8081"))
48+
assert.Nil(t, err)
49+
defer conn3.Close()
50+
tests[3].Proto = "udp"
51+
tests[3].Addr = conn3.LocalAddr().String()
52+
tests[3].Expect = "127.0.0.1"
53+
54+
for i := 0; i < len(tests); i++ {
55+
te := &tests[i]
56+
result, e := GetLocalConnectIP(te.Proto, te.Addr)
57+
assert.Nil(t, e)
58+
assert.Equal(t, te.Expect, result)
59+
}
60+
}

stringutil/strings.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package stringutil
2+
3+
import (
4+
"strings"
5+
)
6+
7+
func Index(s, substr string, start int) int {
8+
return start + strings.Index(s[start:], substr)
9+
}

0 commit comments

Comments
 (0)