<commit_before>// main.go
package main

import (
	"database/sql"
	"flag"
	"log"
	"os/exec"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

const (
	// time between processing xinput output
	SLEEP_TIME = 3 * time.Second

	// Buffer that we read from xinput
	KEYBOARD_BUFER_SIZE = 10000

	// Database that stores keylog and other settings
	DATABASE_NAME = "file:gokeystat.db?cache=shared&mode=rwc"

	// time in seconds between capturing keyboard to db
	CAPTURE_TIME = 5
)

// StatForTime stotres pressed keys and beginning time
type StatForTime struct {
	time int64
	keys map[uint8]int
}

// Init set time to Now().Unix() and keys to empty map
func (stat *StatForTime) Init() {
	stat.time = time.Now().Unix()
	stat.keys = make(map[uint8]int)
}

// GetKeymap returns map from key numbers to key names like "F1", "Tab", "d"
func GetKeymap() map[uint8]string {
	return GetKeymapFromOutput(GetKeymapOutput())
}

// GetKeymapOutput returns output of utility that prints system keymap
func GetKeymapOutput() []byte {
	cmd := exec.Command("xmodmap", "-pke")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	return out
}

// GetKeymapFromOutput returns map with keymap from text
func GetKeymapFromOutput(buf []byte) map[uint8]string {
	const KEY_NUM_STRING_RE = "\\d+[ ]*=[ ]*\\S+"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyMap := make(map[uint8]string)
	for _, line := range resByte {
		lineSpitted := strings.Split(string(line), " ")
		if key, err := strconv.Atoi(lineSpitted[0]); err == nil {
			keyMap[uint8(key)] = lineSpitted[2]
		}
	}
	return keyMap
}

// GetKeyNumsFromOutput extract pressed keys from bufer buf
// It returns slice with key numbers in the same order
func GetKeyNumsFromOutput(buf []byte) []uint8 {
	const KEY_NUM_STRING_RE = "press[ ]+(\\d+)"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyNums := make([]uint8, len(resByte))
	re = regexp.MustCompile("\\d+")
	for i, line := range resByte {
		numByte := re.Find(line)
		if num, err := strconv.Atoi(string(numByte)); err == nil {
			keyNums[i] = uint8(num)
		} else {
			log.Fatal(err)
		}
	}
	return keyNums
}

// GetKeyNumsFromKeyMap returns sorted slice with key nums of keyMap
func GetKeyNumsFromKeyMap(keyMap map[uint8]string) []int {
	res := make([]int, 0, len(keyMap))
	for keyNum := range keyMap {
		res = append(res, int(keyNum))
	}
	sort.Ints(res)
	return res
}

// InitDb creates tables, inserts keymap to db
func InitDb(db *sql.DB, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	sqlInit := `CREATE TABLE IF NOT EXISTS keylog (
        time INTEGER primary key`

	for keyNum := range keyNums {
		sqlInit += ",\n" + "KEY" + strconv.Itoa(keyNum) + " INTEGER"
	}
	sqlInit += "\n);"

	// Inserting keymap to table
	sqlInit += ` CREATE TABLE IF NOT EXISTS keymap (
        num INTEGER primary key,
		value STRING
	);`

	_, err := db.Exec(sqlInit)
	if err != nil {
		log.Fatalf("%q: %s\n", err, sqlInit)
	}

	rows, err := db.Query("SELECT COUNT(*) FROM keymap")
	if err != nil {
		log.Fatal(err)
	}

	var rowsCount int
	rows.Next()
	rows.Scan(&rowsCount)
	if rowsCount > 0 {
		// already inserted keymap
		return
	}
	rows.Close()

	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	stmt, err := tx.Prepare("INSERT INTO keymap(num, value) VALUES(?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	for keyNum, keyName := range keyMap {
		_, err = stmt.Exec(keyNum, keyName)
		if err != nil {
			log.Fatal(err)
		}
	}
	tx.Commit()
}

//AddStatTimeToDb insert statTime to db with using keyMap for extracting key nums
func AddStatTimeToDb(db *sql.DB, statTime StatForTime, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)
	sqlStmt := "insert into keylog(time"
	for keyNum := range keyNums {
		sqlStmt += ",\n" + "KEY" + strconv.Itoa(keyNum)
	}
	sqlStmt += ") values "
	sqlStmt += "(" + strconv.FormatInt(statTime.time, 10)
	for keyNum := range keyNums {
		keyNumber, _ := statTime.keys[uint8(keyNum)]
		sqlStmt += ",\n" + strconv.Itoa(keyNumber)
	}
	sqlStmt += ")"
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	_, err = tx.Exec(sqlStmt)
	if err != nil {
		log.Printf("%q: %s\n", err, sqlStmt)
	}

	tx.Commit()
}

// GetStatTimesFromDb returns slice with StatForTime objects that
func GetStatTimesFromDb(db *sql.DB, fromTime int64, keyMap map[uint8]string) []StatForTime {
	sqlStmt := "select * from keylog where time > " + strconv.FormatInt(fromTime, 10)
	rows, err := db.Query(sqlStmt)
	if err != nil {
		log.Fatalln("Error with query", sqlStmt, " is ", err)
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		log.Fatalln("Failed to get columns", err)
	}

	rawResult := make([][]byte, len(cols))
	result := make([]int64, len(cols))

	dest := make([]interface{}, len(cols)) // A temporary interface{} slice
	for i := range rawResult {
		dest[i] = &rawResult[i] // Put pointers to each string in the interface slice
	}

	// keyNums[i] stores i-th keynum
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	// result
	var res []StatForTime
	for rows.Next() {
		err = rows.Scan(dest...)
		if err != nil {
			log.Fatalln("Failed to scan row", err)
		}

		for i, raw := range rawResult {
			if raw == nil {
				result[i] = 0
			} else {
				// Only numbers in db: converting it to int64
				result[i], err = strconv.ParseInt(string(raw), 10, 64)
				if err != nil {
					log.Fatalln("Error when parsing ", raw, " from db:", err)
				}
			}
		}

		var resStatTime StatForTime
		resStatTime.time = result[0]
		resStatTime.keys = make(map[uint8]int)
		for index, val := range result[1:] {
			if val == 0 {
				continue
			}
			resStatTime.keys[uint8(keyNums[index])] = int(val)
		}
		res = append(res, resStatTime)
	}
	if err = rows.Err(); err != nil {
		log.Fatalln("Error when iterating over rows", err)
	}

	return res
}

// GetFileType extract extension from path if we support it
// Allowed if non-supported result with non supported path is wrong
func GetFileType(path string) string {
	if len(path) == 0 {
		return ""
	}
	Point := false
	for _, c := range path {
		if c == '.' {
			Point = true
		}
	}
	if !Point {
		return ""
	}

	path = strings.ToLower(path)

	if len(path) > 3 {
		if path[len(path)-3:] == ".gz" {
			return GetFileType(path[:len(path)-3]) + ".gz"
		}
	}

	i := len(path) - 1
	for path[i] != '.' {
		i--
		if i < 0 {
			break
		}
	}

	return path[i+1:]
}

func main() {

	keyboardID := flag.Int("id", -1, "Your keyboard id")
	outputPath := flag.String("o", "", "Path to export file")
	fullExport := flag.Bool("full", false, "Export full stats")
	flag.Parse()

	log.Println("keyboardID =", *keyboardID, "outputPath =", *outputPath)

	// Opening database
	db, err := sql.Open("sqlite3", DATABASE_NAME)
	if err != nil {
		log.Fatal(err)
	}
	db.SetMaxIdleConns(5)
	db.SetMaxOpenConns(5)
	defer db.Close()

	keyMap := GetKeymap()

	InitDb(db, keyMap)

	switch {
	case *keyboardID == -1 && *outputPath == "":
		flag.PrintDefaults()
		return
	case *keyboardID != -1:

		cmd := exec.Command("xinput", "test", strconv.Itoa(*keyboardID))

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := cmd.Start(); err != nil {
			log.Fatal(err)
		}

		// output of xinput command
		buf := make([]byte, KEYBOARD_BUFER_SIZE)

		var curStat StatForTime
		curStat.Init()

		for {
			n, err := stdout.Read(buf)
			if err != nil {
				log.Fatal(err)
			}
			// processing buf here
			for _, keyNum := range GetKeyNumsFromOutput(buf[:n]) {
				oldKeyCount, _ := curStat.keys[keyNum]
				curStat.keys[keyNum] = oldKeyCount + 1
			}

			// Every CAPTURE_TIME seconds save to BD
			if time.Now().Unix()-curStat.time > CAPTURE_TIME {
				AddStatTimeToDb(db, curStat, keyMap)
				curStat.Init()
			}

			time.Sleep(SLEEP_TIME)
		}
	case *outputPath != "":
		exportingData := GetStatTimesFromDb(db, 0, keyMap)
		filetype := GetFileType(*outputPath)
		log.Println(filetype)
		switch filetype {
		case "csv":
			SaveToCsvFile(exportingData, keyMap, *outputPath, *fullExport)
		case "json":
			SaveToJSONFile(exportingData, keyMap, *outputPath, *fullExport)
		case "jsl":
			SaveToJSLFile(exportingData, keyMap, *outputPath, *fullExport)

		case "csv.gz":
			SaveToCsvGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case "json.gz":
			SaveToJSONGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case "jsl.gz":
			SaveToJSLGzFile(exportingData, keyMap, *outputPath, *fullExport)
		default:
			log.Fatal("Incorrect file type")
		}
	}
}
<commit_msg>Specific begin/end of time period, changed duration of period<commit_after>// main.go
package main

import (
	"database/sql"
	"flag"
	"log"
	"os/exec"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

const (
	// time between processing xinput output
	SLEEP_TIME = 3 * time.Second

	// Buffer that we read from xinput
	KEYBOARD_BUFER_SIZE = 10000

	// Database that stores keylog and other settings
	DATABASE_NAME = "file:gokeystat.db?cache=shared&mode=rwc"

	// time in seconds between capturing keyboard to db
	CAPTURE_TIME = 900
)

// StatForTime stotres pressed keys and beginning time
type StatForTime struct {
	time int64
	keys map[uint8]int
}

// Init set time to Now().Unix() and keys to empty map
func (stat *StatForTime) Init(timePeriodEnd int64) {
	stat.time = timePeriodEnd - CAPTURE_TIME
	stat.keys = make(map[uint8]int)
}

// GetKeymap returns map from key numbers to key names like "F1", "Tab", "d"
func GetKeymap() map[uint8]string {
	return GetKeymapFromOutput(GetKeymapOutput())
}

// GetKeymapOutput returns output of utility that prints system keymap
func GetKeymapOutput() []byte {
	cmd := exec.Command("xmodmap", "-pke")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	return out
}

// GetKeymapFromOutput returns map with keymap from text
func GetKeymapFromOutput(buf []byte) map[uint8]string {
	const KEY_NUM_STRING_RE = "\\d+[ ]*=[ ]*\\S+"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyMap := make(map[uint8]string)
	for _, line := range resByte {
		lineSpitted := strings.Split(string(line), " ")
		if key, err := strconv.Atoi(lineSpitted[0]); err == nil {
			keyMap[uint8(key)] = lineSpitted[2]
		}
	}
	return keyMap
}

// GetKeyNumsFromOutput extract pressed keys from bufer buf
// It returns slice with key numbers in the same order
func GetKeyNumsFromOutput(buf []byte) []uint8 {
	const KEY_NUM_STRING_RE = "press[ ]+(\\d+)"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyNums := make([]uint8, len(resByte))
	re = regexp.MustCompile("\\d+")
	for i, line := range resByte {
		numByte := re.Find(line)
		if num, err := strconv.Atoi(string(numByte)); err == nil {
			keyNums[i] = uint8(num)
		} else {
			log.Fatal(err)
		}
	}
	return keyNums
}

// GetKeyNumsFromKeyMap returns sorted slice with key nums of keyMap
func GetKeyNumsFromKeyMap(keyMap map[uint8]string) []int {
	res := make([]int, 0, len(keyMap))
	for keyNum := range keyMap {
		res = append(res, int(keyNum))
	}
	sort.Ints(res)
	return res
}

// InitDb creates tables, inserts keymap to db
func InitDb(db *sql.DB, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	sqlInit := `CREATE TABLE IF NOT EXISTS keylog (
        time INTEGER primary key`

	for keyNum := range keyNums {
		sqlInit += ",\n" + "KEY" + strconv.Itoa(keyNum) + " INTEGER"
	}
	sqlInit += "\n);"

	// Inserting keymap to table
	sqlInit += ` CREATE TABLE IF NOT EXISTS keymap (
        num INTEGER primary key,
		value STRING
	);`

	_, err := db.Exec(sqlInit)
	if err != nil {
		log.Fatalf("%q: %s\n", err, sqlInit)
	}

	rows, err := db.Query("SELECT COUNT(*) FROM keymap")
	if err != nil {
		log.Fatal(err)
	}

	var rowsCount int
	rows.Next()
	rows.Scan(&rowsCount)
	if rowsCount > 0 {
		// already inserted keymap
		return
	}
	rows.Close()

	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	stmt, err := tx.Prepare("INSERT INTO keymap(num, value) VALUES(?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	for keyNum, keyName := range keyMap {
		_, err = stmt.Exec(keyNum, keyName)
		if err != nil {
			log.Fatal(err)
		}
	}
	tx.Commit()
}

//AddStatTimeToDb insert statTime to db with using keyMap for extracting key nums
func AddStatTimeToDb(db *sql.DB, statTime StatForTime, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)
	sqlStmt := "insert into keylog(time"
	for keyNum := range keyNums {
		sqlStmt += ",\n" + "KEY" + strconv.Itoa(keyNum)
	}
	sqlStmt += ") values "
	sqlStmt += "(" + strconv.FormatInt(statTime.time, 10)
	for keyNum := range keyNums {
		keyNumber, _ := statTime.keys[uint8(keyNum)]
		sqlStmt += ",\n" + strconv.Itoa(keyNumber)
	}
	sqlStmt += ")"
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	_, err = tx.Exec(sqlStmt)
	if err != nil {
		log.Printf("%q: %s\n", err, sqlStmt)
	}

	tx.Commit()
}

// GetStatTimesFromDb returns slice with StatForTime objects that
func GetStatTimesFromDb(db *sql.DB, fromTime int64, keyMap map[uint8]string) []StatForTime {
	sqlStmt := "select * from keylog where time > " + strconv.FormatInt(fromTime, 10)
	rows, err := db.Query(sqlStmt)
	if err != nil {
		log.Fatalln("Error with query", sqlStmt, " is ", err)
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		log.Fatalln("Failed to get columns", err)
	}

	rawResult := make([][]byte, len(cols))
	result := make([]int64, len(cols))

	dest := make([]interface{}, len(cols)) // A temporary interface{} slice
	for i := range rawResult {
		dest[i] = &rawResult[i] // Put pointers to each string in the interface slice
	}

	// keyNums[i] stores i-th keynum
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	// result
	var res []StatForTime
	for rows.Next() {
		err = rows.Scan(dest...)
		if err != nil {
			log.Fatalln("Failed to scan row", err)
		}

		for i, raw := range rawResult {
			if raw == nil {
				result[i] = 0
			} else {
				// Only numbers in db: converting it to int64
				result[i], err = strconv.ParseInt(string(raw), 10, 64)
				if err != nil {
					log.Fatalln("Error when parsing ", raw, " from db:", err)
				}
			}
		}

		var resStatTime StatForTime
		resStatTime.time = result[0]
		resStatTime.keys = make(map[uint8]int)
		for index, val := range result[1:] {
			if val == 0 {
				continue
			}
			resStatTime.keys[uint8(keyNums[index])] = int(val)
		}
		res = append(res, resStatTime)
	}
	if err = rows.Err(); err != nil {
		log.Fatalln("Error when iterating over rows", err)
	}

	return res
}

// GetFileType extract extension from path if we support it
// Allowed if non-supported result with non supported path is wrong
func GetFileType(path string) string {
	if len(path) == 0 {
		return ""
	}
	Point := false
	for _, c := range path {
		if c == '.' {
			Point = true
		}
	}
	if !Point {
		return ""
	}

	path = strings.ToLower(path)

	if len(path) > 3 {
		if path[len(path)-3:] == ".gz" {
			return GetFileType(path[:len(path)-3]) + ".gz"
		}
	}

	i := len(path) - 1
	for path[i] != '.' {
		i--
		if i < 0 {
			break
		}
	}

	return path[i+1:]
}

func main() {

	keyboardID := flag.Int("id", -1, "Your keyboard id")
	outputPath := flag.String("o", "", "Path to export file")
	fullExport := flag.Bool("full", false, "Export full stats")
	flag.Parse()

	log.Println("keyboardID =", *keyboardID, "outputPath =", *outputPath)

	// Opening database
	db, err := sql.Open("sqlite3", DATABASE_NAME)
	if err != nil {
		log.Fatal(err)
	}
	db.SetMaxIdleConns(5)
	db.SetMaxOpenConns(5)
	defer db.Close()

	keyMap := GetKeymap()

	InitDb(db, keyMap)

	switch {
	case *keyboardID == -1 && *outputPath == "":
		flag.PrintDefaults()
		return
	case *keyboardID != -1:

		cmd := exec.Command("xinput", "test", strconv.Itoa(*keyboardID))

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := cmd.Start(); err != nil {
			log.Fatal(err)
		}

		// output of xinput command
		buf := make([]byte, KEYBOARD_BUFER_SIZE)

		timePeriodEnd := time.Now().Unix() - time.Now().Unix()%CAPTURE_TIME + CAPTURE_TIME
		var curStat StatForTime
		curStat.Init(timePeriodEnd)

		for {
			n, err := stdout.Read(buf)
			if err != nil {
				log.Fatal(err)
			}
			// processing buf here
			for _, keyNum := range GetKeyNumsFromOutput(buf[:n]) {
				oldKeyCount, _ := curStat.keys[keyNum]
				curStat.keys[keyNum] = oldKeyCount + 1
			}

			// Every CAPTURE_TIME seconds save to BD
			if time.Now().Unix()-timePeriodEnd > 0 {
				AddStatTimeToDb(db, curStat, keyMap)
				timePeriodEnd += CAPTURE_TIME
				curStat.Init(timePeriodEnd)
			}

			time.Sleep(SLEEP_TIME)
		}
	case *outputPath != "":
		exportingData := GetStatTimesFromDb(db, 0, keyMap)
		filetype := GetFileType(*outputPath)
		log.Println(filetype)
		switch filetype {
		case "csv":
			SaveToCsvFile(exportingData, keyMap, *outputPath, *fullExport)
		case "json":
			SaveToJSONFile(exportingData, keyMap, *outputPath, *fullExport)
		case "jsl":
			SaveToJSLFile(exportingData, keyMap, *outputPath, *fullExport)

		case "csv.gz":
			SaveToCsvGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case "json.gz":
			SaveToJSONGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case "jsl.gz":
			SaveToJSLGzFile(exportingData, keyMap, *outputPath, *fullExport)
		default:
			log.Fatal("Incorrect file type")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/maxmind/geoip2-csv-converter/convert"
)

func main() {
	input := flag.String("block-file", "", "The path to the block CSV file to use as input (REQUIRED)")
	output := flag.String("output-file", "", "The path to the output CSV (REQUIRED)")
	ipRange := flag.Bool("include-range", false, "Include the IP range of the network in string format")
	intRange := flag.Bool("include-integer-range", false, "Include the IP range of the network in integer format")
	cidr := flag.Bool("include-cidr", false, "Include the network in CIDR format")

	flag.Parse()

	var errors []string

	if *input == "" {
		errors = append(errors, "-block-file is required")
	}

	if *output == "" {
		errors = append(errors, "-output-file is required")
	}

	if !*ipRange && !*intRange && !*cidr {
		errors = append(errors, "-include-cidr, -include-range, or -include-integer-range is required")
	}

	args := flag.Args()
	if len(args) > 0 {
		errors = append(errors, "unknown argument(s): "+strings.Join(args, ", "))
	}

	if len(errors) != 0 {
		printHelp(errors)
		os.Exit(1)
	}

	err := convert.ConvertFile(*input, *output, *cidr, *ipRange, *intRange)
	if err != nil {
		fmt.Fprintf(flag.CommandLine.Output(), "Error: %v\n", err)
	}
}

func printHelp(errors []string) {
	for _, message := range errors {
		fmt.Fprintln(flag.CommandLine.Output(), message)
	}
	flag.PrintDefaults()
}
<commit_msg>Show flags passed<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/maxmind/geoip2-csv-converter/convert"
)

func main() {
	input := flag.String("block-file", "", "The path to the block CSV file to use as input (REQUIRED)")
	output := flag.String("output-file", "", "The path to the output CSV (REQUIRED)")
	ipRange := flag.Bool("include-range", false, "Include the IP range of the network in string format")
	intRange := flag.Bool("include-integer-range", false, "Include the IP range of the network in integer format")
	cidr := flag.Bool("include-cidr", false, "Include the network in CIDR format")

	flag.Parse()

	var errors []string

	if *input == "" {
		errors = append(errors, "-block-file is required")
	}

	if *output == "" {
		errors = append(errors, "-output-file is required")
	}

	if !*ipRange && !*intRange && !*cidr {
		errors = append(errors, "-include-cidr, -include-range, or -include-integer-range is required")
	}

	args := flag.Args()
	if len(args) > 0 {
		errors = append(errors, "unknown argument(s): "+strings.Join(args, ", "))
	}

	if len(errors) != 0 {
		printHelp(errors)
		os.Exit(1)
	}

	err := convert.ConvertFile(*input, *output, *cidr, *ipRange, *intRange)
	if err != nil {
		fmt.Fprintf(flag.CommandLine.Output(), "Error: %v\n", err)
	}
}

func printHelp(errors []string) {
	var passedFlags []string
	flag.Visit(func(f *flag.Flag) {
		passedFlags = append(passedFlags, "-"+f.Name)
	})

	if len(passedFlags) > 0 {
		errors = append(errors, "flags passed: "+strings.Join(passedFlags, ", "))
	}

	for _, message := range errors {
		fmt.Fprintln(flag.CommandLine.Output(), message)
	}

	flag.PrintDefaults()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/GeertJohan/go.rice"
	"github.com/gorilla/mux"
	"github.com/wmbest2/android/adb"
	"github.com/wmbest2/rats-server/rats"
	"github.com/wmbest2/rats-server/test"
	"io"
	"labix.org/v2/mgo"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var (
	mgoSession *mgo.Session

	mongodb = flag.String("db", "mongodb://localhost/rats", "Mongo db url")
	port    = flag.Int("port", 3000, "Port to serve")
	debug   = flag.Bool("debug", false, "Log debug information")
)

type RatsHandler func(http.ResponseWriter, *http.Request, *mgo.Database) error

type PageMeta struct {
	Page  int `json:"page"`
	Count int `json:"count"`
	Total int `json:"total"`
}

func (rh RatsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s := mgoSession.Clone()
	defer s.Close()

	err := rh(w, r, s.DB("rats"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func uuid() (string, error) {
	uuid := make([]byte, 16)
	n, err := rand.Read(uuid)
	if n != len(uuid) || err != nil {
		return "", err
	}
	// TODO: verify the two lines implement RFC 4122 correctly
	uuid[8] = 0x80 // variant bits see page 5
	uuid[4] = 0x40 // version 4 Pseudo Random, see page 7

	return hex.EncodeToString(uuid), nil
}

type byteCounter struct {
	Total int64
}

func (b *byteCounter) Write(p []byte) (int, error) {
	b.Total += int64(len(p))
	return len(p), nil
}

func getLength(reader io.ReadSeeker) int64 {
	reader.Seek(0, 0) // reset for new reader
	var counter byteCounter

	t := io.TeeReader(reader, &counter)

	buf := make([]byte, 4096)
	for {
		_, err := t.Read(buf)
		if err != nil {
			break
		}
	}

	reader.Seek(0, 0) // reset
	return counter.Total
}

func RunTests(w http.ResponseWriter, r *http.Request, db *mgo.Database) error {
	uuid, err := uuid()
	if err != nil {
		return err
	}
	main, _, err := r.FormFile("apk")
	testApk, _, err := r.FormFile("test-apk")
	if err != nil {
		return errors.New("A Test Apk must be supplied")
	}

	size := getLength(testApk)

	count, _ := strconv.Atoi(r.FormValue("count"))
	serialList := r.FormValue("serials")
	strict := r.FormValue("strict")
	msg := r.FormValue("message")

	var serials []string
	if serialList != "" {
		serials = strings.Split(serialList, ",")
	}

	filter := &rats.DeviceFilter{
		Count:  count,
		Strict: strict == "true",
	}
	filter.Serials = serials

	manifest := rats.GetManifest(testApk, size)
	filter.MinSdk = manifest.Sdk.Min
	filter.MaxSdk = manifest.Sdk.Max

	testApk.Seek(0, 0) // reset for new reader

	devices := <-rats.GetDevices(filter)
	rats.Reserve(devices...)

	// Remove old if left over
	rats.Uninstall(manifest.Package, devices...)
	rats.Uninstall(manifest.Instrument.Target, devices...)

	// Install New
	if main != nil {
		rats.Install("main.apk", main, devices...)
	}
	rats.Install("test.apk", testApk, devices...)

	rats.Unlock(devices)

	finished, out := test.RunTests(manifest, devices)

	var s *test.TestSuites
SuitesLoop:
	for {
		select {
		case s = <-out:
			break SuitesLoop
		case device := <-finished:
			go func() {
				rats.Uninstall(manifest.Package, device)
				rats.Uninstall(manifest.Instrument.Target, device)
				rats.Release(device)
			}()
		}
	}

	s.Name = uuid
	s.Timestamp = time.Now()
	s.Project = manifest.Instrument.Target
	if msg != "" {
		s.Message = msg
	}

	if dbErr := db.C("runs").Insert(&s); dbErr != nil {
		w.WriteHeader(http.StatusConflict)
		json.NewEncoder(w).Encode(dbErr.Error())
	}

	if !s.Success {
		w.WriteHeader(http.StatusInternalServerError)
	}

	return json.NewEncoder(w).Encode(s)
}

func GetDevices(w http.ResponseWriter, r *http.Request, db *mgo.Database) error {
	return json.NewEncoder(w).Encode(<-rats.GetAllDevices())
}

func PingHandler(w http.ResponseWriter, r *http.Request, db *mgo.Database) error {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")

	return nil
}

func init() {
	flag.Parse()

	var err error
	mgoSession, err = mgo.Dial(*mongodb)
	if err != nil {
		log.Fatal(err)
	}
}

func tryStartAdb() {
	path := os.ExpandEnv("$ANDROID_HOME")
	if path != "" {
		path = filepath.Join(path, "platform-tools", "adb")
		b, err := exec.Command(path, "start-server").CombinedOutput()
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(string(b))
		}
	}
}

func refreshDevices(a *adb.Adb, inRecover bool) {
	defer func() {
		if e := recover(); e != nil {
			if !inRecover && a == adb.Default {
				fmt.Println("Couldn't connect to adb, attempting to recover")
				tryStartAdb()
				refreshDevices(a, true)
			} else if inRecover {
				fmt.Println("Still couldn't connect.  Make sure adb exists in $ANDROID_HOME\n\tor manually start it with 'adb start-server'")
				os.Exit(2)
			} else {
				fmt.Println(e)
				os.Exit(2)
			}
		}
	}()
	rats.UpdateAdb(a)
}

func main() {
	go refreshDevices(adb.Default, false)

	r := mux.NewRouter()

	r.Handle("/api/ping", RatsHandler(PingHandler))
	r.Handle("/api/devices", RatsHandler(GetDevices))
	r.Handle("/api/run", RatsHandler(RunTests))
	r.Handle("/api/runs", RatsHandler(GetRuns))
	r.Handle("/api/runs/{id}", RatsHandler(GetRun))
	r.Handle("/api/runs/{id}/{device}", RatsHandler(GetRunDevice))
	r.PathPrefix("/").Handler(http.FileServer(rice.MustFindBox(`public`).HTTPBox()))

	http.Handle("/", r)

	log.Printf("Listening on port %d\n", *port)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil); err != nil {
		log.Fatalf("Error starting server: %s\n", err.Error())
	}
}
<commit_msg>Added remote ports for rats<commit_after>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/GeertJohan/go.rice"
	"github.com/gorilla/mux"
	"github.com/wmbest2/android/adb"
	"github.com/wmbest2/rats-server/rats"
	"github.com/wmbest2/rats-server/test"
	"io"
	"labix.org/v2/mgo"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var (
	mgoSession *mgo.Session

	mongodb = flag.String("db", "mongodb://localhost/rats", "Mongo db url")
	port    = flag.Int("port", 3000, "Port to serve")
	debug   = flag.Bool("debug", false, "Log debug information")

	adb_address = flag.String("adb_address", "localhost", "Address of ADB server")
	adb_port    = flag.Int("adb_port", 5037, "Port of ADB server")
)

type RatsHandler func(http.ResponseWriter, *http.Request, *mgo.Database) error

type PageMeta struct {
	Page  int `json:"page"`
	Count int `json:"count"`
	Total int `json:"total"`
}

func (rh RatsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s := mgoSession.Clone()
	defer s.Close()

	err := rh(w, r, s.DB("rats"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func uuid() (string, error) {
	uuid := make([]byte, 16)
	n, err := rand.Read(uuid)
	if n != len(uuid) || err != nil {
		return "", err
	}
	// TODO: verify the two lines implement RFC 4122 correctly
	uuid[8] = 0x80 // variant bits see page 5
	uuid[4] = 0x40 // version 4 Pseudo Random, see page 7

	return hex.EncodeToString(uuid), nil
}

type byteCounter struct {
	Total int64
}

func (b *byteCounter) Write(p []byte) (int, error) {
	b.Total += int64(len(p))
	return len(p), nil
}

func getLength(reader io.ReadSeeker) int64 {
	reader.Seek(0, 0) // reset for new reader
	var counter byteCounter

	t := io.TeeReader(reader, &counter)

	buf := make([]byte, 4096)
	for {
		_, err := t.Read(buf)
		if err != nil {
			break
		}
	}

	reader.Seek(0, 0) // reset
	return counter.Total
}

func RunTests(w http.ResponseWriter, r *http.Request, db *mgo.Database) error {
	uuid, err := uuid()
	if err != nil {
		return err
	}
	main, _, err := r.FormFile("apk")
	testApk, _, err := r.FormFile("test-apk")
	if err != nil {
		return errors.New("A Test Apk must be supplied")
	}

	size := getLength(testApk)

	count, _ := strconv.Atoi(r.FormValue("count"))
	serialList := r.FormValue("serials")
	strict := r.FormValue("strict")
	msg := r.FormValue("message")

	var serials []string
	if serialList != "" {
		serials = strings.Split(serialList, ",")
	}

	filter := &rats.DeviceFilter{
		Count:  count,
		Strict: strict == "true",
	}
	filter.Serials = serials

	manifest := rats.GetManifest(testApk, size)
	filter.MinSdk = manifest.Sdk.Min
	filter.MaxSdk = manifest.Sdk.Max

	testApk.Seek(0, 0) // reset for new reader

	devices := <-rats.GetDevices(filter)
	rats.Reserve(devices...)

	// Remove old if left over
	rats.Uninstall(manifest.Package, devices...)
	rats.Uninstall(manifest.Instrument.Target, devices...)

	// Install New
	if main != nil {
		rats.Install("main.apk", main, devices...)
	}
	rats.Install("test.apk", testApk, devices...)

	rats.Unlock(devices)

	finished, out := test.RunTests(manifest, devices)

	var s *test.TestSuites
SuitesLoop:
	for {
		select {
		case s = <-out:
			break SuitesLoop
		case device := <-finished:
			go func() {
				rats.Uninstall(manifest.Package, device)
				rats.Uninstall(manifest.Instrument.Target, device)
				rats.Release(device)
			}()
		}
	}

	s.Name = uuid
	s.Timestamp = time.Now()
	s.Project = manifest.Instrument.Target
	if msg != "" {
		s.Message = msg
	}

	if dbErr := db.C("runs").Insert(&s); dbErr != nil {
		w.WriteHeader(http.StatusConflict)
		json.NewEncoder(w).Encode(dbErr.Error())
	}

	if !s.Success {
		w.WriteHeader(http.StatusInternalServerError)
	}

	return json.NewEncoder(w).Encode(s)
}

func GetDevices(w http.ResponseWriter, r *http.Request, db *mgo.Database) error {
	return json.NewEncoder(w).Encode(<-rats.GetAllDevices())
}

func PingHandler(w http.ResponseWriter, r *http.Request, db *mgo.Database) error {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")

	return nil
}

func init() {
	flag.Parse()

	var err error
	mgoSession, err = mgo.Dial(*mongodb)
	if err != nil {
		log.Fatal(err)
	}
}

func tryStartAdb() {
	path := os.ExpandEnv("$ANDROID_HOME")
	if path != "" {
		path = filepath.Join(path, "platform-tools", "adb")
		b, err := exec.Command(path, "start-server").CombinedOutput()
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(string(b))
		}
	}
}

func refreshDevices(a *adb.Adb, inRecover bool) {
	defer func() {
		if e := recover(); e != nil {
			if !inRecover && a == adb.Default {
				fmt.Println("Couldn't connect to adb, attempting to recover")
				tryStartAdb()
				refreshDevices(a, true)
			} else if inRecover {
				fmt.Println("Still couldn't connect.  Make sure adb exists in $ANDROID_HOME\n\tor manually start it with 'adb start-server'")
				os.Exit(2)
			} else {
				fmt.Println(e)
				os.Exit(2)
			}
		}
	}()
	rats.UpdateAdb(a)
}

func main() {
	conn := adb.Default
	if *adb_address != "localhost" || *adb_port != 5037 {
		conn = adb.Connect(*adb_address, *adb_port)
	}
	go refreshDevices(conn, false)

	r := mux.NewRouter()

	r.Handle("/api/ping", RatsHandler(PingHandler))
	r.Handle("/api/devices", RatsHandler(GetDevices))
	r.Handle("/api/run", RatsHandler(RunTests))
	r.Handle("/api/runs", RatsHandler(GetRuns))
	r.Handle("/api/runs/{id}", RatsHandler(GetRun))
	r.Handle("/api/runs/{id}/{device}", RatsHandler(GetRunDevice))
	r.PathPrefix("/").Handler(http.FileServer(rice.MustFindBox(`public`).HTTPBox()))

	http.Handle("/", r)

	log.Printf("Listening on port %d\n", *port)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil); err != nil {
		log.Fatalf("Error starting server: %s\n", err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"pkg/proxy"
	"strings"
)

func main() {
	host, port, container := parseHostContainerAddrs()

	err := exposePort(host, port)
	if err != nil {
		sendError(err)
	}
	p, err := proxy.NewProxy(host, container)
	if err != nil {
		unexposePort(host)
		sendError(err)
	}
	go handleStopSignals(p)
	sendOK()
	p.Run()
	unexposePort(host)
	os.Exit(0)
}

func exposePort(host net.Addr, port int) error {
	name := host.String()
	log.Printf("exposePort %s\n", name)
	err := os.Mkdir("/port/"+name, 0)
	if err != nil {
		log.Printf("Failed to mkdir /port/%s: %#v\n", name, err)
		return err
	}
	ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0)
	if err != nil {
		log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
		return err
	}
	me, err := getMyAddress()
	if err != nil {
		log.Printf("Failed to determine my local address: %#v\n", err)
		return err
	}
	_, err = ctl.WriteString(fmt.Sprintf("%s:%s:%d", name, me, port))
	if err != nil {
		log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
		return err
	}
	_, err = ctl.Seek(0, 0)
	if err != nil {
		log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err)
		return err
	}
	results := make([]byte, 100)
	count, err := ctl.Read(results)
	if err != nil {
		log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err)
		return err
	}
	// TODO: consider whether close/clunk of ctl would be a better tear down
	// signal
	ctl.Close()

	response := string(results[0:count])
	if strings.HasPrefix(response, "ERROR ") {
		os.Remove("/port/" + name + "/ctl")
		response = strings.Trim(response[6:], " \t\r\n")
		return errors.New(response)
	}

	return nil
}

func unexposePort(host net.Addr) {
	name := host.String()
	log.Printf("unexposePort %s\n", name)
	err := os.Remove("/port/" + name)
	if err != nil {
		log.Printf("Failed to remove /port/%s: %#v\n", name, err)
	}
}

var myAddress string

// getMyAddress returns a string representing my address from the host's
// point of view. For now this is an IP address but it soon should be a vsock
// port.
func getMyAddress() (string, error) {
	if myAddress != "" {
		return myAddress, nil
	}
	d, err := os.Open("/port/docker")
	if err != nil {
		return "", err
	}
	defer d.Close()
	bytes := make([]byte, 100)
	count, err := d.Read(bytes)
	if err != nil {
		return "", err
	}
	s := string(bytes)[0:count]
	bits := strings.Split(s, ":")
	myAddress = bits[2]
	return myAddress, nil
}
<commit_msg>proxy: keep the fd open to the control file<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"pkg/proxy"
	"strings"
)

func main() {
	host, port, container := parseHostContainerAddrs()

	err := exposePort(host, port)
	if err != nil {
		sendError(err)
	}
	p, err := proxy.NewProxy(host, container)
	if err != nil {
		unexposePort(host)
		sendError(err)
	}
	go handleStopSignals(p)
	sendOK()
	p.Run()
	unexposePort(host)
	os.Exit(0)
}

func exposePort(host net.Addr, port int) error {
	name := host.String()
	log.Printf("exposePort %s\n", name)
	err := os.Mkdir("/port/"+name, 0)
	if err != nil {
		log.Printf("Failed to mkdir /port/%s: %#v\n", name, err)
		return err
	}
	ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0)
	if err != nil {
		log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
		return err
	}
	me, err := getMyAddress()
	if err != nil {
		log.Printf("Failed to determine my local address: %#v\n", err)
		return err
	}
	_, err = ctl.WriteString(fmt.Sprintf("%s:%s:%d", name, me, port))
	if err != nil {
		log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
		return err
	}
	_, err = ctl.Seek(0, 0)
	if err != nil {
		log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err)
		return err
	}
	results := make([]byte, 100)
	count, err := ctl.Read(results)
	if err != nil {
		log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err)
		return err
	}
	// We deliberately keep the control file open since 9P clunk
	// will trigger a shutdown on the host side.

	response := string(results[0:count])
	if strings.HasPrefix(response, "ERROR ") {
		os.Remove("/port/" + name + "/ctl")
		response = strings.Trim(response[6:], " \t\r\n")
		return errors.New(response)
	}

	return nil
}

func unexposePort(host net.Addr) {
	name := host.String()
	log.Printf("unexposePort %s\n", name)
	err := os.Remove("/port/" + name)
	if err != nil {
		log.Printf("Failed to remove /port/%s: %#v\n", name, err)
	}
}

var myAddress string

// getMyAddress returns a string representing my address from the host's
// point of view. For now this is an IP address but it soon should be a vsock
// port.
func getMyAddress() (string, error) {
	if myAddress != "" {
		return myAddress, nil
	}
	d, err := os.Open("/port/docker")
	if err != nil {
		return "", err
	}
	defer d.Close()
	bytes := make([]byte, 100)
	count, err := d.Read(bytes)
	if err != nil {
		return "", err
	}
	s := string(bytes)[0:count]
	bits := strings.Split(s, ":")
	myAddress = bits[2]
	return myAddress, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"github.com/robhurring/jit/commands"
)

const (
	Version = "1.0.0"
)

func main() {
	app := cli.NewApp()
	app.Name = "jit"
	app.Usage = "Jira + Git: A workflow story"
	app.Version = Version
	app.Author = "Rob Hurring"
	app.Email = "robhurring@gmail.com"
	app.Action = func(c *cli.Context) {
		cli.ShowAppHelp(c)
	}
	commands.CmdRunner.Execute(app)
}
<commit_msg>version bump<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"github.com/robhurring/jit/commands"
)

const (
	Version = "1.0.2"
)

func main() {
	app := cli.NewApp()
	app.Name = "jit"
	app.Usage = "Jira + Git: A workflow story"
	app.Version = Version
	app.Author = "Rob Hurring"
	app.Email = "robhurring@gmail.com"
	app.Action = func(c *cli.Context) {
		cli.ShowAppHelp(c)
	}
	commands.CmdRunner.Execute(app)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"time"

	"github.com/ninjasphere/go-ninja/api"
	nlog "github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/support"
	"github.com/ninjasphere/sphere-go-led-controller/model"
	"github.com/paypal/gatt"
)

const WirelessNetworkInterface = "wlan0"

// consider the wifi to be invalid after this timeout
const WirelessStaleTimeout = time.Second * 30 // FIXME: INCREASE THIS. a few minutes at least when not in testing.

var firewallHook = flag.Bool("firewall-hook", false, "Sets up the firewall based on configuration options, and nothing else.")
var factoryReset = false

// factoryReset - we can't use anything that requires MQTT in this mode

var logger = nlog.GetLogger("sphere-setup")

func main() {
	// ap0 adhoc/hostap management
	flag.BoolVar(&factoryReset, "factory-reset", false, "Run in factory reset mode.")

	go func() {
		support.WaitUntilSignal()
	}()

	config := LoadConfig("/etc/opt/ninja/setup-assistant.conf")
	apManager := NewAccessPointManager(config)

	flag.Parse()
	if *firewallHook {
		logger.Debugf("Setting ip firewall rules...")
		apManager.SetupFirewall()
		return
	}
	var pairing_ui ConsolePairingUI
	var controlChecker *ControlChecker

	restartHeartbeat := false

	startResetMonitor(func(m *model.ResetMode) {
		if pairing_ui == nil || controlChecker == nil {
			return
		}
		if m.Mode == "none" {
			if restartHeartbeat {
				// only restart the heartbeat if we stopped it previously
				controlChecker.StartHeartbeat()
			}
		} else {
			restartHeartbeat = controlChecker.StopHeartbeat()
			pairing_ui.DisplayResetMode(m)
		}
	})

	apManager.WriteAPConfig()
	if config.Wireless_Host.Always_Active {
		apManager.StartHostAP()
	} else {
		apManager.StopHostAP()
	}

	// wlan0 client management
	wifi_manager, err := NewWifiManager(WirelessNetworkInterface)
	if err != nil {
		log.Fatal("Could not setup manager for wlan0, does the interface exist?: %v", err)
	}
	defer wifi_manager.Cleanup()

	// When in reset mode, this will talk to the led matrix directly,
	// otherwise, it will use sphere-go-led-controller via mqtt.
	pairing_ui, err = NewPairingUI()
	if err != nil {
		log.Fatal("Could not setup ninja connection")
	}

	// This name is sent in the BLE advertising packet,
	// and is used by the phone to see that this is a
	// sphere, and if it is in factory reset mode.
	serviceName := "ninjasphere"
	if factoryReset {
		serviceName = "resetsphere"
	}

	srv := &gatt.Server{
		Name: serviceName,
		Connect: func(c gatt.Conn) {
			logger.Infof("BLE Connect")
			pairing_ui.DisplayIcon("ble-connected.gif")
		},
		Disconnect: func(c gatt.Conn) {
			logger.Infof("BLE Disconnect")
			pairing_ui.DisplayIcon("ble-disconnected.gif")
		},
		StateChange: func(state string) {
			logger.Infof("BLE State Change: %s", state)
		},
	}

	var conn *ninja.Connection

	if !factoryReset {

		conn, err = ninja.Connect("sphere-setup-assistant-updates")

		if err != nil {
			logger.FatalErrorf(err, "Failed to connect to mqtt")
		}
	}

	// start by registering the RPC functions that will be accessible
	// once the client has authenticated
	// We pass in the ble server so that we can close the connection once the updates are installed
	// (THIS SHOULD HAPPEN OVER WIFI INSTEAD!)
	rpc_router := GetSetupRPCRouter(conn, wifi_manager, srv, pairing_ui)

	StartHTTPServer(conn, wifi_manager, pairing_ui)

	auth_handler := new(OneTimeAuthHandler)
	auth_handler.Init("spheramid")

	controlChecker = NewControlChecker(pairing_ui)

	RegisterSecuredRPCService(srv, rpc_router, auth_handler, pairing_ui)

	// Start the server
	//log.Println("Starting setup assistant...");
	//log.Fatal(srv.AdvertiseAndServe())

	states := wifi_manager.WatchState()

	//wifi_manager.WifiConfigured()

	var wireless_stale *time.Timer

	is_serving_pairer := false

	// start by forcing the state to Disconnected.
	// reloading the configuration in wpa_supplicant will also force this,
	// but we need to do it here in case we are already disconnected
	states <- WifiStateDisconnected
	wifi_manager.Controller.ReloadConfiguration()

	handleBadWireless := func() {
		logger.Warningf("Wireless is stale! Invalid SSID, router down, or not in range.")

		if !is_serving_pairer {
			is_serving_pairer = true
			logger.Infof("Launching BLE pairing assistant...")
			go srv.AdvertiseAndServe()

			// and if the hostap isn't normally active, make it active
			if !config.Wireless_Host.Always_Active {
				logger.Infof("Launching AdHoc pairing assistant...")
				apManager.StartHostAP()
			}
		}
	}

	wifi_configured, _ := wifi_manager.WifiConfigured()
	if !wifi_configured {
		// when wireless isn't configured at all, automatically start doing this, don't wait for staleness
		handleBadWireless()
	}

	if config.Wireless_Host.Enables_Control {
		// the wireless AP causes control to be enabled, so we just start the heartbeat immediately
		controlChecker.StartHeartbeat()
	}

	for {
		state := <-states
		logger.Infof("State: %v", state)

		switch state {
		case WifiStateConnected:
			if wireless_stale != nil {
				wireless_stale.Stop()
			}
			wireless_stale = nil
			logger.Infof("Connected and attempting to get IP.")

			/*if !config.Wireless_Host.Enables_Control {
				// if the wireless AP mode hasn't already enabled normal control, then enable it now that wifi works
				controlChecker.StartHeartbeat()
			}*/

			if is_serving_pairer {
				is_serving_pairer = false

				// We need to keep the server open for now, as we are sending update progress to it, and accepting
				// led drawing messages. Later, this will be over wifi and we can close it here.
				//srv.Close()

				// and if the hostap isn't normally active, turn it off again
				if !config.Wireless_Host.Always_Active {
					logger.Infof("Terminating AdHoc pairing assistant.")
					apManager.StopHostAP()
				}
			}

		case WifiStateDisconnected:
			if wireless_stale == nil {
				wireless_stale = time.AfterFunc(WirelessStaleTimeout, handleBadWireless)
			}

		case WifiStateInvalidKey:
			if wireless_stale == nil {
				wireless_stale = time.AfterFunc(WirelessStaleTimeout, handleBadWireless)
			}
			wifi_configured, _ = wifi_manager.WifiConfigured()
			if wifi_configured {
				// not stale, we actually know the key is wrong
				// FIXME: report back to the user! for now we're just going to let staleness timeout
				/*if wireless_stale != nil {
					wireless_stale.Stop()
				}
				wireless_stale = nil*/

				logger.Warningf("Wireless key is invalid!")
			}
		}
	}
}
<commit_msg>Quit when network acquired.<commit_after>package main

import (
	"flag"
	"log"
	"time"

	"github.com/ninjasphere/go-ninja/api"
	nlog "github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/support"
	"github.com/ninjasphere/sphere-go-led-controller/model"
	"github.com/paypal/gatt"
)

const WirelessNetworkInterface = "wlan0"

// consider the wifi to be invalid after this timeout
const WirelessStaleTimeout = time.Second * 30 // FIXME: INCREASE THIS. a few minutes at least when not in testing.

var firewallHook = flag.Bool("firewall-hook", false, "Sets up the firewall based on configuration options, and nothing else.")
var factoryReset = false

// factoryReset - we can't use anything that requires MQTT in this mode

var logger = nlog.GetLogger("sphere-setup")

func main() {
	// ap0 adhoc/hostap management
	flag.BoolVar(&factoryReset, "factory-reset", false, "Run in factory reset mode.")

	go func() {
		support.WaitUntilSignal()
	}()

	config := LoadConfig("/etc/opt/ninja/setup-assistant.conf")
	apManager := NewAccessPointManager(config)

	flag.Parse()
	if *firewallHook {
		logger.Debugf("Setting ip firewall rules...")
		apManager.SetupFirewall()
		return
	}
	var pairing_ui ConsolePairingUI
	var controlChecker *ControlChecker

	restartHeartbeat := false

	startResetMonitor(func(m *model.ResetMode) {
		if pairing_ui == nil || controlChecker == nil {
			return
		}
		if m.Mode == "none" {
			if restartHeartbeat {
				// only restart the heartbeat if we stopped it previously
				controlChecker.StartHeartbeat()
			}
		} else {
			restartHeartbeat = controlChecker.StopHeartbeat()
			pairing_ui.DisplayResetMode(m)
		}
	})

	apManager.WriteAPConfig()
	if config.Wireless_Host.Always_Active {
		apManager.StartHostAP()
	} else {
		apManager.StopHostAP()
	}

	// wlan0 client management
	wifi_manager, err := NewWifiManager(WirelessNetworkInterface)
	if err != nil {
		log.Fatal("Could not setup manager for wlan0, does the interface exist?: %v", err)
	}
	defer wifi_manager.Cleanup()

	// When in reset mode, this will talk to the led matrix directly,
	// otherwise, it will use sphere-go-led-controller via mqtt.
	pairing_ui, err = NewPairingUI()
	if err != nil {
		log.Fatal("Could not setup ninja connection")
	}

	// This name is sent in the BLE advertising packet,
	// and is used by the phone to see that this is a
	// sphere, and if it is in factory reset mode.
	serviceName := "ninjasphere"
	if factoryReset {
		serviceName = "resetsphere"
	}

	srv := &gatt.Server{
		Name: serviceName,
		Connect: func(c gatt.Conn) {
			logger.Infof("BLE Connect")
			pairing_ui.DisplayIcon("ble-connected.gif")
		},
		Disconnect: func(c gatt.Conn) {
			logger.Infof("BLE Disconnect")
			pairing_ui.DisplayIcon("ble-disconnected.gif")
		},
		StateChange: func(state string) {
			logger.Infof("BLE State Change: %s", state)
		},
	}

	var conn *ninja.Connection

	if !factoryReset {

		conn, err = ninja.Connect("sphere-setup-assistant-updates")

		if err != nil {
			logger.FatalErrorf(err, "Failed to connect to mqtt")
		}
	}

	// start by registering the RPC functions that will be accessible
	// once the client has authenticated
	// We pass in the ble server so that we can close the connection once the updates are installed
	// (THIS SHOULD HAPPEN OVER WIFI INSTEAD!)
	rpc_router := GetSetupRPCRouter(conn, wifi_manager, srv, pairing_ui)

	StartHTTPServer(conn, wifi_manager, pairing_ui)

	auth_handler := new(OneTimeAuthHandler)
	auth_handler.Init("spheramid")

	controlChecker = NewControlChecker(pairing_ui)

	RegisterSecuredRPCService(srv, rpc_router, auth_handler, pairing_ui)

	// Start the server
	//log.Println("Starting setup assistant...");
	//log.Fatal(srv.AdvertiseAndServe())

	states := wifi_manager.WatchState()

	//wifi_manager.WifiConfigured()

	var wireless_stale *time.Timer

	is_serving_pairer := false

	// start by forcing the state to Disconnected.
	// reloading the configuration in wpa_supplicant will also force this,
	// but we need to do it here in case we are already disconnected
	states <- WifiStateDisconnected
	wifi_manager.Controller.ReloadConfiguration()

	handleBadWireless := func() {
		logger.Warningf("Wireless is stale! Invalid SSID, router down, or not in range.")

		if !is_serving_pairer {
			is_serving_pairer = true
			logger.Infof("Launching BLE pairing assistant...")
			go srv.AdvertiseAndServe()

			// and if the hostap isn't normally active, make it active
			if !config.Wireless_Host.Always_Active {
				logger.Infof("Launching AdHoc pairing assistant...")
				apManager.StartHostAP()
			}
		}
	}

	wifi_configured, _ := wifi_manager.WifiConfigured()
	if !wifi_configured {
		// when wireless isn't configured at all, automatically start doing this, don't wait for staleness
		handleBadWireless()
	}

	if config.Wireless_Host.Enables_Control {
		// the wireless AP causes control to be enabled, so we just start the heartbeat immediately
		controlChecker.StartHeartbeat()
	}

	for {
		state := <-states
		logger.Infof("State: %v", state)

		switch state {
		case WifiStateConnected:
			if wireless_stale != nil {
				wireless_stale.Stop()
			}
			wireless_stale = nil
			logger.Infof("Connected and attempting to get IP.")

			/*if !config.Wireless_Host.Enables_Control {
				// if the wireless AP mode hasn't already enabled normal control, then enable it now that wifi works
				controlChecker.StartHeartbeat()
			}*/

			if is_serving_pairer {
				is_serving_pairer = false

				// We need to keep the server open for now, as we are sending update progress to it, and accepting
				// led drawing messages. Later, this will be over wifi and we can close it here.
				//srv.Close()

				// and if the hostap isn't normally active, turn it off again
				if !config.Wireless_Host.Always_Active {
					logger.Infof("Terminating AdHoc pairing assistant.")
					apManager.StopHostAP()
				}
			}
			if factoryReset {
				logger.Infof("Network connected. Quitting.")
				os.Exit(0)
			}

		case WifiStateDisconnected:
			if wireless_stale == nil {
				wireless_stale = time.AfterFunc(WirelessStaleTimeout, handleBadWireless)
			}

		case WifiStateInvalidKey:
			if wireless_stale == nil {
				wireless_stale = time.AfterFunc(WirelessStaleTimeout, handleBadWireless)
			}
			wifi_configured, _ = wifi_manager.WifiConfigured()
			if wifi_configured {
				// not stale, we actually know the key is wrong
				// FIXME: report back to the user! for now we're just going to let staleness timeout
				/*if wireless_stale != nil {
					wireless_stale.Stop()
				}
				wireless_stale = nil*/

				logger.Warningf("Wireless key is invalid!")
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os/exec"
	"strings"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")

	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.tmpl", gin.H{
			"alert":   false,
			"error":   false,
			"message": "",
		})
	})

	r.POST("/submit", func(c *gin.Context) {
		username := c.PostForm("username")
		pubKey := c.PostForm("pubKey")

		// libcompose does not support `docker-compose run`...
		out, err := exec.Command("docker-compose", "run", "--rm", "gitreceive-upload-key", username, pubKey).Output()

		if err != nil {
			c.HTML(http.StatusInternalServerError, "index.tmpl", gin.H{
				"alert":   true,
				"error":   true,
				"message": strings.Join([]string{"error: ", err.Error()}, ""),
			})
		} else {
			c.HTML(http.StatusCreated, "index.tmpl", gin.H{
				"alert":   true,
				"error":   false,
				"message": strings.Join([]string{"fingerprint: ", string(out)}, ""),
			})
		}
	})

	r.Run()
}
<commit_msg>Specify project name<commit_after>package main

import (
	"net/http"
	"os/exec"
	"strings"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")

	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.tmpl", gin.H{
			"alert":   false,
			"error":   false,
			"message": "",
		})
	})

	r.POST("/submit", func(c *gin.Context) {
		username := c.PostForm("username")
		pubKey := c.PostForm("pubKey")

		// libcompose does not support `docker-compose run`...
		out, err := exec.Command("docker-compose", "-p", "paus", "run", "--rm", "gitreceive-upload-key", username, pubKey).Output()

		if err != nil {
			c.HTML(http.StatusInternalServerError, "index.tmpl", gin.H{
				"alert":   true,
				"error":   true,
				"message": strings.Join([]string{"error: ", err.Error()}, ""),
			})
		} else {
			c.HTML(http.StatusCreated, "index.tmpl", gin.H{
				"alert":   true,
				"error":   false,
				"message": strings.Join([]string{"fingerprint: ", string(out)}, ""),
			})
		}
	})

	r.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gin-gonic/gin"
)

type Host struct {
	Hostname string `json:"hostname"`
}

var (
	hosts []Host
)

func main() {
	router := gin.Default()

	router.POST("/checkin/", func(c *gin.Context) {
		var host Host

		c.Bind(&host)

		if host.Hostname != "" {
			hosts = append(hosts, host)
		}

		c.String(200, "")
	})

	router.Run(":8080")
}
<commit_msg>Checked if a host already exists on the checkin endpoint<commit_after>package main

import (
	"github.com/gin-gonic/gin"
)

type Host struct {
	Hostname string `json:"hostname"`
}

var (
	hosts []Host
)

func main() {
	router := gin.Default()

	router.POST("/checkin/", func(c *gin.Context) {
		var host Host

		c.Bind(&host)

		if host.Hostname != "" {
			exists := false
			for _, h := range hosts {
				if h.Hostname == host.Hostname {
					exists = true
				}
			}
			if !exists {
				hosts = append(hosts, host)
			}
		}

		c.String(200, "")
	})

	router.Run(":8080")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"

	"github.com/jessevdk/go-flags"
	"github.com/sosedoff/musicbot/bot"
)

const version = "0.1.0"

var options struct {
	MopidyHost   string `long:"mopidy" description:"Mopidy server host:port" env:"MOPIDY_HOST"`
	SlackToken   string `long:"slack-token" description:"Slack integration token" env:"SLACK_TOKEN"`
	SlackChannel string `long:"slack-channel" description:"Slack channel name" default:"general" env:"SLACK_CHANNEL"`
	Debug        bool   `short:"d" long:"debug" description:"Enable debugging mode" default:"false"`
	Version      bool   `short:"v" long:"version" description:"Print version"`
}

func init() {
	_, err := flags.ParseArgs(&options, os.Args)

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

	if options.Version {
		fmt.Printf("musicbot v%s\n", version)
		os.Exit(0)
	}

	if options.MopidyHost == "" {
		fmt.Println("Error: Mopidy host is not provided")
		os.Exit(1)
	}

	if options.SlackToken == "" {
		fmt.Println("Error: Slack token is not provided")
		os.Exit(1)
	}
}

func handleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}

func main() {
	bot := bot.NewBot(bot.BotConfig{
		MopidyHost:   options.MopidyHost,
		SlackToken:   options.SlackToken,
		SlackChannel: options.SlackChannel,
		Debug:        options.Debug,
	})

	bot.Run()
	handleSignals()
}
<commit_msg>Removed default option for Debug flag<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"

	"github.com/jessevdk/go-flags"
	"github.com/sosedoff/musicbot/bot"
)

const version = "0.1.0"

var options struct {
	MopidyHost   string `long:"mopidy" description:"Mopidy server host:port" env:"MOPIDY_HOST"`
	SlackToken   string `long:"slack-token" description:"Slack integration token" env:"SLACK_TOKEN"`
	SlackChannel string `long:"slack-channel" description:"Slack channel name" default:"general" env:"SLACK_CHANNEL"`
	Debug        bool   `short:"d" long:"debug" description:"Enable debugging mode"`
	Version      bool   `short:"v" long:"version" description:"Print version"`
}

func init() {
	_, err := flags.ParseArgs(&options, os.Args)

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

	if options.Version {
		fmt.Printf("musicbot v%s\n", version)
		os.Exit(0)
	}

	if options.MopidyHost == "" {
		fmt.Println("Error: Mopidy host is not provided")
		os.Exit(1)
	}

	if options.SlackToken == "" {
		fmt.Println("Error: Slack token is not provided")
		os.Exit(1)
	}
}

func handleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}

func main() {
	bot := bot.NewBot(bot.BotConfig{
		MopidyHost:   options.MopidyHost,
		SlackToken:   options.SlackToken,
		SlackChannel: options.SlackChannel,
		Debug:        options.Debug,
	})

	bot.Run()
	handleSignals()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"image"
	"image/draw"
	_ "image/png"
	"os"
	"runtime"
	"strings"

	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/go-gl/mathgl/mgl32"
)

const windowWidth = 800
const windowHeight = 600

func init() {
	runtime.LockOSThread()
}

func main() {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	window, err := glfw.CreateWindow(windowWidth, windowHeight, "dusk", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()

	if err := gl.Init(); err != nil {
		panic(err)
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	fmt.Println("OpenGL version", version)

	program, err := newProgram(vertexShader, fragmentShader)
	if err != nil {
		panic(err)
	}

	gl.UseProgram(program)

	projection := mgl32.Perspective(mgl32.DegToRad(45.0), float32(windowWidth)/windowHeight, 0.1, 10.0)
	projectionUniform := gl.GetUniformLocation(program, gl.Str("projection\x00"))
	gl.UniformMatrix4fv(projectionUniform, 1, false, &projection[0])

	camera := mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0})
	cameraUniform := gl.GetUniformLocation(program, gl.Str("camera\x00"))
	gl.UniformMatrix4fv(cameraUniform, 1, false, &camera[0])

	model := mgl32.Ident4()
	modelUniform := gl.GetUniformLocation(program, gl.Str("model\x00"))
	gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])

	textureUniform := gl.GetUniformLocation(program, gl.Str("tex\x00"))
	gl.Uniform1i(textureUniform, 0)

	gl.BindFragDataLocation(program, 0, gl.Str("outputColor\x00"))

	// Load the texture
	texture, err := newTexture("data/texture.png")
	if err != nil {
		panic(err)
	}

	// Configure the vertex data
	var vao uint32
	gl.GenVertexArrays(1, &vao)
	gl.BindVertexArray(vao)

	var vbo uint32
	gl.GenBuffers(1, &vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, len(cubeVertices)*4, gl.Ptr(cubeVertices), gl.STATIC_DRAW)

	vertAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vert\x00")))
	gl.EnableVertexAttribArray(vertAttrib)
	gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0))

	texCoordAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vertTexCoord\x00")))
	gl.EnableVertexAttribArray(texCoordAttrib)
	gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4))

	// Configure global settings
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)
	gl.ClearColor(1.0, 1.0, 1.0, 1.0)

	angle := 0.0
	gl.ClearColor(0.0, 0.0, 0.0, 1.0)

	previousTime := glfw.GetTime()

	for !window.ShouldClose() {
		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

		time := glfw.GetTime()
		elapsed := time - previousTime
		previousTime = time

		angle += elapsed
		model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0})

		// Render
		gl.UseProgram(program)
		gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])

		gl.BindVertexArray(vao)

		gl.ActiveTexture(gl.TEXTURE0)
		gl.BindTexture(gl.TEXTURE_2D, texture)

		gl.DrawArrays(gl.TRIANGLES, 0, 6*2*3)

		window.SwapBuffers()
		glfw.PollEvents()
	}
}

func newProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error) {
	vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
	if err != nil {
		return 0, err
	}

	fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
	if err != nil {
		return 0, err
	}

	program := gl.CreateProgram()

	gl.AttachShader(program, vertexShader)
	gl.AttachShader(program, fragmentShader)
	gl.LinkProgram(program)

	var status int32
	gl.GetProgramiv(program, gl.LINK_STATUS, &status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength)

		log := strings.Repeat("\x00", int(logLength+1))
		gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf("failed to link program: %v", log)
	}

	gl.DeleteShader(vertexShader)
	gl.DeleteShader(fragmentShader)

	return program, nil
}

func compileShader(source string, shaderType uint32) (uint32, error) {
	shader := gl.CreateShader(shaderType)

	csource := gl.Str(source)
	gl.ShaderSource(shader, 1, &csource, nil)
	gl.CompileShader(shader)

	var status int32
	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)

		log := strings.Repeat("\x00", int(logLength+1))
		gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf("failed to compile %v: %v", source, log)
	}

	return shader, nil
}

func newTexture(file string) (uint32, error) {
	imgFile, err := os.Open(file)
	if err != nil {
		return 0, err
	}
	img, _, err := image.Decode(imgFile)
	if err != nil {
		return 0, err
	}

	rgba := image.NewRGBA(img.Bounds())
	if rgba.Stride != rgba.Rect.Size().X*4 {
		return 0, fmt.Errorf("unsupported stride")
	}
	draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)

	var texture uint32
	gl.GenTextures(1, &texture)
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, texture)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	gl.TexImage2D(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		int32(rgba.Rect.Size().X),
		int32(rgba.Rect.Size().Y),
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(rgba.Pix))

	return texture, nil
}

var vertexShader = `
#version 330
uniform mat4 projection;
uniform mat4 camera;
uniform mat4 model;
in vec3 vert;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
    fragTexCoord = vertTexCoord;
    gl_Position = projection * camera * model * vec4(vert, 1);
}
` + "\x00"

var fragmentShader = `
#version 330
uniform sampler2D tex;
in vec2 fragTexCoord;
out vec4 outputColor;
void main() {
    outputColor = texture(tex, fragTexCoord);
}
` + "\x00"

var cubeVertices = []float32{
	//  X, Y, Z, U, V
	// Bottom
	-1.0, -1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,

	// Top
	-1.0, 1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, 1.0, 1.0, 1.0,

	// Front
	-1.0, -1.0, 1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,

	// Back
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 1.0,

	// Left
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,

	// Right
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
}
<commit_msg>goroutine<commit_after>package main

import (
	"fmt"
	"image"
	"image/draw"
	_ "image/png"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/go-gl/mathgl/mgl32"
)

const windowWidth = 800
const windowHeight = 600

func init() {
	runtime.LockOSThread()
}

func main() {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	window, err := glfw.CreateWindow(windowWidth, windowHeight, "dusk", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()

	if err := gl.Init(); err != nil {
		panic(err)
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	fmt.Println("OpenGL version", version)

	program, err := newProgram(vertexShader, fragmentShader)
	if err != nil {
		panic(err)
	}

	gl.UseProgram(program)

	projection := mgl32.Perspective(mgl32.DegToRad(45.0), float32(windowWidth)/windowHeight, 0.1, 10.0)
	projectionUniform := gl.GetUniformLocation(program, gl.Str("projection\x00"))
	gl.UniformMatrix4fv(projectionUniform, 1, false, &projection[0])

	camera := mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0})
	cameraUniform := gl.GetUniformLocation(program, gl.Str("camera\x00"))
	gl.UniformMatrix4fv(cameraUniform, 1, false, &camera[0])

	model := mgl32.Ident4()
	modelUniform := gl.GetUniformLocation(program, gl.Str("model\x00"))
	gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])

	textureUniform := gl.GetUniformLocation(program, gl.Str("tex\x00"))
	gl.Uniform1i(textureUniform, 0)

	gl.BindFragDataLocation(program, 0, gl.Str("outputColor\x00"))

	// Load the texture
	texture, err := newTexture("data/texture.png")
	if err != nil {
		panic(err)
	}

	// Configure the vertex data
	var vao uint32
	gl.GenVertexArrays(1, &vao)
	gl.BindVertexArray(vao)

	var vbo uint32
	gl.GenBuffers(1, &vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, len(cubeVertices)*4, gl.Ptr(cubeVertices), gl.STATIC_DRAW)

	vertAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vert\x00")))
	gl.EnableVertexAttribArray(vertAttrib)
	gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0))

	texCoordAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vertTexCoord\x00")))
	gl.EnableVertexAttribArray(texCoordAttrib)
	gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4))

	// Configure global settings
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)
	gl.ClearColor(1.0, 1.0, 1.0, 1.0)

	angle := 0.0
	gl.ClearColor(0.0, 0.0, 0.0, 1.0)

	frame := make(chan bool)

	tf := time.NewTicker(time.Second)
	defer tf.Stop()
	go func() {
		counter := 0
		for {
			select {
			case <-frame:
				counter++
			case <-tf.C:
				fmt.Println(counter)
				counter = 0
			}
		}
	}()

	t := time.NewTicker(16666 * time.Microsecond)
	defer t.Stop()
	go func() {
		for range t.C {
			angle += 0.01
		}
	}()

	t2 := time.NewTicker(16666 * time.Microsecond)
	defer t2.Stop()
	for !window.ShouldClose() {
		select {
		case <-t2.C:
			gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

			model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0})

			// Render
			gl.UseProgram(program)
			gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])

			gl.BindVertexArray(vao)

			gl.ActiveTexture(gl.TEXTURE0)
			gl.BindTexture(gl.TEXTURE_2D, texture)

			gl.DrawArrays(gl.TRIANGLES, 0, 6*2*3)

			window.SwapBuffers()
			glfw.PollEvents()

			frame <- true
		}
	}
}

func newProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error) {
	vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
	if err != nil {
		return 0, err
	}

	fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
	if err != nil {
		return 0, err
	}

	program := gl.CreateProgram()

	gl.AttachShader(program, vertexShader)
	gl.AttachShader(program, fragmentShader)
	gl.LinkProgram(program)

	var status int32
	gl.GetProgramiv(program, gl.LINK_STATUS, &status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength)

		log := strings.Repeat("\x00", int(logLength+1))
		gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf("failed to link program: %v", log)
	}

	gl.DeleteShader(vertexShader)
	gl.DeleteShader(fragmentShader)

	return program, nil
}

func compileShader(source string, shaderType uint32) (uint32, error) {
	shader := gl.CreateShader(shaderType)

	csource := gl.Str(source)
	gl.ShaderSource(shader, 1, &csource, nil)
	gl.CompileShader(shader)

	var status int32
	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)

		log := strings.Repeat("\x00", int(logLength+1))
		gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf("failed to compile %v: %v", source, log)
	}

	return shader, nil
}

func newTexture(file string) (uint32, error) {
	imgFile, err := os.Open(file)
	if err != nil {
		return 0, err
	}
	img, _, err := image.Decode(imgFile)
	if err != nil {
		return 0, err
	}

	rgba := image.NewRGBA(img.Bounds())
	if rgba.Stride != rgba.Rect.Size().X*4 {
		return 0, fmt.Errorf("unsupported stride")
	}
	draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)

	var texture uint32
	gl.GenTextures(1, &texture)
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, texture)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	gl.TexImage2D(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		int32(rgba.Rect.Size().X),
		int32(rgba.Rect.Size().Y),
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(rgba.Pix))

	return texture, nil
}

var vertexShader = `
#version 330
uniform mat4 projection;
uniform mat4 camera;
uniform mat4 model;
in vec3 vert;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
    fragTexCoord = vertTexCoord;
    gl_Position = projection * camera * model * vec4(vert, 1);
}
` + "\x00"

var fragmentShader = `
#version 330
uniform sampler2D tex;
in vec2 fragTexCoord;
out vec4 outputColor;
void main() {
    outputColor = texture(tex, fragTexCoord);
}
` + "\x00"

var cubeVertices = []float32{
	//  X, Y, Z, U, V
	// Bottom
	-1.0, -1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,

	// Top
	-1.0, 1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, 1.0, 1.0, 1.0,

	// Front
	-1.0, -1.0, 1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,

	// Back
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 1.0,

	// Left
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,

	// Right
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"runtime"
	"syscall"
	"time"

	"github.com/cespare/window"
	"github.com/codegangsta/cli"
	"github.com/jeanfric/goembed/countingwriter"
)

const Version = "0.3.1"

func usageAndExit(s string, c *cli.Context) {
	fmt.Printf("!! %s\n\n", s)
	cli.ShowAppHelp(c)
	os.Exit(1)
}

func init() {
	runtime.GOMAXPROCS(1)
	runtime.LockOSThread()
}

func main() {
	app := cli.NewApp()
	app.Name = "email-me"
	app.Version = Version
	app.Usage = "email me when a thing is done"
	app.Action = main2
	app.HideHelp = true
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "to",
			Value:  "",
			Usage:  "email address to send output to",
			EnvVar: "EMAIL_ME_TO",
		},
		cli.StringFlag{
			Name:  "subject, s",
			Value: "",
			Usage: "subject of email (optional)",
		},
		cli.IntFlag{
			Name:   "max",
			Value:  10000,
			Usage:  "max bytes to capture for stdout/stderr",
			EnvVar: "EMAIL_ME_MAX",
		},
		cli.BoolFlag{
			Name:  "on-error",
			Usage: "only notify on a non-0 exit code",
		},
	}
	app.Run(os.Args)
}

func main2(c *cli.Context) {
	to := c.String("to")
	max := c.Int("max")
	subject := c.String("subject")
	onError := c.Bool("on-error")

	if to == "" {
		usageAndExit("missing --to=[address]", c)
	}

	args := c.Args()
	if len(args) == 0 {
		usageAndExit("missing [command]", c)
	}

	truncStdout := window.NewWriter(max)
	truncStderr := window.NewWriter(max)
	countedStdout := countingwriter.New(truncStdout)
	countedStderr := countingwriter.New(truncStderr)
	child := exec.Command(args[0], args[1:]...)
	child.Stdout = io.MultiWriter(os.Stdout, countedStdout)
	child.Stderr = io.MultiWriter(os.Stderr, countedStderr)
	child.Stdin = os.Stdin

	start := time.Now()
	err := child.Run()
	end := time.Now()

	stdout := truncStdout.Bytes()
	stderr := truncStderr.Bytes()

	r := &Result{
		Cmd:         child,
		Error:       err,
		Start:       start,
		End:         end,
		Duration:    end.Sub(start),
		Stdout:      string(stdout),
		Stderr:      string(stderr),
		StdoutExtra: countedStdout.BytesWritten() - len(stdout),
		StderrExtra: countedStderr.BytesWritten() - len(stderr),
	}

	me := identity()
	if subject == "" {
		subject = fmt.Sprintf("%s", child.Args)
	}

	m := &Message{
		To:      to,
		From:    me,
		Subject: subject,
		Result:  r,
	}

	exitStatus := 0
	if !child.ProcessState.Success() {
		exitStatus = 1
	}

	// Try to fetch the actual status code if we can
	if status, ok := child.ProcessState.Sys().(syscall.WaitStatus); ok {
		exitStatus = status.ExitStatus()
	}

	if onError && exitStatus == 0 {
		os.Exit(0)
	}

	if err := findMailer().Send([]string{to}, me, m.Bytes()); err != nil {
		log.Fatal(err)
	}

	os.Exit(exitStatus)
}
<commit_msg>0.4.0<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"runtime"
	"syscall"
	"time"

	"github.com/cespare/window"
	"github.com/codegangsta/cli"
	"github.com/jeanfric/goembed/countingwriter"
)

const Version = "0.4.0"

func usageAndExit(s string, c *cli.Context) {
	fmt.Printf("!! %s\n\n", s)
	cli.ShowAppHelp(c)
	os.Exit(1)
}

func init() {
	runtime.GOMAXPROCS(1)
	runtime.LockOSThread()
}

func main() {
	app := cli.NewApp()
	app.Name = "email-me"
	app.Version = Version
	app.Usage = "email me when a thing is done"
	app.Action = main2
	app.HideHelp = true
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "to",
			Value:  "",
			Usage:  "email address to send output to",
			EnvVar: "EMAIL_ME_TO",
		},
		cli.StringFlag{
			Name:  "subject, s",
			Value: "",
			Usage: "subject of email (optional)",
		},
		cli.IntFlag{
			Name:   "max",
			Value:  10000,
			Usage:  "max bytes to capture for stdout/stderr",
			EnvVar: "EMAIL_ME_MAX",
		},
		cli.BoolFlag{
			Name:  "on-error",
			Usage: "only notify on a non-0 exit code",
		},
	}
	app.Run(os.Args)
}

func main2(c *cli.Context) {
	to := c.String("to")
	max := c.Int("max")
	subject := c.String("subject")
	onError := c.Bool("on-error")

	if to == "" {
		usageAndExit("missing --to=[address]", c)
	}

	args := c.Args()
	if len(args) == 0 {
		usageAndExit("missing [command]", c)
	}

	truncStdout := window.NewWriter(max)
	truncStderr := window.NewWriter(max)
	countedStdout := countingwriter.New(truncStdout)
	countedStderr := countingwriter.New(truncStderr)
	child := exec.Command(args[0], args[1:]...)
	child.Stdout = io.MultiWriter(os.Stdout, countedStdout)
	child.Stderr = io.MultiWriter(os.Stderr, countedStderr)
	child.Stdin = os.Stdin

	start := time.Now()
	err := child.Run()
	end := time.Now()

	stdout := truncStdout.Bytes()
	stderr := truncStderr.Bytes()

	r := &Result{
		Cmd:         child,
		Error:       err,
		Start:       start,
		End:         end,
		Duration:    end.Sub(start),
		Stdout:      string(stdout),
		Stderr:      string(stderr),
		StdoutExtra: countedStdout.BytesWritten() - len(stdout),
		StderrExtra: countedStderr.BytesWritten() - len(stderr),
	}

	me := identity()
	if subject == "" {
		subject = fmt.Sprintf("%s", child.Args)
	}

	m := &Message{
		To:      to,
		From:    me,
		Subject: subject,
		Result:  r,
	}

	exitStatus := 0
	if !child.ProcessState.Success() {
		exitStatus = 1
	}

	// Try to fetch the actual status code if we can
	if status, ok := child.ProcessState.Sys().(syscall.WaitStatus); ok {
		exitStatus = status.ExitStatus()
	}

	if onError && exitStatus == 0 {
		os.Exit(0)
	}

	if err := findMailer().Send([]string{to}, me, m.Bytes()); err != nil {
		log.Fatal(err)
	}

	os.Exit(exitStatus)
}
<|endoftext|>