github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/common/common.go (about)

     1  package common
     2  
     3  //
     4  // gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
     5  // This covers these architectures.
     6  //  - linux (amd64, arm)
     7  //  - freebsd (amd64)
     8  //  - windows (amd64)
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"context"
    13  	"errors"
    14  	"fmt"
    15  	"log"
    16  	"net/url"
    17  	"os"
    18  	"os/exec"
    19  	"path"
    20  	"path/filepath"
    21  	"reflect"
    22  	"runtime"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  )
    27  
    28  var (
    29  	Timeout    = 3 * time.Second
    30  	ErrTimeout = errors.New("command timed out")
    31  )
    32  
    33  type Invoker interface {
    34  	Command(string, ...string) ([]byte, error)
    35  	CommandWithContext(context.Context, string, ...string) ([]byte, error)
    36  }
    37  
    38  type Invoke struct{}
    39  
    40  func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
    41  	ctx, cancel := context.WithTimeout(context.Background(), Timeout)
    42  	defer cancel()
    43  	return i.CommandWithContext(ctx, name, arg...)
    44  }
    45  
    46  func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
    47  	cmd := exec.CommandContext(ctx, name, arg...)
    48  
    49  	var buf bytes.Buffer
    50  	cmd.Stdout = &buf
    51  	cmd.Stderr = &buf
    52  
    53  	if err := cmd.Start(); err != nil {
    54  		return buf.Bytes(), err
    55  	}
    56  
    57  	if err := cmd.Wait(); err != nil {
    58  		return buf.Bytes(), err
    59  	}
    60  
    61  	return buf.Bytes(), nil
    62  }
    63  
    64  type FakeInvoke struct {
    65  	Suffix string // Suffix species expected file name suffix such as "fail"
    66  	Error  error  // If Error specfied, return the error.
    67  }
    68  
    69  // Command in FakeInvoke returns from expected file if exists.
    70  func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
    71  	if i.Error != nil {
    72  		return []byte{}, i.Error
    73  	}
    74  
    75  	arch := runtime.GOOS
    76  
    77  	commandName := filepath.Base(name)
    78  
    79  	fname := strings.Join(append([]string{commandName}, arg...), "")
    80  	fname = url.QueryEscape(fname)
    81  	fpath := path.Join("testdata", arch, fname)
    82  	if i.Suffix != "" {
    83  		fpath += "_" + i.Suffix
    84  	}
    85  	if PathExists(fpath) {
    86  		return os.ReadFile(fpath)
    87  	}
    88  	return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
    89  }
    90  
    91  func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
    92  	return i.Command(name, arg...)
    93  }
    94  
    95  var ErrNotImplementedError = errors.New("not implemented yet")
    96  
    97  // ReadFile reads contents from a file
    98  func ReadFile(filename string) (string, error) {
    99  	content, err := os.ReadFile(filename)
   100  
   101  	if err != nil {
   102  		return "", err
   103  	}
   104  
   105  	return string(content), nil
   106  }
   107  
   108  // ReadLines reads contents from a file and splits them by new lines.
   109  // A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
   110  func ReadLines(filename string) ([]string, error) {
   111  	return ReadLinesOffsetN(filename, 0, -1)
   112  }
   113  
   114  // ReadLines reads contents from file and splits them by new line.
   115  // The offset tells at which line number to start.
   116  // The count determines the number of lines to read (starting from offset):
   117  //
   118  //	n >= 0: at most n lines
   119  //	n < 0: whole file
   120  func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
   121  	f, err := os.Open(filename)
   122  	if err != nil {
   123  		return []string{""}, err
   124  	}
   125  	defer func(f *os.File) {
   126  		err := f.Close()
   127  		if err != nil {
   128  			log.Fatalln(err)
   129  		}
   130  	}(f)
   131  
   132  	var ret []string
   133  
   134  	r := bufio.NewReader(f)
   135  	for i := 0; i < n+int(offset) || n < 0; i++ {
   136  		line, err := r.ReadString('\n')
   137  		if err != nil {
   138  			break
   139  		}
   140  		if i < int(offset) {
   141  			continue
   142  		}
   143  		ret = append(ret, strings.Trim(line, "\n"))
   144  	}
   145  
   146  	return ret, nil
   147  }
   148  
   149  func IntToString(orig []int8) string {
   150  	ret := make([]byte, len(orig))
   151  	size := -1
   152  	for i, o := range orig {
   153  		if o == 0 {
   154  			size = i
   155  			break
   156  		}
   157  		ret[i] = byte(o)
   158  	}
   159  	if size == -1 {
   160  		size = len(orig)
   161  	}
   162  
   163  	return string(ret[0:size])
   164  }
   165  
   166  func UintToString(orig []uint8) string {
   167  	ret := make([]byte, len(orig))
   168  	size := -1
   169  	for i, o := range orig {
   170  		if o == 0 {
   171  			size = i
   172  			break
   173  		}
   174  		ret[i] = byte(o)
   175  	}
   176  	if size == -1 {
   177  		size = len(orig)
   178  	}
   179  
   180  	return string(ret[0:size])
   181  }
   182  
   183  func ByteToString(orig []byte) string {
   184  	n := -1
   185  	l := -1
   186  	for i, b := range orig {
   187  		// skip left side null
   188  		if l == -1 && b == 0 {
   189  			continue
   190  		}
   191  		if l == -1 {
   192  			l = i
   193  		}
   194  
   195  		if b == 0 {
   196  			break
   197  		}
   198  		n = i + 1
   199  	}
   200  	if n == -1 {
   201  		return string(orig)
   202  	}
   203  	return string(orig[l:n])
   204  }
   205  
   206  // ReadInts reads contents from single line file and returns them as []int32.
   207  func ReadInts(filename string) ([]int64, error) {
   208  	f, err := os.Open(filename)
   209  	if err != nil {
   210  		return []int64{}, err
   211  	}
   212  	defer func(f *os.File) {
   213  		err := f.Close()
   214  		if err != nil {
   215  			log.Fatalln(err)
   216  		}
   217  	}(f)
   218  
   219  	var ret []int64
   220  
   221  	r := bufio.NewReader(f)
   222  
   223  	// The int files that this is concerned with should only be one liners.
   224  	line, err := r.ReadString('\n')
   225  	if err != nil {
   226  		return []int64{}, err
   227  	}
   228  
   229  	i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
   230  	if err != nil {
   231  		return []int64{}, err
   232  	}
   233  	ret = append(ret, i)
   234  
   235  	return ret, nil
   236  }
   237  
   238  // Parse Hex to uint32 without error
   239  func HexToUint32(hex string) uint32 {
   240  	vv, _ := strconv.ParseUint(hex, 16, 32)
   241  	return uint32(vv)
   242  }
   243  
   244  // Parse to int32 without error
   245  func mustParseInt32(val string) int32 {
   246  	vv, _ := strconv.ParseInt(val, 10, 32)
   247  	return int32(vv)
   248  }
   249  
   250  // Parse to uint64 without error
   251  func mustParseUint64(val string) uint64 {
   252  	vv, _ := strconv.ParseInt(val, 10, 64)
   253  	return uint64(vv)
   254  }
   255  
   256  // Parse to Float64 without error
   257  func mustParseFloat64(val string) float64 {
   258  	vv, _ := strconv.ParseFloat(val, 64)
   259  	return vv
   260  }
   261  
   262  // StringsHas checks the target string slice contains src or not
   263  func StringsHas(target []string, src string) bool {
   264  	for _, t := range target {
   265  		if strings.TrimSpace(t) == src {
   266  			return true
   267  		}
   268  	}
   269  	return false
   270  }
   271  
   272  // StringsContains checks the src in any string of the target string slice
   273  func StringsContains(target []string, src string) bool {
   274  	for _, t := range target {
   275  		if strings.Contains(t, src) {
   276  			return true
   277  		}
   278  	}
   279  	return false
   280  }
   281  
   282  // IntContains checks the src in any int of the target int slice.
   283  func IntContains(target []int, src int) bool {
   284  	for _, t := range target {
   285  		if src == t {
   286  			return true
   287  		}
   288  	}
   289  	return false
   290  }
   291  
   292  // get struct attributes.
   293  // This method is used only for debugging platform dependent code.
   294  func attributes(m interface{}) map[string]reflect.Type {
   295  	typ := reflect.TypeOf(m)
   296  	if typ.Kind() == reflect.Ptr {
   297  		typ = typ.Elem()
   298  	}
   299  
   300  	attrs := make(map[string]reflect.Type)
   301  	if typ.Kind() != reflect.Struct {
   302  		return nil
   303  	}
   304  
   305  	for i := 0; i < typ.NumField(); i++ {
   306  		p := typ.Field(i)
   307  		if !p.Anonymous {
   308  			attrs[p.Name] = p.Type
   309  		}
   310  	}
   311  
   312  	return attrs
   313  }
   314  
   315  func PathExists(filename string) bool {
   316  	if _, err := os.Stat(filename); err == nil {
   317  		return true
   318  	}
   319  	return false
   320  }
   321  
   322  // GetEnv retrieves the environment variable key. If it does not exist it returns the default.
   323  func GetEnv(key string, dfault string, combineWith ...string) string {
   324  	value := os.Getenv(key)
   325  	if value == "" {
   326  		value = dfault
   327  	}
   328  
   329  	switch len(combineWith) {
   330  	case 0:
   331  		return value
   332  	case 1:
   333  		return filepath.Join(value, combineWith[0])
   334  	default:
   335  		all := make([]string, len(combineWith)+1)
   336  		all[0] = value
   337  		copy(all[1:], combineWith)
   338  		return filepath.Join(all...)
   339  	}
   340  }
   341  
   342  func HostProc(combineWith ...string) string {
   343  	return GetEnv("HOST_PROC", "/proc", combineWith...)
   344  }
   345  
   346  func HostSys(combineWith ...string) string {
   347  	return GetEnv("HOST_SYS", "/sys", combineWith...)
   348  }
   349  
   350  func HostEtc(combineWith ...string) string {
   351  	return GetEnv("HOST_ETC", "/etc", combineWith...)
   352  }
   353  
   354  func HostVar(combineWith ...string) string {
   355  	return GetEnv("HOST_VAR", "/var", combineWith...)
   356  }
   357  
   358  func HostRun(combineWith ...string) string {
   359  	return GetEnv("HOST_RUN", "/run", combineWith...)
   360  }
   361  
   362  func HostDev(combineWith ...string) string {
   363  	return GetEnv("HOST_DEV", "/dev", combineWith...)
   364  }
   365  
   366  // getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running
   367  // sysctl commands (see DoSysctrl).
   368  func getSysctrlEnv(env []string) []string {
   369  	foundLC := false
   370  	for i, line := range env {
   371  		if strings.HasPrefix(line, "LC_ALL") {
   372  			env[i] = "LC_ALL=C"
   373  			foundLC = true
   374  		}
   375  	}
   376  	if !foundLC {
   377  		env = append(env, "LC_ALL=C")
   378  	}
   379  	return env
   380  }