<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/user"
	"sync"
	"time"
)

var flightPaths *[]*flightPath
var flightPathsJson string
var filePermissions os.FileMode = 0664
var port = flag.String("port", "80", "Specify which port to use as a webserver")
var webPageFile = flag.String("outFile", "", "Specify where to write the generated webpage. This overrides any webserver settings and cancels the server.")

var START_LOCATIONS = []location{
	location{Latitude: 45.220, Longitude: -111.761},
}

var ALTITUDES = []int{10000, 20000, 30000, 50000, 60000}

var REQUEST_INTERVAL_STRING = "6h"

var DB_FILE string = "/.balloontrackerDb.db"

type pageData struct {
	JsonFlightData string
}

func main() {
	flag.Parse()

	usr, _ := user.Current()
	dbPath := usr.HomeDir + DB_FILE
	db := openDb(dbPath)

	var waitGroup sync.WaitGroup
	intervalDuration, err := time.ParseDuration(REQUEST_INTERVAL_STRING)
	if err != nil {
		log.Fatal(err)
	}
	beginRequesting(START_LOCATIONS, ALTITUDES, intervalDuration, db, &waitGroup)
	//	initDataManager(updateFlightData, &waitGroup)
	fmt.Println("Datamanger initialized")

	/*	if len(*webPageFile) <= 0 {
			fmt.Println("Now listening for http requests on port", ":"+*port)
			http.HandleFunc("/", requestHandler)
			http.ListenAndServe(":"+*port, nil)
		}
	*/
	waitGroup.Wait()
}

func writeWebPageToFile(fullFilePath string) {
	var fileBuf bytes.Buffer
	executeInterfaceTemplate(&fileBuf)
	ioutil.WriteFile(fullFilePath, fileBuf.Bytes(), filePermissions)
	fmt.Println("Wrote updated webpage to", fullFilePath)
}

func executeInterfaceTemplate(destination io.Writer) {
	t, err := template.ParseFiles("interface.html")
	if err != nil {
		log.Fatal(err)
	}
	page := &pageData{JsonFlightData: flightPathsJson}
	err = t.Execute(destination, page)
}

func requestHandler(writer http.ResponseWriter, request *http.Request) {
	executeInterfaceTemplate(writer)
}

func updateFlightData(updatedList *[]*flightPath) {
	flightPaths = updatedList
	jsonArray, error := json.Marshal(flightPaths)
	if error != nil {
		log.Fatal(error)
	}
	var jsonBuffer bytes.Buffer
	json.HTMLEscape(&jsonBuffer, jsonArray)

	//	fmt.Println(string(jsonArray))
	flightPathsJson = jsonBuffer.String() //string(jsonArray)
	if len(*webPageFile) > 0 {
		writeWebPageToFile(*webPageFile)
	}
}
<commit_msg>change altitudes to request<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/user"
	"sync"
	"time"
)

var flightPaths *[]*flightPath
var flightPathsJson string
var filePermissions os.FileMode = 0664
var port = flag.String("port", "80", "Specify which port to use as a webserver")
var webPageFile = flag.String("outFile", "", "Specify where to write the generated webpage. This overrides any webserver settings and cancels the server.")

var START_LOCATIONS = []location{
	location{Latitude: 45.220, Longitude: -111.761},
}

var ALTITUDES = []int{8000, 10000, 12000, 15000, 18000, 20000, 30000, 50000}

var REQUEST_INTERVAL_STRING = "6h"

var DB_FILE string = "/.balloontrackerDb.db"

type pageData struct {
	JsonFlightData string
}

func main() {
	flag.Parse()

	usr, _ := user.Current()
	dbPath := usr.HomeDir + DB_FILE
	db := openDb(dbPath)

	var waitGroup sync.WaitGroup
	intervalDuration, err := time.ParseDuration(REQUEST_INTERVAL_STRING)
	if err != nil {
		log.Fatal(err)
	}
	beginRequesting(START_LOCATIONS, ALTITUDES, intervalDuration, db, &waitGroup)
	//	initDataManager(updateFlightData, &waitGroup)
	fmt.Println("Datamanger initialized")

	/*	if len(*webPageFile) <= 0 {
			fmt.Println("Now listening for http requests on port", ":"+*port)
			http.HandleFunc("/", requestHandler)
			http.ListenAndServe(":"+*port, nil)
		}
	*/
	waitGroup.Wait()
}

func writeWebPageToFile(fullFilePath string) {
	var fileBuf bytes.Buffer
	executeInterfaceTemplate(&fileBuf)
	ioutil.WriteFile(fullFilePath, fileBuf.Bytes(), filePermissions)
	fmt.Println("Wrote updated webpage to", fullFilePath)
}

func executeInterfaceTemplate(destination io.Writer) {
	t, err := template.ParseFiles("interface.html")
	if err != nil {
		log.Fatal(err)
	}
	page := &pageData{JsonFlightData: flightPathsJson}
	err = t.Execute(destination, page)
}

func requestHandler(writer http.ResponseWriter, request *http.Request) {
	executeInterfaceTemplate(writer)
}

func updateFlightData(updatedList *[]*flightPath) {
	flightPaths = updatedList
	jsonArray, error := json.Marshal(flightPaths)
	if error != nil {
		log.Fatal(error)
	}
	var jsonBuffer bytes.Buffer
	json.HTMLEscape(&jsonBuffer, jsonArray)

	//	fmt.Println(string(jsonArray))
	flightPathsJson = jsonBuffer.String() //string(jsonArray)
	if len(*webPageFile) > 0 {
		writeWebPageToFile(*webPageFile)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/goweb/goweb"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"launchpad.net/mgo"
	"launchpad.net/mgo/bson"
	"strconv"
	"strings"
	"time"
)

type Msg struct {
	Iv      string `json:"iv"`
	Message string `json:"message"`
}

type MsgWrap struct {
	Content   Msg    `json:"content"`
	Timestamp string `json:"timestamp"`
	Id        int    `bson:"_id"`
}

type Counter struct {
	Id string `bson:"_id"`
	N  int
}

// utility functions
func updateCounter(id string, s *mgo.Session) int {
	var counter Counter
	col := s.DB("muteswan").C("counters")
	change := mgo.Change{Update: bson.M{"$inc": bson.M{"n": 1}}, New: true, Upsert: true}
	err := col.Find(bson.M{"_id": "C" + id}).Modify(change, &counter)
	if err != nil {
		panic("Failed to update counter")
	}
	fmt.Println(counter.N)
	return counter.N
}

func getCounter(id string, s *mgo.Session) int {
	var counter Counter
	col := s.DB("muteswan").C("counters")
	err := col.Find(bson.M{"_id": "C" + id}).One(&counter)
	if err != nil {
		panic("Failed to get counter")
	}
	fmt.Println(counter.N)
	return counter.N
}

func PostMsg(c *goweb.Context, s *mgo.Session) {
	var m Msg
	var mw MsgWrap

	col := s.DB("muteswan").C("C" + c.PathParams["hash"])
	body, _ := ioutil.ReadAll(c.Request.Body)
	json.Unmarshal(body, &m)
	mw.Content = m
	mw.Id = updateCounter(c.PathParams["hash"], s)
	mw.Timestamp = time.Now().Format(time.RFC1123)
	mw.Timestamp = strings.Replace(mw.Timestamp,"UTC","GMT",-1)
	col.Insert(mw)
}

func GetMsg(c *goweb.Context, s *mgo.Session) {

	if strings.Contains(c.PathParams["id"], "-") {

		ids := strings.Split(c.PathParams["id"], "-")
		top, _ := strconv.Atoi(ids[0])
		bottom, _ := strconv.Atoi(ids[1])
		if bottom > top {
			fmt.Fprintf(c.ResponseWriter, "wtf %d to %d make no sense", top, bottom)
			return
		}

		var msgs []MsgWrap
		col := s.DB("muteswan").C("C" + c.PathParams["hash"])
		//msgQuery := col.Find(bson.M{"_id": bson.M{"$lte": top, "$gte": bottom}})
		msgQuery := col.Find(bson.M{"_id": bson.M{"$gte": bottom, "$lte": top}}).Sort("-_id")
		msgQuery.All(&msgs)

		msgBytes, _ := json.Marshal(msgs)
		buf := bytes.NewBuffer(msgBytes)
		fmt.Fprintf(c.ResponseWriter, "%s", buf.String())

	} else {
		var mw MsgWrap
		col := s.DB("muteswan").C("C" + c.PathParams["hash"])
		id, _ := strconv.Atoi(c.PathParams["id"])
		err := col.Find(bson.M{"_id": id}).One(&mw)
		if err != nil {
			fmt.Printf("Error fetching %s: %s", c.PathParams["hash"], err)
		}

		c.ResponseWriter.Header().Set("Last-Modified", mw.Timestamp)
		msgBytes, _ := json.Marshal(mw.Content)
		buf := bytes.NewBuffer(msgBytes)
		fmt.Fprintf(c.ResponseWriter, "%s", buf.String())
	}

}

func GetLastMsg(c *goweb.Context, s *mgo.Session) {

	mostRecent := getCounter(c.PathParams["hash"], s)

	fmt.Fprintf(c.ResponseWriter, `{"lastMessage":"%d"}`, mostRecent)
}

func main() {

	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	goweb.MapFunc("/{hash}/{id}", func(c *goweb.Context) {
		fmt.Printf("GET %s\n", c.Request.URL.String())
		GetMsg(c, session)
	})

	goweb.MapFunc("/{hash}", func(c *goweb.Context) {
		fmt.Printf("GET %s\n", c.Request.URL.String())
		GetLastMsg(c, session)
	}, goweb.GetMethod)

	goweb.MapFunc("/{hash}", func(c *goweb.Context) {
		fmt.Printf("POST %s\n", c.Request.URL.String())
		PostMsg(c, session)
	}, goweb.PostMethod)

	goweb.ListenAndServe(":8081")

}
<commit_msg>Clone mongodb connections.<commit_after>package main

import (
	"bytes"
	"code.google.com/p/goweb/goweb"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"launchpad.net/mgo"
	"launchpad.net/mgo/bson"
	"strconv"
	"strings"
	"time"
	"runtime"
)

type Msg struct {
	Iv      string `json:"iv"`
	Message string `json:"message"`
}

type MsgWrap struct {
	Content   Msg    `json:"content"`
	Timestamp string `json:"timestamp"`
	Id        int    `bson:"_id"`
}

type Counter struct {
	Id string `bson:"_id"`
	N  int
}

// utility functions
func updateCounter(id string, s *mgo.Session) int {
	var counter Counter
	col := s.DB("muteswan").C("counters")
	change := mgo.Change{Update: bson.M{"$inc": bson.M{"n": 1}}, New: true, Upsert: true}
	err := col.Find(bson.M{"_id": "C" + id}).Modify(change, &counter)
	if err != nil {
		panic("Failed to update counter")
	}
	fmt.Println(counter.N)
	return counter.N
}

func getCounter(id string, s *mgo.Session) int {
	var counter Counter
	col := s.DB("muteswan").C("counters")
	err := col.Find(bson.M{"_id": "C" + id}).One(&counter)
	if err != nil {
		return(0)
	}
	fmt.Println(counter.N)
	return counter.N
}

func PostMsg(c *goweb.Context, s *mgo.Session) {
	var m Msg
	var mw MsgWrap

	col := s.DB("muteswan").C("C" + c.PathParams["hash"])
	body, _ := ioutil.ReadAll(c.Request.Body)
	json.Unmarshal(body, &m)
	mw.Content = m
	mw.Id = updateCounter(c.PathParams["hash"], s)
	mw.Timestamp = time.Now().Format(time.RFC1123)
	mw.Timestamp = strings.Replace(mw.Timestamp,"UTC","GMT",-1)
	col.Insert(mw)
}

func GetMsg(c *goweb.Context, s *mgo.Session) {

	if strings.Contains(c.PathParams["id"], "-") {

		ids := strings.Split(c.PathParams["id"], "-")
		top, _ := strconv.Atoi(ids[0])
		bottom, _ := strconv.Atoi(ids[1])
		if bottom > top {
			fmt.Fprintf(c.ResponseWriter, "wtf %d to %d make no sense", top, bottom)
			return
		}

		var msgs []MsgWrap
		col := s.DB("muteswan").C("C" + c.PathParams["hash"])
		//msgQuery := col.Find(bson.M{"_id": bson.M{"$lte": top, "$gte": bottom}})
		msgQuery := col.Find(bson.M{"_id": bson.M{"$gte": bottom, "$lte": top}}).Sort("-_id")
		msgQuery.All(&msgs)

		msgBytes, _ := json.Marshal(msgs)
		buf := bytes.NewBuffer(msgBytes)
		fmt.Fprintf(c.ResponseWriter, "%s", buf.String())

	} else {
		var mw MsgWrap
		col := s.DB("muteswan").C("C" + c.PathParams["hash"])
		id, _ := strconv.Atoi(c.PathParams["id"])
		err := col.Find(bson.M{"_id": id}).One(&mw)
		if err != nil {
			fmt.Printf("Error fetching %s: %s", c.PathParams["hash"], err)
		}

		c.ResponseWriter.Header().Set("Last-Modified", mw.Timestamp)
		msgBytes, _ := json.Marshal(mw.Content)
		buf := bytes.NewBuffer(msgBytes)
		fmt.Fprintf(c.ResponseWriter, "%s", buf.String())
	}

}

func GetLastMsg(c *goweb.Context, s *mgo.Session) {

	mostRecent := getCounter(c.PathParams["hash"], s)

	fmt.Fprintf(c.ResponseWriter, `{"lastMessage":"%d"}`, mostRecent)
}

func main() {

	fmt.Printf("Max procs: %d\n", runtime.GOMAXPROCS(8))
	fmt.Printf("Max procs: %d\n", runtime.GOMAXPROCS(8))

	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	goweb.MapFunc("/{hash}/{id}", func(c *goweb.Context) {
		//fmt.Printf("GET %s\n", c.Request.URL.String())
		s := session.Copy()
		GetMsg(c, s)
		s.Close()
	})

	goweb.MapFunc("/{hash}", func(c *goweb.Context) {
		//fmt.Printf("GET %s\n", c.Request.URL.String())
		s := session.Copy()
		GetLastMsg(c, s)
		s.Close()
	}, goweb.GetMethod)

	goweb.MapFunc("/{hash}", func(c *goweb.Context) {
		//fmt.Printf("POST %s\n", c.Request.URL.String())
		s := session.Copy()
		PostMsg(c, s)
		s.Close()
	}, goweb.PostMethod)

	goweb.ListenAndServe(":8081")

}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/rand"
	"crypto/subtle"
	"encoding/binary"
	"io"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/crypto/ed25519"
)

// ClientConnection - A client connection
type ClientConnection struct {
	conf          Conf
	conn          net.Conn
	reader        *bufio.Reader
	writer        *bufio.Writer
	clientVersion byte
}

// StoredContent - Paste buffer
type StoredContent struct {
	sync.RWMutex

	encryptSkID         []byte
	ts                  []byte
	signature           []byte
	ciphertextWithNonce []byte
}

var storedContent StoredContent
var trustedClients TrustedClients
var clientsCount = uint64(0)

func (cnx *ClientConnection) getOperation(h1 []byte, isMove bool) {
	conf, reader, writer := cnx.conf, cnx.reader, cnx.writer
	rbuf := make([]byte, 32)
	if _, err := io.ReadFull(reader, rbuf); err != nil {
		log.Print(err)
		return
	}
	h2 := rbuf
	opcode := byte('G')
	if isMove {
		opcode = byte('M')
	}
	wh2 := auth2get(conf, cnx.clientVersion, h1, opcode)
	if subtle.ConstantTimeCompare(wh2, h2) != 1 {
		return
	}

	var encryptSkID, ts, signature, ciphertextWithNonce []byte
	if isMove {
		storedContent.Lock()
		encryptSkID, ts, signature, ciphertextWithNonce =
			storedContent.encryptSkID, storedContent.ts,
			storedContent.signature, storedContent.ciphertextWithNonce
		storedContent.encryptSkID, storedContent.ts, storedContent.signature,
			storedContent.ciphertextWithNonce = nil, nil, nil, nil
		storedContent.Unlock()
	} else {
		storedContent.RLock()
		encryptSkID, ts, signature, ciphertextWithNonce =
			storedContent.encryptSkID, storedContent.ts, storedContent.signature,
			storedContent.ciphertextWithNonce
		storedContent.RUnlock()
	}

	cnx.conn.SetDeadline(time.Now().Add(conf.DataTimeout))
	h3 := auth3get(conf, cnx.clientVersion, h2, encryptSkID, ts, signature)
	writer.Write(h3)
	ciphertextWithNonceLen := uint64(len(ciphertextWithNonce))
	binary.Write(writer, binary.LittleEndian, ciphertextWithNonceLen)
	writer.Write(encryptSkID)
	if cnx.clientVersion >= 5 {
		writer.Write(ts)
	}
	writer.Write(signature)
	writer.Write(ciphertextWithNonce)
	if err := writer.Flush(); err != nil {
		log.Print(err)
		return
	}
}

func (cnx *ClientConnection) storeOperation(h1 []byte) {
	conf, reader, writer := cnx.conf, cnx.reader, cnx.writer
	var rbuf []byte
	if cnx.clientVersion < 5 {
		rbuf = make([]byte, 112)
	} else {
		rbuf = make([]byte, 120)
	}
	if _, err := io.ReadFull(reader, rbuf); err != nil {
		log.Print(err)
		return
	}
	h2 := rbuf[0:32]
	ciphertextWithNonceLen := binary.LittleEndian.Uint64(rbuf[32:40])
	if conf.MaxLen > 0 && ciphertextWithNonceLen > conf.MaxLen {
		log.Printf("%v bytes requested to be stored, but limit set to %v bytes (%v Mb)\n",
			ciphertextWithNonceLen, conf.MaxLen, conf.MaxLen/(1024*1024))
		return
	}
	encryptSkID := rbuf[40:48]
	var ts, signature []byte
	if cnx.clientVersion < 5 {
		ts = make([]byte, 8)
		binary.LittleEndian.PutUint64(ts, uint64(time.Now().Unix()))
		signature = rbuf[48:112]
	} else {
		ts = rbuf[48:56]
		signature = rbuf[56:120]
	}
	opcode := byte('S')

	wh2 := auth2store(conf, cnx.clientVersion, h1, opcode, encryptSkID, ts, signature)
	if subtle.ConstantTimeCompare(wh2, h2) != 1 {
		return
	}
	ciphertextWithNonce := make([]byte, ciphertextWithNonceLen)

	cnx.conn.SetDeadline(time.Now().Add(conf.DataTimeout))
	if _, err := io.ReadFull(reader, ciphertextWithNonce); err != nil {
		log.Print(err)
		return
	}
	if ed25519.Verify(conf.SignPk, ciphertextWithNonce, signature) != true {
		return
	}
	h3 := auth3store(conf, cnx.clientVersion, h2)

	storedContent.Lock()
	storedContent.encryptSkID = encryptSkID
	storedContent.ts = ts
	storedContent.signature = signature
	storedContent.ciphertextWithNonce = ciphertextWithNonce
	storedContent.Unlock()

	writer.Write(h3)
	if err := writer.Flush(); err != nil {
		log.Print(err)
		return
	}
}

func handleClientConnection(conf Conf, conn net.Conn) {
	defer conn.Close()
	reader, writer := bufio.NewReader(conn), bufio.NewWriter(conn)
	cnx := ClientConnection{
		conf:   conf,
		conn:   conn,
		reader: reader,
		writer: writer,
	}
	rbuf := make([]byte, 65)
	if _, err := io.ReadFull(reader, rbuf); err != nil {
		return
	}
	cnx.clientVersion = rbuf[0]
	if cnx.clientVersion < 4 || cnx.clientVersion > 5 {
		log.Print("Unsupported client version - Please run the same version on the server and on the client")
		return
	}
	r := rbuf[1:33]
	h0 := rbuf[33:65]
	wh0 := auth0(conf, cnx.clientVersion, r)
	if subtle.ConstantTimeCompare(wh0, h0) != 1 {
		return
	}
	r2 := make([]byte, 32)
	if _, err := rand.Read(r); err != nil {
		log.Fatal(err)
	}
	h1 := auth1(conf, cnx.clientVersion, h0, r2)
	writer.Write([]byte{cnx.clientVersion})
	writer.Write(r2)
	writer.Write(h1)
	if err := writer.Flush(); err != nil {
		log.Print(err)
		return
	}
	remoteIP := cnx.conn.RemoteAddr().(*net.TCPAddr).IP
	addToTrustedIPs(conf, remoteIP)
	opcode, err := reader.ReadByte()
	if err != nil {
		return
	}
	switch opcode {
	case byte('G'):
		cnx.getOperation(h1, false)
	case byte('M'):
		cnx.getOperation(h1, true)
	case byte('S'):
		cnx.storeOperation(h1)
	}
}

type TrustedClients struct {
	sync.RWMutex

	ips []net.IP
}

func addToTrustedIPs(conf Conf, ip net.IP) {
	trustedClients.Lock()
	if uint64(len(trustedClients.ips)) >= conf.TrustedIPCount {
		trustedClients.ips = append(trustedClients.ips[1:], ip)
	} else {
		trustedClients.ips = append(trustedClients.ips, ip)
	}
	trustedClients.Unlock()
}

func isIPTrusted(conf Conf, ip net.IP) bool {
	trustedClients.RLock()
	defer trustedClients.RUnlock()
	if len(trustedClients.ips) == 0 {
		return true
	}
	for _, foundIP := range trustedClients.ips {
		if foundIP.Equal(ip) {
			return true
		}
	}
	return false
}

func acceptClient(conf Conf, conn net.Conn) {
	handleClientConnection(conf, conn)
	atomic.AddUint64(&clientsCount, ^uint64(0))
}

func maybeAcceptClient(conf Conf, conn net.Conn) {
	conn.SetDeadline(time.Now().Add(conf.Timeout))
	remoteIP := conn.RemoteAddr().(*net.TCPAddr).IP
	for {
		count := atomic.LoadUint64(&clientsCount)
		if count >= conf.MaxClients-conf.TrustedIPCount && isIPTrusted(conf, remoteIP) == false {
			conn.Close()
			return
		}
		if count >= conf.MaxClients {
			conn.Close()
			return
		} else if atomic.CompareAndSwapUint64(&clientsCount, count, count+1) {
			break
		}
	}
	go acceptClient(conf, conn)
}

// RunServer - run a server
func RunServer(conf Conf) {
	listen, err := net.Listen("tcp", conf.Listen)
	if err != nil {
		log.Fatal(err)
	}
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatal(err)
		}
		maybeAcceptClient(conf, conn)
	}
}
<commit_msg>Document TrustedClients<commit_after>package main

import (
	"bufio"
	"crypto/rand"
	"crypto/subtle"
	"encoding/binary"
	"io"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/crypto/ed25519"
)

// ClientConnection - A client connection
type ClientConnection struct {
	conf          Conf
	conn          net.Conn
	reader        *bufio.Reader
	writer        *bufio.Writer
	clientVersion byte
}

// StoredContent - Paste buffer
type StoredContent struct {
	sync.RWMutex

	encryptSkID         []byte
	ts                  []byte
	signature           []byte
	ciphertextWithNonce []byte
}

var storedContent StoredContent
var trustedClients TrustedClients
var clientsCount = uint64(0)

func (cnx *ClientConnection) getOperation(h1 []byte, isMove bool) {
	conf, reader, writer := cnx.conf, cnx.reader, cnx.writer
	rbuf := make([]byte, 32)
	if _, err := io.ReadFull(reader, rbuf); err != nil {
		log.Print(err)
		return
	}
	h2 := rbuf
	opcode := byte('G')
	if isMove {
		opcode = byte('M')
	}
	wh2 := auth2get(conf, cnx.clientVersion, h1, opcode)
	if subtle.ConstantTimeCompare(wh2, h2) != 1 {
		return
	}

	var encryptSkID, ts, signature, ciphertextWithNonce []byte
	if isMove {
		storedContent.Lock()
		encryptSkID, ts, signature, ciphertextWithNonce =
			storedContent.encryptSkID, storedContent.ts,
			storedContent.signature, storedContent.ciphertextWithNonce
		storedContent.encryptSkID, storedContent.ts, storedContent.signature,
			storedContent.ciphertextWithNonce = nil, nil, nil, nil
		storedContent.Unlock()
	} else {
		storedContent.RLock()
		encryptSkID, ts, signature, ciphertextWithNonce =
			storedContent.encryptSkID, storedContent.ts, storedContent.signature,
			storedContent.ciphertextWithNonce
		storedContent.RUnlock()
	}

	cnx.conn.SetDeadline(time.Now().Add(conf.DataTimeout))
	h3 := auth3get(conf, cnx.clientVersion, h2, encryptSkID, ts, signature)
	writer.Write(h3)
	ciphertextWithNonceLen := uint64(len(ciphertextWithNonce))
	binary.Write(writer, binary.LittleEndian, ciphertextWithNonceLen)
	writer.Write(encryptSkID)
	if cnx.clientVersion >= 5 {
		writer.Write(ts)
	}
	writer.Write(signature)
	writer.Write(ciphertextWithNonce)
	if err := writer.Flush(); err != nil {
		log.Print(err)
		return
	}
}

func (cnx *ClientConnection) storeOperation(h1 []byte) {
	conf, reader, writer := cnx.conf, cnx.reader, cnx.writer
	var rbuf []byte
	if cnx.clientVersion < 5 {
		rbuf = make([]byte, 112)
	} else {
		rbuf = make([]byte, 120)
	}
	if _, err := io.ReadFull(reader, rbuf); err != nil {
		log.Print(err)
		return
	}
	h2 := rbuf[0:32]
	ciphertextWithNonceLen := binary.LittleEndian.Uint64(rbuf[32:40])
	if conf.MaxLen > 0 && ciphertextWithNonceLen > conf.MaxLen {
		log.Printf("%v bytes requested to be stored, but limit set to %v bytes (%v Mb)\n",
			ciphertextWithNonceLen, conf.MaxLen, conf.MaxLen/(1024*1024))
		return
	}
	encryptSkID := rbuf[40:48]
	var ts, signature []byte
	if cnx.clientVersion < 5 {
		ts = make([]byte, 8)
		binary.LittleEndian.PutUint64(ts, uint64(time.Now().Unix()))
		signature = rbuf[48:112]
	} else {
		ts = rbuf[48:56]
		signature = rbuf[56:120]
	}
	opcode := byte('S')

	wh2 := auth2store(conf, cnx.clientVersion, h1, opcode, encryptSkID, ts, signature)
	if subtle.ConstantTimeCompare(wh2, h2) != 1 {
		return
	}
	ciphertextWithNonce := make([]byte, ciphertextWithNonceLen)

	cnx.conn.SetDeadline(time.Now().Add(conf.DataTimeout))
	if _, err := io.ReadFull(reader, ciphertextWithNonce); err != nil {
		log.Print(err)
		return
	}
	if ed25519.Verify(conf.SignPk, ciphertextWithNonce, signature) != true {
		return
	}
	h3 := auth3store(conf, cnx.clientVersion, h2)

	storedContent.Lock()
	storedContent.encryptSkID = encryptSkID
	storedContent.ts = ts
	storedContent.signature = signature
	storedContent.ciphertextWithNonce = ciphertextWithNonce
	storedContent.Unlock()

	writer.Write(h3)
	if err := writer.Flush(); err != nil {
		log.Print(err)
		return
	}
}

func handleClientConnection(conf Conf, conn net.Conn) {
	defer conn.Close()
	reader, writer := bufio.NewReader(conn), bufio.NewWriter(conn)
	cnx := ClientConnection{
		conf:   conf,
		conn:   conn,
		reader: reader,
		writer: writer,
	}
	rbuf := make([]byte, 65)
	if _, err := io.ReadFull(reader, rbuf); err != nil {
		return
	}
	cnx.clientVersion = rbuf[0]
	if cnx.clientVersion < 4 || cnx.clientVersion > 5 {
		log.Print("Unsupported client version - Please run the same version on the server and on the client")
		return
	}
	r := rbuf[1:33]
	h0 := rbuf[33:65]
	wh0 := auth0(conf, cnx.clientVersion, r)
	if subtle.ConstantTimeCompare(wh0, h0) != 1 {
		return
	}
	r2 := make([]byte, 32)
	if _, err := rand.Read(r); err != nil {
		log.Fatal(err)
	}
	h1 := auth1(conf, cnx.clientVersion, h0, r2)
	writer.Write([]byte{cnx.clientVersion})
	writer.Write(r2)
	writer.Write(h1)
	if err := writer.Flush(); err != nil {
		log.Print(err)
		return
	}
	remoteIP := cnx.conn.RemoteAddr().(*net.TCPAddr).IP
	addToTrustedIPs(conf, remoteIP)
	opcode, err := reader.ReadByte()
	if err != nil {
		return
	}
	switch opcode {
	case byte('G'):
		cnx.getOperation(h1, false)
	case byte('M'):
		cnx.getOperation(h1, true)
	case byte('S'):
		cnx.storeOperation(h1)
	}
}

// TrustedClients - Clients IPs having recently performed a succesful handshake
type TrustedClients struct {
	sync.RWMutex

	ips []net.IP
}

func addToTrustedIPs(conf Conf, ip net.IP) {
	trustedClients.Lock()
	if uint64(len(trustedClients.ips)) >= conf.TrustedIPCount {
		trustedClients.ips = append(trustedClients.ips[1:], ip)
	} else {
		trustedClients.ips = append(trustedClients.ips, ip)
	}
	trustedClients.Unlock()
}

func isIPTrusted(conf Conf, ip net.IP) bool {
	trustedClients.RLock()
	defer trustedClients.RUnlock()
	if len(trustedClients.ips) == 0 {
		return true
	}
	for _, foundIP := range trustedClients.ips {
		if foundIP.Equal(ip) {
			return true
		}
	}
	return false
}

func acceptClient(conf Conf, conn net.Conn) {
	handleClientConnection(conf, conn)
	atomic.AddUint64(&clientsCount, ^uint64(0))
}

func maybeAcceptClient(conf Conf, conn net.Conn) {
	conn.SetDeadline(time.Now().Add(conf.Timeout))
	remoteIP := conn.RemoteAddr().(*net.TCPAddr).IP
	for {
		count := atomic.LoadUint64(&clientsCount)
		if count >= conf.MaxClients-conf.TrustedIPCount && isIPTrusted(conf, remoteIP) == false {
			conn.Close()
			return
		}
		if count >= conf.MaxClients {
			conn.Close()
			return
		} else if atomic.CompareAndSwapUint64(&clientsCount, count, count+1) {
			break
		}
	}
	go acceptClient(conf, conn)
}

// RunServer - run a server
func RunServer(conf Conf) {
	listen, err := net.Listen("tcp", conf.Listen)
	if err != nil {
		log.Fatal(err)
	}
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatal(err)
		}
		maybeAcceptClient(conf, conn)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/flynn/go-discover/discover"
	"github.com/flynn/go-dockerclient"
	lornec "github.com/flynn/lorne/client"
	"github.com/flynn/lorne/types"
	sampic "github.com/flynn/sampi/client"
	"github.com/flynn/sampi/types"
	strowgerc "github.com/flynn/strowger/client"
	"github.com/flynn/strowger/types"
	"github.com/titanous/go-tigertonic"
)

func main() {
	var err error
	scheduler, err = sampic.New()
	if err != nil {
		log.Fatal(err)
	}
	disc, err = discover.NewClient()
	if err != nil {
		log.Fatal(err)
	}
	router, err = strowgerc.New()
	if err != nil {
		log.Fatal(err)
	}

	mux := tigertonic.NewTrieServeMux()
	mux.Handle("PUT", "/apps/{app_id}/domains/{domain}", tigertonic.Marshaled(addDomain))
	mux.Handle("POST", "/apps/{app_id}/formation/{formation_id}", tigertonic.Marshaled(changeFormation))
	mux.Handle("GET", "/apps/{app_id}/jobs", tigertonic.Marshaled(getJobs))
	mux.HandleFunc("GET", "/apps/{app_id}/jobs/{job_id}/logs", getJobLog)
	mux.HandleFunc("POST", "/apps/{app_id}/jobs", runJob)
	http.ListenAndServe("127.0.0.1:1200", tigertonic.Logged(mux, nil))
}

var scheduler *sampic.Client
var disc *discover.Client
var router *strowgerc.Client

type Job struct {
	ID   string `json:"id"`
	Type string `json:"type"`
}

func addDomain(u *url.URL, h http.Header, data *struct{}) (int, http.Header, struct{}, error) {
	q := u.Query()
	if err := router.AddFrontend(&strowger.Config{Service: q.Get("app_id"), HTTPDomain: q.Get("domain")}); err != nil {
		return 500, nil, struct{}{}, err
	}
	return 200, nil, struct{}{}, nil
}

// GET /apps/{app_id}/jobs
func getJobs(u *url.URL, h http.Header) (int, http.Header, []Job, error) {
	state, err := scheduler.State()
	if err != nil {
		return 500, nil, nil, err
	}

	q := u.Query()
	prefix := q.Get("app_id") + "-"
	jobs := make([]Job, 0)
	for _, host := range state {
		for _, job := range host.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				typ := strings.Split(job.ID[len(prefix):], ".")[0]
				jobs = append(jobs, Job{ID: job.ID, Type: typ})
			}
		}
	}

	return 200, nil, jobs, nil
}

type Formation struct {
	Quantity int    `json:"quantity"`
	Type     string `json:"type"`
}

func shelfURL() string {
	set, _ := disc.Services("shelf")
	addrs := set.OnlineAddrs()
	if len(addrs) < 1 {
		panic("Shelf is not discoverable")
	}
	return addrs[0]
}

// POST /apps/{app_id}/formation/{formation_id}
func changeFormation(u *url.URL, h http.Header, req *Formation) (int, http.Header, *Formation, error) {
	state, err := scheduler.State()
	if err != nil {
		log.Println("scheduler state error", err)
		return 500, nil, nil, err
	}

	q := u.Query()
	req.Type = q.Get("formation_id")
	prefix := q.Get("app_id") + "-" + req.Type + "."
	var jobs []*sampi.Job
	for _, host := range state {
		for _, job := range host.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				if job.Attributes == nil {
					job.Attributes = make(map[string]string)
				}
				job.Attributes["host_id"] = host.ID
				jobs = append(jobs, job)
			}
		}
	}

	if req.Quantity < 0 {
		req.Quantity = 0
	}
	diff := req.Quantity - len(jobs)
	log.Printf("have %d %s, diff %d", len(jobs), req.Type, diff)
	if diff > 0 {
		config := &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          []string{"start", req.Type},
			AttachStdout: true,
			AttachStderr: true,
			Env:          []string{"SLUG_URL=http://" + shelfURL() + "/" + q.Get("app_id") + ".tgz"},
		}
		if req.Type == "web" {
			config.Env = append(config.Env, "SD_NAME="+q.Get("app_id"))
		}
		schedReq := &sampi.ScheduleReq{
			HostJobs: make(map[string][]*sampi.Job),
		}
	outer:
		for {
			for host := range state {
				schedReq.HostJobs[host] = append(schedReq.HostJobs[host], &sampi.Job{ID: prefix + randomID(), TCPPorts: 1, Config: config})
				diff--
				if diff == 0 {
					break outer
				}
			}
		}

		res, err := scheduler.Schedule(schedReq)
		if err != nil || !res.Success {
			log.Println("schedule error", err)
			return 500, nil, nil, err
		}
	} else if diff < 0 {
		for _, job := range jobs[:-diff] {
			host, err := lornec.New(job.Attributes["host_id"])
			if err != nil {
				log.Println("error connecting to", job.Attributes["host_id"], err)
				continue
			}
			if err := host.StopJob(job.ID); err != nil {
				log.Println("error stopping", job.ID, "on", job.Attributes["host_id"], err)
			}
		}
	}

	return 200, nil, req, nil
}

// GET /apps/{app_id}/jobs/{job_id}/logs
func getJobLog(w http.ResponseWriter, req *http.Request) {
	state, err := scheduler.State()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	q := req.URL.Query()
	jobID := q.Get("job_id")
	if prefix := q.Get("app_id") + "-"; !strings.HasPrefix(jobID, prefix) {
		jobID = prefix + jobID
	}
	var job *sampi.Job
	var host sampi.Host
outer:
	for _, host = range state {
		for _, job = range host.Jobs {
			if job.ID == jobID {
				break outer
			}
		}
		job = nil
	}
	if job == nil {
		w.WriteHeader(404)
		return
	}

	attachReq := &lorne.AttachReq{
		JobID: job.ID,
		Flags: lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagLogs,
	}

	client, err := lornec.New(host.ID)
	if err != nil {
		w.WriteHeader(500)
		log.Println("lorne connect failed", err)
		return
	}
	attachConn, _, err := client.Attach(attachReq, false)
	if err != nil {
		w.WriteHeader(500)
		log.Println("attach failed", err)
		return
	}
	defer attachConn.Close()
	io.Copy(w, attachConn)
}

type NewJob struct {
	Cmd     []string          `json:"cmd"`
	Env     map[string]string `json:"env"`
	Attach  bool              `json:"attach"`
	TTY     bool              `json:"tty"`
	Columns int               `json:"tty_columns"`
	Lines   int               `json:"tty_lines"`
}

// POST /apps/{app_id}/jobs
func runJob(w http.ResponseWriter, req *http.Request) {
	var jobReq NewJob
	if err := json.NewDecoder(req.Body).Decode(&jobReq); err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	state, err := scheduler.State()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}
	// pick a random host
	var hostID string
	for hostID = range state {
		break
	}
	if hostID == "" {
		w.WriteHeader(500)
		log.Println("no hosts found")
		return
	}

	env := make([]string, 0, len(jobReq.Env))
	for k, v := range jobReq.Env {
		env = append(env, k+"="+v)
	}

	q := req.URL.Query()
	job := &sampi.Job{
		ID: q.Get("app_id") + "-run." + randomID(),
		Config: &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          jobReq.Cmd,
			AttachStdin:  true,
			AttachStdout: true,
			AttachStderr: true,
			StdinOnce:    true,
			Env:          append(env, "SLUG_URL=http://"+shelfURL()+"/"+q.Get("app_id")+".tgz"),
		},
	}
	if jobReq.TTY {
		job.Config.Tty = true
	}
	if jobReq.Attach {
		job.Config.AttachStdin = true
		job.Config.StdinOnce = true
		job.Config.OpenStdin = true
	}

	var attachConn lornec.ReadWriteCloser
	var attachWait func() error
	if jobReq.Attach {
		attachReq := &lorne.AttachReq{
			JobID:  job.ID,
			Flags:  lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagStdin | lorne.AttachFlagStream,
			Height: jobReq.Lines,
			Width:  jobReq.Columns,
		}
		client, err := lornec.New(hostID)
		if err != nil {
			w.WriteHeader(500)
			log.Println("lorne connect failed", err)
			return
		}
		attachConn, attachWait, err = client.Attach(attachReq, true)
		if err != nil {
			w.WriteHeader(500)
			log.Println("attach failed", err)
			return
		}
		defer attachConn.Close()
	}

	res, err := scheduler.Schedule(&sampi.ScheduleReq{HostJobs: map[string][]*sampi.Job{hostID: {job}}})
	if err != nil || !res.Success {
		w.WriteHeader(500)
		log.Println("schedule failed", err)
		return
	}

	if jobReq.Attach {
		if err := attachWait(); err != nil {
			w.WriteHeader(500)
			log.Println("attach wait failed", err)
			return
		}
		w.Header().Set("Content-Type", "application/vnd.flynn.hijack")
		w.Header().Set("Content-Length", "0")
		w.WriteHeader(200)
		conn, _, err := w.(http.Hijacker).Hijack()
		if err != nil {
			return
		}
		defer conn.Close()

		done := make(chan struct{})
		copy := func(to lornec.ReadWriteCloser, from io.Reader) {
			io.Copy(to, from)
			to.CloseWrite()
			done <- struct{}{}
		}
		go copy(conn.(lornec.ReadWriteCloser), attachConn)
		go copy(attachConn, conn)
		<-done
		<-done

		return
	}
	w.WriteHeader(200)
}

func randomID() string {
	b := make([]byte, 16)
	enc := make([]byte, 24)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		panic(err) // This shouldn't ever happen, right?
	}
	base64.URLEncoding.Encode(enc, b)
	return string(bytes.TrimRight(enc, "="))
}
<commit_msg>controller: Use random IDs from sampi client<commit_after>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/flynn/go-discover/discover"
	"github.com/flynn/go-dockerclient"
	lornec "github.com/flynn/lorne/client"
	"github.com/flynn/lorne/types"
	sampic "github.com/flynn/sampi/client"
	"github.com/flynn/sampi/types"
	strowgerc "github.com/flynn/strowger/client"
	"github.com/flynn/strowger/types"
	"github.com/titanous/go-tigertonic"
)

func main() {
	var err error
	scheduler, err = sampic.New()
	if err != nil {
		log.Fatal(err)
	}
	disc, err = discover.NewClient()
	if err != nil {
		log.Fatal(err)
	}
	router, err = strowgerc.New()
	if err != nil {
		log.Fatal(err)
	}

	mux := tigertonic.NewTrieServeMux()
	mux.Handle("PUT", "/apps/{app_id}/domains/{domain}", tigertonic.Marshaled(addDomain))
	mux.Handle("POST", "/apps/{app_id}/formation/{formation_id}", tigertonic.Marshaled(changeFormation))
	mux.Handle("GET", "/apps/{app_id}/jobs", tigertonic.Marshaled(getJobs))
	mux.HandleFunc("GET", "/apps/{app_id}/jobs/{job_id}/logs", getJobLog)
	mux.HandleFunc("POST", "/apps/{app_id}/jobs", runJob)
	http.ListenAndServe("127.0.0.1:1200", tigertonic.Logged(mux, nil))
}

var scheduler *sampic.Client
var disc *discover.Client
var router *strowgerc.Client

type Job struct {
	ID   string `json:"id"`
	Type string `json:"type"`
}

func addDomain(u *url.URL, h http.Header, data *struct{}) (int, http.Header, struct{}, error) {
	q := u.Query()
	if err := router.AddFrontend(&strowger.Config{Service: q.Get("app_id"), HTTPDomain: q.Get("domain")}); err != nil {
		return 500, nil, struct{}{}, err
	}
	return 200, nil, struct{}{}, nil
}

// GET /apps/{app_id}/jobs
func getJobs(u *url.URL, h http.Header) (int, http.Header, []Job, error) {
	state, err := scheduler.State()
	if err != nil {
		return 500, nil, nil, err
	}

	q := u.Query()
	prefix := q.Get("app_id") + "-"
	jobs := make([]Job, 0)
	for _, host := range state {
		for _, job := range host.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				typ := strings.Split(job.ID[len(prefix):], ".")[0]
				jobs = append(jobs, Job{ID: job.ID, Type: typ})
			}
		}
	}

	return 200, nil, jobs, nil
}

type Formation struct {
	Quantity int    `json:"quantity"`
	Type     string `json:"type"`
}

func shelfURL() string {
	set, _ := disc.Services("shelf")
	addrs := set.OnlineAddrs()
	if len(addrs) < 1 {
		panic("Shelf is not discoverable")
	}
	return addrs[0]
}

// POST /apps/{app_id}/formation/{formation_id}
func changeFormation(u *url.URL, h http.Header, req *Formation) (int, http.Header, *Formation, error) {
	state, err := scheduler.State()
	if err != nil {
		log.Println("scheduler state error", err)
		return 500, nil, nil, err
	}

	q := u.Query()
	req.Type = q.Get("formation_id")
	prefix := q.Get("app_id") + "-" + req.Type + "."
	var jobs []*sampi.Job
	for _, host := range state {
		for _, job := range host.Jobs {
			if strings.HasPrefix(job.ID, prefix) {
				if job.Attributes == nil {
					job.Attributes = make(map[string]string)
				}
				job.Attributes["host_id"] = host.ID
				jobs = append(jobs, job)
			}
		}
	}

	if req.Quantity < 0 {
		req.Quantity = 0
	}
	diff := req.Quantity - len(jobs)
	log.Printf("have %d %s, diff %d", len(jobs), req.Type, diff)
	if diff > 0 {
		config := &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          []string{"start", req.Type},
			AttachStdout: true,
			AttachStderr: true,
			Env:          []string{"SLUG_URL=http://" + shelfURL() + "/" + q.Get("app_id") + ".tgz"},
		}
		if req.Type == "web" {
			config.Env = append(config.Env, "SD_NAME="+q.Get("app_id"))
		}
		schedReq := &sampi.ScheduleReq{
			HostJobs: make(map[string][]*sampi.Job),
		}
	outer:
		for {
			for host := range state {
				schedReq.HostJobs[host] = append(schedReq.HostJobs[host], &sampi.Job{ID: sampic.RandomJobID(prefix), TCPPorts: 1, Config: config})
				diff--
				if diff == 0 {
					break outer
				}
			}
		}

		res, err := scheduler.Schedule(schedReq)
		if err != nil || !res.Success {
			log.Println("schedule error", err)
			return 500, nil, nil, err
		}
	} else if diff < 0 {
		for _, job := range jobs[:-diff] {
			host, err := lornec.New(job.Attributes["host_id"])
			if err != nil {
				log.Println("error connecting to", job.Attributes["host_id"], err)
				continue
			}
			if err := host.StopJob(job.ID); err != nil {
				log.Println("error stopping", job.ID, "on", job.Attributes["host_id"], err)
			}
		}
	}

	return 200, nil, req, nil
}

// GET /apps/{app_id}/jobs/{job_id}/logs
func getJobLog(w http.ResponseWriter, req *http.Request) {
	state, err := scheduler.State()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	q := req.URL.Query()
	jobID := q.Get("job_id")
	if prefix := q.Get("app_id") + "-"; !strings.HasPrefix(jobID, prefix) {
		jobID = prefix + jobID
	}
	var job *sampi.Job
	var host sampi.Host
outer:
	for _, host = range state {
		for _, job = range host.Jobs {
			if job.ID == jobID {
				break outer
			}
		}
		job = nil
	}
	if job == nil {
		w.WriteHeader(404)
		return
	}

	attachReq := &lorne.AttachReq{
		JobID: job.ID,
		Flags: lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagLogs,
	}

	client, err := lornec.New(host.ID)
	if err != nil {
		w.WriteHeader(500)
		log.Println("lorne connect failed", err)
		return
	}
	attachConn, _, err := client.Attach(attachReq, false)
	if err != nil {
		w.WriteHeader(500)
		log.Println("attach failed", err)
		return
	}
	defer attachConn.Close()
	io.Copy(w, attachConn)
}

type NewJob struct {
	Cmd     []string          `json:"cmd"`
	Env     map[string]string `json:"env"`
	Attach  bool              `json:"attach"`
	TTY     bool              `json:"tty"`
	Columns int               `json:"tty_columns"`
	Lines   int               `json:"tty_lines"`
}

// POST /apps/{app_id}/jobs
func runJob(w http.ResponseWriter, req *http.Request) {
	var jobReq NewJob
	if err := json.NewDecoder(req.Body).Decode(&jobReq); err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}

	state, err := scheduler.State()
	if err != nil {
		w.WriteHeader(500)
		log.Println(err)
		return
	}
	// pick a random host
	var hostID string
	for hostID = range state {
		break
	}
	if hostID == "" {
		w.WriteHeader(500)
		log.Println("no hosts found")
		return
	}

	env := make([]string, 0, len(jobReq.Env))
	for k, v := range jobReq.Env {
		env = append(env, k+"="+v)
	}

	q := req.URL.Query()
	job := &sampi.Job{
		ID: sampic.RandomJobID(q.Get("app_id") + "-run."),
		Config: &docker.Config{
			Image:        "flynn/slugrunner",
			Cmd:          jobReq.Cmd,
			AttachStdin:  true,
			AttachStdout: true,
			AttachStderr: true,
			StdinOnce:    true,
			Env:          append(env, "SLUG_URL=http://"+shelfURL()+"/"+q.Get("app_id")+".tgz"),
		},
	}
	if jobReq.TTY {
		job.Config.Tty = true
	}
	if jobReq.Attach {
		job.Config.AttachStdin = true
		job.Config.StdinOnce = true
		job.Config.OpenStdin = true
	}

	var attachConn lornec.ReadWriteCloser
	var attachWait func() error
	if jobReq.Attach {
		attachReq := &lorne.AttachReq{
			JobID:  job.ID,
			Flags:  lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagStdin | lorne.AttachFlagStream,
			Height: jobReq.Lines,
			Width:  jobReq.Columns,
		}
		client, err := lornec.New(hostID)
		if err != nil {
			w.WriteHeader(500)
			log.Println("lorne connect failed", err)
			return
		}
		attachConn, attachWait, err = client.Attach(attachReq, true)
		if err != nil {
			w.WriteHeader(500)
			log.Println("attach failed", err)
			return
		}
		defer attachConn.Close()
	}

	res, err := scheduler.Schedule(&sampi.ScheduleReq{HostJobs: map[string][]*sampi.Job{hostID: {job}}})
	if err != nil || !res.Success {
		w.WriteHeader(500)
		log.Println("schedule failed", err)
		return
	}

	if jobReq.Attach {
		if err := attachWait(); err != nil {
			w.WriteHeader(500)
			log.Println("attach wait failed", err)
			return
		}
		w.Header().Set("Content-Type", "application/vnd.flynn.hijack")
		w.Header().Set("Content-Length", "0")
		w.WriteHeader(200)
		conn, _, err := w.(http.Hijacker).Hijack()
		if err != nil {
			return
		}
		defer conn.Close()

		done := make(chan struct{})
		copy := func(to lornec.ReadWriteCloser, from io.Reader) {
			io.Copy(to, from)
			to.CloseWrite()
			done <- struct{}{}
		}
		go copy(conn.(lornec.ReadWriteCloser), attachConn)
		go copy(attachConn, conn)
		<-done
		<-done

		return
	}
	w.WriteHeader(200)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package channels

import (
	"encoding/json"
	"testing"

	"github.com/couchbaselabs/go.assert"
)

func TestTimedSetMarshal(t *testing.T) {
	var str struct {
		Channels TimedSet
	}
	bytes, err := json.Marshal(str)
	assertNoError(t, err, "Marshal")
	assert.Equals(t, string(bytes), `{"Channels":null}`)

	str.Channels = TimedSet{}
	bytes, err = json.Marshal(str)
	assertNoError(t, err, "Marshal")
	assert.Equals(t, string(bytes), `{"Channels":{}}`)

	str.Channels = AtSequence(SetOf("a", "b"), 17)
	bytes, err = json.Marshal(str)
	assertNoError(t, err, "Marshal")
	assert.Equals(t, string(bytes), `{"Channels":{"a":17,"b":17}}`)
}

func TestTimedSetUnmarshal(t *testing.T) {
	var str struct {
		Channels TimedSet
	}
	err := json.Unmarshal([]byte(`{"channels":null}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet(nil))

	err = json.Unmarshal([]byte(`{"channels":{}}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{})

	err = json.Unmarshal([]byte(`{"channels":{"a":17,"b":17}}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{"a": 17, "b": 17})

	// Now try unmarshaling the alternative array form:
	err = json.Unmarshal([]byte(`{"channels":[]}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{})

	err = json.Unmarshal([]byte(`{"channels":["a","b"]}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{"a": 0, "b": 0})
}

func TestEncodeSequenceID(t *testing.T) {
	set := TimedSet{"ABC": 17, "CBS": 23, "BBC": 1}
	encoded := set.String()
	assert.Equals(t, encoded, "ABC:17,BBC:1,CBS:23")
	decoded := TimedSetFromString(encoded)
	assert.DeepEquals(t, decoded, set)

	assert.Equals(t, TimedSet{"ABC": 17, "CBS": 0}.String(), "ABC:17")

	assert.DeepEquals(t, TimedSetFromString(""), TimedSet{})
	assert.DeepEquals(t, TimedSetFromString("ABC:17"), TimedSet{"ABC": 17})

	assert.DeepEquals(t, TimedSetFromString(":17"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:0"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:-1"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:17,"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString(",ABC:17"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:17,,NBC:12"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:17,ABC:12"), TimedSet(nil))
}
<commit_msg>add TestEqualsWithEqualSet and TestEqualsWithUnequalSet<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package channels

import (
	"encoding/json"
	"testing"

	"github.com/couchbase/sync_gateway/base"
	"github.com/couchbaselabs/go.assert"
)

func TestTimedSetMarshal(t *testing.T) {
	var str struct {
		Channels TimedSet
	}
	bytes, err := json.Marshal(str)
	assertNoError(t, err, "Marshal")
	assert.Equals(t, string(bytes), `{"Channels":null}`)

	str.Channels = TimedSet{}
	bytes, err = json.Marshal(str)
	assertNoError(t, err, "Marshal")
	assert.Equals(t, string(bytes), `{"Channels":{}}`)

	str.Channels = AtSequence(SetOf("a", "b"), 17)
	bytes, err = json.Marshal(str)
	assertNoError(t, err, "Marshal")
	assert.Equals(t, string(bytes), `{"Channels":{"a":17,"b":17}}`)
}

func TestTimedSetUnmarshal(t *testing.T) {
	var str struct {
		Channels TimedSet
	}
	err := json.Unmarshal([]byte(`{"channels":null}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet(nil))

	err = json.Unmarshal([]byte(`{"channels":{}}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{})

	err = json.Unmarshal([]byte(`{"channels":{"a":17,"b":17}}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{"a": 17, "b": 17})

	// Now try unmarshaling the alternative array form:
	err = json.Unmarshal([]byte(`{"channels":[]}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{})

	err = json.Unmarshal([]byte(`{"channels":["a","b"]}`), &str)
	assertNoError(t, err, "Unmarshal")
	assert.DeepEquals(t, str.Channels, TimedSet{"a": 0, "b": 0})
}

func TestEncodeSequenceID(t *testing.T) {
	set := TimedSet{"ABC": 17, "CBS": 23, "BBC": 1}
	encoded := set.String()
	assert.Equals(t, encoded, "ABC:17,BBC:1,CBS:23")
	decoded := TimedSetFromString(encoded)
	assert.DeepEquals(t, decoded, set)

	assert.Equals(t, TimedSet{"ABC": 17, "CBS": 0}.String(), "ABC:17")

	assert.DeepEquals(t, TimedSetFromString(""), TimedSet{})
	assert.DeepEquals(t, TimedSetFromString("ABC:17"), TimedSet{"ABC": 17})

	assert.DeepEquals(t, TimedSetFromString(":17"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:0"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:-1"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:17,"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString(",ABC:17"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:17,,NBC:12"), TimedSet(nil))
	assert.DeepEquals(t, TimedSetFromString("ABC:17,ABC:12"), TimedSet(nil))
}

func TestEqualsWithEqualSet(t *testing.T) {
	set1 := TimedSet{"ABC": 17, "CBS": 23, "BBC": 1}
	set2 := base.SetFromArray([]string{"ABC", "CBS", "BBC"})
	assert.True(t, set1.Equals(set2))

}

func TestEqualsWithUnequalSet(t *testing.T) {
	set1 := TimedSet{"ABC": 17, "CBS": 23, "BBC": 1}
	set2 := base.SetFromArray([]string{"ABC", "BBC"})
	assert.True(t, !set1.Equals(set2))
	set3 := base.SetFromArray([]string{"ABC", "BBC", "CBS", "FOO"})
	assert.True(t, !set1.Equals(set3))

}
<|endoftext|>


<commit_before>package apns

import (
	"fmt"
	"github.com/sideshow/apns2"
	"github.com/smancke/guble/server/connector"
	"github.com/smancke/guble/server/metrics"
	"github.com/smancke/guble/server/router"
	"time"
)

const (
	// schema is the default database schema for APNS
	schema = "apns_registration"
)

// Config is used for configuring the APNS module.
type Config struct {
	Enabled             *bool
	Production          *bool
	CertificateFileName *string
	CertificateBytes    *[]byte
	CertificatePassword *string
	AppTopic            *string
	Workers             *int
	Prefix              *string
	IntervalMetrics     *bool
}

// apns is the private struct for handling the communication with APNS
type apns struct {
	Config
	connector.Connector
}

// New creates a new connector.ResponsiveConnector without starting it
func New(router router.Router, sender connector.Sender, config Config) (connector.ResponsiveConnector, error) {
	baseConn, err := connector.NewConnector(
		router,
		sender,
		connector.Config{
			Name:       "apns",
			Schema:     schema,
			Prefix:     *config.Prefix,
			URLPattern: fmt.Sprintf("/{%s}/{%s}/{%s:.*}", deviceIDKey, userIDKey, connector.TopicParam),
			Workers:    *config.Workers,
		},
	)
	if err != nil {
		logger.WithError(err).Error("Base connector error")
		return nil, err
	}
	a := &apns{
		Config:    config,
		Connector: baseConn,
	}
	a.SetResponseHandler(a)
	return a, nil
}

func (a *apns) Start() error {
	err := a.Connector.Start()
	if err == nil {
		a.startMetrics()
	}
	return err
}

func (a *apns) startMetrics() {
	mTotalSentMessages.Set(0)
	mTotalSendErrors.Set(0)
	mTotalResponseErrors.Set(0)
	mTotalResponseInternalErrors.Set(0)
	mTotalResponseRegistrationErrors.Set(0)
	mTotalResponseOtherErrors.Set(0)

	if *a.IntervalMetrics {
		a.startIntervalMetric(mMinute, time.Minute)
		a.startIntervalMetric(mHour, time.Hour)
		a.startIntervalMetric(mDay, time.Hour*24)
	}
}

func (a *apns) startIntervalMetric(m metrics.Map, td time.Duration) {
	metrics.RegisterInterval(a.Context(), m, td, resetIntervalMetrics, processAndResetIntervalMetrics)
}

func (a *apns) HandleResponse(request connector.Request, responseIface interface{}, metadata *connector.Metadata, errSend error) error {
	if errSend != nil {
		logger.WithError(errSend).Error("error when trying to send APNS notification")
		mTotalSendErrors.Add(1)
		if *a.IntervalMetrics && metadata != nil {
			addToLatenciesAndCountsMaps(currentTotalErrorsLatenciesKey, currentTotalErrorsKey, metadata.Latency)
		}
		return errSend
	}
	r, ok := responseIface.(*apns2.Response)
	if !ok {
		mTotalResponseErrors.Add(1)
		return fmt.Errorf("Response could not be converted to an APNS Response")
	}
	messageID := request.Message().ID
	subscriber := request.Subscriber()
	subscriber.SetLastID(messageID)
	if err := a.Manager().Update(subscriber); err != nil {
		logger.WithField("error", err.Error()).Error("Manager could not update subscription")
		mTotalResponseInternalErrors.Add(1)
		return err
	}
	if r.Sent() {
		logger.WithField("id", r.ApnsID).Debug("APNS notification was successfully sent")
		mTotalSentMessages.Add(1)
		if *a.IntervalMetrics && metadata != nil {
			addToLatenciesAndCountsMaps(currentTotalMessagesLatenciesKey, currentTotalMessagesKey, metadata.Latency)
		}
		return nil
	}
	logger.WithField("id", r.ApnsID).WithField("reason", r.Reason).Error("APNS notification was not sent")
	switch r.Reason {
	case
		apns2.ReasonMissingDeviceToken,
		apns2.ReasonBadDeviceToken,
		apns2.ReasonDeviceTokenNotForTopic,
		apns2.ReasonUnregistered:

		logger.WithField("id", r.ApnsID).Info("trying to removing subscriber because a relevant error was received from APNS")
		mTotalResponseRegistrationErrors.Add(1)
		err := a.Manager().Remove(subscriber)
		if err != nil {
			logger.WithField("id", r.ApnsID).Error("could not remove subscriber")
		}
	default:
		mTotalResponseOtherErrors.Add(1)
	}
	return nil
}
<commit_msg>log in APNS HandleMessage<commit_after>package apns

import (
	"fmt"
	"github.com/sideshow/apns2"
	"github.com/smancke/guble/server/connector"
	"github.com/smancke/guble/server/metrics"
	"github.com/smancke/guble/server/router"
	"time"
)

const (
	// schema is the default database schema for APNS
	schema = "apns_registration"
)

// Config is used for configuring the APNS module.
type Config struct {
	Enabled             *bool
	Production          *bool
	CertificateFileName *string
	CertificateBytes    *[]byte
	CertificatePassword *string
	AppTopic            *string
	Workers             *int
	Prefix              *string
	IntervalMetrics     *bool
}

// apns is the private struct for handling the communication with APNS
type apns struct {
	Config
	connector.Connector
}

// New creates a new connector.ResponsiveConnector without starting it
func New(router router.Router, sender connector.Sender, config Config) (connector.ResponsiveConnector, error) {
	baseConn, err := connector.NewConnector(
		router,
		sender,
		connector.Config{
			Name:       "apns",
			Schema:     schema,
			Prefix:     *config.Prefix,
			URLPattern: fmt.Sprintf("/{%s}/{%s}/{%s:.*}", deviceIDKey, userIDKey, connector.TopicParam),
			Workers:    *config.Workers,
		},
	)
	if err != nil {
		logger.WithError(err).Error("Base connector error")
		return nil, err
	}
	a := &apns{
		Config:    config,
		Connector: baseConn,
	}
	a.SetResponseHandler(a)
	return a, nil
}

func (a *apns) Start() error {
	err := a.Connector.Start()
	if err == nil {
		a.startMetrics()
	}
	return err
}

func (a *apns) startMetrics() {
	mTotalSentMessages.Set(0)
	mTotalSendErrors.Set(0)
	mTotalResponseErrors.Set(0)
	mTotalResponseInternalErrors.Set(0)
	mTotalResponseRegistrationErrors.Set(0)
	mTotalResponseOtherErrors.Set(0)

	if *a.IntervalMetrics {
		a.startIntervalMetric(mMinute, time.Minute)
		a.startIntervalMetric(mHour, time.Hour)
		a.startIntervalMetric(mDay, time.Hour*24)
	}
}

func (a *apns) startIntervalMetric(m metrics.Map, td time.Duration) {
	metrics.RegisterInterval(a.Context(), m, td, resetIntervalMetrics, processAndResetIntervalMetrics)
}

func (a *apns) HandleResponse(request connector.Request, responseIface interface{}, metadata *connector.Metadata, errSend error) error {
	if errSend != nil {
		logger.WithError(errSend).Error("error when trying to send APNS notification")
		mTotalSendErrors.Add(1)
		if *a.IntervalMetrics && metadata != nil {
			addToLatenciesAndCountsMaps(currentTotalErrorsLatenciesKey, currentTotalErrorsKey, metadata.Latency)
		}
		return errSend
	}
	r, ok := responseIface.(*apns2.Response)
	if !ok {
		mTotalResponseErrors.Add(1)
		return fmt.Errorf("Response could not be converted to an APNS Response")
	}
	messageID := request.Message().ID
	subscriber := request.Subscriber()
	subscriber.SetLastID(messageID)
	if err := a.Manager().Update(subscriber); err != nil {
		logger.WithField("error", err.Error()).Error("Manager could not update subscription")
		mTotalResponseInternalErrors.Add(1)
		return err
	}
	if r.Sent() {
		logger.WithField("id", r.ApnsID).Debug("APNS notification was successfully sent")
		mTotalSentMessages.Add(1)
		if *a.IntervalMetrics && metadata != nil {
			addToLatenciesAndCountsMaps(currentTotalMessagesLatenciesKey, currentTotalMessagesKey, metadata.Latency)
		}
		return nil
	}
	logger.WithField("id", r.ApnsID).WithField("reason", r.Reason).Error("APNS notification was not sent")
	switch r.Reason {
	case
		apns2.ReasonMissingDeviceToken,
		apns2.ReasonBadDeviceToken,
		apns2.ReasonDeviceTokenNotForTopic,
		apns2.ReasonUnregistered:

		logger.WithField("id", r.ApnsID).Info("trying to remove subscriber because a relevant error was received from APNS")
		mTotalResponseRegistrationErrors.Add(1)
		err := a.Manager().Remove(subscriber)
		if err != nil {
			logger.WithField("id", r.ApnsID).Error("could not remove subscriber")
		}
	default:
		logger.WithField("id", r.ApnsID).Error("handling other APNS errors")
		mTotalResponseOtherErrors.Add(1)
	}
	return nil
}
<|endoftext|>


<commit_before>package testutils

import (
	"bytes"
	"errors"
	"sync"
	"testing"

	"github.com/cilium/ebpf/internal"
	"github.com/cilium/ebpf/internal/unix"
)

var (
	kernelVersionOnce sync.Once
	kernelVersion     internal.Version
)

func mustKernelVersion() internal.Version {
	kernelVersionOnce.Do(func() {
		var uname unix.Utsname
		err := unix.Uname(&uname)
		if err != nil {
			panic(err)
		}

		end := bytes.IndexByte(uname.Release[:], 0)
		release := string(uname.Release[:end])

		kernelVersion, err = internal.NewVersion(release)
		if err != nil {
			panic(err)
		}
	})

	return kernelVersion
}

func CheckFeatureTest(t *testing.T, fn func() error) {
	t.Helper()

	err := fn()
	if err == nil {
		return
	}

	var ufe *internal.UnsupportedFeatureError
	if errors.As(err, &ufe) {
		checkKernelVersion(t, ufe)
	} else {
		t.Error("Feature test failed:", err)
	}
}

func SkipIfNotSupported(tb testing.TB, err error) {
	var ufe *internal.UnsupportedFeatureError
	if errors.As(err, &ufe) {
		checkKernelVersion(tb, ufe)
		tb.Skip(ufe.Error())
	}
	if errors.Is(err, internal.ErrNotSupported) {
		tb.Skip(err.Error())
	}
}

func checkKernelVersion(tb testing.TB, ufe *internal.UnsupportedFeatureError) {
	if ufe.MinimumVersion.Unspecified() {
		return
	}

	kernelVersion := mustKernelVersion()
	if ufe.MinimumVersion.Less(kernelVersion) {
		tb.Helper()
		tb.Fatalf("Feature '%s' isn't supported even though kernel %s is newer than %s",
			ufe.Name, kernelVersion, ufe.MinimumVersion)
	}
}

func SkipOnOldKernel(tb testing.TB, minVersion, feature string) {
	tb.Helper()

	minv, err := internal.NewVersion(minVersion)
	if err != nil {
		tb.Fatalf("Invalid version %s: %s", minVersion, err)
	}

	if mustKernelVersion().Less(minv) {
		tb.Skipf("Test requires at least kernel %s (due to missing %s)", minv, feature)
	}
}
<commit_msg>testutils: switch mustKernelVersion() over to internal.KernelVersion()<commit_after>package testutils

import (
	"errors"
	"testing"

	"github.com/cilium/ebpf/internal"
)

func mustKernelVersion() internal.Version {
	v, err := internal.KernelVersion()
	if err != nil {
		panic(err)
	}
	return v
}

func CheckFeatureTest(t *testing.T, fn func() error) {
	t.Helper()

	err := fn()
	if err == nil {
		return
	}

	var ufe *internal.UnsupportedFeatureError
	if errors.As(err, &ufe) {
		checkKernelVersion(t, ufe)
	} else {
		t.Error("Feature test failed:", err)
	}
}

func SkipIfNotSupported(tb testing.TB, err error) {
	var ufe *internal.UnsupportedFeatureError
	if errors.As(err, &ufe) {
		checkKernelVersion(tb, ufe)
		tb.Skip(ufe.Error())
	}
	if errors.Is(err, internal.ErrNotSupported) {
		tb.Skip(err.Error())
	}
}

func checkKernelVersion(tb testing.TB, ufe *internal.UnsupportedFeatureError) {
	if ufe.MinimumVersion.Unspecified() {
		return
	}

	kernelVersion := mustKernelVersion()
	if ufe.MinimumVersion.Less(kernelVersion) {
		tb.Helper()
		tb.Fatalf("Feature '%s' isn't supported even though kernel %s is newer than %s",
			ufe.Name, kernelVersion, ufe.MinimumVersion)
	}
}

func SkipOnOldKernel(tb testing.TB, minVersion, feature string) {
	tb.Helper()

	minv, err := internal.NewVersion(minVersion)
	if err != nil {
		tb.Fatalf("Invalid version %s: %s", minVersion, err)
	}

	if mustKernelVersion().Less(minv) {
		tb.Skipf("Test requires at least kernel %s (due to missing %s)", minv, feature)
	}
}
<|endoftext|>


<commit_before>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package utils

import (
	"github.com/gogf/gf/v2/internal/command"
)

const (
	commandEnvKeyForDebugKey = "gf.debug"            // Debug key for checking if in debug mode.
	StackFilterKeyForGoFrame = "github.com/gogf/gf@" // Stack filtering key for all GoFrame module paths.
)

var (
	// isDebugEnabled marks whether GoFrame debug mode is enabled.
	isDebugEnabled = false
)

func init() {
	// Debugging configured.
	value := command.GetOptWithEnv(commandEnvKeyForDebugKey)
	if value == "" || value == "0" || value == "false" {
		isDebugEnabled = false
	} else {
		isDebugEnabled = true
	}
}

// IsDebugEnabled checks and returns whether debug mode is enabled.
// The debug mode is enabled when command argument "gf.debug" or environment "GF_DEBUG" is passed.
func IsDebugEnabled() bool {
	return isDebugEnabled
}
<commit_msg>filter key updates for stack information<commit_after>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package utils

import (
	"github.com/gogf/gf/v2/internal/command"
)

const (
	// Debug key for checking if in debug mode.
	commandEnvKeyForDebugKey = "gf.debug"

	// StackFilterKeyForGoFrame is the stack filtering key for all GoFrame module paths.
	// Eg: .../pkg/mod/github.com/gogf/gf/v2@v2.0.0-20211011134327-54dd11f51122/debug/gdebug/gdebug_caller.go
	StackFilterKeyForGoFrame = "github.com/gogf/gf/v"
)

var (
	// isDebugEnabled marks whether GoFrame debug mode is enabled.
	isDebugEnabled = false
)

func init() {
	// Debugging configured.
	value := command.GetOptWithEnv(commandEnvKeyForDebugKey)
	if value == "" || value == "0" || value == "false" {
		isDebugEnabled = false
	} else {
		isDebugEnabled = true
	}
}

// IsDebugEnabled checks and returns whether debug mode is enabled.
// The debug mode is enabled when command argument "gf.debug" or environment "GF_DEBUG" is passed.
func IsDebugEnabled() bool {
	return isDebugEnabled
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package java

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"v.io/jiri/profiles"
	"v.io/jiri/tool"
	"v.io/x/lib/envvar"
)

const (
	profileName = "java"
)

type versionSpec struct {
	jdkVersion string
}

func init() {
	m := &Manager{
		versionInfo: profiles.NewVersionInfo(profileName, map[string]interface{}{
			"1.7+": versionSpec{"1.7+"},
			"1.8+": versionSpec{"1.8+"},
		}, "1.8+"),
	}
	profiles.Register(profileName, m)
}

type Manager struct {
	root, javaRoot profiles.RelativePath
	versionInfo    *profiles.VersionInfo
	spec           versionSpec
}

func (Manager) Name() string {
	return profileName
}

func (m Manager) String() string {
	return fmt.Sprintf("%s[%s]", profileName, m.versionInfo.Default())
}

func (m Manager) Info() string {
	return `
The java profile provides support for Java and in particular installs java related
tools such as gradle. It does not install a jre, but rather attempts to locate one
on the current system and prompts the user to install it if not present. It also
installs the android profile since android is the primary use of Java. It only
supports a single target of 'arm-android' and assumes it as the default.`
}

func (m Manager) VersionInfo() *profiles.VersionInfo {
	return m.versionInfo
}

func (m *Manager) AddFlags(flags *flag.FlagSet, action profiles.Action) {
}

func (m *Manager) initForTarget(root profiles.RelativePath, target profiles.Target) error {
	m.root = root
	m.javaRoot = root.Join("java")
	if err := m.versionInfo.Lookup(target.Version(), &m.spec); err != nil {
		return err
	}
	return nil
}

func (m *Manager) Install(ctx *tool.Context, root profiles.RelativePath, target profiles.Target) error {
	if err := m.initForTarget(root, target); err != nil {
		return err
	}

	javaHome, err := m.install(ctx, target)
	if err != nil {
		return err
	}
	baseTarget := target
	baseTarget.SetVersion("")
	if err := profiles.EnsureProfileTargetIsInstalled(ctx, "base", root, baseTarget); err != nil {
		return err
	}
	// NOTE(spetrovic): For now, we install android profile along with Java,
	// as the two are bundled up for ease of development.
	androidTarget, err := profiles.NewTarget("arm-android")
	if err != nil {
		return err
	}
	if err := profiles.EnsureProfileTargetIsInstalled(ctx, "android", root, androidTarget); err != nil {
		return err
	}

	// Merge the environments using those in the target as the base
	// with those from the base profile and then the java ones
	// we want to set here.
	env := envvar.VarsFromSlice(target.Env.Vars)
	javaProfileEnv := []string{
		fmt.Sprintf("CGO_CFLAGS=-I%s -I%s", filepath.Join(javaHome, "include"),
			filepath.Join(javaHome, "include", target.OS())),
		"JAVA_HOME=" + javaHome,
	}

	baseProfileEnv := profiles.EnvFromProfile(baseTarget, "base")
	profiles.MergeEnv(profiles.ProfileMergePolicies(), env, baseProfileEnv, javaProfileEnv)
	target.Env.Vars = env.ToSlice()
	if profiles.SchemaVersion() >= 4 {
		profiles.InstallProfile(profileName, m.javaRoot.RelativePath())
	} else {
		profiles.InstallProfile(profileName, m.javaRoot.Expand())
	}
	target.InstallationDir = javaHome
	return profiles.AddProfileTarget(profileName, target)
}

func (m *Manager) Uninstall(ctx *tool.Context, root profiles.RelativePath, target profiles.Target) error {
	if err := m.initForTarget(root, target); err != nil {
		return err
	}
	if err := ctx.Run().RemoveAll(m.javaRoot.Expand()); err != nil {
		return err
	}
	profiles.RemoveProfileTarget(profileName, target)
	return nil
}

func (m *Manager) install(ctx *tool.Context, target profiles.Target) (string, error) {
	switch target.OS() {
	case "darwin":
		if err := profiles.InstallPackages(ctx, []string{"gradle"}); err != nil {
			return "", err
		}
		javaHome, err := getJDKDarwin(ctx, m.spec)
		if err == nil {
			return javaHome, nil
		}
		fmt.Fprintf(os.Stderr, "Couldn't find an existing Java installation: %v", err)

		// Prompt the user to install JDK.
		// (Note that JDK cannot be installed via Homebrew.)
		javaHomeBin := "/usr/libexec/java_home"
		profiles.RunCommand(ctx, nil, javaHomeBin, "-t", "CommandLine", "--request")
		return "", fmt.Errorf("Please follow the OS X prompt instructions to install JDK, then set JAVA_HOME and re-run the profile installation command.")
	case "linux":
		if err := profiles.InstallPackages(ctx, []string{"gradle"}); err != nil {
			return "", err
		}
		javaHome, err := getJDKLinux(ctx, m.spec)
		if err == nil {
			return javaHome, nil
		}
		fmt.Fprintf(os.Stderr, "Couldn't find an existing Java installation: %v", err)

		// Prompt the user to install JDK.
		// (Note that Oracle JDKs cannot be installed via apt-get.)
		dlURL := "http://www.oracle.com/technetwork/java/javase/downloads/index.html"
		profiles.RunCommand(ctx, nil, "xdg-open", dlURL)
		return "", fmt.Errorf("Please follow the instructions in the browser to install JDK, then set JAVA_HOME and re-run the profile installation command")
	default:
		return "", fmt.Errorf("OS %q is not supported", target.OS)
	}
}

func checkInstall(ctx *tool.Context, home, version string) error {
	_, err := ctx.Run().Stat(filepath.Join(home, "include", "jni.h"))
	if err != nil {
		return err
	}
	javacPath := filepath.Join(home, "bin", "javac")
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	ctx.Run().CommandWithOpts(opts, javacPath, "-version")
	if out.Len() == 0 {
		return errors.New("Couldn't find a valid javac at: " + javacPath)
	}
	javacVersion := strings.TrimPrefix(out.String(), "javac ")
	version = strings.TrimSuffix(version, "+")
	if !strings.HasPrefix(javacVersion, version) {
		return fmt.Errorf("Couldn't find javac with version %v, got %v.", version, javacVersion)
	}
	return err
}

func getJDKLinux(ctx *tool.Context, spec versionSpec) (string, error) {
	if javaHome := os.Getenv("JAVA_HOME"); len(javaHome) > 0 {
		if err := checkInstall(ctx, javaHome, spec.jdkVersion); err != nil {
			return "", fmt.Errorf("JAVA_HOME (%s) is incompatible with required profile version: %v", javaHome, err)
		}
		return javaHome, nil
	}
	javacBin := "/usr/bin/javac"
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	ctx.Run().CommandWithOpts(opts, "readlink", "-f", javacBin)
	if out.Len() == 0 {
		return "", errors.New("No Java installed under /usr/bin/javac")
	}
	// Strip "/bin/javac" from the returned path.
	javaHome := strings.TrimSuffix(out.String(), "/bin/javac\n")
	if err := checkInstall(ctx, javaHome, spec.jdkVersion); err != nil {
		return "", errors.New("Java installed in /usr/bin/javac is incompatible with profile version: " + spec.jdkVersion)
	}
	return javaHome, nil
}

func getJDKDarwin(ctx *tool.Context, spec versionSpec) (string, error) {
	if javaHome := os.Getenv("JAVA_HOME"); len(javaHome) > 0 {
		if err := checkInstall(ctx, javaHome, spec.jdkVersion); err != nil {
			return "", fmt.Errorf("JAVA_HOME (%s) is incompatible with required profile version: %v", javaHome, err)
		}
		return javaHome, nil
	}
	javaHomeBin := "/usr/libexec/java_home"
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	ctx.Run().CommandWithOpts(opts, javaHomeBin, "-t", "CommandLine", "-v", spec.jdkVersion)
	if out.Len() == 0 {
		return "", errors.New("Couldn't find a valid Java system installation.")
	}
	jdkLoc, _, err := bufio.NewReader(strings.NewReader(out.String())).ReadLine()
	if err != nil {
		return "", fmt.Errorf("Couldn't find a valid Java system installation: %v", err)
	}
	if err := checkInstall(ctx, string(jdkLoc), spec.jdkVersion); err != nil {
		return "", fmt.Errorf("Java system installation is incompatible with profile version %s: %v", spec.jdkVersion, err)
	}
	return string(jdkLoc), nil
}
<commit_msg>v.io/x/devtools: search for system java installations<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package java

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"v.io/jiri/profiles"
	"v.io/jiri/tool"
	"v.io/x/lib/envvar"
)

const (
	profileName = "java"
)

type versionSpec struct {
	jdkVersion string
}

func init() {
	m := &Manager{
		versionInfo: profiles.NewVersionInfo(profileName, map[string]interface{}{
			"1.7+": versionSpec{"1.7+"},
			"1.8+": versionSpec{"1.8+"},
		}, "1.8+"),
	}
	profiles.Register(profileName, m)
}

type Manager struct {
	root, javaRoot profiles.RelativePath
	versionInfo    *profiles.VersionInfo
	spec           versionSpec
}

func (Manager) Name() string {
	return profileName
}

func (m Manager) String() string {
	return fmt.Sprintf("%s[%s]", profileName, m.versionInfo.Default())
}

func (m Manager) Info() string {
	return `
The java profile provides support for Java and in particular installs java related
tools such as gradle. It does not install a jre, but rather attempts to locate one
on the current system and prompts the user to install it if not present. It also
installs the android profile since android is the primary use of Java. It only
supports a single target of 'arm-android' and assumes it as the default.`
}

func (m Manager) VersionInfo() *profiles.VersionInfo {
	return m.versionInfo
}

func (m *Manager) AddFlags(flags *flag.FlagSet, action profiles.Action) {
}

func (m *Manager) initForTarget(root profiles.RelativePath, target profiles.Target) error {
	m.root = root
	m.javaRoot = root.Join("java")
	if err := m.versionInfo.Lookup(target.Version(), &m.spec); err != nil {
		return err
	}
	return nil
}

func (m *Manager) Install(ctx *tool.Context, root profiles.RelativePath, target profiles.Target) error {
	if err := m.initForTarget(root, target); err != nil {
		return err
	}

	javaHome, err := m.install(ctx, target)
	if err != nil {
		return err
	}
	baseTarget := target
	baseTarget.SetVersion("")
	if err := profiles.EnsureProfileTargetIsInstalled(ctx, "base", root, baseTarget); err != nil {
		return err
	}
	// NOTE(spetrovic): For now, we install android profile along with Java,
	// as the two are bundled up for ease of development.
	androidTarget, err := profiles.NewTarget("arm-android")
	if err != nil {
		return err
	}
	if err := profiles.EnsureProfileTargetIsInstalled(ctx, "android", root, androidTarget); err != nil {
		return err
	}

	// Merge the environments using those in the target as the base
	// with those from the base profile and then the java ones
	// we want to set here.
	env := envvar.VarsFromSlice(target.Env.Vars)
	javaProfileEnv := []string{
		fmt.Sprintf("CGO_CFLAGS=-I%s -I%s", filepath.Join(javaHome, "include"),
			filepath.Join(javaHome, "include", target.OS())),
		"JAVA_HOME=" + javaHome,
	}

	baseProfileEnv := profiles.EnvFromProfile(baseTarget, "base")
	profiles.MergeEnv(profiles.ProfileMergePolicies(), env, baseProfileEnv, javaProfileEnv)
	target.Env.Vars = env.ToSlice()
	if profiles.SchemaVersion() >= 4 {
		profiles.InstallProfile(profileName, m.javaRoot.RelativePath())
	} else {
		profiles.InstallProfile(profileName, m.javaRoot.Expand())
	}
	target.InstallationDir = javaHome
	return profiles.AddProfileTarget(profileName, target)
}

func (m *Manager) Uninstall(ctx *tool.Context, root profiles.RelativePath, target profiles.Target) error {
	if err := m.initForTarget(root, target); err != nil {
		return err
	}
	if err := ctx.Run().RemoveAll(m.javaRoot.Expand()); err != nil {
		return err
	}
	profiles.RemoveProfileTarget(profileName, target)
	return nil
}

func (m *Manager) install(ctx *tool.Context, target profiles.Target) (string, error) {
	switch target.OS() {
	case "darwin":
		if err := profiles.InstallPackages(ctx, []string{"gradle"}); err != nil {
			return "", err
		}
		javaHome, err := getJDKDarwin(ctx, m.spec)
		if err == nil {
			return javaHome, nil
		}
		fmt.Fprintf(os.Stderr, "Couldn't find an existing Java installation: %v", err)

		// Prompt the user to install JDK.
		// (Note that JDK cannot be installed via Homebrew.)
		javaHomeBin := "/usr/libexec/java_home"
		profiles.RunCommand(ctx, nil, javaHomeBin, "-t", "CommandLine", "--request")
		return "", fmt.Errorf("Please follow the OS X prompt instructions to install JDK, then set JAVA_HOME and re-run the profile installation command.")
	case "linux":
		if err := profiles.InstallPackages(ctx, []string{"gradle"}); err != nil {
			return "", err
		}
		javaHome, err := getJDKLinux(ctx, m.spec)
		if err == nil {
			return javaHome, nil
		}
		fmt.Fprintf(os.Stderr, "Couldn't find an existing Java installation: %v", err)

		// Prompt the user to install JDK.
		// (Note that Oracle JDKs cannot be installed via apt-get.)
		dlURL := "http://www.oracle.com/technetwork/java/javase/downloads/index.html"
		profiles.RunCommand(ctx, nil, "xdg-open", dlURL)
		return "", fmt.Errorf("Please follow the instructions in the browser to install JDK, then set JAVA_HOME and re-run the profile installation command")
	default:
		return "", fmt.Errorf("OS %q is not supported", target.OS)
	}
}

func checkInstall(ctx *tool.Context, home, version string) error {
	_, err := ctx.Run().Stat(filepath.Join(home, "include", "jni.h"))
	if err != nil {
		return err
	}
	javacPath := filepath.Join(home, "bin", "javac")
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	ctx.Run().CommandWithOpts(opts, javacPath, "-version")
	if out.Len() == 0 {
		return errors.New("couldn't find a valid javac at: " + javacPath)
	}
	javacVersion := strings.TrimPrefix(out.String(), "javac ")
	if !strings.HasPrefix(javacVersion, strings.TrimSuffix(version, "+")) {
		return fmt.Errorf("want javac version %v, got %v.", version, javacVersion)
	}
	return err
}

func getJDKLinux(ctx *tool.Context, spec versionSpec) (string, error) {
	if javaHome := os.Getenv("JAVA_HOME"); len(javaHome) > 0 {
		err := checkInstall(ctx, javaHome, spec.jdkVersion)
		if err == nil {
			return javaHome, nil
		}
		fmt.Fprintf(os.Stderr, "JAVA_HOME (%s) is incompatible with required profile version: %v; trying to find a compatible system installation.", javaHome, err)
	}
	// JAVA_HOME doesn't point to the right version: check the system installation.
	javacBin := "/usr/bin/javac"
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	ctx.Run().CommandWithOpts(opts, "readlink", "-f", javacBin)
	if out.Len() == 0 {
		return "", errors.New("No Java installed under /usr/bin/javac")
	}
	// Strip "/bin/javac" from the returned path.
	javaHome := strings.TrimSuffix(out.String(), "/bin/javac\n")
	if err := checkInstall(ctx, javaHome, spec.jdkVersion); err != nil {
		return "", errors.New("Java installed in /usr/bin/javac is incompatible with profile version: " + spec.jdkVersion)
	}
	return javaHome, nil
}

func getJDKDarwin(ctx *tool.Context, spec versionSpec) (string, error) {
	if javaHome := os.Getenv("JAVA_HOME"); len(javaHome) > 0 {
		err := checkInstall(ctx, javaHome, spec.jdkVersion)
		if err == nil {
			return javaHome, nil
		}
		fmt.Fprintf(os.Stderr, "JAVA_HOME (%s) is incompatible with required profile version %v; trying to find a compatible system installation", javaHome, err)
	}
	// JAVA_HOME doesn't point to the right version: check the system installation.
	javaHomeBin := "/usr/libexec/java_home"
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	ctx.Run().CommandWithOpts(opts, javaHomeBin, "-t", "CommandLine", "-v", spec.jdkVersion)
	if out.Len() == 0 {
		return "", errors.New("Couldn't find a valid Java system installation.")
	}
	jdkLoc, _, err := bufio.NewReader(strings.NewReader(out.String())).ReadLine()
	if err != nil {
		return "", fmt.Errorf("Couldn't find a valid Java system installation: %v", err)
	}
	if err := checkInstall(ctx, string(jdkLoc), spec.jdkVersion); err != nil {
		return "", fmt.Errorf("Java system installation is incompatible with profile version %s: %v", spec.jdkVersion, err)
	}
	return string(jdkLoc), nil
}
<|endoftext|>


<commit_before>// Copyright © 2016 Yieldbot <devops@yieldbot.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package sensupluginsslack

import (
	"fmt"
	"log/syslog"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/yieldbot/sensuplugin/sensuutil"
	//"github.com/yieldbot/sensupluginsslack/version"
)

// Slack api token
var slackToken string

// Configuration via Viper
var cfgFile string

// Hostname for logging
var host string

// Create a logging instance.
var syslogLog = logrus.New()

// print debug info
var debug bool

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "sensupluginsslack",
	//Short: fmt.Sprintf("A slack handler for Sensu - (%s)", version.AppVersion()),
	Long:  `Generate meaningful slack attachments from Senu events`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Setup logging for the package. Doing it here is much eaiser than in each
	// binary. If you want to overwrite it in a specific binary then feel free.
	hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
	if err != nil {
		panic(err)
	}
	syslogLog.Hooks.Add(hook)
	syslogLog.Formatter = new(logrus.JSONFormatter)

	// Set the hostname for use in logging within the package. Doing it here is
	// cleaner than in each binary but if you want to use some other method just
	// override the variable in the specific binary.
	host, err = os.Hostname()
	if err != nil {
		syslogLog.WithFields(logrus.Fields{
			"check":   "sensupluginsslack",
			"client":  "unknown",
			//"version": version.AppVersion(),
			"error":   err,
		}).Error(`Could not determine the hostname of this machine as reported by the kernel.`)
		sensuutil.Exit("GENERALGOLANGERROR")
	}

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is /etc/sensuplugins/conf.d/.sensupluginschrony.yaml)")
	RootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "print debugging info")
	RootCmd.PersistentFlags().StringVarP(&slackToken, "token", "", "", "the slack api token")
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}

func initConfig() {
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		viper.SetConfigName("sensupluginsslack")
		viper.AddConfigPath("/etc/sensuplugins/conf.d")
	}

	if slackToken == "" {
		viper.AutomaticEnv()
		if err := viper.ReadInConfig(); err == nil {
		} else {
			syslogLog.WithFields(logrus.Fields{
				"check":   "sensupluginsslack",
				"client":  host,
				//"version": version.AppVersion(),
				"error":   err,
				"cfgFile": cfgFile,
			}).Error(`Could not read in the configuration file.`)
		}
	}
}
<commit_msg>Fix default<commit_after>// Copyright © 2016 Yieldbot <devops@yieldbot.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package sensupluginsslack

import (
	"fmt"
	"log/syslog"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/yieldbot/sensuplugin/sensuutil"
	//"github.com/yieldbot/sensupluginsslack/version"
)

// Slack api token
var slackToken string

// Configuration via Viper
var cfgFile string

// Hostname for logging
var host string

// Create a logging instance.
var syslogLog = logrus.New()

// print debug info
var debug bool

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "sensupluginsslack",
	//Short: fmt.Sprintf("A slack handler for Sensu - (%s)", version.AppVersion()),
	Long:  `Generate meaningful slack attachments from Sensu events`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Setup logging for the package. Doing it here is much eaiser than in each
	// binary. If you want to overwrite it in a specific binary then feel free.
	hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
	if err != nil {
		panic(err)
	}
	syslogLog.Hooks.Add(hook)
	syslogLog.Formatter = new(logrus.JSONFormatter)

	// Set the hostname for use in logging within the package. Doing it here is
	// cleaner than in each binary but if you want to use some other method just
	// override the variable in the specific binary.
	host, err = os.Hostname()
	if err != nil {
		syslogLog.WithFields(logrus.Fields{
			"check":   "sensupluginsslack",
			"client":  "unknown",
			//"version": version.AppVersion(),
			"error":   err,
		}).Error(`Could not determine the hostname of this machine as reported by the kernel.`)
		sensuutil.Exit("GENERALGOLANGERROR")
	}

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is /etc/sensuplugins/conf.d/.sensupluginsslack.yaml)")
	RootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "print debugging info")
	RootCmd.PersistentFlags().StringVarP(&slackToken, "token", "", "", "the slack api token")
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}

func initConfig() {
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		viper.SetConfigName("sensupluginsslack")
		viper.AddConfigPath("/etc/sensuplugins/conf.d")
	}

	if slackToken == "" {
		viper.AutomaticEnv()
		if err := viper.ReadInConfig(); err == nil {
		} else {
			syslogLog.WithFields(logrus.Fields{
				"check":   "sensupluginsslack",
				"client":  host,
				//"version": version.AppVersion(),
				"error":   err,
				"cfgFile": cfgFile,
			}).Error(`Could not read in the configuration file.`)
		}
	}
}
<|endoftext|>


<commit_before>package custom

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/pkg/errors"
	"gopkg.in/goracle.v2"
)

var ZeroIsAlmostZero bool

type Number goracle.Number

func (n *Number) Set(num goracle.Number) {
	*n = Number(num)
}
func (n Number) Get() goracle.Number {
	return goracle.Number(n)
}

func NumbersFromStrings(s *[]string) *[]goracle.Number {
	if s == nil {
		return nil
	}
	return (*[]goracle.Number)(unsafe.Pointer(s))
}

type Date string

const timeFormat = time.RFC3339 //"2006-01-02 15:04:05 -0700"

func NewDate(t time.Time) Date {
	if t.IsZero() {
		return Date("")
	}
	return Date(t.Format(timeFormat))
}
func (d *Date) Set(t time.Time) {
	if t.IsZero() {
		*d = Date("")
	}
	*d = NewDate(t)
}
func (d Date) Get() (od time.Time, err error) {
	if d == "" {
		return
	}
	var i int
	if i = strings.IndexByte(string(d), 'T'); i < 0 {
		if i = strings.IndexByte(string(d), ' '); i < 0 {
			d = d + "T00:00:00"
			i = len(d)
		} else {
			d = d[:i] + "T" + d[i+1:]
		}
	}

	n := len(d)
	if n > len(timeFormat) {
		n = len(timeFormat)
	}
	t, err := time.Parse(timeFormat[:n], string(d)) // TODO(tgulacsi): more robust parser
	if err != nil {
		return t, errors.Wrap(err, string(d))
	}
	return t, nil
}

type Lob struct {
	*goracle.Lob
	data []byte
	err  error
}

func (L *Lob) read() error {
	if L.err != nil {
		return L.err
	}
	if L.data == nil {
		L.data, L.err = ioutil.ReadAll(L.Lob)
	}
	return L.err
}
func (L *Lob) Size() int {
	if L.read() != nil {
		return 0
	}
	return len(L.data)
}
func (L *Lob) Marshal() ([]byte, error) {
	err := L.read()
	return L.data, err
}
func (L *Lob) MarshalTo(p []byte) (int, error) {
	err := L.read()
	i := copy(p, L.data)
	return i, err
}
func (L *Lob) Unmarshal(p []byte) error {
	L.data = p
	return nil
}

func AsString(v interface{}) string {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case string:
		return x
	case sql.NullString:
		return x.String
	case fmt.Stringer:
		return x.String()
	}
	return fmt.Sprintf("%v", v)
}

func AsFloat64(v interface{}) float64 {
	if v == nil {
		return 0
	}
	var result float64
	switch x := v.(type) {
	case float64:
		result = x
	case float32:
		result = float64(x)
	case int64:
		result = float64(x)
	case int32:
		result = float64(x)
	case sql.NullFloat64:
		result = x.Float64
	case string, goracle.Number:
		var s string
		switch x := x.(type) {
		case string:
			s = x
		case goracle.Number:
			s = string(x)
		}
		if s == "" {
			return 0
		}
		f, err := strconv.ParseFloat(s, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Float64", s)
		}
		result = f

	default:
		log.Printf("WARN: unknown Int64 type %T", v)
		return 0
	}
	if ZeroIsAlmostZero && result == 0 {
		return math.SmallestNonzeroFloat64
	}
	return result
}
func AsInt32(v interface{}) int32 {
	if v == nil {
		return 0
	}
	switch x := v.(type) {
	case int32:
		return x
	case int64:
		return int32(x)
	case float64:
		return int32(x)
	case float32:
		return int32(x)
	case sql.NullInt64:
		return int32(x.Int64)
	case string, goracle.Number:
		var s string
		switch x := x.(type) {
		case string:
			s = x
		case goracle.Number:
			s = string(x)
		}
		if s == "" {
			return 0
		}
		i, err := strconv.ParseInt(s, 10, 32)
		if err != nil {
			log.Printf("ERROR parsing %q as Int32", s)
		}
		return int32(i)
	default:
		log.Printf("WARN: unknown Int32 type %T", v)
	}
	return 0
}
func AsInt64(v interface{}) int64 {
	switch x := v.(type) {
	case int64:
		return x
	case int32:
		return int64(x)
	case float64:
		return int64(x)
	case float32:
		return int64(x)
	case sql.NullInt64:
		return x.Int64
	case string, goracle.Number:
		var s string
		switch x := x.(type) {
		case string:
			s = x
		case goracle.Number:
			s = string(x)
		}
		if s == "" {
			return 0
		}
		i, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Int64", s)
		}
		return i
	default:
		log.Printf("WARN: unknown Int64 type %T", v)
	}
	return 0
}
func AsDate(v interface{}) Date {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case Date:
		return x
	case time.Time:
		return Date(x.Format(timeFormat))
	case string:
		return Date(x)
	default:
		log.Printf("WARN: unknown Date type %T", v)
	}

	return Date("")
}
<commit_msg>custom: add Scan methods<commit_after>package custom

import (
	"database/sql"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/pkg/errors"
	"gopkg.in/goracle.v2"
)

var ZeroIsAlmostZero bool

type Number goracle.Number

func (n *Number) Set(num goracle.Number) {
	*n = Number(num)
}
func (n Number) Get() goracle.Number {
	return goracle.Number(n)
}

// Scan assigns a value from a database driver.
func (n *Number) Scan(src interface{}) error {
	switch x := src.(type) {
	case Number:
		*n = Number(x)
	case string:
		*n = Number(x)
	case []byte:
		*n = Number(x)
	case int, int8, int16, int32, int64,
		uint, uint16, uint32, uint64:
		*n = Number(fmt.Sprintf("%d", x))
	case float32, float64:
		*n = Number(fmt.Sprintf("%f", x))
	}
	return nil
}

func NumbersFromStrings(s *[]string) *[]goracle.Number {
	if s == nil {
		return nil
	}
	return (*[]goracle.Number)(unsafe.Pointer(s))
}

type Date string

const timeFormat = time.RFC3339 //"2006-01-02 15:04:05 -0700"

func NewDate(t time.Time) Date {
	if t.IsZero() {
		return Date("")
	}
	return Date(t.Format(timeFormat))
}
func (d *Date) Set(t time.Time) {
	if t.IsZero() {
		*d = Date("")
	}
	*d = NewDate(t)
}
func (d Date) Get() (od time.Time, err error) {
	if d == "" {
		return
	}
	var i int
	if i = strings.IndexByte(string(d), 'T'); i < 0 {
		if i = strings.IndexByte(string(d), ' '); i < 0 {
			d = d + "T00:00:00"
			i = len(d)
		} else {
			d = d[:i] + "T" + d[i+1:]
		}
	}

	n := len(d)
	if n > len(timeFormat) {
		n = len(timeFormat)
	}
	t, err := time.Parse(timeFormat[:n], string(d)) // TODO(tgulacsi): more robust parser
	if err != nil {
		return t, errors.Wrap(err, string(d))
	}
	return t, nil
}

// Scan assigns a value from a database driver.
func (d *Date) Scan(src interface{}) error {
	switch x := src.(type) {
	case string:
		*d = Date(x)
	case []byte:
		*d = Date(x)
	case time.Time:
		*d = Date(x.Format(timeFormat))
	default:
		return errors.Errorf("unknown type %T", src)
	}
	return nil
}

type Lob struct {
	*goracle.Lob
	data []byte
	err  error
}

func (L *Lob) read() error {
	if L.err != nil {
		return L.err
	}
	if L.data == nil {
		L.data, L.err = ioutil.ReadAll(L.Lob)
	}
	return L.err
}
func (L *Lob) Size() int {
	if L.read() != nil {
		return 0
	}
	return len(L.data)
}
func (L *Lob) Marshal() ([]byte, error) {
	err := L.read()
	return L.data, err
}
func (L *Lob) MarshalTo(p []byte) (int, error) {
	err := L.read()
	i := copy(p, L.data)
	return i, err
}
func (L *Lob) Unmarshal(p []byte) error {
	L.data = p
	return nil
}

// Scan assigns a value from a database driver.
func (L *Lob) Scan(src interface{}) error {
	switch x := src.(type) {
	case Lob:
		L.data, L.err = ioutil.ReadAll(L.Lob)
	case *Lob:
		L.data, L.err = ioutil.ReadAll(L.Lob)
	case io.Reader:
		L.data, L.err = ioutil.ReadAll(x)
	case []byte:
		L.data = x
	case string:
		L.data = []byte(x)
	default:
		return errors.Errorf("unknown type %T", src)
	}
	return nil
}

func AsString(v interface{}) string {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case string:
		return x
	case sql.NullString:
		return x.String
	case fmt.Stringer:
		return x.String()
	}
	return fmt.Sprintf("%v", v)
}

func AsFloat64(v interface{}) float64 {
	if v == nil {
		return 0
	}
	var result float64
	switch x := v.(type) {
	case float64:
		result = x
	case float32:
		result = float64(x)
	case int64:
		result = float64(x)
	case int32:
		result = float64(x)
	case sql.NullFloat64:
		result = x.Float64
	case string, goracle.Number:
		var s string
		switch x := x.(type) {
		case string:
			s = x
		case goracle.Number:
			s = string(x)
		}
		if s == "" {
			return 0
		}
		f, err := strconv.ParseFloat(s, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Float64", s)
		}
		result = f

	default:
		log.Printf("WARN: unknown Int64 type %T", v)
		return 0
	}
	if ZeroIsAlmostZero && result == 0 {
		return math.SmallestNonzeroFloat64
	}
	return result
}
func AsInt32(v interface{}) int32 {
	if v == nil {
		return 0
	}
	switch x := v.(type) {
	case int32:
		return x
	case int64:
		return int32(x)
	case float64:
		return int32(x)
	case float32:
		return int32(x)
	case sql.NullInt64:
		return int32(x.Int64)
	case string, goracle.Number:
		var s string
		switch x := x.(type) {
		case string:
			s = x
		case goracle.Number:
			s = string(x)
		}
		if s == "" {
			return 0
		}
		i, err := strconv.ParseInt(s, 10, 32)
		if err != nil {
			log.Printf("ERROR parsing %q as Int32", s)
		}
		return int32(i)
	default:
		log.Printf("WARN: unknown Int32 type %T", v)
	}
	return 0
}
func AsInt64(v interface{}) int64 {
	switch x := v.(type) {
	case int64:
		return x
	case int32:
		return int64(x)
	case float64:
		return int64(x)
	case float32:
		return int64(x)
	case sql.NullInt64:
		return x.Int64
	case string, goracle.Number:
		var s string
		switch x := x.(type) {
		case string:
			s = x
		case goracle.Number:
			s = string(x)
		}
		if s == "" {
			return 0
		}
		i, err := strconv.ParseInt(s, 10, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Int64", s)
		}
		return i
	default:
		log.Printf("WARN: unknown Int64 type %T", v)
	}
	return 0
}
func AsDate(v interface{}) Date {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case Date:
		return x
	case time.Time:
		return Date(x.Format(timeFormat))
	case string:
		return Date(x)
	default:
		log.Printf("WARN: unknown Date type %T", v)
	}

	return Date("")
}
<|endoftext|>