<commit_before>package rss

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"text/tabwriter"
	"time"
)

// Parse RSS or Atom data.
func Parse(data []byte) (*Feed, error) {

	if strings.Contains(string(data), "<rss") {
		if debug {
			fmt.Println("[i] Parsing as RSS 2.0")
		}
		return parseRSS2(data, database)
	} else if strings.Contains(string(data), "xmlns=\"http://purl.org/rss/1.0/\"") {
		if debug {
			fmt.Println("[i] Parsing as RSS 1.0")
		}
		return parseRSS1(data, database)
	} else {
		if debug {
			fmt.Println("[i] Parsing as Atom")
		}
		return parseAtom(data, database)
	}
}

// CacheParsedItemIDs enables or disable Item.ID caching when parsing feeds.
// Returns whether Item.ID were cached prior to function call.
func CacheParsedItemIDs(flag bool) (didCache bool) {
	didCache = !disabled
	disabled = !flag
	return
}

type FetchFunc func() (resp *http.Response, err error)

// Fetch downloads and parses the RSS feed at the given URL
func Fetch(url string) (*Feed, error) {
	return FetchByClient(url, http.DefaultClient)
}

func FetchByClient(url string, client *http.Client) (*Feed, error) {
	fetchFunc := func() (resp *http.Response, err error) {
		return client.Get(url)
	}
	return FetchByFunc(fetchFunc, url)
}

func FetchByFunc(fetchFunc FetchFunc, url string) (*Feed, error) {
	resp, err := fetchFunc()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	out, err := Parse(body)
	if err != nil {
		return nil, err
	}

	if out.Link == "" {
		out.Link = url
	}

	out.UpdateURL = url

	return out, nil
}

// Feed is the top-level structure.
type Feed struct {
	Nickname    string              `json:"nickname"` // This is not set by the package, but could be helpful.
	Title       string              `json:"title"`
	Description string              `json:"description"`
	Link        string              `json:"link"`      // Link to the creator's website.
	UpdateURL   string              `json:"updateurl"` // URL of the feed itself.
	Image       *Image              `json:"image"`     // Feed icon.
	Items       []*Item             `json:"items"`
	ItemMap     map[string]struct{} `json:"itemmap"` // Used in checking whether an item has been seen before.
	Refresh     time.Time           `json:"refresh"` // Earliest time this feed should next be checked.
	Unread      uint32              `json:"unread"`  // Number of unread items. Used by aggregators.
}

// Update fetches any new items and updates f.
func (f *Feed) Update() error {

	// Check that we don't update too often.
	if f.Refresh.After(time.Now()) {
		return nil
	}

	if f.UpdateURL == "" {
		return errors.New("Error: feed has no URL.")
	}

	if f.ItemMap == nil {
		f.ItemMap = make(map[string]struct{})
		for _, item := range f.Items {
			if _, ok := f.ItemMap[item.ID]; !ok {
				f.ItemMap[item.ID] = struct{}{}
			}
		}
	}

	update, err := Fetch(f.UpdateURL)
	if err != nil {
		return err
	}

	f.Refresh = update.Refresh
	f.Title = update.Title
	f.Description = update.Description

	for _, item := range update.Items {
		if _, ok := f.ItemMap[item.ID]; !ok {
			f.Items = append(f.Items, item)
			f.ItemMap[item.ID] = struct{}{}
			f.Unread++
		}
	}

	return nil
}

func (f *Feed) String() string {
	buf := new(bytes.Buffer)
	if debug {
		w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.StripEscape)
		fmt.Fprintf(w, "Feed {\n")
		fmt.Fprintf(w, "\xff\t\xffNickname:\t%q\n", f.Nickname)
		fmt.Fprintf(w, "\xff\t\xffTitle:\t%q\n", f.Title)
		fmt.Fprintf(w, "\xff\t\xffDescription:\t%q\n", f.Description)
		fmt.Fprintf(w, "\xff\t\xffLink:\t%q\n", f.Link)
		fmt.Fprintf(w, "\xff\t\xffUpdateURL:\t%q\n", f.UpdateURL)
		fmt.Fprintf(w, "\xff\t\xffImage:\t%q (%s)\n", f.Image.Title, f.Image.Url)
		fmt.Fprintf(w, "\xff\t\xffRefresh:\t%s\n", f.Refresh.Format(DATE))
		fmt.Fprintf(w, "\xff\t\xffUnread:\t%d\n", f.Unread)
		fmt.Fprintf(w, "\xff\t\xffItems:\t(%d) {\n", len(f.Items))
		for _, item := range f.Items {
			fmt.Fprintf(w, "%s\n", item.Format(2))
		}
		fmt.Fprintf(w, "\xff\t\xff}\n}\n")
		w.Flush()
	} else {
		w := buf
		fmt.Fprintf(w, "Feed %q\n", f.Title)
		fmt.Fprintf(w, "\t%q\n", f.Description)
		fmt.Fprintf(w, "\t%q\n", f.Link)
		fmt.Fprintf(w, "\t%s\n", f.Image)
		fmt.Fprintf(w, "\tRefresh at %s\n", f.Refresh.Format(DATE))
		fmt.Fprintf(w, "\tUnread: %d\n", f.Unread)
		fmt.Fprintf(w, "\tItems:\n")
		for _, item := range f.Items {
			fmt.Fprintf(w, "\t%s\n", item.Format(2))
		}
	}
	return buf.String()
}

// Item represents a single story.
type Item struct {
	Title      string       `json:"title"`
	Summary    string       `json:"summary"`
	Content    string       `json:"content"`
	Link       string       `json:"link"`
	Date       time.Time    `json:"date"`
	ID         string       `json:"id"`
	Enclosures []*Enclosure `json:"enclosures"`
	Read       bool         `json:"read"`
}

func (i *Item) String() string {
	return i.Format(0)
}

func (i *Item) Format(indent int) string {
	buf := new(bytes.Buffer)
	single := strings.Repeat("\t", indent)
	double := single + "\t"
	if debug {
		w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.StripEscape)
		fmt.Fprintf(w, "\xff%s\xffItem {\n", single)
		fmt.Fprintf(w, "\xff%s\xffTitle:\t%q\n", double, i.Title)
		fmt.Fprintf(w, "\xff%s\xffSummary:\t%q\n", double, i.Summary)
		fmt.Fprintf(w, "\xff%s\xffLink:\t%s\n", double, i.Link)
		fmt.Fprintf(w, "\xff%s\xffDate:\t%s\n", double, i.Date.Format(DATE))
		fmt.Fprintf(w, "\xff%s\xffID:\t%s\n", double, i.ID)
		fmt.Fprintf(w, "\xff%s\xffRead:\t%v\n", double, i.Read)
		fmt.Fprintf(w, "\xff%s\xffContent:\t%q\n", double, i.Content)
		fmt.Fprintf(w, "\xff%s\xff}\n", single)
		w.Flush()
	} else {
		w := buf
		fmt.Fprintf(w, "%sItem %q\n", single, i.Title)
		fmt.Fprintf(w, "%s%q\n", double, i.Link)
		fmt.Fprintf(w, "%s%s\n", double, i.Date.Format(DATE))
		fmt.Fprintf(w, "%s%q\n", double, i.ID)
		fmt.Fprintf(w, "%sRead: %v\n", double, i.Read)
		fmt.Fprintf(w, "%s%q\n", double, i.Content)
	}
	return buf.String()
}

type Enclosure struct {
	Url    string `json:"url"`
	Type   string `json:"type"`
	Rel    string `json:"rel"`
	Length int    `json:"length"`
}

func (e *Enclosure) Get() (io.ReadCloser, error) {
	if e == nil || e.Url == "" {
		return nil, errors.New("No enclosure")
	}

	res, err := http.Get(e.Url)
	if err != nil {
		return nil, err
	}

	return res.Body, nil
}

type Image struct {
	Title  string `json:"title"`
	Url    string `json:"url"`
	Height uint32 `json:"height"`
	Width  uint32 `json:"width"`
}

func (i *Image) Get() (io.ReadCloser, error) {
	if i == nil || i.Url == "" {
		return nil, errors.New("No image")
	}

	res, err := http.Get(i.Url)
	if err != nil {
		return nil, err
	}

	return res.Body, nil
}

func (i *Image) String() string {
	return fmt.Sprintf("Image %q", i.Title)
}
<commit_msg>Make Update utilize the FetchFunc used in the initial fetch<commit_after>package rss

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"text/tabwriter"
	"time"
)

// Parse RSS or Atom data.
func Parse(data []byte) (*Feed, error) {

	if strings.Contains(string(data), "<rss") {
		if debug {
			fmt.Println("[i] Parsing as RSS 2.0")
		}
		return parseRSS2(data, database)
	} else if strings.Contains(string(data), "xmlns=\"http://purl.org/rss/1.0/\"") {
		if debug {
			fmt.Println("[i] Parsing as RSS 1.0")
		}
		return parseRSS1(data, database)
	} else {
		if debug {
			fmt.Println("[i] Parsing as Atom")
		}
		return parseAtom(data, database)
	}
}

// CacheParsedItemIDs enables or disable Item.ID caching when parsing feeds.
// Returns whether Item.ID were cached prior to function call.
func CacheParsedItemIDs(flag bool) (didCache bool) {
	didCache = !disabled
	disabled = !flag
	return
}

type FetchFunc func() (resp *http.Response, err error)

// Fetch downloads and parses the RSS feed at the given URL
func Fetch(url string) (*Feed, error) {
	return FetchByClient(url, http.DefaultClient)
}

func FetchByClient(url string, client *http.Client) (*Feed, error) {
	fetchFunc := func() (resp *http.Response, err error) {
		return client.Get(url)
	}
	return FetchByFunc(fetchFunc, url)
}

func FetchByFunc(fetchFunc FetchFunc, url string) (*Feed, error) {
	resp, err := fetchFunc()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	out, err := Parse(body)
	if err != nil {
		return nil, err
	}

	if out.Link == "" {
		out.Link = url
	}

	out.UpdateURL = url
	out.FetchFunc = fetchFunc

	return out, nil
}

// Feed is the top-level structure.
type Feed struct {
	Nickname    string              `json:"nickname"` // This is not set by the package, but could be helpful.
	Title       string              `json:"title"`
	Description string              `json:"description"`
	Link        string              `json:"link"`      // Link to the creator's website.
	UpdateURL   string              `json:"updateurl"` // URL of the feed itself.
	Image       *Image              `json:"image"`     // Feed icon.
	Items       []*Item             `json:"items"`
	ItemMap     map[string]struct{} `json:"itemmap"` // Used in checking whether an item has been seen before.
	Refresh     time.Time           `json:"refresh"` // Earliest time this feed should next be checked.
	Unread      uint32              `json:"unread"`  // Number of unread items. Used by aggregators.
	FetchFunc   FetchFunc           `json:"-"`
}

// Update fetches any new items and updates f.
func (f *Feed) Update() error {

	// Check that we don't update too often.
	if f.Refresh.After(time.Now()) {
		return nil
	}

	if f.UpdateURL == "" {
		return errors.New("Error: feed has no URL.")
	}

	if f.ItemMap == nil {
		f.ItemMap = make(map[string]struct{})
		for _, item := range f.Items {
			if _, ok := f.ItemMap[item.ID]; !ok {
				f.ItemMap[item.ID] = struct{}{}
			}
		}
	}

	update, err := FetchByFunc(f.FetchFunc, f.UpdateURL)
	if err != nil {
		return err
	}

	f.Refresh = update.Refresh
	f.Title = update.Title
	f.Description = update.Description

	for _, item := range update.Items {
		if _, ok := f.ItemMap[item.ID]; !ok {
			f.Items = append(f.Items, item)
			f.ItemMap[item.ID] = struct{}{}
			f.Unread++
		}
	}

	return nil
}

func (f *Feed) String() string {
	buf := new(bytes.Buffer)
	if debug {
		w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.StripEscape)
		fmt.Fprintf(w, "Feed {\n")
		fmt.Fprintf(w, "\xff\t\xffNickname:\t%q\n", f.Nickname)
		fmt.Fprintf(w, "\xff\t\xffTitle:\t%q\n", f.Title)
		fmt.Fprintf(w, "\xff\t\xffDescription:\t%q\n", f.Description)
		fmt.Fprintf(w, "\xff\t\xffLink:\t%q\n", f.Link)
		fmt.Fprintf(w, "\xff\t\xffUpdateURL:\t%q\n", f.UpdateURL)
		fmt.Fprintf(w, "\xff\t\xffImage:\t%q (%s)\n", f.Image.Title, f.Image.Url)
		fmt.Fprintf(w, "\xff\t\xffRefresh:\t%s\n", f.Refresh.Format(DATE))
		fmt.Fprintf(w, "\xff\t\xffUnread:\t%d\n", f.Unread)
		fmt.Fprintf(w, "\xff\t\xffItems:\t(%d) {\n", len(f.Items))
		for _, item := range f.Items {
			fmt.Fprintf(w, "%s\n", item.Format(2))
		}
		fmt.Fprintf(w, "\xff\t\xff}\n}\n")
		w.Flush()
	} else {
		w := buf
		fmt.Fprintf(w, "Feed %q\n", f.Title)
		fmt.Fprintf(w, "\t%q\n", f.Description)
		fmt.Fprintf(w, "\t%q\n", f.Link)
		fmt.Fprintf(w, "\t%s\n", f.Image)
		fmt.Fprintf(w, "\tRefresh at %s\n", f.Refresh.Format(DATE))
		fmt.Fprintf(w, "\tUnread: %d\n", f.Unread)
		fmt.Fprintf(w, "\tItems:\n")
		for _, item := range f.Items {
			fmt.Fprintf(w, "\t%s\n", item.Format(2))
		}
	}
	return buf.String()
}

// Item represents a single story.
type Item struct {
	Title      string       `json:"title"`
	Summary    string       `json:"summary"`
	Content    string       `json:"content"`
	Link       string       `json:"link"`
	Date       time.Time    `json:"date"`
	ID         string       `json:"id"`
	Enclosures []*Enclosure `json:"enclosures"`
	Read       bool         `json:"read"`
}

func (i *Item) String() string {
	return i.Format(0)
}

func (i *Item) Format(indent int) string {
	buf := new(bytes.Buffer)
	single := strings.Repeat("\t", indent)
	double := single + "\t"
	if debug {
		w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.StripEscape)
		fmt.Fprintf(w, "\xff%s\xffItem {\n", single)
		fmt.Fprintf(w, "\xff%s\xffTitle:\t%q\n", double, i.Title)
		fmt.Fprintf(w, "\xff%s\xffSummary:\t%q\n", double, i.Summary)
		fmt.Fprintf(w, "\xff%s\xffLink:\t%s\n", double, i.Link)
		fmt.Fprintf(w, "\xff%s\xffDate:\t%s\n", double, i.Date.Format(DATE))
		fmt.Fprintf(w, "\xff%s\xffID:\t%s\n", double, i.ID)
		fmt.Fprintf(w, "\xff%s\xffRead:\t%v\n", double, i.Read)
		fmt.Fprintf(w, "\xff%s\xffContent:\t%q\n", double, i.Content)
		fmt.Fprintf(w, "\xff%s\xff}\n", single)
		w.Flush()
	} else {
		w := buf
		fmt.Fprintf(w, "%sItem %q\n", single, i.Title)
		fmt.Fprintf(w, "%s%q\n", double, i.Link)
		fmt.Fprintf(w, "%s%s\n", double, i.Date.Format(DATE))
		fmt.Fprintf(w, "%s%q\n", double, i.ID)
		fmt.Fprintf(w, "%sRead: %v\n", double, i.Read)
		fmt.Fprintf(w, "%s%q\n", double, i.Content)
	}
	return buf.String()
}

type Enclosure struct {
	Url    string `json:"url"`
	Type   string `json:"type"`
	Rel    string `json:"rel"`
	Length int    `json:"length"`
}

func (e *Enclosure) Get() (io.ReadCloser, error) {
	if e == nil || e.Url == "" {
		return nil, errors.New("No enclosure")
	}

	res, err := http.Get(e.Url)
	if err != nil {
		return nil, err
	}

	return res.Body, nil
}

type Image struct {
	Title  string `json:"title"`
	Url    string `json:"url"`
	Height uint32 `json:"height"`
	Width  uint32 `json:"width"`
}

func (i *Image) Get() (io.ReadCloser, error) {
	if i == nil || i.Url == "" {
		return nil, errors.New("No image")
	}

	res, err := http.Get(i.Url)
	if err != nil {
		return nil, err
	}

	return res.Body, nil
}

func (i *Image) String() string {
	return fmt.Sprintf("Image %q", i.Title)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"unicode/utf8"
)

var homedir string

func init() {
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	homedir = usr.HomeDir
}

// Run fillin
func Run(configPath string, args []string, in *bufio.Reader, out *bufio.Writer) (string, error) {
	path := filepath.Join(strings.Split(configPath, "/")...)
	if path[0] == '~' {
		path = homedir + path[1:]
	}
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return "", err
	}
	rfile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	w := new(bytes.Buffer)
	cmd := quoteJoin(Fillin(args, rfile, w, in, out))
	rfile.Close() // not be defered due to rename
	tmpFileName := fmt.Sprintf("fillin.%d-%d.json", os.Getpid(), rand.Int())
	tmp := filepath.Join(filepath.Dir(path), tmpFileName)
	defer os.Remove(tmp)
	wfile, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	if n, err := wfile.Write(w.Bytes()); n != w.Len() || err != nil {
		wfile.Close()
		return "", err
	}
	wfile.Close() // not be defered due to rename
	if err := os.Rename(tmp, path); err != nil {
		return "", err
	}
	return cmd, nil
}

func quoteJoin(args []string) string {
	for i, arg := range args {
		args[i] = quote(arg)
	}
	return strings.Join(args, " ")
}

func quote(arg string) string {
quote:
	for _, quote := range []bool{false, true} {
		s := arg
		var buf bytes.Buffer
		if quote {
			buf.WriteByte('\'')
		}
		for len(s) > 0 {
			c, l := utf8.DecodeRuneInString(s)
			s = s[l:]
			if strings.ContainsRune("\\'\"`${[|&;<>()*?!", c) && !quote {
				buf.WriteByte('\\')
				buf.WriteRune(c)
			} else if c == rune(' ') && !quote {
				continue quote
			} else if c == rune('\t') {
				if quote {
					buf.WriteByte('\\')
					buf.WriteByte('t')
				} else {
					continue quote
				}
			} else {
				buf.WriteRune(c)
			}
		}
		if quote {
			buf.WriteByte('\'')
		}
		return buf.String()
	}
	return ""
}
<commit_msg>leave pipe, operators and redirect as they are<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"unicode/utf8"
)

var homedir string

func init() {
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	homedir = usr.HomeDir
}

// Run fillin
func Run(configPath string, args []string, in *bufio.Reader, out *bufio.Writer) (string, error) {
	path := filepath.Join(strings.Split(configPath, "/")...)
	if path[0] == '~' {
		path = homedir + path[1:]
	}
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return "", err
	}
	rfile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	w := new(bytes.Buffer)
	cmd := quoteJoin(Fillin(args, rfile, w, in, out))
	rfile.Close() // not be defered due to rename
	tmpFileName := fmt.Sprintf("fillin.%d-%d.json", os.Getpid(), rand.Int())
	tmp := filepath.Join(filepath.Dir(path), tmpFileName)
	defer os.Remove(tmp)
	wfile, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	if n, err := wfile.Write(w.Bytes()); n != w.Len() || err != nil {
		wfile.Close()
		return "", err
	}
	wfile.Close() // not be defered due to rename
	if err := os.Rename(tmp, path); err != nil {
		return "", err
	}
	return cmd, nil
}

func quoteJoin(args []string) string {
	for i, arg := range args {
		args[i] = quote(arg)
	}
	return strings.Join(args, " ")
}

func quote(arg string) string {
	switch arg {
	case "|", "||", "&&", ">", "<":
		return arg
	}
quote:
	for _, quote := range []bool{false, true} {
		s := arg
		var buf bytes.Buffer
		if quote {
			buf.WriteByte('\'')
		}
		for len(s) > 0 {
			c, l := utf8.DecodeRuneInString(s)
			s = s[l:]
			if strings.ContainsRune("\\'\"`${[|&;<>()*?!", c) && !quote {
				buf.WriteByte('\\')
				buf.WriteRune(c)
			} else if c == rune(' ') && !quote {
				continue quote
			} else if c == rune('\t') {
				if quote {
					buf.WriteByte('\\')
					buf.WriteByte('t')
				} else {
					continue quote
				}
			} else {
				buf.WriteRune(c)
			}
		}
		if quote {
			buf.WriteByte('\'')
		}
		return buf.String()
	}
	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"
	"os/exec"
	"path"
	"regexp"

	"github.com/armon/circbuf"
)

const (
	StateStopped = iota
	StateLoading
	StateRunning
	StateShuttingDown
)

const BufferSize = 1024 * 512

var (
	saveCmd = []byte{'\r', '\n', 's', 'a', 'v', 'e', 'a', 'l', 'l', ' ', '\r', '\n'}
	stopCmd = []byte{'\r', '\n', 's', 't', 'o', 'p', ' ', '\r', '\n'}
)

// 2015-09-27 15:33:41 [INFO] [Minecraft-Server] Done (3.959s)! For help, type "help" or "?"
var doneRegex = regexp.MustCompile("^[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9}{2} \\[Info\\] \\[Minecraft-Server\\] Done ")

type controller struct {
	c       *Config
	running map[int]running
}

func (c *controller) Start(sID int) error {
	c.c.mu.Lock()
	defer c.c.mu.Unlock()
	s, ok := c.c.Servers[sID]
	if !ok {
		return ErrNoServer
	}
	if s.state != StateStopped {
		return ErrServerRunning
	}
	if s.Map == -1 {
		return ErrNoMap
	}
	s.state = StateLoading
	c.c.Servers[sID] = s
	go c.run(s)
	return nil
}

func (c *controller) Stop(sID int) {
	c.c.mu.RLock()
	defer c.c.mu.RUnlock()
	r, ok := c.running[sID]
	if !ok {
		return ErrServerNotRunning
	}
	close(r.shutdown)
	delete(c.running, sID)
	return nil
}

// runs in its own goroutine
func (c *controller) run(s Server) {
	r := running{
		shutdown: make(chan struct{}),
	}
	c.c.mu.Lock()
	c.running[s.ID] = r
	c.c.mu.Unlock()
	cmd := exec.Command(path.Join(s.Path, "server.jar"), s.Args...)
	cmd.Dir = s.Path
	r.cb = circbuf.NewBuffer(BufferSize)
	cmd.Stdout = r.cb
	wp, _ := cmd.StdoutPipe()
	r.w.io.MultiWriter(r.cb, wp)
}

type running struct {
	shutdown chan struct{}
	cb       *circbuf.Buffer
	stdin    io.Writer
	w        io.Writer
}

func (r *running) Write(p []byte) (int, error) {
	if r.id < 0 {
		return 0, ErrServerNotRunning
	}
	return r.w.Write(p)
}

// Errors
var (
	ErrServerRunning    = errors.New("server already running")
	ErrServerNotRunning = errors.New("server not running")
)
<commit_msg>Set Stdout/Stdin and Stderr for testing<commit_after>package main

import (
	"errors"
	"io"
	"os"
	"os/exec"
	"path"
	"regexp"

	"github.com/armon/circbuf"
)

const (
	StateStopped = iota
	StateLoading
	StateRunning
	StateShuttingDown
)

const BufferSize = 1024 * 512

var (
	saveCmd = []byte{'\r', '\n', 's', 'a', 'v', 'e', 'a', 'l', 'l', ' ', '\r', '\n'}
	stopCmd = []byte{'\r', '\n', 's', 't', 'o', 'p', ' ', '\r', '\n'}
)

// 2015-09-27 15:33:41 [INFO] [Minecraft-Server] Done (3.959s)! For help, type "help" or "?"
var doneRegex = regexp.MustCompile("^[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9}{2} \\[Info\\] \\[Minecraft-Server\\] Done ")

type controller struct {
	c       *Config
	running map[int]running
}

func (c *controller) Start(sID int) error {
	c.c.mu.Lock()
	defer c.c.mu.Unlock()
	s, ok := c.c.Servers[sID]
	if !ok {
		return ErrNoServer
	}
	if s.state != StateStopped {
		return ErrServerRunning
	}
	if s.Map == -1 {
		return ErrNoMap
	}
	s.state = StateLoading
	c.c.Servers[sID] = s
	go c.run(s)
	return nil
}

func (c *controller) Stop(sID int) {
	c.c.mu.RLock()
	defer c.c.mu.RUnlock()
	r, ok := c.running[sID]
	if !ok {
		return ErrServerNotRunning
	}
	close(r.shutdown)
	delete(c.running, sID)
	return nil
}

// runs in its own goroutine
func (c *controller) run(s Server) {
	r := running{
		shutdown: make(chan struct{}),
	}
	c.c.mu.Lock()
	c.running[s.ID] = r
	c.c.mu.Unlock()
	cmd := exec.Command(path.Join(s.Path, "server.jar"), s.Args...)
	cmd.Dir = s.Path
	/*r.cb = circbuf.NewBuffer(BufferSize)
	cmd.Stdout = r.cb
	wp, _ := cmd.StdoutPipe()
	r.w.io.MultiWriter(r.cb, wp)
	*/
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
}

type running struct {
	shutdown chan struct{}
	cb       *circbuf.Buffer
	stdin    io.Writer
	w        io.Writer
}

func (r *running) Write(p []byte) (int, error) {
	if r.id < 0 {
		return 0, ErrServerNotRunning
	}
	return r.w.Write(p)
}

// Errors
var (
	ErrServerRunning    = errors.New("server already running")
	ErrServerNotRunning = errors.New("server not running")
)
<|endoftext|>


<commit_before>package main

/*
loadTinzenite loads an existing Tinzenite directory and runs it.
*/import (
	"fmt"
	"github.com/tinzenite/bootstrap"
	"github.com/tinzenite/core"
	"github.com/tinzenite/shared"
	"log"
	"os"
	"os/signal"
	"time"
)

func bootstrapTinzenite(path string) {
	var boot *bootstrap.Bootstrap
	var err error
	done := make(chan bool)
	if shared.IsTinzenite(path) {
		boot, err = bootstrap.Load(path, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap load error:", err.Error())
			return
		}
	} else {
		peerName := getString("Enter the peer name for this Tinzenite directory:")
		boot, err = bootstrap.Create(path, peerName, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap create error:", err.Error())
			return
		}
		// connect to:
		address := getString("Please enter the address of the peer to connect to:")
		err = boot.Start(address)
		if err != nil {
			logMain("Bootstrap start error:", err.Error())
			// return because we don't want to store a faulty bootstrap
			return
		}
		err = boot.Store()
		if err != nil {
			logMain("Bootstrap store error:", err.Error())
		}
	}
	// print information
	address, _ := boot.Address()
	fmt.Printf("Bootstrapping.\nID: %s\n", address)
	// wait for successful bootstrap
	<-done
	log.Println("Closing Bootstrap.")
	// this is required before closing boot because ToxCore may still need to
	// notify the other client that the file transfers are complete - this can
	// take a few iterations, so we delay for a second to give it time to do that.
	<-time.Tick(1 * time.Second)
	// manually close boot if we're done! It won't close itself!
	boot.Close()
	// continue to executing the directory
	fmt.Println("Bootstrapping was successful. Loading Tinzenite.")
	loadTinzenite(path)
}

func createTinzenite(path string) {
	if shared.IsTinzenite(path) {
		logMain("Directory is already a valid Tinzenite directory!")
		return
	}
	// get options
	peerName := getString("Enter the peer name for this Tinzenite directory:")
	userName := getString("Enter your username:")
	password := getString("Enter a password for this Tinzenite network:")
	relPath := shared.CreatePathRoot(path)
	tinzenite, err := core.CreateTinzenite(relPath.LastElement(), relPath.FullPath(), peerName, userName, password)
	if err != nil {
		logMain("Creation error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

func loadTinzenite(path string) {
	if !shared.IsTinzenite(path) {
		logMain("Directory is not a valid Tinzenite directory!")
		return
	}
	password := getString("Please enter the directory password:")
	tinzenite, err := core.LoadTinzenite(path, password)
	if err != nil {
		// TODO catch wrong password and allow retry
		logMain("Loading error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

/*
runTinzenite runs the given Tinzenite instance.
*/
func runTinzenite(t *core.Tinzenite) {
	// do this here so that it is guaranteed to be set
	t.RegisterPeerValidation(allowPeer)
	// print important info
	address, _ := t.Address()
	fmt.Printf("Running peer <%s>.\nID: %s\n", t.Name(), address)
	// run update and sync in intervalls
	var counter int
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for {
		select {
		case <-time.Tick(time.Duration(10) * time.Second):
			if counter >= 5 {
				// TODO remove once Merge bug is fixed
				log.Println("DEBUG: Model sync ---------------------------")
				counter = 0
				err := t.SyncRemote()
				if err != nil {
					logMain("SyncRemote error:", err.Error())
				}
				continue
			}
			// log.Println("DEBUG: Update")
			counter++
			err := t.SyncLocal()
			if err != nil {
				logMain("SyncLocal error:", err.Error())
			}
		case <-c:
			// on interrupt close tinzenite
			t.Close()
			return
		} // select
	} // for
}

/*
allowPeer asks the user whether to accept the given peer.
*/
func allowPeer(address string, wantsTrust bool) bool {
	// TODO actually ask!
	log.Println("TODO: Actually ask, for now accepting everything!", address)
	return true
}
<commit_msg>todo comment<commit_after>package main

/*
loadTinzenite loads an existing Tinzenite directory and runs it.
*/import (
	"fmt"
	"github.com/tinzenite/bootstrap"
	"github.com/tinzenite/core"
	"github.com/tinzenite/shared"
	"log"
	"os"
	"os/signal"
	"time"
)

func bootstrapTinzenite(path string) {
	var boot *bootstrap.Bootstrap
	var err error
	done := make(chan bool)
	if shared.IsTinzenite(path) {
		boot, err = bootstrap.Load(path, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap load error:", err.Error())
			return
		}
	} else {
		peerName := getString("Enter the peer name for this Tinzenite directory:")
		boot, err = bootstrap.Create(path, peerName, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap create error:", err.Error())
			return
		}
		// connect to:
		address := getString("Please enter the address of the peer to connect to:")
		err = boot.Start(address)
		if err != nil {
			logMain("Bootstrap start error:", err.Error())
			// return because we don't want to store a faulty bootstrap
			return
		}
		err = boot.Store()
		if err != nil {
			logMain("Bootstrap store error:", err.Error())
		}
	}
	// print information
	address, _ := boot.Address()
	fmt.Printf("Bootstrapping.\nID: %s\n", address)
	// wait for successful bootstrap
	<-done
	log.Println("Closing Bootstrap.")
	// this is required before closing boot because ToxCore may still need to
	// notify the other client that the file transfers are complete - this can
	// take a few iterations, so we delay for a second to give it time to do that.
	<-time.Tick(1 * time.Second)
	// manually close boot if we're done! It won't close itself!
	boot.Close()
	// continue to executing the directory
	fmt.Println("Bootstrapping was successful. Loading Tinzenite.")
	loadTinzenite(path)
}

func createTinzenite(path string) {
	if shared.IsTinzenite(path) {
		logMain("Directory is already a valid Tinzenite directory!")
		return
	}
	// get options
	peerName := getString("Enter the peer name for this Tinzenite directory:")
	userName := getString("Enter your username:")
	password := getString("Enter a password for this Tinzenite network:")
	relPath := shared.CreatePathRoot(path)
	tinzenite, err := core.CreateTinzenite(relPath.LastElement(), relPath.FullPath(), peerName, userName, password)
	if err != nil {
		logMain("Creation error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

func loadTinzenite(path string) {
	if !shared.IsTinzenite(path) {
		logMain("Directory is not a valid Tinzenite directory!")
		return
	}
	password := getString("Please enter the directory password:")
	tinzenite, err := core.LoadTinzenite(path, password)
	if err != nil {
		// TODO catch wrong password and allow retry
		logMain("Loading error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

/*
runTinzenite runs the given Tinzenite instance.
*/
func runTinzenite(t *core.Tinzenite) {
	// do this here so that it is guaranteed to be set
	t.RegisterPeerValidation(allowPeer)
	// print important info
	address, _ := t.Address()
	fmt.Printf("Running peer <%s>.\nID: %s\n", t.Name(), address)
	// run update and sync in intervalls
	var counter int
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for {
		select {
		case <-time.Tick(time.Duration(10) * time.Second):
			if counter >= 5 {
				// TODO remove once Merge bug is fixed
				log.Println("DEBUG: Model sync ---------------------------")
				counter = 0
				err := t.SyncRemote()
				if err != nil {
					logMain("SyncRemote error:", err.Error())
				}
				continue
			}
			// log.Println("DEBUG: Update")
			counter++
			err := t.SyncLocal()
			if err != nil {
				logMain("SyncLocal error:", err.Error())
			}
		case <-c:
			// on interrupt close tinzenite
			t.Close()
			return
		} // select
	} // for
}

/*
allowPeer asks the user whether to accept the given peer.
*/
func allowPeer(address string, wantsTrust bool) bool {
	// TODO actually ask! NOTE: shouldn't block... how? Call silent add friend on success?
	log.Println("TODO: Actually ask, for now accepting everything!", address)
	return true
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"sync/atomic"

	"github.com/hajimehoshi/ebiten/internal/loop"
	"github.com/hajimehoshi/ebiten/internal/ui"
)

// FPS represents how many times game updating happens in a second.
const FPS = 60

// CurrentFPS returns the current number of frames per second of rendering.
//
// This function is concurrent-safe.
//
// This value represents how many times rendering happens in 1/60 second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second
// as long as the screen is active.
func CurrentFPS() float64 {
	return loop.CurrentFPS()
}

var (
	isRunningSlowly = int32(0)
)

func setRunningSlowly(slow bool) {
	v := int32(0)
	if slow {
		v = 1
	}
	atomic.StoreInt32(&isRunningSlowly, v)
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing, when IsRunningSlowly is true.
//
// This function is concurrent-safe.
func IsRunningSlowly() bool {
	return atomic.LoadInt32(&isRunningSlowly) != 0
}

var theGraphicsContext atomic.Value

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
//
// Run must be called from the main thread.
// Note that ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the screen is not shown.
//
// Run returns error when 1) OpenGL error happens, or 2) f returns error.
// In the case of 2), Run returns the same error.
//
// The size unit is device-independent pixel.
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
	ch := make(chan error)
	go func() {
		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := loop.Run(g, width, height, scale, title, FPS); err != nil {
			ch <- err
		}
		close(ch)
	}()
	// TODO: Use context in Go 1.7?
	if err := ui.RunMainThreadLoop(ch); err != nil {
		return err
	}
	return nil
}

// RunWithoutMainLoop runs the game, but don't call the loop on the main (UI) thread.
// Different from Run, this function returns immediately.
//
// Typically, Ebiten users don't have to call this directly.
// Instead, functions in github.com/hajimehoshi/ebiten/mobile module call this.
//
// The size unit is device-independent pixel.
func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
	ch := make(chan error)
	go func() {
		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := loop.Run(g, width, height, scale, title, FPS); err != nil {
			ch <- err
		}
		close(ch)
	}()
	return ch
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
//
// Unit is device-independent pixel.
//
// This function is concurrent-safe.
func SetScreenSize(width, height int) {
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	ui.SetScreenSize(width, height)
}

// SetScreenScale changes the scale of the screen.
//
// This function is concurrent-safe.
func SetScreenScale(scale float64) {
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	ui.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
//
// If Run is not called, this returns 0.
//
// This function is concurrent-safe.
func ScreenScale() float64 {
	return ui.ScreenScale()
}

// SetCursorVisibility changes the state of cursor visiblity.
//
// This function is concurrent-safe.
func SetCursorVisibility(visible bool) {
	ui.SetCursorVisibility(visible)
}

func IsFullscreen() bool {
	return ui.IsFullscreen()
}

func SetFullscreen(fullscreen bool) {
	ui.SetFullscreen(fullscreen)
}
<commit_msg>ui: Add comments<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"sync/atomic"

	"github.com/hajimehoshi/ebiten/internal/loop"
	"github.com/hajimehoshi/ebiten/internal/ui"
)

// FPS represents how many times game updating happens in a second.
const FPS = 60

// CurrentFPS returns the current number of frames per second of rendering.
//
// This function is concurrent-safe.
//
// This value represents how many times rendering happens in 1/60 second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second
// as long as the screen is active.
func CurrentFPS() float64 {
	return loop.CurrentFPS()
}

var (
	isRunningSlowly = int32(0)
)

func setRunningSlowly(slow bool) {
	v := int32(0)
	if slow {
		v = 1
	}
	atomic.StoreInt32(&isRunningSlowly, v)
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing, when IsRunningSlowly is true.
//
// This function is concurrent-safe.
func IsRunningSlowly() bool {
	return atomic.LoadInt32(&isRunningSlowly) != 0
}

var theGraphicsContext atomic.Value

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
//
// Run must be called from the main thread.
// Note that ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the screen is not shown.
//
// The given scale is ignored on fullscreen mode.
//
// Run returns error when 1) OpenGL error happens, or 2) f returns error.
// In the case of 2), Run returns the same error.
//
// The size unit is device-independent pixel.
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
	ch := make(chan error)
	go func() {
		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := loop.Run(g, width, height, scale, title, FPS); err != nil {
			ch <- err
		}
		close(ch)
	}()
	// TODO: Use context in Go 1.7?
	if err := ui.RunMainThreadLoop(ch); err != nil {
		return err
	}
	return nil
}

// RunWithoutMainLoop runs the game, but don't call the loop on the main (UI) thread.
// Different from Run, this function returns immediately.
//
// Typically, Ebiten users don't have to call this directly.
// Instead, functions in github.com/hajimehoshi/ebiten/mobile module call this.
//
// The size unit is device-independent pixel.
func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
	ch := make(chan error)
	go func() {
		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := loop.Run(g, width, height, scale, title, FPS); err != nil {
			ch <- err
		}
		close(ch)
	}()
	return ch
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
//
// Unit is device-independent pixel.
//
// This function is concurrent-safe.
func SetScreenSize(width, height int) {
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	ui.SetScreenSize(width, height)
}

// SetScreenScale changes the scale of the screen.
//
// This function is concurrent-safe.
func SetScreenScale(scale float64) {
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	ui.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
//
// If Run is not called, this returns 0.
//
// This function is concurrent-safe.
func ScreenScale() float64 {
	return ui.ScreenScale()
}

// SetCursorVisibility changes the state of cursor visiblity.
//
// This function is concurrent-safe.
func SetCursorVisibility(visible bool) {
	ui.SetCursorVisibility(visible)
}

// IsScreen returns a boolean value indicating whether
// the current mode is fullscreen or not.
//
// This function is concurrent-safe.
func IsFullscreen() bool {
	return ui.IsFullscreen()
}

// SetFullscreen changes the current mode to fullscreen or not.
//
// On fullscreen mode, the game screen is automatically enlarged
// to fit with the monitor. The current scale value is ignored.
//
// Ebiten uses 'windowed' fullscreen mode, which doesn't change
// your monitor's resolution.
//
// This function is concurrent-safe.
func SetFullscreen(fullscreen bool) {
	ui.SetFullscreen(fullscreen)
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"fmt"
	"image"
	"os"
	"sync/atomic"

	"github.com/hajimehoshi/ebiten/internal/clock"
	"github.com/hajimehoshi/ebiten/internal/devicescale"
	"github.com/hajimehoshi/ebiten/internal/png"
	"github.com/hajimehoshi/ebiten/internal/ui"
)

// FPS represents how many times game updating happens in a second (60).
const FPS = clock.FPS

// CurrentFPS returns the current number of frames per second of rendering.
//
// The returned value represents how many times rendering happens in a second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second.
//
// This function is concurrent-safe.
func CurrentFPS() float64 {
	return clock.CurrentFPS()
}

var (
	isRunningSlowly = int32(0)
)

func setRunningSlowly(slow bool) {
	v := int32(0)
	if slow {
		v = 1
	}
	atomic.StoreInt32(&isRunningSlowly, v)
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing screen,
// when IsRunningSlowly is true.
//
// The typical code with IsRunningSlowly is this:
//
//    func update(screen *ebiten.Image) error {
//
//        // Update the state.
//
//        // When IsRunningSlowly is true, the rendered result is not adopted.
//        // Skip rendering then.
//        if ebiten.IsRunningSlowly() {
//            return nil
//        }
//
//        // Draw something to the screen.
//
//        return nil
//    }
//
// This function is concurrent-safe.
func IsRunningSlowly() bool {
	return atomic.LoadInt32(&isRunningSlowly) != 0
}

var theGraphicsContext atomic.Value

func run(width, height int, scale float64, title string, g *graphicsContext, mainloop bool) error {
	if err := ui.Run(width, height, scale, title, g, mainloop); err != nil {
		if err == ui.RegularTermination {
			return nil
		}
		return err
	}
	return nil
}

var screenshot = false
var screenshotKey Key

func init() {
	keyname := os.Getenv("EBITEN_SCREENSHOT_KEY")
	if keyname == "" {
		return
	}
	key, ok := keyNameToKey(keyname)
	if !ok {
		return
	}
	screenshot = true
	screenshotKey = key
}

type screenshotTaker struct {
	f          func(screen *Image) error
	keyState   int
	needToTake bool
}

func (s *screenshotTaker) update(screen *Image) error {
	if err := s.f(screen); err != nil {
		return err
	}
	if !screenshot {
		return nil
	}

	if IsKeyPressed(screenshotKey) {
		s.keyState++
		if s.keyState == 1 {
			s.needToTake = true
		}
	} else {
		s.keyState = 0
	}
	if s.needToTake && !IsRunningSlowly() {
		filename := "screenshot.png"
		i := 0
		for {
			if _, err := os.Stat(filename); os.IsNotExist(err) {
				break
			}
			i++
			filename = fmt.Sprintf("screenshot%d.png", i)
		}
		f, err := os.Create(filename)
		if err != nil {
			return err
		}
		defer f.Close()

		if err := png.Encode(f, screen); err != nil {
			return err
		}
		s.needToTake = false
	}
	return nil
}

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
// The screen size is based on the given values (width and height).
//
// A window size is based on the given values (width, height and scale).
// scale is used to enlarge the screen.
// Note that the actual screen is multiplied not only by the given scale but also
// by the device scale on high-DPI display.
// If you pass inverse of the device scale,
// you can disable this automatical device scaling as a result.
// You can get the device scale by DeviceScaleFactor function.
//
// Run must be called from the OS main thread.
// Note that Ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the window is in background by default.
// This setting is configurable with SetRunnableInBackground.
//
// The given scale is ignored on fullscreen mode or gomobile-build mode.
//
// Run returns error when 1) OpenGL error happens, 2) audio error happens or 3) f returns error.
// In the case of 3), Run returns the same error.
//
// The size unit is device-independent pixel.
//
// Don't call Run twice or more in one process.
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
	if screenshot {
		s := &screenshotTaker{f: f}
		f = s.update
	}

	ch := make(chan error)
	go func() {
		defer close(ch)

		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := run(width, height, scale, title, g, true); err != nil {
			ch <- err
			return
		}
	}()
	// TODO: Use context in Go 1.7?
	if err := ui.RunMainThreadLoop(ch); err != nil {
		return err
	}
	return nil
}

// RunWithoutMainLoop runs the game, but don't call the loop on the main (UI) thread.
// Different from Run, this function returns immediately.
//
// Ebiten users should NOT call this function.
// Instead, functions in github.com/hajimehoshi/ebiten/mobile package calls this.
func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
	if screenshot {
		s := &screenshotTaker{f: f}
		f = s.update
	}

	ch := make(chan error)
	go func() {
		defer close(ch)

		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := run(width, height, scale, title, g, false); err != nil {
			ch <- err
			return
		}
	}()
	return ch
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
//
// Unit is device-independent pixel.
//
// This function is concurrent-safe.
func SetScreenSize(width, height int) {
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	ui.SetScreenSize(width, height)
}

// SetScreenScale changes the scale of the screen.
//
// Note that the actual screen is multiplied not only by the given scale but also
// by the device scale on high-DPI display.
// If you pass inverse of the device scale,
// you can disable this automatical device scaling as a result.
// You can get the device scale by DeviceScaleFactor function.
//
// This function is concurrent-safe.
func SetScreenScale(scale float64) {
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	ui.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
//
// If Run is not called, this returns 0.
//
// This function is concurrent-safe.
func ScreenScale() float64 {
	return ui.ScreenScale()
}

// IsCursorVisible returns a boolean value indicating whether
// the cursor is visible or not.
//
// IsCursorVisible always returns false on mobiles.
//
// This function is concurrent-safe.
func IsCursorVisible() bool {
	return ui.IsCursorVisible()
}

// SetCursorVisible changes the state of cursor visiblity.
//
// SetCursorVisible does nothing on mobiles.
//
// This function is concurrent-safe.
func SetCursorVisible(visible bool) {
	ui.SetCursorVisible(visible)
}

// SetCursorVisibility is deprecated as of 1.6.0-alpha. Use SetCursorVisible instead.
func SetCursorVisibility(visible bool) {
	SetCursorVisible(visible)
}

// IsFullscreen returns a boolean value indicating whether
// the current mode is fullscreen or not.
//
// IsFullscreen always returns false on mobiles.
//
// This function is concurrent-safe.
func IsFullscreen() bool {
	return ui.IsFullscreen()
}

// SetFullscreen changes the current mode to fullscreen or not.
//
// On fullscreen mode, the game screen is automatically enlarged
// to fit with the monitor. The current scale value is ignored.
//
// On desktops, Ebiten uses 'windowed' fullscreen mode, which doesn't change
// your monitor's resolution.
//
// On browsers, the game screen is resized to fit with the body element (client) size.
// Additionally, the game screen is automatically resized when the body element is resized.
//
// SetFullscreen does nothing on mobiles.
//
// This function is concurrent-safe.
func SetFullscreen(fullscreen bool) {
	ui.SetFullscreen(fullscreen)
}

// IsRunnableInBackground returns a boolean value indicating whether
// the game runs even in background.
//
// This function is concurrent-safe.
func IsRunnableInBackground() bool {
	return ui.IsRunnableInBackground()
}

// SetWindowDecorated sets the state if the window is decorated.
//
// SetWindowDecorated works only on desktops.
// SetWindowDecorated does nothing on other platforms.
//
// SetWindowDecorated panics if SetWindowDecorated is called after Run.
//
// This function is concurrent-safe.
func SetWindowDecorated(decorated bool) {
	ui.SetWindowDecorated(decorated)
}

// IsWindowDecorated returns a boolean value indicating whether
// the window is decorated.
//
// This function is concurrent-safe.
func IsWindowDecorated() bool {
	return ui.IsWindowDecorated()
}

// SetRunnableInBackground sets the state if the game runs even in background.
//
// If the given value is true, the game runs in background e.g. when losing focus.
// The initial state is false.
//
// Known issue: On browsers, even if the state is on, the game doesn't run in background tabs.
// This is because browsers throttles background tabs not to often update.
//
// SetRunnableInBackground does nothing on mobiles so far.
//
// This function is concurrent-safe.
func SetRunnableInBackground(runnableInBackground bool) {
	ui.SetRunnableInBackground(runnableInBackground)
}

// SetWindowIcon sets the icon of the game window.
//
// If len(iconImages) is 0, SetWindowIcon reverts the icon to the default one.
//
// For desktops, see the document of glfwSetWindowIcon of GLFW 3.2:
//
//     This function sets the icon of the specified window.
//     If passed an array of candidate images, those of or closest to the sizes
//     desired by the system are selected.
//     If no images are specified, the window reverts to its default icon.
//
//     The desired image sizes varies depending on platform and system settings.
//     The selected images will be rescaled as needed.
//     Good sizes include 16x16, 32x32 and 48x48.
//
// As macOS windows don't have icons, SetWindowIcon doesn't work on macOS.
//
// SetWindowIcon doesn't work on browsers or mobiles.
//
// This function is concurrent-safe.
func SetWindowIcon(iconImages []image.Image) {
	ui.SetWindowIcon(iconImages)
}

// DeviceScaleFactor returns a device scale factor value.
//
// DeviceScaleFactor returns a meaningful value on high-DPI display environment,
// otherwise DeviceScaleFactor returns 1.
//
// This function is concurrent-safe.
func DeviceScaleFactor() float64 {
	return devicescale.DeviceScale()
}
<commit_msg>graphics: Refactoring: screenshot dump: remove global variables<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"fmt"
	"image"
	"os"
	"sync/atomic"

	"github.com/hajimehoshi/ebiten/internal/clock"
	"github.com/hajimehoshi/ebiten/internal/devicescale"
	"github.com/hajimehoshi/ebiten/internal/png"
	"github.com/hajimehoshi/ebiten/internal/ui"
)

// FPS represents how many times game updating happens in a second (60).
const FPS = clock.FPS

// CurrentFPS returns the current number of frames per second of rendering.
//
// The returned value represents how many times rendering happens in a second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second.
//
// This function is concurrent-safe.
func CurrentFPS() float64 {
	return clock.CurrentFPS()
}

var (
	isRunningSlowly = int32(0)
)

func setRunningSlowly(slow bool) {
	v := int32(0)
	if slow {
		v = 1
	}
	atomic.StoreInt32(&isRunningSlowly, v)
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing screen,
// when IsRunningSlowly is true.
//
// The typical code with IsRunningSlowly is this:
//
//    func update(screen *ebiten.Image) error {
//
//        // Update the state.
//
//        // When IsRunningSlowly is true, the rendered result is not adopted.
//        // Skip rendering then.
//        if ebiten.IsRunningSlowly() {
//            return nil
//        }
//
//        // Draw something to the screen.
//
//        return nil
//    }
//
// This function is concurrent-safe.
func IsRunningSlowly() bool {
	return atomic.LoadInt32(&isRunningSlowly) != 0
}

var theGraphicsContext atomic.Value

func run(width, height int, scale float64, title string, g *graphicsContext, mainloop bool) error {
	if err := ui.Run(width, height, scale, title, g, mainloop); err != nil {
		if err == ui.RegularTermination {
			return nil
		}
		return err
	}
	return nil
}

type imageDumper struct {
	f func(screen *Image) error

	keyState map[Key]int

	hasScreenshotKey bool
	screenshotKey    Key
	toTakeScreenshot bool
}

func (i *imageDumper) update(screen *Image) error {
	if err := i.f(screen); err != nil {
		return err
	}

	// If keyState is nil, all values are not initialized.
	if i.keyState == nil {
		i.keyState = map[Key]int{}

		if keyname := os.Getenv("EBITEN_SCREENSHOT_KEY"); keyname != "" {
			if key, ok := keyNameToKey(keyname); ok {
				i.hasScreenshotKey = true
				i.screenshotKey = key
			}
		}
	}

	if i.hasScreenshotKey && IsKeyPressed(i.screenshotKey) {
		i.keyState[i.screenshotKey]++
		if i.keyState[i.screenshotKey] == 1 {
			i.toTakeScreenshot = true
		}
	} else {
		i.keyState[i.screenshotKey] = 0
	}

	if i.toTakeScreenshot && !IsRunningSlowly() {
		filename := "screenshot.png"
		idx := 0
		for {
			if _, err := os.Stat(filename); os.IsNotExist(err) {
				break
			}
			idx++
			filename = fmt.Sprintf("screenshot%d.png", idx)
		}
		f, err := os.Create(filename)
		if err != nil {
			return err
		}
		defer f.Close()

		if err := png.Encode(f, screen); err != nil {
			return err
		}
		i.toTakeScreenshot = false
	}
	return nil
}

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
// The screen size is based on the given values (width and height).
//
// A window size is based on the given values (width, height and scale).
// scale is used to enlarge the screen.
// Note that the actual screen is multiplied not only by the given scale but also
// by the device scale on high-DPI display.
// If you pass inverse of the device scale,
// you can disable this automatical device scaling as a result.
// You can get the device scale by DeviceScaleFactor function.
//
// Run must be called from the OS main thread.
// Note that Ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the window is in background by default.
// This setting is configurable with SetRunnableInBackground.
//
// The given scale is ignored on fullscreen mode or gomobile-build mode.
//
// Run returns error when 1) OpenGL error happens, 2) audio error happens or 3) f returns error.
// In the case of 3), Run returns the same error.
//
// The size unit is device-independent pixel.
//
// Don't call Run twice or more in one process.
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
	f = (&imageDumper{f: f}).update

	ch := make(chan error)
	go func() {
		defer close(ch)

		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := run(width, height, scale, title, g, true); err != nil {
			ch <- err
			return
		}
	}()
	// TODO: Use context in Go 1.7?
	if err := ui.RunMainThreadLoop(ch); err != nil {
		return err
	}
	return nil
}

// RunWithoutMainLoop runs the game, but don't call the loop on the main (UI) thread.
// Different from Run, this function returns immediately.
//
// Ebiten users should NOT call this function.
// Instead, functions in github.com/hajimehoshi/ebiten/mobile package calls this.
func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
	f = (&imageDumper{f: f}).update

	ch := make(chan error)
	go func() {
		defer close(ch)

		g := newGraphicsContext(f)
		theGraphicsContext.Store(g)
		if err := run(width, height, scale, title, g, false); err != nil {
			ch <- err
			return
		}
	}()
	return ch
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
//
// Unit is device-independent pixel.
//
// This function is concurrent-safe.
func SetScreenSize(width, height int) {
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	ui.SetScreenSize(width, height)
}

// SetScreenScale changes the scale of the screen.
//
// Note that the actual screen is multiplied not only by the given scale but also
// by the device scale on high-DPI display.
// If you pass inverse of the device scale,
// you can disable this automatical device scaling as a result.
// You can get the device scale by DeviceScaleFactor function.
//
// This function is concurrent-safe.
func SetScreenScale(scale float64) {
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	ui.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
//
// If Run is not called, this returns 0.
//
// This function is concurrent-safe.
func ScreenScale() float64 {
	return ui.ScreenScale()
}

// IsCursorVisible returns a boolean value indicating whether
// the cursor is visible or not.
//
// IsCursorVisible always returns false on mobiles.
//
// This function is concurrent-safe.
func IsCursorVisible() bool {
	return ui.IsCursorVisible()
}

// SetCursorVisible changes the state of cursor visiblity.
//
// SetCursorVisible does nothing on mobiles.
//
// This function is concurrent-safe.
func SetCursorVisible(visible bool) {
	ui.SetCursorVisible(visible)
}

// SetCursorVisibility is deprecated as of 1.6.0-alpha. Use SetCursorVisible instead.
func SetCursorVisibility(visible bool) {
	SetCursorVisible(visible)
}

// IsFullscreen returns a boolean value indicating whether
// the current mode is fullscreen or not.
//
// IsFullscreen always returns false on mobiles.
//
// This function is concurrent-safe.
func IsFullscreen() bool {
	return ui.IsFullscreen()
}

// SetFullscreen changes the current mode to fullscreen or not.
//
// On fullscreen mode, the game screen is automatically enlarged
// to fit with the monitor. The current scale value is ignored.
//
// On desktops, Ebiten uses 'windowed' fullscreen mode, which doesn't change
// your monitor's resolution.
//
// On browsers, the game screen is resized to fit with the body element (client) size.
// Additionally, the game screen is automatically resized when the body element is resized.
//
// SetFullscreen does nothing on mobiles.
//
// This function is concurrent-safe.
func SetFullscreen(fullscreen bool) {
	ui.SetFullscreen(fullscreen)
}

// IsRunnableInBackground returns a boolean value indicating whether
// the game runs even in background.
//
// This function is concurrent-safe.
func IsRunnableInBackground() bool {
	return ui.IsRunnableInBackground()
}

// SetWindowDecorated sets the state if the window is decorated.
//
// SetWindowDecorated works only on desktops.
// SetWindowDecorated does nothing on other platforms.
//
// SetWindowDecorated panics if SetWindowDecorated is called after Run.
//
// This function is concurrent-safe.
func SetWindowDecorated(decorated bool) {
	ui.SetWindowDecorated(decorated)
}

// IsWindowDecorated returns a boolean value indicating whether
// the window is decorated.
//
// This function is concurrent-safe.
func IsWindowDecorated() bool {
	return ui.IsWindowDecorated()
}

// SetRunnableInBackground sets the state if the game runs even in background.
//
// If the given value is true, the game runs in background e.g. when losing focus.
// The initial state is false.
//
// Known issue: On browsers, even if the state is on, the game doesn't run in background tabs.
// This is because browsers throttles background tabs not to often update.
//
// SetRunnableInBackground does nothing on mobiles so far.
//
// This function is concurrent-safe.
func SetRunnableInBackground(runnableInBackground bool) {
	ui.SetRunnableInBackground(runnableInBackground)
}

// SetWindowIcon sets the icon of the game window.
//
// If len(iconImages) is 0, SetWindowIcon reverts the icon to the default one.
//
// For desktops, see the document of glfwSetWindowIcon of GLFW 3.2:
//
//     This function sets the icon of the specified window.
//     If passed an array of candidate images, those of or closest to the sizes
//     desired by the system are selected.
//     If no images are specified, the window reverts to its default icon.
//
//     The desired image sizes varies depending on platform and system settings.
//     The selected images will be rescaled as needed.
//     Good sizes include 16x16, 32x32 and 48x48.
//
// As macOS windows don't have icons, SetWindowIcon doesn't work on macOS.
//
// SetWindowIcon doesn't work on browsers or mobiles.
//
// This function is concurrent-safe.
func SetWindowIcon(iconImages []image.Image) {
	ui.SetWindowIcon(iconImages)
}

// DeviceScaleFactor returns a device scale factor value.
//
// DeviceScaleFactor returns a meaningful value on high-DPI display environment,
// otherwise DeviceScaleFactor returns 1.
//
// This function is concurrent-safe.
func DeviceScaleFactor() float64 {
	return devicescale.DeviceScale()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	"github.com/nu7hatch/gouuid"
	"github.com/spf13/cobra"
	"gopkg.in/zabawaba99/firego.v1"

	docker "github.com/fsouza/go-dockerclient"
	log "github.com/sirupsen/logrus"
)

const (
	//VerboseFlag flag to set more verbose level
	VerboseFlag = "verbose"
	//EndpointFlag flag to set the endpoint to use (default: unix:///var/run/docker.sock)
	EndpointFlag = "endpoint"
	//EndpointEnv env to set endpoint of docker
	EndpointEnv = "DOCKER_HOST"
	//TimeoutFlag flag to set timeout period
	TimeoutFlag = "timeout"
	//TokenFlag flag to set firebase token
	TokenFlag = "token"
	//BaseURLFlag flag to set firebase url
	BaseURLFlag = "url"
	longHelp    = `
sca (Simple Collector Agent)
Collect local data and forward them to a realtime database.
== Version: %s - Hash: %s ==
`
)

var (
	//Version version of running code
	version = "testing" // By default use testing but will be set at build time on release -X main.version=v${VERSION}
	hash    = ""

	client *docker.Client

	authToken string
	baseURL   string

	timeout   time.Duration
	startTime = time.Now()

	cmd = &cobra.Command{
		Use:              "sca",
		Short:            "Simple Collector Agent",
		Long:             longHelp,
		PersistentPreRun: setupLogger,
	}
	infoCmd = &cobra.Command{
		Use:   "info",
		Short: "Display one-time collected informations in term for testing",
		Run: func(cmd *cobra.Command, args []string) {
			client := initClient(cmd, args)
			j, _ := json.MarshalIndent(getData(client), "", "  ")
			//j, _ := json.Marshal(getData(client))
			fmt.Println(string(j))
		},
	}
	daemonCmd = &cobra.Command{
		Use:   "daemon",
		Short: "Start collecting informations and send them to the remote database",
		Run:   startDaemon,
	}
	versionCmd = &cobra.Command{
		Use:   "version",
		Short: "Display current version and build date",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Version: %s - Hash: %s\n", version, hash)
		},
	}
)

func main() {
	setupFlags()
	//*
	h, err := getHash(os.Args[0])
	if err != nil {
		panic(err)
	}
	hash = h
	/**/
	cmd.Long = fmt.Sprintf(longHelp, version, hash)
	cmd.AddCommand(versionCmd, infoCmd, daemonCmd)
	cmd.Execute()
}

func setupFlags() {
	cmd.PersistentFlags().BoolP(VerboseFlag, "v", false, "Turns on verbose logging")
	cmd.PersistentFlags().StringP(EndpointFlag, "e", "unix:///var/run/docker.sock", "Docker endpoint.  Can also set default environment DOCKER_HOST")

	daemonCmd.Flags().DurationVarP(&timeout, TimeoutFlag, "r", 5*time.Minute, "Timeout before force refresh of collected data without event trigger during timeout period")
	daemonCmd.Flags().StringVarP(&authToken, TokenFlag, "t", "", "Firebase authentification token")
	daemonCmd.Flags().StringVarP(&baseURL, BaseURLFlag, "u", "", "Firebase base url")
	//TODO Setup a list modules to load like modules=host,collector,docker ...
	//TODO add flag to force UUID
}

func initClient(cmd *cobra.Command, args []string) *docker.Client {
	//TODO detect if remote and SSL
	endpoint := typeOrEnv(cmd, EndpointFlag, EndpointEnv)
	client, err := docker.NewClient(endpoint)
	if err != nil {
		panic(err)
	}
	return client
}
func getDockerData(client *docker.Client) *DockerResponse {

	//Get images
	imgs, err := client.ListImages(docker.ListImagesOptions{All: true})
	if err != nil {
		panic(err)
	}
	for id, i := range imgs {
		if len(i.Labels) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(i.Labels))
			for iid, val := range i.Labels {
				tmp[strings.Replace(iid, ".", "-", -1)] = val
			}
			imgs[id].Labels = tmp
		}
	}

	//Get container
	cnts, err := client.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		panic(err)
	}
	for id, c := range cnts {
		if len(c.Labels) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(c.Labels))
			for vid, val := range c.Labels {
				tmp[strings.Replace(vid, ".", "-", -1)] = val
			}
			cnts[id].Labels = tmp
		}
	}

	//Get volumes
	vols, err := client.ListVolumes(docker.ListVolumesOptions{})
	if err != nil {
		panic(err)
	}

	//Get server info
	info, err := client.Info()
	if err != nil {
		panic(err)
	}
	//Clean of . in key info.RegistryConfig.IndexConfigs
	tmp := make(map[string]*docker.IndexInfo, len(info.RegistryConfig.IndexConfigs))
	for id, conf := range info.RegistryConfig.IndexConfigs {
		tmp[strings.Replace(id, ".", "-", -1)] = conf
	}
	info.RegistryConfig.IndexConfigs = tmp

	//Get networks
	nets, err := client.ListNetworks()
	if err != nil {
		panic(err)
	}
	//Clean . in key of options
	for id, n := range nets {
		if len(n.Options) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(n.Options))
			for oid, opt := range n.Options {
				tmp[strings.Replace(oid, ".", "-", -1)] = opt
			}
			nets[id].Options = tmp
		}
	}

	return &DockerResponse{
		Info:       info,
		Containers: cnts,
		Images:     imgs,
		Volumes:    vols,
		Networks:   nets,
	}
}
func getCollectorData() *CollectorResponse {
	return &CollectorResponse{
		Version:   version,
		StartTime: startTime,
		Hash:      hash,
	}
}
func getHostData(client *docker.Client) *HostResponse {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	ifaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	ints := make([]InterfaceResponse, len(ifaces))
	for id, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			panic(err)
		}
		ints[id] = InterfaceResponse{
			Info:  i,
			Addrs: addrs,
		}
	}
	return &HostResponse{
		Name:       hostname,
		Interfaces: ints,
	}
}
func getData(client *docker.Client) *GlobalResponse {
	//TODO detect if docket and filter by modules list
	host := getHostData(client)
	u5, err := uuid.NewV5(uuid.NamespaceURL, []byte(host.Name)) //TODO better discriminate
	if err != nil {
		panic(err)
	}
	return &GlobalResponse{
		UUID:      u5.String(),
		Host:      host,
		Collector: getCollectorData(),
		Docker:    getDockerData(client),
	}
}
func startDaemon(cmd *cobra.Command, args []string) {
	if authToken == "" {
		panic(errors.New("You need to set a auth token"))
	}
	//TODO monitor event and update data
	client := initClient(cmd, args)
	data := getData(client)
	j, _ := json.Marshal(data)
	log.Debugln(string(j))

	f := firego.New(baseURL+"/"+data.UUID, nil)
	f.Auth(authToken)
	defer f.Unauth()
	if err := f.Set(data); err != nil {
		log.Fatal(err)
	}
	c := time.Tick(timeout)
	for now := range c {
		data = getData(client)
		j, _ := json.Marshal(data)
		//fmt.Printf("%v %s\n", now, string(j))
		log.Debugln(now, string(j))
		if err := f.Update(data); err != nil {
			log.Fatal(err)
		}
	}
	//func (c *Client) AddEventListener(listener chan<- *APIEvents) error
}
<commit_msg>Fix . key of json and invalide with firebase<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	"github.com/nu7hatch/gouuid"
	"github.com/spf13/cobra"
	"gopkg.in/zabawaba99/firego.v1"

	docker "github.com/fsouza/go-dockerclient"
	log "github.com/sirupsen/logrus"
)

const (
	//VerboseFlag flag to set more verbose level
	VerboseFlag = "verbose"
	//EndpointFlag flag to set the endpoint to use (default: unix:///var/run/docker.sock)
	EndpointFlag = "endpoint"
	//EndpointEnv env to set endpoint of docker
	EndpointEnv = "DOCKER_HOST"
	//TimeoutFlag flag to set timeout period
	TimeoutFlag = "timeout"
	//TokenFlag flag to set firebase token
	TokenFlag = "token"
	//BaseURLFlag flag to set firebase url
	BaseURLFlag = "url"
	longHelp    = `
sca (Simple Collector Agent)
Collect local data and forward them to a realtime database.
== Version: %s - Hash: %s ==
`
)

var (
	//Version version of running code
	version = "testing" // By default use testing but will be set at build time on release -X main.version=v${VERSION}
	hash    = ""

	client *docker.Client

	authToken string
	baseURL   string

	timeout   time.Duration
	startTime = time.Now()

	cmd = &cobra.Command{
		Use:              "sca",
		Short:            "Simple Collector Agent",
		Long:             longHelp,
		PersistentPreRun: setupLogger,
	}
	infoCmd = &cobra.Command{
		Use:   "info",
		Short: "Display one-time collected informations in term for testing",
		Run: func(cmd *cobra.Command, args []string) {
			client := initClient(cmd, args)
			j, _ := json.MarshalIndent(getData(client), "", "  ")
			//j, _ := json.Marshal(getData(client))
			fmt.Println(string(j))
		},
	}
	daemonCmd = &cobra.Command{
		Use:   "daemon",
		Short: "Start collecting informations and send them to the remote database",
		Run:   startDaemon,
	}
	versionCmd = &cobra.Command{
		Use:   "version",
		Short: "Display current version and build date",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Version: %s - Hash: %s\n", version, hash)
		},
	}
)

func main() {
	setupFlags()
	//*
	h, err := getHash(os.Args[0])
	if err != nil {
		panic(err)
	}
	hash = h
	/**/
	cmd.Long = fmt.Sprintf(longHelp, version, hash)
	cmd.AddCommand(versionCmd, infoCmd, daemonCmd)
	cmd.Execute()
}

func setupFlags() {
	cmd.PersistentFlags().BoolP(VerboseFlag, "v", false, "Turns on verbose logging")
	cmd.PersistentFlags().StringP(EndpointFlag, "e", "unix:///var/run/docker.sock", "Docker endpoint.  Can also set default environment DOCKER_HOST")

	daemonCmd.Flags().DurationVarP(&timeout, TimeoutFlag, "r", 5*time.Minute, "Timeout before force refresh of collected data without event trigger during timeout period")
	daemonCmd.Flags().StringVarP(&authToken, TokenFlag, "t", "", "Firebase authentification token")
	daemonCmd.Flags().StringVarP(&baseURL, BaseURLFlag, "u", "", "Firebase base url")
	//TODO Setup a list modules to load like modules=host,collector,docker ...
	//TODO add flag to force UUID
}

func initClient(cmd *cobra.Command, args []string) *docker.Client {
	//TODO detect if remote and SSL
	endpoint := typeOrEnv(cmd, EndpointFlag, EndpointEnv)
	client, err := docker.NewClient(endpoint)
	if err != nil {
		panic(err)
	}
	return client
}
func getDockerData(client *docker.Client) *DockerResponse {

	//Get images
	imgs, err := client.ListImages(docker.ListImagesOptions{All: true})
	if err != nil {
		panic(err)
	}
	for id, i := range imgs {
		if len(i.Labels) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(i.Labels))
			for iid, val := range i.Labels {
				tmp[strings.Replace(iid, ".", "-", -1)] = val
			}
			imgs[id].Labels = tmp
		}
	}

	//Get container
	cnts, err := client.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		panic(err)
	}
	for id, c := range cnts {
		if len(c.Labels) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(c.Labels))
			for vid, val := range c.Labels {
				tmp[strings.Replace(vid, ".", "-", -1)] = val
			}
			cnts[id].Labels = tmp
		}
	}

	//Get volumes
	vols, err := client.ListVolumes(docker.ListVolumesOptions{})
	if err != nil {
		panic(err)
	}

	//Get server info
	info, err := client.Info()
	if err != nil {
		panic(err)
	}
	//Clean of . in key info.RegistryConfig.IndexConfigs
	tmp := make(map[string]*docker.IndexInfo, len(info.RegistryConfig.IndexConfigs))
	for id, conf := range info.RegistryConfig.IndexConfigs {
		tmp[strings.Replace(id, ".", "-", -1)] = conf
	}
	info.RegistryConfig.IndexConfigs = tmp

	//Get networks
	nets, err := client.ListNetworks()
	if err != nil {
		panic(err)
	}
	//Clean . in key of options
	for id, n := range nets {
		if len(n.Options) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(n.Options))
			for oid, opt := range n.Options {
				tmp[strings.Replace(oid, ".", "-", -1)] = opt
			}
			nets[id].Options = tmp
		}
		if len(n.Labels) > 0 { //Reconstruct map without . in key
			tmp := make(map[string]string, len(n.Labels))
			for lid, val := range n.Labels {
				tmp[strings.Replace(lid, ".", "-", -1)] = val
			}
			nets[id].Labels = tmp
		}
	}

	return &DockerResponse{
		Info:       info,
		Containers: cnts,
		Images:     imgs,
		Volumes:    vols,
		Networks:   nets,
	}
}
func getCollectorData() *CollectorResponse {
	return &CollectorResponse{
		Version:   version,
		StartTime: startTime,
		Hash:      hash,
	}
}
func getHostData(client *docker.Client) *HostResponse {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	ifaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	ints := make([]InterfaceResponse, len(ifaces))
	for id, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			panic(err)
		}
		ints[id] = InterfaceResponse{
			Info:  i,
			Addrs: addrs,
		}
	}
	return &HostResponse{
		Name:       hostname,
		Interfaces: ints,
	}
}
func getData(client *docker.Client) *GlobalResponse {
	//TODO detect if docket and filter by modules list
	host := getHostData(client)
	u5, err := uuid.NewV5(uuid.NamespaceURL, []byte(host.Name)) //TODO better discriminate
	if err != nil {
		panic(err)
	}
	return &GlobalResponse{
		UUID:      u5.String(),
		Host:      host,
		Collector: getCollectorData(),
		Docker:    getDockerData(client),
	}
}
func startDaemon(cmd *cobra.Command, args []string) {
	if authToken == "" {
		panic(errors.New("You need to set a auth token"))
	}
	//TODO monitor event and update data
	client := initClient(cmd, args)
	data := getData(client)
	j, _ := json.Marshal(data)
	log.Debugln(string(j))

	f := firego.New(baseURL+"/"+data.UUID, nil)
	f.Auth(authToken)
	defer f.Unauth()
	if err := f.Set(data); err != nil {
		log.Fatal(err)
	}
	c := time.Tick(timeout)
	for now := range c {
		data = getData(client)
		j, _ := json.Marshal(data)
		//fmt.Printf("%v %s\n", now, string(j))
		log.Debugln(now, string(j))
		if err := f.Update(data); err != nil {
			log.Fatal(err)
		}
	}
	//func (c *Client) AddEventListener(listener chan<- *APIEvents) error
}
<|endoftext|>


<commit_before>package tfjson

// Action is a valid action type for a resource change.
//
// Note that a singular Action is not telling of a full resource
// change operation. Certain resource actions, such as replacement,
// are a composite of more than one type. See the Actions type and
// its helpers for more information.
type Action string

const (
	// ActionNoop denotes a no-op operation.
	ActionNoop Action = "NoOp"

	// ActionCreate denotes a create operation.
	ActionCreate Action = "Create"

	// ActionRead denotes a read operation.
	ActionRead Action = "Read"

	// ActionUpdate denotes an update operation.
	ActionUpdate Action = "Update"

	// ActionDelete denotes a delete operation.
	ActionDelete Action = "Delete"

	// ActionDeleteThenCreate denotes a standard replacement operation
	// (destroy before create).
	ActionDeleteThenCreate Action = "DeleteThenCreate"

	// ActionCreateThenDelete denotes a create-before-destroy replacement
	// operation (destroy before create, usually a result of specifying
	// create_before_destroy).
	ActionCreateThenDelete Action = "DeleteThenCreate"
)

// Actions denotes a valid change type.
type Actions []Action

// NoOp is true if this set of Actions denotes a no-op.
func (a Actions) NoOp() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionNoop
}

// Create is true if this set of Actions denotes creation of a new
// resource.
func (a Actions) Create() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionCreate
}

// Read is true if this set of Actions denotes a read operation only.
func (a Actions) Read() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionRead
}

// Update is true if this set of Actions denotes an update operation.
func (a Actions) Update() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionUpdate
}

// Delete is true if this set of Actions denotes resource removal.
func (a Actions) Delete() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionDelete
}

// DestroyBeforeCreate is true if this set of Actions denotes a
// destroy-before-create operation. This is the standard resource
// replacement method.
func (a Actions) DestroyBeforeCreate() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionDeleteThenCreate
}

// CreateBeforeDestroy is true if this set of Actions denotes a
// create-before-destroy operation, usually the result of replacement
// to a resource that has the create_before_destroy lifecycle option
// set.
func (a Actions) CreateBeforeDestroy() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionCreateThenDelete
}

// Replace is true if this set of Actions denotes a valid replacement
// operation.
func (a Actions) Replace() bool {
	return a.DestroyBeforeCreate() || a.CreateBeforeDestroy()
}
<commit_msg>Adjust action messaging to canonical format<commit_after>package tfjson

// Action is a valid action type for a resource change.
//
// Note that a singular Action is not telling of a full resource
// change operation. Certain resource actions, such as replacement,
// are a composite of more than one type. See the Actions type and
// its helpers for more information.
type Action string

const (
	// ActionNoop denotes a no-op operation.
	ActionNoop Action = "no-op"

	// ActionCreate denotes a create operation.
	ActionCreate Action = "create"

	// ActionRead denotes a read operation.
	ActionRead Action = "read"

	// ActionUpdate denotes an update operation.
	ActionUpdate Action = "update"

	// ActionDelete denotes a delete operation.
	ActionDelete Action = "delete"
)

// Actions denotes a valid change type.
type Actions []Action

// NoOp is true if this set of Actions denotes a no-op.
func (a Actions) NoOp() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionNoop
}

// Create is true if this set of Actions denotes creation of a new
// resource.
func (a Actions) Create() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionCreate
}

// Read is true if this set of Actions denotes a read operation only.
func (a Actions) Read() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionRead
}

// Update is true if this set of Actions denotes an update operation.
func (a Actions) Update() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionUpdate
}

// Delete is true if this set of Actions denotes resource removal.
func (a Actions) Delete() bool {
	if len(a) != 1 {
		return false
	}

	return a[0] == ActionDelete
}

// DestroyBeforeCreate is true if this set of Actions denotes a
// destroy-before-create operation. This is the standard resource
// replacement method.
func (a Actions) DestroyBeforeCreate() bool {
	if len(a) != 2 {
		return false
	}

	return a[0] == ActionDelete && a[1] == ActionCreate
}

// CreateBeforeDestroy is true if this set of Actions denotes a
// create-before-destroy operation, usually the result of replacement
// to a resource that has the create_before_destroy lifecycle option
// set.
func (a Actions) CreateBeforeDestroy() bool {
	if len(a) != 2 {
		return false
	}

	return a[0] == ActionCreate && a[1] == ActionDelete
}

// Replace is true if this set of Actions denotes a valid replacement
// operation.
func (a Actions) Replace() bool {
	return a.DestroyBeforeCreate() || a.CreateBeforeDestroy()
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/hex"
	"io"
	"net/http"
)

// putAuthorizationRequest generates a request to add new authorization
// data to the server
func (c *Client) putAuthorizationRequest(
	pubKey *[PublicKeySize]byte,
	authorizationReader io.Reader,
) (*http.Request, error) {
	pubKeyString := hex.EncodeToString(pubKey[:])

	req, err := http.NewRequest(
		"PUT",
		c.BaseURL+"/authorizations/"+pubKeyString,
		authorizationReader,
	)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/octet-stream")
	SignWithKey(req, c.signingPrivateKey)
	return req, nil
}

// PutAuthorization adds a new authorization assignment
// for the passed public key to the server.
func (c *Client) PutAuthorization(
	pubKey *[PublicKeySize]byte,
	authorizationReader io.Reader,
) error {
	req, err := c.putAuthorizationRequest(pubKey, authorizationReader)
	if err != nil {
		return err
	}

	_, err = c.doRequest(req, http.StatusOK, http.StatusCreated)
	return err
}
<commit_msg>api: added requests to get authorization data from the server.<commit_after>package api

import (
	"encoding/hex"
	"io"
	"net/http"
)

// putAuthorizationRequest generates a request to add new authorization
// data to the server
func (c *Client) putAuthorizationRequest(
	pubKey *[PublicKeySize]byte,
	authorizationReader io.Reader,
) (*http.Request, error) {
	pubKeyString := hex.EncodeToString(pubKey[:])

	req, err := http.NewRequest(
		"PUT",
		c.BaseURL+"/authorizations/"+pubKeyString,
		authorizationReader,
	)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/octet-stream")
	SignWithKey(req, c.signingPrivateKey)
	return req, nil
}

// PutAuthorization adds a new authorization assignment
// for the passed public key to the server.
func (c *Client) PutAuthorization(
	pubKey *[PublicKeySize]byte,
	authorizationReader io.Reader,
) error {
	req, err := c.putAuthorizationRequest(pubKey, authorizationReader)
	if err != nil {
		return err
	}

	_, err = c.doRequest(req, http.StatusOK, http.StatusCreated)
	return err
}

// getAuthorizationRequest generates a request to request a authorization
// from the server.
func (c *Client) getAuthorizationRequest(authorizationURL string,
	authPrivKey [PrivateKeySize]byte,) (*http.Request, error) {
	req, err := http.NewRequest(
		"GET",
		authorizationURL,
		nil,
	)
	if err != nil {
		return nil, err
	}

	SignWithKey(req, authPrivKey)
	return req, nil
}

func (c *Client) GetAuthorization(authorizationURL string,
	authPrivKey [PrivateKeySize]byte,) (io.Reader, error) {
	req, err := c.getAuthorizationRequest(authorizationURL, authPrivKey)
	if err != nil {
		return nil, err
	}

	resp, err := c.doRequest(req, http.StatusOK)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}
<|endoftext|>


<commit_before>package response

import (
	"math"
	"testing"

	"github.com/raintank/metrictank/api/models"
	"gopkg.in/raintank/schema.v1"
)

func BenchmarkHttpRespPickleEmptySeries(b *testing.B) {
	data := []models.Series{
		{
			Target:     "an.empty.series",
			Datapoints: make([]schema.Point, 0),
			Interval:   10,
		},
	}
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleEmptySeriesNeedsEscaping(b *testing.B) {
	data := []models.Series{
		{
			Target:     `an.empty\series`,
			Datapoints: make([]schema.Point, 0),
			Interval:   10,
		},
	}
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleIntegers(b *testing.B) {
	points := make([]schema.Point, 1000, 1000)
	baseTs := 1500000000
	for i := 0; i < 1000; i++ {
		points[i] = schema.Point{Val: float64(10000 * i), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "some.metric.with.a-whole-bunch-of.integers",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleFloats(b *testing.B) {
	points := make([]schema.Point, 1000, 1000)
	baseTs := 1500000000
	for i := 0; i < 1000; i++ {
		points[i] = schema.Point{Val: 12.34 * float64(i), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "some.metric.with.a-whole-bunch-of.floats",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleNulls(b *testing.B) {
	points := make([]schema.Point, 1000, 1000)
	baseTs := 1500000000
	for i := 0; i < 1000; i++ {
		points[i] = schema.Point{Val: math.NaN(), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "some.metric.with.a-whole-bunch-of.nulls",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}
<commit_msg>benchmark conversion of series to seriesForPickle format<commit_after>package response

import (
	"math"
	"testing"

	"github.com/raintank/metrictank/api/models"
	"gopkg.in/raintank/schema.v1"
)

func BenchmarkHttpRespPickleEmptySeries(b *testing.B) {
	data := []models.Series{
		{
			Target:     "an.empty.series",
			Datapoints: make([]schema.Point, 0),
			Interval:   10,
		},
	}
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleEmptySeriesNeedsEscaping(b *testing.B) {
	data := []models.Series{
		{
			Target:     `an.empty\series`,
			Datapoints: make([]schema.Point, 0),
			Interval:   10,
		},
	}
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleIntegers(b *testing.B) {
	points := make([]schema.Point, 1000, 1000)
	baseTs := 1500000000
	for i := 0; i < 1000; i++ {
		points[i] = schema.Point{Val: float64(10000 * i), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "some.metric.with.a-whole-bunch-of.integers",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleFloats(b *testing.B) {
	points := make([]schema.Point, 1000, 1000)
	baseTs := 1500000000
	for i := 0; i < 1000; i++ {
		points[i] = schema.Point{Val: 12.34 * float64(i), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "some.metric.with.a-whole-bunch-of.floats",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

func BenchmarkHttpRespPickleNulls(b *testing.B) {
	points := make([]schema.Point, 1000, 1000)
	baseTs := 1500000000
	for i := 0; i < 1000; i++ {
		points[i] = schema.Point{Val: math.NaN(), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "some.metric.with.a-whole-bunch-of.nulls",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var resp *Pickle
	for n := 0; n < b.N; n++ {
		resp = NewPickle(200, models.SeriesPickleFormat(data))
		resp.Body()
		resp.Close()
	}
}

var foo []models.SeriesForPickle

func BenchmarkConvertSeriesToPickleFormat10k(b *testing.B) {
	points := make([]schema.Point, 10000)
	baseTs := 1500000000
	for i := 0; i < 10000; i++ {
		points[i] = schema.Point{Val: 1.2345 * float64(i), Ts: uint32(baseTs + 10*i)}
	}
	data := []models.Series{
		{
			Target:     "foo",
			Datapoints: points,
			Interval:   10,
		},
	}
	b.SetBytes(int64(len(points) * 12))

	b.ResetTimer()
	var bar []models.SeriesForPickle
	for n := 0; n < b.N; n++ {
		bar = models.SeriesPickleFormat(data)
	}
	foo = bar
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"encoding/json"
	"net/http"
	"os"
	"strings"
	"time"

	"cloud.google.com/go/datastore"
	"cloud.google.com/go/errors"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

type Entry struct {
	Value   string    `datastore:"value"`
	Created time.Time `datastore:"created"`
}

var (
	datastoreClient *datastore.Client
	projectID       string
)

func ListRangeHandler(rw http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["key"]

	var entries []*Entry

	query := datastore.NewQuery(key).Order("created")
	_, err := datastoreClient.GetAll(context.Background(), query, &entries)
	if err != nil {
		panic(err)
	}

	membersJSON := PanicOnError(json.MarshalIndent(entries, "", "  ")).([]byte)
	PanicOnError(rw.Write(membersJSON))
}

func ListPushHandler(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	// Bug:
	key := vars["k"]
	value := vars["v"]
	// Functional code:
	// key := vars["key"]
	// value := vars["value"]

	if key == "" || value == "" {
		panic("error: can not store empty values")
	}

	newEntry := &Entry{
		Value:   value,
		Created: time.Now(),
	}

	datastoreKey := datastore.IncompleteKey(key, nil)
	_, err := datastoreClient.Put(context.Background(), datastoreKey, newEntry)
	if err != nil {
		panic(err)
	}

	ListRangeHandler(rw, req)
}

func InfoHandler(rw http.ResponseWriter, req *http.Request) {
}

func EnvHandler(rw http.ResponseWriter, req *http.Request) {
	environment := make(map[string]string)
	for _, item := range os.Environ() {
		splits := strings.Split(item, "=")
		key := splits[0]
		val := strings.Join(splits[1:], "=")
		environment[key] = val
	}

	var output []byte
	output = append(output, []byte("Environment:\n")...)
	envJSON := PanicOnError(json.MarshalIndent(environment, "", "  ")).([]byte)
	output = append(output, envJSON...)
	output = append(output, []byte("\nRequest:\n")...)
	reqJSON := PanicOnError(json.MarshalIndent(req.Header, "", "  ")).([]byte)
	output = append(output, reqJSON...)
	PanicOnError(rw.Write(output))
}

func PanicOnError(result interface{}, err error) (r interface{}) {
	if err != nil {
		panic(err)
	}
	return result
}

var errorsClient *errors.Client

type ErrorsMiddleware struct{}

func (l *ErrorsMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
	defer errorsClient.Catch(context.Background(), errors.WithRequest(req))
	if next != nil {
		next(w, req)
	}
}

func main() {
	projectID = os.Getenv("GOOGLE_PROJECT")
	if projectID == "" {
		panic("Please set the env variable GOOGLE_PROJECT in manifest.yml to a project with Google Cloud Datastore and Stackdriver Error Reporting enabled")
	}

	ctx := context.Background()
	errorsClient = PanicOnError(errors.NewClient(ctx, projectID, "cf-stackdriver-example", "0.0.1", true)).(*errors.Client)

	var err error
	datastoreClient, err = datastore.NewClient(context.Background(), projectID)
	if err != nil {
		panic("error connecting to the Google Cloud Datastore. Does this project have an App Engine App? see: https://cloud.google.com/datastore/docs/activate")
	}

	r := mux.NewRouter()
	r.Path("/lrange/{key}").Methods("GET").HandlerFunc(ListRangeHandler)
	r.Path("/rpush/{key}/{value}").Methods("GET").HandlerFunc(ListPushHandler)
	r.Path("/info").Methods("GET").HandlerFunc(InfoHandler)
	r.Path("/env").Methods("GET").HandlerFunc(EnvHandler)

	n := negroni.Classic()
	n.Use(&ErrorsMiddleware{})
	n.UseHandler(r)
	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}

	if err := http.ListenAndServe(":"+port, n); err != nil {
		panic(err)
	}
}
<commit_msg>Small go style edit in example app<commit_after>/*
Copyright 2014 The Kubernetes Authors.
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"encoding/json"
	"net/http"
	"os"
	"strings"
	"time"

	"cloud.google.com/go/datastore"
	"cloud.google.com/go/errors"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

type Entry struct {
	Value   string    `datastore:"value"`
	Created time.Time `datastore:"created"`
}

var (
	datastoreClient *datastore.Client
	projectID       string
)

func ListRangeHandler(rw http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["key"]

	var entries []*Entry

	query := datastore.NewQuery(key).Order("created")
	_, err := datastoreClient.GetAll(context.Background(), query, &entries)
	if err != nil {
		panic(err)
	}

	membersJSON := PanicOnError(json.MarshalIndent(entries, "", "  ")).([]byte)
	PanicOnError(rw.Write(membersJSON))
}

func ListPushHandler(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	// Bug:
	key := vars["k"]
	value := vars["v"]
	// Functional code:
	// key := vars["key"]
	// value := vars["value"]

	if key == "" || value == "" {
		panic("error: can not store empty values")
	}

	newEntry := &Entry{
		Value:   value,
		Created: time.Now(),
	}

	datastoreKey := datastore.IncompleteKey(key, nil)
	_, err := datastoreClient.Put(context.Background(), datastoreKey, newEntry)
	if err != nil {
		panic(err)
	}

	ListRangeHandler(rw, req)
}

func InfoHandler(_ http.ResponseWriter, _ *http.Request) {
}

func EnvHandler(rw http.ResponseWriter, req *http.Request) {
	environment := make(map[string]string)
	for _, item := range os.Environ() {
		splits := strings.Split(item, "=")
		key := splits[0]
		val := strings.Join(splits[1:], "=")
		environment[key] = val
	}

	var output []byte
	output = append(output, []byte("Environment:\n")...)
	envJSON := PanicOnError(json.MarshalIndent(environment, "", "  ")).([]byte)
	output = append(output, envJSON...)
	output = append(output, []byte("\nRequest:\n")...)
	reqJSON := PanicOnError(json.MarshalIndent(req.Header, "", "  ")).([]byte)
	output = append(output, reqJSON...)
	PanicOnError(rw.Write(output))
}

func PanicOnError(result interface{}, err error) (r interface{}) {
	if err != nil {
		panic(err)
	}
	return result
}

var errorsClient *errors.Client

type ErrorsMiddleware struct{}

func (l *ErrorsMiddleware) ServeHTTP(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
	defer errorsClient.Catch(context.Background(), errors.WithRequest(req))
	if next != nil {
		next(w, req)
	}
}

func main() {
	projectID = os.Getenv("GOOGLE_PROJECT")
	if projectID == "" {
		panic("Please set the env variable GOOGLE_PROJECT in manifest.yml to a project with Google Cloud Datastore and Stackdriver Error Reporting enabled")
	}

	ctx := context.Background()
	errorsClient = PanicOnError(errors.NewClient(ctx, projectID, "cf-stackdriver-example", "0.0.1", true)).(*errors.Client)

	var err error
	datastoreClient, err = datastore.NewClient(context.Background(), projectID)
	if err != nil {
		panic("error connecting to the Google Cloud Datastore. Does this project have an App Engine App? see: https://cloud.google.com/datastore/docs/activate")
	}

	r := mux.NewRouter()
	r.Path("/lrange/{key}").Methods("GET").HandlerFunc(ListRangeHandler)
	r.Path("/rpush/{key}/{value}").Methods("GET").HandlerFunc(ListPushHandler)
	r.Path("/info").Methods("GET").HandlerFunc(InfoHandler)
	r.Path("/env").Methods("GET").HandlerFunc(EnvHandler)

	n := negroni.Classic()
	n.Use(&ErrorsMiddleware{})
	n.UseHandler(r)
	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}

	if err := http.ListenAndServe(":"+port, n); err != nil {
		panic(err)
	}
}
<|endoftext|>