github.com/ergo-services/ergo@v1.999.224/lib/tools.go (about) 1 package lib 2 3 import ( 4 "crypto/rand" 5 "encoding/hex" 6 "flag" 7 "fmt" 8 "hash/crc32" 9 "io" 10 "log" 11 "math" 12 "path/filepath" 13 "runtime" 14 "strconv" 15 "strings" 16 "sync" 17 "time" 18 ) 19 20 // Buffer 21 type Buffer struct { 22 B []byte 23 original []byte 24 } 25 26 var ( 27 ergoTrace = false 28 ergoWarning = false 29 ergoNoRecover = false 30 ergoDebug = false 31 32 DefaultBufferLength = 16384 33 buffers = &sync.Pool{ 34 New: func() interface{} { 35 b := &Buffer{ 36 B: make([]byte, 0, DefaultBufferLength), 37 } 38 b.original = b.B 39 return b 40 }, 41 } 42 43 timers = &sync.Pool{ 44 New: func() interface{} { 45 return time.NewTimer(time.Second * 5) 46 }, 47 } 48 49 ErrTooLarge = fmt.Errorf("Too large") 50 51 CRC32Q = crc32.MakeTable(0xD5828281) 52 ) 53 54 func init() { 55 flag.BoolVar(&ergoTrace, "ergo.trace", false, "enable/disable extended node logging info") 56 flag.BoolVar(&ergoWarning, "ergo.warning", true, "enable/disable warning messages") 57 flag.BoolVar(&ergoNoRecover, "ergo.norecover", false, "disable panic catching") 58 flag.BoolVar(&ergoDebug, "ergo.debug", false, "enable/disable debug messages") 59 } 60 61 // Log 62 func Log(f string, a ...interface{}) { 63 if ergoTrace { 64 printf(f, a...) 65 } 66 } 67 68 // Warning 69 func Warning(f string, a ...interface{}) { 70 if ergoWarning { 71 printf("WARNING! "+f, a...) 72 } 73 } 74 75 // Print log information 76 func printf(formating string, args ...interface{}) { 77 if ergoDebug { 78 goID, fileName, line, funcName := 0, "unknown", 0, "unknown" 79 var buf [64]byte 80 n := runtime.Stack(buf[:], false) 81 idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] 82 goID, _ = strconv.Atoi(idField) 83 pc, fileName, line, ok := runtime.Caller(2) 84 if ok { 85 funcName = runtime.FuncForPC(pc).Name() 86 funcName = filepath.Base(funcName) 87 fileName = filepath.Base(fileName) 88 } 89 log.Printf("<Go#%d>@%s:%d %s %s\n", goID, fileName, line, funcName, fmt.Sprintf(formating, args...)) 90 } else { 91 log.Printf(formating, args...) 92 } 93 } 94 95 // CatchPanic 96 func CatchPanic() bool { 97 return ergoNoRecover == false 98 } 99 100 // TakeTimer 101 func TakeTimer() *time.Timer { 102 return timers.Get().(*time.Timer) 103 } 104 105 // ReleaseTimer 106 func ReleaseTimer(t *time.Timer) { 107 if !t.Stop() { 108 select { 109 case <-t.C: 110 default: 111 } 112 } 113 timers.Put(t) 114 } 115 116 // TakeBuffer 117 func TakeBuffer() *Buffer { 118 return buffers.Get().(*Buffer) 119 } 120 121 // ReleaseBuffer 122 func ReleaseBuffer(b *Buffer) { 123 c := cap(b.B) 124 // cO := cap(b.original) 125 // overlaps := c > 0 && cO > 0 && &(x[:c][c-1]) == &(y[:cO][cO-1]) 126 if c > DefaultBufferLength && c < 65536 { 127 // reallocation happened. keep reallocated buffer as an original 128 // if it doesn't exceed the size of 65K (we don't want to keep 129 // too big slices) 130 b.original = b.B[:0] 131 } 132 b.B = b.original[:0] 133 buffers.Put(b) 134 } 135 136 // Reset 137 func (b *Buffer) Reset() { 138 c := cap(b.B) 139 if c > DefaultBufferLength && c < 65536 { 140 b.original = b.B[:0] 141 } 142 // use the original start point of the slice 143 b.B = b.original[:0] 144 } 145 146 // Set 147 func (b *Buffer) Set(v []byte) { 148 b.B = append(b.B[:0], v...) 149 } 150 151 // AppendByte 152 func (b *Buffer) AppendByte(v byte) { 153 b.B = append(b.B, v) 154 } 155 156 // Append 157 func (b *Buffer) Append(v []byte) { 158 b.B = append(b.B, v...) 159 } 160 161 // String 162 func (b *Buffer) String() string { 163 return string(b.B) 164 } 165 166 // Len 167 func (b *Buffer) Len() int { 168 return len(b.B) 169 } 170 171 // WriteDataTo 172 func (b *Buffer) WriteDataTo(w io.Writer) error { 173 l := len(b.B) 174 if l == 0 { 175 return nil 176 } 177 178 for { 179 n, e := w.Write(b.B) 180 if e != nil { 181 return e 182 } 183 184 l -= n 185 if l > 0 { 186 continue 187 } 188 189 break 190 } 191 192 b.Reset() 193 return nil 194 } 195 196 // ReadDataFrom 197 func (b *Buffer) ReadDataFrom(r io.Reader, limit int) (int, error) { 198 capB := cap(b.B) 199 lenB := len(b.B) 200 if limit == 0 { 201 limit = math.MaxInt 202 } 203 // if buffer becomes too large 204 if lenB > limit { 205 return 0, ErrTooLarge 206 } 207 if capB-lenB < capB>>1 { 208 // less than (almost) 50% space left. increase capacity 209 b.increase() 210 capB = cap(b.B) 211 } 212 n, e := r.Read(b.B[lenB:capB]) 213 l := lenB + n 214 b.B = b.B[:l] 215 return n, e 216 } 217 218 func (b *Buffer) Write(v []byte) (n int, err error) { 219 b.B = append(b.B, v...) 220 return len(v), nil 221 } 222 223 func (b *Buffer) Read(v []byte) (n int, err error) { 224 copy(v, b.B) 225 return len(b.B), io.EOF 226 } 227 228 func (b *Buffer) increase() { 229 cap1 := cap(b.B) * 8 230 b1 := make([]byte, cap(b.B), cap1) 231 copy(b1, b.B) 232 b.B = b1 233 } 234 235 // Allocate 236 func (b *Buffer) Allocate(n int) { 237 for { 238 if cap(b.B) < n { 239 b.increase() 240 continue 241 } 242 b.B = b.B[:n] 243 return 244 } 245 } 246 247 // Extend 248 func (b *Buffer) Extend(n int) []byte { 249 l := len(b.B) 250 e := l + n 251 for { 252 if e > cap(b.B) { 253 b.increase() 254 continue 255 } 256 b.B = b.B[:e] 257 return b.B[l:e] 258 } 259 } 260 261 // RandomString 262 func RandomString(length int) string { 263 buff := make([]byte, length/2) 264 rand.Read(buff) 265 return hex.EncodeToString(buff) 266 }