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  }