GOLANG SNIPPETS


SEND/RECEIVE DATA

SendJSONToClient


import (
    "encoding/json"
    "log"
    "net/http"
)

// SendJSONToClient ...
func SendJSONToClient(w http.ResponseWriter, d interface{}) {
    w.Header().Set("Content-Type", "application/json")
    var dataJSON = []byte(`{}`)
    dataJSON, err := json.MarshalIndent(d, "", " ")
    if err != nil {
        log.Printf("ERROR Marshaling %s\n", err)
        w.Write([]byte(`{}`))
    }
    w.Write(dataJSON)
}

SendXMLToClient


import (
    "encoding/xml"
    "log"
    "net/http"
)

// SendXMLToClient ...
func SendXMLToClient(w http.ResponseWriter, d interface{}) {
    w.Header().Set("Content-Type", "application/xml")
    var dataXML = []byte(`<output></output>`)
    dataXML, err := xml.Marshal(&d)
    if err != nil {
        log.Printf("ERROR Parsing into XML %s\n", err)
        w.Write([]byte(`{}`))
    }
    w.Write(dataXML)
}

SendErrorToClient

import (
    "encoding/json"
    "log"
    "net/http"
)

// SendErrorToClient ...
func SendErrorToClient(w http.ResponseWriter, d interface{}) {
    w.WriteHeader(http.StatusBadRequest)
    w.Header().Set("Content-Type", "application/json")
    var dataJSON = []byte(`{}`)
    dataJSON, err := json.MarshalIndent(d, "", " ")
    if err != nil {
        log.Printf("ERROR Marshaling %s\n", err)
        w.Write([]byte(`{}`))
    }
    w.Write(dataJSON)
}

DoGetRequest

import (
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
    "time"
)

// DoGetRequest ...
func DoGetRequest(w http.ResponseWriter, url string, d interface{}) {
    var netClient = &http.Client{
        Timeout: time.Second * 10,
    }
    resp, err := netClient.Get(url)
    if err != nil {
        log.Fatal(err)
    }

    if resp.StatusCode != 200 {
        log.Fatal(err)
        return
    }

    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    // body is a string, for use we must Unmarshal over a struct
    err = json.Unmarshal(body, &d)
    if err != nil {
        log.Fatalln(err)
    }
}

DoGetConcurrentRequest

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func fillDefaultStocks(links []string) {
    ch := make(chan []byte)
    for _, link := range links {
        go doGetConcurrentRequest(link, ch)
    }
    for range links {
        json.Unmarshal(<-ch, &stocks)
    }
}

func doGetConcurrentRequest(url string, ch chan<- []byte) {
    resp, err := http.Get(url)
    if err != nil {
        msg := fmt.Sprintf("ERROR 1 HTTP Request %s", err)
        log.Printf(msg)
        ch <- []byte(msg)
        return
    }
    if resp.StatusCode != 200 {
        msg := fmt.Sprintf("ERROR 2 Status Code %d", resp.StatusCode)
        log.Printf(msg)
        ch <- []byte(msg)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        msg := fmt.Sprintf("ERROR 3 HTTP Request %s", err)
        log.Printf(msg)
        ch <- []byte(msg)
        return
    }
    ch <- body
}

DoPostRequest

func sendRequest(data []byte, a app) {
    server, _ := os.Hostname()
    server = strings.ToLower(server)
    contentType := "application/x-www-form-urlencoded" //; param=value"
    host := "https://" + a.Conf.Host + a.Conf.PathToAPI

    var client = &http.Client{
        Timeout: time.Second * 3,
    }
    params := url.Values{
        //"server": {server},
        "test": {a.Conf.Valid},
        "data": {string(data)},
    }
    params.Add("server", server)

    query := bytes.NewBufferString(params.Encode())
    resp, err := http.NewRequest("POST", host, query)
    resp.Header.Add("Content-Type", contentType)
    resp.Header.Add("Accept-Charset", "utf-8")
    if err != nil {
        log.Fatal("Error preparing POST request => ", err)
    }

    r, err := client.Do(resp)
    if err != nil {
        log.Fatal("Error sending POST request => ", err)
    }
    if r.StatusCode != 200 {
        log.Fatal("Error received from server => ", r.Status, " ", err)
    }
}

GetInterfacesTypes

import "fmt"

// GetInterfacesTypes ...
func GetInterfacesTypes(f interface{}) {
    switch vf := f.(type) {
    case map[string]interface{}:
        //fmt.Println("is a map:")
        for k, v := range vf {
            switch vv := v.(type) {
            case string:
                //fmt.Printf("%v: is string - %q\n", k, vv)
            case int:
                //fmt.Printf("%v: is int - %q\n", k, vv)
            case float64:
                //fmt.Printf("%v: is float64 - %g\n", k, vv)
            default:
                fmt.Sprintln(k, v, vv)
                //fmt.Printf("%v: ", k)
                GetInterfacesTypes(v)
            }
        }
    case []interface{}:
        //fmt.Println("is an array:")
        for k, v := range vf {
            switch vv := v.(type) {
            case string:
                //fmt.Printf("%v: is string - %q\n", k, vv)
            case int:
                //fmt.Printf("%v: is int - %q\n", k, vv)
            case float64:
                //fmt.Printf("%v: is float64 - %g\n", k, vv)
                if k == 4 {
                    fmt.Println(`ALELUYA==>`, vv)
                }
            default:
                fmt.Sprintln(k, v, vv)
                //fmt.Printf("%v: ", k)
                GetInterfacesTypes(v)
            }
        }
    }
}

IsJSON

import "encoding/json"
// IsJSON ...

func IsJSON(str string) bool {
    var js json.RawMessage
    return json.Unmarshal([]byte(str), &js) == nil
}

ERRORCHECK

Check

import "log"

// Check ...
func Check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

FILES

ReadFile

import (
    "log"
    "os"
)

// ReadFile ...
func ReadFile(filePath string) string {
    file, err := os.Open(filePath)
    defer file.Close()
    stat, err := file.Stat()
    if err != nil {
        log.Fatal(err)
    }
    bs := make([]byte, stat.Size())
    _, err = file.Read(bs)
    if err != nil {
        log.Fatal(err)
    }
    data := string(bs)
    return data
}

ReadFileLineByLine

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

// ReadFileLineByLine ...
func ReadFileLineByLine(filePath string) {
    file, err := os.Open(filePath)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        line := scanner.Text()
        fmt.Println(line)
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}

WriteFile

import (
    "log"
    "os"
)

// WriteFile ...
func WriteFile(filePath string, content string) {
    file, err := os.Create(filePath)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    file.WriteString(content)
}

LoadJSONfromFileDecoder

import (
    "encoding/json"
    "log"
    "os"
)

// LoadJSONfromFileDecoder ...
func LoadJSONfromFileDecoder(filePath string, data interface{}) {
    file, err := os.Open(filePath)
    if err != nil {
        log.Fatalln("Cannot open config file", err)
    }
    defer file.Close()
    decoder := json.NewDecoder(file)
    err = decoder.Decode(&data)
    if err != nil {
        log.Fatalln("Cannot get configuration from file", err)
    }
}

LoadJSONfromFileMarshall

import (
    "encoding/json"
    "io/ioutil"
    "log"
    "os"
)

// LoadJSONfromFileMarshall ...
func LoadJSONfromFileMarshall(filePath string, data interface{}) {
    file, err := os.Open(filePath)
    if err != nil {
        log.Fatalln("Cannot open config file", err)
    }
    defer file.Close()
    body, err := ioutil.ReadAll(file) //    get file content
    if err != nil {
        log.Fatalln(err)
    }
    err = json.Unmarshal(body, &data)
    if err != nil {
        log.Fatalln(err)
    }
}

WriteJSONtoFile

import (
    "encoding/json"
    "os"
)

// WriteJSONtoFile ...
func WriteJSONtoFile(filePath string, d interface{}) {
    f, err := os.Create(filePath)
    if err != nil {
        panic(err)
    }
    defer f.Close()
    e := json.NewEncoder(f)
    e.Encode(&d)
}

DownloadFile

import (
    "io"
    "net/http"
    "os"
)

// DownloadFile ...
func DownloadFile(filePath string, url string) (err error) {
    // Create the file
    out, err := os.Create(filePath)
    if err != nil {
        return err
    }
    defer out.Close()
    // Get the data
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    // Writer the body to file
    _, err = io.Copy(out, resp.Body)
    if err != nil {
        return err
    }
    return nil
}

SendFileFromServerToClient

import (
    "fmt"
    "io"
    "net"
    "net/http"
    "time"
)

func Index(w http.ResponseWriter, r *http.Request) {
    url := "http://upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png"

    timeout := time.Duration(5) * time.Second
    transport := &http.Transport{
        ResponseHeaderTimeout: timeout,
        Dial: func(network, addr string) (net.Conn, error) {
            return net.DialTimeout(network, addr, timeout)
        },
        DisableKeepAlives: true,
    }
    client := &http.Client{
        Transport: transport,
    }
    resp, err := client.Get(url)
    if err != nil {
        fmt.Println(err)
    }
    defer resp.Body.Close()

    //copy the relevant headers. If you want to preserve the downloaded 
    // file name, extract it with go's url parser.
    w.Header().Set("Content-Disposition", "attachment; filename=Wiki.png")
    w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
    w.Header().Set("Content-Length", r.Header.Get("Content-Length"))

    //stream the body to the client without fully loading it into memory
    io.Copy(w, resp.Body)
}

func main() {
    http.HandleFunc("/", Index)
    err := http.ListenAndServe(":8000", nil)

    if err != nil {
        fmt.Println(err)
    }
}

ParseCSVFile

// file.csv
"AAPL","Apple Inc","4.10%"
"AMZN","Amazon.com Inc","3.49%"
"MSFT","Microsoft Corp","3.23%"
"GOOGL","Alphabet Inc","3.09%"
import (
    "bufio"
    "encoding/csv"
    "encoding/json"
    "fmt"
    "io"
    "os"
)

type stock struct {
    Symbol string `json:"symbol"`
}

func main() {
    csvFile, _ := os.Open("sp.csv")
    reader := csv.NewReader(bufio.NewReader(csvFile))
    var stocks []stock
    for {
        line, error := reader.Read()
        if error == io.EOF {
            break
        }
        aux := stock{
            Symbol: line[0],
        }
        stocks = append(stocks, aux)
    }
    //stocksJSON, _ := json.Marshal(stocks)
    //fmt.Println(string(stocksJSON))

    f, err := os.Create("spList.json")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    e := json.NewEncoder(f)
    e.Encode(&stocks)
    fmt.Println(`END`)
}
// result
[
  {
    "symbol": "AAPL"
  },
  {
    "symbol": "AMZN"
  },
  {
    "symbol": "MSFT"
  },
  {
    "symbol": "GOOGL"
    }
]

HTTP SERVER

Lectura

Request Handling in Go

type Handler interface {
    ServeHttp( ResponseWriter, *Request )
}

Wrapper

Es muy sencillo pero luego complica para testearlo

mux.HandleFunc("/path", func(w http.ResponseWriter, r *http.Request) {
        nombreFuncion(w, r, loQueQueramosPasar)
})

Handle + HandleFunc

package main

import (
    "fmt"
    "net/http"
    "time"
)

func timeHandler1(w http.ResponseWriter, r *http.Request) {
    tm := time.Now().Format(time.RFC1123)
    fmt.Println("/time/" + tm)
    w.Write([]byte("The time is: " + tm))
}

func timeHandler2(format string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
        tm := time.Now().Format(format)
        fmt.Println("/time/" + tm)
        w.Write([]byte("The time is: " + tm))
    })
}

/*  lo mismo pero con conversion implicita al tipo HandlerFunc
func timeHandler2(format string) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        tm := time.Now().Format(format)
        fmt.Println("/time/" + tm)
        w.Write([]byte("The time is: " + tm))
    }
}
*/

func hiHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("/hello")
    w.Write([]byte("/hello"))
}

func main() {
    mux := http.NewServeMux()

    // Creamos un closure con las variables que queremos usar
    th2 := timeHandler2(time.RFC3339)

    mux.HandleFunc("/time/1", timeHandler1)
    mux.Handle("/time/2", th2)
    mux.HandleFunc("/hello", hiHandler)

    //http.HandleFunc("/time/1", timeHandler1)
    //http.Handle("/time/2", th2)
    //http.HandleFunc("/hello", hiHandler)

    http.ListenAndServe(":3000", mux /*nil*/)
}

Handler

type specificHandler struct {
    Thing string
}

func(h *specificHandler)ServeHTTP(w http.ResponseWriter,r *http.Request) {
    w.Write(h.Thing)
}

func main() {
  http.Handle("/something", &specificHandler{Thing: "Hello world!"})
  http.ListenAndServe(":8080", nil)
}
package main

import (
    "fmt"
    "net/http"
    "time"
)

type timeHandler struct {
    format string
}

func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    tm := time.Now().Format(th.format)
    fmt.Println("/time/" + tm)
    w.Write([]byte("The time is: " + tm))
}

type hiHandler struct{}

func (ti *hiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Println("/hello")
    w.Write([]byte("/hello"))
}

func main() {
    /mux := http.NewServeMux()

    th1 := &timeHandler{format: time.RFC1123}
    th2 := &timeHandler{format: time.RFC3339}
    hi := &hiHandler{}

    mux.Handle("/time/1", th1)
    mux.Handle("/time/2", th2)
    mux.Handle("/hello", hi)

    //http.Handle("/time/1", th1)
    //http.Handle("/time/2", th2)
    //http.Handle("/hello", hi)

    http.ListenAndServe(":3000", /*nil*/ mux)
}

Ejemplo Completo

package main

import (
    "errors"
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

type app struct {
    Config struct {
        Mode          string `json:"mode"`
        Port          int    `json:"port"`
        Valid         string `json:"valid"`
        ErrorsLogFile string `json:"errorsLogFile"`
        HitsLogFile   string `json:"hitsLogFile"`
    } `json:"config"`
    Mysql struct {
        User      string `json:"user"`
        Password  string `json:"password"`
        DB        string `json:"db"`
        Host      string `json:"host"`
        Port      int    `json:"port"`
        TableBW   string `json:"tableBw"`
        TableHits string `json:"tableHits"`
    }
}

type requestError struct {
    Error      error  `json:"-"`
    Message    string `json:"message"`
    StatusCode int    `json:"-"`
}

func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    valid := r.Form.Get("test")
    if valid != a.Config.Valid {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }
    updateBw(w, r, a)
}

func main() {
    var a app
    loadConfigJSON(&a)
    checkMode(&a)

    // Custom Log File
    if a.Config.Mode == "production" {
        var f = a.Config.ErrorsLogFile
        mylog, err := os.OpenFile(f, os.O_WRONLY|os.O_CREATE|os.O_APPEND
                , 0644)
        if err != nil {
            log.Printf("ERROR opening log file %s\n", err)
        }
        defer mylog.Close() // defer must be in main
        log.SetOutput(mylog)
    }

    mux := http.NewServeMux()

    mux.Handle("/savebw/", &a)
    mux.Handle("/saveHits/", checkValid(
        func(w http.ResponseWriter, r *http.Request) {
            updateHits(w, r, &a)
        }, a.Config.Valid))
    mux.HandleFunc("/get/", checkValid(
        func(w http.ResponseWriter, r *http.Request) {
            getStats(w, r, &a)
        }, a.Config.Valid))
    mux.HandleFunc("/", badRequest)

    server := http.Server{
        Addr:           fmt.Sprintf("localhost:%d", a.Config.Port),
        Handler:        mux,
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   30 * time.Second,
        MaxHeaderBytes: 1 << 20,
    }

    log.Printf("Server up listening %s in mode %s", server.Addr
            , a.Config.Mode)
    server.ListenAndServe()

}

func checkValid(next http.HandlerFunc, test string) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        r.ParseForm()
        valid := r.Form.Get("test")
        if valid != test {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    }
}

func badRequest(w http.ResponseWriter, r *http.Request) {
    re := &requestError{
        Error:      errors.New("Unexistent Endpoint"),
        Message:    "Bad Request",
        StatusCode: 400,
    }
    sendErrorToClient(w, re)
}

MIDDLEWARES

RateLimit

import "net/http"

// ExceedLimit ...
func ExceedLimit(ip string) bool {
    // ToDO
    return false
}

// RateLimit ...
func RateLimit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if ExceedLimit(GetIP(r)) {
            http.Error(w, "Too many requests", http.StatusTooManyRequests)
            return
        }
        next.ServeHTTP(w, r)
    })
}

NETWORK

GetIP

import (
    "net"
    "net/http"
)

// GetIP returns string with IP
func GetIP(r *http.Request) string {
    ip := r.Header.Get("X-Forwarded-For")
    if len(ip) > 0 {
        return ip
    }
    ip, _, _ = net.SplitHostPort(r.RemoteAddr)
    return ip
}

IsValidURL

import "net/url"

// IsValidURL ...
func IsValidURL(rawurl string) bool {
    _, err := url.ParseRequestURI(rawurl)
    if err != nil {
        return false
    }
    return true
}

ExistsURL

import "net/http"

func ExistsURL(myurl string) bool {
    resp, err := http.Head(myurl)
    if err != nil {
        return false
    }
    if resp.StatusCode != http.StatusOK {
        return false
    }
    return true
}

GetLanguage

import (
    "net/http"
    "strings"
)

// GetLanguage ...
func GetLanguage(r *http.Request) string {
    lang := r.Header.Get("Accept-Language")
    if lang != "" { // curl request doesnt have Accept-Language
        lang = lang[0:strings.Index(lang, ",")]
    }
    return lang
}

RemoveProtocolFromURL

// RemoveProtocolFromURL ...
func RemoveProtocolFromURL(url string) string {
    if strings.HasPrefix(url, "https://") {
        return url[8:]
    }
    if strings.HasPrefix(url, "https:/") {
        return url[7:]
    }
    if strings.HasPrefix(url, "http://") {
        return url[7:]
    }
    if strings.HasPrefix(url, "http:/") {
        return url[6:]
    }
    return url
}

RemoveProtocolAndWWWFromURL

// RemoveProtocolAndWWWFromURL ...
func RemoveProtocolAndWWWFromURL(url string) string {
    if strings.HasPrefix(url, "https://www.") {
        return url[12:]
    }
    if strings.HasPrefix(url, "https:/www.") {
        return url[11:]
    }
    if strings.HasPrefix(url, "http://www.") {
        return url[11:]
    }
    if strings.HasPrefix(url, "http:/www.") {
        return url[10:]
    }
    return RemoveProtocolFromURL(url)
}

NUMBERS

GetRandomInt

import (
    "math/rand"
    "time"
)

// GetRandomInt [min, max] both included
func GetRandomInt(min, max int) int {
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    //rand.Seed(time.Now().UnixNano())
    //  return rand.Intn(max-min+1) + min
    return r.Intn(max-min+1) + min
}

GetRandomFloat64

import (
    "math/rand"
    "time"
)

// GetRandomFloat64 [min, max] both included
func GetRandomFloat64(min, max float64) float64 {
    rand.Seed(time.Now().UnixNano())
    return (rand.Float64() * (max - min)) + (min)
}

ToFixedFloat64

import "math"

// ToFixedFloat64 (untruncated, num) -> untruncated.toFixed(num)
func ToFixedFloat64(untruncated float64, precision int) float64 {
    coef := math.Pow10(precision)
    truncated := float64(int(untruncated*coef)) / coef
    return truncated
}

ToFixedFloat32

import "math"

// ToFixedFloat32 (untruncated, num) -> untruncated.toFixed(num)
func ToFixedFloat32(untruncated float32, precision int) float32 {
    coef := float32(math.Pow10(precision))
    truncated := float32(int(untruncated*coef)) / coef
    return truncated
}

RoundFloat64

// RoundFloat64 -> rounds float64 into integer
func RoundFloat64(num float64) int {
    if num < 0 {
        return int(num - 0.5)
    }
    return int(num + 0.5)
}

RoundFloat32

// RoundFloat32 -> rounds float32 into integer
func RoundFloat32(num float32) int {
    if num < 0 {
        return int(num - 0.5)
    }
    return int(num + 0.5)
}

ReverseSliceInt

// ReverseSliceInt [0,1,2,3,4,5] ==> [5,4,3,2,1,0]
func ReverseSliceInt(reverse []int) []int {
    for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 {
        reverse[i], reverse[j] = reverse[j], reverse[i]
    }
    return reverse
}

TransposeMatrixInt

// TransposeMatrixInt rows > cols or cols > rows
// but rows.elements >= cols.elements
func TransposeMatrixInt(matrix [][]int) [][]int {
    result := make([][]int, len(matrix[0]))
    for i := range result {
        result[i] = make([]int, len(matrix))
    }
    for y, v := range matrix {
        for x, t := range v {
            result[x][y] = t
        }
    }
    return result
}

SliceContainsInt

// SliceContainsInt ... returns true/false
func SliceContainsInt(num int, slice []int) bool {
    for _, v := range slice {
        if v == num {
            return true
        }
    }
    return false
}

ArabicToRomanNumbers

import "math"

// ArabicToRomanNumbers converts arabic int to roman numeral (string)
func ArabicToRomanNumbers(n int) string {
    var rom string
    hundreds := []string{
        "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}
    tens := []string{
        "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}
    units := []string{
        "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}
    t := int(math.Floor(float64(n / 1000)))
    h := int(math.Floor(float64(n % 1000 / 100)))
    d := int(math.Floor(float64(n % 100 / 10)))
    u := int(math.Floor(float64(n % 10)))
    for i := 0; i < t; i++ {
        rom += "M"
    }
    if h > 0 {
        rom += hundreds[h-1]
    }
    if d > 0 {
        rom += tens[d-1]
    }
    if u > 0 {
        rom += units[u-1]
    }
    return rom
}


STRINGS

RemoveAllWhitespaces

import "strings"

// RemoveAllWhitespaces ...
func RemoveAllWhitespaces(str string) string {
    return strings.Replace(str, " ", "", -1)
}

ReplaceAllWhitespacesByChar

import "strings"

// ReplaceAllWhitespacesByChar ...
func ReplaceAllWhitespacesByChar(str string, otherChar string) string {
    return strings.Replace(str, " ", otherChar, -1)
}

ReverseSliceString

// ReverseSliceString ["H","O","L","A"] ==> ["A","L","O","H"]
func ReverseSliceString(reverse []string) []string {
    for i, j := 0, len(reverse)-1; i < j; i, j = i+1, j-1 {
        reverse[i], reverse[j] = reverse[j], reverse[i]
    }
    return reverse
}

TransposeMatrixString

// TransposeMatrixString rows > cols or cols > rows
// but rows.elements >= cols.elements
func TransposeMatrixString(matrix [][]string) [][]string {
    result := make([][]string, len(matrix[0]))
    for i := range result {
        result[i] = make([]string, len(matrix))
    }
    for y, v := range matrix {
        for x, t := range v {
            result[x][y] = t
        }
    }
    return result
}

SliceContainsString

// SliceContainsString ... returns true/false
func SliceContainsString(str string, slice []string) bool {
    for _, v := range slice {
        if v == str {
            return true
        }
    }
    return false
}

FixBadEncodedStrings

// FixBadEncodedStrings ...
func FixBadEncodedStrings(bad string) string {
    //bad := "Kläder"
    var good []byte
    for _, c := range bad {
        good = append(good, byte(c))
    }
    //fmt.Println(string(good))
    return string(good)
}

OS

execCommand

import (
    "fmt"
    "os/exec"
)

func main()  {
    command := []string{"vnstat", "-i", ifinterface, "--json"}
    ///fmt.Println("Command =>", command)
    chunk, err := execCommand(command)
    if err != nil {
        log.Fatal(err)
    }
    //fmt.Println(`CHUNK =>`, string(chunk))
}

func execCommand(args []string) (err error) {
    _, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput()
    if err != nil {
        fmt.Println(err)
        return err
    }
    return err
}

func execCommand(args []string) (c []byte, err error) {
    c, err = exec.Command(args[0], args[1:len(args)]...).CombinedOutput()
    if err != nil {
        return nil, err
    }
    return c, err
}

func execCommand(comm string) {
    _, err := exec.Command("sh", "-c", comm).CombinedOutput()
    if err != nil {
        log.Fatal(err)
    }
}

TIME

ParseStringToTime

import "time"

// ParseStringToTime ...
func ParseStringToTime(start string) time.Time {
    layout1 := "2006-01-02" // Layout numbers?
    layout2 := "2006-01-02T15:04:05"
    t, err := time.Parse(layout1, start)
    if err != nil {
        t, err = time.Parse(layout2, start)
    }
    return t
}

GetTimestampFromDate

import (
    "strconv"
    "strings"
    "time"
)

// GetTimestampFromDateString ...(yyyy-mm-dd)
func GetTimestampFromDateString(date string) float64 {
    var t int64
    params := strings.Split(date, "-")
    day, _ := strconv.Atoi(params[2])
    month, _ := strconv.Atoi(params[1])
    year, _ := strconv.Atoi(params[0])
    auxT := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
    t = int64(auxT.UnixNano() / int64(time.Millisecond))
    return float64(t)
}

OnceADayTask

import "time"

func onceADayTask() {
    t := time.Now()
    n := time.Date(t.Year(),t.Month(),t.Day(),3,10,10,0,t.Location())
    d := n.Sub(t)
    if d < 0 {
        n = n.Add(24 * time.Hour)
        d = n.Sub(t)
    }
    for {
        time.Sleep(d)
        d = 24 * time.Hour
        doSomeTask()
    }
}

SetInterval


import (
    "fmt"
    "net/http"
    "time"
)

type updates []struct {
    Symbol string  `json:"symbol"`
    Price  float64 `json:"price"`
}

func initUpdateIntervals() {
    var u updates
    var w http.ResponseWriter
    ticker := time.NewTicker(time.Millisecond * 1000)
    go func() {
        for _ = range ticker.C {
            u = updates{}
            lib.MakeGetRequest(w, url, &u)
            for _, v := range u {
                if v.Symbol != "" {
                    stocks[v.Symbol].PriceNow = v.Price
                }
            }
            t := time.Now()
            hour, min, sec := t.Clock()
            fmt.Println(`TICK`, hour, min, sec)
            if hour == 6 && min == 1 {
                if sec > 0 && sec < 6 {
                    go dailyWork()
                }
            }
        }
    }()
}
ticker := time.NewTicker(2 * time.Second)
quit := make(chan struct{})
go func() {
    for {
        select {
        case <-ticker.C:
            fmt.Println("Se ejecuta cada X * time.Second")
        case <-quit:
            ticker.Stop()
            return
        }
    }
}()
func interval() {
    ticker := time.NewTicker(time.Millisecond * 2000)
    for _ = range ticker.C {
        fmt.Println("Hi Every 2 secs")
    }
}

LOGS

Custom Logs

// main.go
/////// Custom Error Log File + Custom Info Log File /////////
iLog := createCustomInfoLogFile2(a.Conf.InfoLogFile)
mylog := createCustomErrorLogFile(a.Conf.ErrorsLogFile)
defer mylog.Close()
//////////////////////////////////////////////////////////////

// ya por donde queramos
func createCustomErrorLogFile(f string) *os.File {
    mylog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644)
    if err != nil {
        log.Fatalf("ERROR opening Error log file %s\n", err)
    }
    log.SetOutput(mylog)
    return mylog
}

func createCustomInfoLogFile2(f string) *log.Logger {
    infoLog,err:=os.OpenFile(f,os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644)
    if err != nil {
        log.Fatalf("ERROR opening Info log file %s\n", err)
    }
    var iLog *log.Logger
    iLog = log.New(infoLog, "INFO :\t", log.Ldate|log.Ltime)
    return iLog
}

PrettyPrint Structs

func prettyPrintStruct(s interface{}) {
    result, _ := json.MarshalIndent(s, "", "\t")
    fmt.Print(string(result), "\n")
}

FLAGS

Binarios con versiones

package main

import (
    "flag"
    "fmt"
    "os"
)

var version = "0.0.0"
var when = "undefined"

func main() {
    checkFlags()
    fmt.Println("Continue...")
}

func checkFlags() {
    versionFlag := flag.Bool("v", false, "Show current version and exit")
    flag.Parse()
    switch {
    case *versionFlag:
        fmt.Printf("Version:\t: %s\n", version)
        fmt.Printf("Date   :\t: %s\n", when)
        os.Exit(0)
    }
}

/*
go build  -ldflags="
-X 'main.version=v0.2.0' 
-X 'main.when=$(date -u +%F_%T)'"

go build  -ldflags="-X 'main.when=$(date -u +%F_%T)'"

luego podemos hacer ./binary -v
*/

ORGANIZACION DE CODIGO

Compartir structs entre paquetes

// main.go
package main

import (
    s "pruebas/secondarypkg"
    "time"
)

func main() {
    p := &s.Placeholder{
        Name: "FooBar",
        Date: time.Now().String(),
    }
    s.Foo(p)
}

// secondarypkg/otro.go
package secondarypkg

import "fmt"

type Placeholder struct {
    Name string
    Date string
}

func Foo(p *Placeholder) {
    fmt.Println(p.Date, p.Name)
}
// main.go
package main

import (
    s "pruebas/paquete"
    "time"
)
func main() {
    p := s.NewPlaceHolder("FooBar", time.Now().String())
    p.Foo()
}

// secondarypkg/otro.go
package secondarypkg

import "fmt"

type Placeholder struct {
    Name string
    Date string
}

func (p *Placeholder) Foo() {
    fmt.Println(p.Date, p.Name)
}

func NewPlaceHolder(name string, date string) *Placeholder {
    return &Placeholder{
        Name: name,
        Date: date,
    }
}

Lo mismo usando interfaces

// main.go
package main

import (
    s "pruebas/paquete"
    "time"
)

func main() {
    p := s.NewPlaceHolder("FooBar", time.Now().String())
    p.Foo()
}

// secondarypkg/otro.go
package secondarypkg

import "fmt"

type PlaceHolder interface {
    Foo()
}

type placeholder struct {
    Name string
    Date string
}

func (p *placeholder) Foo() {
    fmt.Println(p.Date, p.Name)
}

func NewPlaceHolder(name string, date string) PlaceHolder {
    return &placeholder{
        Name: name,
        Date: date,
    }
}