<commit_before>package main

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/blackjack/syslog"
	"github.com/boltdb/bolt"
	"github.com/satori/go.uuid"
	"golang.org/x/crypto/ssh"
)

// AUTHKEYSFILE stores the location of the ssh keys file to store newly-assigned client keys.
var AUTHKEYSFILE = os.Getenv("HOME") + "/.ssh/authorized_keys"

// CLIENTDB is the filename of the client database file.
var CLIENTDB = "clients.db"

// Debug logs a debug message to syslog.
func Debug(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_DEBUG, format, a...)
}

// Log logs a normal message to syslog.
func Log(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_NOTICE, format, a...)
}

// Warn logs a warning to syslog.
func Warn(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_WARNING, format, a...)
}

// Fatal aborts all services.
func Fatal(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_CRIT, format, a...)
	os.Exit(1)
}

// Session holds details about a remote client when serving a reauest.
type session struct {
	RemoteAddr string
	UUID       string
	Username   string
	Hostname   string
	Command    string
}

func newSession() session {
	s := session{}
	s.RemoteAddr = strings.Split(os.Getenv("SSH_CLIENT"), " ")[0]

	return s
}

func (s *session) Parse(nsCommand []string) {
	s.UUID = "nouuid"
	s.Username = "user"
	s.Hostname = "unknown"
	s.Command = strings.ToLower(nsCommand[0])

	var (
		uuidPosition     int
		usernamePosition int
		hostnamePosition int
	)

	switch s.Command {
	case "netskeldb", "addkey":
		uuidPosition = 1
		usernamePosition = 2
		hostnamePosition = 3
	case "sendfile", "sendbase64":
		uuidPosition = 2
		usernamePosition = 3
		hostnamePosition = 4
	default:
		return
	}

	if len(nsCommand) > uuidPosition {
		c, err := uuid.FromString(nsCommand[uuidPosition])
		if err != nil {
			Fatal("Unable to parse client-supplied UUID %v: %v", nsCommand[uuidPosition], err)
		} else {
			s.UUID = c.String()
		}
	}

	if len(nsCommand) > usernamePosition {
		s.Username = nsCommand[usernamePosition]
	}

	if len(nsCommand) > hostnamePosition {
		s.Hostname = nsCommand[hostnamePosition]
	}
}

func (s *session) NetskelDB() {
	servername, _ := os.Hostname()
	now := time.Now().Format("Mon, 2 Jan 2006 15:04:05 UTC")

	fmt.Printf("#\n# .netskeldb for %s at %v\n#\n# Generated %v by %v\n#\n", s.UUID, s.RemoteAddr, now, servername)

	// Force-inject the client itself
	dbDirLine("bin")
	dbFileLine("bin/netskel")

	os.Chdir("db")
	listDir(".")

	Log("Sent netskeldb to %s@%s at %s (%s)", s.Username, s.Hostname, s.RemoteAddr, s.UUID)
}

func (s *session) Heartbeat() {
	now := time.Now()
	secs := strconv.Itoa(int(now.Unix()))

	clientPut(s.UUID, "inet", s.RemoteAddr)
	clientPut(s.UUID, "lastSeen", secs)
	clientPut(s.UUID, "hostname", s.Hostname)
	clientPut(s.UUID, "username", s.Username)

	Debug("Stored heartbeat for %v", s.UUID)
}

func syntaxError() {
	fmt.Println("ERROR")
	os.Exit(1)
}

func dbFileLine(filename string) {
	file, err := os.Stat(filename)
	if err != nil {
		Warn("Error Stat %v: %v", filename, err)
		return
	}

	trimmed := strings.TrimPrefix(filename, "./")

	hash, _ := fingerprint(filename)

	mode := 0600
	if file.Mode()&0111 != 0 {
		mode = 0700
	}

	fmt.Printf("%s\t%o\t*\t%d\t%x\n", trimmed, mode, file.Size(), hash)
}

func dbDirLine(directory string) {
	trimmed := strings.TrimPrefix(directory, "./")
	fmt.Printf("%s/\t%d\t*\n", trimmed, 700)
}

func listDir(dirname string) {
	files, err := ioutil.ReadDir(dirname)
	if err != nil {
		Warn("Error reading directory %v", dirname)
		return
	}

	for _, file := range files {
		if file.Name() == ".git" {
			continue
		}

		fullname := dirname + "/" + file.Name()

		switch mode := file.Mode(); {
		case mode.IsDir():
			dbDirLine(fullname)
			listDir(fullname)
		case mode.IsRegular():
			dbFileLine(fullname)
		}
	}
}

func fingerprint(filename string) ([]byte, error) {
	var result []byte

	file, err := os.Open(filename)
	if err != nil {
		return result, err
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return result, err
	}

	return hash.Sum(result), nil
}

func (s *session) SendBase64(filename string) {
	linelength := 76
	count := 0

	file, err := ioutil.ReadFile(filename)
	if err != nil {
		Warn("Error trying to base64 %v: %v", filename, err)
		os.Exit(1)
	}

	str := base64.StdEncoding.EncodeToString(file)

	for _, c := range str {
		fmt.Printf("%c", c)
		count++
		if count >= linelength {
			count = 0
			fmt.Printf("\n")
		}
	}
	fmt.Printf("\n")

	Log("Sent base64 %s (%d bytes) to %s@%s at %s (%s)", filename, len(file), s.Username, s.Hostname, s.RemoteAddr, s.UUID)
}

func (s *session) SendHexdump(filename string) {
	linelength := 30
	count := 0

	file, err := ioutil.ReadFile(filename)
	if err != nil {
		Warn("Error trying to hexdump %v: %v", filename, err)
		os.Exit(1)
	}

	for _, c := range file {
		fmt.Printf("%02x", c)
		count++
		if count >= linelength {
			count = 0
			fmt.Printf("\n")
		}
	}
	fmt.Printf("\n")
	Log("Sent hexdump %s (%d bytes) to %s@%s at %s (%s)", filename, len(file), s.Username, s.Hostname, s.RemoteAddr, s.UUID)
}

func (s *session) SendRaw(filename string) {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		Warn("Error trying to sendRaw %v: %v", filename, err)
		os.Exit(1)
	}
	fmt.Printf("%v", string(file))
	Log("Sent raw %s (%d bytes) to %s@%s at %s (%s)", filename, len(file), s.Username, s.Hostname, s.RemoteAddr, s.UUID)
	os.Exit(0)
}

func (s *session) AddKey() {
	servername, err := os.Hostname()
	now := time.Now()
	nowFmt := now.Format("Mon Jan _2 15:04:05 2006")
	uuid, _ := uuid.NewV4()
	cuuid := uuid.String()

	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		Warn("Error generating private key: %v", err)
		os.Exit(1)
	}
	privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
	pemdata := pem.EncodeToMemory(privateKeyPEM)

	pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
	if err != nil {
		Warn("Error constructing public key: %v", err)
		os.Exit(1)
	}
	pubdata := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pub)))

	f, err := os.OpenFile(AUTHKEYSFILE, os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		Warn("Error opening %s for writing: %v", AUTHKEYSFILE, err)
		os.Exit(1)
	}

	defer f.Close()

	if _, err = f.WriteString("restrict " + pubdata + " " + s.Hostname + " " + cuuid + " " + nowFmt + "\n"); err != nil {
		panic(err)
	}

	fmt.Printf("#\n# Netskel private key generated by %v for %v (%v)\n#\n", servername, s.Hostname, s.RemoteAddr)
	fmt.Printf("# CLIENT_UUID %s\n#\n", uuid)
	fmt.Println(string(pemdata))

	secs := strconv.Itoa(int(now.Unix()))

	clientPut(cuuid, "hostname", s.Hostname)
	clientPut(cuuid, "originalHostname", s.Hostname)
	clientPut(cuuid, "created", secs)

	Log("Added %d byte public key to %s for %s@%s (%v) uuid %s", len(pubdata), AUTHKEYSFILE, s.Username, s.Hostname, s.RemoteAddr, uuid)
}

// clientPut stores a key/value in the client database.
func clientPut(uuid, key, value string) error {
	db, err := bolt.Open(CLIENTDB, 0660, &bolt.Options{Timeout: 2 * time.Second})
	if err != nil {
		return fmt.Errorf("Can't open client db: %v", err)
	}
	defer db.Close()

	berr := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(uuid))
		if err != nil {
			return fmt.Errorf("Can't create bucket for %s: %v", uuid, err)
		}

		perr := b.Put([]byte(key), []byte(value))
		return perr
	})

	if berr != nil {
		return fmt.Errorf("clientPut %v error: %v", uuid, err)
	}

	return nil
}

func main() {
	syslog.Openlog("netskel-server", syslog.LOG_PID, syslog.LOG_USER)

	s := newSession()

	if os.Args[0] != "server" {
		syntaxError()
	}

	nsCommand := strings.Split(os.Args[2], " ")
	s.Command = strings.ToLower(nsCommand[0])

	Debug("Launched from %v with %v", s.RemoteAddr, nsCommand)

	switch s.Command {
	case "netskeldb":
		s.Parse(nsCommand)
		s.Heartbeat()
		s.NetskelDB()

	case "md5":
		filename := nsCommand[1]
		hash, _ := fingerprint(filename)
		fmt.Println(hash)

	case "sendfile":
		s.Parse(nsCommand)
		filename := nsCommand[1]

		if filename == "db/bin/netskel" {
			filename = "bin/netskel"
		}

		s.SendHexdump(filename)

	case "sendbase64":
		s.Parse(nsCommand)
		filename := nsCommand[1]

		if filename == "db/bin/netskel" {
			filename = "bin/netskel"
		}

		s.SendBase64(filename)

	case "rawclient":
		filename := "bin/netskel"
		s.SendRaw(filename)

	case "addkey":
		s.Parse(nsCommand)
		s.AddKey()

	case "uname":
		s.Parse(nsCommand)
		uname := nsCommand[4]
		clientPut(s.UUID, "uname", uname)

	default:
		syntaxError()
	}

	os.Exit(0)
}
<commit_msg>Re-order functions for logical grouping<commit_after>package main

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/blackjack/syslog"
	"github.com/boltdb/bolt"
	"github.com/satori/go.uuid"
	"golang.org/x/crypto/ssh"
)

// AUTHKEYSFILE stores the location of the ssh keys file to store newly-assigned client keys.
var AUTHKEYSFILE = os.Getenv("HOME") + "/.ssh/authorized_keys"

// CLIENTDB is the filename of the client database file.
var CLIENTDB = "clients.db"

// Debug logs a debug message to syslog.
func Debug(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_DEBUG, format, a...)
}

// Log logs a normal message to syslog.
func Log(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_NOTICE, format, a...)
}

// Warn logs a warning to syslog.
func Warn(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_WARNING, format, a...)
}

// Fatal aborts all services.
func Fatal(format string, a ...interface{}) {
	syslog.Syslogf(syslog.LOG_CRIT, format, a...)
	os.Exit(1)
}

// Session holds details about a remote client when serving a reauest.
type session struct {
	RemoteAddr string
	UUID       string
	Username   string
	Hostname   string
	Command    string
}

func newSession() session {
	s := session{}
	s.RemoteAddr = strings.Split(os.Getenv("SSH_CLIENT"), " ")[0]

	return s
}

func (s *session) Parse(nsCommand []string) {
	s.UUID = "nouuid"
	s.Username = "user"
	s.Hostname = "unknown"
	s.Command = strings.ToLower(nsCommand[0])

	var (
		uuidPosition     int
		usernamePosition int
		hostnamePosition int
	)

	switch s.Command {
	case "netskeldb", "addkey":
		uuidPosition = 1
		usernamePosition = 2
		hostnamePosition = 3
	case "sendfile", "sendbase64":
		uuidPosition = 2
		usernamePosition = 3
		hostnamePosition = 4
	default:
		return
	}

	if len(nsCommand) > uuidPosition {
		c, err := uuid.FromString(nsCommand[uuidPosition])
		if err != nil {
			Fatal("Unable to parse client-supplied UUID %v: %v", nsCommand[uuidPosition], err)
		} else {
			s.UUID = c.String()
		}
	}

	if len(nsCommand) > usernamePosition {
		s.Username = nsCommand[usernamePosition]
	}

	if len(nsCommand) > hostnamePosition {
		s.Hostname = nsCommand[hostnamePosition]
	}
}

func (s *session) NetskelDB() {
	servername, _ := os.Hostname()
	now := time.Now().Format("Mon, 2 Jan 2006 15:04:05 UTC")

	fmt.Printf("#\n# .netskeldb for %s at %v\n#\n# Generated %v by %v\n#\n", s.UUID, s.RemoteAddr, now, servername)

	// Force-inject the client itself
	dbDirLine("bin")
	dbFileLine("bin/netskel")

	os.Chdir("db")
	listDir(".")

	Log("Sent netskeldb to %s@%s at %s (%s)", s.Username, s.Hostname, s.RemoteAddr, s.UUID)
}

func (s *session) Heartbeat() {
	now := time.Now()
	secs := strconv.Itoa(int(now.Unix()))

	clientPut(s.UUID, "inet", s.RemoteAddr)
	clientPut(s.UUID, "lastSeen", secs)
	clientPut(s.UUID, "hostname", s.Hostname)
	clientPut(s.UUID, "username", s.Username)

	Debug("Stored heartbeat for %v", s.UUID)
}

func syntaxError() {
	fmt.Println("ERROR")
	os.Exit(1)
}

func dbFileLine(filename string) {
	file, err := os.Stat(filename)
	if err != nil {
		Warn("Error Stat %v: %v", filename, err)
		return
	}

	trimmed := strings.TrimPrefix(filename, "./")

	hash, _ := fingerprint(filename)

	mode := 0600
	if file.Mode()&0111 != 0 {
		mode = 0700
	}

	fmt.Printf("%s\t%o\t*\t%d\t%x\n", trimmed, mode, file.Size(), hash)
}

func dbDirLine(directory string) {
	trimmed := strings.TrimPrefix(directory, "./")
	fmt.Printf("%s/\t%d\t*\n", trimmed, 700)
}

func listDir(dirname string) {
	files, err := ioutil.ReadDir(dirname)
	if err != nil {
		Warn("Error reading directory %v", dirname)
		return
	}

	for _, file := range files {
		if file.Name() == ".git" {
			continue
		}

		fullname := dirname + "/" + file.Name()

		switch mode := file.Mode(); {
		case mode.IsDir():
			dbDirLine(fullname)
			listDir(fullname)
		case mode.IsRegular():
			dbFileLine(fullname)
		}
	}
}

func (s *session) SendBase64(filename string) {
	linelength := 76
	count := 0

	file, err := ioutil.ReadFile(filename)
	if err != nil {
		Warn("Error trying to base64 %v: %v", filename, err)
		os.Exit(1)
	}

	str := base64.StdEncoding.EncodeToString(file)

	for _, c := range str {
		fmt.Printf("%c", c)
		count++
		if count >= linelength {
			count = 0
			fmt.Printf("\n")
		}
	}
	fmt.Printf("\n")

	Log("Sent base64 %s (%d bytes) to %s@%s at %s (%s)", filename, len(file), s.Username, s.Hostname, s.RemoteAddr, s.UUID)
}

func (s *session) SendHexdump(filename string) {
	linelength := 30
	count := 0

	file, err := ioutil.ReadFile(filename)
	if err != nil {
		Warn("Error trying to hexdump %v: %v", filename, err)
		os.Exit(1)
	}

	for _, c := range file {
		fmt.Printf("%02x", c)
		count++
		if count >= linelength {
			count = 0
			fmt.Printf("\n")
		}
	}
	fmt.Printf("\n")
	Log("Sent hexdump %s (%d bytes) to %s@%s at %s (%s)", filename, len(file), s.Username, s.Hostname, s.RemoteAddr, s.UUID)
}

func (s *session) SendRaw(filename string) {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		Warn("Error trying to sendRaw %v: %v", filename, err)
		os.Exit(1)
	}
	fmt.Printf("%v", string(file))
	Log("Sent raw %s (%d bytes) to %s@%s at %s (%s)", filename, len(file), s.Username, s.Hostname, s.RemoteAddr, s.UUID)
	os.Exit(0)
}

func (s *session) AddKey() {
	servername, err := os.Hostname()
	now := time.Now()
	nowFmt := now.Format("Mon Jan _2 15:04:05 2006")
	uuid, _ := uuid.NewV4()
	cuuid := uuid.String()

	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		Warn("Error generating private key: %v", err)
		os.Exit(1)
	}
	privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
	pemdata := pem.EncodeToMemory(privateKeyPEM)

	pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
	if err != nil {
		Warn("Error constructing public key: %v", err)
		os.Exit(1)
	}
	pubdata := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pub)))

	f, err := os.OpenFile(AUTHKEYSFILE, os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		Warn("Error opening %s for writing: %v", AUTHKEYSFILE, err)
		os.Exit(1)
	}

	defer f.Close()

	if _, err = f.WriteString("restrict " + pubdata + " " + s.Hostname + " " + cuuid + " " + nowFmt + "\n"); err != nil {
		panic(err)
	}

	fmt.Printf("#\n# Netskel private key generated by %v for %v (%v)\n#\n", servername, s.Hostname, s.RemoteAddr)
	fmt.Printf("# CLIENT_UUID %s\n#\n", uuid)
	fmt.Println(string(pemdata))

	secs := strconv.Itoa(int(now.Unix()))

	clientPut(cuuid, "hostname", s.Hostname)
	clientPut(cuuid, "originalHostname", s.Hostname)
	clientPut(cuuid, "created", secs)

	Log("Added %d byte public key to %s for %s@%s (%v) uuid %s", len(pubdata), AUTHKEYSFILE, s.Username, s.Hostname, s.RemoteAddr, uuid)
}

// fingerprint calculates the MD5 fingerprint of a file.
func fingerprint(filename string) ([]byte, error) {
	var result []byte

	file, err := os.Open(filename)
	if err != nil {
		return result, err
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return result, err
	}

	return hash.Sum(result), nil
}

// clientPut stores a key/value in the client database.
func clientPut(uuid, key, value string) error {
	db, err := bolt.Open(CLIENTDB, 0660, &bolt.Options{Timeout: 2 * time.Second})
	if err != nil {
		return fmt.Errorf("Can't open client db: %v", err)
	}
	defer db.Close()

	berr := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(uuid))
		if err != nil {
			return fmt.Errorf("Can't create bucket for %s: %v", uuid, err)
		}

		perr := b.Put([]byte(key), []byte(value))
		return perr
	})

	if berr != nil {
		return fmt.Errorf("clientPut %v error: %v", uuid, err)
	}

	return nil
}

func main() {
	syslog.Openlog("netskel-server", syslog.LOG_PID, syslog.LOG_USER)

	s := newSession()

	if os.Args[0] != "server" {
		syntaxError()
	}

	nsCommand := strings.Split(os.Args[2], " ")
	s.Command = strings.ToLower(nsCommand[0])

	Debug("Launched from %v with %v", s.RemoteAddr, nsCommand)

	switch s.Command {
	case "netskeldb":
		s.Parse(nsCommand)
		s.Heartbeat()
		s.NetskelDB()

	case "md5":
		filename := nsCommand[1]
		hash, _ := fingerprint(filename)
		fmt.Println(hash)

	case "sendfile":
		s.Parse(nsCommand)
		filename := nsCommand[1]

		if filename == "db/bin/netskel" {
			filename = "bin/netskel"
		}

		s.SendHexdump(filename)

	case "sendbase64":
		s.Parse(nsCommand)
		filename := nsCommand[1]

		if filename == "db/bin/netskel" {
			filename = "bin/netskel"
		}

		s.SendBase64(filename)

	case "rawclient":
		filename := "bin/netskel"
		s.SendRaw(filename)

	case "addkey":
		s.Parse(nsCommand)
		s.AddKey()

	case "uname":
		s.Parse(nsCommand)
		uname := nsCommand[4]
		clientPut(s.UUID, "uname", uname)

	default:
		syntaxError()
	}

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


<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/albertyw/reaction-pics/tumblr"
	"github.com/ikeikeikeike/go-sitemap-generator/v2/stm"
	"github.com/pkg/errors"
	"github.com/rollbar/rollbar-go"
	"go.uber.org/zap"
)

const (
	maxResults = 20
)

type metaHeader struct {
	Property string
	Content  string
}

func relToAbsPath(path string) string {
	_, filename, _, ok := runtime.Caller(0)
	if !ok {
		filename = "."
	}
	absPath := filepath.Join(filepath.Dir(filename), path)
	return absPath
}

// indexHandler is an http handler that returns the index page HTML
func indexHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	if r.URL.Path != "/" && !strings.HasPrefix(r.URL.Path, "/post/") {
		err := fmt.Errorf("file not found: %s", r.URL.Path)
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	indexHandlerWithHeaders(w, r, d, []metaHeader{})
}

func indexHandlerWithHeaders(w http.ResponseWriter, r *http.Request, d handlerDeps, headers []metaHeader) {
	path := relToAbsPath("static/index.htm")
	t, err := template.ParseFiles(path)
	if err != nil {
		err = errors.Wrap(err, "Cannot read post template")
		d.logger.Error(err)
		rollbar.RequestError(rollbar.ERR, r, err)
		http.Error(w, err.Error(), 500)
		return
	}
	templateData := struct {
		CacheString string
		MetaHeaders []metaHeader
	}{
		CacheString: d.appCacheString,
		MetaHeaders: headers,
	}
	err = t.Execute(w, templateData)
	if err != nil {
		err = errors.Wrap(err, "Cannot execute template")
		d.logger.Error(err)
		rollbar.RequestError(rollbar.ERR, r, err)
		http.Error(w, err.Error(), 500)
		return
	}
}

// searchHandler is an http handler to search data for keywords in json format
// It matches the query against post titles and then ranks posts by number of likes
func searchHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	query := r.URL.Query().Get("query")
	query = strings.TrimSpace(strings.ToLower(query))
	queriedBoard := d.board.FilterBoard([]string{query})
	if query == "" {
		queriedBoard.RandomizePosts()
	}
	offsetString := r.URL.Query().Get("offset")
	offset, err := strconv.Atoi(offsetString)
	if err != nil {
		offset = 0
	}
	data := map[string]interface{}{
		"offset":       offset,
		"totalResults": len(queriedBoard.Posts),
	}
	queriedBoard.LimitBoard(offset, maxResults)
	queriedBoard.SortPostsByLikes()
	data["data"] = queriedBoard.PostsToJSON()
	dataBytes, _ := json.Marshal(data)
	fmt.Fprint(w, string(dataBytes))
}

// postDataHandler is an http handler to return post data by ID in json format
func postDataHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	pathStrings := strings.Split(r.URL.Path, "/")
	postIDString := pathStrings[2]
	postID, err := strconv.ParseInt(postIDString, 10, 64)
	if err != nil {
		err = errors.Wrap(err, "Cannot parse post id")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	post := d.board.GetPostByID(postID)
	if post == nil {
		err = errors.New("Cannot find post")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	data := map[string]interface{}{
		"offset":       0,
		"totalResults": 1,
		"data":         []tumblr.PostJSON{post.ToJSONStruct()},
	}
	marshalledPost, _ := json.Marshal(data)
	fmt.Fprint(w, string(marshalledPost))
}

// postHandler is an http handler that validates the correctness of a post url
// and returns the index page html to render it correct
func postHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	pathStrings := strings.Split(r.URL.Path, "/")
	postIDString := pathStrings[2]
	postID, err := strconv.ParseInt(postIDString, 10, 64)
	if err != nil {
		err = errors.Wrap(err, "Cannot parse post id")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	var post *tumblr.Post
	for _, p := range d.board.Posts {
		if p.ID == postID {
			post = &p
			break
		}
	}
	if post == nil {
		err = errors.New("Cannot find post")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}

	headers := []metaHeader{
		{"og:title", post.Title},
		{"og:image", post.Image},
	}

	indexHandlerWithHeaders(w, r, d, headers)
}

// statsHandler returns internal stats about the reaction.pics DB as json
func statsHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	postCount := strconv.Itoa(len(d.board.Posts))
	data := map[string]interface{}{
		"postCount": postCount,
		"keywords":  d.board.Keywords(),
	}
	stats, _ := json.Marshal(data)
	fmt.Fprint(w, string(stats))
}

// sitemapHandler returns a sitemap of reaction.pics as an xml file
func sitemapHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	sm := stm.NewSitemap(0)
	sm.SetDefaultHost(os.Getenv("HOST"))

	sm.Create()
	sm.Add(stm.URL{{"loc", "/"}})
	for _, url := range d.board.URLs() {
		sm.Add(stm.URL{{"loc", url}})
	}
	w.Write(sm.XMLContent())
}

// staticHandler returns static files
func staticHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	staticFS := rewriteFS(http.FileServer(http.Dir(relToAbsPath("static"))).ServeHTTP)
	staticFS(w, r)
}

func timeHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	unixTime := int32(time.Now().Unix())
	data := map[string]interface{}{
		"unixtime": unixTime,
	}
	timeData, _ := json.Marshal(data)
	fmt.Fprint(w, string(timeData))
}

func faviconHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	faviconPath := relToAbsPath("static/favicon/favicon.iso")
	http.ServeFile(w, r, faviconPath)
}

func robotsTxtHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	fmt.Fprint(w, "")
}

// Run starts up the HTTP server
func Run(logger *zap.SugaredLogger) {
	board := tumblr.InitializeBoard()
	address := fmt.Sprintf(":%s", os.Getenv("PORT"))
	logger.Infof("server listening on %s", address)
	generator := newHandlerGenerator(board, logger)
	http.Handle("/", generator.newHandler(indexHandler))
	http.Handle("/favicon.ico", generator.newHandler(faviconHandler))
	http.Handle("/robots.txt", generator.newHandler(robotsTxtHandler))
	http.Handle("/search", generator.newHandler(searchHandler))
	http.Handle("/postdata/", generator.newHandler(postDataHandler))
	http.Handle("/post/", generator.newHandler(postHandler))
	http.Handle("/stats.json", generator.newHandler(statsHandler))
	http.Handle("/sitemap.xml", generator.newHandler(sitemapHandler))
	http.Handle("/static/", generator.newHandler(staticHandler))
	http.Handle("/time/", generator.newHandler(timeHandler))
	http.ListenAndServe(address, nil)
}
<commit_msg>Split queries by words and look them up individually<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/albertyw/reaction-pics/tumblr"
	"github.com/ikeikeikeike/go-sitemap-generator/v2/stm"
	"github.com/pkg/errors"
	"github.com/rollbar/rollbar-go"
	"go.uber.org/zap"
)

const (
	maxResults = 20
)

type metaHeader struct {
	Property string
	Content  string
}

func relToAbsPath(path string) string {
	_, filename, _, ok := runtime.Caller(0)
	if !ok {
		filename = "."
	}
	absPath := filepath.Join(filepath.Dir(filename), path)
	return absPath
}

// indexHandler is an http handler that returns the index page HTML
func indexHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	if r.URL.Path != "/" && !strings.HasPrefix(r.URL.Path, "/post/") {
		err := fmt.Errorf("file not found: %s", r.URL.Path)
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	indexHandlerWithHeaders(w, r, d, []metaHeader{})
}

func indexHandlerWithHeaders(w http.ResponseWriter, r *http.Request, d handlerDeps, headers []metaHeader) {
	path := relToAbsPath("static/index.htm")
	t, err := template.ParseFiles(path)
	if err != nil {
		err = errors.Wrap(err, "Cannot read post template")
		d.logger.Error(err)
		rollbar.RequestError(rollbar.ERR, r, err)
		http.Error(w, err.Error(), 500)
		return
	}
	templateData := struct {
		CacheString string
		MetaHeaders []metaHeader
	}{
		CacheString: d.appCacheString,
		MetaHeaders: headers,
	}
	err = t.Execute(w, templateData)
	if err != nil {
		err = errors.Wrap(err, "Cannot execute template")
		d.logger.Error(err)
		rollbar.RequestError(rollbar.ERR, r, err)
		http.Error(w, err.Error(), 500)
		return
	}
}

// searchHandler is an http handler to search data for keywords in json format
// It matches the query against post titles and then ranks posts by number of likes
func searchHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	query := r.URL.Query().Get("query")
	query = strings.TrimSpace(strings.ToLower(query))
	queries := strings.Split(query, " ")
	queriedBoard := d.board.FilterBoard(queries)
	if query == "" {
		queriedBoard.RandomizePosts()
	}
	offsetString := r.URL.Query().Get("offset")
	offset, err := strconv.Atoi(offsetString)
	if err != nil {
		offset = 0
	}
	data := map[string]interface{}{
		"offset":       offset,
		"totalResults": len(queriedBoard.Posts),
	}
	queriedBoard.LimitBoard(offset, maxResults)
	queriedBoard.SortPostsByLikes()
	data["data"] = queriedBoard.PostsToJSON()
	dataBytes, _ := json.Marshal(data)
	fmt.Fprint(w, string(dataBytes))
}

// postDataHandler is an http handler to return post data by ID in json format
func postDataHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	pathStrings := strings.Split(r.URL.Path, "/")
	postIDString := pathStrings[2]
	postID, err := strconv.ParseInt(postIDString, 10, 64)
	if err != nil {
		err = errors.Wrap(err, "Cannot parse post id")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	post := d.board.GetPostByID(postID)
	if post == nil {
		err = errors.New("Cannot find post")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	data := map[string]interface{}{
		"offset":       0,
		"totalResults": 1,
		"data":         []tumblr.PostJSON{post.ToJSONStruct()},
	}
	marshalledPost, _ := json.Marshal(data)
	fmt.Fprint(w, string(marshalledPost))
}

// postHandler is an http handler that validates the correctness of a post url
// and returns the index page html to render it correct
func postHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	pathStrings := strings.Split(r.URL.Path, "/")
	postIDString := pathStrings[2]
	postID, err := strconv.ParseInt(postIDString, 10, 64)
	if err != nil {
		err = errors.Wrap(err, "Cannot parse post id")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}
	var post *tumblr.Post
	for _, p := range d.board.Posts {
		if p.ID == postID {
			post = &p
			break
		}
	}
	if post == nil {
		err = errors.New("Cannot find post")
		d.logger.Warn(err)
		rollbar.RequestError(rollbar.WARN, r, err)
		http.NotFound(w, r)
		return
	}

	headers := []metaHeader{
		{"og:title", post.Title},
		{"og:image", post.Image},
	}

	indexHandlerWithHeaders(w, r, d, headers)
}

// statsHandler returns internal stats about the reaction.pics DB as json
func statsHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	postCount := strconv.Itoa(len(d.board.Posts))
	data := map[string]interface{}{
		"postCount": postCount,
		"keywords":  d.board.Keywords(),
	}
	stats, _ := json.Marshal(data)
	fmt.Fprint(w, string(stats))
}

// sitemapHandler returns a sitemap of reaction.pics as an xml file
func sitemapHandler(w http.ResponseWriter, r *http.Request, d handlerDeps) {
	sm := stm.NewSitemap(0)
	sm.SetDefaultHost(os.Getenv("HOST"))

	sm.Create()
	sm.Add(stm.URL{{"loc", "/"}})
	for _, url := range d.board.URLs() {
		sm.Add(stm.URL{{"loc", url}})
	}
	w.Write(sm.XMLContent())
}

// staticHandler returns static files
func staticHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	staticFS := rewriteFS(http.FileServer(http.Dir(relToAbsPath("static"))).ServeHTTP)
	staticFS(w, r)
}

func timeHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	unixTime := int32(time.Now().Unix())
	data := map[string]interface{}{
		"unixtime": unixTime,
	}
	timeData, _ := json.Marshal(data)
	fmt.Fprint(w, string(timeData))
}

func faviconHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	faviconPath := relToAbsPath("static/favicon/favicon.iso")
	http.ServeFile(w, r, faviconPath)
}

func robotsTxtHandler(w http.ResponseWriter, r *http.Request, _ handlerDeps) {
	fmt.Fprint(w, "")
}

// Run starts up the HTTP server
func Run(logger *zap.SugaredLogger) {
	board := tumblr.InitializeBoard()
	address := fmt.Sprintf(":%s", os.Getenv("PORT"))
	logger.Infof("server listening on %s", address)
	generator := newHandlerGenerator(board, logger)
	http.Handle("/", generator.newHandler(indexHandler))
	http.Handle("/favicon.ico", generator.newHandler(faviconHandler))
	http.Handle("/robots.txt", generator.newHandler(robotsTxtHandler))
	http.Handle("/search", generator.newHandler(searchHandler))
	http.Handle("/postdata/", generator.newHandler(postDataHandler))
	http.Handle("/post/", generator.newHandler(postHandler))
	http.Handle("/stats.json", generator.newHandler(statsHandler))
	http.Handle("/sitemap.xml", generator.newHandler(sitemapHandler))
	http.Handle("/static/", generator.newHandler(staticHandler))
	http.Handle("/time/", generator.newHandler(timeHandler))
	http.ListenAndServe(address, nil)
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "net"  //now look at this net that I just found
import "time" //time is a tool you can put on the wall or wear it on your wrist
//the past is far behind us, the future doesn't exist
import "./players"

func getPlayerOfIp(ip string) players.NetworkPlayer {
	for _, plr := range networkPlayerList {
		if plr.GetIp() == ip {
			return plr
		}
	}
	return nil
}

func handleConn1(conn net.Conn) {
	fmt.Println("conn 1")
	plr := getPlayerOfIp(conn.RemoteAddr().String())
	for len(plr.GetDataToBeSent()) == 0 {
		time.Sleep(time.Second / 2)
	}
	_, err := conn.Write(plr.GetDataToBeSent()[0])
	if err == nil {
		plr.RemoveASentData()
	}
}

func handleConn2(conn net.Conn) {
	fmt.Println("conn 2")
	var chat []byte
	_, err := conn.Read(chat)
	if err != nil {
		return
	}
	chat = append([]byte("CHAT"), chat...)
	plr := getPlayerOfIp(conn.RemoteAddr().String())
	for _, plr2 := range networkPlayerList {
		if plr2 != plr {
			plr2.SendData(chat)
		}
	}
}

func serverFunc(quitChan chan struct{}) {
	ln1, _ := net.Listen("tcp", ":5252") //event listeners
	ln2, _ := net.Listen("tcp", ":6565") //chat
	for {
		select {
		case <-quitChan:
			console.log("65")
			return
		default:
			conn1, _ := ln1.Accept()
			go handleConn1(conn1)
			conn2, _ := ln2.Accept()
			go handleConn2(conn2)
		}
	}
}
<commit_msg>aaaaaa<commit_after>package main

import "fmt"
import "net"  //now look at this net that I just found
import "time" //time is a tool you can put on the wall or wear it on your wrist
//the past is far behind us, the future doesn't exist
import "./players"

func getPlayerOfIp(ip string) players.NetworkPlayer {
	for _, plr := range networkPlayerList {
		if plr.GetIp() == ip {
			return plr
		}
	}
	return nil
}

func handleConn1(conn net.Conn) {
	fmt.Println("conn 1")
	plr := getPlayerOfIp(conn.RemoteAddr().String())
	for len(plr.GetDataToBeSent()) == 0 {
		time.Sleep(time.Second / 2)
	}
	_, err := conn.Write(plr.GetDataToBeSent()[0])
	if err == nil {
		plr.RemoveASentData()
	}
}

func handleConn2(conn net.Conn) {
	fmt.Println("conn 2")
	var chat []byte
	_, err := conn.Read(chat)
	if err != nil {
		return
	}
	chat = append([]byte("CHAT"), chat...)
	plr := getPlayerOfIp(conn.RemoteAddr().String())
	for _, plr2 := range networkPlayerList {
		if plr2 != plr {
			plr2.SendData(chat)
		}
	}
}

func serverFunc(quitChan chan struct{}) {
	ln1, _ := net.Listen("tcp", ":5252") //event listeners
	ln2, _ := net.Listen("tcp", ":6565") //chat
	for {
		select {
		case <-quitChan:
			fmt.Println("65")
			return
		default:
			conn1, _ := ln1.Accept()
			go handleConn1(conn1)
			conn2, _ := ln2.Accept()
			go handleConn2(conn2)
		}
	}
}
<|endoftext|>


<commit_before>package repos

import (
	"log"
	"time"

	"github.com/khades/servbot/models"
	"gopkg.in/mgo.v2/bson"
)

var autoMessageCollectionName = "autoMessages"

func DecrementAutoMessages(channelID *string) {
	channelInfo, error := GetChannelInfo(channelID)
	games := []string{""}
	if error == nil && channelInfo.StreamStatus.Online == true {
		games = append(games, channelInfo.StreamStatus.Game)
	}
	Db.C(autoMessageCollectionName).UpdateAll(bson.M{
		"channelid": *channelID,
		"message":   bson.M{"$ne": ""},
		"$or": []bson.M{
			bson.M{"game": bson.M{"$in": games}},
			bson.M{"game": bson.M{"$exists": false}}}},
		bson.M{"$inc": bson.M{"messagethreshold": -1}})
}

func GetCurrentAutoMessages() (*[]models.AutoMessage, error) {
	//log.Println("AutoMessage: Getting Current AutoMessages")
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{
		"message":           bson.M{"$ne": ""},
		"messagethreshold":  bson.M{"$lte": 0},
		"durationthreshold": bson.M{"$lte": time.Now()}}).All(&result)
	log.Printf("AutoMessage: Got %d AutoMessages", len(result))
	//log.Println(error)
	return &result, error
}

func ResetAutoMessageThreshold(autoMessage *models.AutoMessage) {
	log.Printf("AutoMessage: Resetting AutoMessage %s", autoMessage.ID)
	now := time.Now()
	Db.C(autoMessageCollectionName).Update(bson.M{"_id": autoMessage.ID}, bson.M{"$set": bson.M{
		"messagethreshold":  autoMessage.MessageLimit,
		"durationthreshold": now.Add(autoMessage.DurationLimit)}})
}

func GetAutoMessage(id *string, channelID *string) (*models.AutoMessageWithHistory, error) {
	var result models.AutoMessageWithHistory
	objectID := bson.ObjectIdHex(*id)
	error := Db.C(autoMessageCollectionName).Find(bson.M{"_id": objectID, "channelid": *channelID}).One(&result)
	return &result, error
}

func GetAutoMessages(channelID *string) (*[]models.AutoMessage, error) {
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{"channelid": *channelID}).All(&result)
	return &result, error
}
func CreateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) *bson.ObjectId {
	id := bson.NewObjectId()
	now := time.Now()
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Insert(
		models.AutoMessageWithHistory{
			AutoMessage: models.AutoMessage{
				ID:                id,
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)},
			History: []models.AutoMessageHistory{
				models.AutoMessageHistory{
					User:   autoMessageUpdate.User,
					UserID: autoMessageUpdate.UserID,

					Date:          now,
					Message:       autoMessageUpdate.Message,
					MessageLimit:  autoMessageUpdate.MessageLimit,
					DurationLimit: durationLimit}}})
	return &id
}

func UpdateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) {
	now := time.Now()
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Update(
		bson.M{"_id": bson.ObjectIdHex(autoMessageUpdate.ID), "channelid": autoMessageUpdate.ChannelID},
		bson.M{
			"$push": bson.M{
				"history": bson.M{
					"$each": []models.AutoMessageHistory{models.AutoMessageHistory{
						User:          autoMessageUpdate.User,
						UserID:        autoMessageUpdate.UserID,
						Game:          autoMessageUpdate.Game,
						Date:          now,
						Message:       autoMessageUpdate.Message,
						MessageLimit:  autoMessageUpdate.MessageLimit,
						DurationLimit: durationLimit}},
					"$sort":  bson.M{"date": -1},
					"$slice": 5}},

			"$set": models.AutoMessage{
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)}})

}
<commit_msg>Feature: automessages during specific game<commit_after>package repos

import (
	"log"
	"time"

	"github.com/khades/servbot/models"
	"gopkg.in/mgo.v2/bson"
)

var autoMessageCollectionName = "autoMessages"

func DecrementAutoMessages(channelID *string) {
	channelInfo, error := GetChannelInfo(channelID)
	games := []string{""}
	if error == nil && channelInfo.StreamStatus.Online == true {
		games = append(games, channelInfo.StreamStatus.Game)
	}
	Db.C(autoMessageCollectionName).UpdateAll(bson.M{
		"channelid": *channelID,
		"message":   bson.M{"$ne": ""},
		"$or": []bson.M{
			bson.M{"game": bson.M{"$in": games}},
			bson.M{"game": bson.M{"$exists": false}}}},
		bson.M{"$inc": bson.M{"messagethreshold": -1}})
}

func GetCurrentAutoMessages() (*[]models.AutoMessage, error) {
	//log.Println("AutoMessage: Getting Current AutoMessages")
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{
		"message":           bson.M{"$ne": ""},
		"messagethreshold":  bson.M{"$lte": 0},
		"durationthreshold": bson.M{"$lte": time.Now()}}).All(&result)
	log.Printf("AutoMessage: Got %d AutoMessages", len(result))
	//log.Println(error)
	return &result, error
}

func ResetAutoMessageThreshold(autoMessage *models.AutoMessage) {
	log.Printf("AutoMessage: Resetting AutoMessage %s", autoMessage.ID)
	now := time.Now()
	Db.C(autoMessageCollectionName).Update(bson.M{"_id": autoMessage.ID}, bson.M{"$set": bson.M{
		"messagethreshold":  autoMessage.MessageLimit,
		"durationthreshold": now.Add(autoMessage.DurationLimit)}})
}

func GetAutoMessage(id *string, channelID *string) (*models.AutoMessageWithHistory, error) {
	var result models.AutoMessageWithHistory
	objectID := bson.ObjectIdHex(*id)
	error := Db.C(autoMessageCollectionName).Find(bson.M{"_id": objectID, "channelid": *channelID}).One(&result)
	return &result, error
}

func GetAutoMessages(channelID *string) (*[]models.AutoMessage, error) {
	var result []models.AutoMessage
	error := Db.C(autoMessageCollectionName).Find(bson.M{"channelid": *channelID}).All(&result)
	return &result, error
}
func CreateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) *bson.ObjectId {
	id := bson.NewObjectId()
	now := time.Now()
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Insert(
		models.AutoMessageWithHistory{
			AutoMessage: models.AutoMessage{
				ID:                id,
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)},
			History: []models.AutoMessageHistory{
				models.AutoMessageHistory{
					User:          autoMessageUpdate.User,
					UserID:        autoMessageUpdate.UserID,
					Game:          autoMessageUpdate.Game,
					Date:          now,
					Message:       autoMessageUpdate.Message,
					MessageLimit:  autoMessageUpdate.MessageLimit,
					DurationLimit: durationLimit}}})
	return &id
}

func UpdateAutoMessage(autoMessageUpdate *models.AutoMessageUpdate) {
	now := time.Now()
	var durationLimit = time.Second * time.Duration(autoMessageUpdate.DurationLimit)
	Db.C(autoMessageCollectionName).Update(
		bson.M{"_id": bson.ObjectIdHex(autoMessageUpdate.ID), "channelid": autoMessageUpdate.ChannelID},
		bson.M{
			"$push": bson.M{
				"history": bson.M{
					"$each": []models.AutoMessageHistory{models.AutoMessageHistory{
						User:          autoMessageUpdate.User,
						UserID:        autoMessageUpdate.UserID,
						Game:          autoMessageUpdate.Game,
						Date:          now,
						Message:       autoMessageUpdate.Message,
						MessageLimit:  autoMessageUpdate.MessageLimit,
						DurationLimit: durationLimit}},
					"$sort":  bson.M{"date": -1},
					"$slice": 5}},

			"$set": models.AutoMessage{
				ChannelID:         autoMessageUpdate.ChannelID,
				Message:           autoMessageUpdate.Message,
				MessageThreshold:  autoMessageUpdate.MessageLimit,
				MessageLimit:      autoMessageUpdate.MessageLimit,
				Game:              autoMessageUpdate.Game,
				DurationLimit:     durationLimit,
				DurationThreshold: now.Add(durationLimit)}})

}
<|endoftext|>


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

// +build js,wasm

// Package js gives access to the WebAssembly host environment when using the js/wasm architecture.
// Its API is based on JavaScript semantics.
//
// This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a
// comprehensive API for users. It is exempt from the Go compatibility promise.
package js

import (
	"unsafe"
)

// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly.
//
// The JavaScript value "undefined" is represented by the value 0.
// A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation.
// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as
// an ID and bits 32-33 used to differentiate between string, symbol, function and object.
type ref uint64

// nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above).
const nanHead = 0x7FF80000

// Wrapper is implemented by types that are backed by a JavaScript value.
type Wrapper interface {
	// JSValue returns a JavaScript value associated with an object.
	JSValue() Value
}

// Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
type Value struct {
	ref ref
}

// JSValue implements Wrapper interface.
func (v Value) JSValue() Value {
	return v
}

func makeValue(v ref) Value {
	return Value{ref: v}
}

func predefValue(id uint32) Value {
	return Value{ref: nanHead<<32 | ref(id)}
}

func floatValue(f float64) Value {
	if f == 0 {
		return valueZero
	}
	if f != f {
		return valueNaN
	}
	return Value{ref: *(*ref)(unsafe.Pointer(&f))}
}

// Error wraps a JavaScript error.
type Error struct {
	// Value is the underlying JavaScript error value.
	Value
}

// Error implements the error interface.
func (e Error) Error() string {
	return "JavaScript error: " + e.Get("message").String()
}

var (
	valueUndefined = Value{ref: 0}
	valueNaN       = predefValue(0)
	valueZero      = predefValue(1)
	valueNull      = predefValue(2)
	valueTrue      = predefValue(3)
	valueFalse     = predefValue(4)
	valueGlobal    = predefValue(5)
	memory         = predefValue(6) // WebAssembly linear memory
	jsGo           = predefValue(7) // instance of the Go class in JavaScript

	objectConstructor = valueGlobal.Get("Object")
	arrayConstructor  = valueGlobal.Get("Array")
)

// Undefined returns the JavaScript value "undefined".
func Undefined() Value {
	return valueUndefined
}

// Null returns the JavaScript value "null".
func Null() Value {
	return valueNull
}

// Global returns the JavaScript global object, usually "window" or "global".
func Global() Value {
	return valueGlobal
}

// ValueOf returns x as a JavaScript value:
//
//  | Go                     | JavaScript             |
//  | ---------------------- | ---------------------- |
//  | js.Value               | [its value]            |
//  | js.TypedArray          | typed array            |
//  | js.Callback            | function               |
//  | nil                    | null                   |
//  | bool                   | boolean                |
//  | integers and floats    | number                 |
//  | string                 | string                 |
//  | []interface{}          | new array              |
//  | map[string]interface{} | new object             |
func ValueOf(x interface{}) Value {
	switch x := x.(type) {
	case Value: // should precede Wrapper to avoid a loop
		return x
	case Wrapper:
		return x.JSValue()
	case nil:
		return valueNull
	case bool:
		if x {
			return valueTrue
		} else {
			return valueFalse
		}
	case int:
		return floatValue(float64(x))
	case int8:
		return floatValue(float64(x))
	case int16:
		return floatValue(float64(x))
	case int32:
		return floatValue(float64(x))
	case int64:
		return floatValue(float64(x))
	case uint:
		return floatValue(float64(x))
	case uint8:
		return floatValue(float64(x))
	case uint16:
		return floatValue(float64(x))
	case uint32:
		return floatValue(float64(x))
	case uint64:
		return floatValue(float64(x))
	case uintptr:
		return floatValue(float64(x))
	case unsafe.Pointer:
		return floatValue(float64(uintptr(x)))
	case float32:
		return floatValue(float64(x))
	case float64:
		return floatValue(x)
	case string:
		return makeValue(stringVal(x))
	case []interface{}:
		a := arrayConstructor.New(len(x))
		for i, s := range x {
			a.SetIndex(i, s)
		}
		return a
	case map[string]interface{}:
		o := objectConstructor.New()
		for k, v := range x {
			o.Set(k, v)
		}
		return o
	default:
		panic("ValueOf: invalid value")
	}
}

func stringVal(x string) ref

// Type represents the JavaScript type of a Value.
type Type int

const (
	TypeUndefined Type = iota
	TypeNull
	TypeBoolean
	TypeNumber
	TypeString
	TypeSymbol
	TypeObject
	TypeFunction
)

func (t Type) String() string {
	switch t {
	case TypeUndefined:
		return "undefined"
	case TypeNull:
		return "null"
	case TypeBoolean:
		return "boolean"
	case TypeNumber:
		return "number"
	case TypeString:
		return "string"
	case TypeSymbol:
		return "symbol"
	case TypeObject:
		return "object"
	case TypeFunction:
		return "function"
	default:
		panic("bad type")
	}
}

// Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator,
// except that it returns TypeNull instead of TypeObject for null.
func (v Value) Type() Type {
	switch v.ref {
	case valueUndefined.ref:
		return TypeUndefined
	case valueNull.ref:
		return TypeNull
	case valueTrue.ref, valueFalse.ref:
		return TypeBoolean
	}
	if v.isNumber() {
		return TypeNumber
	}
	typeFlag := v.ref >> 32 & 3
	switch typeFlag {
	case 1:
		return TypeString
	case 2:
		return TypeSymbol
	case 3:
		return TypeFunction
	default:
		return TypeObject
	}
}

// Get returns the JavaScript property p of value v.
func (v Value) Get(p string) Value {
	return makeValue(valueGet(v.ref, p))
}

func valueGet(v ref, p string) ref

// Set sets the JavaScript property p of value v to ValueOf(x).
func (v Value) Set(p string, x interface{}) {
	valueSet(v.ref, p, ValueOf(x).ref)
}

func valueSet(v ref, p string, x ref)

// Index returns JavaScript index i of value v.
func (v Value) Index(i int) Value {
	return makeValue(valueIndex(v.ref, i))
}

func valueIndex(v ref, i int) ref

// SetIndex sets the JavaScript index i of value v to ValueOf(x).
func (v Value) SetIndex(i int, x interface{}) {
	valueSetIndex(v.ref, i, ValueOf(x).ref)
}

func valueSetIndex(v ref, i int, x ref)

func makeArgs(args []interface{}) []ref {
	argVals := make([]ref, len(args))
	for i, arg := range args {
		argVals[i] = ValueOf(arg).ref
	}
	return argVals
}

// Length returns the JavaScript property "length" of v.
func (v Value) Length() int {
	return valueLength(v.ref)
}

func valueLength(v ref) int

// Call does a JavaScript call to the method m of value v with the given arguments.
// It panics if v has no method m.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Call(m string, args ...interface{}) Value {
	res, ok := valueCall(v.ref, m, makeArgs(args))
	if !ok {
		if vType := v.Type(); vType != TypeObject && vType != TypeFunction { // check here to avoid overhead in success case
			panic(&ValueError{"Value.Call", vType})
		}
		if propType := v.Get(m).Type(); propType != TypeFunction {
			panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String())
		}
		panic(Error{makeValue(res)})
	}
	return makeValue(res)
}

func valueCall(v ref, m string, args []ref) (ref, bool)

// Invoke does a JavaScript call of the value v with the given arguments.
// It panics if v is not a function.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Invoke(args ...interface{}) Value {
	res, ok := valueInvoke(v.ref, makeArgs(args))
	if !ok {
		if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case
			panic(&ValueError{"Value.Invoke", vType})
		}
		panic(Error{makeValue(res)})
	}
	return makeValue(res)
}

func valueInvoke(v ref, args []ref) (ref, bool)

// New uses JavaScript's "new" operator with value v as constructor and the given arguments.
// It panics if v is not a function.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) New(args ...interface{}) Value {
	res, ok := valueNew(v.ref, makeArgs(args))
	if !ok {
		panic(Error{makeValue(res)})
	}
	return makeValue(res)
}

func valueNew(v ref, args []ref) (ref, bool)

func (v Value) isNumber() bool {
	return v.ref == valueZero.ref ||
		v.ref == valueNaN.ref ||
		(v.ref != valueUndefined.ref && v.ref>>32&nanHead != nanHead)
}

func (v Value) float(method string) float64 {
	if !v.isNumber() {
		panic(&ValueError{method, v.Type()})
	}
	if v.ref == valueZero.ref {
		return 0
	}
	return *(*float64)(unsafe.Pointer(&v.ref))
}

// Float returns the value v as a float64. It panics if v is not a JavaScript number.
func (v Value) Float() float64 {
	return v.float("Value.Float")
}

// Int returns the value v truncated to an int. It panics if v is not a JavaScript number.
func (v Value) Int() int {
	return int(v.float("Value.Int"))
}

// Bool returns the value v as a bool. It panics if v is not a JavaScript boolean.
func (v Value) Bool() bool {
	switch v.ref {
	case valueTrue.ref:
		return true
	case valueFalse.ref:
		return false
	default:
		panic(&ValueError{"Value.Bool", v.Type()})
	}
}

// Truthy returns the JavaScript "truthiness" of the value v. In JavaScript,
// false, 0, "", null, undefined, and NaN are "falsy", and everything else is
// "truthy". See https://developer.mozilla.org/en-US/docs/Glossary/Truthy.
func (v Value) Truthy() bool {
	switch v.Type() {
	case TypeUndefined, TypeNull:
		return false
	case TypeBoolean:
		return v.Bool()
	case TypeNumber:
		return v.ref != valueNaN.ref && v.ref != valueZero.ref
	case TypeString:
		return v.String() != ""
	case TypeSymbol, TypeFunction, TypeObject:
		return true
	default:
		panic("bad type")
	}
}

// String returns the value v converted to string according to JavaScript type conversions.
func (v Value) String() string {
	str, length := valuePrepareString(v.ref)
	b := make([]byte, length)
	valueLoadString(str, b)
	return string(b)
}

func valuePrepareString(v ref) (ref, int)

func valueLoadString(v ref, b []byte)

// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator.
func (v Value) InstanceOf(t Value) bool {
	return valueInstanceOf(v.ref, t.ref)
}

func valueInstanceOf(v ref, t ref) bool

// A ValueError occurs when a Value method is invoked on
// a Value that does not support it. Such cases are documented
// in the description of each method.
type ValueError struct {
	Method string
	Type   Type
}

func (e *ValueError) Error() string {
	return "syscall/js: call of " + e.Method + " on " + e.Type.String()
}
<commit_msg>syscall/js: document ValueOf() panic<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build js,wasm

// Package js gives access to the WebAssembly host environment when using the js/wasm architecture.
// Its API is based on JavaScript semantics.
//
// This package is EXPERIMENTAL. Its current scope is only to allow tests to run, but not yet to provide a
// comprehensive API for users. It is exempt from the Go compatibility promise.
package js

import (
	"unsafe"
)

// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly.
//
// The JavaScript value "undefined" is represented by the value 0.
// A JavaScript number (64-bit float, except 0 and NaN) is represented by its IEEE 754 binary representation.
// All other values are represented as an IEEE 754 binary representation of NaN with bits 0-31 used as
// an ID and bits 32-33 used to differentiate between string, symbol, function and object.
type ref uint64

// nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above).
const nanHead = 0x7FF80000

// Wrapper is implemented by types that are backed by a JavaScript value.
type Wrapper interface {
	// JSValue returns a JavaScript value associated with an object.
	JSValue() Value
}

// Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
type Value struct {
	ref ref
}

// JSValue implements Wrapper interface.
func (v Value) JSValue() Value {
	return v
}

func makeValue(v ref) Value {
	return Value{ref: v}
}

func predefValue(id uint32) Value {
	return Value{ref: nanHead<<32 | ref(id)}
}

func floatValue(f float64) Value {
	if f == 0 {
		return valueZero
	}
	if f != f {
		return valueNaN
	}
	return Value{ref: *(*ref)(unsafe.Pointer(&f))}
}

// Error wraps a JavaScript error.
type Error struct {
	// Value is the underlying JavaScript error value.
	Value
}

// Error implements the error interface.
func (e Error) Error() string {
	return "JavaScript error: " + e.Get("message").String()
}

var (
	valueUndefined = Value{ref: 0}
	valueNaN       = predefValue(0)
	valueZero      = predefValue(1)
	valueNull      = predefValue(2)
	valueTrue      = predefValue(3)
	valueFalse     = predefValue(4)
	valueGlobal    = predefValue(5)
	memory         = predefValue(6) // WebAssembly linear memory
	jsGo           = predefValue(7) // instance of the Go class in JavaScript

	objectConstructor = valueGlobal.Get("Object")
	arrayConstructor  = valueGlobal.Get("Array")
)

// Undefined returns the JavaScript value "undefined".
func Undefined() Value {
	return valueUndefined
}

// Null returns the JavaScript value "null".
func Null() Value {
	return valueNull
}

// Global returns the JavaScript global object, usually "window" or "global".
func Global() Value {
	return valueGlobal
}

// ValueOf returns x as a JavaScript value:
//
//  | Go                     | JavaScript             |
//  | ---------------------- | ---------------------- |
//  | js.Value               | [its value]            |
//  | js.TypedArray          | typed array            |
//  | js.Callback            | function               |
//  | nil                    | null                   |
//  | bool                   | boolean                |
//  | integers and floats    | number                 |
//  | string                 | string                 |
//  | []interface{}          | new array              |
//  | map[string]interface{} | new object             |
//
// Panics if x is not one of the expected types.
func ValueOf(x interface{}) Value {
	switch x := x.(type) {
	case Value: // should precede Wrapper to avoid a loop
		return x
	case Wrapper:
		return x.JSValue()
	case nil:
		return valueNull
	case bool:
		if x {
			return valueTrue
		} else {
			return valueFalse
		}
	case int:
		return floatValue(float64(x))
	case int8:
		return floatValue(float64(x))
	case int16:
		return floatValue(float64(x))
	case int32:
		return floatValue(float64(x))
	case int64:
		return floatValue(float64(x))
	case uint:
		return floatValue(float64(x))
	case uint8:
		return floatValue(float64(x))
	case uint16:
		return floatValue(float64(x))
	case uint32:
		return floatValue(float64(x))
	case uint64:
		return floatValue(float64(x))
	case uintptr:
		return floatValue(float64(x))
	case unsafe.Pointer:
		return floatValue(float64(uintptr(x)))
	case float32:
		return floatValue(float64(x))
	case float64:
		return floatValue(x)
	case string:
		return makeValue(stringVal(x))
	case []interface{}:
		a := arrayConstructor.New(len(x))
		for i, s := range x {
			a.SetIndex(i, s)
		}
		return a
	case map[string]interface{}:
		o := objectConstructor.New()
		for k, v := range x {
			o.Set(k, v)
		}
		return o
	default:
		panic("ValueOf: invalid value")
	}
}

func stringVal(x string) ref

// Type represents the JavaScript type of a Value.
type Type int

const (
	TypeUndefined Type = iota
	TypeNull
	TypeBoolean
	TypeNumber
	TypeString
	TypeSymbol
	TypeObject
	TypeFunction
)

func (t Type) String() string {
	switch t {
	case TypeUndefined:
		return "undefined"
	case TypeNull:
		return "null"
	case TypeBoolean:
		return "boolean"
	case TypeNumber:
		return "number"
	case TypeString:
		return "string"
	case TypeSymbol:
		return "symbol"
	case TypeObject:
		return "object"
	case TypeFunction:
		return "function"
	default:
		panic("bad type")
	}
}

// Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator,
// except that it returns TypeNull instead of TypeObject for null.
func (v Value) Type() Type {
	switch v.ref {
	case valueUndefined.ref:
		return TypeUndefined
	case valueNull.ref:
		return TypeNull
	case valueTrue.ref, valueFalse.ref:
		return TypeBoolean
	}
	if v.isNumber() {
		return TypeNumber
	}
	typeFlag := v.ref >> 32 & 3
	switch typeFlag {
	case 1:
		return TypeString
	case 2:
		return TypeSymbol
	case 3:
		return TypeFunction
	default:
		return TypeObject
	}
}

// Get returns the JavaScript property p of value v.
func (v Value) Get(p string) Value {
	return makeValue(valueGet(v.ref, p))
}

func valueGet(v ref, p string) ref

// Set sets the JavaScript property p of value v to ValueOf(x).
func (v Value) Set(p string, x interface{}) {
	valueSet(v.ref, p, ValueOf(x).ref)
}

func valueSet(v ref, p string, x ref)

// Index returns JavaScript index i of value v.
func (v Value) Index(i int) Value {
	return makeValue(valueIndex(v.ref, i))
}

func valueIndex(v ref, i int) ref

// SetIndex sets the JavaScript index i of value v to ValueOf(x).
func (v Value) SetIndex(i int, x interface{}) {
	valueSetIndex(v.ref, i, ValueOf(x).ref)
}

func valueSetIndex(v ref, i int, x ref)

func makeArgs(args []interface{}) []ref {
	argVals := make([]ref, len(args))
	for i, arg := range args {
		argVals[i] = ValueOf(arg).ref
	}
	return argVals
}

// Length returns the JavaScript property "length" of v.
func (v Value) Length() int {
	return valueLength(v.ref)
}

func valueLength(v ref) int

// Call does a JavaScript call to the method m of value v with the given arguments.
// It panics if v has no method m.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Call(m string, args ...interface{}) Value {
	res, ok := valueCall(v.ref, m, makeArgs(args))
	if !ok {
		if vType := v.Type(); vType != TypeObject && vType != TypeFunction { // check here to avoid overhead in success case
			panic(&ValueError{"Value.Call", vType})
		}
		if propType := v.Get(m).Type(); propType != TypeFunction {
			panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String())
		}
		panic(Error{makeValue(res)})
	}
	return makeValue(res)
}

func valueCall(v ref, m string, args []ref) (ref, bool)

// Invoke does a JavaScript call of the value v with the given arguments.
// It panics if v is not a function.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Invoke(args ...interface{}) Value {
	res, ok := valueInvoke(v.ref, makeArgs(args))
	if !ok {
		if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case
			panic(&ValueError{"Value.Invoke", vType})
		}
		panic(Error{makeValue(res)})
	}
	return makeValue(res)
}

func valueInvoke(v ref, args []ref) (ref, bool)

// New uses JavaScript's "new" operator with value v as constructor and the given arguments.
// It panics if v is not a function.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) New(args ...interface{}) Value {
	res, ok := valueNew(v.ref, makeArgs(args))
	if !ok {
		panic(Error{makeValue(res)})
	}
	return makeValue(res)
}

func valueNew(v ref, args []ref) (ref, bool)

func (v Value) isNumber() bool {
	return v.ref == valueZero.ref ||
		v.ref == valueNaN.ref ||
		(v.ref != valueUndefined.ref && v.ref>>32&nanHead != nanHead)
}

func (v Value) float(method string) float64 {
	if !v.isNumber() {
		panic(&ValueError{method, v.Type()})
	}
	if v.ref == valueZero.ref {
		return 0
	}
	return *(*float64)(unsafe.Pointer(&v.ref))
}

// Float returns the value v as a float64. It panics if v is not a JavaScript number.
func (v Value) Float() float64 {
	return v.float("Value.Float")
}

// Int returns the value v truncated to an int. It panics if v is not a JavaScript number.
func (v Value) Int() int {
	return int(v.float("Value.Int"))
}

// Bool returns the value v as a bool. It panics if v is not a JavaScript boolean.
func (v Value) Bool() bool {
	switch v.ref {
	case valueTrue.ref:
		return true
	case valueFalse.ref:
		return false
	default:
		panic(&ValueError{"Value.Bool", v.Type()})
	}
}

// Truthy returns the JavaScript "truthiness" of the value v. In JavaScript,
// false, 0, "", null, undefined, and NaN are "falsy", and everything else is
// "truthy". See https://developer.mozilla.org/en-US/docs/Glossary/Truthy.
func (v Value) Truthy() bool {
	switch v.Type() {
	case TypeUndefined, TypeNull:
		return false
	case TypeBoolean:
		return v.Bool()
	case TypeNumber:
		return v.ref != valueNaN.ref && v.ref != valueZero.ref
	case TypeString:
		return v.String() != ""
	case TypeSymbol, TypeFunction, TypeObject:
		return true
	default:
		panic("bad type")
	}
}

// String returns the value v converted to string according to JavaScript type conversions.
func (v Value) String() string {
	str, length := valuePrepareString(v.ref)
	b := make([]byte, length)
	valueLoadString(str, b)
	return string(b)
}

func valuePrepareString(v ref) (ref, int)

func valueLoadString(v ref, b []byte)

// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator.
func (v Value) InstanceOf(t Value) bool {
	return valueInstanceOf(v.ref, t.ref)
}

func valueInstanceOf(v ref, t ref) bool

// A ValueError occurs when a Value method is invoked on
// a Value that does not support it. Such cases are documented
// in the description of each method.
type ValueError struct {
	Method string
	Type   Type
}

func (e *ValueError) Error() string {
	return "syscall/js: call of " + e.Method + " on " + e.Type.String()
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mapper

import (
	"github.com/ernestio/aws-definition-mapper/definition"
	"github.com/ernestio/aws-definition-mapper/output"
)

// MapNats : Generates necessary nats rules for input networks
func MapNats(d definition.Definition) []output.Nat {
	var nats []output.Nat

	for _, ng := range d.NatGateways {
		nws := mapNetworkNames(d, ng.Name)

		nats = append(nats, output.Nat{
			Name:                d.GeneratedName() + ng.Name,
			NatType:             "$(datacenters.items.0.type)",
			PublicNetwork:       d.GeneratedName() + ng.PublicNetwork,
			RoutedNetworks:      nws,
			PublicNetworkAWSID:  `$(networks.items.#[name="` + ng.PublicNetwork + `"].network_aws_id)`,
			RoutedNetworkAWSIDs: mapNatNetworkIDs(nws),
			DatacenterType:      "$(datacenters.items.0.type)",
			DatacenterName:      "$(datacenters.items.0.name)",
			DatacenterSecret:    "$(datacenters.items.0.secret)",
			DatacenterToken:     "$(datacenters.items.0.token)",
			DatacenterRegion:    "$(datacenters.items.0.region)",
			VpcID:               "$(vpcs.items.0.vpc_id)",
		})

	}

	return nats
}

func mapNatNetworkIDs(nws []string) []string {
	var ids []string

	for _, nw := range nws {
		ids = append(ids, `$(networks.items.#[name="`+nw+`"].network_aws_id)`)
	}

	return ids
}

func mapNetworkNames(d definition.Definition, name string) []string {
	var nws []string
	for _, network := range d.Networks {
		if network.NatGateway == name {
			nws = append(nws, d.GeneratedName()+network.Name)
		}
	}

	return nws
}
<commit_msg>adding prefix to template variable when mapping networkids for nats<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mapper

import (
	"github.com/ernestio/aws-definition-mapper/definition"
	"github.com/ernestio/aws-definition-mapper/output"
)

// MapNats : Generates necessary nats rules for input networks
func MapNats(d definition.Definition) []output.Nat {
	var nats []output.Nat

	for _, ng := range d.NatGateways {
		nws := mapNetworkNames(d, ng.Name)

		nats = append(nats, output.Nat{
			Name:                d.GeneratedName() + ng.Name,
			NatType:             "$(datacenters.items.0.type)",
			PublicNetwork:       d.GeneratedName() + ng.PublicNetwork,
			RoutedNetworks:      nws,
			PublicNetworkAWSID:  `$(networks.items.#[name="` + d.GeneratedName() + ng.PublicNetwork + `"].network_aws_id)`,
			RoutedNetworkAWSIDs: mapNatNetworkIDs(nws, d.GeneratedName()),
			DatacenterType:      "$(datacenters.items.0.type)",
			DatacenterName:      "$(datacenters.items.0.name)",
			DatacenterSecret:    "$(datacenters.items.0.secret)",
			DatacenterToken:     "$(datacenters.items.0.token)",
			DatacenterRegion:    "$(datacenters.items.0.region)",
			VpcID:               "$(vpcs.items.0.vpc_id)",
		})

	}

	return nats
}

func mapNatNetworkIDs(nws []string, prefix string) []string {
	var ids []string

	for _, nw := range nws {
		ids = append(ids, `$(networks.items.#[name="`+prefix+nw+`"].network_aws_id)`)
	}

	return ids
}

func mapNetworkNames(d definition.Definition, name string) []string {
	var nws []string
	for _, network := range d.Networks {
		if network.NatGateway == name {
			nws = append(nws, d.GeneratedName()+network.Name)
		}
	}

	return nws
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"strings"

	"io/ioutil"
)

func Typescript(dir string, module string, types []Type, propPre []Type) {
	var buffer bytes.Buffer

	objects := make(map[string]*Object)
	for _, t := range types {
		if object, ok := t.(*Object); ok {
			if o, exist := objects[object.Name]; exist {
				log.Fatalf("[Tygo][Typescript] Object already exists: %v %v", o, object)
			}
			objects[object.Name] = object
		}
	}

	var codes []string
	for _, t := range types {
		codes = append(codes, t.Typescript(objects, propPre))
	}
	buffer.Write([]byte(fmt.Sprintf(`// Generated for tyts by tygo.  DO NOT EDIT!

declare module %s {
	interface Type {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
	}%s
}
`, module, strings.Join(codes, ""))))

	ioutil.WriteFile(path.Join(dir, module+".d.ts"), buffer.Bytes(), 0666)
	Javascript(dir, module, types, propPre)
}

func (t *Enum) Typescript(objects map[string]*Object, propPre []Type) string {
	var enums []string
	for _, name := range t.Sorted() {
		enums = append(enums, fmt.Sprintf(`
		%s = %d`, name, t.Values[name]))
	}
	return fmt.Sprintf(`

	const enum %s {%s
	}`, t.Name, strings.Join(enums, ","))
}

func typeListTypescript(name string, typ string, ts []Type, objects map[string]*Object, propPre []Type) string {
	var items []string
	for i, t := range ts {
		items = append(items, fmt.Sprintf("a%d: %s", i, t.Typescript(objects, propPre)))
	}
	return fmt.Sprintf(`
		Serialize%s%s(%s): Uint8Array;
		Deserialize%s%s(data: Uint8Array): any;`, name, typ, strings.Join(items, ", "), name, typ)
}

func (t *Object) Typescript(objects map[string]*Object, propPre []Type) string {
	var parent string
	if t.HasParent() {
		parent = fmt.Sprintf(" extends %s", t.Parent.Typescript(objects, propPre))
	}
	var members []string
	for _, field := range t.Fields {
		members = append(members, fmt.Sprintf(`
		%s: %s;`, field.Name, field.Typescript(objects, propPre)))
	}

	if propPre != nil {
		for _, field := range t.Fields {
			members = append(members, typeListTypescript(field.Name, "", append(propPre, field), objects, propPre))
		}
	}

	for _, method := range t.Methods {
		members = append(members, typeListTypescript(method.Name, "Param", method.Params, objects, propPre))
		members = append(members, typeListTypescript(method.Name, "Result", method.Results, objects, propPre))
	}

	return fmt.Sprintf(`

	class %s%s {
		__class__: string;
		constructor();
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
%s
	}

	namespace %s {
		function Deserialize(data: Uint8Array): %s;
	}`, t.Name, parent, strings.Join(members, ""), t.Name, t.Name)
}

func (t UnknownType) Typescript(objects map[string]*Object, propPre []Type) string {
	return ""
}

func (t SimpleType) Typescript(objects map[string]*Object, propPre []Type) string {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		fallthrough
	case SimpleType_FLOAT32:
		fallthrough
	case SimpleType_FLOAT64:
		return "number"
	case SimpleType_BYTES:
		return "Uint8Array"
	case SimpleType_STRING:
		return "string"
	case SimpleType_BOOL:
		return "boolean"
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Typescript: %d", t)
		return "unknown"
	}
}

func (t *EnumType) Typescript(objects map[string]*Object, propPre []Type) string {
	return t.Name
}

func (t *InstanceType) Typescript(objects map[string]*Object, propPre []Type) string {
	if _, ok := objects[t.Name]; ok {
		return t.Name
	} else {
		return "Type"
	}
}

func (t *FixedPointType) Typescript(objects map[string]*Object, propPre []Type) string {
	return "number"
}

func (t *ListType) Typescript(objects map[string]*Object, propPre []Type) string {
	return fmt.Sprintf("%s[]", t.E.Typescript(objects, propPre))
}

func (t *DictType) Typescript(objects map[string]*Object, propPre []Type) string {
	return fmt.Sprintf("{[index: %s]: %s}", t.K.Typescript(objects, propPre), t.V.Typescript(objects, propPre))
}

func (t *VariantType) Typescript(objects map[string]*Object, propPre []Type) string {
	return "any"
}
<commit_msg>remove unnecessary constructor declare<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"strings"

	"io/ioutil"
)

func Typescript(dir string, module string, types []Type, propPre []Type) {
	var buffer bytes.Buffer

	objects := make(map[string]*Object)
	for _, t := range types {
		if object, ok := t.(*Object); ok {
			if o, exist := objects[object.Name]; exist {
				log.Fatalf("[Tygo][Typescript] Object already exists: %v %v", o, object)
			}
			objects[object.Name] = object
		}
	}

	var codes []string
	for _, t := range types {
		codes = append(codes, t.Typescript(objects, propPre))
	}
	buffer.Write([]byte(fmt.Sprintf(`// Generated for tyts by tygo.  DO NOT EDIT!

declare module %s {
	interface Type {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
	}%s
}
`, module, strings.Join(codes, ""))))

	ioutil.WriteFile(path.Join(dir, module+".d.ts"), buffer.Bytes(), 0666)
	Javascript(dir, module, types, propPre)
}

func (t *Enum) Typescript(objects map[string]*Object, propPre []Type) string {
	var enums []string
	for _, name := range t.Sorted() {
		enums = append(enums, fmt.Sprintf(`
		%s = %d`, name, t.Values[name]))
	}
	return fmt.Sprintf(`

	const enum %s {%s
	}`, t.Name, strings.Join(enums, ","))
}

func typeListTypescript(name string, typ string, ts []Type, objects map[string]*Object, propPre []Type) string {
	var items []string
	for i, t := range ts {
		items = append(items, fmt.Sprintf("a%d: %s", i, t.Typescript(objects, propPre)))
	}
	return fmt.Sprintf(`
		Serialize%s%s(%s): Uint8Array;
		Deserialize%s%s(data: Uint8Array): any;`, name, typ, strings.Join(items, ", "), name, typ)
}

func (t *Object) Typescript(objects map[string]*Object, propPre []Type) string {
	var parent string
	if t.HasParent() {
		parent = fmt.Sprintf(" extends %s", t.Parent.Typescript(objects, propPre))
	}
	var members []string
	for _, field := range t.Fields {
		members = append(members, fmt.Sprintf(`
		%s: %s;`, field.Name, field.Typescript(objects, propPre)))
	}

	if propPre != nil {
		for _, field := range t.Fields {
			members = append(members, typeListTypescript(field.Name, "", append(propPre, field), objects, propPre))
		}
	}

	for _, method := range t.Methods {
		members = append(members, typeListTypescript(method.Name, "Param", method.Params, objects, propPre))
		members = append(members, typeListTypescript(method.Name, "Result", method.Results, objects, propPre))
	}

	return fmt.Sprintf(`

	class %s%s {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
%s
	}

	namespace %s {
		function Deserialize(data: Uint8Array): %s;
	}`, t.Name, parent, strings.Join(members, ""), t.Name, t.Name)
}

func (t UnknownType) Typescript(objects map[string]*Object, propPre []Type) string {
	return ""
}

func (t SimpleType) Typescript(objects map[string]*Object, propPre []Type) string {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		fallthrough
	case SimpleType_FLOAT32:
		fallthrough
	case SimpleType_FLOAT64:
		return "number"
	case SimpleType_BYTES:
		return "Uint8Array"
	case SimpleType_STRING:
		return "string"
	case SimpleType_BOOL:
		return "boolean"
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Typescript: %d", t)
		return "unknown"
	}
}

func (t *EnumType) Typescript(objects map[string]*Object, propPre []Type) string {
	return t.Name
}

func (t *InstanceType) Typescript(objects map[string]*Object, propPre []Type) string {
	if _, ok := objects[t.Name]; ok {
		return t.Name
	} else {
		return "Type"
	}
}

func (t *FixedPointType) Typescript(objects map[string]*Object, propPre []Type) string {
	return "number"
}

func (t *ListType) Typescript(objects map[string]*Object, propPre []Type) string {
	return fmt.Sprintf("%s[]", t.E.Typescript(objects, propPre))
}

func (t *DictType) Typescript(objects map[string]*Object, propPre []Type) string {
	return fmt.Sprintf("{[index: %s]: %s}", t.K.Typescript(objects, propPre), t.V.Typescript(objects, propPre))
}

func (t *VariantType) Typescript(objects map[string]*Object, propPre []Type) string {
	return "any"
}
<|endoftext|>


<commit_before>package docker_discovery

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/newrelic/bosun/service"
)

const (
	SLEEP_INTERVAL = 2 * time.Second
)

type DockerDiscovery struct {
	events chan *docker.APIEvents  // Where events are announced to us
	endpoint string                // The Docker endpoint to talk to
	containers []*service.Service  // The list of containers we know about
	containersLock sync.RWMutex    // Reader/Writer lock controlling .containers
}

func New(endpoint string) *DockerDiscovery {
	discovery := DockerDiscovery{endpoint: endpoint}
	discovery.events = make(chan *docker.APIEvents)
	return &discovery
}

func (d *DockerDiscovery) Run(quit chan bool) {
	getContainersQuit := make(chan bool)
	watchEventsQuit   := make(chan bool)
	processEventsQuit := make(chan bool)

	// Propagate quit channel message
	go func() {
		<-quit // Block on channel until we get a message
		go func() { getContainersQuit <-true }()
		go func() { watchEventsQuit <-true }()
		go func() { processEventsQuit <-true }()
	}()

	// Loop around fetching the whole container list
	go func() {
		for ;; {
			d.getContainers()
			select {
			case <- getContainersQuit:
				return
			default:
			}
			time.Sleep(SLEEP_INTERVAL)
		}
	}()

	go d.watchEvents(watchEventsQuit)
	go d.processEvents(processEventsQuit)
}

func (d *DockerDiscovery) Services() []service.Service {
	d.containersLock.RLock()
	defer d.containersLock.RUnlock()

	containerList := make([]service.Service, 0, len(d.containers))

	for _, container := range d.containers {
		containerList = append(containerList, *container)
	}

	return containerList
}

func (d *DockerDiscovery) getContainers() {
	// New connection every time
	client, _ := docker.NewClient(d.endpoint)
	containers, err := client.ListContainers(docker.ListContainersOptions{ All: false })
	if err != nil {
		return
	}

	d.containersLock.Lock()
	defer d.containersLock.Unlock()

	d.containers = make([]*service.Service, 0, len(containers))

	for _, container := range containers {
		svc := service.ToService(&container)
		d.containers = append(d.containers, &svc)
	}
}

func (d *DockerDiscovery) watchEvents(quit chan bool) {
	client, _ := docker.NewClient(d.endpoint)
	client.AddEventListener(d.events)

	// Health check the connection and set it back up when it goes away.
	for ;; {
		err := client.Ping()
		if err != nil {
			log.Println("Lost connection to Docker, re-connecting")
			client.RemoveEventListener(d.events)
			d.events  = make(chan *docker.APIEvents) // RemoveEventListener closes it
			client, _ = docker.NewClient(d.endpoint)
			client.AddEventListener(d.events)
		}
		select {
		case <- quit:
			return
		default:
		}
		time.Sleep(SLEEP_INTERVAL)
	}
}

func (d *DockerDiscovery) handleEvent(event *docker.APIEvents) {
	// We're only worried about stopping containers
	if event.Status == "die" || event.Status == "stop" {
		d.containersLock.Lock()
		defer d.containersLock.Unlock()

		for i, container := range d.containers {
			if event.ID[:12] == container.ID {
				log.Printf("Deleting %s based on event\n", container.ID)
				// Delete the entry in the slice
				d.containers[i] = nil
				d.containers = append(d.containers[:i], d.containers[i+1:]...)
				// Once we found a match, return
				return
			}
		}
	}
}

func (d *DockerDiscovery) processEvents(quit chan bool) {
	for ;; {
		select {
		case <- quit:
			return
		default:
		}

		event := <-d.events
		fmt.Printf("Event: %#v\n", event)
		if event == nil {
			continue
		}
		go d.handleEvent(event)
	}
}
<commit_msg>Fix bad CPU burn on Docker restart and nils on the channel.<commit_after>package docker_discovery

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/newrelic/bosun/service"
)

const (
	SLEEP_INTERVAL = 2 * time.Second
)

type DockerDiscovery struct {
	events chan *docker.APIEvents  // Where events are announced to us
	endpoint string                // The Docker endpoint to talk to
	containers []*service.Service  // The list of containers we know about
	containersLock sync.RWMutex    // Reader/Writer lock controlling .containers
}

func New(endpoint string) *DockerDiscovery {
	discovery := DockerDiscovery{endpoint: endpoint}
	discovery.events = make(chan *docker.APIEvents)
	return &discovery
}

func (d *DockerDiscovery) Run(quit chan bool) {
	getContainersQuit := make(chan bool)
	watchEventsQuit   := make(chan bool)
	processEventsQuit := make(chan bool)

	// Propagate quit channel message
	go func() {
		<-quit // Block on channel until we get a message
		go func() { getContainersQuit <-true }()
		go func() { watchEventsQuit <-true }()
		go func() { processEventsQuit <-true }()
	}()

	// Loop around fetching the whole container list
	go func() {
		for ;; {
			d.getContainers()
			select {
			case <- getContainersQuit:
				return
			default:
			}
			time.Sleep(SLEEP_INTERVAL)
		}
	}()

	go d.watchEvents(watchEventsQuit)
	go d.processEvents(processEventsQuit)
}

func (d *DockerDiscovery) Services() []service.Service {
	d.containersLock.RLock()
	defer d.containersLock.RUnlock()

	containerList := make([]service.Service, 0, len(d.containers))

	for _, container := range d.containers {
		containerList = append(containerList, *container)
	}

	return containerList
}

func (d *DockerDiscovery) getContainers() {
	// New connection every time
	client, _ := docker.NewClient(d.endpoint)
	containers, err := client.ListContainers(docker.ListContainersOptions{ All: false })
	if err != nil {
		return
	}

	d.containersLock.Lock()
	defer d.containersLock.Unlock()

	d.containers = make([]*service.Service, 0, len(containers))

	for _, container := range containers {
		svc := service.ToService(&container)
		d.containers = append(d.containers, &svc)
	}
}

func (d *DockerDiscovery) watchEvents(quit chan bool) {
	client, _ := docker.NewClient(d.endpoint)
	client.AddEventListener(d.events)

	// Health check the connection and set it back up when it goes away.
	for ;; {
		err := client.Ping()
		if err != nil {
			log.Println("Lost connection to Docker, re-connecting")
			client.RemoveEventListener(d.events)
			d.events  = make(chan *docker.APIEvents) // RemoveEventListener closes it
			client, err = docker.NewClient(d.endpoint)
			if err == nil {
				client.AddEventListener(d.events)
			} else {
				log.Println("Can't reconnect to Docker!")
			}
		}
		select {
		case <- quit:
			return
		default:
		}
		time.Sleep(SLEEP_INTERVAL)
	}
}

func (d *DockerDiscovery) handleEvent(event docker.APIEvents) {
	// We're only worried about stopping containers
	if event.Status == "die" || event.Status == "stop" {
		go func() {
			d.containersLock.Lock()
			defer d.containersLock.Unlock()

			for i, container := range d.containers {
				if event.ID[:12] == container.ID {
					log.Printf("Deleting %s based on event\n", container.ID)
					// Delete the entry in the slice
					d.containers[i] = nil
					d.containers = append(d.containers[:i], d.containers[i+1:]...)
					// Once we found a match, return
					return
				}
			}
		}()
	}
}

func (d *DockerDiscovery) processEvents(quit chan bool) {
	for ;; {
		select {
		case <- quit:
			return
		default:
		}

		event := <-d.events
		if event == nil {
			// This usually happens because of a Docker restart.
			// Sleep, let us reconnect in the background, then loop.
			time.Sleep(SLEEP_INTERVAL)
			continue
		}
		fmt.Printf("Event: %#v\n", event)
		d.handleEvent(*event)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.
//
// 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 proxyutil

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

// Header is a generic representation of a set of HTTP headers for requests and
// responses.
type Header struct {
	h http.Header

	host func() string
	cl   func() int64
	te   func() []string

	setHost func(string)
	setCL   func(int64)
	setTE   func([]string)
}

// RequestHeader returns a new set of headers from a request.
func RequestHeader(req *http.Request) *Header {
	return &Header{
		h:       req.Header,
		host:    func() string { return req.Host },
		cl:      func() int64 { return req.ContentLength },
		te:      func() []string { return req.TransferEncoding },
		setHost: func(host string) { req.Host = host },
		setCL:   func(cl int64) { req.ContentLength = cl },
		setTE:   func(te []string) { req.TransferEncoding = te },
	}
}

// ResponseHeader returns a new set of headers from a request.
func ResponseHeader(res *http.Response) *Header {
	return &Header{
		h:       res.Header,
		host:    func() string { return "" },
		cl:      func() int64 { return res.ContentLength },
		te:      func() []string { return res.TransferEncoding },
		setHost: func(string) {},
		setCL:   func(cl int64) { res.ContentLength = cl },
		setTE:   func(te []string) { res.TransferEncoding = te },
	}
}

// Set sets value at header name for the request or response.
func (h *Header) Set(name, value string) error {
	switch name {
	case "Host":
		h.setHost(value)
	case "Content-Length":
		cl, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return err
		}

		h.setCL(cl)
	case "Transfer-Encoding":
		h.setTE([]string{value})
	default:
		h.h.Set(name, value)
	}

	return nil
}

// Add appends the value to the existing header at name for the request or
// response.
func (h *Header) Add(name, value string) error {
	switch name {
	case "Host":
		if h.host() != "" {
			return fmt.Errorf("proxyutil: illegal header multiple: %s", "Host")
		}

		return h.Set(name, value)
	case "Content-Length":
		if h.cl() > 0 {
			return fmt.Errorf("proxyutil: illegal header multiple: %s", "Content-Length")
		}

		return h.Set(name, value)
	case "Transfer-Encoding":
		h.setTE(append(h.te(), value))
	default:
		h.h.Add(name, value)
	}

	return nil
}

// Get returns the first value at header name for the request or response.
func (h *Header) Get(name string) string {
	switch name {
	case "Host":
		return h.host()
	case "Content-Length":
		if h.cl() < 0 {
			return ""
		}

		return strconv.FormatInt(h.cl(), 10)
	case "Transfer-Encoding":
		if len(h.te()) < 1 {
			return ""
		}

		return h.te()[0]
	default:
		return h.h.Get(name)
	}
}

// All returns all the values for header name. If the header does not exist it
// returns nil, false.
func (h *Header) All(name string) ([]string, bool) {
	switch name {
	case "Host":
		if h.host() == "" {
			return nil, false
		}

		return []string{h.host()}, true
	case "Content-Length":
		if h.cl() <= 0 {
			return nil, false
		}

		return []string{strconv.FormatInt(h.cl(), 10)}, true
	case "Transfer-Encoding":
		if h.te() == nil {
			return nil, false
		}

		return h.te(), true
	default:
		vs, ok := h.h[name]
		return vs, ok
	}
}

// Del deletes the header at name for the request or response.
func (h *Header) Del(name string) {
	switch name {
	case "Host":
		h.setHost("")
	case "Content-Length":
		h.setCL(-1)
	case "Transfer-Encoding":
		h.setTE(nil)
	default:
		h.h.Del(name)
	}
}
<commit_msg>proxyutil: use http.CanonicalHeaderKey for header name.<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// 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 proxyutil

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

// Header is a generic representation of a set of HTTP headers for requests and
// responses.
type Header struct {
	h http.Header

	host func() string
	cl   func() int64
	te   func() []string

	setHost func(string)
	setCL   func(int64)
	setTE   func([]string)
}

// RequestHeader returns a new set of headers from a request.
func RequestHeader(req *http.Request) *Header {
	return &Header{
		h:       req.Header,
		host:    func() string { return req.Host },
		cl:      func() int64 { return req.ContentLength },
		te:      func() []string { return req.TransferEncoding },
		setHost: func(host string) { req.Host = host },
		setCL:   func(cl int64) { req.ContentLength = cl },
		setTE:   func(te []string) { req.TransferEncoding = te },
	}
}

// ResponseHeader returns a new set of headers from a request.
func ResponseHeader(res *http.Response) *Header {
	return &Header{
		h:       res.Header,
		host:    func() string { return "" },
		cl:      func() int64 { return res.ContentLength },
		te:      func() []string { return res.TransferEncoding },
		setHost: func(string) {},
		setCL:   func(cl int64) { res.ContentLength = cl },
		setTE:   func(te []string) { res.TransferEncoding = te },
	}
}

// Set sets value at header name for the request or response.
func (h *Header) Set(name, value string) error {
	switch http.CanonicalHeaderKey(name) {
	case "Host":
		h.setHost(value)
	case "Content-Length":
		cl, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return err
		}

		h.setCL(cl)
	case "Transfer-Encoding":
		h.setTE([]string{value})
	default:
		h.h.Set(name, value)
	}

	return nil
}

// Add appends the value to the existing header at name for the request or
// response.
func (h *Header) Add(name, value string) error {
	switch http.CanonicalHeaderKey(name) {
	case "Host":
		if h.host() != "" {
			return fmt.Errorf("proxyutil: illegal header multiple: %s", "Host")
		}

		return h.Set(name, value)
	case "Content-Length":
		if h.cl() > 0 {
			return fmt.Errorf("proxyutil: illegal header multiple: %s", "Content-Length")
		}

		return h.Set(name, value)
	case "Transfer-Encoding":
		h.setTE(append(h.te(), value))
	default:
		h.h.Add(name, value)
	}

	return nil
}

// Get returns the first value at header name for the request or response.
func (h *Header) Get(name string) string {
	switch http.CanonicalHeaderKey(name) {
	case "Host":
		return h.host()
	case "Content-Length":
		if h.cl() < 0 {
			return ""
		}

		return strconv.FormatInt(h.cl(), 10)
	case "Transfer-Encoding":
		if len(h.te()) < 1 {
			return ""
		}

		return h.te()[0]
	default:
		return h.h.Get(name)
	}
}

// All returns all the values for header name. If the header does not exist it
// returns nil, false.
func (h *Header) All(name string) ([]string, bool) {
	switch http.CanonicalHeaderKey(name) {
	case "Host":
		if h.host() == "" {
			return nil, false
		}

		return []string{h.host()}, true
	case "Content-Length":
		if h.cl() <= 0 {
			return nil, false
		}

		return []string{strconv.FormatInt(h.cl(), 10)}, true
	case "Transfer-Encoding":
		if h.te() == nil {
			return nil, false
		}

		return h.te(), true
	default:
		vs, ok := h.h[http.CanonicalHeaderKey(name)]
		return vs, ok
	}
}

// Del deletes the header at name for the request or response.
func (h *Header) Del(name string) {
	switch http.CanonicalHeaderKey(name) {
	case "Host":
		h.setHost("")
	case "Content-Length":
		h.setCL(-1)
	case "Transfer-Encoding":
		h.setTE(nil)
	default:
		h.h.Del(name)
	}
}
<|endoftext|>


<commit_before>package runtime

import (
	"context"
	"fmt"
	"io"

	"github.com/concourse/concourse/atc"
)

const (
	InitializingEvent          = "Initializing"
	StartingEvent              = "Starting"
	FinishedEvent              = "Finished"
	ResourceResultPropertyName = "concourse:resource-result"
	ResourceProcessID          = "resource"
)

type VersionResult struct {
	Version  atc.Version         `json:"version"`
	Metadata []atc.MetadataField `json:"metadata,omitempty"`
}

type PutRequest struct {
	Source atc.Source `json:"source"`
	Params atc.Params `json:"params,omitempty"`
}

type GetRequest struct {
	Source atc.Source `json:"source"`
	Params atc.Params `json:"params,omitempty"`
}

type Artifact interface {
	ID() string
}

type CacheArtifact struct {
	TeamID   int
	JobID    int
	StepName string
	Path     string
}

func (art CacheArtifact) ID() string {
	return fmt.Sprintf("%d, %d, %s, %s", art.TeamID, art.JobID, art.StepName, art.Path)
}

type GetArtifact struct {
	VolumeHandle string
}

func (art GetArtifact) ID() string {
	return art.VolumeHandle
}

type TaskArtifact struct {
	VolumeHandle string
}

func (art TaskArtifact) ID() string {
	return art.VolumeHandle
}

//go:generate counterfeiter . Runner
type Runner interface {
	RunScript(
		context.Context,
		string,
		[]string,
		[]byte,
		interface{},
		io.Writer,
		bool,
	) error
}

type ProcessSpec struct {
	Path         string
	Args         []string
	Dir          string
	User         string
	StdoutWriter io.Writer
	StderrWriter io.Writer
}
<commit_msg>add named args to Runner RunScript<commit_after>package runtime

import (
	"context"
	"fmt"
	"io"

	"github.com/concourse/concourse/atc"
)

const (
	InitializingEvent          = "Initializing"
	StartingEvent              = "Starting"
	FinishedEvent              = "Finished"
	ResourceResultPropertyName = "concourse:resource-result"
	ResourceProcessID          = "resource"
)

type VersionResult struct {
	Version  atc.Version         `json:"version"`
	Metadata []atc.MetadataField `json:"metadata,omitempty"`
}

type PutRequest struct {
	Source atc.Source `json:"source"`
	Params atc.Params `json:"params,omitempty"`
}

type GetRequest struct {
	Source atc.Source `json:"source"`
	Params atc.Params `json:"params,omitempty"`
}

type Artifact interface {
	ID() string
}

type CacheArtifact struct {
	TeamID   int
	JobID    int
	StepName string
	Path     string
}

func (art CacheArtifact) ID() string {
	return fmt.Sprintf("%d, %d, %s, %s", art.TeamID, art.JobID, art.StepName, art.Path)
}

type GetArtifact struct {
	VolumeHandle string
}

func (art GetArtifact) ID() string {
	return art.VolumeHandle
}

type TaskArtifact struct {
	VolumeHandle string
}

func (art TaskArtifact) ID() string {
	return art.VolumeHandle
}

//go:generate counterfeiter . Runner
type Runner interface {
	RunScript(
		ctx context.Context,
		path string,
		args []string,
		input []byte,
		output interface{},
		logDest io.Writer,
		recoverable bool,
	) error
}

type ProcessSpec struct {
	Path         string
	Args         []string
	Dir          string
	User         string
	StdoutWriter io.Writer
	StderrWriter io.Writer
}
<|endoftext|>


<commit_before>package main

import (
	"net"
	"net/http"
	"net/rpc"
	"strconv"
	"time"

	"github.com/namsral/flag"

	"github.com/PaddlePaddle/Paddle/go/pserver"
	log "github.com/sirupsen/logrus"
)

func main() {
	port := flag.Int("port", 0, "port of the pserver")
	index := flag.Int("index", -1, "index of this pserver, should be larger or equal than 0")
	etcdEndpoint := flag.String("etcd-endpoint", "http://127.0.0.1:2379",
		"comma separated endpoint string for pserver to connect to etcd")
	etcdTimeout := flag.Int("etcd-timeout", 5, "timeout for etcd calls")
	numPservers := flag.Int("num-pservers", 1, "total pserver count in a training job")
	checkpointPath := flag.String("checkpoint-path", "/checkpoints/", "save checkpoint path")
	checkpointInterval := flag.Int("checkpoint-interval", "10", "save checkpoint per interval seconds")
	logLevel := flag.String("log-level", "info",
		"log level, possible values: debug, info, warning, error, fatal, panic")
	flag.Parse()

	level, err := log.ParseLevel(*logLevel)
	if err != nil {
		panic(err)
	}
	log.SetLevel(level)

	var idx int
	var cp pserver.Checkpoint
	if *index >= 0 {
		idx = *index
	} else {
		timeout := time.Second * time.Duration((*etcdTimeout))
		e := pserver.NewEtcdClient(*etcdEndpoint, *numPservers, timeout)
		idx, err = e.Register()
		if err != nil {
			panic(err)
		}
	}

	s, err := pserver.NewService(idx, *checkpointInterval, *checkpointPath, e, cp)
	if err != nil {
		panic(err)
	}
	err = rpc.Register(s)
	if err != nil {
		panic(err)
	}

	rpc.HandleHTTP()
	l, err := net.Listen("tcp", ":"+strconv.Itoa(*port))
	if err != nil {
		panic(err)
	}

	log.Infof("start pserver at port %d", *port)
	err = http.Serve(l, nil)

	if err != nil {
		panic(err)
	}
}
<commit_msg>"pserver flags type error"<commit_after>package main

import (
	"net"
	"net/http"
	"net/rpc"
	"strconv"
	"time"

	"github.com/namsral/flag"

	"github.com/PaddlePaddle/Paddle/go/pserver"
	log "github.com/sirupsen/logrus"
)

func main() {
	port := flag.Int("port", 0, "port of the pserver")
	index := flag.Int("index", -1, "index of this pserver, should be larger or equal than 0")
	etcdEndpoint := flag.String("etcd-endpoint", "http://127.0.0.1:2379",
		"comma separated endpoint string for pserver to connect to etcd")
	etcdTimeout := flag.Int("etcd-timeout", 5, "timeout for etcd calls")
	numPservers := flag.Int("num-pservers", 1, "total pserver count in a training job")
	checkpointPath := flag.String("checkpoint-path", "/checkpoints/", "save checkpoint path")
	checkpointInterval := flag.Int("checkpoint-interval", 10, "save checkpoint per interval seconds")
	logLevel := flag.String("log-level", "info",
		"log level, possible values: debug, info, warning, error, fatal, panic")
	flag.Parse()

	level, err := log.ParseLevel(*logLevel)
	if err != nil {
		panic(err)
	}
	log.SetLevel(level)

	var idx int
	var cp pserver.Checkpoint
	var e *pserver.EtcdClient
	if *index >= 0 {
		idx = *index
	} else {
		timeout := time.Second * time.Duration((*etcdTimeout))
		e = pserver.NewEtcdClient(*etcdEndpoint, *numPservers, timeout)
		idx, err = e.Register()
		if err != nil {
			panic(err)
		}
	}

	s, err := pserver.NewService(idx, *checkpointInterval, *checkpointPath, e, cp)
	if err != nil {
		panic(err)
	}
	err = rpc.Register(s)
	if err != nil {
		panic(err)
	}

	rpc.HandleHTTP()
	l, err := net.Listen("tcp", ":"+strconv.Itoa(*port))
	if err != nil {
		panic(err)
	}

	log.Infof("start pserver at port %d", *port)
	err = http.Serve(l, nil)

	if err != nil {
		panic(err)
	}
}
<|endoftext|>