del[go]: delete golang net for zfoo protocol

This commit is contained in:
sun
2023-10-20 10:52:53 +08:00
parent 9f599ea878
commit 7db552cfd1
64 changed files with 0 additions and 11391 deletions
-134
View File
@@ -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)
}
-3
View File
@@ -1,3 +0,0 @@
module gonet
go 1.19
-900
View File
@@ -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)
}
-341
View File
@@ -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
}
-54
View File
@@ -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
}
-54
View File
@@ -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
}
-54
View File
@@ -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
}
-54
View File
@@ -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
}
-54
View File
@@ -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
}
-30
View File
@@ -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()
}
-65
View File
@@ -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
}
-36
View File
@@ -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))
}
-166
View File
@@ -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
}
}
}
-29
View File
@@ -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
)
-38
View File
@@ -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))
}
-198
View File
@@ -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
})
}
-79
View File
@@ -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)
}
-73
View File
@@ -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
}
-64
View File
@@ -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...)...)
}
-311
View File
@@ -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
}
-373
View File
@@ -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)
}
-348
View File
@@ -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
}
-179
View File
@@ -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位小数
}
-115
View File
@@ -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
}
-46
View File
@@ -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)
}
-125
View File
@@ -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()))
}
-84
View File
@@ -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
}
-20
View File
@@ -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)
}
-283
View File
@@ -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))
}
-158
View File
@@ -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:]
}
-242
View File
@@ -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
}
-65
View File
@@ -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))
}
-546
View File
@@ -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"))
}
-104
View File
@@ -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)
}
-375
View File
@@ -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
}
-57
View File
@@ -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
}
-344
View File
@@ -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
}
-106
View File
@@ -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]
}
-59
View File
@@ -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
}
-104
View File
@@ -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
}
-34
View File
@@ -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
}
-418
View File
@@ -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())
}
-153
View File
@@ -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")
}
-69
View File
@@ -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))
}
-79
View File
@@ -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)]
}
-133
View File
@@ -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
}
-27
View File
@@ -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))
}
-76
View File
@@ -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
-441
View File
@@ -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)
}
}
-145
View File
@@ -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
}
-37
View File
@@ -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
}
-96
View File
@@ -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)
}
}
}
}
-126
View File
@@ -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
}
}
}
-66
View File
@@ -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)
}