<commit_before>package mchan

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"gopkg.in/logex.v1"

	"github.com/chzyer/flow"
	"github.com/chzyer/next/util/clock"
)

type Server struct {
	cfg    *SvrConf
	flow   *flow.Flow
	key    []byte
	server *http.Server
	ct     *clock.Clock
	router map[string]HandlerFunc
}

type SvrConf struct {
	CertFile string
	KeyFile  string
}

func NewServer(f *flow.Flow, listen string, ct *clock.Clock, key []byte, cfg *SvrConf) *Server {
	httpserver := &http.Server{
		Addr:           listen,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 10,
	}
	httpserver.SetKeepAlivesEnabled(false)
	svr := &Server{
		flow:   f,
		cfg:    cfg,
		key:    key,
		server: httpserver,
		ct:     ct,
		router: make(map[string]HandlerFunc),
	}
	svr.server.Handler = svr
	return svr
}

type Req struct {
	payload []byte
}

func (r *Req) Unmarshal(obj interface{}) error {
	return json.Unmarshal(r.payload, obj)
}

type HandlerFunc func(*Req) interface{}

func (s *Server) HandleFunc(path string, f HandlerFunc) {
	s.router[path] = f
}

func (s *Server) DecodeRequest(w http.ResponseWriter, body []byte) error {
	reply, err := Decode(s.key, body)
	if err != nil {
		return err
	}
	if f := s.router[reply.Path]; f != nil {
		ret := f(&Req{reply.Payload})
		if ret == nil {
			return nil
		}
		switch t := ret.(type) {
		case error:
			w.Write(ReplyError(s.key, t))
		default:
			w.Write(Reply(s.key, ret))
		}
		return nil
	}
	return fmt.Errorf("not found")
}

func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		logex.Error(err)
		return
	}
	if err := s.DecodeRequest(w, body); err == nil {
		return
	}

	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(`
		<title>Hello World!</title>

Hello

`))
}

func (s *Server) Run() error {
	return s.server.ListenAndServe()
}
<commit_msg>add warn<commit_after>package mchan

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"gopkg.in/logex.v1"

	"github.com/chzyer/flow"
	"github.com/chzyer/next/util/clock"
)

type Server struct {
	cfg    *SvrConf
	flow   *flow.Flow
	key    []byte
	server *http.Server
	ct     *clock.Clock
	router map[string]HandlerFunc
}

type SvrConf struct {
	CertFile string
	KeyFile  string
}

func NewServer(f *flow.Flow, listen string, ct *clock.Clock, key []byte, cfg *SvrConf) *Server {
	httpserver := &http.Server{
		Addr:           listen,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 10,
	}
	httpserver.SetKeepAlivesEnabled(false)
	svr := &Server{
		flow:   f,
		cfg:    cfg,
		key:    key,
		server: httpserver,
		ct:     ct,
		router: make(map[string]HandlerFunc),
	}
	svr.server.Handler = svr
	return svr
}

type Req struct {
	payload []byte
}

func (r *Req) Unmarshal(obj interface{}) error {
	return json.Unmarshal(r.payload, obj)
}

type HandlerFunc func(*Req) interface{}

func (s *Server) HandleFunc(path string, f HandlerFunc) {
	s.router[path] = f
}

func (s *Server) DecodeRequest(w http.ResponseWriter, body []byte) error {
	reply, err := Decode(s.key, body)
	if err != nil {
		return err
	}
	if f := s.router[reply.Path]; f != nil {
		ret := f(&Req{reply.Payload})
		if ret == nil {
			return nil
		}
		switch t := ret.(type) {
		case error:
			w.Write(ReplyError(s.key, t))
		default:
			w.Write(Reply(s.key, ret))
		}
		return nil
	}
	return fmt.Errorf("not found")
}

func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		logex.Error(err)
		return
	}
	if err := s.DecodeRequest(w, body); err == nil {
		return
	}
	logex.Warn("invalid request from:", req.RemoteAddr)

	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(`
		<title>Hello World!</title>

Hello

`))
}

func (s *Server) Run() error {
	return s.server.ListenAndServe()
}
<|endoftext|>


<commit_before>package md5

import (
	"testing"
)

func TestMd5sumFile(t *testing.T) {
	file := "/home/jerry/Downloads/ubuntu-gnome-14.10-desktop-i386.iso"

	md5sum, error := MD5sum(file)
	if error != nil || md5sum != "8041c76ef092626f4564baa0ffb595b6" {
		t.Error("Md5sum(file) failed", md5sum, error)
	}
}

func TestMd5sumDir(t *testing.T) {
	file := "/home/jerry/Downloads"

	md5sum, error := MD5sum(file)
	if error != nil || md5sum != "" {
		t.Error("Md5sum(dir) failed", md5sum, error)
	}
}
<commit_msg>change package for test<commit_after>package md5_test

import (
	"github.com/codingsince1985/checksum/md5"
	"testing"
)

func TestMd5sumFile(t *testing.T) {
	file := "/home/jerry/Downloads/ubuntu-gnome-14.10-desktop-i386.iso"

	md5sum, error := md5.MD5sum(file)
	if error != nil || md5sum != "8041c76ef092626f4564baa0ffb595b6" {
		t.Error("Md5sum(file) failed", md5sum, error)
	}
}

func TestMd5sumDir(t *testing.T) {
	file := "/home/jerry/Downloads"

	md5sum, error := md5.MD5sum(file)
	if error != nil || md5sum != "" {
		t.Error("Md5sum(dir) failed", md5sum, error)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/wader/ydls/ydls"
)

var infoFlag = flag.Bool("info", false, "info output")
var debugFlag = flag.Bool("debug", false, "debug output")
var formatsFlag = flag.String("formats", "formats.json", "formats config file")
var indexFlag = flag.String("index", "", "index html template")
var listenFlag = flag.String("listen", ":8080", "listen address")

var infoLog = log.New(ioutil.Discard, "INFO: ", log.Ltime)
var debugLog = log.New(ioutil.Discard, "DEBUG: ", log.Ltime)

func init() {
	flag.Parse()

	if os.Getenv("DEBUG") != "" {
		*debugFlag = true
	}
	if *infoFlag {
		infoLog.SetOutput(os.Stdout)
	}
	if *debugFlag {
		debugLog.SetOutput(os.Stdout)
	}
}

// URL encode with space encoded as "%20"
func urlEncode(s string) string {
	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
}

// make string safe to use in non-encoded content disposition filename
func contentDispositionFilename(s string) string {
	rs := []rune(s)
	for i, r := range rs {
		if r < 0x20 || r > 0x7e || r == '"' || r == '/' || r == '\\' {
			rs[i] = '_'
		}
	}

	return string(rs)
}

func splitRequestURL(URL *url.URL) (format string, urlStr string) {
	if URL.Query().Get("url") != "" {
		// ?url=url&format=format
		return URL.Query().Get("format"), URL.Query().Get("url")
	}

	// /format/schema://host.domin/path?query
	// /format/host.domain/path?query
	// /schema://host.domain/path?query
	// /host.domain/path?query

	parts := strings.SplitN(URL.Path, "/", 3)
	// parts[0] always empty, path always starts with /
	parts = parts[1:]

	// format? part does not contains ":" or "."
	if !strings.Contains(parts[0], ":") && !strings.Contains(parts[0], ".") {
		format = parts[0]
		parts = parts[1:]
	}

	if len(parts) == 0 {
		return "", ""
	}

	if len(parts) == 2 {
		// had schema:// but split has removed one /
		return format, parts[0] + "/" + parts[1] + "?" + URL.RawQuery

	}

	return format, parts[0] + "?" + URL.RawQuery
}

func parseFormatDownloadURL(URL *url.URL) (format string, downloadURL *url.URL) {
	var urlStr string
	format, urlStr = splitRequestURL(URL)

	if !strings.HasPrefix(urlStr, "http://") && !strings.HasPrefix(urlStr, "https://") {
		urlStr = "http://" + urlStr
	}

	downloadURL, err := url.Parse(urlStr)
	if err != nil {
		return "", nil
	}

	if downloadURL.Host == "" {
		return "", nil
	}

	if downloadURL.Host == "" ||
		(downloadURL.Scheme != "http" && downloadURL.Scheme != "https") {
		return "", nil
	}

	return format, downloadURL
}

type ydlsHandler struct {
	ydls      *ydls.YDLs
	indexTmpl *template.Template
}

func (yh *ydlsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("X-Content-Type-Options", "nosniff")

	debugLog.Printf("%s Request %s %s", r.RemoteAddr, r.Method, r.URL.String())

	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	if r.URL.Path == "/" && r.URL.RawQuery == "" {
		if yh.indexTmpl != nil {
			w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'unsafe-inline'; form-action 'self'; reflected-xss block")
			yh.indexTmpl.Execute(w, yh.ydls.Formats)
		} else {
			http.Error(w, "Not found", http.StatusNotFound)
		}
		return
	} else if r.URL.Path == "/favicon.ico" {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}

	formatName, downloadURL := parseFormatDownloadURL(r.URL)
	if downloadURL == nil {
		infoLog.Printf("%s Invalid request %s %s", r.RemoteAddr, r.Method, r.URL.Path)
		http.Error(w, "Invalid URL", http.StatusBadRequest)
		return
	}

	fancyFormatName := "best"
	if formatName != "" {
		fancyFormatName = formatName
	}
	infoLog.Printf("%s Downloading (%s) %s", r.RemoteAddr, fancyFormatName, downloadURL)

	mediaReader, filename, mimeType, err := yh.ydls.Download(downloadURL.String(), formatName, debugLog)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer mediaReader.Close()

	w.Header().Set("Content-Security-Policy", "default-src 'none'; reflected-xss block")
	w.Header().Set("Content-Type", mimeType)
	w.Header().Set("Content-Disposition",
		fmt.Sprintf("attachment; filename*=UTF-8''%s; filename=\"%s\"",
			urlEncode(filename), contentDispositionFilename(filename)),
	)

	io.Copy(w, mediaReader)
}

func main() {
	var yh ydlsHandler
	var err error

	yh.ydls, err = ydls.NewFromFile(*formatsFlag)
	if err != nil {
		log.Fatalf("failed to read formats: %s", err)
	}

	if *indexFlag != "" {
		yh.indexTmpl, err = template.ParseFiles(*indexFlag)
		if err != nil {
			log.Fatalf("failed to parse index template: %s", err)
		}
	}

	log.Printf("service listen on %s", *listenFlag)
	log.Fatal(http.ListenAndServe(*listenFlag, &yh))
}
<commit_msg>Remove redundant downloadURL.Host check<commit_after>package main

import (
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/wader/ydls/ydls"
)

var infoFlag = flag.Bool("info", false, "info output")
var debugFlag = flag.Bool("debug", false, "debug output")
var formatsFlag = flag.String("formats", "formats.json", "formats config file")
var indexFlag = flag.String("index", "", "index html template")
var listenFlag = flag.String("listen", ":8080", "listen address")

var infoLog = log.New(ioutil.Discard, "INFO: ", log.Ltime)
var debugLog = log.New(ioutil.Discard, "DEBUG: ", log.Ltime)

func init() {
	flag.Parse()

	if os.Getenv("DEBUG") != "" {
		*debugFlag = true
	}
	if *infoFlag {
		infoLog.SetOutput(os.Stdout)
	}
	if *debugFlag {
		debugLog.SetOutput(os.Stdout)
	}
}

// URL encode with space encoded as "%20"
func urlEncode(s string) string {
	return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
}

// make string safe to use in non-encoded content disposition filename
func contentDispositionFilename(s string) string {
	rs := []rune(s)
	for i, r := range rs {
		if r < 0x20 || r > 0x7e || r == '"' || r == '/' || r == '\\' {
			rs[i] = '_'
		}
	}

	return string(rs)
}

func splitRequestURL(URL *url.URL) (format string, urlStr string) {
	if URL.Query().Get("url") != "" {
		// ?url=url&format=format
		return URL.Query().Get("format"), URL.Query().Get("url")
	}

	// /format/schema://host.domin/path?query
	// /format/host.domain/path?query
	// /schema://host.domain/path?query
	// /host.domain/path?query

	parts := strings.SplitN(URL.Path, "/", 3)
	// parts[0] always empty, path always starts with /
	parts = parts[1:]

	// format? part does not contains ":" or "."
	if !strings.Contains(parts[0], ":") && !strings.Contains(parts[0], ".") {
		format = parts[0]
		parts = parts[1:]
	}

	if len(parts) == 0 {
		return "", ""
	}

	if len(parts) == 2 {
		// had schema:// but split has removed one /
		return format, parts[0] + "/" + parts[1] + "?" + URL.RawQuery

	}

	return format, parts[0] + "?" + URL.RawQuery
}

func parseFormatDownloadURL(URL *url.URL) (format string, downloadURL *url.URL) {
	var urlStr string
	format, urlStr = splitRequestURL(URL)

	if !strings.HasPrefix(urlStr, "http://") && !strings.HasPrefix(urlStr, "https://") {
		urlStr = "http://" + urlStr
	}

	downloadURL, err := url.Parse(urlStr)
	if err != nil {
		return "", nil
	}

	if downloadURL.Host == "" ||
		(downloadURL.Scheme != "http" && downloadURL.Scheme != "https") {
		return "", nil
	}

	return format, downloadURL
}

type ydlsHandler struct {
	ydls      *ydls.YDLs
	indexTmpl *template.Template
}

func (yh *ydlsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("X-Content-Type-Options", "nosniff")

	debugLog.Printf("%s Request %s %s", r.RemoteAddr, r.Method, r.URL.String())

	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	if r.URL.Path == "/" && r.URL.RawQuery == "" {
		if yh.indexTmpl != nil {
			w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'unsafe-inline'; form-action 'self'; reflected-xss block")
			yh.indexTmpl.Execute(w, yh.ydls.Formats)
		} else {
			http.Error(w, "Not found", http.StatusNotFound)
		}
		return
	} else if r.URL.Path == "/favicon.ico" {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}

	formatName, downloadURL := parseFormatDownloadURL(r.URL)
	if downloadURL == nil {
		infoLog.Printf("%s Invalid request %s %s", r.RemoteAddr, r.Method, r.URL.Path)
		http.Error(w, "Invalid URL", http.StatusBadRequest)
		return
	}

	fancyFormatName := "best"
	if formatName != "" {
		fancyFormatName = formatName
	}
	infoLog.Printf("%s Downloading (%s) %s", r.RemoteAddr, fancyFormatName, downloadURL)

	mediaReader, filename, mimeType, err := yh.ydls.Download(downloadURL.String(), formatName, debugLog)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer mediaReader.Close()

	w.Header().Set("Content-Security-Policy", "default-src 'none'; reflected-xss block")
	w.Header().Set("Content-Type", mimeType)
	w.Header().Set("Content-Disposition",
		fmt.Sprintf("attachment; filename*=UTF-8''%s; filename=\"%s\"",
			urlEncode(filename), contentDispositionFilename(filename)),
	)

	io.Copy(w, mediaReader)
}

func main() {
	var yh ydlsHandler
	var err error

	yh.ydls, err = ydls.NewFromFile(*formatsFlag)
	if err != nil {
		log.Fatalf("failed to read formats: %s", err)
	}

	if *indexFlag != "" {
		yh.indexTmpl, err = template.ParseFiles(*indexFlag)
		if err != nil {
			log.Fatalf("failed to parse index template: %s", err)
		}
	}

	log.Printf("service listen on %s", *listenFlag)
	log.Fatal(http.ListenAndServe(*listenFlag, &yh))
}
<|endoftext|>


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

package io

import (
	"os";
	"syscall";
)

var ErrEOF = os.NewError("EOF")

type Read interface {
	Read(p []byte) (n int, err *os.Error);
}

type Write interface {
	Write(p []byte) (n int, err *os.Error);
}

type Close interface {
	Close() *os.Error;
}

type ReadWrite interface {
	Read;
	Write;
}

type ReadClose interface {
	Read;
	Close;
}

type WriteClose interface {
	Write;
	Close;
}

type ReadWriteClose interface {
	Read;
	Write;
	Close;
}

// Convert a string to an array of bytes for easy marshaling.
// Could fill with syscall.StringToBytes but it adds an unnecessary \000
// so the length would be wrong.
func StringBytes(s string) []byte {
	b := make([]byte, len(s));
	for i := 0; i < len(s); i++ {
		b[i] = s[i];
	}
	return b;
}

func WriteString(w Write, s string) (n int, err *os.Error) {
	return w.Write(StringBytes(s))
}

// Read until buffer is full, EOF, or error
func Readn(fd Read, buf []byte) (n int, err *os.Error) {
	n = 0;
	for n < len(buf) {
		nn, e := fd.Read(buf[n:len(buf)]);
		if nn > 0 {
			n += nn
		}
		if e != nil {
			return n, e
		}
		if nn <= 0 {
			return n, ErrEOF	// no error but insufficient data
		}
	}
	return n, nil
}

// Convert something that implements Read into something
// whose Reads are always Readn
type fullRead struct {
	fd	Read;
}

func (fd *fullRead) Read(p []byte) (n int, err *os.Error) {
	n, err = Readn(fd.fd, p);
	return n, err
}

func MakeFullReader(fd Read) Read {
	if fr, ok := fd.(*fullRead); ok {
		// already a fullRead
		return fd
	}
	return &fullRead(fd)
}

// Copies n bytes (or until EOF is reached) from src to dst.
// Returns the number of bytes copied and the error, if any.
func Copyn(src Read, dst Write, n int64) (written int64, err *os.Error) {
	buf := make([]byte, 32*1024);
	for written < n {
		l := len(buf);
		if d := n - written; d < int64(l) {
			l = int(d);
		}
		nr, er := src.Read(buf[0 : l]);
		if nr > 0 {
			nw, ew := dst.Write(buf[0 : nr]);
			if nw > 0 {
				written += int64(nw);
			}
			if ew != nil {
				err = ew;
				break;
			}
			if nr != nw {
				err = os.EIO;
				break;
			}
		}
		if er != nil {
			err = er;
			break;
		}
		if nr == 0 {
			err = ErrEOF;
			break;
		}
	}
	return written, err
}

// Copies from src to dst until EOF is reached.
// Returns the number of bytes copied and the error, if any.
func Copy(src Read, dst Write) (written int64, err *os.Error) {
	buf := make([]byte, 32*1024);
	for {
		nr, er := src.Read(buf);
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr]);
			if nw > 0 {
				written += int64(nw);
			}
			if ew != nil {
				err = ew;
				break;
			}
			if nr != nw {
				err = os.EIO;
				break;
			}
		}
		if er != nil {
			err = er;
			break;
		}
		if nr == 0 {
			break;
		}
	}
	return written, err
}
<commit_msg>comment nit<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package io

import (
	"os";
	"syscall";
)

var ErrEOF = os.NewError("EOF")

type Read interface {
	Read(p []byte) (n int, err *os.Error);
}

type Write interface {
	Write(p []byte) (n int, err *os.Error);
}

type Close interface {
	Close() *os.Error;
}

type ReadWrite interface {
	Read;
	Write;
}

type ReadClose interface {
	Read;
	Close;
}

type WriteClose interface {
	Write;
	Close;
}

type ReadWriteClose interface {
	Read;
	Write;
	Close;
}

// Convert a string to an array of bytes for easy marshaling.
func StringBytes(s string) []byte {
	b := make([]byte, len(s));
	for i := 0; i < len(s); i++ {
		b[i] = s[i];
	}
	return b;
}

func WriteString(w Write, s string) (n int, err *os.Error) {
	return w.Write(StringBytes(s))
}

// Read until buffer is full, EOF, or error
func Readn(fd Read, buf []byte) (n int, err *os.Error) {
	n = 0;
	for n < len(buf) {
		nn, e := fd.Read(buf[n:len(buf)]);
		if nn > 0 {
			n += nn
		}
		if e != nil {
			return n, e
		}
		if nn <= 0 {
			return n, ErrEOF	// no error but insufficient data
		}
	}
	return n, nil
}

// Convert something that implements Read into something
// whose Reads are always Readn
type fullRead struct {
	fd	Read;
}

func (fd *fullRead) Read(p []byte) (n int, err *os.Error) {
	n, err = Readn(fd.fd, p);
	return n, err
}

func MakeFullReader(fd Read) Read {
	if fr, ok := fd.(*fullRead); ok {
		// already a fullRead
		return fd
	}
	return &fullRead(fd)
}

// Copies n bytes (or until EOF is reached) from src to dst.
// Returns the number of bytes copied and the error, if any.
func Copyn(src Read, dst Write, n int64) (written int64, err *os.Error) {
	buf := make([]byte, 32*1024);
	for written < n {
		l := len(buf);
		if d := n - written; d < int64(l) {
			l = int(d);
		}
		nr, er := src.Read(buf[0 : l]);
		if nr > 0 {
			nw, ew := dst.Write(buf[0 : nr]);
			if nw > 0 {
				written += int64(nw);
			}
			if ew != nil {
				err = ew;
				break;
			}
			if nr != nw {
				err = os.EIO;
				break;
			}
		}
		if er != nil {
			err = er;
			break;
		}
		if nr == 0 {
			err = ErrEOF;
			break;
		}
	}
	return written, err
}

// Copies from src to dst until EOF is reached.
// Returns the number of bytes copied and the error, if any.
func Copy(src Read, dst Write) (written int64, err *os.Error) {
	buf := make([]byte, 32*1024);
	for {
		nr, er := src.Read(buf);
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr]);
			if nw > 0 {
				written += int64(nw);
			}
			if ew != nil {
				err = ew;
				break;
			}
			if nr != nw {
				err = os.EIO;
				break;
			}
		}
		if er != nil {
			err = er;
			break;
		}
		if nr == 0 {
			break;
		}
	}
	return written, err
}
<|endoftext|>


<commit_before>package main

import (
  "encoding/json"
  "fmt"
  "net/http"
  "net/url"
  "strconv"
  "github.com/rcrowley/go-tigertonic"
  "github.com/rkbodenner/parallel_universe/collection"
  "github.com/rkbodenner/parallel_universe/game"
  "github.com/rkbodenner/parallel_universe/session"
)

var players = []*game.Player{
  &game.Player{1, "Player One"},
  &game.Player{2, "Player Two"},
}
var playerIndex = make(map[uint64]*game.Player)

func initPlayerData() {
  for _,player := range players {
    playerIndex[(uint64)(player.Id)] = player
  }
}

var gameCollection = collection.NewCollection()
var gameIndex = make(map[uint64]*game.Game)

func initGameData() {
  for i,game := range gameCollection.Games {
    game.Id = (uint)(i+1)
    gameIndex[(uint64)(i+1)] = game
  }
}

var sessions []*session.Session
var sessionIndex = make(map[uint64]*session.Session)

func initSessionData() {
  sessions = make([]*session.Session, 2)
  sessions[0] = session.NewSession(gameCollection.Games[0], players)
  sessions[0].Step(players[0])
  sessions[0].Step(players[1])

  sessions[1] = session.NewSession(gameCollection.Games[1], players)
  sessions[1].Step(players[0])
  sessions[1].Step(players[1])

  for i,session := range sessions {
    session.Id = (uint)(i+1)
    sessionIndex[(uint64)(i+1)] = session
  }
}

func corsHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
  return func(w http.ResponseWriter, r *http.Request) {
    header := w.Header()
    header.Add("Access-Control-Allow-Origin", "http://localhost:8000")
    handler(w, r)
  }
}

type CollectionHandler struct{}
func (h CollectionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(gameCollection)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type GameHandler struct{}
func (h GameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  game, ok := gameIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(game)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type PlayersHandler struct{}
func (h PlayersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(players)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type PlayerHandler struct{}
func (h PlayerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  player, ok := playerIndex[player_id]
  if ok {
    err = json.NewEncoder(w).Encode(player)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type SessionsHandler struct{}
func (h SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(sessions)
  if ( nil != err ) {
    http.Error(w, "Error", http.StatusInternalServerError)
  }
}

type SessionHandler struct{}
func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("session_id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  session, ok := sessionIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(session)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type StepHandler struct{}
func (h StepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  session_id_str := r.URL.Query().Get("session_id")
  session_id, err := strconv.ParseUint(session_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  step_desc,err := url.QueryUnescape(r.URL.Query().Get("step_desc"))
  for _,step := range sessionIndex[session_id].SetupSteps {
    if ( step.GetRule().Description == step_desc ) {
      step.Finish()  // FIXME. Should look in request data to see what to change.
      return
    }
  }
  http.Error(w, "Not found", http.StatusNotFound)
}

func main() {
  initPlayerData()
  initGameData()
  initSessionData()

  mux := tigertonic.NewTrieServeMux()
  cors := tigertonic.NewCORSBuilder().AddAllowedOrigins("http://localhost:8000")
  mux.Handle("GET", "/games", cors.Build(CollectionHandler{}))
  mux.Handle("GET", "/games/{id}", cors.Build(GameHandler{}))
  mux.Handle("GET", "/players", cors.Build(PlayersHandler{}))
  mux.Handle("GET", "/players/{player_id}", cors.Build(PlayerHandler{}))
  mux.Handle("GET", "/sessions", cors.Build(SessionsHandler{}))
  mux.Handle("PUT", "/sessions/{session_id}/steps/{step_desc}", cors.Build(StepHandler{}))
  mux.Handle("GET", "/sessions/{session_id}", cors.Build(SessionHandler{}))
  http.ListenAndServe(":8080", mux)
}
<commit_msg>Include player when looking up step to finish<commit_after>package main

import (
  "encoding/json"
  "fmt"
  "net/http"
  "net/url"
  "strconv"
  "github.com/rcrowley/go-tigertonic"
  "github.com/rkbodenner/parallel_universe/collection"
  "github.com/rkbodenner/parallel_universe/game"
  "github.com/rkbodenner/parallel_universe/session"
)

var players = []*game.Player{
  &game.Player{1, "Player One"},
  &game.Player{2, "Player Two"},
}
var playerIndex = make(map[uint64]*game.Player)

func initPlayerData() {
  for _,player := range players {
    playerIndex[(uint64)(player.Id)] = player
  }
}

var gameCollection = collection.NewCollection()
var gameIndex = make(map[uint64]*game.Game)

func initGameData() {
  for i,game := range gameCollection.Games {
    game.Id = (uint)(i+1)
    gameIndex[(uint64)(i+1)] = game
  }
}

var sessions []*session.Session
var sessionIndex = make(map[uint64]*session.Session)

func initSessionData() {
  sessions = make([]*session.Session, 2)
  sessions[0] = session.NewSession(gameCollection.Games[0], players)
  sessions[0].Step(players[0])
  sessions[0].Step(players[1])

  sessions[1] = session.NewSession(gameCollection.Games[1], players)
  sessions[1].Step(players[0])
  sessions[1].Step(players[1])

  for i,session := range sessions {
    session.Id = (uint)(i+1)
    sessionIndex[(uint64)(i+1)] = session
  }
}

func corsHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
  return func(w http.ResponseWriter, r *http.Request) {
    header := w.Header()
    header.Add("Access-Control-Allow-Origin", "http://localhost:8000")
    handler(w, r)
  }
}

type CollectionHandler struct{}
func (h CollectionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(gameCollection)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type GameHandler struct{}
func (h GameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  game, ok := gameIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(game)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type PlayersHandler struct{}
func (h PlayersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(players)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type PlayerHandler struct{}
func (h PlayerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  player, ok := playerIndex[player_id]
  if ok {
    err = json.NewEncoder(w).Encode(player)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type SessionsHandler struct{}
func (h SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(sessions)
  if ( nil != err ) {
    http.Error(w, "Error", http.StatusInternalServerError)
  }
}

type SessionHandler struct{}
func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("session_id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  session, ok := sessionIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(session)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type StepHandler struct{}
func (h StepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  session_id_str := r.URL.Query().Get("session_id")
  session_id, err := strconv.ParseUint(session_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }
  session,ok := sessionIndex[session_id]
  if !ok {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }

  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }
  player, ok := playerIndex[player_id]
  if !ok {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }

  step_desc,err := url.QueryUnescape(r.URL.Query().Get("step_desc"))
  for _,step := range session.SetupSteps {
    if ( step.GetRule().Description == step_desc && step.CanBeOwnedBy(player) ) {
      step.Finish()  // FIXME. Should look in request data to see what to change.
      session.Step(player)
      session.Print()  // FIXME
      return
    }
  }
  http.Error(w, "Step not found", http.StatusNotFound)
}

func main() {
  initPlayerData()
  initGameData()
  initSessionData()

  mux := tigertonic.NewTrieServeMux()
  cors := tigertonic.NewCORSBuilder().AddAllowedOrigins("http://localhost:8000")
  mux.Handle("GET", "/games", cors.Build(CollectionHandler{}))
  mux.Handle("GET", "/games/{id}", cors.Build(GameHandler{}))
  mux.Handle("GET", "/players", cors.Build(PlayersHandler{}))
  mux.Handle("GET", "/players/{player_id}", cors.Build(PlayerHandler{}))
  mux.Handle("GET", "/sessions", cors.Build(SessionsHandler{}))
  mux.Handle("GET", "/sessions/{session_id}", cors.Build(SessionHandler{}))
  mux.Handle("PUT", "/sessions/{session_id}/players/{player_id}/steps/{step_desc}", cors.Build(StepHandler{}))
  http.ListenAndServe(":8080", mux)
}
<|endoftext|>


<commit_before>package meta

import (
	"fmt"
	"io"
	"io/ioutil"
)

// RegisteredApplications maps from a registered application ID to a
// description.
//
// ref: http://flac.sourceforge.net/id.html
var RegisteredApplications = map[string]string{
	"ATCH": "FlacFile",
	"BSOL": "beSolo",
	"BUGS": "Bugs Player",
	"Cues": "GoldWave cue points (specification)",
	"Fica": "CUE Splitter",
	"Ftol": "flac-tools",
	"MOTB": "MOTB MetaCzar",
	"MPSE": "MP3 Stream Editor",
	"MuML": "MusicML: Music Metadata Language",
	"RIFF": "Sound Devices RIFF chunk storage",
	"SFFL": "Sound Font FLAC",
	"SONY": "Sony Creative Software",
	"SQEZ": "flacsqueeze",
	"TtWv": "TwistedWave",
	"UITS": "UITS Embedding tools",
	"aiff": "FLAC AIFF chunk storage",
	"imag": "flac-image application for storing arbitrary files in APPLICATION metadata blocks",
	"peem": "Parseable Embedded Extensible Metadata (specification)",
	"qfst": "QFLAC Studio",
	"riff": "FLAC RIFF chunk storage",
	"tune": "TagTuner",
	"xbat": "XBAT",
	"xmcd": "xmcd",
}

// An Application metadata block is for use by third-party applications. The
// only mandatory field is a 32-bit identifier. This ID is granted upon request
// to an application by the FLAC maintainers. The remainder of the block is
// defined by the registered application.
type Application struct {
	// Registered application ID.
	ID string
	// Application data.
	Data []byte
}

// NewApplication parses and returns a new Application metadata block. The
// provided io.Reader should limit the amount of data that can be read to
// header.Length bytes.
//
// Application format (pseudo code):
//
//    type METADATA_BLOCK_APPLICATION struct {
//       ID   uint32
//       Data [header.Length-4]byte
//    }
//
// ref: http://flac.sourceforge.net/format.html#metadata_block_application
func NewApplication(r io.Reader) (app *Application, err error) {
	// Application ID (size: 4 bytes).
	buf := make([]byte, 4)
	_, err = io.ReadFull(r, buf)
	if err != nil {
		return nil, err
	}
	app = new(Application)
	app.ID = string(buf)
	_, ok := RegisteredApplications[app.ID]
	if !ok {
		return nil, fmt.Errorf("meta.NewApplication: unregistered application ID %q", app.ID)
	}

	// Data.
	buf, err = ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	app.Data = buf

	return app, nil
}
<commit_msg>meta: Add ID type as an identifier for registered applications.<commit_after>package meta

import (
	"fmt"
	"io"
	"io/ioutil"
)

// registeredApplications maps from a registered application ID to a
// description.
//
// ref: http://flac.sourceforge.net/id.html
var registeredApplications = map[ID]string{
	"ATCH": "FlacFile",
	"BSOL": "beSolo",
	"BUGS": "Bugs Player",
	"Cues": "GoldWave cue points (specification)",
	"Fica": "CUE Splitter",
	"Ftol": "flac-tools",
	"MOTB": "MOTB MetaCzar",
	"MPSE": "MP3 Stream Editor",
	"MuML": "MusicML: Music Metadata Language",
	"RIFF": "Sound Devices RIFF chunk storage",
	"SFFL": "Sound Font FLAC",
	"SONY": "Sony Creative Software",
	"SQEZ": "flacsqueeze",
	"TtWv": "TwistedWave",
	"UITS": "UITS Embedding tools",
	"aiff": "FLAC AIFF chunk storage",
	"imag": "flac-image application for storing arbitrary files in APPLICATION metadata blocks",
	"peem": "Parseable Embedded Extensible Metadata (specification)",
	"qfst": "QFLAC Studio",
	"riff": "FLAC RIFF chunk storage",
	"tune": "TagTuner",
	"xbat": "XBAT",
	"xmcd": "xmcd",
}

// An ID is a 4 byte identifier of a registered application.
type ID string

func (id ID) String() string {
	s, ok := registeredApplications[id]
	if ok {
		return s
	}
	return fmt.Sprintf("<unregistered ID: %q>", string(id))
}

// An Application metadata block is for use by third-party applications. The
// only mandatory field is a 32-bit identifier. This ID is granted upon request
// to an application by the FLAC maintainers. The remainder of the block is
// defined by the registered application.
type Application struct {
	// Registered application ID.
	ID ID
	// Application data.
	Data []byte
}

// NewApplication parses and returns a new Application metadata block. The
// provided io.Reader should limit the amount of data that can be read to
// header.Length bytes.
//
// Application format (pseudo code):
//
//    type METADATA_BLOCK_APPLICATION struct {
//       ID   uint32
//       Data [header.Length-4]byte
//    }
//
// ref: http://flac.sourceforge.net/format.html#metadata_block_application
func NewApplication(r io.Reader) (app *Application, err error) {
	// Application ID (size: 4 bytes).
	buf := make([]byte, 4)
	_, err = io.ReadFull(r, buf)
	if err != nil {
		return nil, err
	}
	app = &Application{ID: ID(buf)}
	_, ok := registeredApplications[app.ID]
	if !ok {
		return nil, fmt.Errorf("meta.NewApplication: unregistered application ID %q", string(app.ID))
	}

	// Data.
	buf, err = ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	app.Data = buf

	return app, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"gopkg.in/urfave/cli.v1"
	"net/url"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

type Opts struct {
	TargetBucket string `short: "t", long: "target-bucket"`

	InPlace    bool   `long: "in-place"`
	FromBucket string `long: "from-bucket"`
	// TODO validation - Please provide the source of the objects. Either --in-place or --from-bucket must be specified. Or use InPlace as the default for FromBucket
	SetCacheControl string `long: "set-cache-control" default:"max-age=31536000,public"`
	// cache for one year - so almost forever
	SetCacheControlForever string `long: "set-cache-control-forever"`
}

var opts Opts

// modify aws s3 copy args in place
func args_src_copy_from(key string, opts Opts, input *s3.CopyObjectInput) {
	input.SetCopySource(opts.FromBucket + key)
}

// modify aws s3 copy args in place,
// set cache-control
func args_src_cache_control(opts Opts, input *s3.CopyObjectInput) {
}

// modify aws s3 copy args in place,
// gather existing object meta data, especially content type
func args_src_existing_meta(opts Opts, input *s3.CopyObjectInput) {
}

func copy(object string, opts Opts) {
	prepareCopy(object, opts)
	// svc := s3.New(session.New())
}

func prepareCopy(key string, opts Opts) {
	/*
		object := load_existing_metadata(key)
		input := &s3.CopyObjectInput{
			Bucket: aws.String(opts.TargetBucket),
			Key:    aws.String(key),
		}
		args_src_copy_from(key, opts, input)
		args_src_cache_control(object, opts, input)
		args_src_existing_meta(object, opts, input)
	*/
}

func listObjectsFromStdin(names chan<- string, bucketname string, context CopyContext) {
	input := bufio.NewScanner(os.Stdin)
	for input.Scan() {
		names <- input.Text()
	}
}

func listObjectsToCopy(names chan<- string, bucketname string, context CopyContext) {
	input := &s3.ListObjectsV2Input{
		Bucket:  aws.String(bucketname),
		MaxKeys: aws.Int64(20),
	}

	result, err := context.s3svc.ListObjectsV2(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			case s3.ErrCodeNoSuchBucket:
				fmt.Println(s3.ErrCodeNoSuchBucket, aerr.Error())
			default:
				fmt.Println(aerr.Error())
			}
		} else {
			// Print the error, cast err to awserr.Error to get the Code and
			// Message from an error.
			fmt.Println(err.Error())
		}
		return
	}
	for _, _ = range result.Contents {
		fmt.Print("W")
	}
	// fmt.Println(result)

	pageNum := 0
	err = context.s3svc.ListObjectsV2Pages(input,
		func(page *s3.ListObjectsV2Output, lastPage bool) bool {
			pageNum++
			// fmt.Println(page)
			for _, item := range page.Contents {
				// fmt.Printf("Key: %s ETag: %s\n", *item.Key, *item.ETag)
				names <- *item.Key
			}
			return pageNum <= 5
		})
}

func main() {

	app := cli.NewApp()
	app.Usage = "Set Cache-Control header for all objects in a s3 bucket. Optionally copies objects from another bucket."
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name: "target-bucket, t",
		},
		cli.StringFlag{
			Name: "from-bucket, f",
		},
		cli.StringFlag{
			Name:  "cache-control, c",
			Value: "max-age=31536000,public",
			Usage: "by default cache for one year",
		},
		cli.StringFlag{
			Name:  "exclude-pictures, e",
			Value: "max-age=31536000,public",
			Usage: "do not process picture object which names match regex",
		},
	}
	app.Action = func(c *cli.Context) error {
		context, _ := prepareContextFromCli(c)

		parallelity := 200 // set well below the typical ulimit of 1024
		// to avoid "socket: too many open files".
		// Also fits AWS API limits, avoid "503 SlowDown: Please reduce your request rate."
		names := make(chan string)
		context.wg.Add(parallelity)
		for gr := 1; gr <= parallelity; gr++ {
			go cpworker(&context, names)
		}

		listObjectsToCopy(names, context.from, context)
		close(names)
		context.wg.Wait()
		fmt.Printf("\nDone.\n")
		return nil
	}
	app.Run(os.Args)
}

/* Hello world */
func CheckPublicCommentTmp() {
}

/* CopyContext defines context for running concurrent copy operations and remembers the progress */
type CopyContext struct {
	s3svc      *s3.S3
	bucketname string // TODO: rename to target
	from       string
	newvalue   string
	exclude    string

	copiedObjects   int64
	copiedBytes     int64
	expectedObjects int64
	start           time.Time
	statusLineMutex sync.Mutex
	lastStatusShown float64

	wg sync.WaitGroup
}

func prepareContext() (CopyContext, error) {
	// Session with the new library
	sess, err := session.NewSession() /*&aws.Config{
		Region: aws.String("eu-central-1")},
	)*/
	if err != nil {
		panic(fmt.Sprintf("Can not create AWS SDK session %s", err))
	}

	if len(os.Args) != 3 {
		panic("Please provide bucket name and desired Cache-Control setting")
	}
	return CopyContext{
		s3svc:           s3.New(sess),
		bucketname:      os.Args[1],
		expectedObjects: 3867874,
		newvalue:        os.Args[2],
		start:           time.Now(),
	}, nil
}

func prepareContextFromCli(c *cli.Context) (CopyContext, error) {
	// Session with the new library
	sess, err := session.NewSession() /*&aws.Config{
		Region: aws.String("eu-central-1")},
	)*/
	if err != nil {
		panic(fmt.Sprintf("Can not create AWS SDK session %s", err))
	}

	target := c.GlobalString("target-bucket")
	if target == "" {
		cli.ShowAppHelp(c)
		return CopyContext{}, cli.NewExitError("\n\nError: --target-bucket is a required flag\n", 1)
	}

	from := c.GlobalString("from-bucket")
	if from == "" {
		from = target
	}

	fmt.Printf("Copying   to %s\nCopying from %s\n", target, from)

	return CopyContext{
		s3svc:           s3.New(sess),
		bucketname:      target,
		from:            from,
		expectedObjects: 3867874,
		newvalue:        c.GlobalString("cache-control"),
		exclude:         c.GlobalString("exclude-pictures"),
		start:           time.Now(),
	}, nil
}

func cpworker(context *CopyContext, names <-chan string) {
	for {
		name, more := <-names
		if more {
			// fmt.Printf("Starting copy %v\n", name)
			if err := cp(context, name); err != nil {
				os.Stderr.WriteString(fmt.Sprintf("==> Failed processing '%s': %v\n", name, err))
				filename := "error_keys.txt"
				os.Stderr.WriteString(fmt.Sprintf("Adding name to '%s' for later processing or reference", filename))
				f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
				if err != nil {
					os.Stderr.WriteString(fmt.Sprintf("Could not write to 'TODO' file '%s'. Error: %v\n", filename, err))
					panic(err)
				}
				fmt.Fprintln(f, name)
				f.Close()
			}
		} else {
			// fmt.Printf("\nNo more data in names channel.\n")
			context.wg.Done()
			return
		}
	}
}

func cp(context *CopyContext, name string) error {
	//fmt.Println(context.bucketname)
	//fmt.Println(url.PathEscape(name))
	headin := s3.HeadObjectInput{
		Bucket: aws.String(context.bucketname),
		Key:    aws.String(name),
		//		Key:    aws.String(url.PathEscape(name)),
	}
	headresp, err := context.s3svc.HeadObject(&headin)
	if err != nil {
		return fmt.Errorf("aws sdk Head failed: %v", err)
	}

	contenttype := headresp.ContentType
	oldcachecontrol := headresp.CacheControl

	var status string
	// . - skip
	// X - type was not set, set to image/png
	// j - was image/jpeg; adjusted CacheControl
	// g - was image/png; adjusted CacheControl
	// P - pdf file; adjusted CacheControl
	// Y - other file type; adjusted CacheControl
	if oldcachecontrol != nil && *oldcachecontrol == context.newvalue {
		status = "."
	} else {
		if contenttype == nil {
			status = "X"
			contenttype = aws.String("image/png")
		} else {
			// contenttype = contenttypes[0] // theoretically, there can be multiple HTTP headers with the same key
			// but lets assume, there is at most one
			if *contenttype == "image/png" {
				status = "g"
			} else if *contenttype == "image/jpeg" {
				status = "j"
			} else if *contenttype == "application/pdf" {
				status = "P"
			} else {
				status = "Y"
			}
		}

		src := fmt.Sprintf("%s/%s", context.bucketname, url.PathEscape(name))
		inp := s3.CopyObjectInput{
			Bucket:            aws.String(context.bucketname),
			CopySource:        &src,
			Key:               &name,
			CacheControl:      &context.newvalue,
			ContentType:       contenttype,
			MetadataDirective: aws.String("REPLACE"),
		}
		_, err := context.s3svc.CopyObject(&inp)
		if err != nil {
			return fmt.Errorf("Failed changing (inplace-copying) object: %v", err)
		}
	}
	fmt.Print(status)

	atomic.AddInt64(&context.copiedObjects, 1)
	sec := time.Since(context.start).Seconds()
	o_s := float64(context.copiedObjects) / sec
	expectedDuration := time.Duration(int(float64(context.expectedObjects-context.copiedObjects)/o_s)) * time.Second
	days := int(expectedDuration.Hours() / 24)
	andHours := expectedDuration.Hours() - float64(days)*24
	eta := fmt.Sprintf("%dd %.1fh", days, andHours)
	if days == 0 {
		hours := int(expectedDuration.Minutes() / 60)
		andMinutes := expectedDuration.Minutes() - float64(hours)*60
		eta = fmt.Sprintf("%dh %.1fm", hours, andMinutes)
	}
	if context.expectedObjects < context.copiedObjects {
		eta = "-"
	}

	const everySeconds = 10
	show := false
	context.statusLineMutex.Lock()
	if context.lastStatusShown < sec-everySeconds {
		show = true
		context.lastStatusShown = sec
	}
	context.statusLineMutex.Unlock()

	if show {
		fmt.Printf("\n%-30s Totals: %d/%d objects. Avg: %.2f obj/s. ETA: %v    \n",
			name, context.copiedObjects, context.expectedObjects, o_s, eta,
		)
	}
	return nil
}
<commit_msg>Exclude picture objects which names match a regex (/original$)<commit_after>package main

import (
	"bufio"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"gopkg.in/urfave/cli.v1"
	"net/url"
	"os"
	"regexp"
	"sync"
	"sync/atomic"
	"time"
)

type Opts struct {
	TargetBucket string `short: "t", long: "target-bucket"`

	InPlace    bool   `long: "in-place"`
	FromBucket string `long: "from-bucket"`
	// TODO validation - Please provide the source of the objects. Either --in-place or --from-bucket must be specified. Or use InPlace as the default for FromBucket
	SetCacheControl string `long: "set-cache-control" default:"max-age=31536000,public"`
	// cache for one year - so almost forever
	SetCacheControlForever string `long: "set-cache-control-forever"`
}

var opts Opts

// modify aws s3 copy args in place
func args_src_copy_from(key string, opts Opts, input *s3.CopyObjectInput) {
	input.SetCopySource(opts.FromBucket + key)
}

// modify aws s3 copy args in place,
// set cache-control
func args_src_cache_control(opts Opts, input *s3.CopyObjectInput) {
}

// modify aws s3 copy args in place,
// gather existing object meta data, especially content type
func args_src_existing_meta(opts Opts, input *s3.CopyObjectInput) {
}

func copy(object string, opts Opts) {
	prepareCopy(object, opts)
	// svc := s3.New(session.New())
}

func prepareCopy(key string, opts Opts) {
	/*
		object := load_existing_metadata(key)
		input := &s3.CopyObjectInput{
			Bucket: aws.String(opts.TargetBucket),
			Key:    aws.String(key),
		}
		args_src_copy_from(key, opts, input)
		args_src_cache_control(object, opts, input)
		args_src_existing_meta(object, opts, input)
	*/
}

func listObjectsFromStdin(names chan<- string, bucketname string, context CopyContext) {
	input := bufio.NewScanner(os.Stdin)
	for input.Scan() {
		names <- input.Text()
	}
}

func listObjectsToCopy(names chan<- string, bucketname string, context CopyContext) {
	input := &s3.ListObjectsV2Input{
		Bucket:  aws.String(bucketname),
		MaxKeys: aws.Int64(20),
	}

	pageNum := 0
	err := context.s3svc.ListObjectsV2Pages(input,
		func(page *s3.ListObjectsV2Output, lastPage bool) bool {
			pageNum++
			// fmt.Println(page)
			for _, item := range page.Contents {
				// fmt.Printf("Key: %s ETag: %s\n", *item.Key, *item.ETag)
				names <- *item.Key
			}
			return pageNum <= 5
		})
	if err != nil {
		os.Stderr.WriteString(fmt.Sprintf("%s", err))
	}
}

func main() {

	app := cli.NewApp()
	app.Usage = "Set Cache-Control header for all objects in a s3 bucket. Optionally copies objects from another bucket."
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name: "target-bucket, t",
		},
		cli.StringFlag{
			Name: "from-bucket, f",
		},
		cli.StringFlag{
			Name:  "cache-control, c",
			Value: "max-age=31536000,public",
			Usage: "by default cache for one year",
		},
		cli.StringFlag{
			Name:  "exclude-pictures, e",
			Usage: "do not process picture object which names match regex",
		},
	}
	app.Action = func(c *cli.Context) error {
		context, _ := prepareContextFromCli(c)

		parallelity := 200 // set well below the typical ulimit of 1024
		// to avoid "socket: too many open files".
		// Also fits AWS API limits, avoid "503 SlowDown: Please reduce your request rate."
		names := make(chan string)
		context.wg.Add(parallelity)
		for gr := 1; gr <= parallelity; gr++ {
			go cpworker(&context, names)
		}

		listObjectsToCopy(names, context.from, context)
		close(names)
		context.wg.Wait()
		fmt.Printf("\nDone.\n")
		return nil
	}
	app.Run(os.Args)
}

func CheckPublicCommentTmp() {
}

/* CopyContext defines context for running concurrent copy operations and remembers the progress */
type CopyContext struct {
	s3svc    *s3.S3
	target   string
	from     string
	newvalue string
	exclude  regexp.Regexp

	copiedObjects   int64
	copiedBytes     int64
	expectedObjects int64
	start           time.Time
	statusLineMutex sync.Mutex
	lastStatusShown float64

	wg sync.WaitGroup
}

func prepareContext() (CopyContext, error) {
	// Session with the new library
	sess, err := session.NewSession() /*&aws.Config{
		Region: aws.String("eu-central-1")},
	)*/
	if err != nil {
		panic(fmt.Sprintf("Can not create AWS SDK session %s", err))
	}

	if len(os.Args) != 3 {
		panic("Please provide bucket name and desired Cache-Control setting")
	}
	return CopyContext{
		s3svc:           s3.New(sess),
		target:          os.Args[1],
		expectedObjects: 3867874,
		newvalue:        os.Args[2],
		start:           time.Now(),
	}, nil
}

func prepareContextFromCli(c *cli.Context) (CopyContext, error) {
	// Session with the new library
	sess, err := session.NewSession() /*&aws.Config{
		Region: aws.String("eu-central-1")},
	)*/
	if err != nil {
		panic(fmt.Sprintf("Can not create AWS SDK session %s", err))
	}

	target := c.GlobalString("target-bucket")
	if target == "" {
		cli.ShowAppHelp(c)
		return CopyContext{}, cli.NewExitError("\n\nError: --target-bucket is a required flag\n", 1)
	}

	from := c.GlobalString("from-bucket")
	if from == "" {
		from = target
	}

	fmt.Printf("Copying   to %s\nCopying from %s\n", target, from)

	exclude_pattern := c.GlobalString("exclude-pictures")
	if exclude_pattern == "" {
		exclude_pattern = "^some-pattern-which-would-never-match$"
	}
	return CopyContext{
		s3svc:           s3.New(sess),
		target:          target,
		from:            from,
		expectedObjects: 3867874,
		newvalue:        c.GlobalString("cache-control"),
		exclude:         *regexp.MustCompile(exclude_pattern),
		start:           time.Now(),
	}, nil
}

func cpworker(context *CopyContext, names <-chan string) {
	for {
		name, more := <-names
		if more {
			// fmt.Printf("Starting copy %v\n", name)
			if err := cp(context, name); err != nil {
				os.Stderr.WriteString(fmt.Sprintf("==> Failed processing '%s': %v\n", name, err))
				filename := "error_keys.txt"
				os.Stderr.WriteString(fmt.Sprintf("Adding name to '%s' for later processing or reference", filename))
				f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
				if err != nil {
					os.Stderr.WriteString(fmt.Sprintf("Could not write to 'TODO' file '%s'. Error: %v\n", filename, err))
					panic(err)
				}
				fmt.Fprintln(f, name)
				f.Close()
			}
		} else {
			// fmt.Printf("\nNo more data in names channel.\n")
			context.wg.Done()
			return
		}
	}
}

func cp(context *CopyContext, name string) error {
	//fmt.Println(context.target)
	//fmt.Println(url.PathEscape(name))
	// key := aws.String(url.PathEscape(name)),
	key := name
	headin := s3.HeadObjectInput{
		Bucket: aws.String(context.from),
		Key:    aws.String(key),
	}
	headresp, err := context.s3svc.HeadObject(&headin)
	if err != nil {
		return fmt.Errorf("aws sdk Head for `%s` failed: %v", key, err)
	}

	contenttype := headresp.ContentType
	oldcachecontrol := headresp.CacheControl

	var status string
	// I - ignore due pattern
	// . - skip
	// X - type was not set, set to image/png
	// j - was image/jpeg; adjusted CacheControl
	// g - was image/png; adjusted CacheControl
	// P - pdf file; adjusted CacheControl
	// Y - other file type; adjusted CacheControl
	if context.exclude.MatchString(name) {
		status = "I"
	} else if oldcachecontrol != nil && *oldcachecontrol == context.newvalue {
		status = "."
	} else {
		if contenttype == nil {
			status = "X"
			contenttype = aws.String("image/png")
		} else {
			// contenttype = contenttypes[0] // theoretically, there can be multiple HTTP headers with the same key
			// but lets assume, there is at most one
			if *contenttype == "image/png" {
				status = "g"
			} else if *contenttype == "image/jpeg" {
				status = "j"
			} else if *contenttype == "application/pdf" {
				status = "P"
			} else {
				status = "Y"
			}
		}

		src := fmt.Sprintf("%s/%s", context.from, url.PathEscape(name))
		inp := s3.CopyObjectInput{
			Bucket:            aws.String(context.target),
			CopySource:        &src,
			Key:               &name,
			CacheControl:      &context.newvalue,
			ContentType:       contenttype,
			MetadataDirective: aws.String("REPLACE"),
		}
		_, err := context.s3svc.CopyObject(&inp)
		if err != nil {
			return fmt.Errorf("Failed changing (inplace-copying) object: %v", err)
		}
	}
	fmt.Print(status)

	atomic.AddInt64(&context.copiedObjects, 1)
	sec := time.Since(context.start).Seconds()
	o_s := float64(context.copiedObjects) / sec
	expectedDuration := time.Duration(int(float64(context.expectedObjects-context.copiedObjects)/o_s)) * time.Second
	days := int(expectedDuration.Hours() / 24)
	andHours := expectedDuration.Hours() - float64(days)*24
	eta := fmt.Sprintf("%dd %.1fh", days, andHours)
	if days == 0 {
		hours := int(expectedDuration.Minutes() / 60)
		andMinutes := expectedDuration.Minutes() - float64(hours)*60
		eta = fmt.Sprintf("%dh %.1fm", hours, andMinutes)
	}
	if context.expectedObjects < context.copiedObjects {
		eta = "-"
	}

	const everySeconds = 10
	show := false
	context.statusLineMutex.Lock()
	if context.lastStatusShown < sec-everySeconds {
		show = true
		context.lastStatusShown = sec
	}
	context.statusLineMutex.Unlock()

	if show {
		fmt.Printf("\n%-30s Totals: %d/%d objects. Avg: %.2f obj/s. ETA: %v    \n",
			name, context.copiedObjects, context.expectedObjects, o_s, eta,
		)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import "trace"

const (
	imageW = 640
	imageH = 480
)

func createRandomImage() [][]trace.Color {
	image := make([][]trace.Color, imageH)
	for i := range image {
		image[i] = make([]trace.Color, imageW)
		for j := range image[i] {
			image[i][j].R = float64(i) / float64(imageH)
			image[i][j].G = float64(j) / float64(imageW)
			image[i][j].B = 0.0

			//log.Printf("%d %d %+v | ", i, j, image[i][j])
		}
		//log.Printf("\n")
	}
	return image
}

func main() {
	c := trace.NewContext(imageW, imageH)

	o2w := trace.NewM44()
	o2w.Translate(trace.NewV3(0, 0, -5))/*.scale(trace.NewV3(1.0, 2.0, 1.0))*/
	//c.AddPrimitive(trace.NewSphere(o2w))
	c.AddPrimitive(trace.NewTriangle(o2w))

	image := trace.Render(c)
	//image := createRandomImage()
	trace.WriteImageToPPM(image, "render")
}
<commit_msg>Show sphere and triangle<commit_after>package main

import "trace"

const (
	imageW = 640
	imageH = 480
)

func createRandomImage() [][]trace.Color {
	image := make([][]trace.Color, imageH)
	for i := range image {
		image[i] = make([]trace.Color, imageW)
		for j := range image[i] {
			image[i][j].R = float64(i) / float64(imageH)
			image[i][j].G = float64(j) / float64(imageW)
			image[i][j].B = 0.0

			//log.Printf("%d %d %+v | ", i, j, image[i][j])
		}
		//log.Printf("\n")
	}
	return image
}

func main() {
	c := trace.NewContext(imageW, imageH)

	o2w := trace.NewM44()
	o2w.Translate(trace.NewV3(-2, 0, -5))/*.scale(trace.NewV3(1.0, 2.0, 1.0))*/
	c.AddPrimitive(trace.NewSphere(o2w))

	o2w = trace.NewM44()
	o2w.Translate(trace.NewV3(2, 0, -5))
	c.AddPrimitive(trace.NewTriangle(o2w))

	image := trace.Render(c)
	//image := createRandomImage()
	trace.WriteImageToPPM(image, "render")
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package main

import (
	oaocs "github.com/Noxaro/oneandone-cloudserver-api"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestIntegrationCreateMonitoringPolicy(t *testing.T) {
	monitoringPolicy := oaocs.MonitoringPolicy{
		Name:  "Integration Test Monitoring Policy",
		Email: "",
		Agent: false,
		Thresholds: oaocs.MonitoringThreshold{
			Cpu: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 90,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 95,
					Alert: false,
				},
			},
			Ram: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 90,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 95,
					Alert: false,
				},
			},
			Disk: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 80,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 90,
					Alert: false,
				},
			},
			Transfer: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 1000,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 2000,
					Alert: false,
				},
			},
			InternalPing: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 50,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 100,
					Alert: false,
				},
			},
		},
	}

	createdMonitoringPolicy, err := GetAPI().CreateMonitoringPolicy(monitoringPolicy)
	assert.Nil(t, err)

	monitoringPolicies, err := GetAPI().GetMonitoringPolicies()
	assert.Nil(t, err)

	if len(monitoringPolicies) == 0 {
		t.Error("")
	}

	for index, _ := range monitoringPolicies {
		time.Sleep(1 * time.Second)
		monitoringPolicy, err := GetAPI().GetMonitoringPolicy(monitoringPolicies[index].Id)
		assert.Nil(t, err)
		assert.Equal(t, monitoringPolicies[index].Id, monitoringPolicy.Id)
		assert.Equal(t, monitoringPolicies[index].Name, monitoringPolicy.Name)
		assert.Equal(t, monitoringPolicies[index].Description, monitoringPolicy.Description)
		assert.Equal(t, monitoringPolicies[index].Default, monitoringPolicy.Default)
		assert.Equal(t, monitoringPolicies[index].State, monitoringPolicy.State)
		assert.Equal(t, monitoringPolicies[index].CreationDate, monitoringPolicy.CreationDate)
		assert.Equal(t, monitoringPolicies[index].Email, monitoringPolicy.Email)
		assert.Equal(t, monitoringPolicies[index].Agent, monitoringPolicy.Agent)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Warning.Value, monitoringPolicy.Thresholds.Cpu.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Warning.Alert, monitoringPolicy.Thresholds.Cpu.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Critical.Value, monitoringPolicy.Thresholds.Cpu.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Critical.Alert, monitoringPolicy.Thresholds.Cpu.Critical.Alert)

		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Warning.Value, monitoringPolicy.Thresholds.Ram.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Warning.Alert, monitoringPolicy.Thresholds.Ram.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Critical.Value, monitoringPolicy.Thresholds.Ram.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Critical.Alert, monitoringPolicy.Thresholds.Ram.Critical.Alert)

		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Warning.Value, monitoringPolicy.Thresholds.Transfer.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Warning.Alert, monitoringPolicy.Thresholds.Transfer.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Critical.Value, monitoringPolicy.Thresholds.Transfer.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Critical.Alert, monitoringPolicy.Thresholds.Transfer.Critical.Alert)

		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Warning.Value, monitoringPolicy.Thresholds.InternalPing.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Warning.Alert, monitoringPolicy.Thresholds.InternalPing.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Critical.Value, monitoringPolicy.Thresholds.InternalPing.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Critical.Alert, monitoringPolicy.Thresholds.InternalPing.Critical.Alert)

	}

	createdMonitoringPolicy.Delete()

}
<commit_msg>Implement defer for cleanup<commit_after>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package main

import (
	oaocs "github.com/Noxaro/oneandone-cloudserver-api"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestIntegrationCreateMonitoringPolicy(t *testing.T) {
	monitoringPolicy := oaocs.MonitoringPolicy{
		Name:  "Integration Test Monitoring Policy",
		Email: "",
		Agent: false,
		Thresholds: oaocs.MonitoringThreshold{
			Cpu: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 90,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 95,
					Alert: false,
				},
			},
			Ram: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 90,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 95,
					Alert: false,
				},
			},
			Disk: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 80,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 90,
					Alert: false,
				},
			},
			Transfer: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 1000,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 2000,
					Alert: false,
				},
			},
			InternalPing: oaocs.MonitoringLevel{
				Warning: oaocs.MonitoringValue{
					Value: 50,
					Alert: false,
				},
				Critical: oaocs.MonitoringValue{
					Value: 100,
					Alert: false,
				},
			},
		},
	}

	cmp, err := GetAPI().CreateMonitoringPolicy(monitoringPolicy)
	assert.Nil(t, err)

	defer DeleteMonitoringPolicy(t, cmp)

	monitoringPolicies, err := GetAPI().GetMonitoringPolicies()
	assert.Nil(t, err)

	if len(monitoringPolicies) == 0 {
		t.Error("")
	}

	for index, _ := range monitoringPolicies {
		time.Sleep(1 * time.Second)
		monitoringPolicy, err := GetAPI().GetMonitoringPolicy(monitoringPolicies[index].Id)
		assert.Nil(t, err)
		assert.Equal(t, monitoringPolicies[index].Id, monitoringPolicy.Id)
		assert.Equal(t, monitoringPolicies[index].Name, monitoringPolicy.Name)
		assert.Equal(t, monitoringPolicies[index].Description, monitoringPolicy.Description)
		assert.Equal(t, monitoringPolicies[index].Default, monitoringPolicy.Default)
		assert.Equal(t, monitoringPolicies[index].State, monitoringPolicy.State)
		assert.Equal(t, monitoringPolicies[index].CreationDate, monitoringPolicy.CreationDate)
		assert.Equal(t, monitoringPolicies[index].Email, monitoringPolicy.Email)
		assert.Equal(t, monitoringPolicies[index].Agent, monitoringPolicy.Agent)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Warning.Value, monitoringPolicy.Thresholds.Cpu.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Warning.Alert, monitoringPolicy.Thresholds.Cpu.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Critical.Value, monitoringPolicy.Thresholds.Cpu.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Cpu.Critical.Alert, monitoringPolicy.Thresholds.Cpu.Critical.Alert)

		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Warning.Value, monitoringPolicy.Thresholds.Ram.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Warning.Alert, monitoringPolicy.Thresholds.Ram.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Critical.Value, monitoringPolicy.Thresholds.Ram.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Ram.Critical.Alert, monitoringPolicy.Thresholds.Ram.Critical.Alert)

		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Warning.Value, monitoringPolicy.Thresholds.Transfer.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Warning.Alert, monitoringPolicy.Thresholds.Transfer.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Critical.Value, monitoringPolicy.Thresholds.Transfer.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.Transfer.Critical.Alert, monitoringPolicy.Thresholds.Transfer.Critical.Alert)

		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Warning.Value, monitoringPolicy.Thresholds.InternalPing.Warning.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Warning.Alert, monitoringPolicy.Thresholds.InternalPing.Warning.Alert)
		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Critical.Value, monitoringPolicy.Thresholds.InternalPing.Critical.Value)
		assert.Equal(t, monitoringPolicies[index].Thresholds.InternalPing.Critical.Alert, monitoringPolicy.Thresholds.InternalPing.Critical.Alert)

	}
}

func DeleteMonitoringPolicy(t *testing.T, mp *oaocs.MonitoringPolicy){
	_, err := mp.Delete()
	assert.Nil(t, err)
}
<|endoftext|>


<commit_before>// Reconnect example for GoMySQL
// This script will run forever, reconnect can be tested by restarting MySQL
// server while script is running.
package main

import (
	"mysql"
	"fmt"
	"os"
	"time"
)

// Reconnect function, attempts to reconnect once per second
func reconnect(db *mysql.MySQL, done chan int) {
	attempts := 0
	for {
		time.Sleep(1000000000)
		db.Reconnect()
		if db.Errno == 0 {
			break
		} else {
			attempts ++
			fmt.Printf("Reconnect attempt %d failed\n", attempts)
		}
	}
	done <- 1
}

func main() {
	// Create new instance
	db := mysql.New()
	// Enable logging
	db.Logging = true
	// Connect to database
	db.Connect("localhost", "root", "********", "gotesting")
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Repeat query forever
	for {
		res := db.Query("select * from test1")
		// On error reconnect to the server
		if res == nil {
			fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
			done := make(chan int)
    			go reconnect(db, done)
    			<-done
		}
		// Sleep for 0.5 seconds
		time.Sleep(500000000)
	}
}
<commit_msg>slightly ammended reconnect example<commit_after>// Reconnect example for GoMySQL
// This script will run forever, reconnect can be tested by restarting MySQL
// server while script is running.
package main

import (
	"mysql"
	"fmt"
	"os"
	"time"
)

// Reconnect function, attempts to reconnect once per second
func reconnect(db *mysql.MySQL, done chan int) {
	attempts := 0
	for {
		// Sleep for 1 second
		time.Sleep(1000000000)
		// Attempt to reconnect
		db.Reconnect()
		// If there was no error break for loop
		if db.Errno == 0 {
			break
		} else {
			attempts ++
			fmt.Printf("Reconnect attempt %d failed\n", attempts)
		}
	}
	done <- 1
}

func main() {
	// Create new instance
	db := mysql.New()
	// Enable logging
	db.Logging = true
	// Connect to database
	db.Connect("localhost", "root", "********", "gotesting")
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Repeat query forever
	for {
		res := db.Query("select * from test1")
		// On error reconnect to the server
		if res == nil {
			fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
			done := make(chan int)
    			go reconnect(db, done)
    			<- done
		}
		// Sleep for 0.5 seconds
		time.Sleep(500000000)
	}
}
<|endoftext|>


<commit_before>package query

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
)

// Ensure the parser can parse an empty query.
func TestParser_ParseQuery_Empty(t *testing.T) {
	expr, err := NewParser(strings.NewReader(``), "defField").Parse()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	if expr != nil {
		t.Fatalf("expected nil expr, got %v", expr)
	}
}

// Ensure the parser can parse strings into Query ASTs.
func TestParser_ParseStatement(t *testing.T) {
	defaultField := "defField"

	var tests = []struct {
		s    string
		expr Expr
		err  string
	}{
		{
			s:    `sshd`,
			expr: &FieldExpr{Field: defaultField, Term: "sshd"},
		},
		{
			s: `sshd pamd`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `sshd AND pamd`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `sshd and pamd`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `sshd OR pamd`,
			expr: &BinaryExpr{
				Op:  OR,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `GET apache.status:404`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "GET"},
				RHS: &FieldExpr{Field: "apache.status", Term: "404"},
			},
		},
		{
			s:    `sourceip:192.168.1.22`,
			expr: &FieldExpr{Field: "sourceip", Term: "192.168.1.22"},
		},
		{
			s: `GET AND apache.status:404 OR apache.status:500`,
			expr: &BinaryExpr{
				Op: OR,
				LHS: &BinaryExpr{
					Op:  AND,
					LHS: &FieldExpr{Field: defaultField, Term: "GET"},
					RHS: &FieldExpr{Field: "apache.status", Term: "404"},
				},
				RHS: &FieldExpr{Field: "apache.status", Term: "500"},
			},
		},
		{
			s: `GET AND (apache.status:404 OR apache.status:500)`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "GET"},
				RHS: &ParenExpr{
					Expr: &BinaryExpr{
						Op:  OR,
						LHS: &FieldExpr{Field: "apache.status", Term: "404"},
						RHS: &FieldExpr{Field: "apache.status", Term: "500"},
					},
				},
			},
		},
		{
			s: `GET (apache.status:404 OR apache.status:500)`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "GET"},
				RHS: &ParenExpr{
					Expr: &BinaryExpr{
						Op:  OR,
						LHS: &FieldExpr{Field: "apache.status", Term: "404"},
						RHS: &FieldExpr{Field: "apache.status", Term: "500"},
					},
				},
			},
		},

		// Errors
		{s: `apache.status:`, err: `found 'EOF', expected SEARCH TERM`},
		{s: `GET AND`, err: `found 'EOF', expected FIELD or SEARCH TERM`},
		{s: `GET AND NOT`, err: `found 'NOT', expected FIELD or SEARCH TERM`},
		{s: `:500`, err: `found ':', expected FIELD or SEARCH TERM`},
		{s: `GET (apache.status:404 OR apache.status:500`, err: `found 'EOF', expected )`},
		{s: `GET (apache.status:404 OR apache.status:`, err: `found 'EOF', expected SEARCH TERM`},
	}

	for i, tt := range tests {
		fmt.Println("testing:", tt.s)
		expr, err := NewParser(strings.NewReader(tt.s), defaultField).Parse()
		if !reflect.DeepEqual(tt.err, errstring(err)) {
			t.Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == "" && !reflect.DeepEqual(tt.expr, expr) {
			t.Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v %s\n\ngot=%#v %s\n\n", i, tt.s, tt.expr, tt.expr, expr, expr)
		}
	}
}

// errstring returns the string representation of an error.
func errstring(err error) string {
	if err != nil {
		return err.Error()
	}
	return ""
}
<commit_msg>Add note re testing of parenthesized queries<commit_after>package query

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
)

// Ensure the parser can parse an empty query.
func TestParser_ParseQuery_Empty(t *testing.T) {
	expr, err := NewParser(strings.NewReader(``), "defField").Parse()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	if expr != nil {
		t.Fatalf("expected nil expr, got %v", expr)
	}
}

// Ensure the parser can parse strings into Query ASTs.
// XXX Still missing tests for parenthesized queries.
func TestParser_ParseStatement(t *testing.T) {
	defaultField := "defField"

	var tests = []struct {
		s    string
		expr Expr
		err  string
	}{
		{
			s:    `sshd`,
			expr: &FieldExpr{Field: defaultField, Term: "sshd"},
		},
		{
			s: `sshd pamd`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `sshd AND pamd`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `sshd and pamd`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `sshd OR pamd`,
			expr: &BinaryExpr{
				Op:  OR,
				LHS: &FieldExpr{Field: defaultField, Term: "sshd"},
				RHS: &FieldExpr{Field: defaultField, Term: "pamd"},
			},
		},
		{
			s: `GET apache.status:404`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "GET"},
				RHS: &FieldExpr{Field: "apache.status", Term: "404"},
			},
		},
		{
			s:    `sourceip:192.168.1.22`,
			expr: &FieldExpr{Field: "sourceip", Term: "192.168.1.22"},
		},
		{
			s: `GET AND apache.status:404 OR apache.status:500`,
			expr: &BinaryExpr{
				Op: OR,
				LHS: &BinaryExpr{
					Op:  AND,
					LHS: &FieldExpr{Field: defaultField, Term: "GET"},
					RHS: &FieldExpr{Field: "apache.status", Term: "404"},
				},
				RHS: &FieldExpr{Field: "apache.status", Term: "500"},
			},
		},
		{
			s: `GET AND (apache.status:404 OR apache.status:500)`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "GET"},
				RHS: &ParenExpr{
					Expr: &BinaryExpr{
						Op:  OR,
						LHS: &FieldExpr{Field: "apache.status", Term: "404"},
						RHS: &FieldExpr{Field: "apache.status", Term: "500"},
					},
				},
			},
		},
		{
			s: `GET (apache.status:404 OR apache.status:500)`,
			expr: &BinaryExpr{
				Op:  AND,
				LHS: &FieldExpr{Field: defaultField, Term: "GET"},
				RHS: &ParenExpr{
					Expr: &BinaryExpr{
						Op:  OR,
						LHS: &FieldExpr{Field: "apache.status", Term: "404"},
						RHS: &FieldExpr{Field: "apache.status", Term: "500"},
					},
				},
			},
		},

		// Errors
		{s: `apache.status:`, err: `found 'EOF', expected SEARCH TERM`},
		{s: `GET AND`, err: `found 'EOF', expected FIELD or SEARCH TERM`},
		{s: `GET AND NOT`, err: `found 'NOT', expected FIELD or SEARCH TERM`},
		{s: `:500`, err: `found ':', expected FIELD or SEARCH TERM`},
		{s: `GET (apache.status:404 OR apache.status:500`, err: `found 'EOF', expected )`},
		{s: `GET (apache.status:404 OR apache.status:`, err: `found 'EOF', expected SEARCH TERM`},
	}

	for i, tt := range tests {
		fmt.Println("testing:", tt.s)
		expr, err := NewParser(strings.NewReader(tt.s), defaultField).Parse()
		if !reflect.DeepEqual(tt.err, errstring(err)) {
			t.Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == "" && !reflect.DeepEqual(tt.expr, expr) {
			t.Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v %s\n\ngot=%#v %s\n\n", i, tt.s, tt.expr, tt.expr, expr, expr)
		}
	}
}

// errstring returns the string representation of an error.
func errstring(err error) string {
	if err != nil {
		return err.Error()
	}
	return ""
}
<|endoftext|>


<commit_before>package web

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"regexp/syntax"
	"strings"
)

type regexpPattern struct {
	re     *regexp.Regexp
	prefix string
	names  []string
}

func (p regexpPattern) Prefix() string {
	return p.prefix
}
func (p regexpPattern) Match(r *http.Request, c *C) bool {
	return p.match(r, c, false)
}
func (p regexpPattern) Run(r *http.Request, c *C) {
	p.match(r, c, false)
}

func (p regexpPattern) match(r *http.Request, c *C, dryrun bool) bool {
	matches := p.re.FindStringSubmatch(r.URL.Path)
	if matches == nil || len(matches) == 0 {
		return false
	}

	if c == nil || dryrun || len(matches) == 1 {
		return true
	}

	if c.URLParams == nil {
		c.URLParams = make(map[string]string, len(matches)-1)
	}
	for i := 1; i < len(matches); i++ {
		c.URLParams[p.names[i]] = matches[i]
	}
	return true
}

func (p regexpPattern) String() string {
	return fmt.Sprintf("regexpPattern(%v)", p.re)
}

/*
I'm sorry, dear reader. I really am.

The problem here is to take an arbitrary regular expression and:
1. return a regular expression that is just like it, but left-anchored,
   preferring to return the original if possible.
2. determine a string literal prefix that all matches of this regular expression
   have, much like regexp.Regexp.Prefix(). Unfortunately, Prefix() does not work
   in the presence of anchors, so we need to write it ourselves.

What this actually means is that we need to sketch on the internals of the
standard regexp library to forcefully extract the information we want.

Unfortunately, regexp.Regexp hides a lot of its state, so our abstraction is
going to be pretty leaky. The biggest leak is that we blindly assume that all
regular expressions are perl-style, not POSIX. This is probably Mostly True, and
I think most users of the library probably won't be able to notice.
*/
func sketchOnRegex(re *regexp.Regexp) (*regexp.Regexp, string) {
	rawRe := re.String()
	sRe, err := syntax.Parse(rawRe, syntax.Perl)
	if err != nil {
		log.Printf("WARN(web): unable to parse regexp %v as perl. "+
			"This route might behave unexpectedly.", re)
		return re, ""
	}
	sRe = sRe.Simplify()
	p, err := syntax.Compile(sRe)
	if err != nil {
		log.Printf("WARN(web): unable to compile regexp %v. This "+
			"route might behave unexpectedly.", re)
		return re, ""
	}
	if p.StartCond()&syntax.EmptyBeginText == 0 {
		// I hope doing this is always legal...
		newRe, err := regexp.Compile(`\A` + rawRe)
		if err != nil {
			log.Printf("WARN(web): unable to create a left-"+
				"anchored regexp from %v. This route might "+
				"behave unexpectedly", re)
			return re, ""
		}
		re = newRe
	}

	// Run the regular expression more or less by hand :(
	pc := uint32(p.Start)
	atStart := true
	i := &p.Inst[pc]
	var buf bytes.Buffer
Sadness:
	for {
		switch i.Op {
		case syntax.InstEmptyWidth:
			if !atStart {
				break Sadness
			}
		case syntax.InstCapture, syntax.InstNop:
			// nop!
		case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny,
			syntax.InstRuneAnyNotNL:

			atStart = false
			if len(i.Rune) != 1 ||
				syntax.Flags(i.Arg)&syntax.FoldCase != 0 {
				break Sadness
			}
			buf.WriteRune(i.Rune[0])
		default:
			break Sadness
		}
		pc = i.Out
		i = &p.Inst[pc]
	}
	return re, buf.String()
}

func parseRegexpPattern(re *regexp.Regexp) regexpPattern {
	re, prefix := sketchOnRegex(re)
	rnames := re.SubexpNames()
	// We have to make our own copy since package regexp forbids us
	// from scribbling over the slice returned by SubexpNames().
	names := make([]string, len(rnames))
	for i, rname := range rnames {
		if rname == "" {
			rname = fmt.Sprintf("$%d", i)
		}
		names[i] = rname
	}
	return regexpPattern{
		re:     re,
		prefix: prefix,
		names:  names,
	}
}

type stringPattern struct {
	raw      string
	pats     []string
	literals []string
	isPrefix bool
}

func (s stringPattern) Prefix() string {
	return s.literals[0]
}
func (s stringPattern) Match(r *http.Request, c *C) bool {
	return s.match(r, c, true)
}
func (s stringPattern) Run(r *http.Request, c *C) {
	s.match(r, c, false)
}
func (s stringPattern) match(r *http.Request, c *C, dryrun bool) bool {
	path := r.URL.Path
	var matches map[string]string
	if !dryrun && len(s.pats) > 0 {
		matches = make(map[string]string, len(s.pats))
	}
	for i := 0; i < len(s.pats); i++ {
		if !strings.HasPrefix(path, s.literals[i]) {
			return false
		}
		path = path[len(s.literals[i]):]

		m := strings.IndexRune(path, '/')
		if m == -1 {
			m = len(path)
		}
		if m == 0 {
			// Empty strings are not matches, otherwise routes like
			// "/:foo" would match the path "/"
			return false
		}
		if !dryrun {
			matches[s.pats[i]] = path[:m]
		}
		path = path[m:]
	}
	// There's exactly one more literal than pat.
	if s.isPrefix {
		if !strings.HasPrefix(path, s.literals[len(s.pats)]) {
			return false
		}
	} else {
		if path != s.literals[len(s.pats)] {
			return false
		}
	}

	if c == nil || dryrun {
		return true
	}

	if c.URLParams == nil {
		c.URLParams = matches
	} else {
		for k, v := range matches {
			c.URLParams[k] = v
		}
	}
	return true
}

func (s stringPattern) String() string {
	return fmt.Sprintf("stringPattern(%q, %v)", s.raw, s.isPrefix)
}

var patternRe = regexp.MustCompile(`/:([^/]+)`)

func parseStringPattern(s string) stringPattern {
	var isPrefix bool
	// Routes that end in an asterisk ("*") are prefix routes
	if len(s) > 0 && s[len(s)-1] == '*' {
		s = s[:len(s)-1]
		isPrefix = true
	}

	matches := patternRe.FindAllStringSubmatchIndex(s, -1)
	pats := make([]string, len(matches))
	literals := make([]string, len(matches)+1)
	n := 0
	for i, match := range matches {
		a, b := match[2], match[3]
		literals[i] = s[n : a-1] // Need to leave off the colon
		pats[i] = s[a:b]
		n = b
	}
	literals[len(matches)] = s[n:]
	return stringPattern{
		raw:      s,
		pats:     pats,
		literals: literals,
		isPrefix: isPrefix,
	}
}
<commit_msg>Don't look up s.literals[i] twice<commit_after>package web

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"regexp/syntax"
	"strings"
)

type regexpPattern struct {
	re     *regexp.Regexp
	prefix string
	names  []string
}

func (p regexpPattern) Prefix() string {
	return p.prefix
}
func (p regexpPattern) Match(r *http.Request, c *C) bool {
	return p.match(r, c, false)
}
func (p regexpPattern) Run(r *http.Request, c *C) {
	p.match(r, c, false)
}

func (p regexpPattern) match(r *http.Request, c *C, dryrun bool) bool {
	matches := p.re.FindStringSubmatch(r.URL.Path)
	if matches == nil || len(matches) == 0 {
		return false
	}

	if c == nil || dryrun || len(matches) == 1 {
		return true
	}

	if c.URLParams == nil {
		c.URLParams = make(map[string]string, len(matches)-1)
	}
	for i := 1; i < len(matches); i++ {
		c.URLParams[p.names[i]] = matches[i]
	}
	return true
}

func (p regexpPattern) String() string {
	return fmt.Sprintf("regexpPattern(%v)", p.re)
}

/*
I'm sorry, dear reader. I really am.

The problem here is to take an arbitrary regular expression and:
1. return a regular expression that is just like it, but left-anchored,
   preferring to return the original if possible.
2. determine a string literal prefix that all matches of this regular expression
   have, much like regexp.Regexp.Prefix(). Unfortunately, Prefix() does not work
   in the presence of anchors, so we need to write it ourselves.

What this actually means is that we need to sketch on the internals of the
standard regexp library to forcefully extract the information we want.

Unfortunately, regexp.Regexp hides a lot of its state, so our abstraction is
going to be pretty leaky. The biggest leak is that we blindly assume that all
regular expressions are perl-style, not POSIX. This is probably Mostly True, and
I think most users of the library probably won't be able to notice.
*/
func sketchOnRegex(re *regexp.Regexp) (*regexp.Regexp, string) {
	rawRe := re.String()
	sRe, err := syntax.Parse(rawRe, syntax.Perl)
	if err != nil {
		log.Printf("WARN(web): unable to parse regexp %v as perl. "+
			"This route might behave unexpectedly.", re)
		return re, ""
	}
	sRe = sRe.Simplify()
	p, err := syntax.Compile(sRe)
	if err != nil {
		log.Printf("WARN(web): unable to compile regexp %v. This "+
			"route might behave unexpectedly.", re)
		return re, ""
	}
	if p.StartCond()&syntax.EmptyBeginText == 0 {
		// I hope doing this is always legal...
		newRe, err := regexp.Compile(`\A` + rawRe)
		if err != nil {
			log.Printf("WARN(web): unable to create a left-"+
				"anchored regexp from %v. This route might "+
				"behave unexpectedly", re)
			return re, ""
		}
		re = newRe
	}

	// Run the regular expression more or less by hand :(
	pc := uint32(p.Start)
	atStart := true
	i := &p.Inst[pc]
	var buf bytes.Buffer
Sadness:
	for {
		switch i.Op {
		case syntax.InstEmptyWidth:
			if !atStart {
				break Sadness
			}
		case syntax.InstCapture, syntax.InstNop:
			// nop!
		case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny,
			syntax.InstRuneAnyNotNL:

			atStart = false
			if len(i.Rune) != 1 ||
				syntax.Flags(i.Arg)&syntax.FoldCase != 0 {
				break Sadness
			}
			buf.WriteRune(i.Rune[0])
		default:
			break Sadness
		}
		pc = i.Out
		i = &p.Inst[pc]
	}
	return re, buf.String()
}

func parseRegexpPattern(re *regexp.Regexp) regexpPattern {
	re, prefix := sketchOnRegex(re)
	rnames := re.SubexpNames()
	// We have to make our own copy since package regexp forbids us
	// from scribbling over the slice returned by SubexpNames().
	names := make([]string, len(rnames))
	for i, rname := range rnames {
		if rname == "" {
			rname = fmt.Sprintf("$%d", i)
		}
		names[i] = rname
	}
	return regexpPattern{
		re:     re,
		prefix: prefix,
		names:  names,
	}
}

type stringPattern struct {
	raw      string
	pats     []string
	literals []string
	isPrefix bool
}

func (s stringPattern) Prefix() string {
	return s.literals[0]
}
func (s stringPattern) Match(r *http.Request, c *C) bool {
	return s.match(r, c, true)
}
func (s stringPattern) Run(r *http.Request, c *C) {
	s.match(r, c, false)
}
func (s stringPattern) match(r *http.Request, c *C, dryrun bool) bool {
	path := r.URL.Path
	var matches map[string]string
	if !dryrun && len(s.pats) > 0 {
		matches = make(map[string]string, len(s.pats))
	}
	for i := 0; i < len(s.pats); i++ {
		sli := s.literals[i]
		if !strings.HasPrefix(path, sli) {
			return false
		}
		path = path[len(sli):]

		m := strings.IndexRune(path, '/')
		if m == -1 {
			m = len(path)
		}
		if m == 0 {
			// Empty strings are not matches, otherwise routes like
			// "/:foo" would match the path "/"
			return false
		}
		if !dryrun {
			matches[s.pats[i]] = path[:m]
		}
		path = path[m:]
	}
	// There's exactly one more literal than pat.
	if s.isPrefix {
		if !strings.HasPrefix(path, s.literals[len(s.pats)]) {
			return false
		}
	} else {
		if path != s.literals[len(s.pats)] {
			return false
		}
	}

	if c == nil || dryrun {
		return true
	}

	if c.URLParams == nil {
		c.URLParams = matches
	} else {
		for k, v := range matches {
			c.URLParams[k] = v
		}
	}
	return true
}

func (s stringPattern) String() string {
	return fmt.Sprintf("stringPattern(%q, %v)", s.raw, s.isPrefix)
}

var patternRe = regexp.MustCompile(`/:([^/]+)`)

func parseStringPattern(s string) stringPattern {
	var isPrefix bool
	// Routes that end in an asterisk ("*") are prefix routes
	if len(s) > 0 && s[len(s)-1] == '*' {
		s = s[:len(s)-1]
		isPrefix = true
	}

	matches := patternRe.FindAllStringSubmatchIndex(s, -1)
	pats := make([]string, len(matches))
	literals := make([]string, len(matches)+1)
	n := 0
	for i, match := range matches {
		a, b := match[2], match[3]
		literals[i] = s[n : a-1] // Need to leave off the colon
		pats[i] = s[a:b]
		n = b
	}
	literals[len(matches)] = s[n:]
	return stringPattern{
		raw:      s,
		pats:     pats,
		literals: literals,
		isPrefix: isPrefix,
	}
}
<|endoftext|>


<commit_before>package mtgprice

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"

	"github.com/broady/mtgprice/gatherer"
	"github.com/broady/mtgprice/tcg"
	"github.com/cznic/kv"
)

type Opts struct {
	Filename, CardData string
}

type Client struct {
	db *kv.DB
	mu sync.RWMutex

	// Immutable.
	cards map[string]*CardInfo
}

type CardInfo struct {
	Name  string   `json:"name"`
	Names []string `json:"names,omitempty"`
	// NOTE: there is one card with .5 mana cost.
	CMC          float64  `json:"cmc"`
	MultiverseID *int     `json:"multiverseid,omitempty"`
	ManaCost     string   `json:"manaCost"`
	Rarity       string   `json:"rarity"`
	Power        string   `json:"power,omitempty"`
	Toughness    string   `json:"toughness,omitempty"`
	Type         string   `json:"type"`
	Types        []string `json:"types"`
	Colors       []string `json:"colors"`
	Text         string   `json:"text"`
}

func (c *CardInfo) String() string {
	return c.Name
}

func (c *CardInfo) Detail() string {
	s := fmt.Sprintf("%v %v", c.Name, c.ManaCost)
	for _, t := range c.Types {
		if t == "Creature" {
			s += fmt.Sprintf(" (%v/%v)", c.Power, c.Toughness)
		}
	}
	s += "\n" + c.Type
	if c.Text != "" {
		s += "\n" + c.Text
	}
	return s
}

// entry represents an entry for the database.
type entry struct {
	TCGPrice     *tcg.Price
	GathererInfo *gatherer.CardInfo
}

func Open(opts Opts) (c *Client, err error) {
	c = new(Client)
	c.cards, err = readCardData(opts.CardData)
	if err != nil {
		return
	}
	c.db, err = kv.Open(opts.Filename, &kv.Options{})
	if err != nil {
		log.Printf("Creating new database... %v", err)
		c.db, err = kv.Create(opts.Filename, &kv.Options{})
	}
	return
}

func readCardData(fn string) (map[string]*CardInfo, error) {
	f, err := os.Open(fn)
	if err != nil {
		return nil, err
	}
	var cardData map[string]*CardInfo
	if err := json.NewDecoder(f).Decode(&cardData); err != nil {
		return nil, fmt.Errorf("could not read card json file: %v", err)
	}
	// Normalize.
	out := make(map[string]*CardInfo)
	for _, card := range cardData {
		if len(card.Names) != 0 {
			out[strings.ToLower(strings.Join(card.Names, " & "))] = card
			out[strings.ToLower(strings.Join(card.Names, " / "))] = card
			out[strings.ToLower(strings.Join(card.Names, " // "))] = card
		}
		card.Name = normalizeCardName(card.Name)
		out[strings.ToLower(card.Name)] = card
	}
	return out, nil
}

func (c *Client) Close() error {
	if c != nil && c.db != nil {
		return c.db.Close()
	}
	return nil
}

func normalizeCardName(s string) string {
	s = strings.Replace(s, "Æ", "Ae", -1)
	return strings.Replace(s, "’", "'", -1)
}

func (c *Client) CardInfo(cardName string) (ci CardInfo, ok bool) {
	card, ok := c.cards[strings.ToLower(normalizeCardName(cardName))]
	if ok {
		return *card, ok
	}
	return
}

func (c *Client) getEntry(cardName string) (e entry, err error) {
	cardName = normalizeCardName(cardName)
	ci, ok := c.CardInfo(cardName)
	if !ok {
		return e, errors.New("card not found")
	}
	err = c.get(ci.Name, &e)
	if err != nil && err != doesNotExistError {
		return e, err
	}
	if err == nil && e.TCGPrice != nil && e.GathererInfo != nil {
		//log.Printf("cache hit: %s", cardName)
		return e, nil
	}
	touch := false
	if e.TCGPrice == nil {
		prices, err := c.priceForCard(ci)
		if err != nil {
			log.Println("Fetching price:", err)
		} else {
			e.TCGPrice = prices
			touch = true
		}
	}
	if e.GathererInfo == nil {
		name := ci.Name
		if len(ci.Names) != 0 {
			name = strings.Join(ci.Names, " & ")
		}
		gInfo, err := gatherer.InfoByName(name)
		if err != nil {
			log.Println("Fetching gatherer:", err)
		} else {
			e.GathererInfo = gInfo
			touch = true
		}
	}
	if touch {
		go c.set(ci.Name, e)
	}
	return e, nil
}

type info struct {
	entry
	CardInfo
}

func (c *Client) RichInfo(cardName string) (i info, err error) {
	ci, ok := c.CardInfo(cardName)
	if !ok {
		return i, errors.New("could not find card")
	}
	i.CardInfo = ci

	e, err := c.getEntry(cardName)
	if err != nil {
		return
	}
	i.entry = e
	return
}

func (c *Client) PriceForCard(cardName string) (prices tcg.Price, err error) {
	e, err := c.getEntry(cardName)
	if err != nil {
		return
	}
	prices = *e.TCGPrice
	return
}

var doesNotExistError = errors.New("val does not exist")

func (c *Client) get(key string, val interface{}) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	v, err := c.db.Get(nil, []byte(key))
	if err != nil {
		return err
	}
	if len(v) == 0 {
		return doesNotExistError
	}
	return gob.NewDecoder(bytes.NewBuffer(v)).Decode(val)
}

func (c *Client) set(key string, val interface{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	b := new(bytes.Buffer)
	err := gob.NewEncoder(b).Encode(val)
	if err != nil {
		return err
	}
	err = c.db.Set([]byte(key), b.Bytes())
	if err != nil {
		log.Printf("ERROR writing to cache: %v", err)
	}
	return err
}

func (c *Client) priceForCard(ci CardInfo) (prices *tcg.Price, err error) {
	name := ci.Name
	if len(ci.Names) != 0 {
		name = strings.Join(ci.Names, " // ")
	}
	return tcg.Get(name)
}
<commit_msg>load legalities, show banned and restricted<commit_after>package mtgprice

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"

	"github.com/broady/mtgprice/gatherer"
	"github.com/broady/mtgprice/tcg"
	"github.com/cznic/kv"
)

type Opts struct {
	Filename, CardData string
}

type Client struct {
	db *kv.DB
	mu sync.RWMutex

	// Immutable.
	cards map[string]*CardInfo
}

type CardInfo struct {
	Name  string   `json:"name"`
	Names []string `json:"names,omitempty"`
	// NOTE: there is one card with .5 mana cost.
	CMC          float64    `json:"cmc"`
	MultiverseID *int       `json:"multiverseid,omitempty"`
	ManaCost     string     `json:"manaCost"`
	Rarity       string     `json:"rarity"`
	Power        string     `json:"power,omitempty"`
	Toughness    string     `json:"toughness,omitempty"`
	Type         string     `json:"type"`
	Types        []string   `json:"types"`
	Colors       []string   `json:"colors"`
	Text         string     `json:"text"`
	Legalities   []Legality `json:"legalities"`
}

type Legality struct {
	Format   string `json:"format"`
	Legality string `json:"legality"`
}

func (c *CardInfo) String() string {
	return c.Name
}

func (c *CardInfo) Detail() string {
	s := fmt.Sprintf("%v %v", c.Name, c.ManaCost)
	for _, t := range c.Types {
		if t == "Creature" {
			s += fmt.Sprintf(" (%v/%v)", c.Power, c.Toughness)
		}
	}
	s += "\n" + c.Type
	if c.Text != "" {
		s += "\n" + c.Text
	}
	legality := map[string][]string{}
	for _, l := range c.Legalities {
		if l.Legality != "Legal" {
			legality[l.Legality] = append(legality[l.Legality], l.Format)
		}
	}
	for l, fs := range legality {
		s += fmt.Sprintf("\n%v: %v", l, strings.Join(fs, ", "))
	}
	return s
}

// entry represents an entry for the database.
type entry struct {
	TCGPrice     *tcg.Price
	GathererInfo *gatherer.CardInfo
}

func Open(opts Opts) (c *Client, err error) {
	c = new(Client)
	c.cards, err = readCardData(opts.CardData)
	if err != nil {
		return
	}
	c.db, err = kv.Open(opts.Filename, &kv.Options{})
	if err != nil {
		log.Printf("Creating new database... %v", err)
		c.db, err = kv.Create(opts.Filename, &kv.Options{})
	}
	return
}

func readCardData(fn string) (map[string]*CardInfo, error) {
	f, err := os.Open(fn)
	if err != nil {
		return nil, err
	}
	var cardData map[string]*CardInfo
	if err := json.NewDecoder(f).Decode(&cardData); err != nil {
		return nil, fmt.Errorf("could not read card json file: %v", err)
	}
	// Normalize.
	out := make(map[string]*CardInfo)
	for _, card := range cardData {
		if len(card.Names) != 0 {
			out[strings.ToLower(strings.Join(card.Names, " & "))] = card
			out[strings.ToLower(strings.Join(card.Names, " / "))] = card
			out[strings.ToLower(strings.Join(card.Names, " // "))] = card
		}
		card.Name = normalizeCardName(card.Name)
		out[strings.ToLower(card.Name)] = card
	}
	return out, nil
}

func (c *Client) Close() error {
	if c != nil && c.db != nil {
		return c.db.Close()
	}
	return nil
}

func normalizeCardName(s string) string {
	s = strings.Replace(s, "Æ", "Ae", -1)
	return strings.Replace(s, "’", "'", -1)
}

func (c *Client) CardInfo(cardName string) (ci CardInfo, ok bool) {
	card, ok := c.cards[strings.ToLower(normalizeCardName(cardName))]
	if ok {
		return *card, ok
	}
	return
}

func (c *Client) getEntry(cardName string) (e entry, err error) {
	cardName = normalizeCardName(cardName)
	ci, ok := c.CardInfo(cardName)
	if !ok {
		return e, errors.New("card not found")
	}
	err = c.get(ci.Name, &e)
	if err != nil && err != doesNotExistError {
		return e, err
	}
	if err == nil && e.TCGPrice != nil && e.GathererInfo != nil {
		//log.Printf("cache hit: %s", cardName)
		return e, nil
	}
	touch := false
	if e.TCGPrice == nil {
		prices, err := c.priceForCard(ci)
		if err != nil {
			log.Println("Fetching price:", err)
		} else {
			e.TCGPrice = prices
			touch = true
		}
	}
	if e.GathererInfo == nil {
		name := ci.Name
		if len(ci.Names) != 0 {
			name = strings.Join(ci.Names, " & ")
		}
		gInfo, err := gatherer.InfoByName(name)
		if err != nil {
			log.Println("Fetching gatherer:", err)
		} else {
			e.GathererInfo = gInfo
			touch = true
		}
	}
	if touch {
		go c.set(ci.Name, e)
	}
	return e, nil
}

type info struct {
	entry
	CardInfo
}

func (c *Client) RichInfo(cardName string) (i info, err error) {
	ci, ok := c.CardInfo(cardName)
	if !ok {
		return i, errors.New("could not find card")
	}
	i.CardInfo = ci

	e, err := c.getEntry(cardName)
	if err != nil {
		return
	}
	i.entry = e
	return
}

func (c *Client) PriceForCard(cardName string) (prices tcg.Price, err error) {
	e, err := c.getEntry(cardName)
	if err != nil {
		return
	}
	prices = *e.TCGPrice
	return
}

var doesNotExistError = errors.New("val does not exist")

func (c *Client) get(key string, val interface{}) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	v, err := c.db.Get(nil, []byte(key))
	if err != nil {
		return err
	}
	if len(v) == 0 {
		return doesNotExistError
	}
	return gob.NewDecoder(bytes.NewBuffer(v)).Decode(val)
}

func (c *Client) set(key string, val interface{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	b := new(bytes.Buffer)
	err := gob.NewEncoder(b).Encode(val)
	if err != nil {
		return err
	}
	err = c.db.Set([]byte(key), b.Bytes())
	if err != nil {
		log.Printf("ERROR writing to cache: %v", err)
	}
	return err
}

func (c *Client) priceForCard(ci CardInfo) (prices *tcg.Price, err error) {
	name := ci.Name
	if len(ci.Names) != 0 {
		name = strings.Join(ci.Names, " // ")
	}
	return tcg.Get(name)
}
<|endoftext|>