Files
gb28181/pkg/gbs/sip/utils.go
T

265 lines
5.6 KiB
Go

package sip
import (
"bytes"
"context"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"io/ioutil"
"log/slog"
"math/rand"
"net"
"net/http"
"time"
"unicode/utf8"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
// Error Error
type Error struct {
err error
params []interface{}
}
func (err *Error) Error() string {
if err == nil {
return "<nil>"
}
str := fmt.Sprint(err.params...)
if err.err != nil {
str += fmt.Sprintf(" err:%s", err.err.Error())
}
return str
}
// NewError NewError
func NewError(err error, params ...interface{}) error {
return &Error{err, params}
}
// JSONEncode JSONEncode
func JSONEncode(data interface{}) []byte {
d, err := json.Marshal(data)
if err != nil {
slog.Error("JSONEncode error:", "err", err)
}
return d
}
// JSONDecode JSONDecode
func JSONDecode(data []byte, obj interface{}) error {
return json.Unmarshal(data, obj)
}
func RandInt(min, max int) int {
if max < min {
return 0
}
max++
max -= min
rand.Seed(time.Now().UnixNano())
r := rand.Int()
return r%max + min
}
const (
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)
// RandString https://github.com/kpbird/golang_random_string
func RandString(n int) string {
rand.Seed(time.Now().UnixNano())
output := make([]byte, n)
// We will take n bytes, one byte for each character of output.
randomness := make([]byte, n)
// read all random
_, err := rand.Read(randomness)
if err != nil {
panic(err)
}
l := len(letterBytes)
// fill output
for pos := range output {
// get random item
random := randomness[pos]
// random % 64
randomPos := random % uint8(l)
// put into output
output[pos] = letterBytes[randomPos]
}
return string(output)
}
func timeoutClient() *http.Client {
connectTimeout := time.Duration(20 * time.Second)
readWriteTimeout := time.Duration(30 * time.Second)
return &http.Client{
Transport: &http.Transport{
DialContext: timeoutDialer(connectTimeout, readWriteTimeout),
MaxIdleConnsPerHost: 200,
DisableKeepAlives: true,
},
}
}
func timeoutDialer(cTimeout time.Duration,
rwTimeout time.Duration,
) func(ctx context.Context, net, addr string) (c net.Conn, err error) {
return func(ctx context.Context, netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, cTimeout)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(rwTimeout))
return conn, nil
}
}
// PostRequest PostRequest
func PostRequest(url string, bodyType string, body io.Reader) ([]byte, error) {
client := timeoutClient()
resp, err := client.Post(url, bodyType, body)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respbody, nil
}
// PostJSONRequest PostJSONRequest
func PostJSONRequest(url string, data interface{}) ([]byte, error) {
bytesData, err := json.Marshal(data)
if err != nil {
return nil, err
}
return PostRequest(url, "application/json;charset=UTF-8", bytes.NewReader(bytesData))
}
// GetRequest GetRequest
func GetRequest(url string) ([]byte, error) {
client := timeoutClient()
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respbody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respbody, nil
}
// XMLDecode 解码 xml
func XMLDecode(data []byte, v interface{}) error {
if err := xmlDecode(data, v); err == nil {
return nil
}
// 有些body xml发送过来的不带encoding ,而且格式不是utf8的,导致xml解析失败,此处使用gbk转utf8后再次尝试xml解析
body, err := GbkToUtf8(data)
if err != nil {
return err
}
return xmlDecode(body, v)
}
func xmlDecode(data []byte, v interface{}) error {
decoder := xml.NewDecoder(bytes.NewReader(data))
decoder.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
if utf8.Valid(data) {
return input, nil
}
return simplifiedchinese.GB18030.NewDecoder().Reader(input), nil
}
return decoder.Decode(v)
}
// XMLEncode XML编码器
func XMLEncode(data any) ([]byte, error) {
b, err := xml.Marshal(data)
if err != nil {
slog.Error("MarshalIndent", "err", err)
return nil, err
}
xmlHeader := "<?xml version=\"1.0\" encoding=\"GB2312\"?>\n"
return Utf8ToGbk([]byte(xmlHeader + string(b)))
}
// Max Max
func Max(a, b int64) int64 {
if a > b {
return a
}
return b
}
// ResolveSelfIP ResolveSelfIP
func ResolveSelfIP() (net.IP, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
addrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
return ip, nil
}
}
return nil, errors.New("server not connected to any network")
}
// GBK 转 UTF-8
func GbkToUtf8(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
d, e := io.ReadAll(reader)
if e != nil {
return nil, e
}
return d, nil
}
// UTF-8 转 GBK
func Utf8ToGbk(s []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
d, e := io.ReadAll(reader)
if e != nil {
return nil, e
}
return d, nil
}