Files
gb28181/pkg/gbs/sip/utils.go
2025-01-31 19:55:33 +08:00

254 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
// 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
}