GOLANG SNIPPETS
SEND/RECEIVE DATA
SendResponse
// SendResponse...
func SendResponse(w http.ResponseWriter, d interface{}, s int) {
w.WriteHeader(s)
if d == nil {
return
}
w.Header().Set("Content-Type", "application/json")
dataJSON, err := json.MarshalIndent(d, "", " ")
if err != nil {
log.Printf("ERROR Marshaling %v\n", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
_, err = w.Write(dataJSON)
if err != nil {
log.Printf("ERROR writing JSON response: %v\n", err)
}
}
// SendtResponseXML ...
func SendResponseXML(w http.ResponseWriter, d interface{}, s int) {
w.WriteHeader(s)
if d == nil {
return
}
w.Header().Set("Content-Type", "application/xml")
dataXML, err := xml.MarshalIndent(d, "", " ")
if err != nil {
log.Printf("ERROR Marshaling XML: %v\n", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
_, err = w.Write(dataXML)
if err != nil {
log.Printf("ERROR writing XML response: %v\n", err)
}
}
Fetch GET
// FetchGET ...
func FetchGET(url string, d interface{}) error {
client := &http.Client{
Timeout: 10 * time.Second,
}
// with headers
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Printf("ERROR: creating request %s => %v", url, err)
return err
}
req.Header.Set("Authorization", "Bearer ACCESS_TOKEN")
req.Header.Set("Accept", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Printf("ERROR: Request %s => %v", url, err)
return err
}
// without Headers
resp, err := client.Get(url)
if err != nil {
log.Printf("ERROR: Request %s => %v", url, err)
return err
}
// common
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err := errors.New("HTTP status:" + http.StatusText(resp.StatusCode))
log.Printf("ERROR: %v", err)
return err
}
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&d)
if err != nil {
log.Printf("ERROR unnmarshalling => %v", err)
return err
}
return nil
}
DoGetConcurrentRequest
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
}
fetchPOST
// FetchPOST ...
func FetchPOST(url string, d interface{}) error {
client := &http.Client{
Timeout: 10 * time.Second,
}
jsonData, err := json.Marshal(d)
if err != nil {
log.Printf("ERROR: Failed to marshal request body => %v", err)
return err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
log.Printf("ERROR: Failed to create request for %s => %v", url, err)
return err
}
req.Header.Set("Authorization", "Bearer ACCESS_TOKEN")
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Printf("ERROR: Request %s => %v", url, err)
return err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err := errors.New("HTTP status: " + http.StatusText(resp.StatusCode))
log.Printf("ERROR: %v", err)
return err
}
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&d)
if err != nil {
log.Printf("ERROR unmarshalling => %v", err)
return err
}
return nil
}
fetchPOST with params
import (
url "net/url"
)
// FetchPOSTparams ...
func FetchPOSTparams(path string, d map[string]string) error {
client := &http.Client{
Timeout: 10 * time.Second,
}
params := url.Values{}
for key, value := range d {
params.Add(key, value)
}
/*params := url.Values{
"test": {myTest},
"data": {myData},
}*/
body := bytes.NewBufferString(params.Encode())
req, err := http.NewRequest("POST", path, body)
if err != nil {
log.Printf("ERROR: Failed to create request for %s => %v", path, err)
return err
}
req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
req.Header.Set("Accept-Charset", "utf-8")
req.Header.Set("Content-Type", "application/x-www-form-pathencoded")
resp, err := client.Do(req)
if err != nil {
log.Printf("ERROR: Request %s => %v", path, err)
return err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err := errors.New("HTTP status: " + http.StatusText(resp.StatusCode))
log.Printf("ERROR: %v", err)
return err
}
return nil
}
GetInterfacesTypes
// 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
// IsJSON ...
func IsJSON(str string) bool {
var js json.RawMessage
return json.Unmarshal([]byte(str), &js) == nil
}
IsPointer
func IsPointer(d interface{}) bool {
return reflect.TypeOf(d).Kind() == reflect.Ptr
}
FILES
ReadFile
// ReadFile ...
func ReadFile(filePath string) (string, error) {
data, err := ioutil.ReadFile(filePath)
if err != nil {
return "", err
}
return string(data), nil
}
// ReadFileLineByLine ...
func ReadFileLineByLine(filePath string) ([]string, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
return nil, err
}
return lines, nil
}
WriteFile
// WriteFile ...
func WriteFile(filePath string, content string) error {
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(content)
if err != nil {
return err
}
return nil
}
LoadJSON from File
// LoadJSONFIleDecoder ... use streams
func LoadJSONFileDecoder(filePath string, data interface{}) error {
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
decoder := json.NewDecoder(file)
err = decoder.Decode(data)
if err != nil {
return err
}
return nil
}
// LoadJSONFileMarschall ... loads all
func LoadJSONFileMarshall(filePath string, data interface{}) error {
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
body, err := ioutil.ReadAll(file)
if err != nil {
return err
}
err = json.Unmarshal(body, data)
if err != nil {
return err
}
return nil
}
WriteJSONtoFile
// WriteJSONtoFile ...
func WriteJSONtoFile(filePath string, d interface{}) error {
f, err := os.Create(filePath)
if err != nil {
return err
}
defer f.Close()
encoder := json.NewEncoder(f)
err = encoder.Encode(d)
if err != nil {
return err
}
return nil
}
DownloadFile
// DownloadFile ...
func DownloadFile(filePath string, url string) error {
out, err := os.Create(filePath)
if err != nil {
return err
}
defer out.Close()
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("ERROR Downloading file: %d", resp.StatusCode)
}
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}
SendFileFromServerToClient
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%"
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
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)
}
NETWORK
GetIP
// GetIP ...
func GetIP(r *http.Request) string {
headers := []string{
"X-Forwarded-For",
"X-Real-IP",
"CF-Connecting-IP",
}
for _, header := range headers {
ips := r.Header.Get(header)
if ips != "" {
return strings.TrimSpace(strings.Split(ips, ",")[0])
}
}
ip := r.RemoteAddr
colon := strings.LastIndex(ip, ":")
if colon != -1 {
ip = ip[:colon]
}
return strings.TrimSpace(ip)
}
GetRequestOrigin
func GetRequestOrigin(r *http.Request) string {
switch {
case r.Header.Get("Host") != "":
return r.Header.Get("Host")
case r.Header.Get("Origin") != "":
return r.Header.Get("Origin")
case r.Header.Get("Referer") != "":
return r.Header.Get("Referer")
default:
return "?????"
}
}
IsValidURL
// IsValidURL ...
func IsValidURL(rawurl string) bool {
rawurl = strings.TrimSpace(rawurl)
parsedURL, err := url.Parse(rawurl)
if err != nil {
return false
}
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
return false
}
if parsedURL.Host == "" {
return false
}
return true
}
ExistsURL
// ExistsURL ...
func ExistsURL(myUrl string) bool {
client := http.Client{
Timeout: 5 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // Dont follow redirections
},
}
resp, err := client.Head(myUrl)
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode >= 200 && resp.StatusCode < 400
}
GetLanguage
// GetLanguage ...
func GetLanguage(r *http.Request) string {
lang := r.Header.Get("Accept-Language")
if lang != "" {
langs := strings.SplitN(lang, ",", 2)
return strings.ToLower(strings.TrimSpace(langs[0]))
}
return "en"
}
RemoveProtocolFromURL
// RemoveProtocol ...
func RemoveProtocol(url string) string {
if strings.HasPrefix(url, "https://") {
return url[8:]
}
if strings.HasPrefix(url, "http://") {
return url[7:]
}
return url
}
RemoveProtocolAndWWWFromURL
// RemoveProtocolAndWWW ...
func RemoveProtocolAndWWWL(url string) string {
url = RemoveProtocol(url)
if strings.HasPrefix(url, "www.") {
return url[4:]
}
return url
}
Nginx return 444
func close(w http.ResponseWriter, r *http.Request) {
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Server does not support hijacking", http.StatusInternalServerError)
return
}
conn, _, err := hijacker.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
conn.Close()
return
}
Slow Response
func slowSend(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
if !ok {
err := "Server does not support flusher"
http.Error(w, err, http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintln(w, "Initiating slow response...")
for i := 0; i < 100; i++ {
fmt.Fprintf(w, "Fragmento %d\n", i+1)
flusher.Flush()
time.Sleep(1 * time.Second)
}
fmt.Fprintln(w, "Task accomplished")
}
func holdConn(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Begin.............")
time.Sleep(60 * time.Second)
fmt.Fprintf(w, "Thats all")
}
NUMBERS
GetRandomInt
import (
"time"
"golang.org/x/exp/rand"
)
// RandomInt ... min and max included
func RandomInt(min, max int) int {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return r.Intn(max-min+1) + min
}
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 {
if len(matrix) == 0 {
return [][]int{}
}
result := make([][]int, len(matrix[0]))
for i := range result {
result[i] = make([]int, len(matrix))
}
for y, row := range matrix {
for x, value := range row {
result[x][y] = value
}
}
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
}
STRINGS
RemoveAllWhitespaces
import "strings"
// RemoveAllWhitespaces ...
func RemoveAllWhitespaces(str string) string {
return strings.ReplaceAll(str, " ", "")
}
ReplaceAllWhitespacesByChar
import "strings"
// ReplaceAllWhitespacesByChar ...
func ReplaceAllWhitespacesByChar(str, otherChar string) string {
return strings.ReplaceAll(str, " ", otherChar)
}
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 {
if len(matrix) == 0 || len(matrix[0]) == 0 {
return [][]string{}
}
result := make([][]string, len(matrix[0]))
for i := range result {
result[i] = make([]string, len(matrix))
}
for y, row := range matrix {
for x, value := range row {
result[x][y] = value
}
}
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
}
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:]...).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:]...).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, error) {
formats := []string{
time.RFC3339,
"2006-01-02T15:04:05",
"2006-01-02",
}
for _, layout := range formats {
t, err := time.Parse(layout, start)
if err == nil {
return t, nil
}
}
fail := fmt.Errorf("Fail parsing time: %s", start)
return time.Time{}, fail
}
OnceADayTask
func main() {
go onceADayTask(3, 10, 10)
select {}
}
func onceADayTask(h, m, s int) {
t := time.Now()
n := time.Date(
t.Year(), t.Month(), t.Day(),
h, m, s, 0,
t.Location(),
)
if n.Before(t) {
n = n.Add(24 * time.Hour)
}
for {
time.Sleep(time.Until(n))
doSomeTask()
n = n.Add(24 * time.Hour)
}
}
func doSomeTask() {
fmt.Printf("Hi: %s\n", time.Now().Format("03:04:05 PM"))
}
SetInterval
func main() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
done := make(chan bool)
go func() {
for {
select {
case <-ticker.C:
fmt.Println("Ticker every X * time.Second")
case <-done:
return
}
}
}()
time.Sleep(5 * time.Second)
done <- true
fmt.Println("Ticker stopped. Exiting program.")
}
func main() {
go interval()
select {}
}
func interval() {
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
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
}
const (
errorLogFile = "error.log"
infoLogFile = "info.log"
)
func openLogFile(filename string) (*os.File, error) {
return os.OpenFile(
filename,
os.O_CREATE|os.O_WRONLY|os.O_APPEND,
0664,
)
}
func main() {
errorFile, err := openLogFile(errorLogFile)
if err != nil {
log.Fatalf("ERROR opening error log: %s: %v", errorLogFile, err)
}
defer errorFile.Close()
infoFile, err := openLogFile(infoLogFile)
if err != nil {
log.Fatalf("ERRRO opening info log: %s: %v", infoLogFile, err)
}
defer infoFile.Close()
eLog :=
log.New(errorFile, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
iLog :=
log.New(infoFile, "INFO: ", log.Ldate|log.Ltime)
eLog.Println("ERROR")
iLog.Println("INFO")
}
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
*/
Args + Flags + test
#go build -ldflags="-X 'main.when=$(date -u +%F_%T)'"
DATE=$(shell date -u +%F_%T)
LDFLAGS=-ldflags "-X main.when=$(DATE)"
all: build
build:
go build $(LDFLAGS)
clean:
rm binary
// main.go
var version = "0.0.1"
var when = ""
func main() {
tasks := checkFlags()
fmt.Println("USER => ", getUserName())
fmt.Println("TASKS=", tasks)
}
func checkFlags() []string {
if len(os.Args) > 1 && os.Args[1] == "-v" {
versionFlag := flag.Bool("v", false, "Show Version")
flag.Parse()
if *versionFlag {
fmt.Printf("Version ->\t%s\n", version)
fmt.Printf("Date ->\t%s\n", when)
os.Exit(0)
}
}
var result []string
validFlags := []string{"vnstat", "www", "cloud", "mysql", "rsync"}
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "-") {
flag := strings.TrimPrefix(arg, "-")
for _, validFlag := range validFlags {
if flag == validFlag {
if !includes(result, validFlag) {
result = append(result, validFlag)
}
}
}
}
}
return result
}
func getUserName() string {
currentUser, err := user.Current()
if err != nil {
fmt.Println("Error:", err)
os.Exit(0)
}
return currentUser.Username
}
func includes(slice []string, element string) bool {
for _, v := range slice {
if v == element {
return true
}
}
return false
}
// main_test.go
func TestCheckFlags(t *testing.T) {
tests := []struct {
name string
args []string
expected []string
}{
{"Test vnstat flag", []string{"cmd", "-vnstat"},
[]string{"vnstat"}},
{"Test www flag", []string{"cmd", "-www"},
[]string{"www"}},
{"Test cloud flag", []string{"cmd", "-cloud"},
[]string{"cloud"}},
{"Test mysql flag", []string{"cmd", "-mysql"},
[]string{"mysql"}},
{"Test rsync flag", []string{"cmd", "-rsync"},
[]string{"rsync"}},
{"Test vnstat and mysql flags",
[]string{"cmd", "-vnstat", "-mysql"},
[]string{"vnstat", "mysql"}},
{"Test no flags", []string{"cmd"}, []string{}},
{"Test repeated flags", []string{"cmd", "-www", "-www"},
[]string{"www"}},
{"Test unknown flag", []string{"cmd", "-unknown"},
[]string{}},
{"Test multiple unknown flags",
[]string{"cmd", "-unknown", "-anotherunknown"},
[]string{}},
{"Test multiple unknown and known flags",
[]string{"cmd", "-www", "-unknown", "-rsync", "-anotherunk"},
[]string{"www", "rsync"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
os.Args = tt.args
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
result := checkFlags()
if len(result) != len(tt.expected) {
t.Errorf("expected length %d, got %d",
len(tt.expected), len(result))
}
for i, v := range tt.expected {
if result[i] != v {
t.Errorf("expected %s at index %d, got %s",
v, i, result[i])
}
}
})
}
}
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,
}
}