mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-04 12:52:28 +08:00
publish lancet
This commit is contained in:
83
netutil/net.go
Normal file
83
netutil/net.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// GetInternalIp return internal ipv4
|
||||
func GetInternalIp() string {
|
||||
addr, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
for _, a := range addr {
|
||||
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
|
||||
if ipNet.IP.To4() != nil {
|
||||
return ipNet.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetPublicIpInfo return public ip information
|
||||
// return the PublicIpInfo struct
|
||||
func GetPublicIpInfo() (*PublicIpInfo, error) {
|
||||
resp, err := http.Get("http://ip-api.com/json/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ip PublicIpInfo
|
||||
err = json.Unmarshal(body, &ip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ip, nil
|
||||
}
|
||||
|
||||
type PublicIpInfo struct {
|
||||
Status string `json:"status"`
|
||||
Country string `json:"country"`
|
||||
CountryCode string `json:"countryCode"`
|
||||
Region string `json:"region"`
|
||||
RegionName string `json:"regionName"`
|
||||
City string `json:"city"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
Isp string `json:"isp"`
|
||||
Org string `json:"org"`
|
||||
As string `json:"as"`
|
||||
Ip string `json:"query"`
|
||||
}
|
||||
|
||||
// IsPublicIP verify a ip is public or not
|
||||
func IsPublicIP(IP net.IP) bool {
|
||||
if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
|
||||
return false
|
||||
}
|
||||
if ip4 := IP.To4(); ip4 != nil {
|
||||
switch {
|
||||
case ip4[0] == 10:
|
||||
return false
|
||||
case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
|
||||
return false
|
||||
case ip4[0] == 192 && ip4[1] == 168:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
46
netutil/net_test.go
Normal file
46
netutil/net_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/utils"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetInternalIp(t *testing.T) {
|
||||
internalIp := GetInternalIp()
|
||||
ip := net.ParseIP(internalIp)
|
||||
if ip == nil {
|
||||
utils.LogFailedTestInfo(t, "GetInternalIp", "GetInternalIp", "", ip)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPublicIpInfo(t *testing.T) {
|
||||
publicIpInfo, err := GetPublicIpInfo()
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
fmt.Printf("public ip info is: %+v \n", *publicIpInfo)
|
||||
}
|
||||
|
||||
func TestIsPublicIP(t *testing.T) {
|
||||
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{false, false, false, false, true}
|
||||
|
||||
for i := 0; i < len(ips); i++ {
|
||||
res := IsPublicIP(ips[i])
|
||||
|
||||
if res != expected[i] {
|
||||
utils.LogFailedTestInfo(t, "IsPublicIP", ips[i], expected[i], res)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
67
netutil/request.go
Normal file
67
netutil/request.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license.
|
||||
|
||||
// Package netutil implements some basic functions to send http request and get ip info.
|
||||
// Note:
|
||||
// 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]interface{},
|
||||
// params[2] is post body which type should be []byte.
|
||||
// params[3] is http client which type should be http.Client.
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//HttpGet send get http request
|
||||
func HttpGet(url string, params ...interface{}) (*http.Response, error) {
|
||||
return request(http.MethodGet, url, params...)
|
||||
}
|
||||
|
||||
//HttpPost send post http request
|
||||
func HttpPost(url string, params ...interface{}) (*http.Response, error) {
|
||||
return request(http.MethodPost, url, params...)
|
||||
}
|
||||
|
||||
//HttpPut send put http request
|
||||
func HttpPut(url string, params ...interface{}) (*http.Response, error) {
|
||||
return request(http.MethodPut, url, params...)
|
||||
}
|
||||
|
||||
//HttpDelete send delete http request
|
||||
func HttpDelete(url string, params ...interface{}) (*http.Response, error) {
|
||||
return request(http.MethodDelete, url, params...)
|
||||
}
|
||||
|
||||
// HttpPatch send patch http request
|
||||
func HttpPatch(url string, params ...interface{}) (*http.Response, error) {
|
||||
return request(http.MethodPatch, url, params...)
|
||||
}
|
||||
|
||||
// ConvertMapToQueryString convert map to sorted url query string
|
||||
func ConvertMapToQueryString(param map[string]interface{}) string {
|
||||
if param == nil {
|
||||
return ""
|
||||
}
|
||||
var keys []string
|
||||
for key := range param {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var build strings.Builder
|
||||
for i, v := range keys {
|
||||
build.WriteString(v)
|
||||
build.WriteString("=")
|
||||
build.WriteString(fmt.Sprintf("%v", param[v]))
|
||||
if i != len(keys)-1 {
|
||||
build.WriteString("&")
|
||||
}
|
||||
}
|
||||
return build.String()
|
||||
}
|
||||
98
netutil/request_test.go
Normal file
98
netutil/request_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"github.com/duke-git/lancet/utils"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHttpGet(t *testing.T) {
|
||||
url := "https://gutendex.com/books?"
|
||||
queryParams := make(map[string]interface{})
|
||||
queryParams["ids"] = "1"
|
||||
|
||||
resp, err := HttpGet(url, nil, queryParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println("response: ", resp.StatusCode, string(body))
|
||||
|
||||
}
|
||||
|
||||
func TestHttpPost(t *testing.T) {
|
||||
url := "http://public-api-v1.aspirantzhang.com/users"
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
user := User{
|
||||
"test",
|
||||
"test@test.com",
|
||||
}
|
||||
bodyParams, _ := json.Marshal(user)
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp, err := HttpPost(url, header, nil, bodyParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
t.FailNow()
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
func TestHttpPut(t *testing.T) {
|
||||
url := "http://public-api-v1.aspirantzhang.com/users/10420"
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
user := User{
|
||||
"test",
|
||||
"test@test.com",
|
||||
}
|
||||
bodyParams, _ := json.Marshal(user)
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp, err := HttpPut(url, header, nil, bodyParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
t.FailNow()
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
func TestHttpDelete(t *testing.T) {
|
||||
url := "http://public-api-v1.aspirantzhang.com/users/10420"
|
||||
resp, err := HttpDelete(url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
t.FailNow()
|
||||
}
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Println("response: ", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
func TestConvertMapToQueryString(t *testing.T) {
|
||||
var m = map[string]interface{}{
|
||||
"c": 3,
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
}
|
||||
|
||||
expected := "a=1&b=2&c=3"
|
||||
r := ConvertMapToQueryString(m)
|
||||
if r != expected {
|
||||
utils.LogFailedTestInfo(t, "ConvertMapToQueryString", m, expected, r)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
181
netutil/request_util.go
Normal file
181
netutil/request_util.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func request(method, reqUrl string, params ...interface{}) (*http.Response, error) {
|
||||
if len(reqUrl) == 0 {
|
||||
return nil, errors.New("url should be specified")
|
||||
}
|
||||
|
||||
req := &http.Request{
|
||||
Method: method,
|
||||
Header: make(http.Header),
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
switch len(params) {
|
||||
case 0:
|
||||
err := setUrl(req, reqUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 1:
|
||||
err := setUrl(req, reqUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setHeader(req, params[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 2:
|
||||
err := setHeader(req, params[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setQueryParam(req, reqUrl, params[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 3:
|
||||
err := setHeader(req, params[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setQueryParam(req, reqUrl, params[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setBodyByte(req, params[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 4:
|
||||
err := setHeader(req, params[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setQueryParam(req, reqUrl, params[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = setBodyByte(req, params[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err = getClient(params[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
resp, e := client.Do(req)
|
||||
return resp, e
|
||||
}
|
||||
|
||||
func setHeader(req *http.Request, header interface{}) error {
|
||||
if header != nil {
|
||||
switch v := header.(type) {
|
||||
case map[string]string:
|
||||
for k := range v {
|
||||
req.Header.Add(k, v[k])
|
||||
}
|
||||
case http.Header:
|
||||
for k, vv := range v {
|
||||
for _, vvv := range vv {
|
||||
req.Header.Add(k, vvv)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("header params type should be http.Header or map[string]string")
|
||||
}
|
||||
}
|
||||
|
||||
if host := req.Header.Get("Host"); host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func setUrl(req *http.Request, reqUrl string) error {
|
||||
u, err := url.Parse(reqUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.URL = u
|
||||
return nil
|
||||
}
|
||||
func setQueryParam(req *http.Request, reqUrl string, queryParam interface{}) error {
|
||||
var values url.Values
|
||||
if queryParam != nil {
|
||||
switch v := queryParam.(type) {
|
||||
case map[string]interface{}:
|
||||
values = url.Values{}
|
||||
for k := range v {
|
||||
values.Set(k, fmt.Sprintf("%s", v[k]))
|
||||
}
|
||||
case url.Values:
|
||||
values = v
|
||||
default:
|
||||
return errors.New("query params type should be url.Values or map[string]interface{}")
|
||||
}
|
||||
}
|
||||
|
||||
// set url
|
||||
if values != nil {
|
||||
if !strings.Contains(reqUrl, "?") {
|
||||
reqUrl = reqUrl + "?" + values.Encode()
|
||||
} else {
|
||||
reqUrl = reqUrl + "&" + values.Encode()
|
||||
}
|
||||
}
|
||||
u, err := url.Parse(reqUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.URL = u
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setBodyByte(req *http.Request, body interface{}) error {
|
||||
if body != nil {
|
||||
var bodyByte []byte
|
||||
if body != nil {
|
||||
switch v := body.(type) {
|
||||
case []byte:
|
||||
bodyByte = v
|
||||
default:
|
||||
return errors.New("body type should be []byte")
|
||||
}
|
||||
}
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(bodyByte))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getClient(client interface{}) (*http.Client, error) {
|
||||
c := http.Client{}
|
||||
if client != nil {
|
||||
switch v := client.(type) {
|
||||
case http.Client:
|
||||
c = v
|
||||
default:
|
||||
return nil, errors.New("client type should be http.Client")
|
||||
}
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
Reference in New Issue
Block a user