├── README.md ├── main.go ├── strtool └── strtool.go ├── rpctool └── rpctool.go ├── .gitignore ├── filetool ├── convert.go ├── writer.go ├── reader.go └── filetool.go ├── convertor └── convertor.go ├── formatter └── formatter.go ├── timetool └── timetool.go ├── systool ├── command.go └── system.go ├── LICENSE ├── logtool └── logtool.go ├── slicetool └── slicetool.go └── paginator └── paginator.go /README.md: -------------------------------------------------------------------------------- 1 | goutils 2 | ======= 3 | 4 | go utils 5 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ulricqin/goutils/systool" 6 | "github.com/ulricqin/goutils/timetool" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | fmt.Println(systool.IntranetIP()) 12 | fmt.Println(timetool.DateFormat(time.Now(), "YYYY-MM-DD")) 13 | } 14 | -------------------------------------------------------------------------------- /strtool/strtool.go: -------------------------------------------------------------------------------- 1 | package strtool 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func TrimRightSpace(s string) string { 10 | return strings.TrimRight(string(s), "\r\n\t ") 11 | } 12 | 13 | func Md5(s string) string { 14 | h := md5.New() 15 | h.Write([]byte(s)) 16 | return fmt.Sprintf("%x", h.Sum(nil)) 17 | } 18 | -------------------------------------------------------------------------------- /rpctool/rpctool.go: -------------------------------------------------------------------------------- 1 | package rpctool 2 | 3 | import ( 4 | "net" 5 | "net/rpc" 6 | "net/rpc/jsonrpc" 7 | "time" 8 | ) 9 | 10 | func DialTimeout(network, address string, timeout time.Duration) (*rpc.Client, error) { 11 | conn, err := net.DialTimeout(network, address, timeout) 12 | if err != nil { 13 | return nil, err 14 | } 15 | return jsonrpc.NewClient(conn), err 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | test.go 24 | 25 | goutils 26 | 27 | -------------------------------------------------------------------------------- /filetool/convert.go: -------------------------------------------------------------------------------- 1 | package filetool 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | func FileToUint64(file string) (uint64, error) { 8 | content, err := ReadFileToStringNoLn(file) 9 | if err != nil { 10 | return 0, err 11 | } 12 | 13 | var ret uint64 14 | if ret, err = strconv.ParseUint(content, 10, 64); err != nil { 15 | return 0, err 16 | } 17 | return ret, nil 18 | } 19 | 20 | func FileToInt64(file string) (int64, error) { 21 | content, err := ReadFileToStringNoLn(file) 22 | if err != nil { 23 | return 0, err 24 | } 25 | 26 | var ret int64 27 | if ret, err = strconv.ParseInt(content, 10, 64); err != nil { 28 | return 0, err 29 | } 30 | return ret, nil 31 | } 32 | -------------------------------------------------------------------------------- /filetool/writer.go: -------------------------------------------------------------------------------- 1 | package filetool 2 | 3 | import ( 4 | "os" 5 | "path" 6 | ) 7 | 8 | // WriteBytesToFile saves content type '[]byte' to file by given path. 9 | // It returns error when fail to finish operation. 10 | func WriteBytesToFile(filePath string, b []byte) (int, error) { 11 | os.MkdirAll(path.Dir(filePath), os.ModePerm) 12 | fw, err := os.Create(filePath) 13 | if err != nil { 14 | return 0, err 15 | } 16 | defer fw.Close() 17 | return fw.Write(b) 18 | } 19 | 20 | // WriteStringFile saves content type 'string' to file by given path. 21 | // It returns error when fail to finish operation. 22 | func WriteStringToFile(filePath string, s string) (int, error) { 23 | return WriteBytesToFile(filePath, []byte(s)) 24 | } 25 | -------------------------------------------------------------------------------- /convertor/convertor.go: -------------------------------------------------------------------------------- 1 | package convertor 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | func Int64ToBytes(i int64) []byte { 10 | var buf = make([]byte, 8) 11 | binary.BigEndian.PutUint64(buf, uint64(i)) 12 | return buf 13 | } 14 | 15 | func BytesToInt64(buf []byte) int64 { 16 | return int64(binary.BigEndian.Uint64(buf)) 17 | } 18 | 19 | // convert any numeric value to int64 20 | func ToInt64(value interface{}) (d int64, err error) { 21 | val := reflect.ValueOf(value) 22 | switch value.(type) { 23 | case int, int8, int16, int32, int64: 24 | d = val.Int() 25 | case uint, uint8, uint16, uint32, uint64: 26 | d = int64(val.Uint()) 27 | default: 28 | err = fmt.Errorf("ToInt64 need numeric not `%T`", value) 29 | } 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /formatter/formatter.go: -------------------------------------------------------------------------------- 1 | package formatter 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func DisplaySize(raw float64) string { 8 | if raw < 1024 { 9 | return fmt.Sprintf("%.1fB", raw) 10 | } 11 | 12 | if raw < 1024*1024 { 13 | return fmt.Sprintf("%.1fK", raw/1024.0) 14 | } 15 | 16 | if raw < 1024*1024*1024 { 17 | return fmt.Sprintf("%.1fM", raw/1024.0/1024.0) 18 | } 19 | 20 | if raw < 1024*1024*1024*1024 { 21 | return fmt.Sprintf("%.1fG", raw/1024.0/1024.0/1024.0) 22 | } 23 | 24 | if raw < 1024*1024*1024*1024*1024 { 25 | return fmt.Sprintf("%.1fT", raw/1024.0/1024.0/1024.0/1024.0) 26 | } 27 | 28 | if raw < 1024*1024*1024*1024*1024*1024 { 29 | return fmt.Sprintf("%.1fP", raw/1024.0/1024.0/1024.0/1024.0/1024.0) 30 | } 31 | 32 | return "TooLarge" 33 | } 34 | -------------------------------------------------------------------------------- /filetool/reader.go: -------------------------------------------------------------------------------- 1 | package filetool 2 | 3 | import ( 4 | "github.com/ulricqin/goutils/strtool" 5 | "io/ioutil" 6 | ) 7 | 8 | // ReadFileToBytes reads data type '[]byte' from file by given path. 9 | // It returns error when fail to finish operation. 10 | func ReadFileToBytes(filePath string) ([]byte, error) { 11 | b, err := ioutil.ReadFile(filePath) 12 | if err != nil { 13 | return []byte(""), err 14 | } 15 | return b, nil 16 | } 17 | 18 | // ReadFileToString reads data type 'string' from file by given path. 19 | // It returns error when fail to finish operation. 20 | func ReadFileToString(filePath string) (string, error) { 21 | b, err := ReadFileToBytes(filePath) 22 | if err != nil { 23 | return "", err 24 | } 25 | return string(b), nil 26 | } 27 | 28 | func ReadFileToStringNoLn(filePath string) (string, error) { 29 | str, err := ReadFileToString(filePath) 30 | if err != nil { 31 | return "", err 32 | } 33 | 34 | return strtool.TrimRightSpace(str), nil 35 | } 36 | -------------------------------------------------------------------------------- /timetool/timetool.go: -------------------------------------------------------------------------------- 1 | package timetool 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | ) 8 | 9 | // Format time.Time struct to string 10 | // MM - month - 01 11 | // M - month - 1, single bit 12 | // DD - day - 02 13 | // D - day 2 14 | // YYYY - year - 2006 15 | // YY - year - 06 16 | // HH - 24 hours - 03 17 | // H - 24 hours - 3 18 | // hh - 12 hours - 03 19 | // h - 12 hours - 3 20 | // mm - minute - 04 21 | // m - minute - 4 22 | // ss - second - 05 23 | // s - second = 5 24 | func DateFormat(t time.Time, format string) string { 25 | res := strings.Replace(format, "MM", t.Format("01"), -1) 26 | res = strings.Replace(res, "M", t.Format("1"), -1) 27 | res = strings.Replace(res, "DD", t.Format("02"), -1) 28 | res = strings.Replace(res, "D", t.Format("2"), -1) 29 | res = strings.Replace(res, "YYYY", t.Format("2006"), -1) 30 | res = strings.Replace(res, "YY", t.Format("06"), -1) 31 | res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1) 32 | res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1) 33 | res = strings.Replace(res, "hh", t.Format("03"), -1) 34 | res = strings.Replace(res, "h", t.Format("3"), -1) 35 | res = strings.Replace(res, "mm", t.Format("04"), -1) 36 | res = strings.Replace(res, "m", t.Format("4"), -1) 37 | res = strings.Replace(res, "ss", t.Format("05"), -1) 38 | res = strings.Replace(res, "s", t.Format("5"), -1) 39 | return res 40 | } 41 | -------------------------------------------------------------------------------- /systool/command.go: -------------------------------------------------------------------------------- 1 | package systool 2 | 3 | import ( 4 | "bytes" 5 | log "github.com/ulricqin/goutils/logtool" 6 | "github.com/ulricqin/goutils/strtool" 7 | "os/exec" 8 | "time" 9 | ) 10 | 11 | func CmdOut(name string, arg ...string) (string, error) { 12 | cmd := exec.Command(name, arg...) 13 | var out bytes.Buffer 14 | cmd.Stdout = &out 15 | err := cmd.Run() 16 | return out.String(), err 17 | } 18 | 19 | func CmdOutBytes(name string, arg ...string) ([]byte, error) { 20 | cmd := exec.Command(name, arg...) 21 | var out bytes.Buffer 22 | cmd.Stdout = &out 23 | err := cmd.Run() 24 | return out.Bytes(), err 25 | } 26 | 27 | func CmdOutNoLn(name string, arg ...string) (out string, err error) { 28 | out, err = CmdOut(name, arg...) 29 | if err != nil { 30 | return 31 | } 32 | 33 | return strtool.TrimRightSpace(string(out)), nil 34 | } 35 | 36 | func CmdRunWithTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) { 37 | done := make(chan error) 38 | go func() { 39 | done <- cmd.Wait() 40 | }() 41 | 42 | var err error 43 | select { 44 | case <-time.After(timeout): 45 | //timeout 46 | if err = cmd.Process.Kill(); err != nil { 47 | log.Error("failed to kill: %s, error: %s", cmd.Path, err) 48 | } 49 | go func() { 50 | <-done // allow goroutine to exit 51 | }() 52 | log.Info("process:%s killed", cmd.Path) 53 | return err, true 54 | case err = <-done: 55 | return err, false 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, UlricQin 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /logtool/logtool.go: -------------------------------------------------------------------------------- 1 | package logtool 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | ) 8 | 9 | var level int = 0 10 | 11 | func SetLevelWithDefault(lv, defaultLv string) { 12 | err := SetLevel(lv) 13 | if err != nil { 14 | SetLevel(defaultLv) 15 | Warn("log level not valid. use default level: %s", defaultLv) 16 | } 17 | } 18 | 19 | func SetLevel(lv string) error { 20 | if lv == "" { 21 | return fmt.Errorf("log level is blank") 22 | } 23 | 24 | l := strings.ToUpper(lv) 25 | 26 | switch l[0] { 27 | case 'T': 28 | level = 0 29 | case 'D': 30 | level = 1 31 | case 'I': 32 | level = 2 33 | case 'W': 34 | level = 3 35 | case 'E': 36 | level = 4 37 | case 'F': 38 | level = 5 39 | default: 40 | level = 6 41 | } 42 | 43 | if level == 6 { 44 | return fmt.Errorf("log level setting error") 45 | } 46 | 47 | return nil 48 | } 49 | 50 | // level: 0 51 | func Trace(format string, v ...interface{}) { 52 | if level <= 0 { 53 | p(" [T] "+format, v...) 54 | } 55 | } 56 | 57 | // level: 1 58 | func Debug(format string, v ...interface{}) { 59 | if level <= 1 { 60 | p(" [D] "+format, v...) 61 | } 62 | } 63 | 64 | // level: 2 65 | func Info(format string, v ...interface{}) { 66 | if level <= 2 { 67 | p(" [I] "+format, v...) 68 | } 69 | } 70 | 71 | // level: 3 72 | func Warn(format string, v ...interface{}) { 73 | if level <= 3 { 74 | p(" [W] "+format, v...) 75 | } 76 | } 77 | 78 | // level: 4 79 | func Error(format string, v ...interface{}) { 80 | if level <= 4 { 81 | p(" [E] "+format, v...) 82 | } 83 | } 84 | 85 | // level: 5 86 | func Fetal(format string, v ...interface{}) { 87 | if level <= 5 { 88 | p(" [F] "+format, v...) 89 | } 90 | } 91 | 92 | func p(format string, v ...interface{}) { 93 | fmt.Printf(time.Now().Format("2006/01/02 15:04:05")+format+"\n", v...) 94 | } 95 | -------------------------------------------------------------------------------- /slicetool/slicetool.go: -------------------------------------------------------------------------------- 1 | package slicetool 2 | 3 | func SliceContains(sl []interface{}, v interface{}) bool { 4 | for _, vv := range sl { 5 | if vv == v { 6 | return true 7 | } 8 | } 9 | return false 10 | } 11 | 12 | func SliceContainsInt(sl []int, v int) bool { 13 | for _, vv := range sl { 14 | if vv == v { 15 | return true 16 | } 17 | } 18 | return false 19 | } 20 | 21 | func SliceContainsInt64(sl []int64, v int64) bool { 22 | for _, vv := range sl { 23 | if vv == v { 24 | return true 25 | } 26 | } 27 | return false 28 | } 29 | 30 | func SliceContainsString(sl []string, v string) bool { 31 | for _, vv := range sl { 32 | if vv == v { 33 | return true 34 | } 35 | } 36 | return false 37 | } 38 | 39 | // SliceMerge merges interface slices to one slice. 40 | func SliceMerge(slice1, slice2 []interface{}) (c []interface{}) { 41 | c = append(slice1, slice2...) 42 | return 43 | } 44 | 45 | func SliceMergeInt(slice1, slice2 []int) (c []int) { 46 | c = append(slice1, slice2...) 47 | return 48 | } 49 | 50 | func SliceMergeInt64(slice1, slice2 []int64) (c []int64) { 51 | c = append(slice1, slice2...) 52 | return 53 | } 54 | 55 | func SliceMergeString(slice1, slice2 []string) (c []string) { 56 | c = append(slice1, slice2...) 57 | return 58 | } 59 | 60 | func SliceUniqueInt64(s []int64) []int64 { 61 | size := len(s) 62 | if size == 0 { 63 | return []int64{} 64 | } 65 | 66 | m := make(map[int64]bool) 67 | for i := 0; i < size; i++ { 68 | m[s[i]] = true 69 | } 70 | 71 | realLen := len(m) 72 | ret := make([]int64, realLen) 73 | 74 | idx := 0 75 | for key := range m { 76 | ret[idx] = key 77 | idx++ 78 | } 79 | 80 | return ret 81 | } 82 | 83 | func SliceUniqueInt(s []int) []int { 84 | size := len(s) 85 | if size == 0 { 86 | return []int{} 87 | } 88 | 89 | m := make(map[int]bool) 90 | for i := 0; i < size; i++ { 91 | m[s[i]] = true 92 | } 93 | 94 | realLen := len(m) 95 | ret := make([]int, realLen) 96 | 97 | idx := 0 98 | for key := range m { 99 | ret[idx] = key 100 | idx++ 101 | } 102 | 103 | return ret 104 | } 105 | 106 | func SliceUniqueString(s []string) []string { 107 | size := len(s) 108 | if size == 0 { 109 | return []string{} 110 | } 111 | 112 | m := make(map[string]bool) 113 | for i := 0; i < size; i++ { 114 | m[s[i]] = true 115 | } 116 | 117 | realLen := len(m) 118 | ret := make([]string, realLen) 119 | 120 | idx := 0 121 | for key := range m { 122 | ret[idx] = key 123 | idx++ 124 | } 125 | 126 | return ret 127 | } 128 | 129 | func SliceSumInt64(intslice []int64) (sum int64) { 130 | for _, v := range intslice { 131 | sum += v 132 | } 133 | return 134 | } 135 | 136 | func SliceSumInt(intslice []int) (sum int) { 137 | for _, v := range intslice { 138 | sum += v 139 | } 140 | return 141 | } 142 | 143 | func SliceSumFloat64(intslice []float64) (sum float64) { 144 | for _, v := range intslice { 145 | sum += v 146 | } 147 | return 148 | } 149 | -------------------------------------------------------------------------------- /paginator/paginator.go: -------------------------------------------------------------------------------- 1 | package paginator 2 | 3 | import ( 4 | "github.com/ulricqin/goutils/convertor" 5 | "math" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | type Paginator struct { 12 | Request *http.Request 13 | PerPageNums int 14 | MaxPages int 15 | 16 | nums int64 17 | pageRange []int 18 | pageNums int 19 | page int 20 | } 21 | 22 | func (p *Paginator) PageNums() int { 23 | if p.pageNums != 0 { 24 | return p.pageNums 25 | } 26 | pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums)) 27 | if p.MaxPages > 0 { 28 | pageNums = math.Min(pageNums, float64(p.MaxPages)) 29 | } 30 | p.pageNums = int(pageNums) 31 | return p.pageNums 32 | } 33 | 34 | func (p *Paginator) Nums() int64 { 35 | return p.nums 36 | } 37 | 38 | func (p *Paginator) SetNums(nums interface{}) { 39 | p.nums, _ = convertor.ToInt64(nums) 40 | } 41 | 42 | func (p *Paginator) Page() int { 43 | if p.page != 0 { 44 | return p.page 45 | } 46 | if p.Request.Form == nil { 47 | p.Request.ParseForm() 48 | } 49 | p.page, _ = strconv.Atoi(p.Request.Form.Get("p")) 50 | if p.page > p.PageNums() { 51 | p.page = p.PageNums() 52 | } 53 | if p.page <= 0 { 54 | p.page = 1 55 | } 56 | return p.page 57 | } 58 | 59 | func (p *Paginator) Pages() []int { 60 | if p.pageRange == nil && p.nums > 0 { 61 | var pages []int 62 | pageNums := p.PageNums() 63 | page := p.Page() 64 | switch { 65 | case page >= pageNums-4 && pageNums > 9: 66 | start := pageNums - 9 + 1 67 | pages = make([]int, 9) 68 | for i, _ := range pages { 69 | pages[i] = start + i 70 | } 71 | case page >= 5 && pageNums > 9: 72 | start := page - 5 + 1 73 | pages = make([]int, int(math.Min(9, float64(page+4+1)))) 74 | for i, _ := range pages { 75 | pages[i] = start + i 76 | } 77 | default: 78 | pages = make([]int, int(math.Min(9, float64(pageNums)))) 79 | for i, _ := range pages { 80 | pages[i] = i + 1 81 | } 82 | } 83 | p.pageRange = pages 84 | } 85 | return p.pageRange 86 | } 87 | 88 | func (p *Paginator) PageLink(page int) string { 89 | link, _ := url.ParseRequestURI(p.Request.RequestURI) 90 | values := link.Query() 91 | if page == 1 { 92 | values.Del("p") 93 | } else { 94 | values.Set("p", strconv.Itoa(page)) 95 | } 96 | link.RawQuery = values.Encode() 97 | return link.String() 98 | } 99 | 100 | func (p *Paginator) PageLinkPrev() (link string) { 101 | if p.HasPrev() { 102 | link = p.PageLink(p.Page() - 1) 103 | } 104 | return 105 | } 106 | 107 | func (p *Paginator) PageLinkNext() (link string) { 108 | if p.HasNext() { 109 | link = p.PageLink(p.Page() + 1) 110 | } 111 | return 112 | } 113 | 114 | func (p *Paginator) PageLinkFirst() (link string) { 115 | return p.PageLink(1) 116 | } 117 | 118 | func (p *Paginator) PageLinkLast() (link string) { 119 | return p.PageLink(p.PageNums()) 120 | } 121 | 122 | func (p *Paginator) HasPrev() bool { 123 | return p.Page() > 1 124 | } 125 | 126 | func (p *Paginator) HasNext() bool { 127 | return p.Page() < p.PageNums() 128 | } 129 | 130 | func (p *Paginator) IsActive(page int) bool { 131 | return p.Page() == page 132 | } 133 | 134 | func (p *Paginator) Offset() int { 135 | return (p.Page() - 1) * p.PerPageNums 136 | } 137 | 138 | func (p *Paginator) HasPages() bool { 139 | return p.PageNums() > 1 140 | } 141 | 142 | func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator { 143 | p := Paginator{} 144 | p.Request = req 145 | if per <= 0 { 146 | per = 10 147 | } 148 | p.PerPageNums = per 149 | p.SetNums(nums) 150 | return &p 151 | } 152 | -------------------------------------------------------------------------------- /filetool/filetool.go: -------------------------------------------------------------------------------- 1 | package filetool 2 | 3 | import ( 4 | "errors" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | "path/filepath" 9 | ) 10 | 11 | // SelfPath gets compiled executable file absolute path 12 | func SelfPath() string { 13 | path, _ := filepath.Abs(os.Args[0]) 14 | return path 15 | } 16 | 17 | // SelfDir gets compiled executable file directory 18 | func SelfDir() string { 19 | return filepath.Dir(SelfPath()) 20 | } 21 | 22 | // get filepath base name 23 | func Basename(file string) string { 24 | return path.Base(file) 25 | } 26 | 27 | // get filepath dir name 28 | func Dir(file string) string { 29 | return path.Dir(file) 30 | } 31 | 32 | func InsureDir(path string) error { 33 | if IsExist(path) { 34 | return nil 35 | } 36 | return os.MkdirAll(path, os.ModePerm) 37 | } 38 | 39 | func Ext(file string) string { 40 | return path.Ext(file) 41 | } 42 | 43 | // rename file name 44 | func Rename(file string, to string) error { 45 | return os.Rename(file, to) 46 | } 47 | 48 | // delete file 49 | func Unlink(file string) error { 50 | return os.Remove(file) 51 | } 52 | 53 | // IsFile checks whether the path is a file, 54 | // it returns false when it's a directory or does not exist. 55 | func IsFile(filePath string) bool { 56 | f, e := os.Stat(filePath) 57 | if e != nil { 58 | return false 59 | } 60 | return !f.IsDir() 61 | } 62 | 63 | // IsExist checks whether a file or directory exists. 64 | // It returns false when the file or directory does not exist. 65 | func IsExist(path string) bool { 66 | _, err := os.Stat(path) 67 | return err == nil || os.IsExist(err) 68 | } 69 | 70 | // Search a file in paths. 71 | // this is often used in search config file in /etc ~/ 72 | func SearchFile(filename string, paths ...string) (fullPath string, err error) { 73 | for _, path := range paths { 74 | if fullPath = filepath.Join(path, filename); IsExist(fullPath) { 75 | return 76 | } 77 | } 78 | err = errors.New(fullPath + " not found in paths") 79 | return 80 | } 81 | 82 | // get absolute filepath, based on built executable file 83 | func RealPath(file string) (string, error) { 84 | if path.IsAbs(file) { 85 | return file, nil 86 | } 87 | wd, err := os.Getwd() 88 | return path.Join(wd, file), err 89 | } 90 | 91 | // get file modified time 92 | func FileMTime(file string) (int64, error) { 93 | f, e := os.Stat(file) 94 | if e != nil { 95 | return 0, e 96 | } 97 | return f.ModTime().Unix(), nil 98 | } 99 | 100 | // get file size as how many bytes 101 | func FileSize(file string) (int64, error) { 102 | f, e := os.Stat(file) 103 | if e != nil { 104 | return 0, e 105 | } 106 | return f.Size(), nil 107 | } 108 | 109 | // list dirs under dirPath 110 | func DirsUnder(dirPath string) ([]string, error) { 111 | if !IsExist(dirPath) { 112 | return []string{}, nil 113 | } 114 | 115 | fs, err := ioutil.ReadDir(dirPath) 116 | if err != nil { 117 | return []string{}, err 118 | } 119 | 120 | sz := len(fs) 121 | if sz == 0 { 122 | return []string{}, nil 123 | } 124 | 125 | ret := []string{} 126 | for i := 0; i < sz; i++ { 127 | if fs[i].IsDir() { 128 | name := fs[i].Name() 129 | if name != "." && name != ".." { 130 | ret = append(ret, name) 131 | } 132 | } 133 | } 134 | 135 | return ret, nil 136 | 137 | } 138 | 139 | // list files under dirPath 140 | func FilesUnder(dirPath string) ([]string, error) { 141 | if !IsExist(dirPath) { 142 | return []string{}, nil 143 | } 144 | 145 | fs, err := ioutil.ReadDir(dirPath) 146 | if err != nil { 147 | return []string{}, err 148 | } 149 | 150 | sz := len(fs) 151 | if sz == 0 { 152 | return []string{}, nil 153 | } 154 | 155 | ret := []string{} 156 | for i := 0; i < sz; i++ { 157 | if !fs[i].IsDir() { 158 | ret = append(ret, fs[i].Name()) 159 | } 160 | } 161 | 162 | return ret, nil 163 | 164 | } 165 | -------------------------------------------------------------------------------- /systool/system.go: -------------------------------------------------------------------------------- 1 | package systool 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/ulricqin/goutils/convertor" 7 | "github.com/ulricqin/goutils/filetool" 8 | "math/rand" 9 | "net" 10 | "os" 11 | "os/exec" 12 | "strconv" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | func WritePidFile(pidFilePath string) error { 18 | if pidFilePath == "" { 19 | panic("parameter pidFilePath is blank") 20 | } 21 | 22 | _, err := filetool.WriteStringToFile(pidFilePath, fmt.Sprintf("%d", os.Getpid())) 23 | if err != nil { 24 | return err 25 | } 26 | 27 | return nil 28 | } 29 | 30 | func LocalIP() (string, error) { 31 | addr, err := net.ResolveUDPAddr("udp", "1.2.3.4:1") 32 | if err != nil { 33 | return "", err 34 | } 35 | 36 | conn, err := net.DialUDP("udp", nil, addr) 37 | if err != nil { 38 | return "", err 39 | } 40 | 41 | defer conn.Close() 42 | 43 | host, _, err := net.SplitHostPort(conn.LocalAddr().String()) 44 | if err != nil { 45 | return "", err 46 | } 47 | 48 | // host = "10.180.2.66" 49 | return host, nil 50 | } 51 | 52 | func LocalDnsName() (hostname string, err error) { 53 | var ip string 54 | ip, err = LocalIP() 55 | if err != nil { 56 | return 57 | } 58 | 59 | cmd := exec.Command("host", ip) 60 | var out bytes.Buffer 61 | cmd.Stdout = &out 62 | err = cmd.Run() 63 | if err != nil { 64 | return 65 | } 66 | 67 | tmp := out.String() 68 | arr := strings.Split(tmp, ".\n") 69 | 70 | if len(arr) > 1 { 71 | content := arr[0] 72 | arr = strings.Split(content, " ") 73 | return arr[len(arr)-1], nil 74 | } 75 | 76 | err = fmt.Errorf("parse host %s fail", ip) 77 | return 78 | } 79 | 80 | func GrabEphemeralPort() (port uint16, err error) { 81 | var listener net.Listener 82 | var portStr string 83 | var p int 84 | 85 | listener, err = net.Listen("tcp", ":0") 86 | if err != nil { 87 | return 88 | } 89 | defer listener.Close() 90 | 91 | _, portStr, err = net.SplitHostPort(listener.Addr().String()) 92 | if err != nil { 93 | return 94 | } 95 | 96 | p, err = strconv.Atoi(portStr) 97 | port = uint16(p) 98 | 99 | return 100 | } 101 | 102 | func URandom() string { 103 | f, _ := os.Open("/dev/urandom") 104 | b := make([]byte, 16) 105 | f.Read(b) 106 | f.Close() 107 | 108 | return fmt.Sprintf("%x", b) 109 | } 110 | 111 | func GenerateRandomSeed() int64 { 112 | return convertor.BytesToInt64([]byte(URandom())) 113 | } 114 | 115 | func SleepRandomDuration(t int) { 116 | r := rand.New(rand.NewSource(GenerateRandomSeed())) 117 | d := time.Duration(r.Intn(t)) * time.Millisecond 118 | time.Sleep(d) 119 | } 120 | 121 | func IntranetIP() (ips []string, err error) { 122 | ips = make([]string, 0) 123 | 124 | ifaces, e := net.Interfaces() 125 | if e != nil { 126 | return ips, e 127 | } 128 | 129 | for _, iface := range ifaces { 130 | if iface.Flags&net.FlagUp == 0 { 131 | continue // interface down 132 | } 133 | 134 | if iface.Flags&net.FlagLoopback != 0 { 135 | continue // loopback interface 136 | } 137 | 138 | if strings.HasPrefix(iface.Name, "docker") || strings.HasPrefix(iface.Name, "w-") { 139 | continue 140 | } 141 | 142 | addrs, e := iface.Addrs() 143 | if e != nil { 144 | return ips, e 145 | } 146 | 147 | for _, addr := range addrs { 148 | var ip net.IP 149 | switch v := addr.(type) { 150 | case *net.IPNet: 151 | ip = v.IP 152 | case *net.IPAddr: 153 | ip = v.IP 154 | } 155 | 156 | if ip == nil || ip.IsLoopback() { 157 | continue 158 | } 159 | 160 | ip = ip.To4() 161 | if ip == nil { 162 | continue // not an ipv4 address 163 | } 164 | 165 | ipStr := ip.String() 166 | if is_intranet(ipStr) { 167 | ips = append(ips, ipStr) 168 | } 169 | } 170 | } 171 | 172 | return ips, nil 173 | } 174 | 175 | func is_intranet(ipStr string) bool { 176 | if strings.HasPrefix(ipStr, "10.") || strings.HasPrefix(ipStr, "192.168.") { 177 | return true 178 | } 179 | 180 | if strings.HasPrefix(ipStr, "172.") { 181 | // 172.16.0.0-172.31.255.255 182 | arr := strings.Split(ipStr, ".") 183 | if len(arr) != 4 { 184 | return false 185 | } 186 | 187 | second, err := strconv.ParseInt(arr[1], 10, 64) 188 | if err != nil { 189 | return false 190 | } 191 | 192 | if second >= 16 && second <= 31 { 193 | return true 194 | } 195 | } 196 | 197 | return false 198 | } 199 | --------------------------------------------------------------------------------