<commit_before>package main

import (
	"time"
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"net/http/httputil"
	"log"
	"os"
	//"io"
	"fmt"
	"database/sql"
	_ "github.com/lib/pq"
	"gopkg.in/antage/eventsource.v1"
)

var conn *sql.DB
var es eventsource.EventSource

func SetHeaders(w *http.ResponseWriter) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Content-Type", "application/json")
}

func GetBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog")
	data := []BlogPost{}
	for rows.Next() {
		post := BlogPost{}
		rows.Scan(&post.Id, &post.Titel, &post.Text, &post.Auteur, &post.Img_url, &post.Ctime, &post.Image)
		data = append(data, post)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM blog WHERE id = $1 LIMIT 1", ps.ByName("id"))
	data := BlogPost{}
	row.Scan(&data.Id, &data.Titel, &data.Text, &data.Auteur, &data.Img_url, &data.Ctime, &data.Image)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata ORDER BY tijd DESC LIMIT 1")
	spin := SpinData{}
	rows.Next()
	rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
	buf,_ := json.Marshal(spin)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT batterij FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data int
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT mode FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data string
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata")
	data := []SpinData{}
	for rows.Next() {
		spin := SpinData{}
		rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
		data = append(data, spin)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata")
	data := make([]int, 0)
	var scanInt int
	for rows.Next() {
		rows.Scan(&scanInt)
		data = append(data, scanInt)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata")
	data := make([]string, 0)
	var scanStr string
	for rows.Next() {
		rows.Scan(&scanStr)
		data = append(data, scanStr)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM servodata ORDER BY tijd DESC LIMIT 1")
	servo := ServoData{}
	row.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
	buf,_ := json.Marshal(servo)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata")
	data := []ServoData{}
	for rows.Next() {
		servo := ServoData{}
		rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
		data = append(data, servo)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM logs")
	data := []LogData{}
	for rows.Next() {
		log := LogData{}
		rows.Scan(&log.Id, &log.Log)
		data = append(data, log)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func Test(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	buf,_ := json.Marshal("test")
	SetHeaders(&w)
	w.Write(buf)
}

func PostBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//r.ParseMultipartForm(32 << 20)
	/*file, handler, err := r.FormFile("uploadfile")
	defer file.Close()
	if err == nil {
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}

	err = nil*/

	//_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime, image) VALUES ($1, $2, $3, $4, $5)", r.FormValue("titel"), r.FormValue("text"), r.FormValue("auteur"), time.Now(), "http://idp-api.herokuapp.com/img/"+handler.Filename)
	_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime) VALUES ($1, $2, $3, $4)", r.FormValue("onderwerp"), r.FormValue("bericht"), r.FormValue("naam"), time.Now())
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(201)
	w.Write([]byte("<meta http-equiv=\"refresh\" content=\"1; url=http://knightspider.herokuapp.com/#/blog\">successful"))
}

func PostSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//reqStr, _ := httputil.DumpRequest(r, true)
	//w.Write([]byte(r.FormValue("mode")))
	//r.ParseForm()
	mode := r.FormValue("mode")
	hellingsgraad := r.FormValue("hellingsgraad")
	snelheid := r.FormValue("snelheid")
	batterij := r.FormValue("batterij")
	balloncount := r.FormValue("ballonCount")
	/*_,err := conn.Query("INSERT INTO spindata (tijd, mode, hellingsgraad, snelheid, batterij, balloncount) VALUES ($1, $2, $3, $4, $5, $6)", time.Now(),
		mode, hellingsgraad, snelheid, batterij, balloncount)
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, batterij, balloncount)))
		w.Write([]byte(err.Error()))
		return
	}*/
	w.WriteHeader(201)
	w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, snelheid = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, snelheid, batterij, balloncount)))
	//w.Write([]byte("successful"))
}

func PostServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO servodata (servo_id, tijd, voltage, positie, load, temperatuur) VALUES ($1, $2, $3, $4, $5, $6)",
		r.FormValue("servo_id"), time.Now(), r.FormValue("voltage"), r.FormValue("positie"), r.FormValue("load"), r.FormValue("Temperatuur"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

func PostLog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO logs (log) VALUES ($1)",
		r.FormValue("log"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	es.SendEventMessage(r.FormValue("log"), "log", "")
	w.WriteHeader(201)
	w.Write([]byte(r.FormValue("log")))
}

func Head(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	SetHeaders(&w)
	w.WriteHeader(204)
}

func main() {
	conn,_ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	defer conn.Close()

	es = eventsource.New(
		&eventsource.Settings{
			Timeout: 5 * time.Second,
			CloseOnTimeout: false,
			IdleTimeout: 30 * time.Minute,
		},
		func(req *http.Request) [][]byte {
			return [][]byte{
				[]byte("X-Accel-Buffering: no"),
				[]byte("Access-Control-Allow-Origin: *"),
			}
		},
	)
	defer es.Close()

	router := httprouter.New()
	router.HEAD("/*path", Head)
	router.GET("/test", Test)
	router.GET("/blog", GetBlog)
	router.GET("/blog/:id", GetPost)
	router.GET("/spin/latest", GetLatestSpinData)
	router.GET("/spin/latest/batterij", GetLatestSpinBatterij)
	router.GET("/spin/latest/mode", GetLatestSpinMode)
	router.GET("/spin/archive", GetArchivedSpinData)
	router.GET("/spin/archive/batterij", GetArchivedSpinBatterij)
	router.GET("/spin/archive/mode", GetArchivedSpinMode)
	router.GET("/servo/latest", GetLatestServoData)
	router.GET("/servo/archive", GetArchivedServoData)
	router.GET("/log", GetLogs)
	router.POST("/blog", PostBlog)
	router.POST("/spin", PostSpinData)
	router.POST("/servo", PostServoData)
	router.POST("/log", PostLog)

	http.Handle("/subscribe", es)
	http.Handle("/", router)

	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	fmt.Printf("Starting server at localhost:%s...", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}<commit_msg>postformvalue<commit_after>package main

import (
	"time"
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"net/http"
	//"net/http/httputil"
	"log"
	"os"
	//"io"
	"fmt"
	"database/sql"
	_ "github.com/lib/pq"
	"gopkg.in/antage/eventsource.v1"
)

var conn *sql.DB
var es eventsource.EventSource

func SetHeaders(w *http.ResponseWriter) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Content-Type", "application/json")
}

func GetBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog")
	data := []BlogPost{}
	for rows.Next() {
		post := BlogPost{}
		rows.Scan(&post.Id, &post.Titel, &post.Text, &post.Auteur, &post.Img_url, &post.Ctime, &post.Image)
		data = append(data, post)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM blog WHERE id = $1 LIMIT 1", ps.ByName("id"))
	data := BlogPost{}
	row.Scan(&data.Id, &data.Titel, &data.Text, &data.Auteur, &data.Img_url, &data.Ctime, &data.Image)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata ORDER BY tijd DESC LIMIT 1")
	spin := SpinData{}
	rows.Next()
	rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
	buf,_ := json.Marshal(spin)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT batterij FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data int
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT mode FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data string
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata")
	data := []SpinData{}
	for rows.Next() {
		spin := SpinData{}
		rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
		data = append(data, spin)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata")
	data := make([]int, 0)
	var scanInt int
	for rows.Next() {
		rows.Scan(&scanInt)
		data = append(data, scanInt)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata")
	data := make([]string, 0)
	var scanStr string
	for rows.Next() {
		rows.Scan(&scanStr)
		data = append(data, scanStr)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM servodata ORDER BY tijd DESC LIMIT 1")
	servo := ServoData{}
	row.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
	buf,_ := json.Marshal(servo)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata")
	data := []ServoData{}
	for rows.Next() {
		servo := ServoData{}
		rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
		data = append(data, servo)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM logs")
	data := []LogData{}
	for rows.Next() {
		log := LogData{}
		rows.Scan(&log.Id, &log.Log)
		data = append(data, log)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func Test(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	buf,_ := json.Marshal("test")
	SetHeaders(&w)
	w.Write(buf)
}

func PostBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//r.ParseMultipartForm(32 << 20)
	/*file, handler, err := r.FormFile("uploadfile")
	defer file.Close()
	if err == nil {
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}

	err = nil*/

	//_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime, image) VALUES ($1, $2, $3, $4, $5)", r.FormValue("titel"), r.FormValue("text"), r.FormValue("auteur"), time.Now(), "http://idp-api.herokuapp.com/img/"+handler.Filename)
	_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime) VALUES ($1, $2, $3, $4)", r.FormValue("onderwerp"), r.FormValue("bericht"), r.FormValue("naam"), time.Now())
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(201)
	w.Write([]byte("<meta http-equiv=\"refresh\" content=\"1; url=http://knightspider.herokuapp.com/#/blog\">successful"))
}

func PostSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//reqStr, _ := httputil.DumpRequest(r, true)
	//w.Write([]byte(r.FormValue("mode")))
	//r.ParseForm()
	mode := r.FormValue("mode")
	hellingsgraad := r.FormValue("hellingsgraad")
	snelheid := r.FormValue("snelheid")
	batterij := r.FormValue("batterij")
	balloncount := r.FormValue("ballonCount")
	/*_,err := conn.Query("INSERT INTO spindata (tijd, mode, hellingsgraad, snelheid, batterij, balloncount) VALUES ($1, $2, $3, $4, $5, $6)", time.Now(),
		mode, hellingsgraad, snelheid, batterij, balloncount)
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, batterij, balloncount)))
		w.Write([]byte(err.Error()))
		return
	}*/
	w.WriteHeader(201)
	w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, snelheid = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, snelheid, batterij, balloncount)))
	//w.Write([]byte("successful"))
}

func PostServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO servodata (servo_id, tijd, voltage, positie, load, temperatuur) VALUES ($1, $2, $3, $4, $5, $6)",
		r.FormValue("servo_id"), time.Now(), r.FormValue("voltage"), r.FormValue("positie"), r.FormValue("load"), r.FormValue("Temperatuur"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

func PostLog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO logs (log) VALUES ($1)",
		r.FormValue("log"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	es.SendEventMessage(r.FormValue("log"), "log", "")
	w.WriteHeader(201)
	w.Write([]byte(r.FormValue("log")))
}

func Head(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	SetHeaders(&w)
	w.WriteHeader(204)
}

func main() {
	conn,_ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	defer conn.Close()

	es = eventsource.New(
		&eventsource.Settings{
			Timeout: 5 * time.Second,
			CloseOnTimeout: false,
			IdleTimeout: 30 * time.Minute,
		},
		func(req *http.Request) [][]byte {
			return [][]byte{
				[]byte("X-Accel-Buffering: no"),
				[]byte("Access-Control-Allow-Origin: *"),
			}
		},
	)
	defer es.Close()

	router := httprouter.New()
	router.HEAD("/*path", Head)
	router.GET("/test", Test)
	router.GET("/blog", GetBlog)
	router.GET("/blog/:id", GetPost)
	router.GET("/spin/latest", GetLatestSpinData)
	router.GET("/spin/latest/batterij", GetLatestSpinBatterij)
	router.GET("/spin/latest/mode", GetLatestSpinMode)
	router.GET("/spin/archive", GetArchivedSpinData)
	router.GET("/spin/archive/batterij", GetArchivedSpinBatterij)
	router.GET("/spin/archive/mode", GetArchivedSpinMode)
	router.GET("/servo/latest", GetLatestServoData)
	router.GET("/servo/archive", GetArchivedServoData)
	router.GET("/log", GetLogs)
	router.POST("/blog", PostBlog)
	router.POST("/spin", PostSpinData)
	router.POST("/servo", PostServoData)
	router.POST("/log", PostLog)

	http.Handle("/subscribe", es)
	http.Handle("/", router)

	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	fmt.Printf("Starting server at localhost:%s...", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

var pattern = regexp.MustCompile(`^(MemFree|Buffers|Cached): + (\d+) kB`)

func gradient(shades uint, max_value uint) func(val uint) string {
	var (
		colors              = make([]string, shades)
		breakpoints         = make([]uint, shades-1)
		step                = max_value / shades
		scale       float32 = 255 / (float32(max_value) / 2)
	)

	color := func(val uint) string {
		switch {
		case val < step:
			// red
			return "#FF0000"
		case val >= step*(shades-1):
			// green
			return "#00FF00"
		case val < max_value/2:
			// red-ish
			return fmt.Sprintf("#FF%02X00", uint(float32(val)*scale))
		default:
			// green-ish
			return fmt.Sprintf("#%02XFF00", uint(255-(float32(val)-float32(max_value/2-step))*scale))
		}
	}

	for i := uint(0); i < shades-1; i++ {
		breakpoints[i] = step * (i + 1)
	}

	for i := uint(0); i < shades; i++ {
		colors[i] = color(step * i)
	}

	out := func(val uint) string {
		if val <= breakpoints[0] {
			return colors[0]
		} else if val > breakpoints[len(breakpoints)-1] {
			return colors[len(colors)-1]
		}

		for i := 0; i < len(breakpoints); i++ {
			if val > breakpoints[i] && val <= breakpoints[i+1] {
				return colors[i+1]
			}
		}

		log.Println("failed to determine color")
		return ""
	}

	return out
}

func getFreeMemory() (freeMemory uint) {
	file, err := os.Open("/proc/meminfo")

	if err != nil {
		log.Println(err)
		freeMemory = 0
		return
	}

	defer file.Close()

	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		line := scanner.Text()

		if pattern.MatchString(line) {
			memory := (pattern.FindAllStringSubmatch(line, -1)[0][2])
			tmp, err := strconv.ParseUint(memory, 10, 32)

			if err != nil {
				log.Println(err)
				continue
			}

			freeMemory += uint(tmp)
		}
	}

	// Return free memory in MB.
	freeMemory /= 1024
	return
}

func main() {
	type Element struct {
		FullText            string `json:"full_text"`
		ShortText           string `json:"short_text,omitempty"`
		Color               string `json:"color,omitempty"`
		MinWidth            string `json:"min_width,omitempty"`
		Align               string `json:"align,omitempty"`
		Name                string `json:"name"`
		Instance            string `json:"instance,omitempty"`
		Urgent              string `json:"urgent,omitempty"`
		Separator           string `json:"separator,omitempty"`
		SeparatorBlockWidth string `json:"separator_block_width,omitempty"`
	}

	var (
		buffer   bytes.Buffer
		status   []Element
		colorize = gradient(4, 1024)
	)

	scanner := bufio.NewScanner(os.Stdin)

	// Skip the first line which contains the version header.
	if scanner.Scan() {
		if _, err := buffer.WriteString(scanner.Text()); err != nil {
			log.Fatal(err)
		}
	}

	// The second line contains the start of the infinite array.
	if scanner.Scan() {
		if _, err := buffer.WriteString(scanner.Text()); err != nil {
			log.Fatal(err)
		}
	}

	for scanner.Scan() {
		line, prefix := scanner.Text(), ""

		// Remember the comma at the beginning of the line.
		if strings.HasPrefix(line, ",") {
			line, prefix = line[1:], ","
		}

		if _, err := buffer.WriteString(prefix); err != nil {
			log.Println(err)
			continue
		}

		freeMemory := getFreeMemory()

		memoryElement := Element{
			FullText: fmt.Sprintf("Mem: %d MB", freeMemory),
			Name:     "mem_info",
			Color:    colorize(freeMemory),
		}

		dec := json.NewDecoder(strings.NewReader(line))

		if err := dec.Decode(&status); err != nil {
			log.Println(err)
			continue
		}

		// Prepend the memory element.
		status = append([]Element{memoryElement}, status...)

		out, err := json.Marshal(status)

		if err != nil {
			log.Println(err)
			continue
		}

		buffer.Write(out)
		buffer.WriteTo(os.Stdout)

		// Reset output.
		status = []Element{}
	}
}
<commit_msg>use MemAvailable from /proc/meminfo<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

var pattern = regexp.MustCompile(`^MemAvailable: +(\d+) kB`)

func gradient(shades uint, max_value uint) func(val uint) string {
	var (
		colors              = make([]string, shades)
		breakpoints         = make([]uint, shades-1)
		step                = max_value / shades
		scale       float32 = 255 / (float32(max_value) / 2)
	)

	color := func(val uint) string {
		switch {
		case val < step:
			// red
			return "#FF0000"
		case val >= step*(shades-1):
			// green
			return "#00FF00"
		case val < max_value/2:
			// red-ish
			return fmt.Sprintf("#FF%02X00", uint(float32(val)*scale))
		default:
			// green-ish
			return fmt.Sprintf("#%02XFF00", uint(255-(float32(val)-float32(max_value/2-step))*scale))
		}
	}

	for i := uint(0); i < shades-1; i++ {
		breakpoints[i] = step * (i + 1)
	}

	for i := uint(0); i < shades; i++ {
		colors[i] = color(step * i)
	}

	out := func(val uint) string {
		if val <= breakpoints[0] {
			return colors[0]
		} else if val > breakpoints[len(breakpoints)-1] {
			return colors[len(colors)-1]
		}

		for i := 0; i < len(breakpoints); i++ {
			if val > breakpoints[i] && val <= breakpoints[i+1] {
				return colors[i+1]
			}
		}

		log.Println("failed to determine color")
		return ""
	}

	return out
}

func getFreeMemory() (freeMemory uint) {
	file, err := os.Open("/proc/meminfo")

	if err != nil {
		log.Println(err)
		freeMemory = 0
		return
	}

	defer file.Close()

	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		line := scanner.Text()

		if pattern.MatchString(line) {
			memory := (pattern.FindAllStringSubmatch(line, -1)[0][1])
			tmp, err := strconv.ParseUint(memory, 10, 32)

			if err != nil {
				log.Println(err)
				continue
			}

			freeMemory = uint(tmp)
			break
		}
	}

	// Return free memory in MB.
	freeMemory /= 1024
	return
}

func main() {
	type Element struct {
		FullText            string `json:"full_text"`
		ShortText           string `json:"short_text,omitempty"`
		Color               string `json:"color,omitempty"`
		MinWidth            string `json:"min_width,omitempty"`
		Align               string `json:"align,omitempty"`
		Name                string `json:"name"`
		Instance            string `json:"instance,omitempty"`
		Urgent              string `json:"urgent,omitempty"`
		Separator           string `json:"separator,omitempty"`
		SeparatorBlockWidth string `json:"separator_block_width,omitempty"`
	}

	var (
		buffer   bytes.Buffer
		status   []Element
		colorize = gradient(4, 1024)
	)

	scanner := bufio.NewScanner(os.Stdin)

	// Skip the first line which contains the version header.
	if scanner.Scan() {
		if _, err := buffer.WriteString(scanner.Text()); err != nil {
			log.Fatal(err)
		}
	}

	// The second line contains the start of the infinite array.
	if scanner.Scan() {
		if _, err := buffer.WriteString(scanner.Text()); err != nil {
			log.Fatal(err)
		}
	}

	for scanner.Scan() {
		line, prefix := scanner.Text(), ""

		// Remember the comma at the beginning of the line.
		if strings.HasPrefix(line, ",") {
			line, prefix = line[1:], ","
		}

		if _, err := buffer.WriteString(prefix); err != nil {
			log.Println(err)
			continue
		}

		freeMemory := getFreeMemory()

		memoryElement := Element{
			FullText: fmt.Sprintf("Mem: %d MB", freeMemory),
			Name:     "mem_info",
			Color:    colorize(freeMemory),
		}

		dec := json.NewDecoder(strings.NewReader(line))

		if err := dec.Decode(&status); err != nil {
			log.Println(err)
			continue
		}

		// Prepend the memory element.
		status = append([]Element{memoryElement}, status...)

		out, err := json.Marshal(status)

		if err != nil {
			log.Println(err)
			continue
		}

		buffer.Write(out)
		buffer.WriteTo(os.Stdout)

		// Reset output.
		status = []Element{}
	}
}
<|endoftext|>


<commit_before>// Lab2_file_database project main.go
package main

import (
	"bufio"
	"bytes"
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
)

type cache struct {
	tables []table
}

type Person struct {
	XMLName xml.Name `xml:"person"`
	Name    string   `xml:"name"`
	Age     int      `xml:"age"`
}

type People struct {
	XMLName xml.Name `xml:"people"`
	People  []Person `xml:"person"`
}

func ReadEntries(reader io.Reader) ([]Person, error) {
	var people People
	if err := xml.NewDecoder(reader).Decode(&people); err != nil {
		return nil, err
	}

	return people.People, nil
}

func FlushDatabase(writer io.Writer, xmlEntries People) error {
	if err := xml.NewEncoder(writer).Encode(xmlEntries); err != nil {
		return err
	}

	return nil
}

func (c *cache) get(name string) *table {
	//Проверяем есть ли таблицца на оперативке
	fmt.Println("Try to get table")
	for _, t := range c.tables {
		if t.name == name {
			fmt.Println("table find in cache")
			return &t
		}
	}
	//Пытаемся загрузить базу из файлововой системы
	f, err := os.Open(name)
	if err == nil {
		data := make([][]string, 0, 0)
		r := csv.NewReader(bufio.NewReader(f))

		for {
			record, err := r.Read()
			// Stop at EOF.
			if err == io.EOF {
				break
			}

			row_data := []string{record[0], record[1]}
			data = append(data, row_data)
		}
		t := table{name: name, data: &data}
		c.tables = append(c.tables, t)
		return &t
	}
	//Ну и если ни черта не вышло создаем пустую базу
	t := table{name: name, data: new([][]string)}
	c.tables = append(c.tables, t)
	fmt.Println("table returned")
	return &t
}

type table struct {
	isLocked sync.Mutex
	name     string
	data     *[][]string
}

func (t *table) save() {
	//	for t.isLocked {

	//	}

	t.isLocked.Lock()
	file, _ := os.Create(t.name)
	defer file.Close()
	for _, row := range *t.data {
		file.WriteString(row[0] + "," + row[1] + "\n")
	}
	t.isLocked.Unlock()
}

const (
	CONN_HOST = "localhost"
	CONN_PORT = "8888"
	CONN_TYPE = "tcp"
)

//func main() {
//	// Listen for incoming connections.
//	c := cache{}
//	l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
//	if err != nil {
//		fmt.Println("Error listening:", err.Error())
//		os.Exit(1)
//	}
//	// Close the listener when the application closes.
//	defer l.Close()
//	fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
//	for {
//		// Listen for an incoming connection.
//		conn, err := l.Accept()
//		fmt.Println("accept")
//
//		if err != nil {
//			fmt.Println("Error accepting: ", err.Error())
//			os.Exit(1)
//		}
//		// Handle connections in a new goroutine.
//		go handleConnection(conn, &c)
//	}
//}

// Handles incoming requests.
func handleConnection(conn net.Conn, c *cache) {
	// Make a buffer to hold incoming data.
	var buf [512]byte
	empty_string := ""
	for {
		copy(buf[:], empty_string) //make  buffer empty
		_, err := conn.Read(buf[0:])
		if err != nil {
			return
		}
		n := bytes.Index(buf[:], []byte{0})
		s := string(buf[:n])
		go handleRequest(s, c, conn)
	}
}

func handleRequest(command string, c *cache, conn net.Conn) {
	fmt.Println("handle request: " + command)

	params := strings.Fields(command)
	// remove empty entries and remove whitespaces
	fmt.Println(params)
	fmt.Println(params[0])
	// remove empty entries and remove whitespaces
	switch strings.ToLower(params[0]) {
	case "exit":
		os.Exit(0)
	case "insert":
		fmt.Println("switching")

		fmt.Println("insert")
		insert_regex := regexp.MustCompile(`^insert\s+\w+\s+\w+\s+into\s+[A-z]+[A-z_0-9]*`)
		if insert_regex.MatchString(command) {
			t := c.get(params[4])
			t.insert_(params[1], params[2])

		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
	case "select":
		fmt.Println("try to select")
		select_regex := regexp.MustCompile(`^select\s+\w+\s+from\s+[A-z]+[A-z_0-9]*`)
		if select_regex.MatchString(command) {

			t := c.get(params[3])
			data := ""
			for _, elem := range t.select_(params[1]) {
				data += elem + " "
				conn.Write([]byte(string(elem) + " "))

			}
			conn.Write([]byte("\n"))

			fmt.Println(data + "\n newline was sended")
		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
		fmt.Println("select")
	case "delete":
		delete_regex := regexp.MustCompile(`^delete\s+\w+\s+in\s+[A-z]+[A-z_0-9]*`)
		if delete_regex.MatchString(command) {
			t := c.get(params[3])
			t.delete_(params[1])
		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
		fmt.Println("delete")

	case "update":
		update_regex := regexp.MustCompile(`^update\s+\w+\s+to\s+\w+\s+in\s+[A-z]+[A-z_0-9]*`)
		if update_regex.MatchString(command) {
			t := c.get(params[5])
			t.update_(params[1], params[3])
		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
		fmt.Println("update")
	default:
		conn.Write([]byte(string("Your command didn't match the pattern\n")))
	}
}

func (t *table) insert_(key string, value string) {
	row := []string{key, value}
	//Возможное место для мютекса
	fmt.Println(t.data)
	t.additem(row)
	fmt.Println(t.data)
	go t.save()
}
func (t *table) additem(value []string) {
	*t.data = append(*t.data, value)
}

func (t *table) select_(key string) []string {
	selecting_data := []string{}
	fmt.Println(*t.data)
	for _, row := range *t.data {
		if row[0] == key {
			selecting_data = append(selecting_data, row[1])
		}
	}

	return selecting_data
}

func (p *People) selectByKey(key name) []int {
	selecting_data := []int{}

	for _, item := range p.People {
		if item.Name == name {
			selecting_data = append(selecting_data, item.Age)
		}
	}
	return selecting_data
}

func (p *People) deleteByKey(name string) {
	for index := 0; index < len(p.People); index++ {
		if p.People[index].Name == name {
			p.People = append((p.People)[:index], (p.People)[index+1:]...)
		}
	}
}

func (p *People) updateByKey(name string, age int) {
	for index := 0; index < len(p.People); index++ {
		if p.People[index].Name == name {
			p.People[index].Age = age
		}
	}
}

func (p *People) addItem(name string, age int) {
	human := Person{Name: name, Age: age}
	p.People = append(p.People, human)
}

func (t *table) delete_(key string) {
	for index := 0; index < len(*t.data); index++ {
		if (*t.data)[index][0] == key {
			*t.data = append((*t.data)[:index], (*t.data)[index+1:]...)
		}
	}
	go t.save()
}

func (t *table) update_(key string, value string) {
	for i, row := range *t.data {
		if row[0] == key {
			(*t.data)[i][1] = value
		}

	}
	go t.save()
}

func main() {
	// Build the location of the straps.xml file
	// filepath.Abs appends the file name to the default working directly
	strapsFilePath, err := filepath.Abs("entries.xml")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Open the container file
	file, err := os.Open(strapsFilePath)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Parse entries
	entries, err := ReadEntries(file)
	file.Close()

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

	a := Person{Name: "Vasya", Age: 25}

	entries = append(entries, a)

	humans := People{People: entries}

	fmt.Print("++++++++++++++++++++++++++++++++++++++++++++")
	tmp := humans.selectByKey("Vasya")
	fmt.Printf("Age: %2d\n", tmp)
	humans.updateByKey("Vasya", 34)
	fmt.Print("++++++++++++++++++++++++++++++++++++++++++++")
	tmp = humans.selectByKey("Vasya")
	fmt.Printf("Age: %2d\n", tmp)
	humans.deleteByKey("Vasya")
	fmt.Print("++++++++++++++++++++++++++++++++++++++++++++")
	tmp = humans.selectByKey("Vasya")
	fmt.Printf("Age: %2d\n", tmp)
	humans.addItem("Vasya", 25)
	fmt.Print("++++++++++++++++++++++++++++++++++++++++++++")
	tmp = humans.selectByKey("Vasya")
	fmt.Printf("Age: %2d\n", tmp)
	res := People{People: entries}
	fileToWrite, err := os.Create("result.xml")

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	FlushDatabase(fileToWrite, res)

	for _, person := range humans.People {
		// index is the index where we are
		// element is the element from someSlice for where we are
		fmt.Printf("Name: %6s  Age: %2d\n", person.Name, person.Age)
	}
	// Display The first strap
}
<commit_msg>+ add ToString method + fix parameter + remake test output<commit_after>// Lab2_file_database project main.go
package main

import (
	"bufio"
	"bytes"
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
)

type cache struct {
	tables []table
}

type Person struct {
	XMLName xml.Name `xml:"person"`
	Name    string   `xml:"name"`
	Age     int      `xml:"age"`
}

func (p Person) String() string {
	return fmt.Sprintf("{Name: %s, Age: %d}", p.Name, p.Age)
}

type People struct {
	XMLName xml.Name `xml:"people"`
	People  []Person `xml:"person"`
}

func ReadEntries(reader io.Reader) ([]Person, error) {
	var people People
	if err := xml.NewDecoder(reader).Decode(&people); err != nil {
		return nil, err
	}

	return people.People, nil
}

func FlushDatabase(writer io.Writer, xmlEntries People) error {
	if err := xml.NewEncoder(writer).Encode(xmlEntries); err != nil {
		return err
	}

	return nil
}

func (c *cache) get(name string) *table {
	//Проверяем есть ли таблицца на оперативке
	fmt.Println("Try to get table")
	for _, t := range c.tables {
		if t.name == name {
			fmt.Println("table find in cache")
			return &t
		}
	}
	//Пытаемся загрузить базу из файлововой системы
	f, err := os.Open(name)
	if err == nil {
		data := make([][]string, 0, 0)
		r := csv.NewReader(bufio.NewReader(f))

		for {
			record, err := r.Read()
			// Stop at EOF.
			if err == io.EOF {
				break
			}

			row_data := []string{record[0], record[1]}
			data = append(data, row_data)
		}
		t := table{name: name, data: &data}
		c.tables = append(c.tables, t)
		return &t
	}
	//Ну и если ни черта не вышло создаем пустую базу
	t := table{name: name, data: new([][]string)}
	c.tables = append(c.tables, t)
	fmt.Println("table returned")
	return &t
}

type table struct {
	isLocked sync.Mutex
	name     string
	data     *[][]string
}

func (t *table) save() {
	//	for t.isLocked {

	//	}

	t.isLocked.Lock()
	file, _ := os.Create(t.name)
	defer file.Close()
	for _, row := range *t.data {
		file.WriteString(row[0] + "," + row[1] + "\n")
	}
	t.isLocked.Unlock()
}

const (
	CONN_HOST = "localhost"
	CONN_PORT = "8888"
	CONN_TYPE = "tcp"
)

//func main() {
//	// Listen for incoming connections.
//	c := cache{}
//	l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
//	if err != nil {
//		fmt.Println("Error listening:", err.Error())
//		os.Exit(1)
//	}
//	// Close the listener when the application closes.
//	defer l.Close()
//	fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
//	for {
//		// Listen for an incoming connection.
//		conn, err := l.Accept()
//		fmt.Println("accept")
//
//		if err != nil {
//			fmt.Println("Error accepting: ", err.Error())
//			os.Exit(1)
//		}
//		// Handle connections in a new goroutine.
//		go handleConnection(conn, &c)
//	}
//}

// Handles incoming requests.
func handleConnection(conn net.Conn, c *cache) {
	// Make a buffer to hold incoming data.
	var buf [512]byte
	empty_string := ""
	for {
		copy(buf[:], empty_string) //make  buffer empty
		_, err := conn.Read(buf[0:])
		if err != nil {
			return
		}
		n := bytes.Index(buf[:], []byte{0})
		s := string(buf[:n])
		go handleRequest(s, c, conn)
	}
}

func handleRequest(command string, c *cache, conn net.Conn) {
	fmt.Println("handle request: " + command)

	params := strings.Fields(command)
	// remove empty entries and remove whitespaces
	fmt.Println(params)
	fmt.Println(params[0])
	// remove empty entries and remove whitespaces
	switch strings.ToLower(params[0]) {
	case "exit":
		os.Exit(0)
	case "insert":
		fmt.Println("switching")

		fmt.Println("insert")
		insert_regex := regexp.MustCompile(`^insert\s+\w+\s+\w+\s+into\s+[A-z]+[A-z_0-9]*`)
		if insert_regex.MatchString(command) {
			t := c.get(params[4])
			t.insert_(params[1], params[2])

		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
	case "select":
		fmt.Println("try to select")
		select_regex := regexp.MustCompile(`^select\s+\w+\s+from\s+[A-z]+[A-z_0-9]*`)
		if select_regex.MatchString(command) {

			t := c.get(params[3])
			data := ""
			for _, elem := range t.select_(params[1]) {
				data += elem + " "
				conn.Write([]byte(string(elem) + " "))

			}
			conn.Write([]byte("\n"))

			fmt.Println(data + "\n newline was sended")
		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
		fmt.Println("select")
	case "delete":
		delete_regex := regexp.MustCompile(`^delete\s+\w+\s+in\s+[A-z]+[A-z_0-9]*`)
		if delete_regex.MatchString(command) {
			t := c.get(params[3])
			t.delete_(params[1])
		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
		fmt.Println("delete")

	case "update":
		update_regex := regexp.MustCompile(`^update\s+\w+\s+to\s+\w+\s+in\s+[A-z]+[A-z_0-9]*`)
		if update_regex.MatchString(command) {
			t := c.get(params[5])
			t.update_(params[1], params[3])
		} else {
			conn.Write([]byte(string("Your command didn't match the pattern\n")))
		}
		fmt.Println("update")
	default:
		conn.Write([]byte(string("Your command didn't match the pattern\n")))
	}
}

func (t *table) insert_(key string, value string) {
	row := []string{key, value}
	//Возможное место для мютекса
	fmt.Println(t.data)
	t.additem(row)
	fmt.Println(t.data)
	go t.save()
}
func (t *table) additem(value []string) {
	*t.data = append(*t.data, value)
}

func (t *table) select_(key string) []string {
	selecting_data := []string{}
	fmt.Println(*t.data)
	for _, row := range *t.data {
		if row[0] == key {
			selecting_data = append(selecting_data, row[1])
		}
	}

	return selecting_data
}

func (p *People) selectByKey(name string) []Person {
	selecting_data := []Person{}

	for _, item := range p.People {
		if item.Name == name {
			selecting_data = append(selecting_data, item)
		}
	}
	return selecting_data
}

func (p *People) deleteByKey(name string) {
	for index := 0; index < len(p.People); index++ {
		if p.People[index].Name == name {
			p.People = append((p.People)[:index], (p.People)[index + 1:]...)
		}
	}
}

func (p *People) updateByKey(name string, age int) {
	for index := 0; index < len(p.People); index++ {
		if p.People[index].Name == name {
			p.People[index].Age = age
		}
	}
}

func (p *People) addItem(name string, age int) {
	human := Person{Name: name, Age: age}
	p.People = append(p.People, human)
}

func (t *table) delete_(key string) {
	for index := 0; index < len(*t.data); index++ {
		if (*t.data)[index][0] == key {
			*t.data = append((*t.data)[:index], (*t.data)[index + 1:]...)
		}
	}
	go t.save()
}

func (t *table) update_(key string, value string) {
	for i, row := range *t.data {
		if row[0] == key {
			(*t.data)[i][1] = value
		}

	}
	go t.save()
}

func main() {
	// Build the location of the straps.xml file
	// filepath.Abs appends the file name to the default working directly
	strapsFilePath, err := filepath.Abs("entries.xml")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Open the container file
	file, err := os.Open(strapsFilePath)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Parse entries
	entries, err := ReadEntries(file)
	file.Close()

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

	a := Person{Name: "Vasya", Age: 25}

	entries = append(entries, a)

	humans := People{People: entries}

	fmt.Println("Select by key Vasya:")
	tmp := humans.selectByKey("Vasya")
	fmt.Println(tmp)

	humans.updateByKey("Vasya", 34)
	fmt.Println("Update by key Vasya:")
	tmp = humans.selectByKey("Vasya")
	fmt.Println(tmp)

	fmt.Println("Delete by key Vasya(should return nothing):")
	humans.deleteByKey("Vasya")
	tmp = humans.selectByKey("Vasya")
	fmt.Println(tmp)

	fmt.Println("Adding with key Vasya:")
	humans.addItem("Vasya", 25)
	tmp = humans.selectByKey("Vasya")
	fmt.Println(tmp)

	res := People{People: entries}
	fileToWrite, err := os.Create("result.xml")

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	FlushDatabase(fileToWrite, res)

	fmt.Println("Printing loaded data from xml:")

	for _, person := range humans.People {
		// index is the index where we are
		// element is the element from someSlice for where we are
		fmt.Println(person)
	}
	// Display The first strap
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"text/template"
	"sync"
	"time"
	"net"

	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
)

//////////////////////
//HUB
/////////////////////
type hub struct {
	// the mutex to protect connections
	connectionsMx sync.RWMutex

	// Registered connections.
	connections map[*connection]struct{}

	// Inbound messages from the connections.
	broadcast chan []byte

	logMx sync.RWMutex
	log   [][]byte
}

func newHub() *hub {
	h := &hub{
		connectionsMx: sync.RWMutex{},
		broadcast:     make(chan []byte),
		connections:   make(map[*connection]struct{}),
	}

	go func() {
		for {
			msg := <-h.broadcast
			h.connectionsMx.RLock()
			for c := range h.connections {
				select {
				case c.send <- msg:
				// stop trying to send to this connection after trying for 1 second.
				// if we have to stop, it means that a reader died so remove the connection also.
				case <-time.After(1 * time.Second):
					log.Printf("shutting down connection %s", c)
					h.removeConnection(c)
				}
			}
			h.connectionsMx.RUnlock()
		}
	}()
	return h
}

func (h *hub) addConnection(conn *connection) {
	h.connectionsMx.Lock()
	defer h.connectionsMx.Unlock()
	h.connections[conn] = struct{}{}
}

func (h *hub) removeConnection(conn *connection) {
	h.connectionsMx.Lock()
	defer h.connectionsMx.Unlock()
	if _, ok := h.connections[conn]; ok {
		delete(h.connections, conn)
		close(conn.send)
	}
}

//////////////////////
//CONNECTIONS
/////////////////////

type connection struct {
	// Buffered channel of outbound messages.
	send chan []byte

	// The hub.
	h *hub
}

func (c *connection) reader(wg *sync.WaitGroup, wsConn *websocket.Conn) {
	defer wg.Done()
	for {
		_, message, err := wsConn.ReadMessage()
		if err != nil {
			break
		}
		c.h.broadcast <- message
	}
}

func (c *connection) writer(wg *sync.WaitGroup, wsConn *websocket.Conn) {
	defer wg.Done()
	for message := range c.send {
		err := wsConn.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			break
		}
	}
}

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}

type wsHandler struct {
	h *hub
}

func (wsh wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	//BAN USERS HERE!
	//Update ip's with syntax "HOST:PORT"
	var bannedIp []string
	bannedIp = append(bannedIp, "")
	/////////////
	//Finds user IP
	ip,_,_ := net.SplitHostPort(r.RemoteAddr)
	log.Printf("%s has connected.", ip)

	//Checks to see if user IP matches slice of banned IP's
	for i := range bannedIp{
		if bannedIp[i] == ip{
			log.Printf("%s has been banned from the web server", ip)
			http.Error(w, "BANNED", http.StatusUnauthorized)
			return
		}
	}
	//////////

	wsConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Printf("error upgrading %s", err)
		return
	}
	c := &connection{send: make(chan []byte, 256), h: wsh.h}
	c.h.addConnection(c)
	defer c.h.removeConnection(c)
	var wg sync.WaitGroup
	wg.Add(2)
	go c.writer(&wg, wsConn)
	go c.reader(&wg, wsConn)
	wg.Wait()
	wsConn.Close()
}

//////////////////////
//MAIN
/////////////////////

type user struct {
	UserName string
	Pass string
	First string
	Last string
}

var dbUsers = map[string]user{}
var dbSessions = map[string]string{}
var tpl *template.Template

func init() {
	tpl = template.Must(template.ParseGlob("templates/*"))
	dbUsers["EthanBB13@gmail.com"] = user{"EthanBB13@gmail.com", "eth787878", "Ethan", "Garnier"}
}

func login(w http.ResponseWriter, req *http.Request)  {
	if req.Method == http.MethodPost{
		un := req.FormValue("username")
		p := req.FormValue("password")
		//Does this user exist?? Using comma ok idiom
		u, ok := dbUsers[un]
		if !ok{
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}
		//does the username/password combo match at all??
		if u.Pass != p{
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}
		//Create a session
		sID := uuid.NewV4()
		c := &http.Cookie{
			Name: "session",
			Value: sID.String(),
			HttpOnly: true,
		}
		http.SetCookie(w, c)
		dbSessions[c.Value] = un
		http.Redirect(w, req, "/", http.StatusSeeOther)
		return
	}

	tpl.ExecuteTemplate(w, "login.gohtml", nil)
}

func homeHandler(tpl *template.Template) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tpl.Execute(w, r)
	})
}

func main() {
	flag.Parse()
	tpl := template.Must(template.ParseFiles("templates/chat.html"))
	h := newHub()
	router := http.NewServeMux()
	//router.HandleFunc("/", home)
	router.HandleFunc("/login", login)
	router.Handle("/chat", homeHandler(tpl))
	router.Handle("/ws", wsHandler{h: h} )
	log.Println("serving on port 8080")
	log.Fatal(http.ListenAndServe(":8080", router))
}

//TODO: Here is a comment, current build is not user friendly!!
//TODO: Build a home function where users can be redirected to and from login, signup and the chat
//TODO: Add redirecting links to gohtml files
//TODO: Make chat.html into "gohtml"
<commit_msg>Proper login now redirects to chat page<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"text/template"
	"sync"
	"time"
	"net"

	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
)

//////////////////////
//HUB
/////////////////////
type hub struct {
	// the mutex to protect connections
	connectionsMx sync.RWMutex

	// Registered connections.
	connections map[*connection]struct{}

	// Inbound messages from the connections.
	broadcast chan []byte

	logMx sync.RWMutex
	log   [][]byte
}

func newHub() *hub {
	h := &hub{
		connectionsMx: sync.RWMutex{},
		broadcast:     make(chan []byte),
		connections:   make(map[*connection]struct{}),
	}

	go func() {
		for {
			msg := <-h.broadcast
			h.connectionsMx.RLock()
			for c := range h.connections {
				select {
				case c.send <- msg:
				// stop trying to send to this connection after trying for 1 second.
				// if we have to stop, it means that a reader died so remove the connection also.
				case <-time.After(1 * time.Second):
					log.Printf("shutting down connection %s", c)
					h.removeConnection(c)
				}
			}
			h.connectionsMx.RUnlock()
		}
	}()
	return h
}

func (h *hub) addConnection(conn *connection) {
	h.connectionsMx.Lock()
	defer h.connectionsMx.Unlock()
	h.connections[conn] = struct{}{}
}

func (h *hub) removeConnection(conn *connection) {
	h.connectionsMx.Lock()
	defer h.connectionsMx.Unlock()
	if _, ok := h.connections[conn]; ok {
		delete(h.connections, conn)
		close(conn.send)
	}
}

//////////////////////
//CONNECTIONS
/////////////////////

type connection struct {
	// Buffered channel of outbound messages.
	send chan []byte

	// The hub.
	h *hub
}

func (c *connection) reader(wg *sync.WaitGroup, wsConn *websocket.Conn) {
	defer wg.Done()
	for {
		_, message, err := wsConn.ReadMessage()
		if err != nil {
			break
		}
		c.h.broadcast <- message
	}
}

func (c *connection) writer(wg *sync.WaitGroup, wsConn *websocket.Conn) {
	defer wg.Done()
	for message := range c.send {
		err := wsConn.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			break
		}
	}
}

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}

type wsHandler struct {
	h *hub
}

func (wsh wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	//BAN USERS HERE!
	//Update ip's with syntax "HOST:PORT"
	var bannedIp []string
	bannedIp = append(bannedIp, "")
	/////////////
	//Finds user IP
	ip,_,_ := net.SplitHostPort(r.RemoteAddr)
	log.Printf("%s has connected.", ip)

	//Checks to see if user IP matches slice of banned IP's
	for i := range bannedIp{
		if bannedIp[i] == ip{
			log.Printf("%s has been banned from the web server", ip)
			http.Error(w, "BANNED", http.StatusUnauthorized)
			return
		}
	}
	//////////

	wsConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Printf("error upgrading %s", err)
		return
	}
	c := &connection{send: make(chan []byte, 256), h: wsh.h}
	c.h.addConnection(c)
	defer c.h.removeConnection(c)
	var wg sync.WaitGroup
	wg.Add(2)
	go c.writer(&wg, wsConn)
	go c.reader(&wg, wsConn)
	wg.Wait()
	wsConn.Close()
}

//////////////////////
//MAIN
/////////////////////

type user struct {
	UserName string
	Pass string
	First string
	Last string
}

var dbUsers = map[string]user{}
var dbSessions = map[string]string{}
var tpl *template.Template

func init() {
	tpl = template.Must(template.ParseGlob("templates/*"))
	dbUsers["Test"] = user{"Test", "eth787878", "Ethan", "Garnier"}
}

func login(w http.ResponseWriter, req *http.Request)  {
	if req.Method == http.MethodPost{
		un := req.FormValue("username")
		p := req.FormValue("password")
		//Does this user exist?? Using comma ok idiom
		u, ok := dbUsers[un]
		if !ok{
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}
		//does the username/password combo match at all??
		if u.Pass != p{
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}
		//Create a session
		sID := uuid.NewV4()
		c := &http.Cookie{
			Name: "session",
			Value: sID.String(),
			HttpOnly: true,
		}
		http.SetCookie(w, c)
		dbSessions[c.Value] = un
		http.Redirect(w, req, "/chat", http.StatusSeeOther)
		return
	}

	tpl.ExecuteTemplate(w, "login.gohtml", nil)
}

func homeHandler(tpl *template.Template) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tpl.Execute(w, r)
	})
}

func main() {
	flag.Parse()
	tpl := template.Must(template.ParseFiles("templates/chat.html"))
	h := newHub()
	router := http.NewServeMux()
	//router.HandleFunc("/signup", singup)
	router.HandleFunc("/", login)
	router.Handle("/chat", homeHandler(tpl))
	router.Handle("/ws", wsHandler{h: h} )
	log.Println("serving on port 8080")
	log.Fatal(http.ListenAndServe(":8080", router))
}

//TODO: Here is a comment, current build is not user friendly!!
//TODO: Build a home function where users can be redirected to and from login, signup and the chat
//TODO: Add redirecting links to gohtml files
//TODO: Make chat.html into "gohtml"
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"fmt"
	"time"
	"os"
)

const version string = "1.0.1"

// subtract process startup overhead from requested duration
const delay = time.Duration(10 * time.Millisecond)

// command line flags
var showVersion bool

func init() {
	flag.BoolVar(&showVersion, "version", false, "print version and exit")
}

func main() {
	log.SetFlags(0)
	flag.Parse()
	setCustomUsage()

	if showVersion {
		fmt.Println("sleep version", version)
	} else {
		if flag.NArg() != 1 {
			flag.Usage()
		}
		d, err := time.ParseDuration(flag.Arg(0)+"s")
		if err != nil {
			log.Fatalln(err)
		}
		time.Sleep(d - delay)
	}
}

// Redefines flag.Usage() function.
func setCustomUsage() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s seconds\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(1)
	}
}<commit_msg>adjust delay<commit_after>package main

import (
	"flag"
	"log"
	"fmt"
	"time"
	"os"
)

const version string = "1.0.1"

// subtract process startup overhead from requested duration
const delay = time.Duration(14 * time.Millisecond)

// command line flags
var showVersion bool

func init() {
	flag.BoolVar(&showVersion, "version", false, "print version and exit")
}

func main() {
	log.SetFlags(0)
	flag.Parse()
	setCustomUsage()

	if showVersion {
		fmt.Println("sleep version", version)
	} else {
		if flag.NArg() != 1 {
			flag.Usage()
		}
		d, err := time.ParseDuration(flag.Arg(0)+"s")
		if err != nil {
			log.Fatalln(err)
		}
		time.Sleep(d - delay)
	}
}

// Redefines flag.Usage() function.
func setCustomUsage() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s seconds\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(1)
	}
}<|endoftext|>


<commit_before>/*
   Multihost
   Multiple ports
*/

package main

import (
	"flag"
	"github.com/crosbymichael/skydock/docker"
	"github.com/crosbymichael/skydock/utils"
	"github.com/skynetservices/skydns/client"
	"github.com/skynetservices/skydns/msg"
	"log"
	"os"
	"sync"
	"time"
)

var (
	pathToSocket     string
	domain           string
	environment      string
	skydnsUrl        string
	secret           string
	ttl              int
	beat             int
	numberOfHandlers int

	skydns       Skydns
	dockerClient docker.Docker
	running      = make(map[string]struct{})
)

func init() {
	flag.StringVar(&pathToSocket, "s", "/var/run/docker.sock", "path to the docker unix socket")
	flag.StringVar(&skydnsUrl, "skydns", "", "url to the skydns url")
	flag.StringVar(&secret, "secret", "", "skydns secret")
	flag.StringVar(&domain, "domain", "", "same domain passed to skydns")
	flag.StringVar(&environment, "environment", "dev", "environment name where service is running")
	flag.IntVar(&ttl, "ttl", 60, "default ttl to use when registering a service")
	flag.IntVar(&beat, "beat", 0, "heartbeat interval")
	flag.IntVar(&numberOfHandlers, "workers", 10, "number of concurrent workers")

	flag.Parse()
}

func validateSettings() {
	if beat < 1 {
		beat = ttl - (ttl / 4)
	}

	if skydnsUrl == "" {
		skydnsUrl = "http://" + os.Getenv("SKYDNS_PORT_8080_TCP_ADDR") + ":8080"
	}

	if domain == "" {
		log.Fatal("Must specify your skydns domain")
	}
}

func heartbeat(uuid string) {
	if _, exists := running[uuid]; exists {
		return
	}
	// TODO: not safe for concurrent access
	running[uuid] = struct{}{}
	defer delete(running, uuid)

	var (
		errorCount int
		err        error
		container  *docker.Container
	)

	for _ = range time.Tick(time.Duration(beat) * time.Second) {
		if errorCount > 10 {
			// if we encountered more than 10 errors just quit
			log.Printf("Aborting heartbeat for %s after 10 errors\n", uuid)
			return
		}

		if container, err = dockerClient.FetchContainer(uuid, ""); err != nil {
			errorCount++
			log.Println(err)
			break
		}

		if !container.State.Running {
			if err := removeService(uuid); err != nil {
				log.Println(err)
			}
			return
		}

		// don't fill logs if we have a low beat
		// may need to do something better here
		if beat >= 30 {
			log.Printf("Updating ttl for %s\n", container.Name)
		}

		if err := skydns.Update(uuid, uint32(ttl)); err != nil {
			errorCount++
			log.Println(err)
			break
		}
	}
}

// restoreContainers loads all running containers and inserts
// them into skydns when skydock starts
func restoreContainers() error {
	containers, err := dockerClient.FetchAllContainers()
	if err != nil {
		return err
	}

	var container *docker.Container
	for _, cnt := range containers {
		uuid := utils.Truncate(cnt.Id)
		if container, err = dockerClient.FetchContainer(uuid, cnt.Image); err != nil {
			if err != docker.ErrImageNotTagged {
				log.Printf("Failed to fetch %s for restore - %s\n", cnt.Id, err)
			}
			continue
		}

		if err := sendService(uuid, createService(container)); err != nil {
			log.Printf("Failed to send %s to skydns for restore - %s\n", uuid, err)
		}
	}
	return nil
}

// <uuid>.<host>.<region>.<version>.<service>.<environment>.skydns.local
func createService(container *docker.Container) *msg.Service {
	return &msg.Service{
		Name:        utils.CleanImageImage(container.Image), // Service name
		Version:     utils.RemoveSlash(container.Name),      // Instance of the service
		Host:        container.NetworkSettings.IpAddress,
		Environment: environment, // testing, prod, dev
		TTL:         uint32(ttl), // 60 seconds
		Port:        80,          // TODO: How to handle multiple ports
	}
}

// sendService sends the uuid and service data to skydns
func sendService(uuid string, service *msg.Service) error {
	log.Printf("Adding %s (%s)\n", uuid, service.Name)

	if err := skydns.Add(uuid, service); err != nil {
		return err
	}
	go heartbeat(uuid)

	return nil
}

func removeService(uuid string) error {
	log.Printf("Removing %s from skydns\n", uuid)

	return skydns.Delete(uuid)
}

func addService(uuid, image string) error {
	log.Printf("Adding %s for %s\n", uuid, image)

	container, err := dockerClient.FetchContainer(uuid, image)
	if err != nil {
		if err != docker.ErrImageNotTagged {
			return err
		}
		return nil
	}

	if err := sendService(uuid, createService(container)); err != nil {
		return err
	}
	return nil
}

func eventHandler(c <-chan *docker.Event, group *sync.WaitGroup) {
	group.Add(1)
	defer group.Done()

	for event := range c {
		uuid := utils.Truncate(event.ContainerId)

		switch event.Status {
		case "die", "stop", "kill":
			if err := removeService(uuid); err != nil {
				log.Printf("Error deleting %s - %s\n", uuid, err)
			}
		case "start", "restart":
			if err := addService(uuid, event.Image); err != nil {
				log.Printf("Error adding %s - %s\n", uuid, err)
			}
		}
	}
}

func main() {
	validateSettings()

	var (
		err   error
		group = &sync.WaitGroup{}
	)

	if dockerClient, err = docker.NewClient(pathToSocket); err != nil {
		log.Fatal(err)
	}

	if skydns, err = client.NewClient(skydnsUrl, secret, domain, 53); err != nil {
		log.Fatal(err)
	}

	log.Println("Starting restore of running containers...")
	if err := restoreContainers(); err != nil {
		log.Fatal(err)
	}

	events, err := dockerClient.GetEvents()
	if err != nil {
		log.Fatal(err)
	}

	// Start event handlers
	for i := 0; i < numberOfHandlers; i++ {
		go eventHandler(events, group)
	}

	log.Println("Starting run loop...")
	group.Wait()
	log.Println("Stopping cleanly via EOF")
}
<commit_msg>Update skydns client for changes<commit_after>/*
   Multihost
   Multiple ports
*/

package main

import (
	"flag"
	"github.com/crosbymichael/skydock/docker"
	"github.com/crosbymichael/skydock/utils"
	"github.com/skynetservices/skydns/client"
	"github.com/skynetservices/skydns/msg"
	"log"
	"os"
	"sync"
	"time"
)

var (
	pathToSocket     string
	domain           string
	environment      string
	skydnsUrl        string
	secret           string
	ttl              int
	beat             int
	numberOfHandlers int

	skydns       Skydns
	dockerClient docker.Docker
	running      = make(map[string]struct{})
)

func init() {
	flag.StringVar(&pathToSocket, "s", "/var/run/docker.sock", "path to the docker unix socket")
	flag.StringVar(&skydnsUrl, "skydns", "", "url to the skydns url")
	flag.StringVar(&secret, "secret", "", "skydns secret")
	flag.StringVar(&domain, "domain", "", "same domain passed to skydns")
	flag.StringVar(&environment, "environment", "dev", "environment name where service is running")
	flag.IntVar(&ttl, "ttl", 60, "default ttl to use when registering a service")
	flag.IntVar(&beat, "beat", 0, "heartbeat interval")
	flag.IntVar(&numberOfHandlers, "workers", 10, "number of concurrent workers")

	flag.Parse()
}

func validateSettings() {
	if beat < 1 {
		beat = ttl - (ttl / 4)
	}

	if skydnsUrl == "" {
		skydnsUrl = "http://" + os.Getenv("SKYDNS_PORT_8080_TCP_ADDR") + ":8080"
	}

	if domain == "" {
		log.Fatal("Must specify your skydns domain")
	}
}

func heartbeat(uuid string) {
	if _, exists := running[uuid]; exists {
		return
	}
	// TODO: not safe for concurrent access
	running[uuid] = struct{}{}
	defer delete(running, uuid)

	var (
		errorCount int
		err        error
		container  *docker.Container
	)

	for _ = range time.Tick(time.Duration(beat) * time.Second) {
		if errorCount > 10 {
			// if we encountered more than 10 errors just quit
			log.Printf("Aborting heartbeat for %s after 10 errors\n", uuid)
			return
		}

		if container, err = dockerClient.FetchContainer(uuid, ""); err != nil {
			errorCount++
			log.Println(err)
			break
		}

		if !container.State.Running {
			if err := removeService(uuid); err != nil {
				log.Println(err)
			}
			return
		}

		// don't fill logs if we have a low beat
		// may need to do something better here
		if beat >= 30 {
			log.Printf("Updating ttl for %s\n", container.Name)
		}

		if err := skydns.Update(uuid, uint32(ttl)); err != nil {
			errorCount++
			log.Println(err)
			break
		}
	}
}

// restoreContainers loads all running containers and inserts
// them into skydns when skydock starts
func restoreContainers() error {
	containers, err := dockerClient.FetchAllContainers()
	if err != nil {
		return err
	}

	var container *docker.Container
	for _, cnt := range containers {
		uuid := utils.Truncate(cnt.Id)
		if container, err = dockerClient.FetchContainer(uuid, cnt.Image); err != nil {
			if err != docker.ErrImageNotTagged {
				log.Printf("Failed to fetch %s for restore - %s\n", cnt.Id, err)
			}
			continue
		}

		if err := sendService(uuid, createService(container)); err != nil {
			log.Printf("Failed to send %s to skydns for restore - %s\n", uuid, err)
		}
	}
	return nil
}

// <uuid>.<host>.<region>.<version>.<service>.<environment>.skydns.local
func createService(container *docker.Container) *msg.Service {
	return &msg.Service{
		Name:        utils.CleanImageImage(container.Image), // Service name
		Version:     utils.RemoveSlash(container.Name),      // Instance of the service
		Host:        container.NetworkSettings.IpAddress,
		Environment: environment, // testing, prod, dev
		TTL:         uint32(ttl), // 60 seconds
		Port:        80,          // TODO: How to handle multiple ports
	}
}

// sendService sends the uuid and service data to skydns
func sendService(uuid string, service *msg.Service) error {
	log.Printf("Adding %s (%s)\n", uuid, service.Name)

	if err := skydns.Add(uuid, service); err != nil {
		return err
	}
	go heartbeat(uuid)

	return nil
}

func removeService(uuid string) error {
	log.Printf("Removing %s from skydns\n", uuid)

	return skydns.Delete(uuid)
}

func addService(uuid, image string) error {
	log.Printf("Adding %s for %s\n", uuid, image)

	container, err := dockerClient.FetchContainer(uuid, image)
	if err != nil {
		if err != docker.ErrImageNotTagged {
			return err
		}
		return nil
	}

	if err := sendService(uuid, createService(container)); err != nil {
		return err
	}
	return nil
}

func eventHandler(c <-chan *docker.Event, group *sync.WaitGroup) {
	group.Add(1)
	defer group.Done()

	for event := range c {
		uuid := utils.Truncate(event.ContainerId)

		switch event.Status {
		case "die", "stop", "kill":
			if err := removeService(uuid); err != nil {
				log.Printf("Error deleting %s - %s\n", uuid, err)
			}
		case "start", "restart":
			if err := addService(uuid, event.Image); err != nil {
				log.Printf("Error adding %s - %s\n", uuid, err)
			}
		}
	}
}

func main() {
	validateSettings()

	var (
		err   error
		group = &sync.WaitGroup{}
	)

	if dockerClient, err = docker.NewClient(pathToSocket); err != nil {
		log.Fatal(err)
	}

	if skydns, err = client.NewClient(skydnsUrl, secret, domain, "172.17.42.1:53"); err != nil {
		log.Fatal(err)
	}

	log.Println("Starting restore of running containers...")
	if err := restoreContainers(); err != nil {
		log.Fatal(err)
	}

	events, err := dockerClient.GetEvents()
	if err != nil {
		log.Fatal(err)
	}

	// Start event handlers
	for i := 0; i < numberOfHandlers; i++ {
		go eventHandler(events, group)
	}

	log.Println("Starting run loop...")
	group.Wait()
	log.Println("Stopping cleanly via EOF")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"os/exec"

	"github.com/lukechampine/ply/importer"
	"github.com/lukechampine/ply/types"
)

const mergeTempl = `package %[3]s
func merge%[1]s%[2]s(m1, m2 map[%[1]s]%[2]s) map[%[1]s]%[2]s {
	m3 := make(map[%[1]s]%[2]s)
	for k, v := range m1 {
		m3[k] = v
	}
	for k, v := range m2 {
		m3[k] = v
	}
	return m3
}
`

// A specializer is an ast.Visitor that inserts specialized versions of each
// generic ply function, and rewrites the callsites to use their corresponding
// specialized function.
type specializer struct {
	types map[ast.Expr]types.TypeAndValue
	fset  *token.FileSet
	pkg   *ast.Package
}

func (s specializer) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.CallExpr:
		fn, ok := n.Fun.(*ast.Ident)
		if !ok {
			// ply functions are always idents
			return s
		}
		if fn.Name == "merge" {
			mt := s.types[n.Args[0]].Type.(*types.Map)
			fn.Name += mt.Key().String() + mt.Elem().String()
			if _, ok := s.pkg.Files[fn.Name]; !ok {
				// check for existence first, because constructing a new decl
				// is expensive
				code := fmt.Sprintf(mergeTempl, mt.Key().String(), mt.Elem().String(), s.pkg.Name)
				f, err := parser.ParseFile(s.fset, "", code, 0)
				if err != nil {
					panic(err)
				}
				s.pkg.Files[fn.Name] = f
			}
		}
	}
	return s
}

func main() {
	log.SetFlags(0)

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, os.Args[1], nil, 0)
	if err != nil {
		log.Fatal(err)
	}

	info := types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
	}
	var conf types.Config
	conf.Importer = importer.Default()
	pkg, err := conf.Check("ply", fset, []*ast.File{f}, &info)
	if err != nil {
		log.Fatal(err)
	}

	// modify the AST as needed
	spec := specializer{
		types: info.Types,
		fset:  fset,
		pkg: &ast.Package{
			Name:  pkg.Name(),
			Files: make(map[string]*ast.File),
		},
	}
	ast.Walk(spec, f)

	// combine generated files into a single package file
	merged := ast.MergePackageFiles(spec.pkg, ast.FilterFuncDuplicates|ast.FilterImportDuplicates)

	// output modified original to current directory
	origFile, err := os.Create("test_plied.go")
	if err != nil {
		log.Fatal(err)
	}
	printer.Fprint(origFile, fset, f)

	// output generated code to current directory
	genFile, err := os.Create("ply_builtins.go")
	if err != nil {
		log.Fatal(err)
	}
	printer.Fprint(genFile, fset, merged)

	// invoke Go compiler
	cmd := exec.Command("go", "build")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>support multiple files<commit_after>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"os/exec"

	"github.com/lukechampine/ply/importer"
	"github.com/lukechampine/ply/types"
)

const mergeTempl = `package %[3]s
func merge%[1]s%[2]s(m1, m2 map[%[1]s]%[2]s) map[%[1]s]%[2]s {
	m3 := make(map[%[1]s]%[2]s)
	for k, v := range m1 {
		m3[k] = v
	}
	for k, v := range m2 {
		m3[k] = v
	}
	return m3
}
`

// A specializer is an ast.Visitor that inserts specialized versions of each
// generic ply function, and rewrites the callsites to use their corresponding
// specialized function.
type specializer struct {
	types map[ast.Expr]types.TypeAndValue
	fset  *token.FileSet
	pkg   *ast.Package
}

func (s specializer) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.CallExpr:
		fn, ok := n.Fun.(*ast.Ident)
		if !ok {
			// ply functions are always idents
			return s
		}
		if fn.Name == "merge" {
			mt := s.types[n.Args[0]].Type.(*types.Map)
			fn.Name += mt.Key().String() + mt.Elem().String()
			if _, ok := s.pkg.Files[fn.Name]; !ok {
				// check for existence first, because constructing a new decl
				// is expensive
				code := fmt.Sprintf(mergeTempl, mt.Key().String(), mt.Elem().String(), s.pkg.Name)
				f, err := parser.ParseFile(s.fset, "", code, 0)
				if err != nil {
					panic(err)
				}
				s.pkg.Files[fn.Name] = f
			}
		}
	}
	return s
}

func main() {
	log.SetFlags(0)
	flag.Parse()

	// parse each supplied file
	fset := token.NewFileSet()
	var files []*ast.File
	fileNames := make(map[*ast.File]string)
	for _, arg := range flag.Args() {
		f, err := parser.ParseFile(fset, arg, nil, 0)
		if err != nil {
			log.Fatal(err)
		}
		files = append(files, f)
		fileNames[f] = arg
	}

	// type-check the package
	info := types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
	}
	var conf types.Config
	conf.Importer = importer.Default()
	pkg, err := conf.Check("ply", fset, files, &info)
	if err != nil {
		log.Fatal(err)
	}

	// walk the AST of each file in the package, generating ply functions and
	// rewriting their callsites
	spec := specializer{
		types: info.Types,
		fset:  fset,
		pkg: &ast.Package{
			Name:  pkg.Name(),
			Files: make(map[string]*ast.File),
		},
	}
	for _, f := range files {
		ast.Walk(spec, f)
	}

	// combine generated ply functions into a single file and write it to the
	// current directory
	merged := ast.MergePackageFiles(spec.pkg, ast.FilterFuncDuplicates|ast.FilterImportDuplicates)
	implFile, err := os.Create("ply_impls.go")
	if err != nil {
		log.Fatal(err)
	}
	printer.Fprint(implFile, fset, merged)

	// output a .go file for each .ply file
	for _, f := range files {
		goFile, err := os.Create(fileNames[f] + ".go")
		if err != nil {
			log.Fatal(err)
		}
		printer.Fprint(goFile, fset, f)
	}

	// invoke the Go compiler
	cmd := exec.Command("go", "build")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

func hello(context web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s!", context.URLParams["name"])
}

func main() {
	SetupRoutes()
	goji.Serve()
}

func SetupRoutes() {
	goji.Get("/hello/:name", hello)
	goji.Post("/devices", addDevice)
}

func addDevice(context web.C, writer http.ResponseWriter, request *http.Request) {
	decoder := json.NewDecoder(request.Body)

	var sentJSON interface{}
	err := decoder.Decode(&sentJSON)
	if err != nil {
		fmt.Fprintln(writer, err.Error())
	}

	encoder := json.NewEncoder(writer)

	writer.Header().Set("Content-Type", "application/json")
	writer.WriteHeader(201)

	err = encoder.Encode(sentJSON)
	if err != nil {
		fmt.Fprintln(writer, err.Error())
	}
}
<commit_msg>Minor text change in order to verify that automated deployment is working.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

func hello(context web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Aloha, %s!", context.URLParams["name"])
}

func main() {
	SetupRoutes()
	goji.Serve()
}

func SetupRoutes() {
	goji.Get("/hello/:name", hello)
	goji.Post("/devices", addDevice)
}

func addDevice(context web.C, writer http.ResponseWriter, request *http.Request) {
	decoder := json.NewDecoder(request.Body)

	var sentJSON interface{}
	err := decoder.Decode(&sentJSON)
	if err != nil {
		fmt.Fprintln(writer, err.Error())
	}

	encoder := json.NewEncoder(writer)

	writer.Header().Set("Content-Type", "application/json")
	writer.WriteHeader(201)

	err = encoder.Encode(sentJSON)
	if err != nil {
		fmt.Fprintln(writer, err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/joho/godotenv"
	_ "github.com/joho/godotenv/autoload"
	"github.com/urfave/cli"
)

// Version set at compile-time
var Version string

func main() {
	year := fmt.Sprintf("%v", time.Now().Year())
	app := cli.NewApp()
	app.Name = "Drone Discord"
	app.Usage = "Sending message to Discord channel using Webhook"
	app.Copyright = "Copyright (c) " + year + " Bo-Yi Wu"
	app.Authors = []cli.Author{
		{
			Name:  "Bo-Yi Wu",
			Email: "appleboy.tw@gmail.com",
		},
	}
	app.Action = run
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "webhook-id",
			Usage:  "discord webhook id",
			EnvVar: "PLUGIN_WEBHOOK_ID,WEBHOOK_ID,DISCORD_WEBHOOK_ID,INPUT_WEBHOOK_ID",
		},
		cli.StringFlag{
			Name:   "webhook-token",
			Usage:  "discord webhook token",
			EnvVar: "PLUGIN_WEBHOOK_TOKEN,WEBHOOK_TOKEN,DISCORD_WEBHOOK_TOKEN,INPUT_WEBHOOK_TOKEN",
		},
		cli.StringSliceFlag{
			Name:   "message",
			Usage:  "the message contents (up to 2000 characters)",
			EnvVar: "PLUGIN_MESSAGE,DISCORD_MESSAGE,MESSAGE,INPUT_MESSAGE",
		},
		cli.StringSliceFlag{
			Name:   "file",
			Usage:  "the contents of the file being sent",
			EnvVar: "PLUGIN_FILE,DISCORD_FILE,FILE,INPUT_FILE",
		},
		cli.StringFlag{
			Name:   "color",
			Usage:  "color code of the embed",
			EnvVar: "PLUGIN_COLOR,COLOR,INPUT_COLOR",
		},
		cli.BoolFlag{
			Name:   "wait",
			Usage:  "waits for server confirmation of message send before response, and returns the created message body",
			EnvVar: "PLUGIN_WAIT,WAIT,INPUT_WAIT",
		},
		cli.BoolFlag{
			Name:   "tts",
			Usage:  "true if this is a TTS message",
			EnvVar: "PLUGIN_TTS,TTS,INPUT_TTS",
		},
		cli.StringFlag{
			Name:   "username",
			Usage:  "override the default username of the webhook",
			EnvVar: "PLUGIN_USERNAME,USERNAME,INPUT_USERNAME",
		},
		cli.StringFlag{
			Name:   "avatar-url",
			Usage:  "override the default avatar of the webhook",
			EnvVar: "PLUGIN_AVATAR_URL,AVATAR_URL,INPUT_AVATAR_URL",
		},
		cli.BoolFlag{
			Name:   "drone",
			Usage:  "environment is drone",
			EnvVar: "DRONE",
		},
		cli.StringFlag{
			Name:   "repo",
			Usage:  "repository owner and repository name",
			EnvVar: "DRONE_REPO,GITHUB_REPOSITORY",
		},
		cli.StringFlag{
			Name:   "repo.namespace",
			Usage:  "repository namespace",
			EnvVar: "DRONE_REPO_OWNER,DRONE_REPO_NAMESPACE,GITHUB_ACTOR",
		},
		cli.StringFlag{
			Name:   "repo.name",
			Usage:  "repository name",
			EnvVar: "DRONE_REPO_NAME",
		},
		cli.StringFlag{
			Name:   "commit.sha",
			Usage:  "git commit sha",
			EnvVar: "DRONE_COMMIT_SHA,GITHUB_SHA",
		},
		cli.StringFlag{
			Name:   "commit.ref",
			Usage:  "git commit ref",
			EnvVar: "DRONE_COMMIT_REF,GITHUB_REF",
		},
		cli.StringFlag{
			Name:   "commit.branch",
			Value:  "master",
			Usage:  "git commit branch",
			EnvVar: "DRONE_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "commit.link",
			Usage:  "git commit link",
			EnvVar: "DRONE_COMMIT_LINK",
		},
		cli.StringFlag{
			Name:   "commit.author",
			Usage:  "git author name",
			EnvVar: "DRONE_COMMIT_AUTHOR",
		},
		cli.StringFlag{
			Name:   "commit.author.email",
			Usage:  "git author email",
			EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
		},
		cli.StringFlag{
			Name:   "commit.author.avatar",
			Usage:  "git author avatar",
			EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
		},
		cli.StringFlag{
			Name:   "commit.message",
			Usage:  "commit message",
			EnvVar: "DRONE_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "build.event",
			Value:  "push",
			Usage:  "build event",
			EnvVar: "DRONE_BUILD_EVENT",
		},
		cli.IntFlag{
			Name:   "build.number",
			Usage:  "build number",
			EnvVar: "DRONE_BUILD_NUMBER",
		},
		cli.StringFlag{
			Name:   "build.status",
			Usage:  "build status",
			Value:  "success",
			EnvVar: "DRONE_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "build.link",
			Usage:  "build link",
			EnvVar: "DRONE_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "build.tag",
			Usage:  "build tag",
			EnvVar: "DRONE_TAG",
		},
		cli.StringFlag{
			Name:   "pull.request",
			Usage:  "pull request",
			EnvVar: "DRONE_PULL_REQUEST",
		},
		cli.Int64Flag{
			Name:   "job.started",
			Usage:  "job started",
			EnvVar: "DRONE_JOB_STARTED",
		},
		cli.Int64Flag{
			Name:   "job.finished",
			Usage:  "job finished",
			EnvVar: "DRONE_JOB_FINISHED",
		},
		cli.StringFlag{
			Name:  "env-file",
			Usage: "source env file",
		},
		cli.BoolFlag{
			Name:   "github",
			Usage:  "Boolean value, indicates the runtime environment is GitHub Action.",
			EnvVar: "PLUGIN_GITHUB,GITHUB",
		},
		cli.StringFlag{
			Name:   "github.workflow",
			Usage:  "The name of the workflow.",
			EnvVar: "GITHUB_WORKFLOW",
		},
		cli.StringFlag{
			Name:   "github.action",
			Usage:  "The name of the action.",
			EnvVar: "GITHUB_ACTION",
		},
		cli.StringFlag{
			Name:   "github.event.name",
			Usage:  "The webhook name of the event that triggered the workflow.",
			EnvVar: "GITHUB_EVENT_NAME",
		},
		cli.StringFlag{
			Name:   "github.event.path",
			Usage:  "The path to a file that contains the payload of the event that triggered the workflow. Value: /github/workflow/event.json.",
			EnvVar: "GITHUB_EVENT_PATH",
		},
		cli.StringFlag{
			Name:   "github.workspace",
			Usage:  "The GitHub workspace path. Value: /github/workspace.",
			EnvVar: "GITHUB_WORKSPACE",
		},
		cli.StringFlag{
			Name:   "deploy.to",
			Usage:  "Provides the target deployment environment for the running build. This value is only available to promotion and rollback pipelines.",
			EnvVar: "DRONE_DEPLOY_TO",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}

	plugin := Plugin{
		GitHub: GitHub{
			Workflow:  c.String("github.workflow"),
			Workspace: c.String("github.workspace"),
			Action:    c.String("github.action"),
			EventName: c.String("github.event.name"),
			EventPath: c.String("github.event.path"),
		},
		Repo: Repo{
			FullName:  c.String("repo"),
			Namespace: c.String("repo.namespace"),
			Name:      c.String("repo.name"),
		},
		Commit: Commit{
			Sha:     c.String("commit.sha"),
			Ref:     c.String("commit.ref"),
			Branch:  c.String("commit.branch"),
			Link:    c.String("commit.link"),
			Author:  c.String("commit.author"),
			Email:   c.String("commit.author.email"),
			Avatar:  c.String("commit.author.avatar"),
			Message: c.String("commit.message"),
		},
		Build: Build{
			Tag:      c.String("build.tag"),
			Number:   c.Int("build.number"),
			Event:    c.String("build.event"),
			Status:   c.String("build.status"),
			Link:     c.String("build.link"),
			Started:  c.Int64("job.started"),
			Finished: c.Int64("job.finished"),
			PR:       c.String("pull.request"),
			DeployTo: c.String("deploy.to"),
		},
		Config: Config{
			WebhookID:    c.String("webhook-id"),
			WebhookToken: c.String("webhook-token"),
			Message:      c.StringSlice("message"),
			File:         c.StringSlice("file"),
			Color:        c.String("color"),
			Drone:        c.Bool("drone"),
			GitHub:       c.Bool("github"),
		},
		Payload: Payload{
			Wait:      c.Bool("wait"),
			Username:  c.String("username"),
			AvatarURL: c.String("avatar-url"),
			TTS:       c.Bool("tts"),
		},
	}

	return plugin.Exec()
}
<commit_msg>fix: #21 update build.started env<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/joho/godotenv"
	_ "github.com/joho/godotenv/autoload"
	"github.com/urfave/cli"
)

// Version set at compile-time
var Version string

func main() {
	year := fmt.Sprintf("%v", time.Now().Year())
	app := cli.NewApp()
	app.Name = "Drone Discord"
	app.Usage = "Sending message to Discord channel using Webhook"
	app.Copyright = "Copyright (c) " + year + " Bo-Yi Wu"
	app.Authors = []cli.Author{
		{
			Name:  "Bo-Yi Wu",
			Email: "appleboy.tw@gmail.com",
		},
	}
	app.Action = run
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "webhook-id",
			Usage:  "discord webhook id",
			EnvVar: "PLUGIN_WEBHOOK_ID,WEBHOOK_ID,DISCORD_WEBHOOK_ID,INPUT_WEBHOOK_ID",
		},
		cli.StringFlag{
			Name:   "webhook-token",
			Usage:  "discord webhook token",
			EnvVar: "PLUGIN_WEBHOOK_TOKEN,WEBHOOK_TOKEN,DISCORD_WEBHOOK_TOKEN,INPUT_WEBHOOK_TOKEN",
		},
		cli.StringSliceFlag{
			Name:   "message",
			Usage:  "the message contents (up to 2000 characters)",
			EnvVar: "PLUGIN_MESSAGE,DISCORD_MESSAGE,MESSAGE,INPUT_MESSAGE",
		},
		cli.StringSliceFlag{
			Name:   "file",
			Usage:  "the contents of the file being sent",
			EnvVar: "PLUGIN_FILE,DISCORD_FILE,FILE,INPUT_FILE",
		},
		cli.StringFlag{
			Name:   "color",
			Usage:  "color code of the embed",
			EnvVar: "PLUGIN_COLOR,COLOR,INPUT_COLOR",
		},
		cli.BoolFlag{
			Name:   "wait",
			Usage:  "waits for server confirmation of message send before response, and returns the created message body",
			EnvVar: "PLUGIN_WAIT,WAIT,INPUT_WAIT",
		},
		cli.BoolFlag{
			Name:   "tts",
			Usage:  "true if this is a TTS message",
			EnvVar: "PLUGIN_TTS,TTS,INPUT_TTS",
		},
		cli.StringFlag{
			Name:   "username",
			Usage:  "override the default username of the webhook",
			EnvVar: "PLUGIN_USERNAME,USERNAME,INPUT_USERNAME",
		},
		cli.StringFlag{
			Name:   "avatar-url",
			Usage:  "override the default avatar of the webhook",
			EnvVar: "PLUGIN_AVATAR_URL,AVATAR_URL,INPUT_AVATAR_URL",
		},
		cli.BoolFlag{
			Name:   "drone",
			Usage:  "environment is drone",
			EnvVar: "DRONE",
		},
		cli.StringFlag{
			Name:   "repo",
			Usage:  "repository owner and repository name",
			EnvVar: "DRONE_REPO,GITHUB_REPOSITORY",
		},
		cli.StringFlag{
			Name:   "repo.namespace",
			Usage:  "repository namespace",
			EnvVar: "DRONE_REPO_OWNER,DRONE_REPO_NAMESPACE,GITHUB_ACTOR",
		},
		cli.StringFlag{
			Name:   "repo.name",
			Usage:  "repository name",
			EnvVar: "DRONE_REPO_NAME",
		},
		cli.StringFlag{
			Name:   "commit.sha",
			Usage:  "git commit sha",
			EnvVar: "DRONE_COMMIT_SHA,GITHUB_SHA",
		},
		cli.StringFlag{
			Name:   "commit.ref",
			Usage:  "git commit ref",
			EnvVar: "DRONE_COMMIT_REF,GITHUB_REF",
		},
		cli.StringFlag{
			Name:   "commit.branch",
			Value:  "master",
			Usage:  "git commit branch",
			EnvVar: "DRONE_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "commit.link",
			Usage:  "git commit link",
			EnvVar: "DRONE_COMMIT_LINK",
		},
		cli.StringFlag{
			Name:   "commit.author",
			Usage:  "git author name",
			EnvVar: "DRONE_COMMIT_AUTHOR",
		},
		cli.StringFlag{
			Name:   "commit.author.email",
			Usage:  "git author email",
			EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
		},
		cli.StringFlag{
			Name:   "commit.author.avatar",
			Usage:  "git author avatar",
			EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
		},
		cli.StringFlag{
			Name:   "commit.message",
			Usage:  "commit message",
			EnvVar: "DRONE_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "build.event",
			Value:  "push",
			Usage:  "build event",
			EnvVar: "DRONE_BUILD_EVENT",
		},
		cli.IntFlag{
			Name:   "build.number",
			Usage:  "build number",
			EnvVar: "DRONE_BUILD_NUMBER",
		},
		cli.StringFlag{
			Name:   "build.status",
			Usage:  "build status",
			Value:  "success",
			EnvVar: "DRONE_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "build.link",
			Usage:  "build link",
			EnvVar: "DRONE_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "build.tag",
			Usage:  "build tag",
			EnvVar: "DRONE_TAG",
		},
		cli.StringFlag{
			Name:   "pull.request",
			Usage:  "pull request",
			EnvVar: "DRONE_PULL_REQUEST",
		},
		cli.Int64Flag{
			Name:   "job.started",
			Usage:  "job started",
			EnvVar: "DRONE_BUILD_STARTED",
		},
		cli.Int64Flag{
			Name:   "job.finished",
			Usage:  "job finished",
			EnvVar: "DRONE_BUILD_FINISHED",
		},
		cli.StringFlag{
			Name:  "env-file",
			Usage: "source env file",
		},
		cli.BoolFlag{
			Name:   "github",
			Usage:  "Boolean value, indicates the runtime environment is GitHub Action.",
			EnvVar: "PLUGIN_GITHUB,GITHUB",
		},
		cli.StringFlag{
			Name:   "github.workflow",
			Usage:  "The name of the workflow.",
			EnvVar: "GITHUB_WORKFLOW",
		},
		cli.StringFlag{
			Name:   "github.action",
			Usage:  "The name of the action.",
			EnvVar: "GITHUB_ACTION",
		},
		cli.StringFlag{
			Name:   "github.event.name",
			Usage:  "The webhook name of the event that triggered the workflow.",
			EnvVar: "GITHUB_EVENT_NAME",
		},
		cli.StringFlag{
			Name:   "github.event.path",
			Usage:  "The path to a file that contains the payload of the event that triggered the workflow. Value: /github/workflow/event.json.",
			EnvVar: "GITHUB_EVENT_PATH",
		},
		cli.StringFlag{
			Name:   "github.workspace",
			Usage:  "The GitHub workspace path. Value: /github/workspace.",
			EnvVar: "GITHUB_WORKSPACE",
		},
		cli.StringFlag{
			Name:   "deploy.to",
			Usage:  "Provides the target deployment environment for the running build. This value is only available to promotion and rollback pipelines.",
			EnvVar: "DRONE_DEPLOY_TO",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}

	plugin := Plugin{
		GitHub: GitHub{
			Workflow:  c.String("github.workflow"),
			Workspace: c.String("github.workspace"),
			Action:    c.String("github.action"),
			EventName: c.String("github.event.name"),
			EventPath: c.String("github.event.path"),
		},
		Repo: Repo{
			FullName:  c.String("repo"),
			Namespace: c.String("repo.namespace"),
			Name:      c.String("repo.name"),
		},
		Commit: Commit{
			Sha:     c.String("commit.sha"),
			Ref:     c.String("commit.ref"),
			Branch:  c.String("commit.branch"),
			Link:    c.String("commit.link"),
			Author:  c.String("commit.author"),
			Email:   c.String("commit.author.email"),
			Avatar:  c.String("commit.author.avatar"),
			Message: c.String("commit.message"),
		},
		Build: Build{
			Tag:      c.String("build.tag"),
			Number:   c.Int("build.number"),
			Event:    c.String("build.event"),
			Status:   c.String("build.status"),
			Link:     c.String("build.link"),
			Started:  c.Int64("job.started"),
			Finished: c.Int64("job.finished"),
			PR:       c.String("pull.request"),
			DeployTo: c.String("deploy.to"),
		},
		Config: Config{
			WebhookID:    c.String("webhook-id"),
			WebhookToken: c.String("webhook-token"),
			Message:      c.StringSlice("message"),
			File:         c.StringSlice("file"),
			Color:        c.String("color"),
			Drone:        c.Bool("drone"),
			GitHub:       c.Bool("github"),
		},
		Payload: Payload{
			Wait:      c.Bool("wait"),
			Username:  c.String("username"),
			AvatarURL: c.String("avatar-url"),
			TTS:       c.Bool("tts"),
		},
	}

	return plugin.Exec()
}
<|endoftext|>