mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-09-02 10:20:31 +00:00
del[go]: delete golang net for zfoo protocol
This commit is contained in:
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package base
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fmt.Println("base init")
|
||||
}
|
||||
|
||||
func VarTest() {
|
||||
var a string = "Runoob"
|
||||
fmt.Println(a)
|
||||
|
||||
var b, c int = 1, 2
|
||||
fmt.Println(b, c)
|
||||
}
|
||||
|
||||
func NilTest() {
|
||||
var a *int
|
||||
var b []int
|
||||
var c map[string]int
|
||||
var d chan int
|
||||
var e func(string) int
|
||||
var f error // error 是接口
|
||||
|
||||
fmt.Println(a)
|
||||
fmt.Println(b)
|
||||
fmt.Println(c)
|
||||
fmt.Println(d)
|
||||
fmt.Println(e)
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
func ConstTest() {
|
||||
const LENGTH int = 10
|
||||
const WIDTH int = 5
|
||||
var area int
|
||||
const a, b, c = 1, false, "str" //多重赋值
|
||||
|
||||
area = LENGTH * WIDTH
|
||||
fmt.Printf("面积为 : %d", area)
|
||||
println()
|
||||
println(a, b, c)
|
||||
}
|
||||
|
||||
func IfTest() {
|
||||
/* 局部变量定义 */
|
||||
var a int = 100
|
||||
|
||||
/* 判断布尔表达式 */
|
||||
if a < 20 {
|
||||
/* 如果条件为 true 则执行以下语句 */
|
||||
fmt.Println("a 小于 20")
|
||||
} else {
|
||||
/* 如果条件为 false 则执行以下语句 */
|
||||
fmt.Println("a 不小于 20")
|
||||
}
|
||||
fmt.Println("a 的值为 : ", a)
|
||||
}
|
||||
|
||||
func ForTest() {
|
||||
sum := 0
|
||||
for i := 0; i <= 10; i++ {
|
||||
sum += i
|
||||
}
|
||||
fmt.Println(sum)
|
||||
|
||||
// for each
|
||||
var strArray = []string{"google", "runoob"}
|
||||
for i, s := range strArray {
|
||||
fmt.Println(i, s)
|
||||
}
|
||||
|
||||
// for map
|
||||
map1 := make(map[int]float32)
|
||||
map1[1] = 1.0
|
||||
map1[2] = 2.0
|
||||
map1[3] = 3.0
|
||||
map1[4] = 4.0
|
||||
|
||||
// 读取 key 和 value
|
||||
for key, value := range map1 {
|
||||
fmt.Printf("key is: %d - value is: %f\n", key, value)
|
||||
}
|
||||
}
|
||||
|
||||
/* 函数返回两个数的最大值 */
|
||||
func maxTest(num1, num2 int) int {
|
||||
/* 定义局部变量 */
|
||||
var result int
|
||||
|
||||
if num1 > num2 {
|
||||
result = num1
|
||||
} else {
|
||||
result = num2
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Max(num1, num2 int) int {
|
||||
type maxFunc func(int, int) int
|
||||
var max maxFunc
|
||||
max = maxTest
|
||||
return max(num1, num2)
|
||||
}
|
||||
|
||||
var myChan = make(chan string)
|
||||
|
||||
func show(msg string) {
|
||||
fmt.Println(msg)
|
||||
time.Sleep(time.Millisecond * 5000)
|
||||
myChan <- ("go" + msg)
|
||||
}
|
||||
|
||||
func RoutinesTest() {
|
||||
go show("java")
|
||||
fmt.Println("wait...")
|
||||
var msg = <-myChan
|
||||
fmt.Println(msg)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module gonet
|
||||
|
||||
go 1.19
|
||||
@@ -1,900 +0,0 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
const initSize int = 128
|
||||
const maxSize int = 655537
|
||||
|
||||
var initArray []byte = make([]byte, initSize, initSize)
|
||||
|
||||
type ByteBuffer struct {
|
||||
buffer []byte
|
||||
writeIndex int
|
||||
readIndex int
|
||||
}
|
||||
|
||||
// -------------------------------------------------get/set-------------------------------------------------
|
||||
func (byteBuffer *ByteBuffer) WriteOffset() int {
|
||||
return byteBuffer.writeIndex
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) SetWriteOffset(writeIndex int) {
|
||||
if writeIndex > len(byteBuffer.buffer) {
|
||||
var error = fmt.Sprintf("writeIndex:[{%d}] out of bounds exception: readerIndex:[{%d}] , writerIndex:[{%d}] (expected: 0 <= readerIndex <= writerIndex <= capacity:[{%d}])", writeIndex, byteBuffer.readIndex, byteBuffer.writeIndex, len(byteBuffer.buffer))
|
||||
panic(error)
|
||||
}
|
||||
byteBuffer.writeIndex = writeIndex
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) SetReadOffset(readIndex int) {
|
||||
if readIndex > byteBuffer.writeIndex {
|
||||
var error = fmt.Sprintf("readIndex:[{%d}] out of bounds exception: readerIndex:[{%d}] , writerIndex:[{%d}] (expected: 0 <= readerIndex <= writerIndex <= capacity:[{%d}])", readIndex, byteBuffer.readIndex, byteBuffer.writeIndex, len(byteBuffer.buffer))
|
||||
panic(error)
|
||||
}
|
||||
byteBuffer.readIndex = readIndex
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ToBytes() []byte {
|
||||
return byteBuffer.buffer[0:byteBuffer.writeIndex]
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ToString() string {
|
||||
return fmt.Sprintf("writeIndex:[{%d}], readIndex:[{%d}], len:[{%d}], cap:[{%d}]", byteBuffer.writeIndex, byteBuffer.readIndex, len(byteBuffer.buffer), cap(byteBuffer.buffer))
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) GetCapacity() int {
|
||||
return len(byteBuffer.buffer) - byteBuffer.writeIndex
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) EnsureCapacity(capacity int) {
|
||||
for {
|
||||
if byteBuffer.GetCapacity() > capacity {
|
||||
break
|
||||
}
|
||||
|
||||
byteBuffer.buffer = append(byteBuffer.buffer, initArray...)
|
||||
|
||||
if len(byteBuffer.buffer) > maxSize {
|
||||
panic("Bytebuf max size is [655537], out of memory error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) Clear() {
|
||||
byteBuffer.writeIndex = 0
|
||||
byteBuffer.readIndex = 0
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) IsReadable() bool {
|
||||
return byteBuffer.writeIndex > byteBuffer.readIndex
|
||||
}
|
||||
|
||||
// -------------------------------------------------write/read-------------------------------------------------
|
||||
|
||||
// 整形转换成字节
|
||||
func IntToBytes(n int) []byte {
|
||||
var x = int32(n)
|
||||
bytesBuffer := bytes.NewBuffer([]byte{})
|
||||
binary.Write(bytesBuffer, binary.BigEndian, x)
|
||||
return bytesBuffer.Bytes()
|
||||
}
|
||||
|
||||
// 字节转换成整形
|
||||
func BytesToInt(b []byte) int {
|
||||
bytesBuffer := bytes.NewBuffer(b)
|
||||
var x int32
|
||||
binary.Read(bytesBuffer, binary.BigEndian, &x)
|
||||
return int(x)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteBool(value bool) {
|
||||
byteBuffer.EnsureCapacity(1)
|
||||
if value {
|
||||
byteBuffer.buffer[byteBuffer.writeIndex] = 1
|
||||
} else {
|
||||
byteBuffer.buffer[byteBuffer.writeIndex] = 0
|
||||
}
|
||||
byteBuffer.writeIndex++
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadBool() bool {
|
||||
var byteValue = byteBuffer.buffer[byteBuffer.readIndex]
|
||||
byteBuffer.readIndex++
|
||||
return byteValue == 1
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteByte(value int8) {
|
||||
byteBuffer.EnsureCapacity(1)
|
||||
byteBuffer.buffer[byteBuffer.writeIndex] = byte(value)
|
||||
byteBuffer.writeIndex++
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadByte() int8 {
|
||||
var byteValue = byteBuffer.buffer[byteBuffer.readIndex]
|
||||
byteBuffer.readIndex++
|
||||
return int8(byteValue)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteUByte(value byte) {
|
||||
byteBuffer.EnsureCapacity(1)
|
||||
byteBuffer.buffer[byteBuffer.writeIndex] = value
|
||||
byteBuffer.writeIndex++
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadUByte() byte {
|
||||
var byteValue = byteBuffer.buffer[byteBuffer.readIndex]
|
||||
byteBuffer.readIndex++
|
||||
return byteValue
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteUBytes(bytes []byte) {
|
||||
var length = len(bytes)
|
||||
byteBuffer.EnsureCapacity(length)
|
||||
copy(byteBuffer.buffer[byteBuffer.writeIndex:], bytes)
|
||||
byteBuffer.writeIndex += length
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadUBytes(length int) []byte {
|
||||
var readOffset = byteBuffer.readIndex
|
||||
var endOffset = byteBuffer.readIndex + length
|
||||
var bytes = byteBuffer.buffer[readOffset:endOffset]
|
||||
byteBuffer.readIndex += length
|
||||
return bytes
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteShort(value int16) {
|
||||
byteBuffer.EnsureCapacity(2)
|
||||
var bytesBuffer = bytes.NewBuffer([]byte{})
|
||||
binary.Write(bytesBuffer, binary.BigEndian, value)
|
||||
var byteArray = bytesBuffer.Bytes()
|
||||
byteBuffer.WriteUBytes(byteArray)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadShort() int16 {
|
||||
var byteArray = byteBuffer.ReadUBytes(2)
|
||||
bytesBuffer := bytes.NewBuffer(byteArray)
|
||||
var value int16
|
||||
binary.Read(bytesBuffer, binary.BigEndian, &value)
|
||||
return value
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteRawInt32(value int32) {
|
||||
byteBuffer.EnsureCapacity(4)
|
||||
var bytesBuffer = bytes.NewBuffer([]byte{})
|
||||
binary.Write(bytesBuffer, binary.BigEndian, value)
|
||||
var byteArray = bytesBuffer.Bytes()
|
||||
byteBuffer.WriteUBytes(byteArray)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadRawInt32() int32 {
|
||||
var byteArray = byteBuffer.ReadUBytes(4)
|
||||
bytesBuffer := bytes.NewBuffer(byteArray)
|
||||
var value int32
|
||||
binary.Read(bytesBuffer, binary.BigEndian, &value)
|
||||
return value
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteInt(intValue int) {
|
||||
if intValue < math.MinInt32 || intValue > math.MaxInt32 {
|
||||
panic("intValue must range between math.MinInt32:-2147483648 and math.MaxInt32:2147483647")
|
||||
}
|
||||
byteBuffer.WriteInt32(int32(intValue))
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadInt() int {
|
||||
return int(byteBuffer.ReadInt32())
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteInt32(intValue int32) {
|
||||
var value uint32 = uint32(((intValue << 1) ^ (intValue >> 31)))
|
||||
// 右移操作>>是带符号右移
|
||||
if value>>7 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>14 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 7))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>21 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 14))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>28 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 21))
|
||||
return
|
||||
}
|
||||
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 21) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 28))
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadInt32() int32 {
|
||||
var b byte = byteBuffer.ReadUByte()
|
||||
var value uint32 = uint32(b & 0x7F)
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint32(b&0x7F) << 7
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint32(b&0x7F) << 14
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint32(b&0x7F) << 21
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint32(b&0x7F) << 28
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return int32(value>>1) ^ -(int32(value & 1))
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteLong(longValue int64) {
|
||||
var value uint64 = uint64(((longValue << 1) ^ (longValue >> 63)))
|
||||
|
||||
if value>>7 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>14 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 7))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>21 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 14))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>28 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value>>14) | 0x80)
|
||||
byteBuffer.WriteUByte(byte(value >> 21))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>35 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 21) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 28))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>42 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value>>7) | 0x80)
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 21) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 28) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 35))
|
||||
return
|
||||
}
|
||||
|
||||
if value>>49 == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 21) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 28) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 35) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 42))
|
||||
return
|
||||
}
|
||||
|
||||
if (value >> 56) == 0 {
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 21) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 28) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 35) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 42) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 49))
|
||||
return
|
||||
}
|
||||
|
||||
byteBuffer.WriteUByte(byte(value | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 7) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 14) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 21) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 28) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 35) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 42) | 0x80))
|
||||
byteBuffer.WriteUByte(byte((value >> 49) | 0x80))
|
||||
byteBuffer.WriteUByte(byte(value >> 56))
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadLong() int64 {
|
||||
var b byte = byteBuffer.ReadUByte()
|
||||
var value uint64 = uint64(b & 0x7F)
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 7
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 14
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 21
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 28
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 35
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 42
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b&0x7F) << 49
|
||||
if (b & 0x80) != 0 {
|
||||
b = byteBuffer.ReadUByte()
|
||||
value |= uint64(b) << 56
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return int64(value>>1) ^ -(int64(value & 1))
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteFloat(value float32) {
|
||||
byteBuffer.EnsureCapacity(4)
|
||||
var bytesBuffer = bytes.NewBuffer([]byte{})
|
||||
binary.Write(bytesBuffer, binary.BigEndian, value)
|
||||
var byteArray = bytesBuffer.Bytes()
|
||||
byteBuffer.WriteUBytes(byteArray)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadFloat() float32 {
|
||||
var byteArray = byteBuffer.ReadUBytes(4)
|
||||
bytesBuffer := bytes.NewBuffer(byteArray)
|
||||
var value float32
|
||||
binary.Read(bytesBuffer, binary.BigEndian, &value)
|
||||
return value
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteDouble(value float64) {
|
||||
byteBuffer.EnsureCapacity(8)
|
||||
var bytesBuffer = bytes.NewBuffer([]byte{})
|
||||
binary.Write(bytesBuffer, binary.BigEndian, value)
|
||||
var byteArray = bytesBuffer.Bytes()
|
||||
byteBuffer.WriteUBytes(byteArray)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadDouble() float64 {
|
||||
var byteArray = byteBuffer.ReadUBytes(8)
|
||||
bytesBuffer := bytes.NewBuffer(byteArray)
|
||||
var value float64
|
||||
binary.Read(bytesBuffer, binary.BigEndian, &value)
|
||||
return value
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteString(value string) {
|
||||
var bytes []byte = []byte(value)
|
||||
var length = len(bytes)
|
||||
byteBuffer.EnsureCapacity(length)
|
||||
byteBuffer.WriteInt(length)
|
||||
byteBuffer.WriteUBytes(bytes)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadString() string {
|
||||
var length = byteBuffer.ReadInt()
|
||||
var bytes = byteBuffer.ReadUBytes(length)
|
||||
return string(bytes[:])
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteChar(value string) {
|
||||
// 如果为空则写入一个默认的字符0
|
||||
if len(value) == 0 {
|
||||
byteBuffer.WriteInt(0)
|
||||
byteBuffer.WriteUByte(0)
|
||||
return
|
||||
}
|
||||
var char = value[0:1]
|
||||
byteBuffer.WriteString(char)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadChar() string {
|
||||
return byteBuffer.ReadString()
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WritePacketFlag(packet any) bool {
|
||||
var flag = packet == nil
|
||||
byteBuffer.WriteBool(!flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WritePacket(packet any, protocolId int16) {
|
||||
var protocolRegistration = GetProtocol(protocolId)
|
||||
protocolRegistration.write(byteBuffer, packet)
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadPacket(protocolId int16) any {
|
||||
var protocolRegistration = GetProtocol(protocolId)
|
||||
return protocolRegistration.read(byteBuffer)
|
||||
}
|
||||
|
||||
// -------------------------------------------------IProtocolRegistration-------------------------------------------------
|
||||
type IProtocolRegistration interface {
|
||||
ProtocolId() int16
|
||||
|
||||
write(buffer *ByteBuffer, packet any)
|
||||
|
||||
read(buffer *ByteBuffer) any
|
||||
}
|
||||
|
||||
// protocol map
|
||||
var Protocols = make(map[int16]IProtocolRegistration)
|
||||
|
||||
func GetProtocol(protocolId int16) IProtocolRegistration {
|
||||
return Protocols[protocolId]
|
||||
}
|
||||
|
||||
func Write(buffer *ByteBuffer, packet any) {
|
||||
var protocolId = packet.(IProtocolRegistration).ProtocolId()
|
||||
buffer.WriteShort(protocolId)
|
||||
var protocolRegistration = GetProtocol(protocolId)
|
||||
protocolRegistration.write(buffer, packet)
|
||||
}
|
||||
|
||||
func Read(buffer *ByteBuffer) any {
|
||||
var protocolId = buffer.ReadShort()
|
||||
return GetProtocol(protocolId).read(buffer)
|
||||
}
|
||||
|
||||
// -------------------------------------------------CutDown-------------------------------------------------
|
||||
func (byteBuffer *ByteBuffer) WriteBooleanArray(array []bool) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteBool(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadBooleanArray() []bool {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]bool, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadBool()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteByteArray(array []int8) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteByte(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadByteArray() []int8 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]int8, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadByte()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteShortArray(array []int16) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteShort(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadShortArray() []int16 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]int16, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadShort()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteIntArray(array []int) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteInt(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadIntArray() []int {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]int, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadInt()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteLongArray(array []int64) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteLong(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadLongArray() []int64 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]int64, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadLong()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteFloatArray(array []float32) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteFloat(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadFloatArray() []float32 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]float32, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadFloat()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteDoubleArray(array []float64) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteDouble(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadDoubleArray() []float64 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]float64, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadDouble()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteCharArray(array []string) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteChar(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadCharArray() []string {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]string, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadChar()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteStringArray(array []string) {
|
||||
if array == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(array))
|
||||
for _, value := range array {
|
||||
byteBuffer.WriteString(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadStringArray() []string {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var array = make([]string, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
array[i] = byteBuffer.ReadString()
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteIntIntMap(m map[int]int) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteInt(key)
|
||||
byteBuffer.WriteInt(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadIntIntMap() map[int]int {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[int]int, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadInt()
|
||||
var value = byteBuffer.ReadInt()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteIntLongMap(m map[int]int64) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteInt(key)
|
||||
byteBuffer.WriteLong(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadIntLongMap() map[int]int64 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[int]int64, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadInt()
|
||||
var value = byteBuffer.ReadLong()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteIntStringMap(m map[int]string) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteInt(key)
|
||||
byteBuffer.WriteString(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadIntStringMap() map[int]string {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[int]string, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadInt()
|
||||
var value = byteBuffer.ReadString()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteLongIntMap(m map[int64]int) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteLong(key)
|
||||
byteBuffer.WriteInt(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadLongIntMap() map[int64]int {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[int64]int, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadLong()
|
||||
var value = byteBuffer.ReadInt()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteLongLongMap(m map[int64]int64) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteLong(key)
|
||||
byteBuffer.WriteLong(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadLongLongMap() map[int64]int64 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[int64]int64, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadLong()
|
||||
var value = byteBuffer.ReadLong()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteLongStringMap(m map[int64]string) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteLong(key)
|
||||
byteBuffer.WriteString(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadLongStringMap() map[int64]string {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[int64]string, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadLong()
|
||||
var value = byteBuffer.ReadString()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteStringIntMap(m map[string]int) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteString(key)
|
||||
byteBuffer.WriteInt(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadStringIntMap() map[string]int {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[string]int, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadString()
|
||||
var value = byteBuffer.ReadInt()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteStringLongMap(m map[string]int64) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteString(key)
|
||||
byteBuffer.WriteLong(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadStringLongMap() map[string]int64 {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[string]int64, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadString()
|
||||
var value = byteBuffer.ReadLong()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) WriteStringStringMap(m map[string]string) {
|
||||
if m == nil {
|
||||
byteBuffer.WriteInt(0)
|
||||
} else {
|
||||
byteBuffer.WriteInt(len(m))
|
||||
for key, value := range m {
|
||||
byteBuffer.WriteString(key)
|
||||
byteBuffer.WriteString(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (byteBuffer *ByteBuffer) ReadStringStringMap() map[string]string {
|
||||
var size = byteBuffer.ReadInt()
|
||||
var m = make(map[string]string, size)
|
||||
if size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
var key = byteBuffer.ReadString()
|
||||
var value = byteBuffer.ReadString()
|
||||
m[key] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package protocol
|
||||
|
||||
func init() {
|
||||
Protocols[100] = new(Message)
|
||||
Protocols[101] = new(Error)
|
||||
Protocols[102] = new(Heartbeat)
|
||||
Protocols[103] = new(Ping)
|
||||
Protocols[104] = new(Pong)
|
||||
Protocols[111] = new(PairLong)
|
||||
Protocols[112] = new(PairString)
|
||||
Protocols[113] = new(PairLS)
|
||||
Protocols[114] = new(TripleLong)
|
||||
Protocols[115] = new(TripleString)
|
||||
Protocols[116] = new(TripleLSS)
|
||||
Protocols[1200] = new(UdpHelloRequest)
|
||||
Protocols[1201] = new(UdpHelloResponse)
|
||||
Protocols[1300] = new(TcpHelloRequest)
|
||||
Protocols[1301] = new(TcpHelloResponse)
|
||||
Protocols[1500] = new(JProtobufHelloRequest)
|
||||
Protocols[1501] = new(JProtobufHelloResponse)
|
||||
Protocols[1600] = new(JsonHelloRequest)
|
||||
Protocols[1601] = new(JsonHelloResponse)
|
||||
Protocols[5000] = new(GatewayToProviderRequest)
|
||||
Protocols[5001] = new(GatewayToProviderResponse)
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
package protocol
|
||||
|
||||
type Message struct {
|
||||
Code int
|
||||
Message string
|
||||
Module int8
|
||||
}
|
||||
|
||||
func (protocol Message) ProtocolId() int16 {
|
||||
return 100
|
||||
}
|
||||
|
||||
func (protocol Message) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*Message)
|
||||
buffer.WriteInt(message.Code)
|
||||
buffer.WriteString(message.Message)
|
||||
buffer.WriteByte(message.Module)
|
||||
}
|
||||
|
||||
func (protocol Message) read(buffer *ByteBuffer) any {
|
||||
var packet = new(Message)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadInt()
|
||||
packet.Code = result0
|
||||
var result1 = buffer.ReadString()
|
||||
packet.Message = result1
|
||||
var result2 = buffer.ReadByte()
|
||||
packet.Module = result2
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type Error struct {
|
||||
ErrorCode int
|
||||
ErrorMessage string
|
||||
Module int
|
||||
}
|
||||
|
||||
func (protocol Error) ProtocolId() int16 {
|
||||
return 101
|
||||
}
|
||||
|
||||
func (protocol Error) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*Error)
|
||||
buffer.WriteInt(message.ErrorCode)
|
||||
buffer.WriteString(message.ErrorMessage)
|
||||
buffer.WriteInt(message.Module)
|
||||
}
|
||||
|
||||
func (protocol Error) read(buffer *ByteBuffer) any {
|
||||
var packet = new(Error)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadInt()
|
||||
packet.ErrorCode = result0
|
||||
var result1 = buffer.ReadString()
|
||||
packet.ErrorMessage = result1
|
||||
var result2 = buffer.ReadInt()
|
||||
packet.Module = result2
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type Heartbeat struct {
|
||||
|
||||
}
|
||||
|
||||
func (protocol Heartbeat) ProtocolId() int16 {
|
||||
return 102
|
||||
}
|
||||
|
||||
func (protocol Heartbeat) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (protocol Heartbeat) read(buffer *ByteBuffer) any {
|
||||
var packet = new(Heartbeat)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type Ping struct {
|
||||
|
||||
}
|
||||
|
||||
func (protocol Ping) ProtocolId() int16 {
|
||||
return 103
|
||||
}
|
||||
|
||||
func (protocol Ping) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (protocol Ping) read(buffer *ByteBuffer) any {
|
||||
var packet = new(Ping)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type Pong struct {
|
||||
Time int64
|
||||
}
|
||||
|
||||
func (protocol Pong) ProtocolId() int16 {
|
||||
return 104
|
||||
}
|
||||
|
||||
func (protocol Pong) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*Pong)
|
||||
buffer.WriteLong(message.Time)
|
||||
}
|
||||
|
||||
func (protocol Pong) read(buffer *ByteBuffer) any {
|
||||
var packet = new(Pong)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadLong()
|
||||
packet.Time = result0
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type PairLong struct {
|
||||
Key int64
|
||||
Value int64
|
||||
}
|
||||
|
||||
func (protocol PairLong) ProtocolId() int16 {
|
||||
return 111
|
||||
}
|
||||
|
||||
func (protocol PairLong) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*PairLong)
|
||||
buffer.WriteLong(message.Key)
|
||||
buffer.WriteLong(message.Value)
|
||||
}
|
||||
|
||||
func (protocol PairLong) read(buffer *ByteBuffer) any {
|
||||
var packet = new(PairLong)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadLong()
|
||||
packet.Key = result0
|
||||
var result1 = buffer.ReadLong()
|
||||
packet.Value = result1
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type PairString struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
func (protocol PairString) ProtocolId() int16 {
|
||||
return 112
|
||||
}
|
||||
|
||||
func (protocol PairString) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*PairString)
|
||||
buffer.WriteString(message.Key)
|
||||
buffer.WriteString(message.Value)
|
||||
}
|
||||
|
||||
func (protocol PairString) read(buffer *ByteBuffer) any {
|
||||
var packet = new(PairString)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Key = result0
|
||||
var result1 = buffer.ReadString()
|
||||
packet.Value = result1
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type PairLS struct {
|
||||
Key int64
|
||||
Value string
|
||||
}
|
||||
|
||||
func (protocol PairLS) ProtocolId() int16 {
|
||||
return 113
|
||||
}
|
||||
|
||||
func (protocol PairLS) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*PairLS)
|
||||
buffer.WriteLong(message.Key)
|
||||
buffer.WriteString(message.Value)
|
||||
}
|
||||
|
||||
func (protocol PairLS) read(buffer *ByteBuffer) any {
|
||||
var packet = new(PairLS)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadLong()
|
||||
packet.Key = result0
|
||||
var result1 = buffer.ReadString()
|
||||
packet.Value = result1
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type TripleLong struct {
|
||||
Left int64
|
||||
Middle int64
|
||||
Right int64
|
||||
}
|
||||
|
||||
func (protocol TripleLong) ProtocolId() int16 {
|
||||
return 114
|
||||
}
|
||||
|
||||
func (protocol TripleLong) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*TripleLong)
|
||||
buffer.WriteLong(message.Left)
|
||||
buffer.WriteLong(message.Middle)
|
||||
buffer.WriteLong(message.Right)
|
||||
}
|
||||
|
||||
func (protocol TripleLong) read(buffer *ByteBuffer) any {
|
||||
var packet = new(TripleLong)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadLong()
|
||||
packet.Left = result0
|
||||
var result1 = buffer.ReadLong()
|
||||
packet.Middle = result1
|
||||
var result2 = buffer.ReadLong()
|
||||
packet.Right = result2
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type TripleString struct {
|
||||
Left string
|
||||
Middle string
|
||||
Right string
|
||||
}
|
||||
|
||||
func (protocol TripleString) ProtocolId() int16 {
|
||||
return 115
|
||||
}
|
||||
|
||||
func (protocol TripleString) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*TripleString)
|
||||
buffer.WriteString(message.Left)
|
||||
buffer.WriteString(message.Middle)
|
||||
buffer.WriteString(message.Right)
|
||||
}
|
||||
|
||||
func (protocol TripleString) read(buffer *ByteBuffer) any {
|
||||
var packet = new(TripleString)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Left = result0
|
||||
var result1 = buffer.ReadString()
|
||||
packet.Middle = result1
|
||||
var result2 = buffer.ReadString()
|
||||
packet.Right = result2
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type TripleLSS struct {
|
||||
Left int64
|
||||
Middle string
|
||||
Right string
|
||||
}
|
||||
|
||||
func (protocol TripleLSS) ProtocolId() int16 {
|
||||
return 116
|
||||
}
|
||||
|
||||
func (protocol TripleLSS) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*TripleLSS)
|
||||
buffer.WriteLong(message.Left)
|
||||
buffer.WriteString(message.Middle)
|
||||
buffer.WriteString(message.Right)
|
||||
}
|
||||
|
||||
func (protocol TripleLSS) read(buffer *ByteBuffer) any {
|
||||
var packet = new(TripleLSS)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadLong()
|
||||
packet.Left = result0
|
||||
var result1 = buffer.ReadString()
|
||||
packet.Middle = result1
|
||||
var result2 = buffer.ReadString()
|
||||
packet.Right = result2
|
||||
return packet
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package protocol
|
||||
|
||||
type GatewayToProviderRequest struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol GatewayToProviderRequest) ProtocolId() int16 {
|
||||
return 5000
|
||||
}
|
||||
|
||||
func (protocol GatewayToProviderRequest) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*GatewayToProviderRequest)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol GatewayToProviderRequest) read(buffer *ByteBuffer) any {
|
||||
var packet = new(GatewayToProviderRequest)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type GatewayToProviderResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol GatewayToProviderResponse) ProtocolId() int16 {
|
||||
return 5001
|
||||
}
|
||||
|
||||
func (protocol GatewayToProviderResponse) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*GatewayToProviderResponse)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol GatewayToProviderResponse) read(buffer *ByteBuffer) any {
|
||||
var packet = new(GatewayToProviderResponse)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package protocol
|
||||
|
||||
type JProtobufHelloRequest struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol JProtobufHelloRequest) ProtocolId() int16 {
|
||||
return 1500
|
||||
}
|
||||
|
||||
func (protocol JProtobufHelloRequest) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*JProtobufHelloRequest)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol JProtobufHelloRequest) read(buffer *ByteBuffer) any {
|
||||
var packet = new(JProtobufHelloRequest)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type JProtobufHelloResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol JProtobufHelloResponse) ProtocolId() int16 {
|
||||
return 1501
|
||||
}
|
||||
|
||||
func (protocol JProtobufHelloResponse) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*JProtobufHelloResponse)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol JProtobufHelloResponse) read(buffer *ByteBuffer) any {
|
||||
var packet = new(JProtobufHelloResponse)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package protocol
|
||||
|
||||
type JsonHelloRequest struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol JsonHelloRequest) ProtocolId() int16 {
|
||||
return 1600
|
||||
}
|
||||
|
||||
func (protocol JsonHelloRequest) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*JsonHelloRequest)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol JsonHelloRequest) read(buffer *ByteBuffer) any {
|
||||
var packet = new(JsonHelloRequest)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type JsonHelloResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol JsonHelloResponse) ProtocolId() int16 {
|
||||
return 1601
|
||||
}
|
||||
|
||||
func (protocol JsonHelloResponse) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*JsonHelloResponse)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol JsonHelloResponse) read(buffer *ByteBuffer) any {
|
||||
var packet = new(JsonHelloResponse)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package protocol
|
||||
|
||||
type TcpHelloRequest struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol TcpHelloRequest) ProtocolId() int16 {
|
||||
return 1300
|
||||
}
|
||||
|
||||
func (protocol TcpHelloRequest) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*TcpHelloRequest)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol TcpHelloRequest) read(buffer *ByteBuffer) any {
|
||||
var packet = new(TcpHelloRequest)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type TcpHelloResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol TcpHelloResponse) ProtocolId() int16 {
|
||||
return 1301
|
||||
}
|
||||
|
||||
func (protocol TcpHelloResponse) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*TcpHelloResponse)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol TcpHelloResponse) read(buffer *ByteBuffer) any {
|
||||
var packet = new(TcpHelloResponse)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package protocol
|
||||
|
||||
type UdpHelloRequest struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol UdpHelloRequest) ProtocolId() int16 {
|
||||
return 1200
|
||||
}
|
||||
|
||||
func (protocol UdpHelloRequest) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*UdpHelloRequest)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol UdpHelloRequest) read(buffer *ByteBuffer) any {
|
||||
var packet = new(UdpHelloRequest)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
|
||||
|
||||
type UdpHelloResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (protocol UdpHelloResponse) ProtocolId() int16 {
|
||||
return 1201
|
||||
}
|
||||
|
||||
func (protocol UdpHelloResponse) write(buffer *ByteBuffer, packet any) {
|
||||
if buffer.WritePacketFlag(packet) {
|
||||
return
|
||||
}
|
||||
var message = packet.(*UdpHelloResponse)
|
||||
buffer.WriteString(message.Message)
|
||||
}
|
||||
|
||||
func (protocol UdpHelloResponse) read(buffer *ByteBuffer) any {
|
||||
var packet = new(UdpHelloResponse)
|
||||
if !buffer.ReadBool() {
|
||||
return packet
|
||||
}
|
||||
var result0 = buffer.ReadString()
|
||||
packet.Message = result0
|
||||
return packet
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gonet/base"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("hello world")
|
||||
|
||||
//base.VarTest()
|
||||
//base.NilTest()
|
||||
//base.ConstTest()
|
||||
//base.IfTest()
|
||||
//base.ForTest()
|
||||
//fmt.Println(base.Max(1, 2))
|
||||
base.RoutinesTest()
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Encode from Message to []byte
|
||||
func Encode(msg *Message) ([]byte, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
err := binary.Write(buffer, binary.LittleEndian, msg.msgSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Write(buffer, binary.LittleEndian, msg.msgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Write(buffer, binary.LittleEndian, msg.data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// Decode from []byte to Message
|
||||
func Decode(data []byte) (*Message, error) {
|
||||
bufReader := bytes.NewReader(data)
|
||||
|
||||
dataSize := len(data)
|
||||
// 读取消息ID
|
||||
var msgID int32
|
||||
err := binary.Read(bufReader, binary.LittleEndian, &msgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 读取数据
|
||||
dataBufLength := dataSize - 4 - 4
|
||||
dataBuf := make([]byte, dataBufLength)
|
||||
err = binary.Read(bufReader, binary.LittleEndian, &dataBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
message := &Message{}
|
||||
message.msgSize = int32(dataSize)
|
||||
message.msgID = msgID
|
||||
message.data = dataBuf
|
||||
|
||||
return message, nil
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package net
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCodec(t *testing.T) {
|
||||
// test encode
|
||||
msg1 := NewMessage(1, []byte("message codec test..."))
|
||||
|
||||
data, err := Encode(msg1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(msg1)
|
||||
|
||||
// test decode
|
||||
// The first four bytes is size for socket read
|
||||
msg2, err := Decode(data[4:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("ID=%d, Data=%s", msg2.msgID, string(msg2.data))
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Conn wrap net.Conn
|
||||
type Conn struct {
|
||||
sid string
|
||||
rawConn net.Conn
|
||||
sendCh chan []byte
|
||||
done chan error
|
||||
hbTimer *time.Timer
|
||||
name string
|
||||
messageCh chan *Message
|
||||
hbInterval time.Duration
|
||||
hbTimeout time.Duration
|
||||
}
|
||||
|
||||
// GetName Get conn name
|
||||
func (c *Conn) GetName() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
// NewConn create new conn
|
||||
func NewConn(c net.Conn, hbInterval time.Duration, hbTimeout time.Duration) *Conn {
|
||||
conn := &Conn{
|
||||
rawConn: c,
|
||||
sendCh: make(chan []byte, 100),
|
||||
done: make(chan error),
|
||||
messageCh: make(chan *Message, 100),
|
||||
hbInterval: hbInterval,
|
||||
hbTimeout: hbTimeout,
|
||||
}
|
||||
|
||||
conn.name = c.RemoteAddr().String()
|
||||
conn.hbTimer = time.NewTimer(conn.hbInterval)
|
||||
|
||||
if conn.hbInterval == 0 {
|
||||
conn.hbTimer.Stop()
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
// Close close connection
|
||||
func (c *Conn) Close() {
|
||||
c.hbTimer.Stop()
|
||||
c.rawConn.Close()
|
||||
}
|
||||
|
||||
// SendMessage send message
|
||||
func (c *Conn) SendMessage(msg *Message) error {
|
||||
pkg, err := Encode(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.sendCh <- pkg
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeCoroutine write coroutine
|
||||
func (c *Conn) writeCoroutine(ctx context.Context) {
|
||||
hbData := make([]byte, 0)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case pkt := <-c.sendCh:
|
||||
|
||||
if pkt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := c.rawConn.Write(pkt); err != nil {
|
||||
c.done <- err
|
||||
}
|
||||
|
||||
case <-c.hbTimer.C:
|
||||
hbMessage := NewMessage(MsgHeartbeat, hbData)
|
||||
c.SendMessage(hbMessage)
|
||||
// 设置心跳timer
|
||||
if c.hbInterval > 0 {
|
||||
c.hbTimer.Reset(c.hbInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// readCoroutine read coroutine
|
||||
func (c *Conn) readCoroutine(ctx context.Context) {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
default:
|
||||
// 设置超时
|
||||
if c.hbInterval > 0 {
|
||||
err := c.rawConn.SetReadDeadline(time.Now().Add(c.hbTimeout))
|
||||
if err != nil {
|
||||
c.done <- err
|
||||
continue
|
||||
}
|
||||
}
|
||||
// 读取长度
|
||||
buf := make([]byte, 4)
|
||||
_, err := io.ReadFull(c.rawConn, buf)
|
||||
if err != nil {
|
||||
c.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
bufReader := bytes.NewReader(buf)
|
||||
|
||||
var dataSize int32
|
||||
err = binary.Read(bufReader, binary.LittleEndian, &dataSize)
|
||||
if err != nil {
|
||||
c.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
// 读取数据
|
||||
databuf := make([]byte, dataSize)
|
||||
_, err = io.ReadFull(c.rawConn, databuf)
|
||||
if err != nil {
|
||||
c.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
// 解码
|
||||
msg, err := Decode(databuf)
|
||||
if err != nil {
|
||||
c.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
if msg.msgID == MsgHeartbeat {
|
||||
continue
|
||||
}
|
||||
|
||||
c.messageCh <- msg
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package net
|
||||
|
||||
const (
|
||||
// STUnknown Unknown
|
||||
STUnknown = iota
|
||||
// STInited Inited
|
||||
STInited
|
||||
// STRunning Running
|
||||
STRunning
|
||||
// STStop Stop
|
||||
STStop
|
||||
)
|
||||
|
||||
const (
|
||||
// MsgHeartbeat heartbeat
|
||||
MsgHeartbeat = iota
|
||||
)
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Message struct
|
||||
type Message struct {
|
||||
msgSize int32
|
||||
msgID int32
|
||||
data []byte
|
||||
}
|
||||
|
||||
// NewMessage create a new message
|
||||
func NewMessage(msgID int32, data []byte) *Message {
|
||||
msg := &Message{
|
||||
msgSize: int32(len(data)) + 4 + 4,
|
||||
msgID: msgID,
|
||||
data: data,
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
|
||||
func (msg *Message) String() string {
|
||||
return fmt.Sprintf("Size=%d ID=%d DataLen=%d", msg.msgSize, msg.msgID, len(msg.data))
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SocketService struct
|
||||
type SocketService struct {
|
||||
onMessage func(*Session, *Message)
|
||||
onConnect func(*Session)
|
||||
onDisconnect func(*Session, error)
|
||||
sessions *sync.Map
|
||||
hbInterval time.Duration
|
||||
hbTimeout time.Duration
|
||||
laddr string
|
||||
status int
|
||||
listener net.Listener
|
||||
stopCh chan error
|
||||
}
|
||||
|
||||
// NewSocketService create a new socket service
|
||||
func NewSocketService(laddr string) (*SocketService, error) {
|
||||
|
||||
l, err := net.Listen("tcp", laddr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &SocketService{
|
||||
sessions: &sync.Map{},
|
||||
stopCh: make(chan error),
|
||||
hbInterval: 0 * time.Second,
|
||||
hbTimeout: 0 * time.Second,
|
||||
laddr: laddr,
|
||||
status: STInited,
|
||||
listener: l,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// RegMessageHandler register message handler
|
||||
func (s *SocketService) RegMessageHandler(handler func(*Session, *Message)) {
|
||||
s.onMessage = handler
|
||||
}
|
||||
|
||||
// RegConnectHandler register connect handler
|
||||
func (s *SocketService) RegConnectHandler(handler func(*Session)) {
|
||||
s.onConnect = handler
|
||||
}
|
||||
|
||||
// RegDisconnectHandler register disconnect handler
|
||||
func (s *SocketService) RegDisconnectHandler(handler func(*Session, error)) {
|
||||
s.onDisconnect = handler
|
||||
}
|
||||
|
||||
// Serv Start socket service
|
||||
func (s *SocketService) Serv() {
|
||||
|
||||
s.status = STRunning
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
defer func() {
|
||||
s.status = STStop
|
||||
cancel()
|
||||
s.listener.Close()
|
||||
}()
|
||||
|
||||
go s.acceptHandler(ctx)
|
||||
|
||||
for {
|
||||
select {
|
||||
|
||||
case <-s.stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SocketService) acceptHandler(ctx context.Context) {
|
||||
for {
|
||||
c, err := s.listener.Accept()
|
||||
if err != nil {
|
||||
s.stopCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
go s.connectHandler(ctx, c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SocketService) connectHandler(ctx context.Context, c net.Conn) {
|
||||
conn := NewConn(c, s.hbInterval, s.hbTimeout)
|
||||
session := NewSession(conn)
|
||||
s.sessions.Store(session.GetSessionID(), session)
|
||||
|
||||
connctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
defer func() {
|
||||
cancel()
|
||||
conn.Close()
|
||||
s.sessions.Delete(session.GetSessionID())
|
||||
}()
|
||||
|
||||
go conn.readCoroutine(connctx)
|
||||
go conn.writeCoroutine(connctx)
|
||||
|
||||
if s.onConnect != nil {
|
||||
s.onConnect(session)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-conn.done:
|
||||
|
||||
if s.onDisconnect != nil {
|
||||
s.onDisconnect(session, err)
|
||||
}
|
||||
return
|
||||
|
||||
case msg := <-conn.messageCh:
|
||||
if s.onMessage != nil {
|
||||
s.onMessage(session, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetStatus get socket service status
|
||||
func (s *SocketService) GetStatus() int {
|
||||
return s.status
|
||||
}
|
||||
|
||||
// Stop stop socket service with reason
|
||||
func (s *SocketService) Stop(reason string) {
|
||||
s.stopCh <- errors.New(reason)
|
||||
}
|
||||
|
||||
// SetHeartBeat set heart beat
|
||||
func (s *SocketService) SetHeartBeat(hbInterval time.Duration, hbTimeout time.Duration) error {
|
||||
if s.status == STRunning {
|
||||
return errors.New("Can't set heart beat on service running")
|
||||
}
|
||||
|
||||
s.hbInterval = hbInterval
|
||||
s.hbTimeout = hbTimeout
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetConnsCount get connect count
|
||||
func (s *SocketService) GetConnsCount() int {
|
||||
var count int
|
||||
s.sessions.Range(func(k, v interface{}) bool {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
// Unicast Unicast with session ID
|
||||
func (s *SocketService) Unicast(sid string, msg *Message) {
|
||||
v, ok := s.sessions.Load(sid)
|
||||
if ok {
|
||||
session := v.(*Session)
|
||||
err := session.GetConn().SendMessage(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Broadcast Broadcast to all connections
|
||||
func (s *SocketService) Broadcast(msg *Message) {
|
||||
s.sessions.Range(func(k, v interface{}) bool {
|
||||
s := v.(*Session)
|
||||
if err := s.GetConn().SendMessage(msg); err != nil {
|
||||
// log.Println(err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
host := "127.0.0.1:18787"
|
||||
|
||||
ss, err := NewSocketService(host)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// ss.SetHeartBeat(5*time.Second, 30*time.Second)
|
||||
|
||||
ss.RegMessageHandler(HandleMessage)
|
||||
ss.RegConnectHandler(HandleConnect)
|
||||
ss.RegDisconnectHandler(HandleDisconnect)
|
||||
|
||||
go NewClientConnect()
|
||||
|
||||
timer := time.NewTimer(time.Second * 1)
|
||||
go func() {
|
||||
<-timer.C
|
||||
ss.Stop("stop service")
|
||||
t.Log("service stoped")
|
||||
}()
|
||||
|
||||
t.Log("service running on " + host)
|
||||
ss.Serv()
|
||||
}
|
||||
|
||||
func HandleMessage(s *Session, msg *Message) {
|
||||
fmt.Println("receive msgID:", msg)
|
||||
fmt.Println("receive data:", string(msg.data))
|
||||
}
|
||||
|
||||
func HandleDisconnect(s *Session, err error) {
|
||||
fmt.Println(s.GetConn().GetName() + " lost.")
|
||||
}
|
||||
|
||||
func HandleConnect(s *Session) {
|
||||
fmt.Println(s.GetConn().GetName() + " connected.")
|
||||
}
|
||||
|
||||
func NewClientConnect() {
|
||||
host := "127.0.0.1:18787"
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp", host)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := net.DialTCP("tcp", nil, tcpAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := NewMessage(1, []byte("Hello Zero!"))
|
||||
data, err := Encode(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.Write(data)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package net
|
||||
|
||||
// Session struct
|
||||
type Session struct {
|
||||
sID string
|
||||
uID string
|
||||
conn *Conn
|
||||
settings map[string]interface{}
|
||||
}
|
||||
|
||||
// NewSession create a new session
|
||||
func NewSession(conn *Conn) *Session {
|
||||
id := TimeUUID()
|
||||
session := &Session{
|
||||
sID: id.String(),
|
||||
uID: "",
|
||||
conn: conn,
|
||||
settings: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
// GetSessionID get session ID
|
||||
func (s *Session) GetSessionID() string {
|
||||
return s.sID
|
||||
}
|
||||
|
||||
// BindUserID bind a user ID to session
|
||||
func (s *Session) BindUserID(uid string) {
|
||||
s.uID = uid
|
||||
}
|
||||
|
||||
// GetUserID get user ID
|
||||
func (s *Session) GetUserID() string {
|
||||
return s.uID
|
||||
}
|
||||
|
||||
// GetConn get zero.Conn pointer
|
||||
func (s *Session) GetConn() *Conn {
|
||||
return s.conn
|
||||
}
|
||||
|
||||
// SetConn set a zero.Conn to session
|
||||
func (s *Session) SetConn(conn *Conn) {
|
||||
s.conn = conn
|
||||
}
|
||||
|
||||
// GetSetting get setting
|
||||
func (s *Session) GetSetting(key string) interface{} {
|
||||
|
||||
if v, ok := s.settings[key]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSetting set setting
|
||||
func (s *Session) SetSetting(key string, value interface{}) {
|
||||
s.settings[key] = value
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package net
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UUID [16]byte
|
||||
|
||||
var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
|
||||
var hardwareAddr []byte
|
||||
var clockSeq uint32
|
||||
|
||||
func TimeUUID() UUID {
|
||||
return FromTime(time.Now())
|
||||
}
|
||||
|
||||
func FromTime(aTime time.Time) UUID {
|
||||
var u UUID
|
||||
|
||||
utcTime := aTime.In(time.UTC)
|
||||
t := uint64(utcTime.Unix()-timeBase)*10000000 + uint64(utcTime.Nanosecond()/100)
|
||||
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
|
||||
u[4], u[5] = byte(t>>40), byte(t>>32)
|
||||
u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
|
||||
|
||||
clock := atomic.AddUint32(&clockSeq, 1)
|
||||
u[8] = byte(clock >> 8)
|
||||
u[9] = byte(clock)
|
||||
|
||||
copy(u[10:], hardwareAddr)
|
||||
|
||||
u[6] |= 0x10 // set version to 1 (time based uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func (u UUID) String() string {
|
||||
var offsets = [...]int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34}
|
||||
const hexString = "0123456789abcdef"
|
||||
r := make([]byte, 36)
|
||||
for i, b := range u {
|
||||
r[offsets[i]] = hexString[b>>4]
|
||||
r[offsets[i]+1] = hexString[b&0xF]
|
||||
}
|
||||
r[8] = '-'
|
||||
r[13] = '-'
|
||||
r[18] = '-'
|
||||
r[23] = '-'
|
||||
return string(r)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package assert
|
||||
|
||||
import "testing"
|
||||
|
||||
// Equalf asserts that two objects are equal.
|
||||
//
|
||||
// assert.Equalf(t, 123, 123, "error message %s", "formatted")
|
||||
//
|
||||
// Pointer variable equality is determined based on the equality of the
|
||||
// referenced values (as opposed to the memory addresses). Function equality
|
||||
// cannot be determined and will always fail.
|
||||
func Equalf(t *testing.T, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotEqualf asserts that the specified values are NOT equal.
|
||||
//
|
||||
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
|
||||
//
|
||||
// Pointer variable equality is determined based on the equality of the
|
||||
// referenced values (as opposed to the memory addresses).
|
||||
func NotEqualf(t *testing.T, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Nilf asserts that the specified object is nil.
|
||||
//
|
||||
// assert.Nilf(t, err, "error message %s", "formatted")
|
||||
func Nilf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotNilf asserts that the specified object is not nil.
|
||||
//
|
||||
// assert.NotNilf(t, err, "error message %s", "formatted")
|
||||
func NotNilf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return NotNil(t, object, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// assert.Emptyf(t, obj, "error message %s", "formatted")
|
||||
func Emptyf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return Empty(t, object, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
|
||||
// assert.Equal(t, "two", obj[1])
|
||||
// }
|
||||
func NotEmptyf(t *testing.T, object interface{}, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Lenf asserts that the specified object has specific length.
|
||||
// Lenf also fails if the object has a type that len() not accept.
|
||||
//
|
||||
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
|
||||
func Lenf(t *testing.T, object interface{}, length int, msg string, args ...interface{}) bool {
|
||||
t.Helper()
|
||||
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package assert
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Equal asserts that two objects are equal.
|
||||
//
|
||||
// assert.Equal(t, 123, 123)
|
||||
//
|
||||
// Pointer variable equality is determined based on the equality of the
|
||||
// referenced values (as opposed to the memory addresses). Function equality
|
||||
// cannot be determined and will always fail.
|
||||
func Equal(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
t.Helper()
|
||||
if err := validateEqualArgs(expected, actual); err != nil {
|
||||
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
|
||||
expected, actual, err), msgAndArgs...)
|
||||
}
|
||||
if !ObjectsAreEqual(expected, actual) {
|
||||
expected, actual = formatUnequalValues(expected, actual)
|
||||
return Fail(t, fmt.Sprintf("Not equal: \n"+
|
||||
"expected: %s\n"+
|
||||
"actual : %s", expected, actual), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// NotEqual asserts that the specified values are NOT equal.
|
||||
//
|
||||
// assert.NotEqual(t, obj1, obj2)
|
||||
//
|
||||
// Pointer variable equality is determined based on the equality of the
|
||||
// referenced values (as opposed to the memory addresses).
|
||||
func NotEqual(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
t.Helper()
|
||||
if err := validateEqualArgs(expected, actual); err != nil {
|
||||
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
|
||||
expected, actual, err), msgAndArgs...)
|
||||
}
|
||||
if ObjectsAreEqual(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// assert.Empty(t, obj)
|
||||
func Empty(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
pass := isEmpty(object)
|
||||
if !pass {
|
||||
t.Helper()
|
||||
Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
|
||||
}
|
||||
return pass
|
||||
}
|
||||
|
||||
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
||||
// a slice or a channel with len == 0.
|
||||
//
|
||||
// if assert.NotEmpty(t, obj) {
|
||||
// assert.Equal(t, "two", obj[1])
|
||||
// }
|
||||
func NotEmpty(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
pass := !isEmpty(object)
|
||||
if !pass {
|
||||
t.Helper()
|
||||
Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
|
||||
}
|
||||
return pass
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// assert.Nil(t, err)
|
||||
func Nil(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
if isNil(object) {
|
||||
return true
|
||||
}
|
||||
t.Helper()
|
||||
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotNil asserts that the specified object is not nil.
|
||||
//
|
||||
// assert.NotNil(t, err)
|
||||
func NotNil(t *testing.T, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
if !isNil(object) {
|
||||
return true
|
||||
}
|
||||
t.Helper()
|
||||
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
// assert.Len(t, mySlice, 3)
|
||||
func Len(t *testing.T, object interface{}, length int, msgAndArgs ...interface{}) bool {
|
||||
t.Helper()
|
||||
ok, l := getLen(object)
|
||||
if !ok {
|
||||
return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...)
|
||||
}
|
||||
if l != length {
|
||||
return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fail reports a failure through
|
||||
func Fail(t *testing.T, failureMessage string, msgAndArgs ...interface{}) bool {
|
||||
t.Helper()
|
||||
content := []labeledContent{
|
||||
{"Error", failureMessage},
|
||||
}
|
||||
message := messageFromMsgAndArgs(msgAndArgs...)
|
||||
if len(message) > 0 {
|
||||
content = append(content, labeledContent{"Messages", message})
|
||||
}
|
||||
t.Errorf("\n%s", ""+labeledOutput(content...))
|
||||
return false
|
||||
}
|
||||
|
||||
// ObjectsAreEqual determines if two objects are considered equal..
|
||||
func ObjectsAreEqual(expected, actual interface{}) bool {
|
||||
if expected == nil || actual == nil {
|
||||
return expected == actual
|
||||
}
|
||||
|
||||
exp, ok := expected.([]byte)
|
||||
if !ok {
|
||||
return reflect.DeepEqual(expected, actual)
|
||||
}
|
||||
|
||||
act, ok := actual.([]byte)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if exp == nil || act == nil {
|
||||
return exp == nil && act == nil
|
||||
}
|
||||
return bytes.Equal(exp, act)
|
||||
}
|
||||
|
||||
func validateEqualArgs(expected, actual interface{}) error {
|
||||
if expected == nil && actual == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if isFunction(expected) || isFunction(actual) {
|
||||
return errors.New("cannot take func type as argument")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatUnequalValues(expected, actual interface{}) (e string, a string) {
|
||||
if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
|
||||
return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
|
||||
fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
|
||||
}
|
||||
switch expected.(type) {
|
||||
case time.Duration:
|
||||
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
|
||||
}
|
||||
return truncatingFormat(expected), truncatingFormat(actual)
|
||||
}
|
||||
|
||||
func truncatingFormat(data interface{}) string {
|
||||
value := fmt.Sprintf("%#v", data)
|
||||
max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
|
||||
if len(value) > max {
|
||||
value = value[0:max] + "<... truncated>"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
type labeledContent struct {
|
||||
label string
|
||||
content string
|
||||
}
|
||||
|
||||
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
|
||||
if len(msgAndArgs) == 0 || msgAndArgs == nil {
|
||||
return ""
|
||||
}
|
||||
if len(msgAndArgs) == 1 {
|
||||
msg := msgAndArgs[0]
|
||||
if msgAsStr, ok := msg.(string); ok {
|
||||
return msgAsStr
|
||||
}
|
||||
return fmt.Sprintf("%+v", msg)
|
||||
}
|
||||
if len(msgAndArgs) > 1 {
|
||||
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func labeledOutput(content ...labeledContent) string {
|
||||
longestLabel := 0
|
||||
for _, v := range content {
|
||||
if len(v.label) > longestLabel {
|
||||
longestLabel = len(v.label)
|
||||
}
|
||||
}
|
||||
var output string
|
||||
for _, v := range content {
|
||||
output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func indentMessageLines(message string, longestLabelLen int) string {
|
||||
outBuf := new(bytes.Buffer)
|
||||
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
|
||||
// no need to align first line because it starts at the correct location (after the label)
|
||||
if i != 0 {
|
||||
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
|
||||
outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
|
||||
}
|
||||
outBuf.WriteString(scanner.Text())
|
||||
}
|
||||
return outBuf.String()
|
||||
}
|
||||
|
||||
func getLen(x interface{}) (ok bool, length int) {
|
||||
v := reflect.ValueOf(x)
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
return true, v.Len()
|
||||
}
|
||||
|
||||
func isFunction(arg interface{}) bool {
|
||||
if arg == nil {
|
||||
return false
|
||||
}
|
||||
return reflect.TypeOf(arg).Kind() == reflect.Func
|
||||
}
|
||||
|
||||
func isEmpty(object interface{}) bool {
|
||||
|
||||
if object == nil {
|
||||
return true
|
||||
}
|
||||
objValue := reflect.ValueOf(object)
|
||||
switch objValue.Kind() {
|
||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||
return objValue.Len() == 0
|
||||
case reflect.Ptr:
|
||||
if objValue.IsNil() {
|
||||
return true
|
||||
}
|
||||
deref := objValue.Elem().Interface()
|
||||
return isEmpty(deref)
|
||||
default:
|
||||
zero := reflect.Zero(objValue.Type())
|
||||
return reflect.DeepEqual(object, zero.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
|
||||
for i := 0; i < len(kinds); i++ {
|
||||
if kind == kinds[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isNil(object interface{}) bool {
|
||||
if object == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(object)
|
||||
kind := value.Kind()
|
||||
isNilableKind := containsKind(
|
||||
[]reflect.Kind{
|
||||
reflect.Chan, reflect.Func,
|
||||
reflect.Interface, reflect.Map,
|
||||
reflect.Ptr, reflect.Slice},
|
||||
kind)
|
||||
if isNilableKind && value.IsNil() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package byteutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// StringToBytes 强制转换 []byte(s)
|
||||
func StringToBytes(s string) []byte {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
bh := reflect.SliceHeader{
|
||||
Data: sh.Data,
|
||||
Len: sh.Len,
|
||||
Cap: sh.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&bh))
|
||||
}
|
||||
|
||||
// BytesToString 强制转换 string(s)
|
||||
func BytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// Uint64ToBytes uint64转byte
|
||||
func Uint64ToBytes(i uint64) []byte {
|
||||
var buf = make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, i)
|
||||
return buf
|
||||
}
|
||||
|
||||
// BytesToUint64 byte转uint64
|
||||
func BytesToUint64(b []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(b)
|
||||
}
|
||||
|
||||
// Split 数据分片
|
||||
func Split(buf []byte, limit int) [][]byte {
|
||||
var chunk []byte
|
||||
chunks := make([][]byte, 0, len(buf)/limit+1)
|
||||
for len(buf) >= limit {
|
||||
chunk, buf = buf[:limit], buf[limit:]
|
||||
chunks = append(chunks, chunk)
|
||||
}
|
||||
if len(buf) > 0 {
|
||||
chunks = append(chunks, buf[:])
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
// Join 数据合并
|
||||
func Join(s [][]byte) []byte {
|
||||
return bytes.Join(s, []byte(""))
|
||||
}
|
||||
|
||||
|
||||
type RawBytes []byte
|
||||
|
||||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
} else {
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
func AsString(src interface{}) string {
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
case int:
|
||||
return strconv.Itoa(v)
|
||||
case int32:
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
case int64:
|
||||
return strconv.FormatInt(v, 10)
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(v), 'f', -1, 64)
|
||||
case float64:
|
||||
return strconv.FormatFloat(v, 'f', -1, 64)
|
||||
case time.Time:
|
||||
return time.Time.Format(v, "2006-01-02 15:04:05")
|
||||
case bool:
|
||||
return strconv.FormatBool(v)
|
||||
default:
|
||||
{
|
||||
b, _ := json.Marshal(v)
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%v", src)
|
||||
}
|
||||
|
||||
// 编码二进制
|
||||
func EncodeByte(data interface{}) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := gob.NewEncoder(buf)
|
||||
err := enc.Encode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// 解码二进制
|
||||
func DecodeByte(data []byte, to interface{}) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
dec := gob.NewDecoder(buf)
|
||||
return dec.Decode(to)
|
||||
}
|
||||
|
||||
// byte转16进制字符串
|
||||
func ByteToHex(data []byte) string {
|
||||
buffer := new(bytes.Buffer)
|
||||
for _, b := range data {
|
||||
|
||||
s := strconv.FormatInt(int64(b&0xff), 16)
|
||||
if len(s) == 1 {
|
||||
buffer.WriteString("0")
|
||||
}
|
||||
buffer.WriteString(s)
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// 16进制字符串转[]byte
|
||||
func HexToBye(hex string) []byte {
|
||||
length := len(hex) / 2
|
||||
slice := make([]byte, length)
|
||||
rs := []rune(hex)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
s := string(rs[i*2 : i*2+2])
|
||||
value, _ := strconv.ParseInt(s, 16, 10)
|
||||
slice[i] = byte(value & 0xFF)
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
type (
|
||||
// Bytes struct
|
||||
Bytes struct{}
|
||||
)
|
||||
|
||||
// binary units (IEC 60027)
|
||||
const (
|
||||
_ = 1.0 << (10 * iota) // ignore first value by assigning to blank identifier
|
||||
KiB
|
||||
MiB
|
||||
GiB
|
||||
TiB
|
||||
PiB
|
||||
EiB
|
||||
)
|
||||
|
||||
// decimal units (SI international system of units)
|
||||
const (
|
||||
KB = 1000
|
||||
MB = KB * 1000
|
||||
GB = MB * 1000
|
||||
TB = GB * 1000
|
||||
PB = TB * 1000
|
||||
EB = PB * 1000
|
||||
)
|
||||
|
||||
var (
|
||||
patternBinary = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)\s?([KMGTPE]iB?)$`)
|
||||
patternDecimal = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)\s?([KMGTPE]B?|B?)$`)
|
||||
global = New()
|
||||
)
|
||||
|
||||
// New creates a Bytes instance.
|
||||
func New() *Bytes {
|
||||
return &Bytes{}
|
||||
}
|
||||
|
||||
// Format formats bytes integer to human readable string according to IEC 60027.
|
||||
// For example, 31323 bytes will return 30.59KB.
|
||||
func (b *Bytes) Format(value int64) string {
|
||||
return b.FormatBinary(value)
|
||||
}
|
||||
|
||||
// FormatBinary formats bytes integer to human readable string according to IEC 60027.
|
||||
// For example, 31323 bytes will return 30.59KB.
|
||||
func (*Bytes) FormatBinary(value int64) string {
|
||||
multiple := ""
|
||||
val := float64(value)
|
||||
|
||||
switch {
|
||||
case value >= EiB:
|
||||
val /= EiB
|
||||
multiple = "EiB"
|
||||
case value >= PiB:
|
||||
val /= PiB
|
||||
multiple = "PiB"
|
||||
case value >= TiB:
|
||||
val /= TiB
|
||||
multiple = "TiB"
|
||||
case value >= GiB:
|
||||
val /= GiB
|
||||
multiple = "GiB"
|
||||
case value >= MiB:
|
||||
val /= MiB
|
||||
multiple = "MiB"
|
||||
case value >= KiB:
|
||||
val /= KiB
|
||||
multiple = "KiB"
|
||||
case value == 0:
|
||||
return "0"
|
||||
default:
|
||||
return strconv.FormatInt(value, 10) + "B"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%.2f%s", val, multiple)
|
||||
}
|
||||
|
||||
// FormatDecimal formats bytes integer to human readable string according to SI international system of units.
|
||||
// For example, 31323 bytes will return 31.32KB.
|
||||
func (*Bytes) FormatDecimal(value int64) string {
|
||||
multiple := ""
|
||||
val := float64(value)
|
||||
|
||||
switch {
|
||||
case value >= EB:
|
||||
val /= EB
|
||||
multiple = "EB"
|
||||
case value >= PB:
|
||||
val /= PB
|
||||
multiple = "PB"
|
||||
case value >= TB:
|
||||
val /= TB
|
||||
multiple = "TB"
|
||||
case value >= GB:
|
||||
val /= GB
|
||||
multiple = "GB"
|
||||
case value >= MB:
|
||||
val /= MB
|
||||
multiple = "MB"
|
||||
case value >= KB:
|
||||
val /= KB
|
||||
multiple = "KB"
|
||||
case value == 0:
|
||||
return "0"
|
||||
default:
|
||||
return strconv.FormatInt(value, 10) + "B"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%.2f%s", val, multiple)
|
||||
}
|
||||
|
||||
// Parse parses human readable bytes string to bytes integer.
|
||||
// For example, 6GiB (6Gi is also valid) will return 6442450944, and
|
||||
// 6GB (6G is also valid) will return 6000000000.
|
||||
func (b *Bytes) Parse(value string) (int64, error) {
|
||||
|
||||
i, err := b.ParseBinary(value)
|
||||
if err == nil {
|
||||
return i, err
|
||||
}
|
||||
|
||||
return b.ParseDecimal(value)
|
||||
}
|
||||
|
||||
// ParseBinary parses human readable bytes string to bytes integer.
|
||||
// For example, 6GiB (6Gi is also valid) will return 6442450944.
|
||||
func (*Bytes) ParseBinary(value string) (i int64, err error) {
|
||||
parts := patternBinary.FindStringSubmatch(value)
|
||||
if len(parts) < 3 {
|
||||
return 0, fmt.Errorf("error parsing value=%s", value)
|
||||
}
|
||||
bytesString := parts[1]
|
||||
multiple := strings.ToUpper(parts[2])
|
||||
bytes, err := strconv.ParseFloat(bytesString, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch multiple {
|
||||
case "KI", "KIB":
|
||||
return int64(bytes * KiB), nil
|
||||
case "MI", "MIB":
|
||||
return int64(bytes * MiB), nil
|
||||
case "GI", "GIB":
|
||||
return int64(bytes * GiB), nil
|
||||
case "TI", "TIB":
|
||||
return int64(bytes * TiB), nil
|
||||
case "PI", "PIB":
|
||||
return int64(bytes * PiB), nil
|
||||
case "EI", "EIB":
|
||||
return int64(bytes * EiB), nil
|
||||
default:
|
||||
return int64(bytes), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDecimal parses human readable bytes string to bytes integer.
|
||||
// For example, 6GB (6G is also valid) will return 6000000000.
|
||||
func (*Bytes) ParseDecimal(value string) (i int64, err error) {
|
||||
parts := patternDecimal.FindStringSubmatch(value)
|
||||
if len(parts) < 3 {
|
||||
return 0, fmt.Errorf("error parsing value=%s", value)
|
||||
}
|
||||
bytesString := parts[1]
|
||||
multiple := strings.ToUpper(parts[2])
|
||||
bytes, err := strconv.ParseFloat(bytesString, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch multiple {
|
||||
case "K", "KB":
|
||||
return int64(bytes * KB), nil
|
||||
case "M", "MB":
|
||||
return int64(bytes * MB), nil
|
||||
case "G", "GB":
|
||||
return int64(bytes * GB), nil
|
||||
case "T", "TB":
|
||||
return int64(bytes * TB), nil
|
||||
case "P", "PB":
|
||||
return int64(bytes * PB), nil
|
||||
case "E", "EB":
|
||||
return int64(bytes * EB), nil
|
||||
default:
|
||||
return int64(bytes), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Format wraps global Bytes's Format function.
|
||||
func Format(value int64) string {
|
||||
return global.Format(value)
|
||||
}
|
||||
|
||||
// FormatBinary wraps global Bytes's FormatBinary function.
|
||||
func FormatBinary(value int64) string {
|
||||
return global.FormatBinary(value)
|
||||
}
|
||||
|
||||
// FormatDecimal wraps global Bytes's FormatDecimal function.
|
||||
func FormatDecimal(value int64) string {
|
||||
return global.FormatDecimal(value)
|
||||
}
|
||||
|
||||
// Parse wraps global Bytes's Parse function.
|
||||
func Parse(value string) (int64, error) {
|
||||
return global.Parse(value)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package byteutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringToBytes(t *testing.T) {
|
||||
x := "Hello Gopher!"
|
||||
y := StringToBytes(x)
|
||||
z := []byte(x)
|
||||
|
||||
if !bytes.Equal(y, z) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesToString(t *testing.T) {
|
||||
x := []byte("Hello Gopher!")
|
||||
y := BytesToString(x)
|
||||
z := string(x)
|
||||
|
||||
if y != z {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint64ToBytes(t *testing.T) {
|
||||
x := uint64(1234567890)
|
||||
y := Uint64ToBytes(x)
|
||||
t.Logf("Uint64ToBytes: %b", y)
|
||||
}
|
||||
|
||||
func TestBytesToUint64(t *testing.T) {
|
||||
x := uint64(1234567890)
|
||||
y := Uint64ToBytes(x)
|
||||
z := BytesToUint64(y)
|
||||
t.Logf("%d", z)
|
||||
}
|
||||
|
||||
func TestSplit(t *testing.T) {
|
||||
slice := Split([]byte("Hello Gopher!"), 1)
|
||||
t.Logf("%s", slice)
|
||||
}
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
b := Join(Split([]byte("Hello Gopher!"), 1))
|
||||
t.Logf("%s", b)
|
||||
}
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package bitset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"sync"
|
||||
|
||||
)
|
||||
|
||||
// BitSet bit set
|
||||
type BitSet struct {
|
||||
set []byte
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// New creates a bit set object.
|
||||
func New(init ...byte) *BitSet {
|
||||
return &BitSet{set: init}
|
||||
}
|
||||
|
||||
// NewFromHex creates a bit set object from hex string.
|
||||
func NewFromHex(s string) (*BitSet, error) {
|
||||
init, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BitSet{set: init}, nil
|
||||
}
|
||||
|
||||
// Set sets the bit bool value on the specified offset,
|
||||
// and returns the value of before setting.
|
||||
// NOTE:
|
||||
// 0 means the 1st bit, -1 means the bottom 1th bit, -2 means the bottom 2th bit and so on;
|
||||
// If offset>=len(b.set), automatically grow the bit set;
|
||||
// If the bit offset is out of the left range, returns error.
|
||||
func (b *BitSet) Set(offset int, value bool) (bool, error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
size := b.size()
|
||||
// 0 means the 1st bit, -1 means the bottom 1th bit,
|
||||
// -2 means the bottom 2th bit and so on.
|
||||
if offset < 0 {
|
||||
offset += size
|
||||
}
|
||||
if offset < 0 {
|
||||
return false, errors.New("the bit offset is out of the left range")
|
||||
}
|
||||
|
||||
// the bit group index
|
||||
gi := offset / 8
|
||||
// the bit index of in the group
|
||||
bi := offset % 8
|
||||
|
||||
// if the bit offset is out of the right range, automatically grow.
|
||||
if gi >= len(b.set) {
|
||||
newSet := make([]byte, gi+1)
|
||||
copy(newSet, b.set)
|
||||
b.set = newSet
|
||||
}
|
||||
|
||||
gb := b.set[gi]
|
||||
rOff := byte(7 - bi)
|
||||
var mask byte = 1 << rOff
|
||||
oldVal := gb & mask >> rOff
|
||||
if (oldVal == 1) != value {
|
||||
if oldVal == 1 {
|
||||
b.set[gi] = gb &^ mask
|
||||
} else {
|
||||
b.set[gi] = gb | mask
|
||||
}
|
||||
}
|
||||
return oldVal == 1, nil
|
||||
}
|
||||
|
||||
// Get gets the bit bool value on the specified offset.
|
||||
// NOTE:
|
||||
// 0 means the 1st bit, -1 means the bottom 1th bit, -2 means the bottom 2th bit and so on;
|
||||
// If offset>=len(b.set), returns false.
|
||||
func (b *BitSet) Get(offset int) bool {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
size := b.size()
|
||||
// 0 means the 1st bit, -1 means the bottom 1th bit,
|
||||
// -2 means the bottom 2th bit and so on.
|
||||
if offset < 0 {
|
||||
offset += size
|
||||
}
|
||||
if offset < 0 || offset >= size {
|
||||
return false
|
||||
}
|
||||
return getBit(b.set[offset/8], byte(offset%8)) == 1
|
||||
}
|
||||
|
||||
// Range calls f sequentially for each bit present in the bit set.
|
||||
// If f returns false, range stops the iteration.
|
||||
func (b *BitSet) Range(f func(offset int, truth bool) bool) {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
size := b.size()
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
for offset := 0; offset < size; offset++ {
|
||||
if !f(offset, getBit(b.set[offset/8], byte(offset%8)) == 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getBit(gb, offset byte) byte {
|
||||
var rOff = 7 - offset
|
||||
var mask byte = 1 << rOff
|
||||
return gb & mask >> rOff
|
||||
}
|
||||
|
||||
// Count counts the amount of bit set to 1 within the specified range of the bit set.
|
||||
// NOTE:
|
||||
// 0 means the 1st bit, -1 means the bottom 1th bit, -2 means the bottom 2th bit and so on.
|
||||
func (b *BitSet) Count(start, end int) int {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
sgi, sbi, egi, ebi, valid := b.validRange(start, end)
|
||||
if !valid {
|
||||
return 0
|
||||
}
|
||||
var n int
|
||||
n += bits.OnesCount8(b.set[sgi] << sbi)
|
||||
for _, v := range b.set[sgi+1 : egi] {
|
||||
n += bits.OnesCount8(v)
|
||||
}
|
||||
n += bits.OnesCount8(b.set[egi] >> (7 - ebi) << (7 - ebi))
|
||||
return n
|
||||
}
|
||||
|
||||
func (b *BitSet) validRange(start, end int) (sgi, sbi, egi, ebi uint, valid bool) {
|
||||
size := b.size()
|
||||
if start < 0 {
|
||||
start += size
|
||||
}
|
||||
if start >= size {
|
||||
return
|
||||
}
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
if end < 0 {
|
||||
end += size
|
||||
}
|
||||
if end >= size {
|
||||
end = size - 1
|
||||
}
|
||||
if start > end {
|
||||
return
|
||||
}
|
||||
valid = true
|
||||
sgi, sbi = uint(start/8), uint(start%8)
|
||||
egi, ebi = uint(end/8), uint(end%8)
|
||||
return
|
||||
}
|
||||
|
||||
// Not returns ^b.
|
||||
func (b *BitSet) Not() *BitSet {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
rBitSet := &BitSet{
|
||||
set: make([]byte, len(b.set)),
|
||||
}
|
||||
for i, gb := range b.set {
|
||||
rBitSet.set[i] = ^gb
|
||||
}
|
||||
return rBitSet
|
||||
}
|
||||
|
||||
// And returns all the "AND" bit sets.
|
||||
// NOTE:
|
||||
// If the bitSets are empty, returns b.
|
||||
func (b *BitSet) And(bitSets ...*BitSet) *BitSet {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
if len(bitSets) == 0 {
|
||||
return b
|
||||
}
|
||||
var (
|
||||
maxLen = len(b.set)
|
||||
minLen = maxLen
|
||||
currLen int
|
||||
)
|
||||
for _, g := range bitSets {
|
||||
g.mu.RLock()
|
||||
defer g.mu.RUnlock()
|
||||
|
||||
currLen = len(g.set)
|
||||
if currLen > maxLen {
|
||||
maxLen = currLen
|
||||
} else if currLen < minLen {
|
||||
minLen = currLen
|
||||
}
|
||||
}
|
||||
rBitSet := &BitSet{
|
||||
set: make([]byte, maxLen),
|
||||
}
|
||||
for i := range rBitSet.set[:minLen] {
|
||||
rBitSet.set[i] = b.set[i]
|
||||
for _, g := range bitSets {
|
||||
rBitSet.set[i] &= g.set[i]
|
||||
}
|
||||
}
|
||||
return rBitSet
|
||||
}
|
||||
|
||||
// Or returns all the "OR" bit sets.
|
||||
// NOTE:
|
||||
// If the bitSets are empty, returns b.
|
||||
func (b *BitSet) Or(bitSet ...*BitSet) *BitSet {
|
||||
return b.op("|", bitSet)
|
||||
}
|
||||
|
||||
// Xor returns all the "XOR" bit sets.
|
||||
// NOTE:
|
||||
// If the bitSets are empty, returns b.
|
||||
func (b *BitSet) Xor(bitSet ...*BitSet) *BitSet {
|
||||
return b.op("^", bitSet)
|
||||
}
|
||||
|
||||
// AndNot returns all the "&^" bit sets.
|
||||
// NOTE:
|
||||
// If the bitSets are empty, returns b.
|
||||
func (b *BitSet) AndNot(bitSet ...*BitSet) *BitSet {
|
||||
return b.op("&^", bitSet)
|
||||
}
|
||||
|
||||
func (b *BitSet) op(op string, bitSets []*BitSet) *BitSet {
|
||||
if len(bitSets) == 0 {
|
||||
return b
|
||||
}
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
var (
|
||||
maxLen, currLen = len(b.set), 0
|
||||
)
|
||||
for _, g := range bitSets {
|
||||
g.mu.RLock()
|
||||
defer g.mu.RUnlock()
|
||||
currLen = len(g.set)
|
||||
if currLen > maxLen {
|
||||
maxLen = currLen
|
||||
}
|
||||
}
|
||||
rBitSet := &BitSet{
|
||||
set: make([]byte, maxLen),
|
||||
}
|
||||
copy(rBitSet.set, b.set)
|
||||
for _, g := range bitSets {
|
||||
for i, gb := range g.set {
|
||||
switch op {
|
||||
case "|":
|
||||
rBitSet.set[i] = rBitSet.set[i] | gb
|
||||
case "^":
|
||||
rBitSet.set[i] = rBitSet.set[i] ^ gb
|
||||
case "&^":
|
||||
rBitSet.set[i] = rBitSet.set[i] &^ gb
|
||||
}
|
||||
}
|
||||
}
|
||||
return rBitSet
|
||||
}
|
||||
|
||||
// Clear clears the bit set.
|
||||
func (b *BitSet) Clear() {
|
||||
b.mu.Lock()
|
||||
for i := range b.set {
|
||||
b.set[i] = 0
|
||||
}
|
||||
b.mu.Unlock()
|
||||
}
|
||||
|
||||
// Size returns the bits size.
|
||||
func (b *BitSet) Size() int {
|
||||
b.mu.RLock()
|
||||
size := b.size()
|
||||
b.mu.RUnlock()
|
||||
return size
|
||||
}
|
||||
|
||||
func (b *BitSet) size() int {
|
||||
size := len(b.set) * 8
|
||||
if size/8 != len(b.set) {
|
||||
panic("overflow when calculating the bit set size")
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// Bytes returns the bit set copy bytes.
|
||||
func (b *BitSet) Bytes() []byte {
|
||||
b.mu.RLock()
|
||||
set := make([]byte, len(b.set))
|
||||
copy(set, b.set)
|
||||
b.mu.RUnlock()
|
||||
return set
|
||||
}
|
||||
|
||||
|
||||
// String returns the bit set by hex type.
|
||||
func (b *BitSet) String() string {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
return hex.EncodeToString(b.set)
|
||||
}
|
||||
|
||||
// Sub returns the bit subset within the specified range of the bit set.
|
||||
// NOTE:
|
||||
// 0 means the 1st bit, -1 means the bottom 1th bit, -2 means the bottom 2th bit and so on.
|
||||
func (b *BitSet) Sub(start, end int) *BitSet {
|
||||
b.mu.RLock()
|
||||
defer b.mu.RUnlock()
|
||||
newBitSet := &BitSet{
|
||||
set: make([]byte, 0, len(b.set)),
|
||||
}
|
||||
sgi, sbi, egi, ebi, valid := b.validRange(start, end)
|
||||
if !valid {
|
||||
return newBitSet
|
||||
}
|
||||
pre := b.set[sgi] << sbi
|
||||
for _, v := range b.set[sgi+1 : egi] {
|
||||
newBitSet.set = append(newBitSet.set, pre|v>>(7-sbi))
|
||||
pre = v << sbi
|
||||
}
|
||||
last := b.set[egi] >> (7 - ebi) << (7 - ebi)
|
||||
newBitSet.set = append(newBitSet.set, pre|last>>(7-sbi))
|
||||
if sbi < ebi {
|
||||
newBitSet.set = append(newBitSet.set, last<<sbi)
|
||||
}
|
||||
return newBitSet
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package convert
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AnyToString ...
|
||||
func AnyToString(i interface{}) string {
|
||||
var s string
|
||||
switch v := i.(type) {
|
||||
case nil:
|
||||
s = ""
|
||||
case int:
|
||||
s = strconv.Itoa(v)
|
||||
case int8:
|
||||
s = strconv.Itoa(int(v))
|
||||
case int16:
|
||||
s = strconv.Itoa(int(v))
|
||||
case int32: // same as `rune`
|
||||
s = strconv.Itoa(int(v))
|
||||
case int64:
|
||||
s = strconv.Itoa(int(v))
|
||||
case uint:
|
||||
s = strconv.FormatUint(uint64(v), 10)
|
||||
case uint8:
|
||||
s = strconv.FormatUint(uint64(v), 10)
|
||||
case uint16:
|
||||
s = strconv.FormatUint(uint64(v), 10)
|
||||
case uint32:
|
||||
s = strconv.FormatUint(uint64(v), 10)
|
||||
case uint64:
|
||||
s = strconv.FormatUint(v, 10)
|
||||
case float32:
|
||||
s = strconv.FormatFloat(float64(v), 'f', -1, 32)
|
||||
case float64:
|
||||
s = strconv.FormatFloat(v, 'f', -1, 64)
|
||||
case bool:
|
||||
s = strconv.FormatBool(v)
|
||||
case string:
|
||||
s = v
|
||||
case []byte:
|
||||
s = string(v)
|
||||
case time.Duration:
|
||||
s = v.String()
|
||||
case json.Number:
|
||||
s = v.String()
|
||||
default:
|
||||
s = fmt.Sprint(v)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IntToString int => string
|
||||
func IntToString(i int) string {
|
||||
return strconv.Itoa(i)
|
||||
}
|
||||
|
||||
// Uint64ToString uint64 => string
|
||||
func Uint64ToString(i uint64) string {
|
||||
return strconv.FormatUint(i, 10)
|
||||
}
|
||||
|
||||
// Float64ToString float64 => string
|
||||
func Float64ToString(f float64) string {
|
||||
return strconv.FormatFloat(f, 'f', -1, 64)
|
||||
}
|
||||
|
||||
// Float32ToString float32 => string
|
||||
func Float32ToString(f float32) string {
|
||||
return strconv.FormatFloat(float64(f), 'f', -1, 32)
|
||||
}
|
||||
|
||||
// StringToFloat64 string => float64
|
||||
func StringToFloat64(s string) float64 {
|
||||
f, _ := strconv.ParseFloat(s, 64)
|
||||
return f
|
||||
}
|
||||
|
||||
// StringToFloat32 string => float32
|
||||
func StringToFloat32(s string) float32 {
|
||||
f64, _ := strconv.ParseFloat(s, 32)
|
||||
return float32(f64)
|
||||
}
|
||||
|
||||
// StringToInt string => int
|
||||
func StringToInt(s string) int {
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
||||
|
||||
// StringToInt32 string => int32
|
||||
func StringToInt32(s string) int32 {
|
||||
return int32(StringToInt64(s))
|
||||
}
|
||||
|
||||
// StringToInt64 string => int64
|
||||
func StringToInt64(s string) int64 {
|
||||
i, _ := strconv.ParseInt(s, 10, 64)
|
||||
return i
|
||||
}
|
||||
|
||||
// StringToUint64 string => uint64
|
||||
func StringToUint64(s string) uint64 {
|
||||
i, _ := strconv.ParseUint(s, 10, 64)
|
||||
return i
|
||||
}
|
||||
|
||||
// IntToUint int => uint
|
||||
func IntToUint(i int) uint {
|
||||
return uint(i)
|
||||
}
|
||||
|
||||
// UintToInt uint => int
|
||||
func UintToInt(i uint) int {
|
||||
return int(i)
|
||||
}
|
||||
|
||||
// JsonNumberToInt json.Number => int
|
||||
func JsonNumberToInt(n json.Number) int {
|
||||
i64, _ := n.Int64()
|
||||
return int(i64)
|
||||
}
|
||||
|
||||
// MapToJson map => json
|
||||
func MapToJson(m map[string]string) (string, error) {
|
||||
b, e := json.Marshal(m)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// JsonToMap json => map
|
||||
func JsonToMap(s string) (map[string]string, error) {
|
||||
m := make(map[string]string)
|
||||
err := json.Unmarshal([]byte(s), &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Base64Encode base64 编码
|
||||
func Base64Encode(src []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(src)
|
||||
}
|
||||
|
||||
// Base64Decode base64 解码
|
||||
func Base64Decode(src string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(src)
|
||||
}
|
||||
|
||||
// 四舍五入
|
||||
func Float64Rand(v float64, dig int) float64 {
|
||||
cDig := strconv.Itoa(dig)
|
||||
val := fmt.Sprintf("%0."+cDig+"f", v)
|
||||
return StringToFloat64(val)
|
||||
}
|
||||
|
||||
// 浮点数串化(左边是整数位置,右边是小数位,dig参数控制)
|
||||
func FloatToFDig(floVal float64, dig int) string {
|
||||
return fmt.Sprintf("%10."+strconv.Itoa(dig)+"f", floVal) //十位整数,8位小数
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package csvutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// WriteFile 追加写文件
|
||||
func WriteFile(fileName string, body [][]string, head []string) error {
|
||||
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w := csv.NewWriter(f)
|
||||
w.Comma = ','
|
||||
w.UseCRLF = true
|
||||
if len(head) > 0 {
|
||||
r := csv.NewReader(f)
|
||||
var row []string
|
||||
if row, err = r.Read(); err != nil || len(row) == 0 {
|
||||
f.WriteString("\xEF\xBB\xBF")
|
||||
if err = w.Write(head); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = w.WriteAll(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteBytes 写内存
|
||||
func WriteBytes(body [][]string, head []string) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
w := csv.NewWriter(&buf)
|
||||
w.Comma = ','
|
||||
w.UseCRLF = true
|
||||
if len(head) > 0 {
|
||||
if buf.Len() == 0 {
|
||||
buf.WriteString("\xEF\xBB\xBF")
|
||||
if err := w.Write(head); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := w.WriteAll(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// ReadFile 读文件
|
||||
func ReadFile(fileName string) ([][]string, []string, error) {
|
||||
f, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
r := csv.NewReader(f)
|
||||
content, err := r.ReadAll()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return content[1:], content[0], nil
|
||||
}
|
||||
|
||||
// ReadFileOffset 按行读取文件 offset >= 2
|
||||
func ReadFileOffset(fileName string, offset, limit int) ([][]string, []string, error) {
|
||||
f, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
r := csv.NewReader(f)
|
||||
body := make([][]string, 0)
|
||||
head := make([]string, 0)
|
||||
counter := 1
|
||||
for {
|
||||
var row []string
|
||||
if row, err = r.Read(); err != nil && err != io.EOF {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if counter == 1 {
|
||||
head = row
|
||||
} else if counter >= offset && counter < offset+limit {
|
||||
body = append(body, row)
|
||||
} else if counter >= offset+limit {
|
||||
break
|
||||
}
|
||||
counter++
|
||||
}
|
||||
return body, head, nil
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package csvutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestWriteFile(t *testing.T) {
|
||||
filePath := "testdata.csv"
|
||||
head := []string{"序号", "姓名", "电话"}
|
||||
body := make([][]string, 0)
|
||||
body = append(body, []string{"1", "Mark", "18812345678"}, []string{"2", "马克", "18612345678"})
|
||||
err := WriteFile(filePath, body, head)
|
||||
t.Logf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
func TestWriteBytes(t *testing.T) {
|
||||
head := []string{"序号", "姓名", "电话"}
|
||||
body := make([][]string, 0)
|
||||
body = append(body, []string{"1", "Mark", "18812345678"}, []string{"2", "马克", "18612345678"})
|
||||
b, _ := WriteBytes(body, head)
|
||||
t.Logf("WriteBytes: %s", b)
|
||||
}
|
||||
|
||||
func TestReadFile(t *testing.T) {
|
||||
filePath := "testdata.csv"
|
||||
body, head, _ := ReadFile(filePath)
|
||||
t.Logf("body: %s", body)
|
||||
t.Logf("head: %s", head)
|
||||
}
|
||||
|
||||
func TestReadFileOffset(t *testing.T) {
|
||||
filePath := "testdata.csv"
|
||||
body, head, err := ReadFileOffset(filePath, 4, 2)
|
||||
t.Logf("body: %s", body)
|
||||
t.Logf("head: %s", head)
|
||||
t.Logf("err: %v", err)
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package datetime
|
||||
|
||||
import "time"
|
||||
|
||||
const DefaultLayout string = "2006-01-02 15:04:05"
|
||||
const DayLayout string = "2006-01-02"
|
||||
|
||||
// Time 获取当前时间戳
|
||||
func Time() int64 {
|
||||
return time.Now().Unix()
|
||||
}
|
||||
|
||||
// MilliTime 获取当前毫秒时间戳
|
||||
func MilliTime() int64 {
|
||||
return time.Now().UnixNano() / 1e6
|
||||
}
|
||||
|
||||
// MicroTime 获取当前微秒时间戳
|
||||
func MicroTime() int64 {
|
||||
return time.Now().UnixNano() / 1e3
|
||||
}
|
||||
|
||||
// Date 时间戳格式化
|
||||
func Date(timestamp int64, layout string) string {
|
||||
return time.Unix(timestamp, 0).Format(layout)
|
||||
}
|
||||
|
||||
// Timestamp 时间转时间戳
|
||||
func Timestamp(datetime string, layout string) int64 {
|
||||
tm2, err := time.ParseInLocation(layout, datetime, time.Local)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return tm2.Unix()
|
||||
}
|
||||
|
||||
// Datetime 获取当前时间
|
||||
func Datetime() string {
|
||||
return Date(Time(), DefaultLayout)
|
||||
}
|
||||
|
||||
// Today 获取今天日期
|
||||
func Today() string {
|
||||
return Date(Time(), DayLayout)
|
||||
}
|
||||
|
||||
// TodayStartTime Today => 00:00:00 获取今天起始时间戳
|
||||
func TodayStartTime() time.Time {
|
||||
return DayStartTime(time.Now())
|
||||
}
|
||||
|
||||
// TodayEndTime Today => 23:59:59 获取今天结束时间戳
|
||||
func TodayEndTime() time.Time {
|
||||
return DayEndTime(time.Now())
|
||||
}
|
||||
|
||||
// DayStartTime Day => 00:00:00 获取当天起始时间戳
|
||||
func DayStartTime(t time.Time) time.Time {
|
||||
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
|
||||
return tm2
|
||||
}
|
||||
|
||||
// DayEndTime Day => 23:59:59 获取当天结束时间戳
|
||||
func DayEndTime(t time.Time) time.Time {
|
||||
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, time.Local)
|
||||
return tm2
|
||||
}
|
||||
|
||||
// WeekStartTime Monday => 00:00:00 获取周起始时间戳
|
||||
func WeekStartTime(t time.Time) time.Time {
|
||||
offset := int(time.Monday - t.Weekday())
|
||||
if offset > 0 {
|
||||
offset = -6
|
||||
}
|
||||
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local).
|
||||
AddDate(0, 0, offset)
|
||||
return tm2
|
||||
}
|
||||
|
||||
//WeekEndTime Sunday => 23:59:59 获取周结束时间戳
|
||||
func WeekEndTime(t time.Time) time.Time {
|
||||
offset := 0
|
||||
if w := t.Weekday(); w != 0 {
|
||||
offset = int(time.Saturday + 1 - w)
|
||||
}
|
||||
tm2 := time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, time.Local).
|
||||
AddDate(0, 0, offset)
|
||||
return tm2
|
||||
}
|
||||
|
||||
// MonthStartTime 月初 => 00:00:00 获取月起始时间戳
|
||||
func MonthStartTime(t time.Time) time.Time {
|
||||
tm2 := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.Local)
|
||||
return tm2
|
||||
}
|
||||
|
||||
// MonthEndTime 月末 => 23:59:59 获取月结束时间戳
|
||||
func MonthEndTime(t time.Time) time.Time {
|
||||
e := MonthStartTime(t).AddDate(0, 1, -1)
|
||||
tm2 := time.Date(t.Year(), t.Month(), e.Day(), 23, 59, 59, 0, time.Local)
|
||||
return tm2
|
||||
}
|
||||
|
||||
// YearStartTime 年初 => 00:00:00 获取年起始时间戳
|
||||
func YearStartTime(t time.Time) time.Time {
|
||||
tm2 := time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, time.Local)
|
||||
return tm2
|
||||
}
|
||||
|
||||
// YearEndTime 年末 => 23:59:59 获取年起始时间戳
|
||||
func YearEndTime(t time.Time) time.Time {
|
||||
tm2 := time.Date(t.Year(), time.December, 31, 23, 59, 59, 0, time.Local)
|
||||
return tm2
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package datetime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
t.Logf("Time: %d", Time())
|
||||
}
|
||||
|
||||
func TestMilliTime(t *testing.T) {
|
||||
t.Logf("MilliTime: %d", MilliTime())
|
||||
}
|
||||
|
||||
func TestMicroTime(t *testing.T) {
|
||||
t.Logf("MicroTime: %d", MicroTime())
|
||||
}
|
||||
|
||||
func TestDateTime(t *testing.T) {
|
||||
t.Logf("Datetime: %s", Datetime())
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
datetime := "2021-06-06 11:11:11"
|
||||
t.Logf("Date: %d", Timestamp(datetime, DefaultLayout))
|
||||
}
|
||||
|
||||
func TestToday(t *testing.T) {
|
||||
t.Logf("Today: %s", Today())
|
||||
}
|
||||
|
||||
func TestTodayStartTime(t *testing.T) {
|
||||
t.Logf("TodayStartTime: %v", TodayStartTime())
|
||||
}
|
||||
|
||||
func TestTodayEndTime(t *testing.T) {
|
||||
t.Logf("TodayEndTime: %v", TodayEndTime())
|
||||
}
|
||||
|
||||
func TestDayStartTime(t *testing.T) {
|
||||
t.Logf("DayStartTime: %v", DayStartTime(time.Now()))
|
||||
}
|
||||
|
||||
func TestDayEndTime(t *testing.T) {
|
||||
t.Logf("DayEndTime: %v", DayEndTime(time.Now()))
|
||||
}
|
||||
|
||||
func TestWeekStartTime(t *testing.T) {
|
||||
t.Logf("WeekStartTime: %v", WeekStartTime(time.Now()))
|
||||
}
|
||||
|
||||
func TestWeekEndTime(t *testing.T) {
|
||||
t.Logf("WeekEndTime: %v", WeekEndTime(time.Now()))
|
||||
}
|
||||
|
||||
func TestMonthStartTime(t *testing.T) {
|
||||
t.Logf("MonthStartTime: %v", MonthStartTime(time.Now()))
|
||||
}
|
||||
|
||||
func TestMonthEndTime(t *testing.T) {
|
||||
t.Logf("MonthEndTime: %v", MonthEndTime(time.Now()))
|
||||
}
|
||||
func TestYearStartTime(t *testing.T) {
|
||||
t.Logf("YearStartTime: %v", YearStartTime(time.Now()))
|
||||
}
|
||||
|
||||
func TestYearEndTime(t *testing.T) {
|
||||
t.Logf("YearEndTime: %v", YearEndTime(time.Now()))
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
用于抓取错误记录打印(panic信息,不可度量的)
|
||||
注意:每个 goroutine 开始部分都需要写上:defer mycatch.Dmp()
|
||||
类似于
|
||||
go func(){
|
||||
defer mycatch.Dmp()
|
||||
}()
|
||||
*/
|
||||
|
||||
func Dmp() {
|
||||
errstr := ""
|
||||
if err := recover(); err != nil {
|
||||
errstr += (fmt.Sprintf("%v\r\n", err)) //输出panic信息
|
||||
errstr += ("--------------------------------------------\r\n")
|
||||
}
|
||||
|
||||
errstr += (string(debug.Stack())) //输出堆栈信息
|
||||
// OnWriteErrToFile(errstr)
|
||||
}
|
||||
|
||||
func OnWriteErrToFile(errstring string) {
|
||||
path := GetModelPath() + "/err"
|
||||
if !PathExists(path) {
|
||||
os.MkdirAll(path, os.ModePerm) //生成多级目录
|
||||
}
|
||||
|
||||
now := time.Now() //获取当前时间
|
||||
pid := os.Getpid() //获取进程ID
|
||||
time_str := now.Format("2006-01-02") //设定时间格式
|
||||
fname := fmt.Sprintf("%s/panic_%s-%x.log", path, time_str, pid) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
|
||||
fmt.Println("panic to file ", fname)
|
||||
|
||||
f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
f.WriteString("=========================" + now.Format("2006-01-02 15:04:05 ========================= \r\n"))
|
||||
f.WriteString(errstring) //输出堆栈信息
|
||||
f.WriteString("=========================end=========================")
|
||||
}
|
||||
|
||||
// 获取目录地址
|
||||
func GetModelPath() string {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
path := filepath.Dir(file)
|
||||
path, _ = filepath.Abs(path)
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func PathExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package errors
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDmp(t *testing.T) {
|
||||
|
||||
Dmp()
|
||||
panic(1)
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
// from https://github.com/pkg/errors
|
||||
// Package errors provides simple error handling primitives.
|
||||
//
|
||||
// The traditional error handling idiom in Go is roughly akin to
|
||||
//
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// which when applied recursively up the call stack results in error reports
|
||||
// without context or debugging information. The errors package allows
|
||||
// programmers to add context to the failure path in their code in a way
|
||||
// that does not destroy the original value of the error.
|
||||
//
|
||||
// Adding context to an error
|
||||
//
|
||||
// The errors.Wrap function returns a new error that adds context to the
|
||||
// original error by recording a stack trace at the point Wrap is called,
|
||||
// together with the supplied message. For example
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "read failed")
|
||||
// }
|
||||
//
|
||||
// If additional control is required, the errors.WithStack and
|
||||
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||
// operations: annotating an error with a stack trace and with a message,
|
||||
// respectively.
|
||||
//
|
||||
// Retrieving the cause of an error
|
||||
//
|
||||
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||
// preceding error. Depending on the nature of the error it may be necessary
|
||||
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||
// for inspection. Any error value which implements this interface
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||
// the topmost error that does not implement causer, which is assumed to be
|
||||
// the original cause. For example:
|
||||
//
|
||||
// switch err := errors.Cause(err).(type) {
|
||||
// case *MyError:
|
||||
// // handle specifically
|
||||
// default:
|
||||
// // unknown error
|
||||
// }
|
||||
//
|
||||
// Although the causer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// Formatted printing of errors
|
||||
//
|
||||
// All error values returned from this package implement fmt.Formatter and can
|
||||
// be formatted by the fmt package. The following verbs are supported:
|
||||
//
|
||||
// %s print the error. If the error has a Cause it will be
|
||||
// printed recursively.
|
||||
// %v see %s
|
||||
// %+v extended format. Each Frame of the error's StackTrace will
|
||||
// be printed in detail.
|
||||
//
|
||||
// Retrieving the stack trace of an error or wrapper
|
||||
//
|
||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||
// invoked. This information can be retrieved with the following interface:
|
||||
//
|
||||
// type stackTracer interface {
|
||||
// StackTrace() errors.StackTrace
|
||||
// }
|
||||
//
|
||||
// The returned errors.StackTrace type is defined as
|
||||
//
|
||||
// type StackTrace []Frame
|
||||
//
|
||||
// The Frame type represents a call site in the stack trace. Frame supports
|
||||
// the fmt.Formatter interface that can be used for printing information about
|
||||
// the stack trace of this error. For example:
|
||||
//
|
||||
// if err, ok := err.(stackTracer); ok {
|
||||
// for _, f := range err.StackTrace() {
|
||||
// fmt.Printf("%+s:%d", f)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Although the stackTracer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// See the documentation for Frame.Format for more details.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(message string) error {
|
||||
return &fundamental{
|
||||
msg: message,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v", w.Cause())
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||
io.WriteString(s, w.msg)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func test1() error {
|
||||
return test2()
|
||||
}
|
||||
|
||||
func test2() error {
|
||||
return Wrapf(New("something go wrong"), "自定义消息")
|
||||
}
|
||||
|
||||
func TestErr(t *testing.T) {
|
||||
err := test1()
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
err = Cause(err) //获取原始对象
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
|
||||
func test11() error {
|
||||
return test21()
|
||||
}
|
||||
|
||||
func test21() error {
|
||||
return New("something go wrong")
|
||||
}
|
||||
|
||||
func TestErr1(t *testing.T) {
|
||||
err := test11()
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
err = Cause(err) //获取原始对象
|
||||
fmt.Println(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
pc := f.pc()
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
io.WriteString(s, "unknown")
|
||||
} else {
|
||||
file, _ := fn.FileLine(pc)
|
||||
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
|
||||
}
|
||||
default:
|
||||
io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
fmt.Fprintf(s, "%d", f.line())
|
||||
case 'n':
|
||||
name := runtime.FuncForPC(f.pc()).Name()
|
||||
io.WriteString(s, funcname(name))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
fmt.Fprintf(s, "\n%+v", f)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
fmt.Fprintf(s, "%v", []Frame(st))
|
||||
}
|
||||
case 's':
|
||||
fmt.Fprintf(s, "%s", []Frame(st))
|
||||
}
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SelfPath gets compiled executable file absolute path.
|
||||
func SelfPath() string {
|
||||
selfPath, _ := filepath.Abs(os.Args[0])
|
||||
return selfPath
|
||||
}
|
||||
|
||||
// SelfDir gets compiled executable file directory.
|
||||
func SelfDir() string {
|
||||
return filepath.Dir(SelfPath())
|
||||
}
|
||||
|
||||
//MkDir 创建目录.
|
||||
func MkDir(dirPath string) error {
|
||||
if IsExist(dirPath) {
|
||||
return nil
|
||||
}
|
||||
return os.MkdirAll(dirPath, os.ModePerm)
|
||||
}
|
||||
|
||||
// IsExist 判断文件或目录是否存在.
|
||||
func IsExist(filePath string) bool {
|
||||
_, err := os.Stat(filePath)
|
||||
return err == nil || os.IsExist(err)
|
||||
}
|
||||
|
||||
// IsEmpty 判断目录是否为空.
|
||||
func IsEmpty(dirname string) bool {
|
||||
dir, _ := ioutil.ReadDir(dirname)
|
||||
if len(dir) == 0 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsFile 判断文件是否存在.
|
||||
func IsFile(filePath string) bool {
|
||||
f, e := os.Stat(filePath)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
return !f.IsDir()
|
||||
}
|
||||
|
||||
// IsDir 判断目录是否存在.
|
||||
func IsDir(filePath string) bool {
|
||||
f, e := os.Stat(filePath)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
return f.IsDir()
|
||||
}
|
||||
|
||||
// ListIndex 目录下文件和子目录列表.
|
||||
func ListIndex(dirPath string) ([]string, []string, error) {
|
||||
if !IsDir(dirPath) {
|
||||
return nil, nil, errors.New(dirPath + " not a directory")
|
||||
}
|
||||
fs, err := ioutil.ReadDir(dirPath)
|
||||
var files, dirs []string
|
||||
for _, fi := range fs {
|
||||
if !fi.IsDir() {
|
||||
files = append(files, fi.Name())
|
||||
} else {
|
||||
dirs = append(dirs, fi.Name())
|
||||
}
|
||||
}
|
||||
return files, dirs, err
|
||||
}
|
||||
|
||||
// ClearDir 清空目录下所有文件不包括子目录.
|
||||
func ClearDir(dirPath string) error {
|
||||
dir, e := ioutil.ReadDir(dirPath)
|
||||
for _, d := range dir {
|
||||
if d.IsDir() {
|
||||
continue
|
||||
}
|
||||
_ = os.Remove(path.Join([]string{dirPath, d.Name()}...))
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// ClearDirF 清空目录下所有文件和目录.
|
||||
func ClearDirF(dirPath string) error {
|
||||
dir, e := ioutil.ReadDir(dirPath)
|
||||
for _, d := range dir {
|
||||
_ = os.RemoveAll(path.Join([]string{dirPath, d.Name()}...))
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// RemoveDir 删除空目录.
|
||||
func RemoveDir(dirPath string) error {
|
||||
if !IsDir(dirPath) {
|
||||
return errors.New(dirPath + " not a directory")
|
||||
}
|
||||
return os.Remove(dirPath)
|
||||
}
|
||||
|
||||
func PathExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 创建目录
|
||||
func BuildDir(abs_dir string) error {
|
||||
return os.MkdirAll(path.Dir(abs_dir), os.ModePerm) //生成多级目录
|
||||
}
|
||||
|
||||
// 删除文件或文件夹
|
||||
func DeleteFile(abs_dir string) error {
|
||||
return os.RemoveAll(abs_dir)
|
||||
}
|
||||
|
||||
// 获取目录所有文件夹
|
||||
func GetPathDirs(abs_dir string) (re []string) {
|
||||
if PathExists(abs_dir) {
|
||||
files, _ := ioutil.ReadDir(abs_dir)
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
re = append(re, f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取目录所有文件
|
||||
func GetPathFiles(abs_dir string) (re []string) {
|
||||
if PathExists(abs_dir) {
|
||||
files, _ := ioutil.ReadDir(abs_dir)
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
re = append(re, f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取程序运行路径
|
||||
func GetCurrentDirectory() string {
|
||||
dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
return strings.Replace(dir, "\\", "/", -1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GetGopaths returns the list of Go path directories.
|
||||
func GetGopaths() []string {
|
||||
var all []string
|
||||
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
||||
if p == "" || p == build.Default.GOROOT {
|
||||
// Empty paths are uninteresting.
|
||||
// If the path is the GOROOT, ignore it.
|
||||
// People sometimes set GOPATH=$GOROOT.
|
||||
// Do not get confused by this common mistake.
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(p, "~") {
|
||||
// Path segments starting with ~ on Unix are almost always
|
||||
// users who have incorrectly quoted ~ while setting GOPATH,
|
||||
// preventing it from expanding to $HOME.
|
||||
// The situation is made more confusing by the fact that
|
||||
// bash allows quoted ~ in $PATH (most shells do not).
|
||||
// Do not get confused by this, and do not try to use the path.
|
||||
// It does not exist, and printing errors about it confuses
|
||||
// those users even more, because they think "sure ~ exists!".
|
||||
// The go command diagnoses this situation and prints a
|
||||
// useful error.
|
||||
// On Windows, ~ is used in short names, such as c:\progra~1
|
||||
// for c:\program files.
|
||||
continue
|
||||
}
|
||||
all = append(all, p)
|
||||
}
|
||||
for k, v := range all {
|
||||
// GOPATH should end with / or \
|
||||
if strings.HasSuffix(v, "/") || strings.HasSuffix(v, string(os.PathSeparator)) {
|
||||
continue
|
||||
}
|
||||
v += string(os.PathSeparator)
|
||||
all[k] = v
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
// GetFirstGopath gets the first $GOPATH value.
|
||||
func GetFirstGopath(allowAutomaticGuessing bool) (gopath string, err error) {
|
||||
a := GetGopaths()
|
||||
if len(a) > 0 {
|
||||
gopath = a[0]
|
||||
}
|
||||
defer func() {
|
||||
gopath = strings.Replace(gopath, "/", string(os.PathSeparator), -1)
|
||||
}()
|
||||
if gopath != "" {
|
||||
return
|
||||
}
|
||||
if !allowAutomaticGuessing {
|
||||
err = errors.New("not found GOPATH")
|
||||
return
|
||||
}
|
||||
p, _ := os.Getwd()
|
||||
p = strings.Replace(p, "\\", "/", -1) + "/"
|
||||
i := strings.LastIndex(p, "/src/")
|
||||
if i == -1 {
|
||||
err = errors.New("not found GOPATH")
|
||||
return
|
||||
}
|
||||
gopath = p[:i+1]
|
||||
return
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSelfPath(t *testing.T) {
|
||||
t.Logf("SelfPath: %v", SelfPath())
|
||||
}
|
||||
|
||||
func TestSelfDir(t *testing.T) {
|
||||
t.Logf("SelfDir: %v", SelfDir())
|
||||
}
|
||||
|
||||
func TestMkDir(t *testing.T) {
|
||||
dirPath := "testdata/dir/dir1"
|
||||
t.Logf("Mkdir: %v", MkDir(dirPath))
|
||||
}
|
||||
|
||||
func TestIsEmpty(t *testing.T) {
|
||||
dirPath := "testdata/dir"
|
||||
t.Logf("IsEmpty: %v", IsEmpty(dirPath))
|
||||
}
|
||||
|
||||
func TestIsDir(t *testing.T) {
|
||||
dirPath := "testdata/dir"
|
||||
t.Logf("IsDir: %v", IsDir(dirPath))
|
||||
}
|
||||
|
||||
func TestIsFile(t *testing.T) {
|
||||
dirPath := "testdata/dir"
|
||||
t.Logf("IsFile: %v", IsFile(dirPath))
|
||||
}
|
||||
|
||||
func TestListIndex(t *testing.T) {
|
||||
dirPath := "testdata"
|
||||
files, dirs, err := ListIndex(dirPath)
|
||||
t.Logf("ListFiles: %v, %v, %v", files, dirs, err)
|
||||
}
|
||||
|
||||
func TestClearDir(t *testing.T) {
|
||||
dirPath := "testdata/dir/dir1"
|
||||
t.Logf("ClearDir: %v", ClearDir(dirPath))
|
||||
}
|
||||
|
||||
func TestClearDirF(t *testing.T) {
|
||||
dirPath := "testdata"
|
||||
t.Logf("ClearDirF: %v", ClearDirF(dirPath))
|
||||
}
|
||||
|
||||
func TestRemoveDir(t *testing.T) {
|
||||
dirPath := "testdata"
|
||||
t.Logf("RemoveDir: %v", RemoveDir(dirPath))
|
||||
}
|
||||
@@ -1,546 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/**
|
||||
os.O_WRONLY 只写
|
||||
os.O_CREATE 创建文件
|
||||
os.O_RDONLY 只读
|
||||
os.O_RDWR 读写
|
||||
os.O_TRUNC 清空
|
||||
os.O_APPEND 追加
|
||||
*/
|
||||
|
||||
// CreateFile 创建或清空文件
|
||||
func CreateFile(filePath string) (*os.File, error) {
|
||||
if err := MkDir(path.Dir(filePath)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Create(filePath)
|
||||
}
|
||||
|
||||
// ReadFileToBytes 读文件
|
||||
func ReadFileToBytes(filePath string) ([]byte, error) {
|
||||
b, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// WriteBytesToFile 写文件 覆盖
|
||||
func WriteBytesToFile(filePath string, b []byte) error {
|
||||
f, err := CreateFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
wt := bufio.NewWriter(f)
|
||||
_, err = io.Copy(wt, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wt.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadHttpFileToBytes 读网络文件
|
||||
func ReadHttpFileToBytes(fileUrl string) ([]byte, error) {
|
||||
resp, err := http.Get(fileUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// Copy 复制文件
|
||||
func Copy(sourcePath, targetPath string) error {
|
||||
b, err := ReadFileToBytes(sourcePath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return WriteBytesToFile(targetPath, b)
|
||||
}
|
||||
|
||||
// Download 下载文件
|
||||
func Download(sourceUrl, targetPath string) error {
|
||||
b, err := ReadHttpFileToBytes(sourceUrl)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return WriteBytesToFile(targetPath, b)
|
||||
}
|
||||
|
||||
// Name 获取文件名.
|
||||
func Name(filePath string) string {
|
||||
return filepath.Base(filePath)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// RelPath gets relative path.
|
||||
func RelPath(targpath string) string {
|
||||
basepath, _ := filepath.Abs("./")
|
||||
rel, _ := filepath.Rel(basepath, targpath)
|
||||
return strings.Replace(rel, `\`, `/`, -1)
|
||||
}
|
||||
|
||||
var curpath = SelfDir()
|
||||
|
||||
// SelfChdir switch the working path to my own path.
|
||||
func SelfChdir() {
|
||||
if err := os.Chdir(curpath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// FileExists reports whether the named file or directory exists.
|
||||
func FileExists(name string) (existed bool) {
|
||||
existed, _ = FileExist(name)
|
||||
return
|
||||
}
|
||||
|
||||
// FileExist reports whether the named file or directory exists.
|
||||
func FileExist(name string) (existed bool, isDir bool) {
|
||||
info, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return !os.IsNotExist(err), false
|
||||
}
|
||||
return true, info.IsDir()
|
||||
}
|
||||
|
||||
// SearchFile Search a file in paths.
|
||||
// this is often used in search config file in /etc ~/
|
||||
func SearchFile(filename string, paths ...string) (fullpath string, err error) {
|
||||
for _, path := range paths {
|
||||
fullpath = filepath.Join(path, filename)
|
||||
existed, _ := FileExist(fullpath)
|
||||
if existed {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GrepFile like command grep -E
|
||||
// for example: GrepFile(`^hello`, "hello.txt")
|
||||
// \n is striped while read
|
||||
func GrepFile(patten string, filename string) (lines []string, err error) {
|
||||
re, err := regexp.Compile(patten)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fd, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
lines = make([]string, 0)
|
||||
reader := bufio.NewReader(fd)
|
||||
prefix := ""
|
||||
isLongLine := false
|
||||
for {
|
||||
byteLine, isPrefix, er := reader.ReadLine()
|
||||
if er != nil && er != io.EOF {
|
||||
return nil, er
|
||||
}
|
||||
if er == io.EOF {
|
||||
break
|
||||
}
|
||||
line := string(byteLine)
|
||||
if isPrefix {
|
||||
prefix += line
|
||||
continue
|
||||
} else {
|
||||
isLongLine = true
|
||||
}
|
||||
|
||||
line = prefix + line
|
||||
if isLongLine {
|
||||
prefix = ""
|
||||
}
|
||||
if re.MatchString(line) {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
// WalkDirs traverses the directory, return to the relative path.
|
||||
// You can specify the suffix.
|
||||
func WalkDirs(targpath string, suffixes ...string) (dirlist []string) {
|
||||
if !filepath.IsAbs(targpath) {
|
||||
targpath, _ = filepath.Abs(targpath)
|
||||
}
|
||||
err := filepath.Walk(targpath, func(retpath string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !f.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if len(suffixes) == 0 {
|
||||
dirlist = append(dirlist, RelPath(retpath))
|
||||
return nil
|
||||
}
|
||||
_retpath := RelPath(retpath)
|
||||
for _, suffix := range suffixes {
|
||||
if strings.HasSuffix(_retpath, suffix) {
|
||||
dirlist = append(dirlist, _retpath)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("utils.WalkRelDirs: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FilepathSplitExt splits the filename into a pair (root, ext) such that root + ext == filename,
|
||||
// and ext is empty or begins with a period and contains at most one period.
|
||||
// Leading periods on the basename are ignored; splitext('.cshrc') returns ('', '.cshrc').
|
||||
func FilepathSplitExt(filename string, slashInsensitive ...bool) (root, ext string) {
|
||||
insensitive := false
|
||||
if len(slashInsensitive) > 0 {
|
||||
insensitive = slashInsensitive[0]
|
||||
}
|
||||
if insensitive {
|
||||
filename = FilepathSlashInsensitive(filename)
|
||||
}
|
||||
for i := len(filename) - 1; i >= 0 && !os.IsPathSeparator(filename[i]); i-- {
|
||||
if filename[i] == '.' {
|
||||
return filename[:i], filename[i:]
|
||||
}
|
||||
}
|
||||
return filename, ""
|
||||
}
|
||||
|
||||
// FilepathStem returns the stem of filename.
|
||||
// Example:
|
||||
// FilepathStem("/root/dir/sub/file.ext") // output "file"
|
||||
// NOTE:
|
||||
// If slashInsensitive is empty, default is false.
|
||||
func FilepathStem(filename string, slashInsensitive ...bool) string {
|
||||
insensitive := false
|
||||
if len(slashInsensitive) > 0 {
|
||||
insensitive = slashInsensitive[0]
|
||||
}
|
||||
if insensitive {
|
||||
filename = FilepathSlashInsensitive(filename)
|
||||
}
|
||||
base := filepath.Base(filename)
|
||||
for i := len(base) - 1; i >= 0; i-- {
|
||||
if base[i] == '.' {
|
||||
return base[:i]
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
// FilepathSlashInsensitive ignore the difference between the slash and the backslash,
|
||||
// and convert to the same as the current system.
|
||||
func FilepathSlashInsensitive(path string) string {
|
||||
if filepath.Separator == '/' {
|
||||
return strings.Replace(path, "\\", "/", -1)
|
||||
}
|
||||
return strings.Replace(path, "/", "\\", -1)
|
||||
}
|
||||
|
||||
// FilepathContains checks if the basepath path contains the subpaths.
|
||||
func FilepathContains(basepath string, subpaths []string) error {
|
||||
basepath, err := filepath.Abs(basepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range subpaths {
|
||||
p, err = filepath.Abs(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rel, err := filepath.Rel(basepath, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasPrefix(rel, "..") {
|
||||
return fmt.Errorf("%s is not include %s", basepath, p)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func filepathRelative(basepath, targpath string) (string, error) {
|
||||
abs, err := filepath.Abs(targpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rel, err := filepath.Rel(basepath, abs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if strings.HasPrefix(rel, "..") {
|
||||
return "", fmt.Errorf("%s is not include %s", basepath, abs)
|
||||
}
|
||||
return rel, nil
|
||||
}
|
||||
|
||||
// FilepathDistinct removes the same path and return in the original order.
|
||||
// If toAbs is true, return the result to absolute paths.
|
||||
func FilepathDistinct(paths []string, toAbs bool) ([]string, error) {
|
||||
m := make(map[string]bool, len(paths))
|
||||
ret := make([]string, 0, len(paths))
|
||||
for _, p := range paths {
|
||||
abs, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if m[abs] {
|
||||
continue
|
||||
}
|
||||
m[abs] = true
|
||||
if toAbs {
|
||||
ret = append(ret, abs)
|
||||
} else {
|
||||
ret = append(ret, p)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
||||
// FilepathSame checks if the two paths are the same.
|
||||
func FilepathSame(path1, path2 string) (bool, error) {
|
||||
if path1 == path2 {
|
||||
return true, nil
|
||||
}
|
||||
p1, err := filepath.Abs(path1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
p2, err := filepath.Abs(path2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return p1 == p2, nil
|
||||
}
|
||||
|
||||
// MkdirAll creates a directory named path,
|
||||
// along with any necessary parents, and returns nil,
|
||||
// or else returns an error.
|
||||
// The permission bits perm (before umask) are used for all
|
||||
// directories that MkdirAll creates.
|
||||
// If path is already a directory, MkdirAll does nothing
|
||||
// and returns nil.
|
||||
// If perm is empty, default use 0755.
|
||||
func MkdirAll(path string, perm ...os.FileMode) error {
|
||||
var fm os.FileMode = 0755
|
||||
if len(perm) > 0 {
|
||||
fm = perm[0]
|
||||
}
|
||||
return os.MkdirAll(path, fm)
|
||||
}
|
||||
|
||||
// WriteFile writes file, and automatically creates the directory if necessary.
|
||||
// NOTE:
|
||||
// If perm is empty, automatically determine the file permissions based on extension.
|
||||
func WriteFile(filename string, data []byte, perm ...os.FileMode) error {
|
||||
filename = filepath.FromSlash(filename)
|
||||
err := MkdirAll(filepath.Dir(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(perm) > 0 {
|
||||
return ioutil.WriteFile(filename, data, perm[0])
|
||||
}
|
||||
var ext string
|
||||
if idx := strings.LastIndex(filename, "."); idx != -1 {
|
||||
ext = filename[idx:]
|
||||
}
|
||||
switch ext {
|
||||
case ".sh", ".py", ".rb", ".bat", ".com", ".vbs", ".htm", ".run", ".App", ".exe", ".reg":
|
||||
return ioutil.WriteFile(filename, data, 0755)
|
||||
default:
|
||||
return ioutil.WriteFile(filename, data, 0644)
|
||||
}
|
||||
}
|
||||
|
||||
// RewriteFile rewrites the file.
|
||||
func RewriteFile(filename string, fn func(content []byte) (newContent []byte, err error)) error {
|
||||
f, err := os.OpenFile(filename, os.O_RDWR, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
content, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newContent, err := fn(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bytes.Equal(content, newContent) {
|
||||
return nil
|
||||
}
|
||||
f.Seek(0, 0)
|
||||
f.Truncate(0)
|
||||
_, err = f.Write(newContent)
|
||||
return err
|
||||
}
|
||||
|
||||
// RewriteToFile rewrites the file to newfilename.
|
||||
// If newfilename already exists and is not a directory, replaces it.
|
||||
func RewriteToFile(filename, newfilename string, fn func(content []byte) (newContent []byte, err error)) error {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cnt, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newContent, err := fn(cnt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WriteFile(newfilename, newContent, info.Mode())
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
// ReadLines reads all lines of the specified file.
|
||||
func ReadLines(path string) ([]string, int, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var lines []string
|
||||
lineCount := 0
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
lineCount++
|
||||
}
|
||||
|
||||
if scanner.Err() == bufio.ErrTooLong {
|
||||
panic(scanner.Err())
|
||||
}
|
||||
return lines, lineCount, scanner.Err()
|
||||
}
|
||||
|
||||
// ReadLinesV2 reads all lines of the specified file.
|
||||
func ReadLinesV2(path string) ([]string, int, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var lines []string
|
||||
lineCount := 0
|
||||
reader := bufio.NewReader(file)
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
lines = append(lines, line)
|
||||
lineCount++
|
||||
if err == io.EOF {
|
||||
return lines, lineCount, nil
|
||||
}
|
||||
if err != nil {
|
||||
return lines, lineCount, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ListDir lists all the files in the directory
|
||||
func ListDir(path string) []string {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
filenames := make([]string, len(files))
|
||||
for idx, file := range files {
|
||||
filenames[idx] = file.Name()
|
||||
}
|
||||
return filenames
|
||||
}
|
||||
|
||||
// IsPathExist determines whether a file/dir path exists.
|
||||
// User os.Stat to get the info of target file or dir to check whether exists.
|
||||
// If os.Stat returns nil err, the target exists.
|
||||
// If os.Stat returns a os.ErrNotExist err, the target does not exist.
|
||||
// If the error returned is another type, the target is uncertain whether exists.
|
||||
func IsPathExist(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
||||
// Create creates or truncates the target file specified by path.
|
||||
// If the parent directory does not exist, it will be created with mode os.ModePerm.is cr truncated.
|
||||
// If the file does not exist, it is created with mode 0666.
|
||||
// If successful, methods on the returned File can be used for I/O; the associated file descriptor has mode O_RDWR.
|
||||
func Create(filePath string) (*os.File, error) {
|
||||
if exist, err := IsPathExist(filePath); err != nil {
|
||||
return nil, err
|
||||
} else if exist {
|
||||
return os.Create(filePath)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Create(filePath)
|
||||
}
|
||||
|
||||
// FileToBytes serialize the file to bytes.
|
||||
func FileToBytes(path string) []byte {
|
||||
byteStream, _ := ioutil.ReadFile(path)
|
||||
return byteStream
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateFile(t *testing.T) {
|
||||
filePath := "testdata/file/create.txt"
|
||||
fs, err := CreateFile(filePath)
|
||||
defer fs.Close()
|
||||
t.Logf("CreateFile: %v", err)
|
||||
}
|
||||
|
||||
func TestWriteBytesToFile(t *testing.T) {
|
||||
filePath := "testdata/file/write.txt"
|
||||
t.Logf("WriteBytesToFile: %v", WriteBytesToFile(filePath, []byte("hello")))
|
||||
}
|
||||
|
||||
func TestReadFileToBytes(t *testing.T) {
|
||||
filePath := "testdata/file/write.txt"
|
||||
b, err := ReadFileToBytes(filePath)
|
||||
t.Logf("ReadFileToBytes: %v, %v", string(b), err)
|
||||
}
|
||||
|
||||
func TestReadHttpFileToBytes(t *testing.T) {
|
||||
filePath := "https://game.gtimg.cn/images/yxzj/img201606/heroimg/109/109.jpg"
|
||||
b, err := ReadHttpFileToBytes(filePath)
|
||||
err = WriteBytesToFile("testdata/file/httpFile.jpeg", b)
|
||||
t.Logf("ReadHttpFileToBytes: %v", err)
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
sourcePath := "testdata/file/write.txt"
|
||||
targetPath := "testdata/file/target.txt"
|
||||
t.Logf("Copy: %v", Copy(sourcePath, targetPath))
|
||||
}
|
||||
|
||||
func TestDownload(t *testing.T) {
|
||||
sourceUrl := "https://game.gtimg.cn/images/yxzj/img201606/heroimg/109/109.jpg"
|
||||
targetPath := "testdata/file/109-download.jpeg"
|
||||
t.Logf("Copy: %v", Download(sourceUrl, targetPath))
|
||||
}
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
t.Logf("Name: %v", Name("testdata/file/109-download.jpeg"))
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package hashutil
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Md5 hashes using md5 algorithm
|
||||
func Md5(b []byte) []byte {
|
||||
return Hashes(md5.New(), b)
|
||||
}
|
||||
|
||||
// Md5Hex hashes using md5 algorithm
|
||||
func Md5Hex(text string) string {
|
||||
return StringHashes(md5.New(), text)
|
||||
}
|
||||
|
||||
// Sha1 hashes using sha1 algorithm
|
||||
func Sha1(b []byte) []byte {
|
||||
return Hashes(sha1.New(), b)
|
||||
}
|
||||
|
||||
// Sha1Hex hashes using sha1 algorithm
|
||||
func Sha1Hex(text string) string {
|
||||
return StringHashes(sha1.New(), text)
|
||||
}
|
||||
|
||||
// Sha256 hashes using sha256 algorithm
|
||||
func Sha256(b []byte) []byte {
|
||||
return Hashes(sha256.New(), b)
|
||||
}
|
||||
|
||||
// Sha256Hex hashes using sha256 algorithm
|
||||
func Sha256Hex(text string) string {
|
||||
return StringHashes(sha256.New(), text)
|
||||
}
|
||||
|
||||
// Sha512 hashes using sha512 algorithm
|
||||
func Sha512(b []byte) []byte {
|
||||
return Hashes(sha512.New(), b)
|
||||
}
|
||||
|
||||
// Sha512Hex hashes using sha512 algorithm
|
||||
func Sha512Hex(text string) string {
|
||||
return StringHashes(sha512.New(), text)
|
||||
}
|
||||
|
||||
// HmacMd5 hashes using md5 algorithm with a secret
|
||||
func HmacMd5(b []byte, secret []byte) []byte {
|
||||
algorithm := hmac.New(md5.New, secret)
|
||||
return Hashes(algorithm, b)
|
||||
}
|
||||
|
||||
// HmacMd5Hex hashes using md5 algorithm with a secret
|
||||
func HmacMd5Hex(text, secret string) string {
|
||||
return StringHashes(hmac.New(md5.New, []byte(secret)), text)
|
||||
}
|
||||
|
||||
// HmacSha256 hashes using sha256 algorithm with a secret
|
||||
func HmacSha256(b []byte, secret []byte) []byte {
|
||||
return Hashes(hmac.New(sha256.New, secret), b)
|
||||
}
|
||||
|
||||
// HmacSha256Hex hashes using sha256 algorithm with a secret
|
||||
func HmacSha256Hex(text, secret string) string {
|
||||
return StringHashes(hmac.New(sha256.New, []byte(secret)), text)
|
||||
}
|
||||
|
||||
// HmacSha512 hashes using sha512 algorithm with a secret
|
||||
func HmacSha512(b []byte, secret []byte) []byte {
|
||||
return Hashes(hmac.New(sha512.New, secret), b)
|
||||
}
|
||||
|
||||
// HmacSha512Hex hashes using sha512 algorithm with a secret
|
||||
func HmacSha512Hex(text, secret string) string {
|
||||
return StringHashes(hmac.New(sha512.New, []byte(secret)), text)
|
||||
}
|
||||
|
||||
// StringHashes hashes string
|
||||
func StringHashes(algorithm hash.Hash, text string) string {
|
||||
return hex.EncodeToString(Hashes(algorithm, []byte(text)))
|
||||
}
|
||||
|
||||
// Hashes hashes
|
||||
func Hashes(algorithm hash.Hash, b []byte) []byte {
|
||||
algorithm.Write(b)
|
||||
return algorithm.Sum(nil)
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func PostWithHeader(url string, msg []byte, headers map[string]string) (string, error) {
|
||||
client := &http.Client{}
|
||||
|
||||
req, err := http.NewRequest("POST", url, strings.NewReader(string(msg)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for key, header := range headers {
|
||||
req.Header.Set(key, header)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
func PostWithAuthorization(url, authorization string, msg []byte) (string, error) {
|
||||
headers := make(map[string]string)
|
||||
headers["Authorization"] = authorization
|
||||
headers["Content-Type"] = "application/json"
|
||||
return PostWithHeader(url, msg, headers)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const (
|
||||
CONN_TIME_OUT = time.Second * 2
|
||||
)
|
||||
|
||||
func Get(apiURL string, params url.Values) (resData string, e error) {
|
||||
var (
|
||||
Url *url.URL
|
||||
err error
|
||||
)
|
||||
Url, err = url.Parse(apiURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
Url.RawQuery = params.Encode()
|
||||
resp, err := http.Get(Url.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
res, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
/**
|
||||
Get with TimeOut
|
||||
Code == 200 则返回,其他请打印错误
|
||||
第三个参数设置超时 单位:秒 【0:则默认两秒】
|
||||
*/
|
||||
func SendGetWithTimeOut(apiUrl string, params url.Values, time_out int) (resData string, e error) {
|
||||
var (
|
||||
Url *url.URL
|
||||
err error
|
||||
b []byte
|
||||
)
|
||||
Url, err = url.Parse(apiUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
Url.RawQuery = params.Encode()
|
||||
client := _httpClient(time_out)
|
||||
resp, err := client.Get(Url.String())
|
||||
if err != nil || resp == nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", nil
|
||||
}
|
||||
if resp.Body != nil {
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
return string(b), nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func _httpClient(time_out int) http.Client {
|
||||
var (
|
||||
_sec time.Duration
|
||||
)
|
||||
_sec = CONN_TIME_OUT
|
||||
if time_out > 0 {
|
||||
_sec = time.Second * time.Duration(time_out)
|
||||
}
|
||||
return http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: func(netw, addr string) (net.Conn, error) {
|
||||
conn, err := net.DialTimeout(netw, addr, _sec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(_sec))
|
||||
return conn, nil
|
||||
},
|
||||
ResponseHeaderTimeout: _sec,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
网络请求POST
|
||||
*/
|
||||
func Post(apiURL string, params url.Values) (resData string, err error) {
|
||||
resp, err := http.PostForm(apiURL, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
res, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
/**
|
||||
Post with TimeOut
|
||||
Code == 200 则返回,其他请打印错误
|
||||
第三个参数设置超时 单位:秒 【0:则默认两秒】
|
||||
*/
|
||||
func SendPostWithTimeOut(apiUrl string, params url.Values, time_out int) (resData string, e error) {
|
||||
var (
|
||||
err error
|
||||
b []byte
|
||||
)
|
||||
client := _httpClient(time_out)
|
||||
resp, err := client.PostForm(apiUrl, params)
|
||||
if err != nil || resp == nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", nil
|
||||
}
|
||||
if resp.Body != nil {
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
return string(b), nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
|
||||
//OnPostJSON 发送修改密码
|
||||
func OnPostJSON(url, jsonstr string) []byte {
|
||||
//解析这个 URL 并确保解析没有出错。
|
||||
body := bytes.NewBuffer([]byte(jsonstr))
|
||||
resp, err := http.Post(url, "application/json;charset=utf-8", body)
|
||||
if err != nil {
|
||||
return []byte("")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body1, err1 := ioutil.ReadAll(resp.Body)
|
||||
if err1 != nil {
|
||||
return []byte("")
|
||||
}
|
||||
|
||||
return body1
|
||||
}
|
||||
|
||||
//OnGetJSON 发送get 请求
|
||||
func OnGetJSON(url, params string) string {
|
||||
//解析这个 URL 并确保解析没有出错。
|
||||
var urls = url
|
||||
if len(params) > 0 {
|
||||
urls += "?" + params
|
||||
}
|
||||
resp, err := http.Get(urls)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body1, err1 := ioutil.ReadAll(resp.Body)
|
||||
if err1 != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(body1)
|
||||
}
|
||||
|
||||
//SendGet 发送get 请求 返回对象
|
||||
func SendGet(url, params string, obj interface{}) bool {
|
||||
//解析这个 URL 并确保解析没有出错。
|
||||
var urls = url
|
||||
if len(params) > 0 {
|
||||
urls += "?" + params
|
||||
}
|
||||
resp, err := http.Get(urls)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
//log.Println((string(body)))
|
||||
err = json.Unmarshal([]byte(body), &obj)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//SendGetEx 发送GET请求
|
||||
func SendGetEx(url string, reponse interface{}) bool {
|
||||
resp, e := http.Get(url)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = json.Unmarshal(body, &reponse)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//OnPostForm form 方式发送post请求
|
||||
func OnPostForm(url string, data url.Values) (body []byte) {
|
||||
resp, err := http.PostForm(url, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//SendPost 发送POST请求
|
||||
func SendPost(requestBody interface{}, responseBody interface{}, url string) bool {
|
||||
postData, err := json.Marshal(requestBody)
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("POST", url, bytes.NewReader(postData))
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("Content-Type", "application/json;charset=utf-8")
|
||||
// req.Header.Add("Authorization", authorization)
|
||||
resp, e := client.Do(req)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// result := string(body)
|
||||
|
||||
err = json.Unmarshal(body, &responseBody)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//WriteJSON 像指定client 发送json 包
|
||||
//msg message.MessageBody
|
||||
func WriteJSON(w http.ResponseWriter, msg interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
js, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintf(w, string(js))
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
const (
|
||||
XForwardedFor = "X-Forwarded-For"
|
||||
XRealIP = "X-Real-IP"
|
||||
)
|
||||
|
||||
// RemoteIp 返回远程客户端的 IP,如 192.168.1.1
|
||||
func RemoteIp(req *http.Request) string {
|
||||
remoteAddr := req.RemoteAddr
|
||||
if ip := req.Header.Get(XRealIP); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else if ip = req.Header.Get(XForwardedFor); ip != "" {
|
||||
remoteAddr = ip
|
||||
} else {
|
||||
remoteAddr, _, _ = net.SplitHostPort(remoteAddr)
|
||||
}
|
||||
|
||||
if remoteAddr == "::1" {
|
||||
remoteAddr = "127.0.0.1"
|
||||
}
|
||||
|
||||
return remoteAddr
|
||||
}
|
||||
|
||||
// Ip2long 将 IPv4 字符串形式转为 uint32
|
||||
func Ip2long(ipstr string) uint32 {
|
||||
ip := net.ParseIP(ipstr)
|
||||
if ip == nil {
|
||||
return 0
|
||||
}
|
||||
ip = ip.To4()
|
||||
return binary.BigEndian.Uint32(ip)
|
||||
}
|
||||
|
||||
// 获取本机网卡IP
|
||||
func GetLocalIP() (ipv4 string, err error) {
|
||||
var (
|
||||
addrs []net.Addr
|
||||
addr net.Addr
|
||||
ipNet *net.IPNet // IP地址
|
||||
isIpNet bool
|
||||
)
|
||||
// 获取所有网卡
|
||||
if addrs, err = net.InterfaceAddrs(); err != nil {
|
||||
return
|
||||
}
|
||||
// 取第一个非lo的网卡IP
|
||||
for _, addr = range addrs {
|
||||
// 这个网络地址是IP地址: ipv4, ipv6
|
||||
if ipNet, isIpNet = addr.(*net.IPNet); isIpNet && !ipNet.IP.IsLoopback() {
|
||||
// 跳过IPV6
|
||||
if ipNet.IP.To4() != nil {
|
||||
ipv4 = ipNet.IP.String() // 192.168.1.1
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package jsonutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
/**
|
||||
JSON (map转json)
|
||||
*/
|
||||
|
||||
func ToJsonString(data map[string]interface{}) string {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(jsonData)
|
||||
}
|
||||
|
||||
/*
|
||||
泛型比较麻烦,单独做一个
|
||||
*/
|
||||
func Struct2Json(data interface{}) (string, error) {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(jsonData), err
|
||||
}
|
||||
|
||||
/**
|
||||
JSON (json转map)
|
||||
*/
|
||||
func StringToJson(data string) map[string]interface{} {
|
||||
var jsonData map[string]interface{}
|
||||
json.Unmarshal([]byte(data), &jsonData)
|
||||
return jsonData
|
||||
}
|
||||
|
||||
/**
|
||||
JSONstring (json转IntList)
|
||||
*/
|
||||
func ToIntList(data string) []int {
|
||||
var tmp = make([]int, 0)
|
||||
json.Unmarshal([]byte(data), &tmp)
|
||||
return tmp
|
||||
}
|
||||
@@ -1,344 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsEmpty ...
|
||||
func IsEmpty(mp map[string]string) bool {
|
||||
return len(mp) == 0
|
||||
}
|
||||
|
||||
// HasKey ...
|
||||
func HasKey(mp map[string]string, key string) bool {
|
||||
if _, ok := mp[key]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Value ...
|
||||
func Value(mp map[string]string, key string) string {
|
||||
if HasKey(mp, key) {
|
||||
return mp[key]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// HasValue ...
|
||||
func HasValue(mp map[string]string, value string) bool {
|
||||
for _, v := range mp {
|
||||
if v == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Keys ...
|
||||
func Keys(mp map[string]string) []string {
|
||||
ks := make([]string, 0, len(mp))
|
||||
for k, _ := range mp {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
return ks
|
||||
}
|
||||
|
||||
// Values ...
|
||||
func Values(mp map[string]string) []string {
|
||||
vs := make([]string, 0, len(mp))
|
||||
for _, v := range mp {
|
||||
vs = append(vs, v)
|
||||
}
|
||||
return vs
|
||||
}
|
||||
|
||||
// KeyToLower convert keys to lower case.
|
||||
func KeyToLower(mp map[string]string) map[string]string {
|
||||
nmp := make(map[string]string, len(mp))
|
||||
for k, v := range mp {
|
||||
k = strings.ToLower(k)
|
||||
nmp[k] = v
|
||||
}
|
||||
return nmp
|
||||
}
|
||||
|
||||
// Merge src 会覆盖 dst
|
||||
func Merge(src, dst map[string]string) map[string]string {
|
||||
for k, v := range src {
|
||||
dst[k] = v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// 结构体转map
|
||||
func Struct2Map(obj interface{}) map[string]interface{} {
|
||||
t := reflect.TypeOf(obj)
|
||||
v := reflect.ValueOf(obj)
|
||||
|
||||
var data = make(map[string]interface{})
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
data[t.Field(i).Name] = v.Field(i).Interface()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Part 1: convert a slice or array to the specified type map set strictly.
|
||||
// Note that the the element type of slice or array need to be equal to map key type.
|
||||
// For example, []uint64{1, 2, 3} can be converted to map[uint64]struct{}{1:struct{}, 2:struct{},
|
||||
// 3:struct{}} by calling ToUint64MapSetStrict() but can't be converted to map[string]struct{}{"1":struct{},
|
||||
// "2":struct{}, "3":struct{}}.
|
||||
//
|
||||
|
||||
// ToBoolMapSetStrict converts a slice or array to map[bool]struct{} strictly.
|
||||
func ToBoolMapSetStrict(i interface{}) map[bool]struct{} {
|
||||
m, _ := ToBoolMapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToBoolMapSetStrictE converts a slice or array to map[bool]struct{} with error.
|
||||
func ToBoolMapSetStrictE(i interface{}) (map[bool]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[bool]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[bool]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToIntMapSetStrict converts a slice or array to map[int]struct{}.
|
||||
func ToIntMapSetStrict(i interface{}) map[int]struct{} {
|
||||
m, _ := ToIntMapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToIntMapSetStrictE converts a slice or array to map[int]struct{} with error.
|
||||
func ToIntMapSetStrictE(i interface{}) (map[int]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[int]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v isn't map[int]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToInt8MapSetStrict converts a slice or array to map[int8]struct{}.
|
||||
func ToInt8MapSetStrict(i interface{}) map[int8]struct{} {
|
||||
m, _ := ToInt8MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToInt8MapSetStrictE converts a slice or array to map[int8]struct{} with error.
|
||||
func ToInt8MapSetStrictE(i interface{}) (map[int8]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[int8]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[int8]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToInt16MapSetStrict converts a slice or array to map[int16]struct{}.
|
||||
func ToInt16MapSetStrict(i interface{}) map[int16]struct{} {
|
||||
m, _ := ToInt16MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToInt16MapSetStrictE converts a slice or array to map[int16]struct{} with error.
|
||||
func ToInt16MapSetStrictE(i interface{}) (map[int16]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[int16]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[int16]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToInt32MapSetStrict converts a slice or array to map[int32]struct{}.
|
||||
func ToInt32MapSetStrict(i interface{}) map[int32]struct{} {
|
||||
m, _ := ToInt32MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToInt32MapSetStrictE converts a slice or array to map[int32]struct{} with error.
|
||||
func ToInt32MapSetStrictE(i interface{}) (map[int32]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[int32]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[int32]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToInt64MapSetStrict converts a slice or array to map[int64]struct{}.
|
||||
func ToInt64MapSetStrict(i interface{}) map[int64]struct{} {
|
||||
m, _ := ToInt64MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToInt64MapSetStrictE converts a slice or array to map[int64]struct{} with error.
|
||||
func ToInt64MapSetStrictE(i interface{}) (map[int64]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[int64]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[int64]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToUintMapSetStrict converts a slice or array to map[uint]struct{}.
|
||||
func ToUintMapSetStrict(i interface{}) map[uint]struct{} {
|
||||
m, _ := ToUintMapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToUintMapSetStrictE converts a slice or array to map[uint]struct{} with error.
|
||||
func ToUintMapSetStrictE(i interface{}) (map[uint]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[uint]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[uint8]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToUint8MapSetStrict converts a slice or array to map[uint8]struct{}.
|
||||
func ToUint8MapSetStrict(i interface{}) map[uint8]struct{} {
|
||||
m, _ := ToUint8MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToUint8MapSetStrictE converts a slice or array to map[uint8]struct{} with error.
|
||||
func ToUint8MapSetStrictE(i interface{}) (map[uint8]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[uint8]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[uint8]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToUint16MapSetStrict converts a slice or array to map[uint16]struct{}.
|
||||
func ToUint16MapSetStrict(i interface{}) map[uint16]struct{} {
|
||||
m, _ := ToUint16MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToUint16MapSetStrictE converts a slice or array to map[uint16]struct{} with error.
|
||||
func ToUint16MapSetStrictE(i interface{}) (map[uint16]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[uint16]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[uint16]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToUint32MapSetStrict converts a slice or array to map[uint32]struct{}.
|
||||
func ToUint32MapSetStrict(i interface{}) map[uint32]struct{} {
|
||||
m, _ := ToUint32MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToUint32MapSetStrictE converts a slice or array to map[uint32]struct{} with error.
|
||||
func ToUint32MapSetStrictE(i interface{}) (map[uint32]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[uint32]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[uint32]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToUint64MapSetStrict converts a slice or array to map[uint64]struct{}.
|
||||
func ToUint64MapSetStrict(i interface{}) map[uint64]struct{} {
|
||||
m, _ := ToUint64MapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToUint64MapSetStrictE converts a slice or array to map[uint64]struct{} with error.
|
||||
func ToUint64MapSetStrictE(i interface{}) (map[uint64]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[uint64]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[uint64]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToStrMapSetStrict converts a slice or array to map[string]struct{}.
|
||||
func ToStrMapSetStrict(i interface{}) map[string]struct{} {
|
||||
m, _ := ToStrMapSetStrictE(i)
|
||||
return m
|
||||
}
|
||||
|
||||
// ToStrMapSetStrictE converts a slice or array to map[string]struct{} with error.
|
||||
func ToStrMapSetStrictE(i interface{}) (map[string]struct{}, error) {
|
||||
m, err := ToMapSetStrictE(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m.(map[string]struct{}); ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("convert success but the type %T of result %#v of isn't map[string]struct{}", m, m)
|
||||
}
|
||||
|
||||
// ToMapSetStrictE converts a slice or array to map set with error strictly.
|
||||
// The result of map key type is equal to the type input element.
|
||||
func ToMapSetStrictE(i interface{}) (interface{}, error) {
|
||||
// check params.
|
||||
if i == nil {
|
||||
return nil, fmt.Errorf("unable to converts nil to map[interface{}]struct{}")
|
||||
}
|
||||
t := reflect.TypeOf(i)
|
||||
kind := t.Kind()
|
||||
if kind != reflect.Slice && kind != reflect.Array {
|
||||
return nil, fmt.Errorf("the type %T of input %#v isn't a slice or array", i, i)
|
||||
}
|
||||
// execute the convert.
|
||||
v := reflect.ValueOf(i)
|
||||
mT := reflect.MapOf(t.Elem(), reflect.TypeOf(struct{}{}))
|
||||
mV := reflect.MakeMapWithSize(mT, v.Len())
|
||||
for j := 0; j < v.Len(); j++ {
|
||||
mV.SetMapIndex(v.Index(j), reflect.ValueOf(struct{}{}))
|
||||
}
|
||||
return mV.Interface(), nil
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package mask
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Mask 自定义字符脱敏 保留前f位和最后e位
|
||||
func Mask(s string, f, e int) string {
|
||||
l := len(s)
|
||||
if f+e >= l || f < 0 || e < 0 {
|
||||
return ""
|
||||
}
|
||||
return s[0:f] + strings.Repeat("*", l-f-e) + s[l-e:]
|
||||
}
|
||||
|
||||
// Left 保留前f位
|
||||
func Left(s string, f int) string {
|
||||
return Mask(s, f, 0)
|
||||
}
|
||||
|
||||
// Right 保留后e位
|
||||
func Right(s string, e int) string {
|
||||
return Mask(s, 0, e)
|
||||
}
|
||||
|
||||
// First 取值前f位
|
||||
func First(s string, f int) string {
|
||||
l := len(s)
|
||||
if l <= f || f < 0 {
|
||||
return s
|
||||
}
|
||||
return s[0:f]
|
||||
}
|
||||
|
||||
// Last 取值后e位
|
||||
func Last(s string, e int) string {
|
||||
l := len(s)
|
||||
if l <= e || e < 0 {
|
||||
return s
|
||||
}
|
||||
return s[l-e:]
|
||||
}
|
||||
|
||||
// LastFour 后四位
|
||||
func LastFour(s string) string {
|
||||
return Last(s, 4)
|
||||
}
|
||||
|
||||
// IdCard 身份证号脱敏
|
||||
func IdCard(s string) string {
|
||||
if len(s) != 18 {
|
||||
return ""
|
||||
}
|
||||
return s[0:4] + " **** **** " + s[len(s)-4:]
|
||||
}
|
||||
|
||||
// IdCardStrict 严格身份证号脱敏
|
||||
func IdCardStrict(s string) string {
|
||||
if len(s) != 18 {
|
||||
return ""
|
||||
}
|
||||
return s[0:1] + "*** **** **** ***" + s[len(s)-1:]
|
||||
}
|
||||
|
||||
// Mobile 手机号脱敏
|
||||
func Mobile(s string) string {
|
||||
return s[0:3] + "****" + s[len(s)-4:]
|
||||
}
|
||||
|
||||
// ChineseName 中文姓名脱敏
|
||||
func ChineseName(s string) string {
|
||||
r := []rune(s)
|
||||
l := len(r)
|
||||
if l == 2 {
|
||||
return "*" + string(r[1:])
|
||||
} else if l == 3 {
|
||||
return "*" + string(r[l-2:])
|
||||
} else if l == 4 {
|
||||
return "**" + string(r[l-2:])
|
||||
} else if l > 4 {
|
||||
return string(r[:1]) + strings.Repeat("*", l-3) + string(r[l-2:])
|
||||
}
|
||||
return "**"
|
||||
}
|
||||
|
||||
// Email 邮箱脱敏
|
||||
func Email(s string) string {
|
||||
ss := strings.Split(s, "@")
|
||||
l := len(ss[0])
|
||||
if l <= 1 {
|
||||
return "*@" + ss[1]
|
||||
}
|
||||
r := []rune(s)
|
||||
return string(r[0:1]) + strings.Repeat("*", l-1) + "@" + ss[1]
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package mathutil
|
||||
|
||||
// AbsInt8 gets absolute value of int8.
|
||||
//
|
||||
// Example 1: AbsInt8(-5)
|
||||
// -5 code value as below
|
||||
// original code 1000,0101
|
||||
// inverse code 1111,1010
|
||||
// complement code 1111,1011
|
||||
// Negative numbers are represented by complement code in memory.
|
||||
// shifted = n >> 7 = (1111,1011) >> 7 = 1111,1111 = -1(10-base) (负数右移,左补1)
|
||||
// 1111,1011
|
||||
// n xor shifted = ----------- = 0000,0100 = 4(10-base)
|
||||
// 1111,1111
|
||||
// (n ^ shifted) - shifted = 4 - (-1) = 5
|
||||
//
|
||||
// Example 2: AbsInt8(5)
|
||||
// 5 code value as below
|
||||
// original code 0000,0101
|
||||
// Positive numbers are represented by original code in memory,
|
||||
// and the XOR operation between positive numbers and 0 is equal to itself.
|
||||
// shifted = n >> 7 = 0
|
||||
// 0000,0101
|
||||
// n xor shifted = ----------- = 0000,0101 = 5(10-base)
|
||||
// 0000,0000
|
||||
// (n ^ shifted) - shifted = 5 - 0 = 5
|
||||
func AbsInt8(n int8) int8 {
|
||||
shifted := n >> 7
|
||||
return (n ^ shifted) - shifted
|
||||
}
|
||||
|
||||
// AbsInt16 gets absolute value of int16.
|
||||
func AbsInt16(n int16) int16 {
|
||||
shifted := n >> 15
|
||||
return (n ^ shifted) - shifted
|
||||
}
|
||||
|
||||
// AbsInt32 gets absolute value of int32.
|
||||
func AbsInt32(n int32) int32 {
|
||||
shifted := n >> 31
|
||||
return (n ^ shifted) - shifted
|
||||
}
|
||||
|
||||
// AbsInt64 gets absolute value of int64.
|
||||
func AbsInt64(n int64) int64 {
|
||||
shifted := n >> 63
|
||||
return (n ^ shifted) - shifted
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type CMPRES int8
|
||||
|
||||
const (
|
||||
INCMP CMPRES = iota - 2
|
||||
LT
|
||||
EQ
|
||||
GT
|
||||
)
|
||||
|
||||
// Compare compare the size relationship between two numeric values or strings.
|
||||
// The result is INCMP(incomparable), LT(less than), EQ(equal) or GT(greater than).
|
||||
func Compare(lhs, rhs interface{}) CMPRES {
|
||||
if !isComparable(lhs, rhs) {
|
||||
return INCMP
|
||||
}
|
||||
|
||||
lhsVal := reflect.ValueOf(lhs)
|
||||
rhsVal := reflect.ValueOf(rhs)
|
||||
|
||||
switch lhsVal.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch {
|
||||
case lhsVal.Int() < rhsVal.Int():
|
||||
return LT
|
||||
case lhsVal.Int() == rhsVal.Int():
|
||||
return EQ
|
||||
case lhsVal.Int() > rhsVal.Int():
|
||||
return GT
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
switch {
|
||||
case lhsVal.Uint() < rhsVal.Uint():
|
||||
return LT
|
||||
case lhsVal.Uint() == rhsVal.Uint():
|
||||
return EQ
|
||||
case lhsVal.Uint() > rhsVal.Uint():
|
||||
return GT
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch {
|
||||
case lhsVal.Float() < rhsVal.Float():
|
||||
return LT
|
||||
case lhsVal.Float() == rhsVal.Float():
|
||||
return EQ
|
||||
case lhsVal.Float() > rhsVal.Float():
|
||||
return GT
|
||||
}
|
||||
case reflect.String:
|
||||
switch {
|
||||
case lhsVal.String() < rhsVal.String():
|
||||
return LT
|
||||
case lhsVal.String() == rhsVal.String():
|
||||
return EQ
|
||||
case lhsVal.String() > rhsVal.String():
|
||||
return GT
|
||||
}
|
||||
}
|
||||
return INCMP
|
||||
}
|
||||
|
||||
func isComparable(lhs, rhs interface{}) bool {
|
||||
lhsVal := reflect.ValueOf(lhs)
|
||||
rhsVal := reflect.ValueOf(rhs)
|
||||
return lhsVal.Kind() == rhsVal.Kind()
|
||||
}
|
||||
|
||||
func CompareLT(lhs, rhs interface{}) bool {
|
||||
return Compare(lhs, rhs) == LT
|
||||
}
|
||||
|
||||
func CompareLE(lhs, rhs interface{}) bool {
|
||||
res := Compare(lhs, rhs)
|
||||
return res == LT || res == EQ
|
||||
}
|
||||
|
||||
func CompareEQ(lhs, rhs interface{}) bool {
|
||||
return Compare(lhs, rhs) == EQ
|
||||
}
|
||||
|
||||
func CompareGT(lhs, rhs interface{}) bool {
|
||||
return Compare(lhs, rhs) == GT
|
||||
}
|
||||
|
||||
func CompareGE(lhs, rhs interface{}) bool {
|
||||
res := Compare(lhs, rhs)
|
||||
return Compare(lhs, rhs) == GT || res == EQ
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package mathutil
|
||||
|
||||
// MaxInt64 ...
|
||||
func MaxInt64(is ...int64) int64 {
|
||||
max := is[0]
|
||||
for _, v := range is {
|
||||
if v > max {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// MinInt64 ...
|
||||
func MinInt64(is ...int64) int64 {
|
||||
min := is[0]
|
||||
for _, v := range is {
|
||||
if v < min {
|
||||
min = v
|
||||
}
|
||||
}
|
||||
return min
|
||||
}
|
||||
@@ -1,418 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IP ip struct info.
|
||||
type IP struct {
|
||||
Begin uint32
|
||||
End uint32
|
||||
ISPCode int
|
||||
ISP string
|
||||
CountryCode int
|
||||
Country string
|
||||
ProvinceCode int
|
||||
Province string
|
||||
CityCode int
|
||||
City string
|
||||
DistrictCode int
|
||||
District string
|
||||
Latitude float64
|
||||
Longitude float64
|
||||
}
|
||||
|
||||
// Zone ip struct info.
|
||||
type Zone struct {
|
||||
ID int64 `json:"id"`
|
||||
Addr string `json:"addr"`
|
||||
ISP string `json:"isp"`
|
||||
Country string `json:"country"`
|
||||
Province string `json:"province"`
|
||||
City string `json:"city"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
CountryCode int `json:"country_code,omitempty"`
|
||||
}
|
||||
|
||||
// List struct info list.
|
||||
type List struct {
|
||||
IPs []*IP
|
||||
}
|
||||
|
||||
// New create Xip instance and return.
|
||||
func New(path string) (list *List, err error) {
|
||||
var (
|
||||
ip *IP
|
||||
file *os.File
|
||||
line []byte
|
||||
)
|
||||
list = new(List)
|
||||
if file, err = os.Open(path); err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
reader := bufio.NewReader(file)
|
||||
for {
|
||||
if line, _, err = reader.ReadLine(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
lines := strings.Fields(string(line))
|
||||
if len(lines) < 13 {
|
||||
continue
|
||||
}
|
||||
// lines[2]:country lines[3]:province lines[4]:city lines[5]:unit
|
||||
if lines[3] == "香港" || lines[3] == "澳门" || lines[3] == "台湾" {
|
||||
lines[2] = lines[3]
|
||||
lines[3] = lines[4]
|
||||
lines[4] = "*"
|
||||
}
|
||||
// ex.: from 中国 中国 * to 中国 ”“ ”“
|
||||
if lines[2] == lines[3] || lines[3] == "*" {
|
||||
lines[3] = ""
|
||||
lines[4] = ""
|
||||
} else if lines[3] == lines[4] || lines[4] == "*" {
|
||||
// ex.: from 中国 北京 北京 to 中国 北京 ”“
|
||||
lines[4] = ""
|
||||
}
|
||||
ip = &IP{
|
||||
Begin: InetAtoN(lines[0]),
|
||||
End: InetAtoN(lines[1]),
|
||||
Country: lines[2],
|
||||
Province: lines[3],
|
||||
City: lines[4],
|
||||
ISP: lines[6],
|
||||
}
|
||||
ip.Latitude, _ = strconv.ParseFloat(lines[7], 64)
|
||||
ip.Longitude, _ = strconv.ParseFloat(lines[8], 64)
|
||||
ip.CountryCode, _ = strconv.Atoi(lines[12])
|
||||
list.IPs = append(list.IPs, ip)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// IP ip zone info by ip
|
||||
func (l *List) IP(ipStr string) (ip *IP) {
|
||||
addr := InetAtoN(ipStr)
|
||||
i, j := 0, len(l.IPs)
|
||||
for i < j {
|
||||
h := i + (j-i)/2 // avoid overflow when computing h
|
||||
ip = l.IPs[h]
|
||||
// i ≤ h < j
|
||||
if addr < ip.Begin {
|
||||
j = h
|
||||
} else if addr > ip.End {
|
||||
i = h + 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// All return ipInfos.
|
||||
func (l *List) All() []*IP {
|
||||
return l.IPs
|
||||
}
|
||||
|
||||
// ExternalIP get external ip.
|
||||
func ExternalIP() (res []string) {
|
||||
inters, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, inter := range inters {
|
||||
if !strings.HasPrefix(inter.Name, "lo") {
|
||||
addrs, err := inter.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok {
|
||||
if ipnet.IP.IsLoopback() || ipnet.IP.IsLinkLocalMulticast() || ipnet.IP.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
if ip4 := ipnet.IP.To4(); ip4 != nil {
|
||||
switch true {
|
||||
case ip4[0] == 10:
|
||||
continue
|
||||
case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
|
||||
continue
|
||||
case ip4[0] == 192 && ip4[1] == 168:
|
||||
continue
|
||||
default:
|
||||
res = append(res, ipnet.IP.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// InternalIP get internal ip.
|
||||
func InternalIP() string {
|
||||
inters, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
for _, inter := range inters {
|
||||
if !strings.HasPrefix(inter.Name, "lo") {
|
||||
addrs, err := inter.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
return ipnet.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// InetAtoN conver ip addr to uint32.
|
||||
func InetAtoN(s string) (sum uint32) {
|
||||
ip := net.ParseIP(s)
|
||||
if ip == nil {
|
||||
return
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
return
|
||||
}
|
||||
sum += uint32(ip[0]) << 24
|
||||
sum += uint32(ip[1]) << 16
|
||||
sum += uint32(ip[2]) << 8
|
||||
sum += uint32(ip[3])
|
||||
return sum
|
||||
}
|
||||
|
||||
// InetNtoA conver uint32 to ip addr.
|
||||
func InetNtoA(sum uint32) string {
|
||||
ip := make(net.IP, net.IPv4len)
|
||||
ip[0] = byte((sum >> 24) & 0xFF)
|
||||
ip[1] = byte((sum >> 16) & 0xFF)
|
||||
ip[2] = byte((sum >> 8) & 0xFF)
|
||||
ip[3] = byte(sum & 0xFF)
|
||||
return ip.String()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var (
|
||||
nativeEndian binary.ByteOrder
|
||||
|
||||
ipv4PrivateCIDRString = []string{
|
||||
"0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "169.254.0.0/16",
|
||||
"172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24", "192.88.99.0/24", "192.168.0.0/16",
|
||||
"198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4", "255.255.255.255/32",
|
||||
}
|
||||
ipv6PrivateCIDRString = []string{
|
||||
"::1/128", "::/128", "64:ff9b::/96", "::ffff:0:0/96", "100::/64", "2001::/23",
|
||||
"2001::/32", "2001:2::/48", "2001:db8::/32", "2001:10::/28", "2002::/16", "fc00::/7", "fe80::/10",
|
||||
"2001:20::/28", "ff00::/8",
|
||||
}
|
||||
|
||||
ipv4PrivateCIDR []*net.IPNet
|
||||
ipv6PrivateCIDR []*net.IPNet
|
||||
)
|
||||
|
||||
func init() {
|
||||
if nativeEndian == nil {
|
||||
var x uint32 = 0x01020304
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
nativeEndian = binary.BigEndian
|
||||
} else {
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range ipv4PrivateCIDRString {
|
||||
_, n, _ := net.ParseCIDR(v)
|
||||
ipv4PrivateCIDR = append(ipv4PrivateCIDR, n)
|
||||
}
|
||||
|
||||
for _, v := range ipv6PrivateCIDRString {
|
||||
_, n, _ := net.ParseCIDR(v)
|
||||
ipv6PrivateCIDR = append(ipv6PrivateCIDR, n)
|
||||
}
|
||||
}
|
||||
|
||||
// IsReservedIP reports whether ip is private.
|
||||
// Support ipv4/ipv6, refer rfc6890.
|
||||
// Return <0 ip is invalid, =0 ip is public, >0 ip is private.
|
||||
func IsReservedIP(ip string) int {
|
||||
addr := net.ParseIP(ip)
|
||||
if addr == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
if addr.IsLoopback() || addr.IsMulticast() || addr.IsLinkLocalMulticast() || addr.IsLinkLocalUnicast() {
|
||||
return 1
|
||||
}
|
||||
|
||||
if addr.To4() != nil {
|
||||
for _, v := range ipv4PrivateCIDR {
|
||||
if v.Contains(addr) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, v := range ipv6PrivateCIDR {
|
||||
if v.Contains(addr) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Swap16 swap a 16 bit value if aren't big endian
|
||||
func Swap16(i uint16) uint16 {
|
||||
return (i&0xff00)>>8 | (i&0xff)<<8
|
||||
}
|
||||
|
||||
// Swap32 swap a 32 bit value if aren't big endian
|
||||
func Swap32(i uint32) uint32 {
|
||||
return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24
|
||||
}
|
||||
|
||||
// Htons convert uint16 from host byte order to network byte order
|
||||
func Htons(i uint16) uint16 {
|
||||
if GetNativeEndian() == binary.BigEndian {
|
||||
return i
|
||||
}
|
||||
// 大端模式, 高位放在低地址
|
||||
// 0x1234
|
||||
// 0x12 0x34
|
||||
return Swap16(i)
|
||||
}
|
||||
|
||||
// Htonl convert uint32 from host byte order to network byte order.
|
||||
func Htonl(i uint32) uint32 {
|
||||
if GetNativeEndian() == binary.BigEndian {
|
||||
return i
|
||||
}
|
||||
// 大端模式, 高位放在低地址
|
||||
// 0x12345678
|
||||
// 0x12 0x34 0x56 0x78
|
||||
return Swap32(i)
|
||||
}
|
||||
|
||||
// Ntohs convert uint16 from network byte order to host byte order.
|
||||
func Ntohs(i uint16) uint16 {
|
||||
if GetNativeEndian() == binary.BigEndian {
|
||||
return i
|
||||
}
|
||||
// 小端模式, 低位放在低地址
|
||||
// 0x1234
|
||||
// 0x34 0x12
|
||||
return Swap16(i)
|
||||
}
|
||||
|
||||
// Ntohl convert uint32 from network byte order to host byte order.
|
||||
func Ntohl(i uint32) uint32 {
|
||||
if GetNativeEndian() == binary.BigEndian {
|
||||
return i
|
||||
}
|
||||
// 小端模式, 低位放在低地址
|
||||
// 0x12345678
|
||||
// 0x78 0x56 0x34 0x12
|
||||
return Swap32(i)
|
||||
}
|
||||
|
||||
// IPv4ToU32 convert ipv4(a.b.c.d) to uint32 in host byte order.
|
||||
func IPv4ToU32(ip net.IP) uint32 {
|
||||
if ip == nil {
|
||||
return 0
|
||||
}
|
||||
a := uint32(ip[12])
|
||||
b := uint32(ip[13])
|
||||
c := uint32(ip[14])
|
||||
d := uint32(ip[15])
|
||||
return uint32(a<<24 | b<<16 | c<<8 | d)
|
||||
}
|
||||
|
||||
// U32ToIPv4 convert uint32 to ipv4(a.b.c.d) in host byte order.
|
||||
func U32ToIPv4(ip uint32) net.IP {
|
||||
a := byte((ip >> 24) & 0xFF)
|
||||
b := byte((ip >> 16) & 0xFF)
|
||||
c := byte((ip >> 8) & 0xFF)
|
||||
d := byte(ip & 0xFF)
|
||||
return net.IPv4(a, b, c, d)
|
||||
}
|
||||
|
||||
// IPv4StrToU32 convert IPv4 string to uint32 in host byte order.
|
||||
func IPv4StrToU32(s string) (ip uint32) {
|
||||
r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`
|
||||
reg, err := regexp.Compile(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ips := reg.FindStringSubmatch(s)
|
||||
if ips == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ip1, _ := strconv.Atoi(ips[1])
|
||||
ip2, _ := strconv.Atoi(ips[2])
|
||||
ip3, _ := strconv.Atoi(ips[3])
|
||||
ip4, _ := strconv.Atoi(ips[4])
|
||||
|
||||
if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 {
|
||||
return
|
||||
}
|
||||
|
||||
ip += uint32(ip1 * 0x1000000)
|
||||
ip += uint32(ip2 * 0x10000)
|
||||
ip += uint32(ip3 * 0x100)
|
||||
ip += uint32(ip4)
|
||||
return
|
||||
}
|
||||
|
||||
// U32ToIPv4Str convert uint32 to IPv4 string in host byte order.
|
||||
func U32ToIPv4Str(ip uint32) string {
|
||||
return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24)
|
||||
}
|
||||
|
||||
// GetNativeEndian gets byte order for the current system.
|
||||
func GetNativeEndian() binary.ByteOrder {
|
||||
return nativeEndian
|
||||
}
|
||||
|
||||
// IsLittleEndian determines whether the host byte order is little endian.
|
||||
func IsLittleEndian() bool {
|
||||
n := 0x1234
|
||||
return *(*byte)(unsafe.Pointer(&n)) == 0x34
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package netutil
|
||||
|
||||
import "testing"
|
||||
|
||||
|
||||
func TestExternalIP(t *testing.T) {
|
||||
t.Log(ExternalIP())
|
||||
}
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package cmder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var cmdArg [2]string
|
||||
|
||||
func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
cmdArg[0] = "cmd"
|
||||
cmdArg[1] = "/c"
|
||||
} else {
|
||||
cmdArg[0] = "/bin/sh"
|
||||
cmdArg[1] = "-c"
|
||||
}
|
||||
}
|
||||
|
||||
// Run exec cmd and catch the result.
|
||||
// Waits for the given command to finish with a timeout.
|
||||
// If the command times out, it attempts to kill the process.
|
||||
func Run(cmdLine string, timeout ...time.Duration) *Result {
|
||||
cmd := exec.Command(cmdArg[0], cmdArg[1], cmdLine)
|
||||
var ret = new(Result)
|
||||
cmd.Stdout = &ret.buf
|
||||
cmd.Stderr = &ret.buf
|
||||
cmd.Env = os.Environ()
|
||||
ret.err = cmd.Start()
|
||||
if ret.err != nil {
|
||||
return ret
|
||||
}
|
||||
if len(timeout) == 0 || timeout[0] <= 0 {
|
||||
ret.err = cmd.Wait()
|
||||
return ret
|
||||
}
|
||||
timer := time.NewTimer(timeout[0])
|
||||
done := make(chan error)
|
||||
go func() { done <- cmd.Wait() }()
|
||||
select {
|
||||
case ret.err = <-done:
|
||||
timer.Stop()
|
||||
case <-timer.C:
|
||||
if err := cmd.Process.Kill(); err != nil {
|
||||
ret.err = fmt.Errorf("command timed out and killing process fail: %s", err.Error())
|
||||
} else {
|
||||
// wait for the command to return after killing it
|
||||
<-done
|
||||
ret.err = errors.New("command timed out")
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Result cmd exec result
|
||||
type Result struct {
|
||||
buf bytes.Buffer
|
||||
err error
|
||||
str *string
|
||||
}
|
||||
|
||||
// Err returns the error log.
|
||||
func (r *Result) Err() error {
|
||||
if r.err == nil {
|
||||
return nil
|
||||
}
|
||||
r.err = errors.New(r.String())
|
||||
return r.err
|
||||
}
|
||||
|
||||
// String returns the exec log.
|
||||
func (r *Result) String() string {
|
||||
if r.str == nil {
|
||||
b := bytes.TrimSpace(r.buf.Bytes())
|
||||
if r.err != nil {
|
||||
b = append(b, ' ', '(')
|
||||
b = append(b, r.err.Error()...)
|
||||
b = append(b, ')')
|
||||
}
|
||||
r.str = (*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
return *r.str
|
||||
}
|
||||
|
||||
|
||||
// IsWin determine whether the system is windows
|
||||
func IsWin() bool {
|
||||
return runtime.GOOS == "windows"
|
||||
}
|
||||
|
||||
// IsMac determines whether the system is darwin
|
||||
func IsMac() bool {
|
||||
return runtime.GOOS == "darwin"
|
||||
}
|
||||
|
||||
// IsLinux determines whether the system is linux
|
||||
func IsLinux() bool {
|
||||
return runtime.GOOS == "linux"
|
||||
}
|
||||
|
||||
// IsSupportColor check current console whether support color.
|
||||
// Supported: linux, mac, or windows's ConEmu, Cmder, putty, git-bash.exe
|
||||
// Not support: windows cmd.exe, powerShell.exe
|
||||
func IsSupportColor() bool {
|
||||
// Support color: "TERM=xterm" "TERM=xterm-vt220" "TERM=xterm-256color" "TERM=screen-256color"
|
||||
// Don't support color: "TERM=cygwin"
|
||||
envTerm := os.Getenv("TERM")
|
||||
if strings.Contains(envTerm, "xterm") || strings.Contains(envTerm, "screen") {
|
||||
return true
|
||||
}
|
||||
|
||||
// like on ConEmu software, e.g "ConEmuANSI=ON"
|
||||
if os.Getenv("ConEmuANSI") == "ON" {
|
||||
return true
|
||||
}
|
||||
|
||||
// like on ConEmu software, e.g "ANSICON=189x2000 (189x43)"
|
||||
if os.Getenv("ANSICON") != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSupport256Color check current console whether support 256 color.
|
||||
func IsSupport256Color() bool {
|
||||
// "TERM=xterm-256color" "TERM=screen-256color"
|
||||
return strings.Contains(os.Getenv("TERM"), "256color")
|
||||
}
|
||||
|
||||
// IsSupportTrueColor check current console whether support true color
|
||||
func IsSupportTrueColor() bool {
|
||||
// "COLORTERM=truecolor"
|
||||
return strings.Contains(os.Getenv("COLORTERM"), "truecolor")
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package random
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
randSeek = int64(1)
|
||||
l sync.Mutex
|
||||
)
|
||||
|
||||
// GetRandomInt 生成值小于max的随机数
|
||||
func GetRandomInt(max int) int {
|
||||
rand.Seed(getRandSeek())
|
||||
return rand.Intn(max)
|
||||
}
|
||||
|
||||
// GetRandomChars 生成英文字母随机字符串
|
||||
func GetRandomChars(num int) string {
|
||||
ss := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
return GetRandomString(num, ss)
|
||||
}
|
||||
|
||||
// GetRandomNumbers 生成数字类型随机字符串
|
||||
func GetRandomNumbers(num int) string {
|
||||
return GetRandomString(num)
|
||||
}
|
||||
|
||||
// GetRandomString 生成随机字符串
|
||||
func GetRandomString(num int, str ...string) string {
|
||||
s := "0123456789"
|
||||
if len(str) > 0 {
|
||||
s = str[0]
|
||||
}
|
||||
l := len(s)
|
||||
r := rand.New(rand.NewSource(getRandSeek()))
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < num; i++ {
|
||||
x := r.Intn(l)
|
||||
buf.WriteString(s[x : x+1])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getRandSeek() int64 {
|
||||
l.Lock()
|
||||
if randSeek >= 100000000 {
|
||||
randSeek = 1
|
||||
}
|
||||
randSeek++
|
||||
l.Unlock()
|
||||
return time.Now().UnixNano() + randSeek
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package random
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetRandomSring(t *testing.T) {
|
||||
t.Logf("GetRandomString: %s", GetRandomString(4, "abide123456"))
|
||||
t.Logf("GetRandomString: %s", GetRandomString(6, "abcdefghijklmnopqrstuvwxyz0123456789"))
|
||||
}
|
||||
|
||||
func TestGetRandomChars(t *testing.T) {
|
||||
t.Logf("GetRandomChars: %s", GetRandomChars(4))
|
||||
t.Logf("GetRandomChars: %s", GetRandomChars(6))
|
||||
}
|
||||
|
||||
func TestGetRandomNumbers(t *testing.T) {
|
||||
t.Logf("GetRandomNumbers: %s", GetRandomNumbers(4))
|
||||
t.Logf("GetRandomNumbers: %s", GetRandomNumbers(6))
|
||||
}
|
||||
|
||||
func TestGetRandomInt(t *testing.T) {
|
||||
t.Logf("GetRandomInt: %d", GetRandomInt(10))
|
||||
t.Logf("GetRandomInt: %d", GetRandomInt(10000))
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package security
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
)
|
||||
|
||||
/**
|
||||
Aes加解密
|
||||
填充方式【CBC】
|
||||
收集
|
||||
*/
|
||||
|
||||
func AesEncrypt(origData, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
origData = PKCS5Padding(origData, blockSize)
|
||||
// origData = ZeroPadding(origData, block.BlockSize())
|
||||
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
|
||||
crypted := make([]byte, len(origData))
|
||||
// crypted := origData
|
||||
blockMode.CryptBlocks(crypted, origData)
|
||||
return crypted, nil
|
||||
}
|
||||
|
||||
func AesDecrypt(crypted, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
||||
origData := make([]byte, len(crypted))
|
||||
// origData := crypted
|
||||
blockMode.CryptBlocks(origData, crypted)
|
||||
origData = PKCS5UnPadding(origData)
|
||||
// origData = ZeroUnPadding(origData)
|
||||
return origData, nil
|
||||
}
|
||||
|
||||
func ZeroPadding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{0}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
func ZeroUnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
func PKCS5UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
// 去掉最后一个字节 unpadding 次
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package security
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// EncryptToBase64 ...
|
||||
func EncryptToBase64(plainText []byte, base64PubKey string) (string, error) {
|
||||
publicBytes, err := base64.StdEncoding.DecodeString(base64PubKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cipherBytes, err := encrypt(plainText, publicBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(cipherBytes), nil
|
||||
}
|
||||
|
||||
// DecryptByBase64 ...
|
||||
func DecryptByBase64(cipherText, base64PriKey string) ([]byte, error) {
|
||||
privateBytes, err := base64.StdEncoding.DecodeString(base64PriKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherBytes, err := base64.StdEncoding.DecodeString(cipherText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decrypt(cipherBytes, privateBytes)
|
||||
}
|
||||
|
||||
// EncryptToHex ...
|
||||
func EncryptToHex(plainText []byte, hexPubKey string) (string, error) {
|
||||
publicBytes, err := hex.DecodeString(hexPubKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cipherBytes, err := encrypt(plainText, publicBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(cipherBytes), nil
|
||||
}
|
||||
|
||||
// DecryptByHex ...
|
||||
func DecryptByHex(cipherText, hexPriKey string) ([]byte, error) {
|
||||
privateBytes, err := hex.DecodeString(hexPriKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherTextBytes, err := hex.DecodeString(cipherText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decrypt(cipherTextBytes, privateBytes)
|
||||
}
|
||||
|
||||
// encrypt 加密
|
||||
func encrypt(plainText, pubKey []byte) ([]byte, error) {
|
||||
pub, err := x509.ParsePKIXPublicKey(pubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
publicKey := pub.(*rsa.PublicKey)
|
||||
pubSize, plainTextSize := publicKey.Size(), len(plainText)
|
||||
// EncryptPKCS1v15 encrypts the given message with RSA and the padding
|
||||
// scheme from PKCS #1 v1.5. The message must be no longer than the
|
||||
// length of the public modulus minus 11 bytes.
|
||||
//
|
||||
// The rand parameter is used as a source of entropy to ensure that
|
||||
// encrypting the same message twice doesn't result in the same
|
||||
// ciphertext.
|
||||
//
|
||||
// WARNING: use of this function to encrypt plaintexts other than
|
||||
// session keys is dangerous. Use RSA OAEP in new protocols.
|
||||
offSet, once := 0, pubSize-11
|
||||
buffer := bytes.Buffer{}
|
||||
for offSet < plainTextSize {
|
||||
endIndex := offSet + once
|
||||
if endIndex > plainTextSize {
|
||||
endIndex = plainTextSize
|
||||
}
|
||||
bytesOnce, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText[offSet:endIndex])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer.Write(bytesOnce)
|
||||
offSet = endIndex
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// decrypt 解密
|
||||
func decrypt(cipherText, priKey []byte) (plainText []byte, err error) {
|
||||
pri, err := x509.ParsePKCS8PrivateKey(priKey)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
privateKey := pri.(*rsa.PrivateKey)
|
||||
priSize, cipherTextSize := privateKey.Size(), len(cipherText)
|
||||
var offSet = 0
|
||||
var buffer = bytes.Buffer{}
|
||||
for offSet < cipherTextSize {
|
||||
endIndex := offSet + priSize
|
||||
if endIndex > cipherTextSize {
|
||||
endIndex = cipherTextSize
|
||||
}
|
||||
bytesOnce, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText[offSet:endIndex])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer.Write(bytesOnce)
|
||||
offSet = endIndex
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package dmd5
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
/**
|
||||
md5
|
||||
*/
|
||||
|
||||
func Md5EnCode(string string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(string)) // 需要加密的字符串为
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
RSABitsErr = errors.New("bits 1024 or 2048")
|
||||
RSAPrivateKeyPemDecodeErr = errors.New("private key pem.decode error")
|
||||
RSAPublicKeyPemDecodeErr = errors.New("public key pem.decode error")
|
||||
)
|
||||
|
||||
type RsaKey struct {
|
||||
PrivateKey string // PKCS#8
|
||||
PublicKey string // PKCS#8
|
||||
}
|
||||
|
||||
// GenerateRsaKey 生成公钥私钥
|
||||
func GenerateRsaKey(bits int) ([]byte, []byte, error) {
|
||||
if bits != 1024 && bits != 2048 {
|
||||
return nil, nil, RSABitsErr
|
||||
}
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
priKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pubKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return priKey, pubKey, nil
|
||||
}
|
||||
|
||||
// GenerateRsaKeyBase64 生成公钥私钥 Base64
|
||||
func GenerateRsaKeyBase64(bits int) (RsaKey, error) {
|
||||
priKey, pubKey, err := GenerateRsaKey(bits)
|
||||
if err != nil {
|
||||
return RsaKey{}, err
|
||||
}
|
||||
return RsaKey{
|
||||
PrivateKey: base64.StdEncoding.EncodeToString(priKey),
|
||||
PublicKey: base64.StdEncoding.EncodeToString(pubKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateRsaKeyHex 生成公钥私钥 Hex
|
||||
func GenerateRsaKeyHex(bits int) (RsaKey, error) {
|
||||
priKey, pubKey, err := GenerateRsaKey(bits)
|
||||
if err != nil {
|
||||
return RsaKey{}, err
|
||||
}
|
||||
return RsaKey{
|
||||
PrivateKey: hex.EncodeToString(priKey),
|
||||
PublicKey: hex.EncodeToString(pubKey),
|
||||
}, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,441 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package dtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
/**
|
||||
时间获取
|
||||
时间转换必须加入时区设置,请注意
|
||||
*/
|
||||
|
||||
var (
|
||||
randSeek = int64(1)
|
||||
l sync.Mutex
|
||||
zone = "CST" //时区
|
||||
)
|
||||
|
||||
func TimeIntToDate(time_int int) string {
|
||||
var cstZone = time.FixedZone(zone, 8*3600)
|
||||
return time.Unix(int64(time_int), 0).In(cstZone).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func GetNowDateTime() string {
|
||||
var cstZone = time.FixedZone(zone, 8*3600)
|
||||
return time.Now().In(cstZone).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func GetDate() string {
|
||||
var cstZone = time.FixedZone(zone, 8*3600)
|
||||
return time.Now().In(cstZone).Format("2006-01-02")
|
||||
}
|
||||
|
||||
//防时间间隔
|
||||
func GetIntTime() int {
|
||||
var _t = int(time.Now().Unix())
|
||||
return _t
|
||||
}
|
||||
|
||||
//暂时独立
|
||||
func _getRandomSring(num int, str ...string) string {
|
||||
s := "123456789"
|
||||
if len(str) > 0 {
|
||||
s = str[0]
|
||||
}
|
||||
l := len(s)
|
||||
r := rand.New(rand.NewSource(getRandSeek()))
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < num; i++ {
|
||||
x := r.Intn(l)
|
||||
buf.WriteString(s[x : x+1])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func getRandSeek() int64 {
|
||||
l.Lock()
|
||||
if randSeek >= 100000000 {
|
||||
randSeek = 1
|
||||
}
|
||||
randSeek++
|
||||
l.Unlock()
|
||||
return time.Now().UnixNano() + randSeek
|
||||
}
|
||||
|
||||
//获取今天时间戳 Today => 00:00:00
|
||||
func TodayTimeUnix() int {
|
||||
t := time.Now()
|
||||
tm1 := int(time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()).Unix())
|
||||
return tm1
|
||||
}
|
||||
|
||||
//获取今天时间戳 Today => 23:59:59
|
||||
func TodayNightUnix() int {
|
||||
tm1 := TodayTimeUnix() + 86400 - 1
|
||||
return tm1
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Time be used to MySql timestamp converting.
|
||||
type Time int64
|
||||
|
||||
// Scan scan time.
|
||||
func (jt *Time) Scan(src interface{}) (err error) {
|
||||
switch sc := src.(type) {
|
||||
case time.Time:
|
||||
*jt = Time(sc.Unix())
|
||||
case string:
|
||||
var i int64
|
||||
i, err = strconv.ParseInt(sc, 10, 64)
|
||||
*jt = Time(i)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Value get time value.
|
||||
func (jt Time) Value() (driver.Value, error) {
|
||||
return time.Unix(int64(jt), 0), nil
|
||||
}
|
||||
|
||||
// Time get time.
|
||||
func (jt Time) Time() time.Time {
|
||||
return time.Unix(int64(jt), 0)
|
||||
}
|
||||
|
||||
// Duration be used toml unmarshal string time, like 1s, 500ms.
|
||||
type Duration time.Duration
|
||||
|
||||
// UnmarshalText unmarshal text to duration.
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
tmp, err := time.ParseDuration(string(text))
|
||||
if err == nil {
|
||||
*d = Duration(tmp)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Shrink will decrease the duration by comparing with context's timeout duration
|
||||
// and return new timeout\context\CancelFunc.
|
||||
func (d Duration) Shrink(c context.Context) (Duration, context.Context, context.CancelFunc) {
|
||||
if deadline, ok := c.Deadline(); ok {
|
||||
if ctimeout := time.Until(deadline); ctimeout < time.Duration(d) {
|
||||
// deliver small timeout
|
||||
return Duration(ctimeout), c, func() {}
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(c, time.Duration(d))
|
||||
return d, ctx, cancel
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
const (
|
||||
YFormatNum = "2006"
|
||||
YMFormatNum = "200601"
|
||||
DateFormatNum = "20060102"
|
||||
DateHFormatNum = "2006010215"
|
||||
DateHMFormatNum = "200601021504"
|
||||
DateTimeFormatNum = "20060102150405"
|
||||
HFormatNum = "15"
|
||||
HMFormatNum = "1504"
|
||||
TimeFormatNum = "150405"
|
||||
DateFormat = "2006-01-02"
|
||||
TimeFormat = "15:04:05"
|
||||
DateTimeFormat = "2006-01-02 15:04:05"
|
||||
DateTimeFormatMilli = "2006-01-02 15:04:05.000"
|
||||
DateTimeFormatMicro = "2006-01-02 15:04:05.000000"
|
||||
DateTimeFormatNano = "2006-01-02 15:04:05.000000000"
|
||||
)
|
||||
|
||||
//
|
||||
// Part 0: Get some useful infomation about time
|
||||
//
|
||||
|
||||
// GetNowS gets unix timestamp in second
|
||||
func GetNowS() int64 {
|
||||
return time.Now().Unix()
|
||||
}
|
||||
|
||||
// GetNowMs gets unix timestamp in millisecond
|
||||
func GetNowMs() int64 {
|
||||
return time.Now().UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
|
||||
// GetNowUs gets unix timestamp in microsecond
|
||||
func GetNowUs() int64 {
|
||||
return time.Now().UnixNano() / int64(time.Microsecond)
|
||||
}
|
||||
|
||||
// GetNowNs gets unix timestamp in nanosecond
|
||||
func GetNowNs() int64 {
|
||||
return time.Now().UnixNano()
|
||||
}
|
||||
|
||||
// GetNowDate gets now date in YYYY-MM-DD
|
||||
func GetNowDate() string {
|
||||
return time.Now().Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetNowDate gets now time in hh:mm:ss
|
||||
func GetNowTime() string {
|
||||
return time.Now().Format(TimeFormat)
|
||||
}
|
||||
|
||||
// GetNowDateTimeZ gets now datetime with zone in YYYY-MM-DD hh:mm:ss Zone
|
||||
// e.g. 2020-05-11 23:18:07 +08:00
|
||||
func GetNowDateTimeZ() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05 Z07:00")
|
||||
}
|
||||
|
||||
// GetDayBeginMoment gets the starting moment of one day
|
||||
func GetDayBeginMoment(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
n := time.Date(y, m, d, 0, 0, 0, 0, time.Local)
|
||||
return n
|
||||
}
|
||||
|
||||
// GetDayBeginMoment1 gets the starting moment of one day specified by UNIX time stamp
|
||||
func GetDayBeginMoment1(uts int64) time.Time {
|
||||
y, m, d := time.Unix(uts, 0).Date()
|
||||
n := time.Date(y, m, d, 0, 0, 0, 0, time.Local)
|
||||
return n
|
||||
}
|
||||
|
||||
// GetDayEndMoment gets the ending moment of one day
|
||||
func GetDayEndMoment(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
n := time.Date(y, m, d, 23, 59, 59, 999999999, time.Local)
|
||||
return n
|
||||
}
|
||||
|
||||
// GetDayEndMoment1 gets the ending moment of one day specified by UNIX time stamp
|
||||
func GetDayEndMoment1(uts int64) time.Time {
|
||||
y, m, d := time.Unix(uts, 0).Date()
|
||||
n := time.Date(y, m, d, 23, 59, 59, 999999999, time.Local)
|
||||
return n
|
||||
}
|
||||
|
||||
// GetDayElapsedS gets the elapsed seconds since the starting moment of one day
|
||||
func GetDayElapsedS(t time.Time) int64 {
|
||||
return t.Unix() - GetDayBeginMoment(t).Unix()
|
||||
}
|
||||
|
||||
// GetDayElapsedMs gets the elapsed milliseconds since the starting moment of one day
|
||||
func GetDayElapsedMs(t time.Time) int64 {
|
||||
return (t.UnixNano() - GetDayBeginMoment(t).UnixNano()) / int64(time.Millisecond)
|
||||
}
|
||||
|
||||
// GetDayElapsedUs gets the elapsed microseconds since the starting moment of one day
|
||||
func GetDayElapsedUs(t time.Time) int64 {
|
||||
return (t.UnixNano() - GetDayBeginMoment(t).UnixNano()) / int64(time.Microsecond)
|
||||
}
|
||||
|
||||
// GetDayElapsedNs gets the elapsed nanoseconds since the starting moment of one day
|
||||
func GetDayElapsedNs(t time.Time) int64 {
|
||||
return t.Unix() - GetDayBeginMoment(t).Unix()
|
||||
}
|
||||
|
||||
// GetDaysBtwTs gets the number of days between two timestamps and round down
|
||||
func GetDaysBtwTs(ts0, ts1 int64) int64 {
|
||||
return int64(math.Abs(float64(ts0-ts1))) / 86400
|
||||
}
|
||||
|
||||
// GetHoursBtwTs gets the number of hours between two timestamps and round down
|
||||
func GetHoursBtwTs(ts0, ts1 int64) int64 {
|
||||
return int64(math.Abs(float64(ts0-ts1))) / 3600
|
||||
}
|
||||
|
||||
// GetMinutesBtwTs gets the number of hours between two timestamps and round down
|
||||
func GetMinutesBtwTs(ts0, ts1 int64) int64 {
|
||||
return int64(math.Abs(float64(ts0-ts1))) / 60
|
||||
}
|
||||
|
||||
// GetWeekday gets the weekday time
|
||||
func GetWeekday(t time.Time, w time.Weekday) time.Time {
|
||||
if t.Weekday() == w {
|
||||
return t
|
||||
}
|
||||
d := w - t.Weekday()
|
||||
if w == time.Sunday {
|
||||
d += 7
|
||||
} else if t.Weekday() == time.Sunday {
|
||||
d -= 7
|
||||
}
|
||||
return t.AddDate(0, 0, int(d))
|
||||
}
|
||||
|
||||
// GetMonDate gets monday date in format 2006-01-02
|
||||
func GetMonDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Monday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetTuesDate gets tuesday date in format 2006-01-02
|
||||
func GetTuesDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Tuesday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetWedDate gets wednesday date in format 2006-01-02
|
||||
func GetWedDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Wednesday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetThursDate gets thursday date in format 2006-01-02
|
||||
func GetThursDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Thursday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetFriDate gets friday date in format 2006-01-02
|
||||
func GetFriDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Friday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetSatDate gets saturday date in format 2006-01-02
|
||||
func GetSatDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Saturday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// GetSunDate gets sunday date in format 2006-01-02
|
||||
func GetSunDate(t time.Time) string {
|
||||
return GetWeekday(t, time.Sunday).Format(DateFormat)
|
||||
}
|
||||
|
||||
// IsLeapYear checks the year whether is leap year
|
||||
func IsLeapYear(year int) bool {
|
||||
return (year%4 == 0 && year%100 != 0) || year%400 == 0
|
||||
}
|
||||
|
||||
// IsSameYear checks the unix timestamp whether is the same year
|
||||
func IsSameYear(uts1, uts2 int64) bool {
|
||||
t1 := time.Unix(uts1, 0)
|
||||
t2 := time.Unix(uts2, 0)
|
||||
return t1.Format(YFormatNum) == t2.Format(YFormatNum)
|
||||
}
|
||||
|
||||
// IsSameMonth checks the unix timestamp whether is the same month
|
||||
func IsSameMonth(uts1, uts2 int64) bool {
|
||||
t1 := time.Unix(uts1, 0)
|
||||
t2 := time.Unix(uts2, 0)
|
||||
return t1.Format(YMFormatNum) == t2.Format(YMFormatNum)
|
||||
}
|
||||
|
||||
// IsSameDay checks the unix timestamp whether is the same day
|
||||
func IsSameDay(uts1, uts2 int64) bool {
|
||||
t1 := time.Unix(uts1, 0)
|
||||
t2 := time.Unix(uts2, 0)
|
||||
return t1.Format(DateFormatNum) == t2.Format(DateFormatNum)
|
||||
}
|
||||
|
||||
// IsSameHour checks the unix timestamp whether is the same hour
|
||||
func IsSameHour(uts1, uts2 int64) bool {
|
||||
t1 := time.Unix(uts1, 0)
|
||||
t2 := time.Unix(uts2, 0)
|
||||
return t1.Format(DateHFormatNum) == t2.Format(DateHFormatNum)
|
||||
}
|
||||
|
||||
// IsSameMinute checks the unix timestamp whether is the same minute
|
||||
func IsSameMinute(uts1, uts2 int64) bool {
|
||||
t1 := time.Unix(uts1, 0)
|
||||
t2 := time.Unix(uts2, 0)
|
||||
return t1.Format(DateHMFormatNum) == t2.Format(DateHMFormatNum)
|
||||
}
|
||||
|
||||
// IsSameWeek checks the unix timestamp whether is the same week
|
||||
func IsSameWeek(uts1, uts2 int64) bool {
|
||||
t1 := time.Unix(uts1, 0)
|
||||
t2 := time.Unix(uts2, 0)
|
||||
return GetMonDate(t1) == GetMonDate(t2)
|
||||
}
|
||||
|
||||
//
|
||||
// Part 1: Common conversion about time
|
||||
//
|
||||
|
||||
// DateTime2UTs converts datetime in YYYY-MM-DD hh:mm:ss to unix timestamp
|
||||
func DateTime2UTs(dt string) int64 {
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
t, err := time.ParseInLocation(DateTimeFormat, dt, loc)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return t.Unix()
|
||||
}
|
||||
|
||||
// UTs2DateTime converts unix timestamp to datetime in YYYY-MM-DD hh:mm:ss
|
||||
func UTs2DateTime(uts int64) string {
|
||||
return time.Unix(uts, 0).Format(DateTimeFormat)
|
||||
}
|
||||
|
||||
//
|
||||
// Part 2: A time counter to count time interval
|
||||
//
|
||||
|
||||
// TimeCounter is used to count time interval
|
||||
type TimeCounter struct {
|
||||
time.Time
|
||||
int64
|
||||
}
|
||||
|
||||
// NewTimeCounter create a time counter
|
||||
func NewTimeCounter() (t *TimeCounter) {
|
||||
t = new(TimeCounter)
|
||||
t.Set()
|
||||
return t
|
||||
}
|
||||
|
||||
// Set start timing
|
||||
func (t *TimeCounter) Set() {
|
||||
t.Time = time.Now()
|
||||
t.int64 = t.Time.UnixNano()
|
||||
}
|
||||
|
||||
// GetD return the time interval from the beginning to now in time.Duration
|
||||
func (t *TimeCounter) GetD() time.Duration {
|
||||
return time.Since(t.Time)
|
||||
}
|
||||
|
||||
// GetS return the time interval from the beginning to now in second
|
||||
func (t *TimeCounter) GetS() int64 {
|
||||
return (time.Now().UnixNano() - t.int64) / int64(time.Second)
|
||||
}
|
||||
|
||||
// GetMs return the time interval from the beginning to now in millisecond
|
||||
func (t *TimeCounter) GetMs() int64 {
|
||||
return (time.Now().UnixNano() - t.int64) / int64(time.Millisecond)
|
||||
}
|
||||
|
||||
// GetUs return the time interval from the beginning to now in microsecond
|
||||
func (t *TimeCounter) GetUs() int64 {
|
||||
return (time.Now().UnixNano() - t.int64) / int64(time.Microsecond)
|
||||
}
|
||||
|
||||
// GetNs return the time interval from the beginning to now in nanosecond
|
||||
func (t *TimeCounter) GetNs() int64 {
|
||||
return time.Now().UnixNano() - t.int64
|
||||
}
|
||||
|
||||
// TimeCost count time cost
|
||||
func TimeCost() func() time.Duration {
|
||||
start := time.Now()
|
||||
return func() time.Duration {
|
||||
return time.Since(start)
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package ziputil
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Zip compresses the specified files or dirs to zip archive.
|
||||
// If a path is a dir don't need to specify the trailing path separator.
|
||||
// For example calling Zip("archive.zip", "dir", "csv/baz.csv") will get archive.zip and the content of which is
|
||||
// dir
|
||||
// |-- foo.txt
|
||||
// |-- bar.txt
|
||||
// baz.csv
|
||||
func Zip(zipPath string, paths ...string) error {
|
||||
// create zip file
|
||||
if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
archive, err := os.Create(zipPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer archive.Close()
|
||||
|
||||
// new zip writer
|
||||
zipWriter := zip.NewWriter(archive)
|
||||
defer zipWriter.Close()
|
||||
|
||||
// traverse the file or directory
|
||||
for _, srcPath := range paths {
|
||||
// remove the trailing path separator if path is a directory
|
||||
srcPath = strings.TrimSuffix(srcPath, string(os.PathSeparator))
|
||||
|
||||
// visit all the files or directories in the tree
|
||||
err = filepath.Walk(srcPath, func(path string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create a local file header
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set compression
|
||||
header.Method = zip.Deflate
|
||||
|
||||
// set relative path of a file as the header name
|
||||
header.Name, err = filepath.Rel(filepath.Dir(srcPath), path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
header.Name += string(os.PathSeparator)
|
||||
}
|
||||
|
||||
// create writer for the file header and save content of the file
|
||||
headerWriter, err := zipWriter.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.Copy(headerWriter, f)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unzip decompresses a zip file to specified directory.
|
||||
// Note that the destination directory don't need to specify the trailing path separator.
|
||||
func Unzip(zipPath, dstDir string) error {
|
||||
// open zip file
|
||||
reader, err := zip.OpenReader(zipPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
for _, file := range reader.File {
|
||||
if err := unzipFile(file, dstDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unzipFile(file *zip.File, dstDir string) error {
|
||||
// create the directory of file
|
||||
filePath := path.Join(dstDir, file.Name)
|
||||
if file.FileInfo().IsDir() {
|
||||
if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// open the file
|
||||
r, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
// create the file
|
||||
w, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
// save the decompressed file content
|
||||
_, err = io.Copy(w, r)
|
||||
return err
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package znet
|
||||
|
||||
import (
|
||||
protocol "gonet/goProtocol"
|
||||
)
|
||||
|
||||
// Encode from Packet to []byte
|
||||
func Encode(packet any) *protocol.ByteBuffer {
|
||||
var buffer = new(protocol.ByteBuffer)
|
||||
buffer.WriteRawInt32(0)
|
||||
protocol.Write(buffer, packet)
|
||||
var writeOffset = buffer.WriteOffset()
|
||||
buffer.SetWriteOffset(0)
|
||||
buffer.WriteRawInt32(int32(writeOffset - 4))
|
||||
buffer.SetWriteOffset(writeOffset)
|
||||
return buffer
|
||||
}
|
||||
|
||||
// Decode from []byte to Packet
|
||||
func Decode(data []byte) any {
|
||||
var buffer = new(protocol.ByteBuffer)
|
||||
buffer.WriteUBytes(data)
|
||||
var packet = protocol.Read(buffer)
|
||||
return packet
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package znet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Server struct
|
||||
type Server struct {
|
||||
onMessage func(*Session, any)
|
||||
onConnect func(*Session)
|
||||
onDisconnect func(*Session, error)
|
||||
sessions *sync.Map
|
||||
address string
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
// NewServer create a new socket service
|
||||
func NewServer(addr string) *Server {
|
||||
listen, _ := net.Listen("tcp", addr)
|
||||
server := &Server{
|
||||
sessions: &sync.Map{},
|
||||
address: addr,
|
||||
listener: listen,
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
|
||||
// Start Start socket service
|
||||
func (s *Server) Start() {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
defer func() {
|
||||
cancel()
|
||||
s.listener.Close()
|
||||
}()
|
||||
|
||||
s.acceptHandler(ctx)
|
||||
}
|
||||
|
||||
func (s *Server) acceptHandler(ctx context.Context) {
|
||||
for {
|
||||
conn, _ := s.listener.Accept()
|
||||
go s.connectHandler(ctx, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) connectHandler(ctx context.Context, c net.Conn) {
|
||||
var session = NewSession(c)
|
||||
s.sessions.Store(session.sid, session)
|
||||
|
||||
connctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
defer func() {
|
||||
cancel()
|
||||
session.Close()
|
||||
s.sessions.Delete(session.sid)
|
||||
}()
|
||||
|
||||
go session.readCoroutine(connctx)
|
||||
go session.writeCoroutine(connctx)
|
||||
|
||||
if s.onConnect != nil {
|
||||
s.onConnect(session)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-session.done:
|
||||
|
||||
if s.onDisconnect != nil {
|
||||
s.onDisconnect(session, err)
|
||||
}
|
||||
return
|
||||
|
||||
case packet := <-session.messageCh:
|
||||
if s.onMessage != nil {
|
||||
s.onMessage(session, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package znet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Session struct
|
||||
type Session struct {
|
||||
sid uint64
|
||||
uid uint64
|
||||
|
||||
rawConn net.Conn
|
||||
sendCh chan []byte
|
||||
messageCh chan any
|
||||
done chan error
|
||||
}
|
||||
|
||||
var uuid uint64
|
||||
|
||||
// NewSession create a new session
|
||||
func NewSession(conn net.Conn) *Session {
|
||||
var suuid = atomic.AddUint64(&uuid, 1)
|
||||
|
||||
session := &Session{
|
||||
sid: suuid,
|
||||
uid: 0, // 可以为用户的id
|
||||
|
||||
rawConn: conn,
|
||||
sendCh: make(chan []byte, 100),
|
||||
done: make(chan error),
|
||||
messageCh: make(chan any, 100),
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Close close connection
|
||||
func (session *Session) Close() {
|
||||
session.rawConn.Close()
|
||||
}
|
||||
|
||||
// SendMessage send message
|
||||
func (session *Session) SendMessage(msg any) error {
|
||||
var buffer = Encode(msg)
|
||||
session.sendCh <- buffer.ToBytes()
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeCoroutine write coroutine
|
||||
func (session *Session) writeCoroutine(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case pkt := <-session.sendCh:
|
||||
|
||||
if pkt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := session.rawConn.Write(pkt); err != nil {
|
||||
session.done <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// readCoroutine read coroutine
|
||||
func (session *Session) readCoroutine(ctx context.Context) {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
default:
|
||||
// 读取长度
|
||||
buf := make([]byte, 4)
|
||||
_, err := io.ReadFull(session.rawConn, buf)
|
||||
if err != nil {
|
||||
session.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
bufReader := bytes.NewReader(buf)
|
||||
|
||||
var dataSize int32
|
||||
err = binary.Read(bufReader, binary.BigEndian, &dataSize)
|
||||
if err != nil {
|
||||
session.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
// 读取数据
|
||||
var bytes = make([]byte, dataSize)
|
||||
_, err = io.ReadFull(session.rawConn, bytes)
|
||||
if err != nil {
|
||||
session.done <- err
|
||||
continue
|
||||
}
|
||||
|
||||
// 解码
|
||||
var packet = Decode(bytes)
|
||||
session.messageCh <- packet
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The zfoo Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
package znet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
protocol "gonet/goProtocol"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
var host = "127.0.0.1:9000"
|
||||
|
||||
var server = NewServer(host)
|
||||
server.onMessage = HandleMessage
|
||||
server.onConnect = HandleConnect
|
||||
server.onDisconnect = HandleDisconnect
|
||||
|
||||
server.Start()
|
||||
}
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
host := "127.0.0.1:9000"
|
||||
tcpAddr, _ := net.ResolveTCPAddr("tcp", host)
|
||||
|
||||
conn, _ := net.DialTCP("tcp", nil, tcpAddr)
|
||||
|
||||
var packet = new(protocol.TcpHelloRequest)
|
||||
packet.Message = "Hello, This is Golang Client"
|
||||
|
||||
fmt.Println("send message")
|
||||
|
||||
var buffer = Encode(packet)
|
||||
conn.Write(buffer.ToBytes())
|
||||
|
||||
time.Sleep(time.Millisecond * 5000)
|
||||
}
|
||||
|
||||
func HandleMessage(session *Session, packet any) {
|
||||
fmt.Println("receive packet")
|
||||
fmt.Println(packet)
|
||||
|
||||
session.SendMessage(packet)
|
||||
}
|
||||
|
||||
func HandleDisconnect(session *Session, err error) {
|
||||
fmt.Println("disconnect")
|
||||
fmt.Println(session.sid)
|
||||
}
|
||||
|
||||
func HandleConnect(session *Session) {
|
||||
fmt.Println("connected.")
|
||||
fmt.Println(session.sid)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user