forked from x/ContextOS
676 lines
14 KiB
Go
676 lines
14 KiB
Go
package kit
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"io/ioutil"
|
|
"math/rand"
|
|
"os"
|
|
"path"
|
|
"time"
|
|
)
|
|
|
|
func Errorf(str string, args ...interface{}) {
|
|
if len(args) == 0 {
|
|
fmt.Fprintf(os.Stderr, "%s\n", str)
|
|
return
|
|
}
|
|
fmt.Fprintf(os.Stderr, str, args...)
|
|
}
|
|
func Log(action string, str string, args ...interface{}) {
|
|
if len(args) == 0 {
|
|
fmt.Fprintf(os.Stderr, "%s", str)
|
|
} else {
|
|
fmt.Fprintf(os.Stderr, str, args...)
|
|
}
|
|
fmt.Fprintln(os.Stderr)
|
|
}
|
|
|
|
func Width(str string, mul int) int {
|
|
return len([]rune(str)) + (len(str)-len([]rune(str)))/2/mul
|
|
}
|
|
func Int(arg ...interface{}) int {
|
|
result := 0
|
|
for _, v := range arg {
|
|
switch val := v.(type) {
|
|
case int:
|
|
result += val
|
|
case int8:
|
|
result += int(val)
|
|
case int16:
|
|
result += int(val)
|
|
// case int32:
|
|
// result += int(val)
|
|
case int64:
|
|
result += int(val)
|
|
// case uint8:
|
|
// result += int(val)
|
|
case uint16:
|
|
result += int(val)
|
|
case uint32:
|
|
result += int(val)
|
|
case uint64:
|
|
result += int(val)
|
|
case float64:
|
|
result += int(val)
|
|
case byte: // uint8
|
|
result += int(val)
|
|
case rune: // int32
|
|
result += int(val)
|
|
case string:
|
|
if i, e := strconv.Atoi(val); e == nil {
|
|
result += i
|
|
}
|
|
case bool:
|
|
if val {
|
|
result += 1
|
|
}
|
|
case time.Time:
|
|
result += int(val.Unix())
|
|
case []string:
|
|
result += len(val)
|
|
case map[string]string:
|
|
result += len(val)
|
|
case []interface{}:
|
|
result += len(val)
|
|
case map[string]interface{}:
|
|
result += len(val)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
func Right(arg ...interface{}) bool {
|
|
result := false
|
|
for _, v := range arg {
|
|
switch val := v.(type) {
|
|
case int:
|
|
result = result || val != 0
|
|
case bool:
|
|
result = result || val
|
|
case string:
|
|
switch val {
|
|
case "", "0", "false", "off", "no", "error: ":
|
|
result = result || false
|
|
default:
|
|
result = result || true
|
|
}
|
|
case error:
|
|
result = result || false
|
|
case []string:
|
|
result = result || len(val) > 0
|
|
case map[string]string:
|
|
result = result || len(val) > 0
|
|
case []interface{}:
|
|
result = result || len(val) > 0
|
|
case map[string]interface{}:
|
|
result = result || len(val) > 0
|
|
default:
|
|
result = result || val != nil
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
func Format(arg ...interface{}) string {
|
|
result := []string{}
|
|
for _, v := range arg {
|
|
switch val := v.(type) {
|
|
case nil:
|
|
result = result[:0]
|
|
case int, int8, int16, int32, int64:
|
|
result = append(result, fmt.Sprintf("%d", val))
|
|
case uint, uint8, uint16, uint32, uint64:
|
|
result = append(result, fmt.Sprintf("%d", val))
|
|
case float64:
|
|
result = append(result, fmt.Sprintf("%d", int(val)))
|
|
case bool:
|
|
result = append(result, fmt.Sprintf("%t", val))
|
|
case string:
|
|
result = append(result, val)
|
|
case []rune:
|
|
result = append(result, string(val))
|
|
case []string:
|
|
result = append(result, val...)
|
|
case time.Time:
|
|
result = append(result, fmt.Sprintf("%s", val.Format("2006-01-02 15:03:04")))
|
|
case *os.File:
|
|
if s, e := val.Stat(); e == nil {
|
|
result = append(result, fmt.Sprintf("%T [name: %s]", v, s.Name()))
|
|
} else {
|
|
result = append(result, fmt.Sprintf("%T", v))
|
|
}
|
|
// case error:
|
|
// result = append(result, fmt.Sprintf("%v", val))
|
|
default:
|
|
if b, e := json.Marshal(val); e == nil {
|
|
result = append(result, string(b))
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(result) > 1 {
|
|
args := []interface{}{}
|
|
if n := strings.Count(result[0], "%") - strings.Count(result[0], "%%"); len(result) > n {
|
|
for i := 1; i < n+1; i++ {
|
|
args = append(args, result[i])
|
|
}
|
|
return fmt.Sprintf(result[0], args...) + strings.Join(result[n+1:], "")
|
|
} else if len(result) == n+1 {
|
|
for i := 1; i < len(result); i++ {
|
|
args = append(args, result[i])
|
|
}
|
|
return fmt.Sprintf(result[0], args...)
|
|
}
|
|
}
|
|
return strings.Join(result, "")
|
|
}
|
|
func Simple(str string) string {
|
|
return strings.Replace(strings.TrimSpace(str), "\n", "\\n", -1)
|
|
}
|
|
func Formats(arg ...interface{}) string {
|
|
result := []string{}
|
|
for _, v := range arg {
|
|
switch val := v.(type) {
|
|
// case []interface{}:
|
|
// for _, v := range val {
|
|
// result = append(result, Format(v))
|
|
// }
|
|
default:
|
|
if b, e := json.MarshalIndent(val, "", " "); e == nil {
|
|
result = append(result, string(b))
|
|
} else {
|
|
result = append(result, fmt.Sprintf("%#v", val))
|
|
}
|
|
}
|
|
}
|
|
return strings.Join(result, " ")
|
|
}
|
|
func Trans(arg ...interface{}) []string {
|
|
ls := []string{}
|
|
for _, v := range arg {
|
|
switch val := v.(type) {
|
|
// case *Message:
|
|
// if val.Hand {
|
|
// ls = append(ls, val.Meta["result"]...)
|
|
// } else {
|
|
// ls = append(ls, val.Meta["detail"]...)
|
|
// }
|
|
case nil:
|
|
case []float64:
|
|
for _, v := range val {
|
|
ls = append(ls, fmt.Sprintf("%d", int(v)))
|
|
}
|
|
case []int:
|
|
for _, v := range val {
|
|
ls = append(ls, fmt.Sprintf("%d", v))
|
|
}
|
|
case []bool:
|
|
for _, v := range val {
|
|
ls = append(ls, fmt.Sprintf("%t", v))
|
|
}
|
|
case []string:
|
|
ls = append(ls, val...)
|
|
case map[string]string:
|
|
for k, v := range val {
|
|
ls = append(ls, k, v)
|
|
}
|
|
case map[string]interface{}:
|
|
for k, v := range val {
|
|
ls = append(ls, k, Format(v))
|
|
}
|
|
case []interface{}:
|
|
for _, v := range val {
|
|
ls = append(ls, Format(v))
|
|
}
|
|
default:
|
|
ls = append(ls, Format(val))
|
|
}
|
|
}
|
|
return ls
|
|
}
|
|
func Struct(arg ...interface{}) map[string]interface{} {
|
|
value := map[string]interface{}{}
|
|
if len(arg) == 0 {
|
|
return value
|
|
}
|
|
switch val := arg[0].(type) {
|
|
case map[string]interface{}:
|
|
return val
|
|
}
|
|
|
|
return value
|
|
}
|
|
func Structm(args ...interface{}) map[string]interface{} {
|
|
value := Struct(args...)
|
|
for _, arg := range args {
|
|
switch val := arg.(type) {
|
|
case func(k string, v string):
|
|
for k, v := range value {
|
|
val(k, Format(v))
|
|
}
|
|
}
|
|
}
|
|
return value
|
|
}
|
|
func Array(list []string, index int, arg ...interface{}) []string {
|
|
if len(arg) == 0 {
|
|
if -1 < index && index < len(list) {
|
|
return []string{list[index]}
|
|
}
|
|
return []string{""}
|
|
}
|
|
|
|
str := Trans(arg...)
|
|
|
|
index = (index+2)%(len(list)+2) - 2
|
|
if index == -1 {
|
|
list = append(str, list...)
|
|
} else if index == -2 {
|
|
list = append(list, str...)
|
|
} else {
|
|
if index < -2 {
|
|
index += len(list) + 2
|
|
}
|
|
if index < 0 {
|
|
index = 0
|
|
}
|
|
|
|
for i := len(list); i < index+len(str); i++ {
|
|
list = append(list, "")
|
|
}
|
|
for i := 0; i < len(str); i++ {
|
|
list[index+i] = str[i]
|
|
}
|
|
}
|
|
|
|
return list
|
|
}
|
|
func Slice(arg []string, args ...interface{}) ([]string, string) {
|
|
if len(arg) == 0 {
|
|
return arg, ""
|
|
}
|
|
if len(args) == 0 {
|
|
return arg[1:], arg[0]
|
|
}
|
|
|
|
result := ""
|
|
switch v := args[0].(type) {
|
|
case int:
|
|
case string:
|
|
if arg[0] == v && len(arg) > 1 {
|
|
return arg[2:], arg[1]
|
|
}
|
|
if len(args) > 1 {
|
|
return arg, Format(args[1])
|
|
}
|
|
}
|
|
|
|
return arg, result
|
|
}
|
|
func Elect(last interface{}, args ...interface{}) string {
|
|
if len(args) > 0 {
|
|
switch arg := args[0].(type) {
|
|
case []string:
|
|
index := 0
|
|
if len(args) > 1 {
|
|
switch a := args[1].(type) {
|
|
case string:
|
|
i, e := strconv.Atoi(a)
|
|
if e == nil {
|
|
index = i
|
|
}
|
|
case int:
|
|
index = a
|
|
}
|
|
}
|
|
|
|
if 0 <= index && index < len(arg) && arg[index] != "" {
|
|
return arg[index]
|
|
}
|
|
case string:
|
|
if arg != "" {
|
|
return arg
|
|
}
|
|
}
|
|
}
|
|
|
|
switch l := last.(type) {
|
|
case string:
|
|
return l
|
|
}
|
|
return ""
|
|
}
|
|
func Select(value string, args ...interface{}) string {
|
|
if len(args) == 0 {
|
|
return value
|
|
}
|
|
|
|
switch arg := args[0].(type) {
|
|
case string:
|
|
if len(args) > 1 {
|
|
switch b := args[1].(type) {
|
|
case bool:
|
|
if b && arg != "" {
|
|
return arg
|
|
}
|
|
return value
|
|
}
|
|
}
|
|
if arg != "" {
|
|
return arg
|
|
}
|
|
case []interface{}:
|
|
index := 0
|
|
if len(args) > 1 {
|
|
index = Int(args[1])
|
|
}
|
|
if index < len(arg) && Format(arg[index]) != "" {
|
|
return Format(arg[index])
|
|
}
|
|
case []string:
|
|
index := 0
|
|
if len(args) > 1 {
|
|
index = Int(args[1])
|
|
}
|
|
if index < len(arg) && arg[index] != "" {
|
|
return arg[index]
|
|
}
|
|
default:
|
|
if v := Format(args...); v != "" {
|
|
return v
|
|
}
|
|
}
|
|
return value
|
|
}
|
|
func Chain(root interface{}, args ...interface{}) interface{} {
|
|
for i := 0; i < len(args); i += 2 {
|
|
if arg, ok := args[i].(map[string]interface{}); ok {
|
|
argn := []interface{}{}
|
|
for k, v := range arg {
|
|
argn = append(argn, k, v)
|
|
}
|
|
argn = append(argn, args[i+1:])
|
|
args, i = argn, -2
|
|
continue
|
|
}
|
|
|
|
var parent interface{}
|
|
parent_key, parent_index := "", 0
|
|
|
|
keys := []string{}
|
|
for _, v := range Trans(args[i]) {
|
|
keys = append(keys, strings.Split(v, ".")...)
|
|
}
|
|
|
|
data := root
|
|
for j, key := range keys {
|
|
index, e := strconv.Atoi(key)
|
|
|
|
// Log("error", "chain [%v %v] [%v %v] [%v/%v %v/%v] %v", parent_key, parent_index, key, index, i, len(args), j, len(keys), data)
|
|
|
|
var next interface{}
|
|
switch value := data.(type) {
|
|
case nil:
|
|
if i == len(args)-1 {
|
|
return nil
|
|
}
|
|
if j == len(keys)-1 {
|
|
next = args[i+1]
|
|
}
|
|
|
|
if e == nil {
|
|
data, index = []interface{}{next}, 0
|
|
} else {
|
|
data = map[string]interface{}{key: next}
|
|
}
|
|
case []string:
|
|
index = (index+2+len(value)+2)%(len(value)+2) - 2
|
|
|
|
if j == len(keys)-1 {
|
|
if i == len(args)-1 {
|
|
if index < 0 {
|
|
return ""
|
|
}
|
|
return value[index]
|
|
}
|
|
next = args[i+1]
|
|
}
|
|
|
|
if index == -1 {
|
|
data, index = append([]string{Format(next)}, value...), 0
|
|
} else {
|
|
data, index = append(value, Format(next)), len(value)
|
|
}
|
|
next = value[index]
|
|
case map[string]string:
|
|
if j == len(keys)-1 {
|
|
if i == len(args)-1 {
|
|
return value[key] // 读取数据
|
|
}
|
|
value[key] = Format(next) // 修改数据
|
|
}
|
|
next = value[key]
|
|
case map[string]interface{}:
|
|
if j == len(keys)-1 {
|
|
if i == len(args)-1 {
|
|
return value[key] // 读取数据
|
|
}
|
|
value[key] = args[i+1] // 修改数据
|
|
if !Right(args[i+1]) {
|
|
delete(value, key)
|
|
}
|
|
}
|
|
next = value[key]
|
|
case []interface{}:
|
|
index = (index+2+len(value)+2)%(len(value)+2) - 2
|
|
|
|
if j == len(keys)-1 {
|
|
if i == len(args)-1 {
|
|
if index < 0 {
|
|
return nil
|
|
}
|
|
return value[index] // 读取数据
|
|
}
|
|
next = args[i+1] // 修改数据
|
|
}
|
|
|
|
if index == -1 {
|
|
value, index = append([]interface{}{next}, value...), 0
|
|
} else if index == -2 {
|
|
value, index = append(value, next), len(value)
|
|
} else if j == len(keys)-1 {
|
|
value[index] = next
|
|
}
|
|
data, next = value, value[index]
|
|
}
|
|
|
|
switch p := parent.(type) {
|
|
case map[string]interface{}:
|
|
p[parent_key] = data
|
|
case []interface{}:
|
|
p[parent_index] = data
|
|
case nil:
|
|
root = data
|
|
}
|
|
|
|
parent, data = data, next
|
|
parent_key, parent_index = key, index
|
|
}
|
|
}
|
|
|
|
return root
|
|
}
|
|
func Chains(root interface{}, args ...interface{}) string {
|
|
return Format(Chain(root, args...))
|
|
}
|
|
|
|
func View(args []string, conf map[string]interface{}) []string {
|
|
if len(args) == 0 {
|
|
args = append(args, "default")
|
|
}
|
|
|
|
keys := []string{}
|
|
for _, k := range args {
|
|
if v, ok := conf[k]; ok {
|
|
keys = append(keys, Trans(v)...)
|
|
} else {
|
|
keys = append(keys, k)
|
|
}
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func Link(name string, url string) string {
|
|
return fmt.Sprintf("<a href=\"%s\" target=\"_blank\">%s</a>", url, name)
|
|
}
|
|
func Time(arg ...string) int {
|
|
if len(arg) == 0 {
|
|
return Int(time.Now())
|
|
}
|
|
|
|
if len(arg) > 1 {
|
|
if t, e := time.ParseInLocation(arg[1], arg[0], time.Local); e == nil {
|
|
return Int(t)
|
|
}
|
|
}
|
|
|
|
for _, v := range []string{
|
|
"2006-01-02 15:04:05",
|
|
"2006-01-02 15:04",
|
|
"2006-01-02",
|
|
"2006/01/02",
|
|
"01-02 15:04",
|
|
} {
|
|
if t, e := time.ParseInLocation(v, arg[0], time.Local); e == nil {
|
|
return Int(t)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
func Duration(arg ...string) time.Duration {
|
|
d, _ := time.ParseDuration(arg[0])
|
|
return d
|
|
}
|
|
func FileName(name string, meta ...string) string {
|
|
result, app := strings.Split(name, "."), ""
|
|
if len(result) > 1 {
|
|
app, result = result[len(result)-1], result[:len(result)-1]
|
|
}
|
|
|
|
for _, v := range meta {
|
|
switch v {
|
|
case "year":
|
|
result = append(result, "_", time.Now().Format("2006"))
|
|
case "date":
|
|
result = append(result, "_", time.Now().Format("0102"))
|
|
case "time":
|
|
result = append(result, "_", time.Now().Format("2006_0102_1504"))
|
|
case "rand":
|
|
result = append(result, "_", Format(rand.Int()))
|
|
case "uniq":
|
|
result = append(result, "_", Format(Time()))
|
|
result = append(result, "_", Format(rand.Int()))
|
|
}
|
|
}
|
|
|
|
if app != "" {
|
|
result = append(result, ".", app)
|
|
}
|
|
return strings.Join(result, "")
|
|
}
|
|
func FmtSize(size uint64) string {
|
|
if size > 1<<30 {
|
|
return fmt.Sprintf("%d.%dG", size>>30, (size>>20)%1024*100/1024)
|
|
}
|
|
|
|
if size > 1<<20 {
|
|
return fmt.Sprintf("%d.%dM", size>>20, (size>>10)%1024*100/1024)
|
|
}
|
|
|
|
if size > 1<<10 {
|
|
return fmt.Sprintf("%d.%dK", size>>10, size%1024*100/1024)
|
|
}
|
|
|
|
return fmt.Sprintf("%dB", size)
|
|
}
|
|
func FmtNano(nano int64) string {
|
|
if nano > 1000000000 {
|
|
return fmt.Sprintf("%d.%ds", nano/1000000000, nano/100000000%100)
|
|
}
|
|
|
|
if nano > 1000000 {
|
|
return fmt.Sprintf("%d.%dms", nano/100000, nano/100000%100)
|
|
}
|
|
|
|
if nano > 1000 {
|
|
return fmt.Sprintf("%d.%dus", nano/1000, nano/100%100)
|
|
}
|
|
|
|
return fmt.Sprintf("%dns", nano)
|
|
}
|
|
|
|
func Hash(arg ...interface{}) (string, []string) {
|
|
args := []string{}
|
|
for _, v := range Trans(arg...) {
|
|
switch v {
|
|
case "time":
|
|
args = append(args, Format(time.Now()))
|
|
case "rand":
|
|
args = append(args, Format(rand.Int()))
|
|
case "uniq":
|
|
args = append(args, Format(time.Now()))
|
|
args = append(args, Format(rand.Int()))
|
|
default:
|
|
if s, e := os.Stat(v); e == nil && !s.IsDir() {
|
|
if f, e := os.Open(v); e == nil {
|
|
defer f.Close()
|
|
m := md5.New()
|
|
io.Copy(m, f)
|
|
h := m.Sum(nil)
|
|
args = append(args, hex.EncodeToString(h[:]))
|
|
break
|
|
}
|
|
}
|
|
args = append(args, v)
|
|
}
|
|
}
|
|
|
|
h := md5.Sum([]byte(strings.Join(args, "")))
|
|
return hex.EncodeToString(h[:]), args
|
|
}
|
|
func Hashs(arg ...interface{}) string {
|
|
h, _ := Hash(arg...)
|
|
return h
|
|
}
|
|
|
|
func Block(root interface{}, args ...interface{}) interface{} {
|
|
|
|
return root
|
|
}
|
|
|
|
func Check(e error) bool {
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
return true
|
|
}
|
|
func DirWalk(file string, hand func(file string)) {
|
|
s, e := os.Stat(file)
|
|
Check(e)
|
|
hand(file)
|
|
|
|
if s.IsDir() {
|
|
fs, e := ioutil.ReadDir(file)
|
|
Check(e)
|
|
|
|
for _, v := range fs {
|
|
DirWalk(path.Join(file, v.Name()), hand)
|
|
}
|
|
}
|
|
}
|