// Package ansi can print colored and styled text to your terminal. package ansi import ( "fmt" "log" ) // Col defines supported colors type Col int // defines supported colors const ( Black = Col(iota) Red Green Yellow Blue Magenta Cyan White ) // defines text styling options const ( TReset = Col(iota) TBold TFaint TItalic TUnderline TBlinkSlow TBlinkFast TNegative TConceal TCrossedOut ) // Foreground text colors const ( FgBlack = Col(iota + 30) FgRed FgGreen FgYellow FgBlue FgMagenta FgCyan FgWhite ) // Background text colors const ( BgBlack = Col(iota + 40) BgRed BgGreen BgYellow BgBlue BgMagenta BgCyan BgWhite ) // Set sets styling options on strings and stringable interfaces func Set(str interface{}, Attribute ...Col) string { var rstr = fmt.Sprint(str) for _, attr := range Attribute { rstr = fmt.Sprintf("\033[%vm%v\033[0m", attr, rstr) } return rstr } // Color adds the color code of col as text color to str and returns as string func Color(str interface{}, col Col) string { return fmt.Sprintf("\033[3%vm%v\033[0m", col, str) } // BgColor adds the color code of col as background color to str and returns as string func BgColor(str interface{}, col Col) string { return fmt.Sprintf("\033[4%vm%v\033[0m", col, str) } // Bold surrounds str with the code for bold styled text func Bold(str interface{}) string { return fmt.Sprintf("\033[1m%v\033[0m", str) } // Underline surrounds str with the code for underlined text func Underline(str interface{}) string { return fmt.Sprintf("\033[4m%v\033[0m", str) } // Log prints red text via log package func Log(valuea ...interface{}) interface{} { if valuea[1] != nil { log.Println(Color(valuea[1], Red)) } return valuea[0] }
// the arg package simplifies cli flags (arguments) package arg import ( "bufio" "flag" "fmt" "os" "time" ) type argument struct { name string defaultValue string flagValue *string usage string timeout time.Duration argNr int } var flagVar = make(map[string]argument) var values = make(map[string]interface{}) var i = 1 func String(name, defaultValue, usage string, timeout time.Duration) { flagVar[name] = argument{ name: name, defaultValue: defaultValue, flagValue: flag.String(name, "", usage), usage: usage, timeout: timeout, argNr: -1, } } func StringArg(name, defaultValue, usage string, timeout time.Duration) { flagVar[name] = argument{ name: name, defaultValue: defaultValue, flagValue: flag.String(name, "", usage), usage: usage, timeout: timeout, argNr: i, } i++ } func Parse() { var value interface{} flag.Parse() for v := range flagVar { if *flagVar[v].flagValue != "" { value = *flagVar[v].flagValue } else if !(flagVar[v].argNr >= 1 && flagVar[v].argNr < len(os.Args)) && flagVar[v].timeout >= time.Second*1 { fmt.Printf("# %v: ", flagVar[v].usage) scanner := bufio.NewScanner(os.Stdin) ch := make(chan bool, 1) go func() { defer func() { close(ch) }() ch <- scanner.Scan() }() select { case <-ch: value = scanner.Text() case <-time.After(flagVar[v].timeout): value = flagVar[v].defaultValue } } else if flagVar[v].argNr >= 1 && flagVar[v].argNr < len(os.Args) { value = os.Args[flagVar[v].argNr] } else { value = flagVar[v].defaultValue } values[v] = value } } func Get(name string) interface{} { return values[name] } func Dump() string { return fmt.Sprintf("%v\n", flagVar) }
// Package as helps by converting various data types to various other types package as import ( "fmt" "regexp" "strconv" "strings" "time" ) type ree struct { typ string re string } type Dynamic struct { Type string Data interface{} } // regex (regular expression) in a slice of ree struct var regex = [...]ree{ { typ: "bool", re: "(0|1|true|false)", }, { typ: "int", re: "\\d+", }, { typ: "int", re: "\\d+[\\^eE]\\d+", }, { typ: "float", re: "[-+]?[0-9]*[\\.,]?[0-9]+([eE][-+]?[0-9]+)?", }, { typ: "price", re: "((€|\\$|¢|£|EURO?|DM|USD) ?)?[-+]?[0-9]*[\\.,]?[0-9]+([eE][-+]?[0-9]+)?( ?(€|\\$|¢|£|EURO?|DM|USD))?", }, { typ: "url", re: "(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?", }, { typ: "ipv4", re: "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])", }, { typ: "ipv6", re: "([0-9A-Fa-f]{1,4}:([0-9A-Fa-f]{1,4}:([0-9A-Fa-f]{1,4}:([0-9A-Fa-f]{1,4}:([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{0,4}|:[0-9A-Fa-f]{1,4})?|(:[0-9A-Fa-f]{1,4}){0,2})|(:[0-9A-Fa-f]{1,4}){0,3})|(:[0-9A-Fa-f]{1,4}){0,4})|:(:[0-9A-Fa-f]{1,4}){0,5})((:[0-9A-Fa-f]{1,4}){2}|:(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])(\\.(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])){3})|(([0-9A-Fa-f]{1,4}:){1,6}|:):[0-9A-Fa-f]{0,4}|([0-9A-Fa-f]{1,4}:){7}:", }, { typ: "mac", re: "([0-9a-f]{1,2}:){5}([0-9a-f]{1,2})", }, { typ: "email", re: "[a-z0-9\\._%\\+\\-]+\\@[a-z0-9\\.\\-]+\\.[a-z]{2,9}", }, { typ: "creditcard", re: "(?:4\\d{12}(?:\\d{3})?|5[1-5]\\d{14}|3[47]\\d{13}|3(?:0[0-5]|[68]\\d)\\d{11}|6(?:011|5\\d{2})\\d{12}|(?:2131|1800|35\\d{3})\\d{11})", }, { typ: "color", re: "#[a-f0-9]{2,6}", }, { typ: "color", re: "(rgb|hsl|yuv)\\( *[\\d\\.%]+ *, *[\\d\\.%]+ *, *[\\d\\.%]+ *\\)", }, { typ: "color", re: "(rgba|cmyk)\\( *\\d+ *, *\\d+ *, *\\d+ *, *\\d+ *\\)", }, { typ: "isbn", re: "(1(?:(0)|3))?:?[- ]?(\\s)*[0-9]+[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9]*[- ]*[xX0-9]", }, { typ: "date", re: "(?i:([MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))", }, { typ: "alpha", re: "[a-zA-Z]+", }, { typ: "alphanumeric", re: "[a-zA-Z0-9]+", }, { typ: "base64", re: "(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})", }, { typ: "string", re: "[[:print:]]+", }, { typ: "ascii", re: "[[:ascii:]]+", }, } // timeformats contains the supported time formats // for the conversion to time.Time. var timeformats = []string{ time.ANSIC, time.UnixDate, time.RubyDate, time.RFC822, time.RFC822Z, time.RFC850, time.RFC1123, time.RFC1123Z, time.RFC3339, time.RFC3339Nano, time.Kitchen, time.Stamp, time.StampMilli, time.StampMicro, time.StampNano, "Mon, 2 Jan 2006 15:04:05 -0700", "02.01.06", "01/02/06", "2006-01-02", "2006/01/02", "01/02/2006", "02.01.2006", "01/02/06 15:04", "2006-01-02 15:04", "2006-01-02T15:04", "01/02/2006 15:04", "02.01.06 15:04:05", "01/02/06 15:04:05", "01/02/2006 15:04:05", "2006-01-02 15:04:05", "2006-01-02T15:04:05", "02.01.2006 15:04:05", "2006-01-02 15:04:05 -0700 MST", } // Bool returns a boolean value. // It mainly depends on the output of strconv.ParseBool, // but also checks for integer values. func Bool(valuea ...interface{}) bool { value := valuea[0] if Int(value) > 0 { return true } b, _ := strconv.ParseBool(String(value)) return b } // Bytes returns a slice of bytes. func Bytes(valuea ...interface{}) []byte { value := valuea[0] if value == nil { return []byte{} } switch val := value.(type) { case bool: if val == true { return []byte("true") } return []byte("false") case string: return []byte(val) case []byte: return val default: return []byte(fmt.Sprintf("%v", value)) } } // Duration converts input values to time.Duration. // It mainly depends on time.ParseDuration. func Duration(valuea ...interface{}) time.Duration { value := valuea[0] switch value.(type) { case int, int8, int16, int32, int64: return time.Duration(Int(value)) case uint, uint8, uint16, uint32, uint64: return time.Duration(Int(value)) case float32, float64: return time.Duration(Int(value)) default: dur, _ := time.ParseDuration(String(value)) return dur } } // FixedLengthAfter appends spacer chars after a string func FixedLengthAfter(str string, spacer string, length int) string { spacer = spacer[:1] l := length - len(str) if l > 0 { return str + strings.Repeat(spacer, l) } if l == 0 { return str } return str[:length] } // FixedLengthBefore prepends spacer chars before a string func FixedLengthBefore(str string, spacer string, length int) string { spacer = spacer[:1] l := length - len(str) if l > 0 { return strings.Repeat(spacer, l) + str } if l == 0 { return str } return str[:length] } // FixedLengthCenter adds spacer chars after and before a string func FixedLengthCenter(str string, spacer string, length int) string { spacer = spacer[:1] l := length - len(str) if l > 0 { if l%2 == 0 { l = l / 2 return strings.Repeat(spacer, l) + str + strings.Repeat(spacer, l) } l = (l + 1) / 2 return strings.Repeat(spacer, l) + str + strings.Repeat(spacer, l-1) } if l == 0 { return str } return str[:length] } // Float converts it's input to type float64. // int, uint and float gets converted as expected, // time is transformed to a float of the corresponding timestamp. // strings and byte slices gets converted via strconv.ParseFloat. func Float(valuea ...interface{}) float64 { value := valuea[0] switch val := value.(type) { case int: return float64(val) case int8: return float64(val) case int16: return float64(val) case int32: return float64(val) case int64: return float64(val) case uint: return float64(val) case uint8: return float64(val) case uint16: return float64(val) case uint32: return float64(val) case uint64: return float64(val) case float32: return float64(val) case float64: return float64(val) case time.Time: return float64(val.Unix()) case bool: if val == true { return float64(1) } return float64(0) default: f, _ := strconv.ParseFloat(String(value), 64) return float64(f) } } // FloatFromXString converts strings to float64. // Most values can be converted to float via Float(), // but floats as strings in e.g. german spelling // should be converted with this function. func FloatFromXString(valuea ...string) float64 { value := valuea[0] value = strings.Trim(value, "\t\n\r¢§$€ ") var float float64 c := strings.Count(value, ",") p := strings.Count(value, ".") fc := strings.Index(value, ",") fp := strings.Index(value, ".") if c == 0 && p == 1 { float, _ = strconv.ParseFloat(value, 64) } else if c == 1 && p == 0 { value = strings.Replace(value, ",", ".", 1) float, _ = strconv.ParseFloat(value, 64) } else if c == 0 && p == 0 { intx, _ := strconv.ParseInt(value, 0, 64) float = float64(intx) } else if c > 1 && p < 2 { value = strings.Replace(value, ",", "", -1) float, _ = strconv.ParseFloat(value, 64) } else if c < 2 && p > 1 { value = strings.Replace(value, ".", "", -1) value = strings.Replace(value, ",", ".", 1) float, _ = strconv.ParseFloat(value, 64) } else if c == 1 && p == 1 { if fp < fc { value = strings.Replace(value, ".", "", -1) value = strings.Replace(value, ",", ".", 1) } else { value = strings.Replace(value, ",", "", -1) } float, _ = strconv.ParseFloat(value, 64) } else { value = "0" float, _ = strconv.ParseFloat(value, 64) } return float64(float) } // Int returns an int64 of the input value. // Float values and float values in strings will be rounded via // "round half towards positive infinity". // strings get converted via strconv.ParseFloat. func Int(valuea ...interface{}) int64 { value := valuea[0] switch val := value.(type) { case int: return int64(val) case int8: return int64(val) case int16: return int64(val) case int32: return int64(val) case int64: return int64(val) case uint: return int64(val) case uint8: return int64(val) case uint16: return int64(val) case uint32: return int64(val) case uint64: return int64(val) case float32: return int64(val + 0.5) case float64: return int64(val + 0.5) case time.Time: return int64(val.Unix()) case bool: if val == true { return int64(1) } return int64(0) default: i, _ := strconv.ParseFloat(String(value), 64) return int64(i + 0.5) } } // String converts input values to string. // Time and Duration gets converted via standard functions. // Most types gets "converted" via fmt.Sprintf. func String(valuea ...interface{}) string { value := valuea[0] if value == nil { return "" } switch val := value.(type) { case bool: if value.(bool) == true { return "true" } return "false" case time.Duration: return string(val.String()) case time.Time: return string(val.Format(time.RFC3339)) case string: return val case []byte: return string(val) default: return fmt.Sprintf("%v", val) } } // Time converts inputs values to time.Time. // Time formats in the variable timeformats can be used. func Time(valuea ...interface{}) time.Time { value := valuea[0] s := String(value) for _, format := range timeformats { r, err := time.Parse(format, s) if err == nil { return r } } return time.Time{} } // Trimmed takes the first given value, converts it to // a string, trims the whitespace an returns it. func Trimmed(valuea ...interface{}) string { value := valuea[0] return strings.TrimSpace(String(value)) } // Uint returns an uint64 of the input value. // Float values and float values in strings will be rounded via // "round half towards positive infinity". // strings get converted via strconv.ParseFloat. func Uint(valuea ...interface{}) uint64 { value := valuea[0] switch val := value.(type) { case int: return uint64(val) case int8: return uint64(val) case int16: return uint64(val) case int32: return uint64(val) case int64: return uint64(val) case uint: return uint64(val) case uint8: return uint64(val) case uint16: return uint64(val) case uint32: return uint64(val) case uint64: return uint64(val) case float32: return uint64(val + 0.5) case float64: return uint64(val + 0.5) case time.Time: return uint64(val.Unix()) case bool: if val == true { return uint64(1) } return uint64(0) default: i, _ := strconv.ParseFloat(String(value), 64) return uint64(i + 0.5) } } // Type returns a type (string) of a string. func Type(valuea ...interface{}) (string, error) { var err error str := strings.Trim(String(valuea[0]), " \t\n\r") if !Time(str).IsZero() { return "date", nil } for _, b := range regex { var match bool re := "(?i)^" + b.re + "$" if match, err = regexp.MatchString(re, str); match == true { //fmt.Printf("%v tested for %v with %v; result: %v\n", str, b.typ, b.re, match) return b.typ, nil } //fmt.Printf("%v tested for %v with %v; result: %v\n", str, b.typ, b.re, match) } return "", err } // DBType returns a Database Type of a string. func DBType(str string) string { t, err := Type(str) if err != nil { return "string" } switch t { case "bool", "int", "string", "float": return t default: return "string" } } // DBTypeMultiple returns the lowest common denominator of a type for all inserted DBTypes func DBTypeMultiple(val []string) string { var typeint int for _, typ := range val { for i, b := range regex { if b.typ == typ { if typeint < i { typeint = i } } } } return regex[typeint].typ }
package as import ( "strconv" ) type Int64 int64 // MarshalJSON implements json.Marshaler interface for the Int64 Type. func (i Int64) MarshalJSON() ([]byte, error) { return Bytes(i), nil } // UnmarshalJSON implements json.Unmarshaler inferface for the Int64 Type. func (i *Int64) UnmarshalJSON(buf []byte) error { var i64 Int64 str, err := strconv.Unquote(string(buf)) if err == nil { i64 = Int64(Int(str)) } else { i64 = Int64(Int(buf)) } *i = i64 return nil } // UnmarshalJSON implements json.Unmarshaler inferface for the Dynamic Type. func (d *Dynamic) UnmarshalJSON(buf []byte) error { var dyn Dynamic str, err := strconv.Unquote(string(buf)) if err != nil { str = string(buf) } dyn.Type, _ = Type(str) switch dyn.Type { case "date": dyn.Data = Time(str) default: dyn.Data = str } *d = dyn return nil }
package bitmask import "fmt" type Bitmask struct { value int } func New(init int) *Bitmask { return &Bitmask{value: init} } func (b *Bitmask) setBit(pos int) int { b.value |= (1 << pos) return b.value } func (b *Bitmask) clearBit(pos int) int { mask := ^(1 << pos) b.value &= mask return b.value } func (b *Bitmask) Set(pos int, val bool) int { if val == true { return b.setBit(pos) } return b.clearBit(pos) } func (b *Bitmask) hasBit(pos int) bool { return ((b.value & (1 << pos)) > 0) } func (b *Bitmask) Get(pos int) bool { return b.hasBit(pos) } func (b *Bitmask) Int() int { return b.value } func (b *Bitmask) String() string { return fmt.Sprintf("%b", b.value) } func (b *Bitmask) Byte() []byte { return []byte{byte(b.value)} }
// Package cache simplifies caching with GC package cache import ( "encoding/gob" "fmt" "io" "os" "os/signal" "sort" "sync" "syscall" "time" ) // Item as a single object with an interface as value and two time.Time values for creation and expiration dates type Item struct { Object interface{} Creation time.Time Expiration time.Time } func (item *Item) isExpired() bool { if item.Expiration.IsZero() { return false } return item.Expiration.Before(time.Now()) } // Cache is a storage for all Item items type Cache struct { Expiration time.Duration items map[string]*Item lock sync.RWMutex } // Export all items to a gob buffer func (cache *Cache) Export(w io.Writer) error { enc := gob.NewEncoder(w) cache.lock.RLock() defer cache.lock.RUnlock() X := make(map[string]interface{}) for k := range cache.items { X[k] = cache.items[k].Object } if err := enc.Encode(X); err != nil { return err } return nil } // Import all items from a gob buffer func (cache *Cache) Import(r io.Reader) error { dec := gob.NewDecoder(r) X := make(map[string]interface{}) if err := dec.Decode(&X); err != nil { return err } for k, v := range X { cache.Set(k, v) } return nil } // String returns all cached values as string (for debugging) func (cache *Cache) String() string { var str string var keys []string cache.lock.RLock() defer cache.lock.RUnlock() for k := range cache.items { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { str += k + "\t" + fmt.Sprintf("%v", cache.items[k].Object) + "\n" } return str } // Set creates an Item in the cache, if there is already an item with that name it get overwritten func (cache *Cache) Set(key string, value interface{}) { cache.lock.Lock() defer cache.lock.Unlock() cache.items[key] = &Item{ Object: value, Creation: time.Now(), Expiration: time.Now().Add(cache.Expiration), } } // SetWithDuration does the same as Set but with an specific expiration date func (cache *Cache) SetWithDuration(key string, value interface{}, creation time.Time, duration time.Duration) { cache.lock.Lock() defer cache.lock.Unlock() cache.items[key] = &Item{ Object: value, Creation: creation, Expiration: time.Now().Add(duration), } } // Time returns the creation date of a cached item func (cache *Cache) Time(key string) time.Time { return cache.items[key].Creation } // Get returns the value of a cached item or nil if expired func (cache *Cache) Get(key string) interface{} { cache.lock.RLock() defer cache.lock.RUnlock() item, ok := cache.items[key] if !ok || item.isExpired() { return nil } return item.Object } // Delete deletes a cached item func (cache *Cache) Delete(key string) { cache.lock.Lock() defer cache.lock.Unlock() delete(cache.items, key) } // Add creates an cached item func (cache *Cache) Add(key string, value interface{}) bool { item := cache.Get(key) if item != nil { return false } cache.Set(key, value) return true } // Update changes the value of an key. If the key doesn't exist, it returns false func (cache *Cache) Update(key string, value interface{}) bool { item := cache.Get(key) if item == nil { return false } cache.Set(key, value) return true } // DeleteExpired checks all cache items and deletes the expired items func (cache *Cache) DeleteExpired() { cache.lock.Lock() defer cache.lock.Unlock() for k, v := range cache.items { if v.isExpired() { delete(cache.items, k) } } } // DeleteExpiredWithFunc does the same like DeleteExpired // but also calls a function for each deleted item func (cache *Cache) DeleteExpiredWithFunc(fn func(key string, value interface{})) { cache.lock.Lock() defer cache.lock.Unlock() for k, v := range cache.items { if v.isExpired() { fn(k, cache.items[k].Object) delete(cache.items, k) } } } // DeleteAllWithFunc does the same like DeleteExpiredWithFunc // but not just for the expired items, also the non expired func (cache *Cache) DeleteAllWithFunc(fn func(key string, value interface{})) { cache.lock.Lock() defer cache.lock.Unlock() for k := range cache.items { fn(k, cache.items[k].Object) delete(cache.items, k) } } // Size returns the number of cached items // it does not check for expired items, so run DeleteExpired before func (cache *Cache) Size() int { n := len(cache.items) return n } // Clear removes all items in the cache func (cache *Cache) Clear() { cache.lock.Lock() defer cache.lock.Unlock() cache.items = map[string]*Item{} } func cleaner(cache *Cache, interval time.Duration) { ticker := time.Tick(interval) for { select { case <-ticker: cache.DeleteExpired() } } } func cleanerWithFunc(cache *Cache, interval time.Duration, fn func(key string, value interface{})) { defer cache.DeleteAllWithFunc(fn) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) ticker := time.Tick(interval) for { select { case <-ticker: cache.DeleteExpiredWithFunc(fn) case <-c: cache.DeleteAllWithFunc(fn) os.Exit(1) } } } // New creates a new Cache func New(expirationTime, cleanupInterval time.Duration) *Cache { items := make(map[string]*Item) if expirationTime == 0 { expirationTime = -1 } cache := &Cache{ Expiration: expirationTime, items: items, } go cleaner(cache, cleanupInterval) return cache } // New2 creates a new Cache with a cleaner function func New2(expirationTime, cleanupInterval time.Duration, fn func(key string, value interface{})) *Cache { items := make(map[string]*Item) if expirationTime == 0 { expirationTime = -1 } cache := &Cache{ Expiration: expirationTime, items: items, } go cleanerWithFunc(cache, cleanupInterval, fn) return cache }
// simplifies file access and adds a simple caching method package cachedfile import ( "fmt" "simonwaldherr.de/go/golibs/cache" "simonwaldherr.de/go/golibs/file" "time" ) var fileCache *cache.Cache var cacheInit bool func cacheWorker(filename string, value interface{}) { _, mtime, _, err := file.Time(filename) modify := mtime.UnixNano() if err == nil && modify < fileCache.Time(filename).UnixNano() { file.Write(filename, fmt.Sprint(value), false) } } func Init(expirationTime, cleanupInterval time.Duration) { if cacheInit == true { fileCache.DeleteAllWithFunc(cacheWorker) } cacheInit = true fileCache = cache.New2(expirationTime, cleanupInterval, cacheWorker) } func Read(filename string) (string, error) { if cacheInit == false { cacheInit = true fileCache = cache.New2(15*time.Minute, 1*time.Minute, cacheWorker) } var err error var data string filename, err = file.GetAbsolutePath(filename) if err != nil { return "", err } if xdata := fileCache.Get(filename); xdata == nil { if data, err = file.Read(filename); err != nil { return "", err } _, mtime, _, err := file.Time(filename) if err != nil { mtime = time.Now() } duration, _ := time.ParseDuration("2h30m") fileCache.SetWithDuration(filename, data, mtime, duration) } else { data = fmt.Sprint(xdata) } return data, nil } func Write(filename, str string, append bool) error { if cacheInit == false { cacheInit = true fileCache = cache.New2(15*time.Minute, 1*time.Minute, cacheWorker) } var err error var data string filename, err = file.GetAbsolutePath(filename) if err != nil { return err } if append { data, err = Read(filename) if err != nil { return err } fileCache.Set(filename, data+str) } else { fileCache.Set(filename, str) } return nil } func Size(filename string) (int64, error) { str, err := Read(filename) if err != nil { return -1, err } return int64(len(str)), nil } func Clean(filename string) error { return Write(filename, "", false) } func Stop() { if cacheInit == true { fileCache.DeleteAllWithFunc(cacheWorker) } } func Reset() { fileCache = cache.New2(15*time.Minute, 1*time.Minute, cacheWorker) cacheInit = false }
package channel type Communication struct { receiver map[chan interface{}]bool addReceiver chan chan interface{} rmReceiver chan chan interface{} messages chan interface{} } func Init() *Communication { var hub = &Communication{ receiver: make(map[chan interface{}]bool), addReceiver: make(chan (chan interface{})), rmReceiver: make(chan (chan interface{})), messages: make(chan interface{}, 31), } go func() { for { select { case s := <-hub.addReceiver: hub.receiver[s] = true case s := <-hub.rmReceiver: delete(hub.receiver, s) if len(hub.receiver) == 0 { return } case msg := <-hub.messages: for rec := range hub.receiver { go func(message interface{}, receiver chan interface{}) { receiver <- message }(msg, rec) } } } }() return hub } func (hub *Communication) AddReceiver() chan interface{} { messageChannel := make(chan interface{}) hub.addReceiver <- messageChannel return messageChannel } func (hub *Communication) CloseReceiver(ch chan interface{}) int { hub.rmReceiver <- ch return hub.CountReceiver() } func (hub *Communication) CountReceiver() int { return len(hub.receiver) } func (hub *Communication) AddTransmitter() chan<- interface{} { return hub.messages }
package csv import ( "bufio" "encoding/csv" "io" "os" "strings" ) // LoadCSVfromFile parses a CSV from a file and returns two maps // one map with the data and another one with the csv head func LoadCSVfromFile(filename string) (map[int][]string, map[string]int) { fp, _ := os.Open(filename) return loadCSV(bufio.NewReader(fp)) } // LoadCSVfromString parses a CSV from a string and returns two maps // one map with the data and another one with the csv head func LoadCSVfromString(csv string) (map[int][]string, map[string]int) { fp := strings.NewReader(csv) return loadCSV(fp) } func loadCSV(reader io.Reader) (map[int][]string, map[string]int) { var row int var head = map[int][]string{} var data = map[int][]string{} csvReader := csv.NewReader(reader) csvReader.Comma = ';' for { record, err := csvReader.Read() if err == io.EOF { break } if row == 0 { head[row] = record } else { data[row] = record } row++ } return data, GetHead(head) } // GetHead returns a map which represents the head of a csv map func GetHead(data map[int][]string) map[string]int { head := make(map[string]int, len(data[0])) for pos, name := range data[0] { head[name] = pos } return head }
// file wraps around the standard functions to simplify reading and writing on disk package file import ( "bufio" "bytes" "io" "io/ioutil" "os" "path/filepath" "runtime" "simonwaldherr.de/go/golibs/gopath" "strings" ) func contains(s []string, e string) bool { for _, a := range s { if a == e { return true } } return false } func Exists(fn string) bool { if _, err := os.Stat(fn); err == nil { return true } return false } func IsDir(fn string) bool { file, err := os.Stat(fn) if err != nil { return false } if file.IsDir() { return true } return false } func IsFile(fn string) bool { file, err := os.Stat(fn) if err != nil { return false } if file.Mode().IsRegular() { return true } return false } func isSymlink(fi os.FileInfo) bool { return fi.Mode()&os.ModeSymlink == os.ModeSymlink } func IsSymlink(fn string) bool { file, err := os.Lstat(fn) if err != nil { return false } return isSymlink(file) } func Read(fn string) (string, error) { var file *os.File var err error buf := bytes.NewBuffer(nil) file, err = os.Open(fn) if err != nil { return "", err } defer file.Close() if _, err = io.Copy(buf, file); err != nil { return "", err } s := string(buf.Bytes()) return s, nil } func ReadUntil(fn string, delim []string) (string, string, int, error) { file, err := os.Open(fn) defer file.Close() if err != nil { return "", "", 0, err } reader := bufio.NewReader(file) scanner := bufio.NewScanner(reader) scanner.Split(bufio.ScanRunes) pos := 0 buf := "" for scanner.Scan() { char := scanner.Text() if contains(delim, char) { return buf, char, pos, nil } buf += char pos++ } return buf, "", pos, nil } func ReadBlocks(fn string, delim []string, fnc func(string) (string, error)) (string, error) { file, err := os.Open(fn) defer file.Close() if err != nil { return "", err } reader := bufio.NewReader(file) scanner := bufio.NewScanner(reader) scanner.Split(bufio.ScanRunes) pos := 0 buf := "" ret := "" str := "" for scanner.Scan() { char := scanner.Text() if contains(delim, char) { str, err = fnc(buf) ret += str buf = "" } buf += char pos++ } return ret, nil } func Write(fn, str string, append bool) error { var file *os.File var err error if append { file, err = os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.FileMode(0666)) } else { file, err = os.OpenFile(fn, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(0666)) } if err != nil { return err } defer file.Close() if _, err = file.WriteString(str); err != nil { return err } if err = file.Sync(); err != nil { return err } return nil } func Size(fn string) (int64, error) { file, err := os.Open(fn) defer file.Close() if err != nil { return -1, err } fi, err := file.Stat() if err != nil { return -1, err } return fi.Size(), nil } func Clean(fn string) error { return Write(fn, "", false) } func Rename(from, to string) error { err := os.Rename(from, to) if err != nil { return err } return nil } func Copy(from, to string) error { r, err := os.Open(from) if err != nil { return err } defer r.Close() w, err := os.Create(to) if err != nil { return err } defer w.Close() _, err = io.Copy(w, r) if err != nil { return err } return nil } func Delete(fn string) error { err := os.Remove(fn) if err != nil { return err } return nil } func ReadDir(dn string) ([]string, error) { var flist []string dn, err := GetAbsolutePath(dn) if err != nil { return []string{""}, err } files, err := ioutil.ReadDir(dn) if err != nil { return []string{""}, err } for _, f := range files { flist = append(flist, f.Name()) } return flist, nil } func Each(dirname string, recursive bool, fnc func(string, string, string, bool, os.FileInfo)) error { file, err := os.Open(dirname) defer file.Close() if err != nil { return err } list, err := file.Readdir(-1) if err != nil { return err } for _, fi := range list { path, _ := filepath.Abs(dirname + string(os.PathSeparator) + fi.Name()) isDir := fi.IsDir() split := strings.Split(fi.Name(), ".") suffix := split[len(split)-1:][0] // if you want the real filetype, use http.DetectContentType fnc(fi.Name(), suffix, path, isDir, fi) if recursive && isDir { err = Each(path, recursive, fnc) if err != nil { return err } } } return nil } var HomeDir string func SetHomeDir() string { if HomeDir == "#" || runtime.GOOS == "windows" { home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") if home == "" { home = os.Getenv("USERPROFILE") } HomeDir = home return home } HomeDir = os.Getenv("HOME") return os.Getenv("HOME") } func FakeHomeDir(dir string) string { HomeDir = dir return dir } func GetHomeDir() string { if HomeDir == "" { return SetHomeDir() } return HomeDir } func switchSymlink(path []byte, start int, link, after string) []byte { if link[0] == os.PathSeparator { return []byte(filepath.Join(link, after)) } return []byte(filepath.Join(string(path[0:start]), link, after)) } func nextComponent(path []byte, start int) []byte { v := bytes.IndexByte(path[start:], os.PathSeparator) if v < 0 { return path } return path[0 : start+v] } // GetAbsolutePath returns the absolute path to a file or dir // if it is a relative path it is relative to the current working directory func GetAbsolutePath(fn string) (string, error) { pwd, err := os.Getwd() if err != nil { return "", err } return getAbsolutePathHelper(fn, pwd) } // GetAbsolutePathByApp returns the absolute path to a file or dir // if it is a relative path it is relative to the Go Application source or binary func GetAbsolutePathByApp(fn string) (string, error) { pwd := gopath.Dir() return getAbsolutePathHelper(fn, pwd) } func getAbsolutePathHelper(fn string, pwd string) (string, error) { if len(fn) == 0 { return "", os.ErrInvalid } if fn[0] != os.PathSeparator { if fn[0] == '.' { fn = filepath.Join(pwd, fn) } else { fn = strings.Replace(fn, "~", GetHomeDir(), 1) } } path := []byte(fn) nlinks := 0 start := 1 prev := 1 for start < len(path) { c := nextComponent(path, start) cur := c[start:] if len(cur) == 0 { copy(path[start:], path[start+1:]) path = path[0 : len(path)-1] } else if len(cur) == 1 && cur[0] == '.' { if start+2 < len(path) { copy(path[start:], path[start+2:]) } path = path[0 : len(path)-2] } else if len(cur) == 2 && cur[0] == '.' && cur[1] == '.' { copy(path[prev:], path[start+2:]) path = path[0 : len(path)+prev-(start+2)] prev = 1 start = 1 } else { fi, err := os.Lstat(string(c)) if err == nil { if isSymlink(fi) { nlinks++ if nlinks > 8 { return "", os.ErrInvalid } var link string link, err = os.Readlink(string(c)) after := string(path[len(c):]) path = switchSymlink(path, start, link, after) prev = 1 start = 1 } else { prev = start start = len(c) + 1 } } else { return string(path), nil } } } for len(path) > 1 && path[len(path)-1] == os.PathSeparator { path = path[0 : len(path)-1] } return string(path), nil }
package file import ( "os" "syscall" "time" ) func Time(fn string) (time.Time, time.Time, time.Time, error) { file, err := os.Stat(fn) if err != nil { return time.Time{}, time.Time{}, time.Time{}, err } mtime := file.ModTime() stat := file.Sys().(*syscall.Stat_t) atime := time.Unix(int64(stat.Atimespec.Sec), int64(stat.Atimespec.Nsec)) ctime := time.Unix(int64(stat.Ctimespec.Sec), int64(stat.Ctimespec.Nsec)) return atime, mtime, ctime, nil }
// run a function for each ... package foreach import ( "encoding/json" "os" "reflect" "simonwaldherr.de/go/golibs/file" "simonwaldherr.de/go/golibs/node" "simonwaldherr.de/go/golibs/structs" //"encoding/xml" ) func File(dirname string, recursive bool, fnc func(string, string, string, bool, os.FileInfo)) error { return file.Each(dirname, recursive, fnc) } func JSON(str string, handler func(*string, *int, *interface{}, int)) error { var j interface{} err := json.Unmarshal([]byte(str), &j) if err == nil { node.Node(&j, handler) return nil } return err } func Struct(sstruct interface{}, handler func(string, string, interface{}, int)) { v := reflect.ValueOf(sstruct) t := reflect.TypeOf(sstruct) structs.ReflectHelper(v, t, 0, handler) } /* func XML(str string, handler func(*string, *int, *interface{}, int)) error { var x interface{} err := xml.Unmarshal([]byte(str), &x) if err == nil { Node(&x, handler) return nil } return err }*/
// gopath provides an easy way to get system information package gopath import ( "os" "path" "path/filepath" "runtime" "strings" "unicode/utf8" ) type FileType int const ( DontExist FileType = iota Directory ASCII Binary ) // GetFileType returns the type of a given file. // The return values can be Directory, ASCII, Binary // or DontExist. func GetFileType(name string) FileType { if file, err := os.Open(name); err == nil { if fileStat, err := file.Stat(); err == nil && fileStat.IsDir() { return Directory } else if err == nil { data := make([]byte, 100) file.Read(data) if utf8.Valid(data) { return ASCII } return Binary } } return DontExist } // Compiler returns the name of the used compiler func Compiler() string { return runtime.Compiler } // GOARCH returns the system architecture func GOARCH() string { return runtime.GOARCH } // GOOS returns the name of the Operating System func GOOS() string { return runtime.GOOS } // GOROOT returns the $GOROOT environment variable func GOROOT() string { return runtime.GOROOT() } // GOPATH returns the $GOPATH environment variable func GOPATH() string { return os.Getenv("GOPATH") } // WD returns the working directory, this is // the folder where you were last. func WD() string { dir, _ := os.Getwd() return dir } // Compiled returns a boolean which tells if you run // a already compiled binary or "go run" the source. func Compiled() bool { if strings.HasPrefix(os.Args[0], "/var/folders/") || strings.HasPrefix(os.Args[0], "/tmp/go-build") || strings.Contains(os.Args[0], "\\AppData\\Local\\Temp\\") { return false } return true } // gpath is the helper function for the public functions // Path(), Name() and Dir() func gpath(i int) string { var filename string if Compiled() == false { _, filename, _, _ = runtime.Caller(i) } else { filename, _ = filepath.Abs(filepath.Join(WD(), os.Args[0])) } return filename } // Path returns the full path of the binary or source file // which is currently running. func Path() string { return gpath(2) } // Name returns the filename of the binary or source file // which is currently running. func Name() string { _, f := path.Split(gpath(2)) return f } // Dir returns the directory in which the binary or source file // is stored. This is useful if you have config files in the // same folder. func Dir() string { return filepath.Dir(gpath(2)) }
// manipulating images pixel by pixel package graphics import ( "image" "image/color" "image/draw" _ "image/gif" _ "image/jpeg" _ "image/png" "math" "os" ) var edfX = [3][3]int8{{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}} var edfY = [3][3]int8{{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}} func EachPixel(file *os.File, f func(uint8, uint8, uint8, uint8) (uint8, uint8, uint8, uint8)) (image.Image, error) { src, _, err := image.Decode(file) if err != nil { return nil, err } bsrc := src.Bounds() img := image.NewRGBA(bsrc) draw.Draw(img, bsrc, src, bsrc.Min, draw.Src) b := img.Bounds() for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { oldPixel := img.At(x, y) r1, g1, b1, a1 := oldPixel.RGBA() r2, g2, b2, a2 := f(uint8(r1), uint8(g1), uint8(b1), uint8(a1)) pixel := color.RGBA{uint8(r2), uint8(g2), uint8(b2), uint8(a2)} img.Set(x, y, pixel) } } return img, nil } func ResizeNearestNeighbor(file *os.File, newWidth, newHeight int) (*image.NRGBA, error) { img, _, err := image.Decode(file) if err != nil { return nil, err } return NearestNeighbor(img, newWidth, newHeight) } func NearestNeighbor(img image.Image, newWidth, newHeight int) (*image.NRGBA, error) { w := img.Bounds().Max.X h := img.Bounds().Max.Y newimg := image.NewNRGBA(image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{newWidth, newHeight}}) xn := (w<<16)/newWidth + 1 yn := (h<<16)/newHeight + 1 for yo := 0; yo < newHeight; yo++ { y := (yo * yn) >> 16 for xo := 0; xo < newWidth; xo++ { x := (xo * xn) >> 16 newimg.Set(xo, yo, img.At(x, y)) } } return newimg, nil } func Grayscale(img image.Image) image.Image { min := img.Bounds().Min max := img.Bounds().Max grayImg := image.NewGray(image.Rect(max.X, max.Y, min.X, min.Y)) for x := 0; x < max.X; x++ { for y := 0; y < max.Y; y++ { grayPixel := color.GrayModel.Convert(img.At(x, y)) grayImg.Set(x, y, grayPixel) } } return grayImg } func Edgedetect(img image.Image) image.Image { img = Grayscale(img) max := img.Bounds().Max min := img.Bounds().Min edImg := image.NewGray(image.Rect(max.X, max.Y, min.X, min.Y)) width := max.X height := max.Y var pixel color.Color for x := 1; x < width-1; x++ { for y := 1; y < height-1; y++ { pX, pY := detectEdgeAroundPixel(img, x, y) val := uint32(math.Ceil(math.Sqrt(pX*pX + pY*pY))) pixel = color.Gray{Y: uint8(val)} edImg.SetGray(x, y, pixel.(color.Gray)) } } return edImg } func detectEdgeAroundPixel(img image.Image, x int, y int) (float64, float64) { var pX, pY int curX := x - 1 curY := y - 1 for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { r, _, _, _ := img.At(curX, curY).RGBA() pX += int(edfX[i][j]) * int(uint8(r)) pY += int(edfY[i][j]) * int(uint8(r)) curX++ } curX = x - 1 curY++ } return math.Abs(float64(pX)), math.Abs(float64(pY)) }
package http import ( //"context" "io/ioutil" //"net" "net/http" //"strings" "time" //"github.com/rs/dnscache" ) var Transporter *http.Transport var client http.Client var clientReady bool = false func init() { //dnsResolver := &dnscache.Resolver{} Transporter = &http.Transport{ /* DialContext: func(ctx context.Context, network string, addr string) (conn net.Conn, err error) { separator := strings.LastIndex(addr, ":") ips, err := dnsResolver.LookupHost(ctx, addr[:separator]) if err != nil { return nil, err } for _, ip := range ips { conn, err = net.Dial(network, ip+addr[separator:]) if err == nil { break } } return },*/ MaxIdleConns: 1024, MaxConnsPerHost: 1024, IdleConnTimeout: 10 * time.Second, } /* go func() { cacheTicker := time.NewTicker(30 * time.Minute) defer cacheTicker.Stop() for range cacheTicker.C { dnsResolver.Refresh(true) } }()*/ } var NewRequest = http.NewRequest func Client(timeout time.Duration) http.Client { return http.Client{ Transport: Transporter, Timeout: timeout, } } func GetString(url string) (string, error) { if clientReady == false { client = Client(time.Second * 15) } resp, err := client.Get(url) if err != nil { return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } return string(body), nil }
package log import ( "io" "log" "os" ) var ( Info *log.Logger Warning *log.Logger Error *log.Logger Fatal *log.Logger ) func init() { Info = log.New(os.Stdout, "INFO: ", log.Ltime|log.Lshortfile) Warning = log.New(os.Stderr, "WARNING: ", log.Ltime|log.Lshortfile) Error = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) Fatal = log.New(os.Stderr, "FATAL: ", log.Ldate|log.Lmicroseconds|log.Llongfile) } func Change(infoHandle, warningHandle, errorHandle, fatalHandle io.Writer, infoFlag, warningFlag, errorFlag, fatalFlat int) { Info = log.New(infoHandle, "INFO: ", infoFlag) Warning = log.New(warningHandle, "WARNING: ", warningFlag) Error = log.New(errorHandle, "ERROR: ", errorFlag) Fatal = log.New(fatalHandle, "FATAL: ", fatalFlat) }
// wanna do something several times? // Then this is the correct package for you. package re import ( "fmt" "time" ) var MaxAttempts = 10 func Try(retrys int, fn func() (err error)) error { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() var err error for attempt := 1; ; attempt++ { err = fn() if err == nil { break } if attempt >= MaxAttempts || attempt >= retrys { return fmt.Errorf("Reached number of attempts (%v)\n%v", (attempt), err) } } return err } func Do(wait time.Duration, fn func(chan<- interface{})) (<-chan interface{}, chan<- bool) { stop := make(chan bool, 1) ret := make(chan interface{}) go func() { defer func() { close(stop) time.Sleep(wait) close(ret) }() var stopbool = false for stopbool == false { select { case <-stop: stopbool = true default: go fn(ret) time.Sleep(wait) } } }() return ret, stop }
// regex is a wrapper for the standard regexp package. // It automates the regexp.Compile process for you. package regex import ( "regexp" ) var regexArray = make(map[string]*regexp.Regexp) func CheckRegex(regex string) error { _, err := regexp.Compile(regex) return err } func CacheRegex(regex string) error { var err error if _, ok := regexArray[regex]; ok { return nil } if re, err := regexp.Compile(regex); err == nil { regexArray[regex] = re } return err } func MatchString(src, regex string) (bool, error) { var err error if re, ok := regexArray[regex]; ok { return re.MatchString(src), nil } if re, err := regexp.Compile(regex); err == nil { regexArray[regex] = re return re.MatchString(src), nil } return false, err } // ReplaceAllString returns a copy of src, replacing matches of the regular expression // with the replacement string replace. Inside replace, $ signs are interpreted as // in Expand, so for instance $1 represents the text of the first submatch. func ReplaceAllString(src, regex, replace string) (string, error) { var err error if re, ok := regexArray[regex]; ok { return re.ReplaceAllString(src, replace), nil } if re, err := regexp.Compile(regex); err == nil { regexArray[regex] = re return re.ReplaceAllString(src, replace), nil } return "", err } // ReplaceAllStringFunc returns a copy of src in which all matches of the // regular expression have been replaced by the return value of function replace applied // to the matched substring. The replacement returned by replace is substituted // directly, without using Expand. func ReplaceAllStringFunc(src, regex string, replace func(s string) string) (string, error) { var err error if re, ok := regexArray[regex]; ok { return re.ReplaceAllStringFunc(src, replace), nil } if re, err := regexp.Compile(regex); err == nil { regexArray[regex] = re return re.ReplaceAllStringFunc(src, replace), nil } return "", err } // FindAllString returns a slice of all strings holding the text of the leftmost // match in src of the regular expression. If there is no match, the return value is nil. // It will be empty if the regular expression successfully matches an empty string. func FindAllString(src, regex string) ([]string, error) { var err error if re, ok := regexArray[regex]; ok { return re.FindAllString(src, -1), nil } if re, err := regexp.Compile(regex); err == nil { regexArray[regex] = re return re.FindAllString(src, -1), nil } return []string{}, err } // FindAllStringSubmatch returns a slice of a slice of strings holding the text of the // leftmost match of the regular expression in src and the matches. // A return value of nil indicates no match. func FindAllStringSubmatch(src, regex string) ([][]string, error) { var err error if re, ok := regexArray[regex]; ok { return re.FindAllStringSubmatch(src, -1), nil } if re, err := regexp.Compile(regex); err == nil { regexArray[regex] = re return re.FindAllStringSubmatch(src, -1), nil } return [][]string{}, err } func Count() int { return len(regexArray) } func Cleanup() { regexArray = make(map[string]*regexp.Regexp) }
// Package rss provides a RSS parser package rss import ( "encoding/xml" "net/http" "simonwaldherr.de/go/golibs/as" "time" ) // Client is a http client to crawl the feed from (#) type Client interface { Get(url string) (resp *http.Response, err error) } // ItemEnclosure contains an URL and its MIME-Type of an episode file type ItemEnclosure struct { URL string `xml:"url,attr"` Type string `xml:"type,attr"` } // Item represents an episode with all of its content type Item struct { Title string `xml:"title"` Link string `xml:"link"` Comments string `xml:"comments"` PubDate string `xml:"pubDate"` GUID string `xml:"guid"` Category []string `xml:"category"` Enclosure []ItemEnclosure `xml:"enclosure"` Description string `xml:"description"` Content string `xml:"content"` } // Image contains the URL and title of the podcast logo type Image struct { URL string `xml:"url"` Title string `xml:"title"` } // Main struct represents the root of the RSS feed type Main struct { Title string `xml:"title"` Link string `xml:"link"` Copyright string `xml:"copyright"` Description string `xml:"description"` Generator string `xml:"generator"` Language string `xml:"language"` LastBuildDate string `xml:"lastBuildDate"` Items []Item `xml:"item"` Image Image `xml:"image"` } // Read reads from an URL with the Golang default http client and returns rss.Main func Read(url string) (*Main, error) { return ReadCustomClient(url, http.DefaultClient) } // ReadCustomClient allows to read with an custom http client func ReadCustomClient(url string, client Client) (*Main, error) { r, err := client.Get(url) if err != nil { return nil, err } defer func() { err = r.Body.Close() }() xmlDecoder := xml.NewDecoder(r.Body) var rss struct { Main Main `xml:"channel"` } if err = xmlDecoder.Decode(&rss); err != nil { return nil, err } return &rss.Main, nil } // Len returns the episode count func (rss *Main) Len() int { return len(rss.Items) } // Time returns the specified last build date as time.Time func (rss *Main) Time() time.Time { return as.Time(rss.LastBuildDate) } // Time returns the specified publication date as time.Time func (episode *Item) Time() time.Time { return as.Time(episode.PubDate) }
// Generate SSL Certs via this simple to use ssl package. package ssl import ( "bufio" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "log" "math/big" "os" "time" ) const ( day = time.Hour * 24 year = day * 365 ) func Check(certPath string, keyPath string) error { if _, err := os.Stat(certPath); os.IsNotExist(err) { return err } else if _, err := os.Stat(keyPath); os.IsNotExist(err) { return err } return nil } func Generate(options map[string]string) error { var err error var certOut *os.File var derBytes []byte priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { log.Printf("failed to generate private key: %s", err) return err } notBefore := time.Now().Add(day * -1) notAfter := notBefore.Add(year * 2) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { log.Printf("failed to generate serial number: %s", err) return err } scanner := bufio.NewScanner(os.Stdin) var certPath string if options["certPath"] == "" { fmt.Print("# Cert filename: ") scanner.Scan() certPath = scanner.Text() } else { certPath = options["certPath"] } var keyPath string if options["keyPath"] == "" { fmt.Print("# Key filename: ") scanner.Scan() keyPath = scanner.Text() } else { keyPath = options["keyPath"] } var countryName string if options["countryName"] == "" { fmt.Print("# Country Name (2 letter code) [AU]: ") scanner.Scan() countryName = scanner.Text() } else { countryName = options["countryName"] } var provinceName string if options["provinceName"] == "" { fmt.Print("# State or Province Name (full name) [Some-State]: ") scanner.Scan() provinceName = scanner.Text() } else { provinceName = options["provinceName"] } var organizationName string if options["organizationName"] == "" { fmt.Print("# Organization Name (eg, company) [Lorem Ipsum Inc]: ") scanner.Scan() organizationName = scanner.Text() } else { organizationName = options["organizationName"] } var commonName string if options["commonName"] == "" { fmt.Print("# Common Name (eg, YOUR name) [localhost]: ") scanner.Scan() commonName = scanner.Text() } else { commonName = options["commonName"] } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Country: []string{string(countryName)}, Organization: []string{string(organizationName)}, Province: []string{string(provinceName)}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, DNSNames: []string{string(commonName)}, IsCA: true, } if derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv); err != nil { log.Printf("Failed to create certificate: %s", err) return err } if certOut, err = os.Create(certPath); err != nil { log.Printf("failed to open "+certPath+" for writing: %s", err) return err } if err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { return err } if err = certOut.Close(); err != nil { return err } log.Printf("written %v\n", certPath) keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Print("failed to open "+keyPath+" for writing:", err) return err } if err = pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { return err } if err = keyOut.Close(); err != nil { return err } log.Printf("written %v\n", keyPath) return nil }
// stack implements a stack with "last in, first out" functionality. // it also provides a ring memory type which overrides itself after n write ops. package stack type Stype int const ( NIL Stype = iota LiFo FiFo ) // struct Stack contains nodes as slice of interfaces // and a counter for the current position. type Stack struct { nodes []interface{} count int stype Stype } // Lifo returns a pointer to a new stack. func Lifo() *Stack { return &Stack{ stype: LiFo, } } func Fifo() *Stack { return &Stack{ stype: FiFo, } } func (s *Stack) Unset() { *s = Stack{ nodes: []interface{}{}, count: 0, stype: NIL, } } func (s *Stack) ToFifo() *Stack { var x *Stack array := Fifo() if s.stype == FiFo { x = Fifo() *x = *s for s.Len() > 0 { array.Push(s.Pop()) } } if s.stype == LiFo { x = Lifo() *x = *s helper := Lifo() for s.Len() > 0 { helper.Push(s.Pop()) } for helper.Len() > 0 { array.Push(helper.Pop()) } } *s = *x return array } func (s *Stack) ToLifo() *Stack { var x *Stack array := Lifo() if s.stype == FiFo { x = Fifo() *x = *s for s.Len() > 0 { array.Push(s.Pop()) } } if s.stype == LiFo { x = Lifo() *x = *s helper := Lifo() for s.Len() > 0 { helper.Push(s.Pop()) } for helper.Len() > 0 { array.Push(helper.Pop()) } } *s = *x return array } func (s *Stack) Val() []interface{} { var a *Stack var r []interface{} if s.stype == FiFo { a = s.ToFifo() } else if s.stype == LiFo { a = s.ToLifo() } for s.Len() > 0 { r = append(r, s.Pop()) } *s = *a return r } // Push adds a value to the Stack func (s *Stack) Push(n interface{}) { if s.stype == LiFo { s.nodes = append(s.nodes[:s.count], n) s.count++ } else if s.stype == FiFo { s.nodes = append(s.nodes, n) } } func (s *Stack) Add(n interface{}) { s.Push(n) } // Pop returns the last added value and decrease the position counter. func (s *Stack) Pop() interface{} { if s.stype == LiFo { if s.count == 0 { return "" } s.count-- return s.nodes[s.count] } if s.stype == FiFo { if s.count == len(s.nodes) { return "" } s.count++ return s.nodes[s.count-1] } return "" } func (s *Stack) Get() interface{} { return s.Pop() } // Len returns the current position in the Stack. func (s *Stack) Len() int { if s.stype == LiFo { return s.count } if s.stype == FiFo { return len(s.nodes) - s.count } return -1 } func (s *Stack) IsEmpty() bool { if s.Len() == 0 { return true } return false } // Ring returns a pointer to a new ring. func Ring() *Rings { return &Rings{} } // struct Rings contains nodes as slice of strings, // count for the current ring position, // xcount for the total amount of added entries // and size for the maximum size of the "Ring". type Rings struct { nodes []string count int xcount int size int } // SetSize sets the maximum size of the Ring, // this size must be greater then the current counter. func (r *Rings) SetSize(i int) { if i > r.xcount { r.size = i } } // Init sets the default values of the Ring. func (r *Rings) Init(i int) { r.size = i r.count = -1 r.xcount = -1 } // GetSize returns the max size of the Ring. func (r *Rings) GetSize() int { return r.size } // Push adds a string to the Ring and returns it position func (r *Rings) Push(n string) int { r.count++ r.xcount++ if r.count > r.size { r.count = 0 } if r.xcount > r.count { r.nodes[r.count] = n } else { r.nodes = append(r.nodes[:r.count], n) } return r.count } // Get returns a slice of strings from the given // to the current position func (r *Rings) Get(from int) []string { ret := make([]string, r.size) var i int for from != r.count { ret[i] = string(r.nodes[from]) from++ i++ if from > r.size { from = 0 } } return ret } // Pos returns the current position and the // number of overall added values func (r *Rings) Pos() (int, int) { return r.count, r.xcount }
package structs import ( "reflect" ) func Reflect(sstruct interface{}) map[string]interface{} { attrs := make(map[string]interface{}) v := reflect.ValueOf(sstruct) t := reflect.TypeOf(sstruct) attrs = ReflectHelper(v, t, 0, func(name string, vtype string, value interface{}, depth int) { }) return attrs } func ReflectHelper(v reflect.Value, t reflect.Type, depth int, handler func(string, string, interface{}, int)) map[string]interface{} { attrs := make(map[string]interface{}) for i := 0; i < v.NumField(); i++ { e := v.Field(i) f := t.Field(i) handler(f.Name, e.Type().String(), e.Interface(), depth) if e.Kind().String() == "struct" { attrs[f.Name] = ReflectHelper(e, e.Type(), depth+1, handler) } else { attrs[f.Name] = e.Type().String() } } return attrs }
// xmath is a package with math functions. // Besides a few standard formulas it contains various mean algorithms. package xmath import ( "math" "reflect" "simonwaldherr.de/go/golibs/as" "sort" ) // Sqrt calculates the square root of n. func Sqrt(n int64) int64 { var t int64 var b int64 var r int64 t = int64(n) p := int64(1 << 30) for p > t { p >>= 2 } for ; p != 0; p >>= 2 { b = r | p r >>= 1 if t >= b { t -= b r |= p } } return int64(r) } // Prime returns the nth prime number as int. func Prime(n int) int { var primeList = []int{2} isPrime := 1 num := 3 sqrtNum := 0 for len(primeList) < n { sqrtNum = int(Sqrt(int64(num))) for i := 0; i < len(primeList); i++ { if num%primeList[i] == 0 { isPrime = 0 } if primeList[i] > sqrtNum { i = len(primeList) } } if isPrime == 1 { primeList = append(primeList, num) } else { isPrime = 1 } num = num + 2 } return primeList[n-1] } // Deg2Rad returns the rad of a deg. func Deg2Rad(deg float64) float64 { return (deg * math.Pi) / 180 } // Rad2Deg returns the deg of a rad. func Rad2Deg(rad float64) float64 { return (rad * 180) / math.Pi } // Round returns a rounded int from a float64. // It rounds via "Round half away from zero". func Round(v float64) int { if v < 0 { return int(math.Ceil(v - 0.5)) } return int(math.Floor(v + 0.5)) } // Round returns a rounded float64 from a float64 // with d digits after the point. It rounds via // "Round half away from zero". func FloatRound(v float64, d int) float64 { pow := math.Pow(10, float64(d)) return float64(Round(v*pow)) / pow } // Count returns the length of any slice (like len()). func Count(val interface{}) int { slice := reflect.ValueOf(val) return slice.Len() } // Sum returns the sum from a slice of Values as float64. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Sum(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() out := make([]float64, c) for i := 0; i < c; i++ { out[i] = as.Float(slice.Index(i).Interface()) } var sum float64 for _, value := range out { sum = sum + value } return sum } // Min returns the smallest number from a slice of Values as float64. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Min(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() out := make([]float64, c) for i := 0; i < c; i++ { out[i] = as.Float(slice.Index(i).Interface()) } min := out[0] for _, value := range out { if value < min { min = value } } return min } // Max returns the greatest number from a slice of Values as float64. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Max(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() out := make([]float64, c) for i := 0; i < c; i++ { out[i] = as.Float(slice.Index(i).Interface()) } max := out[0] for _, value := range out { if value > max { max = value } } return max } type Meantype int const ( ArithmeticMean Meantype = iota GeometricMean HarmonicMean MedianMean RmsMean Default ) func Mean(val interface{}, t Meantype) float64 { switch t { case ArithmeticMean: return Arithmetic(val) case GeometricMean: return Geometric(val) case HarmonicMean: return Harmonic(val) case MedianMean: return Median(val) case RmsMean: return Rootmeansquare(val) } return Arithmetic(val) } // Median returns the median from a slice of Values as float64. // The median is the numerical value separating the higher half // of a data sample from the lower half. The median of a list of // numbers can be found by arranging all the observations from // lowest value to highest value and picking the middle one. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Median(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() out := make([]float64, c) for i := 0; i < c; i++ { out[i] = as.Float(slice.Index(i).Interface()) } sort.Float64s(out) if c%2 == 1 { return out[c/2] } return (out[c/2] + out[c/2-1]) / 2 } // Arithmetic returns the arithmetic mean from a slice of Values as float64. // The arithmetic mean or simply the mean or average when the context is clear, // is the sum of a list of numbers divided by the number of numbers // in the list. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Arithmetic(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() out := make([]float64, c) for i := 0; i < c; i++ { out[i] = as.Float(slice.Index(i).Interface()) } return (Sum(out) / float64(len(out))) } // Rootmeansquare returns the root mean square from a slice of Values as float64. // The root mean square is the root value of the sum of the squared value of a // list of numbers divided by the number of numbers in the list. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Rootmeansquare(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() out := make([]float64, c) for i := 0; i < c; i++ { out[i] = math.Pow(as.Float(slice.Index(i).Interface()), 2) } return math.Sqrt(Sum(out) / float64(len(out))) } // Harmonic returns the harmonic mean from a slice of Values as float64. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Harmonic(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() s := float64(0) for i := 0; i < c; i++ { s = s + 1/as.Float(slice.Index(i).Interface()) } return (float64(c) * 1 / s) } // Geometric returns the geometric mean from a slice of Values as float64. // The geometric mean is a type of mean or average, which indicates the central // tendency or typical value of a set of numbers by using the product of their // values (as opposed to the arithmetic mean which uses their sum). The // geometric mean is defined as the nth root of the product of n numbers. // It uses "as" (simonwaldherr.de/go/golibs/as) to // convert given values to floats. func Geometric(val interface{}) float64 { slice := reflect.ValueOf(val) c := slice.Len() var m float64 = 1 for i := 0; i < c; i++ { m = m * as.Float(slice.Index(i).Interface()) } return float64(math.Pow(float64(m), 1/float64(c))) } // Even tells if a number is even func Even(number int) bool { return number%2 == 0 } // Odd tells if a number is odd func Odd(number int) bool { return !Even(number) }
package xtime import ( "time" ) var conv = map[rune]string{ 'a': "Mon", 'A': "Monday", 'b': "Jan", 'B': "January", 'd': "02", 'D': "01-02-2006", 'F': "2006-01-02", 'H': "15", 'I': "03", 'L': ".000", 'm': "01", 'M': "04", 'p': "PM", 'S': "05", 'x': "2006-01-02", 'X': "15:04:05", 'y': "06", 'Y': "2006", 'z': "-0700", 'Z': "MST", '0': "", '%': "", } // StrfTime implements a subset of strftime // http://man7.org/linux/man-pages/man3/strftime.3.html func StrfTime(format string, t time.Time) string { ret := make([]byte, 0, len(format)) for i := 0; i < len(format); i++ { if format[i] == '%' { if layout, ok := conv[rune(format[i+1])]; ok { ret = append(ret, []byte(t.Format(layout))...) i++ } else { ret = append(ret, format[i]) } } else { ret = append(ret, format[i]) } } return string(ret) } // Fmt (xtime.Fmt) is an alias for StrfTime func Fmt(format string, t time.Time) string { return StrfTime(format, t) } // FmtNow is like StrfTime, but automatically with the current local time func FmtNow(format string) string { t := time.Now() return StrfTime(format, t) }