<commit_before>package triton

import (
	"bufio"
	"errors"
	"fmt"
	"gopkg.in/fsnotify.v1"
	"html/template"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// Server provides static web hosting and a very minimal Content-Management-System, if it
// could even be called that. It searches the current working directory of execution recursively
// for .tmpl files containing valid html/templates, .css files, and .js files. It watches the file
// system for changes and updates the static site accordingly without restarting.
//
// Template files provide two different, but simple, behaviors depending whether they are located
// in dot-directories.
//
// If a .tmpl file is within a dot directory, it is parsed and added to the master static Template
// for use by other templates.
//
// If a .tmpl file is not within a dot directory, it is parsed and added to the master static
// Template. Additionally, a URL entry to that file location and template filename (without the
// extension) is created for web clients to visit. The template executed to create that particular
// page will be the template filename (again, without extension). A quick example:
//
// If the Server was executed at <ROOT>, hosting at SITE.com, and a template file is located at
// <ROOT>/foo/bar/baz.tmpl, then a web client can go to SITE.com/foo/bar/baz.tmpl and the server
// will execute the template named "baz" and serve it.
//
// The special case is the file "#.tmpl", which will serve and match the directory it is contained
// in. So if <ROOT> hosting SITE.com has <ROOT>/#.tmpl, then the client can go to SITE.com (the
// home page!) and be served template "/".
//
// CSS and Javascript files behave as expected with the caveat that they must not be located in
// any dot-directories.
type Server struct {
	// WebHost is used to handle http requests. Do not call
	// the WebHost's ListenAndServe nor ListenAndServeTLS functions. Call
	// the triton Server's variants instead for proper setup to occur.
	WebHost *http.Server
	// ErrChan can be provided by the client, or is created after the
	// server starts listening for requests. The client must listen to
	// the channel for errors, and a closed channel indicates that the server is
	// no longer properly updating its content and must be restarted.
	ErrChan chan error
	// Map between relative URL paths and template names to execute.
	staticTemplates map[string]string
	// Cached static assets.
	staticAssets map[string][]byte
	// Cached static HTML content.
	templates *template.Template
}

// initializeContent maps all content to URI locations.
func (s *Server) initializeContent() error {
	s.staticTemplates = make(map[string]string)
	s.staticAssets = make(map[string][]byte)
	s.templates = nil
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}
	cw := NewContentWalker(".tmpl", ".css", ".js")
	if err = filepath.Walk(pwd, cw.Walk); err != nil {
		return err
	}
	hiddenTmplFiles, okHidden := cw.HiddenFiles(".tmpl")
	tmplFiles, ok := cw.Files(".tmpl")
	if !ok {
		return errors.New(fmt.Sprintf("No content walker .tmpl files"))
	}
	if okHidden {
		s.templates, err = template.ParseFiles(hiddenTmplFiles...)
		if err != nil {
			return err
		}
		s.templates, err = s.templates.ParseFiles(tmplFiles...)
	} else {
		s.templates, err = template.ParseFiles(tmplFiles...)
	}
	if err != nil {
		return err
	}
	for _, file := range tmplFiles {
		rel, err := filepath.Rel(pwd, file)
		if err != nil {
			return err
		}
		baseWithExt := filepath.Base(file)
		base := baseWithExt
		relNoExt := rel
		if filepath.Ext(file) != "" {
			base = baseWithExt[:strings.LastIndex(baseWithExt, ".")]
			relNoExt = rel[:strings.LastIndex(rel, ".")]
			if base == "#" {
				base = "/" + relNoExt[:len(relNoExt)-1]
				relNoExt = relNoExt[:len(relNoExt)-1]
			}
		}
		s.staticTemplates[base] = "/" + relNoExt
	}
	cssFiles, _ := cw.Files(".css")
	for _, file := range cssFiles {
		err = s.readStaticAssetsFile(pwd, file)
		if err != nil {
			return err
		}
	}
	jsFiles, _ := cw.Files(".js")
	for _, file := range jsFiles {
		err = s.readStaticAssetsFile(pwd, file)
		if err != nil {
			return err
		}
	}
	return nil
}

// readStaticAssetsFile associates a specific asset file path to its content.
func (s *Server) readStaticAssetsFile(baseDir string, assetFile string) error {
	file, err := os.Open(assetFile)
	if err != nil {
		return err
	}
	defer file.Close()
	var asset []byte
	scan := bufio.NewScanner(file)
	for scan.Scan() {
		asset = append(asset, scan.Bytes()...)
	}
	relPath, err := filepath.Rel(baseDir, assetFile)
	if err != nil {
		return err
	}
	s.staticAssets["/"+relPath] = asset
	return nil
}

// applyHandlers takes the URI mapped static content and creates web handlers to service
// the content.
func (s *Server) applyHandlers() {
	basicMux := http.NewServeMux()
	for path, content := range s.staticAssets {
		basicMux.HandleFunc(path, func(myContent []byte) func(http.ResponseWriter, *http.Request) {
			return func(wr http.ResponseWriter, req *http.Request) {
				wr.Write(myContent)
			}
		}(content))
	}
	for tmplName, path := range s.staticTemplates {
		basicMux.HandleFunc(path, func(myTmplName string, myTemplate *template.Template) func(http.ResponseWriter, *http.Request) {
			return func(wr http.ResponseWriter, req *http.Request) {
				myTemplate.ExecuteTemplate(wr, myTmplName, nil)
			}
		}(tmplName, s.templates))
	}
	s.WebHost.Handler = basicMux
}

// async_fsnotifylistener is a separate goroutine handling any changes to the filesystem,
// updating the site without taking it down in the process.
func (s *Server) async_fsnotifylistener() {
	if s.ErrChan == nil {
		s.ErrChan = make(chan error)
	}
	pwd, err := os.Getwd()
	if err != nil {
		s.ErrChan <- err
		close(s.ErrChan)
		return
	}
	tempR := recursiveWatcher(make([]string, 0))
	r := &tempR
	w, err := r.RecursivelyWatch(pwd)
	if err != nil {
		s.ErrChan <- err
		close(s.ErrChan)
		return
	}
	defer w.Close()
	for {
		select {
		case err = <-w.Errors:
			s.ErrChan <- err
		case event := <-w.Events:
			// The following could be quite smarter: for now,
			// be dumb and rebuild the eentire tree.
			switch event.Op {
			case fsnotify.Write:
				fallthrough
			case fsnotify.Rename:
				fallthrough
			case fsnotify.Create:
				fallthrough
			case fsnotify.Remove:
				s.initializeContent()
				s.applyHandlers()
				err = w.Close()
				if err != nil {
					s.ErrChan <- err
					close(s.ErrChan)
					return
				}
				w, err = r.RecursivelyWatch(pwd)
				if err != nil {
					s.ErrChan <- err
					close(s.ErrChan)
					return
				}
			}
		}
	}
}

// ListenAndServe initializes the Server before using the WebHost to serve http
// requests.
func (s *Server) ListenAndServe() error {
	err := s.initializeContent()
	if err != nil {
		return err
	}
	s.applyHandlers()
	go s.async_fsnotifylistener()
	return s.WebHost.ListenAndServe()
}

// ListenAndServeTLS initializes the Server before using the WebHost to serve
// http over TLS.
func (s *Server) ListenAndServeTLS(certFile string, keyFile string) error {
	err := s.initializeContent()
	if err != nil {
		return err
	}
	s.applyHandlers()
	go s.async_fsnotifylistener()
	return s.WebHost.ListenAndServeTLS(certFile, keyFile)
}
<commit_msg>Bugfix for hidden template files not being filtered correctly<commit_after>package triton

import (
	"bufio"
	"errors"
	"fmt"
	"gopkg.in/fsnotify.v1"
	"html/template"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// Server provides static web hosting and a very minimal Content-Management-System, if it
// could even be called that. It searches the current working directory of execution recursively
// for .tmpl files containing valid html/templates, .css files, and .js files. It watches the file
// system for changes and updates the static site accordingly without restarting.
//
// Template files provide two different, but simple, behaviors depending whether they are located
// in dot-directories.
//
// If a .tmpl file is within a dot directory, it is parsed and added to the master static Template
// for use by other templates.
//
// If a .tmpl file is not within a dot directory, it is parsed and added to the master static
// Template. Additionally, a URL entry to that file location and template filename (without the
// extension) is created for web clients to visit. The template executed to create that particular
// page will be the template filename (again, without extension). A quick example:
//
// If the Server was executed at <ROOT>, hosting at SITE.com, and a template file is located at
// <ROOT>/foo/bar/baz.tmpl, then a web client can go to SITE.com/foo/bar/baz.tmpl and the server
// will execute the template named "baz" and serve it.
//
// The special case is the file "#.tmpl", which will serve and match the directory it is contained
// in. So if <ROOT> hosting SITE.com has <ROOT>/#.tmpl, then the client can go to SITE.com (the
// home page!) and be served template "/".
//
// CSS and Javascript files behave as expected with the caveat that they must not be located in
// any dot-directories.
type Server struct {
	// WebHost is used to handle http requests. Do not call
	// the WebHost's ListenAndServe nor ListenAndServeTLS functions. Call
	// the triton Server's variants instead for proper setup to occur.
	WebHost *http.Server
	// ErrChan can be provided by the client, or is created after the
	// server starts listening for requests. The client must listen to
	// the channel for errors, and a closed channel indicates that the server is
	// no longer properly updating its content and must be restarted.
	ErrChan chan error
	// Map between relative URL paths and template names to execute.
	staticTemplates map[string]string
	// Cached static assets.
	staticAssets map[string][]byte
	// Cached static HTML content.
	templates *template.Template
}

// initializeContent maps all content to URI locations.
func (s *Server) initializeContent() error {
	s.staticTemplates = make(map[string]string)
	s.staticAssets = make(map[string][]byte)
	s.templates = nil
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}
	cw := NewContentWalker(".tmpl", ".css", ".js")
	if err = filepath.Walk(pwd, cw.Walk); err != nil {
		return err
	}
	hiddenTmplFiles, okHidden := cw.HiddenFiles(".tmpl")
	tmplFiles, ok := cw.Files(".tmpl")
	if !ok {
		return errors.New(fmt.Sprintf("No content walker .tmpl files"))
	}
	if okHidden && len(hiddenTmplFiles) > 0 {
		s.templates, err = template.ParseFiles(hiddenTmplFiles...)
		if err != nil {
			return err
		}
		s.templates, err = s.templates.ParseFiles(tmplFiles...)
	} else {
		s.templates, err = template.ParseFiles(tmplFiles...)
	}
	if err != nil {
		return err
	}
	for _, file := range tmplFiles {
		rel, err := filepath.Rel(pwd, file)
		if err != nil {
			return err
		}
		baseWithExt := filepath.Base(file)
		base := baseWithExt
		relNoExt := rel
		if filepath.Ext(file) != "" {
			base = baseWithExt[:strings.LastIndex(baseWithExt, ".")]
			relNoExt = rel[:strings.LastIndex(rel, ".")]
			if base == "#" {
				base = "/" + relNoExt[:len(relNoExt)-1]
				relNoExt = relNoExt[:len(relNoExt)-1]
			}
		}
		s.staticTemplates[base] = "/" + relNoExt
	}
	cssFiles, _ := cw.Files(".css")
	for _, file := range cssFiles {
		err = s.readStaticAssetsFile(pwd, file)
		if err != nil {
			return err
		}
	}
	jsFiles, _ := cw.Files(".js")
	for _, file := range jsFiles {
		err = s.readStaticAssetsFile(pwd, file)
		if err != nil {
			return err
		}
	}
	return nil
}

// readStaticAssetsFile associates a specific asset file path to its content.
func (s *Server) readStaticAssetsFile(baseDir string, assetFile string) error {
	file, err := os.Open(assetFile)
	if err != nil {
		return err
	}
	defer file.Close()
	var asset []byte
	scan := bufio.NewScanner(file)
	for scan.Scan() {
		asset = append(asset, scan.Bytes()...)
	}
	relPath, err := filepath.Rel(baseDir, assetFile)
	if err != nil {
		return err
	}
	s.staticAssets["/"+relPath] = asset
	return nil
}

// applyHandlers takes the URI mapped static content and creates web handlers to service
// the content.
func (s *Server) applyHandlers() {
	basicMux := http.NewServeMux()
	for path, content := range s.staticAssets {
		basicMux.HandleFunc(path, func(myContent []byte) func(http.ResponseWriter, *http.Request) {
			return func(wr http.ResponseWriter, req *http.Request) {
				wr.Write(myContent)
			}
		}(content))
	}
	for tmplName, path := range s.staticTemplates {
		basicMux.HandleFunc(path, func(myTmplName string, myTemplate *template.Template) func(http.ResponseWriter, *http.Request) {
			return func(wr http.ResponseWriter, req *http.Request) {
				myTemplate.ExecuteTemplate(wr, myTmplName, nil)
			}
		}(tmplName, s.templates))
	}
	s.WebHost.Handler = basicMux
}

// async_fsnotifylistener is a separate goroutine handling any changes to the filesystem,
// updating the site without taking it down in the process.
func (s *Server) async_fsnotifylistener() {
	if s.ErrChan == nil {
		s.ErrChan = make(chan error)
	}
	pwd, err := os.Getwd()
	if err != nil {
		s.ErrChan <- err
		close(s.ErrChan)
		return
	}
	tempR := recursiveWatcher(make([]string, 0))
	r := &tempR
	w, err := r.RecursivelyWatch(pwd)
	if err != nil {
		s.ErrChan <- err
		close(s.ErrChan)
		return
	}
	defer w.Close()
	for {
		select {
		case err = <-w.Errors:
			s.ErrChan <- err
		case event := <-w.Events:
			// The following could be quite smarter: for now,
			// be dumb and rebuild the eentire tree.
			switch event.Op {
			case fsnotify.Write:
				fallthrough
			case fsnotify.Rename:
				fallthrough
			case fsnotify.Create:
				fallthrough
			case fsnotify.Remove:
				s.initializeContent()
				s.applyHandlers()
				err = w.Close()
				if err != nil {
					s.ErrChan <- err
					close(s.ErrChan)
					return
				}
				w, err = r.RecursivelyWatch(pwd)
				if err != nil {
					s.ErrChan <- err
					close(s.ErrChan)
					return
				}
			}
		}
	}
}

// ListenAndServe initializes the Server before using the WebHost to serve http
// requests.
func (s *Server) ListenAndServe() error {
	err := s.initializeContent()
	if err != nil {
		return err
	}
	s.applyHandlers()
	go s.async_fsnotifylistener()
	return s.WebHost.ListenAndServe()
}

// ListenAndServeTLS initializes the Server before using the WebHost to serve
// http over TLS.
func (s *Server) ListenAndServeTLS(certFile string, keyFile string) error {
	err := s.initializeContent()
	if err != nil {
		return err
	}
	s.applyHandlers()
	go s.async_fsnotifylistener()
	return s.WebHost.ListenAndServeTLS(certFile, keyFile)
}
<|endoftext|>


<commit_before>package commandevaluators

import (
	"errors"
	"log"
	"strings"

	"github.com/byuoitav/av-api/base"
	"github.com/byuoitav/av-api/dbo"
)

//MuteDefault implements CommandEvaluation
type MuteDefault struct {
}

/*
 	Evalute takes a public room struct, scans the struct and builds any needed
	actions based on the contents of the struct.
*/
func (p *MuteDefault) Evaluate(room base.PublicRoom) ([]base.ActionStructure, error) {

	log.Printf("Evaluating for Mute command.")

	//create array of type ActionStructure
	actions := []base.ActionStructure{}

	if room.Muted != nil && *room.Muted {

		//general mute command
		log.Printf("Room-wide Mute request recieved. Retrieving all devices.")

		//get all devices
		devices, err := dbo.GetDevicesByBuildingAndRoomAndRole(room.Building, room.Room, "AudioOut")
		if err != nil {
			return []base.ActionStructure{}, err
		}

		log.Printf("Muting all devices in room.")

		for i := range devices {
			if devices[i].Output {
				log.Printf("Adding device %+v", devices[i].Name)

				actions = append(actions, base.ActionStructure{
					Action:              "Mute",
					GeneratingEvaluator: "MuteDefault",
					Device:              devices[i],
					DeviceSpecific:      false,
				})
			}
		}
	}

	//scan the room struct
	log.Printf("Evaluating audio devices for Mute command.")

	//generate commands
	for _, audioDevice := range room.AudioDevices {
		if audioDevice.Muted != nil && *audioDevice.Muted {

			//get the device
			device, err := dbo.GetDeviceByName(room.Building, room.Room, audioDevice.Name)
			if err != nil {
				return []base.ActionStructure{}, err
			}

			actions = append(actions, base.ActionStructure{
				Action:              "Mute",
				GeneratingEvaluator: "MuteDefault",
				Device:              device,
				DeviceSpecific:      true,
			})

		}

	}

	return actions, nil

}

// Validate takes an ActionStructure and determines if the command and parameter are valid for the device specified
func (p *MuteDefault) Validate(action base.ActionStructure) error {

	log.Printf("Validating mute action for command \"UnMute\".")

	ok, _ := checkCommands(action.Device.Commands, "UnMute")

	if !ok || !strings.EqualFold(action.Action, "UnMute") {
		log.Printf("ERROR. %s is an invalid command for %s", action.Action, action.Device.Name)
		return errors.New(action.Action + " is an invalid command for" + action.Device.Name)
	}

	log.Printf("Done.")

	return nil
}

//  GetIncompatableActions returns a list of commands that are incompatabl with this one (i.e. 'standby' and 'power on', or 'mute' and 'volume up')
func (p *MuteDefault) GetIncompatibleCommands() (incompatibleActions []string) {

	incompatibleActions = []string{
		"UnMute",
	}

	return
}
<commit_msg>fixed bug in mute/unmute. Sorry for not opening a new branch<commit_after>package commandevaluators

import (
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/byuoitav/av-api/base"
	"github.com/byuoitav/av-api/dbo"
)

//MuteDefault implements CommandEvaluation
type MuteDefault struct {
}

/*
 	Evalute takes a public room struct, scans the struct and builds any needed
	actions based on the contents of the struct.
*/
func (p *MuteDefault) Evaluate(room base.PublicRoom) ([]base.ActionStructure, error) {

	log.Printf("Evaluating for Mute command.")

	//create array of type ActionStructure
	actions := []base.ActionStructure{}

	if room.Muted != nil && *room.Muted {

		//general mute command
		log.Printf("Room-wide Mute request recieved. Retrieving all devices.")

		//get all devices
		devices, err := dbo.GetDevicesByBuildingAndRoomAndRole(room.Building, room.Room, "AudioOut")
		if err != nil {
			return []base.ActionStructure{}, err
		}

		log.Printf("Muting all devices in room.")

		for i := range devices {
			if devices[i].Output {
				log.Printf("Adding device %+v", devices[i].Name)

				actions = append(actions, base.ActionStructure{
					Action:              "Mute",
					GeneratingEvaluator: "MuteDefault",
					Device:              devices[i],
					DeviceSpecific:      false,
				})
			}
		}
	}

	//scan the room struct
	log.Printf("Evaluating audio devices for Mute command.")

	//generate commands
	for _, audioDevice := range room.AudioDevices {
		if audioDevice.Muted != nil && *audioDevice.Muted {

			//get the device
			device, err := dbo.GetDeviceByName(room.Building, room.Room, audioDevice.Name)
			if err != nil {
				return []base.ActionStructure{}, err
			}

			actions = append(actions, base.ActionStructure{
				Action:              "Mute",
				GeneratingEvaluator: "MuteDefault",
				Device:              device,
				DeviceSpecific:      true,
			})

		}

	}

	return actions, nil

}

// Validate takes an ActionStructure and determines if the command and parameter are valid for the device specified
func (p *MuteDefault) Validate(action base.ActionStructure) error {

	log.Printf("Validating for command \"Mute\".")

	ok, _ := checkCommands(action.Device.Commands, "Mute")

	// fmt.Printf("action.Device.Commands contains: %+v\n", action.Device.Commands)
	fmt.Printf("Device ID: %v\n", action.Device.ID)
	fmt.Printf("checkCommands returns: %v\n", ok)

	if !ok || !strings.EqualFold(action.Action, "Mute") {
		log.Printf("ERROR. %s is an invalid command for %s", action.Action, action.Device.Name)
		return errors.New(action.Action + " is an invalid command for " + action.Device.Name)
	}

	log.Printf("Done.")

	return nil
}

//  GetIncompatableActions returns a list of commands that are incompatabl with this one (i.e. 'standby' and 'power on', or 'mute' and 'volume up')
func (p *MuteDefault) GetIncompatibleCommands() (incompatibleActions []string) {

	incompatibleActions = []string{
		"UnMute",
	}

	return
}
<|endoftext|>


<commit_before>package configo

import (
	"os"
	"runtime"
	"strings"
)

type CONFIG_TYPE int

const (
	TYPE_DEFAULT CONFIG_TYPE = iota
)

const (
	PROCESS_NONE = iota
	PROCESS_COMMON
	PROCESS_PROPERTY
)

type (
	Common   interface{}
	Property map[string]string
	Default  map[string]Property
)

type Config struct {
	Type      CONFIG_TYPE
	Path      string
	Configure Common
}

var config *Config

const DEFAULT_CONFIG_FILE = "config.env"

func init() {
	config = NewDefaultConfig()
	if e := config.Load(); e != nil {
		config.Configure = make(Default)
	}
}

//GetSystemSeparator System Separator
func GetSystemSeparator() string {
	if runtime.GOOS == "windows" {
		return "\\"
	}
	return "/"
}

//NewDefaultConfig default config
func NewDefaultConfig() *Config {
	wd, err := os.Getwd()
	fp := ""
	if err == nil {
		fp = strings.Join([]string{wd, DEFAULT_CONFIG_FILE}, GetSystemSeparator())
	}

	return NewConfig(fp)
}

func NewConfig(path string, args ...CONFIG_TYPE) *Config {
	defaultConfig := make(Default)

	configType := TYPE_DEFAULT
	if args != nil {
		configType = args[0]
	}

	conf := &Config{
		Type:      configType,
		Path:      path,
		Configure: (Common)(defaultConfig),
	}
	return conf
}

func Load() error {
	return config.Load()
}

func (c *Config) Load() error {
	file, openErr := os.Open(c.Path)
	if openErr != nil {
		return ERROR_CONFIG_CANNOT_OPEN
	}
	defer file.Close()

	if e := envLoad(c, file); e != nil {
		return e
	}
	return nil
}

func envLoad(c *Config, f *os.File) error {
	if c.Type == TYPE_DEFAULT {
		return envDefault(c, f)
	}

	return nil
}

func Get(s string) (*Property, error) {
	return config.Get(s)
}

func (c *Config) Get(s string) (*Property, error) {
	if config.Type == TYPE_DEFAULT {
		p := envDefaultGet(s)
		if p != nil {
			return p, nil
		}
		return nil, ERROR_CONFIG_GET_PROPERTY
	}
	return nil, ERROR_CONFIG_GET_PROPERTY_TYPE
}

func (p *Property) Get(s string) (string, error) {

	if v, ok := (*p)[s]; ok {
		return v, nil
	}

	return "", ERROR_CONFIG_GET_PROPERTY_VALUE

}

func (p *Property) MustGet(s, d string) string {
	if v, ok := (*p)[s]; ok {
		return v
	}
	return d
}
<commit_msg>comment edit<commit_after>package configo

import (
	"os"
	"runtime"
	"strings"
)

type CONFIG_TYPE int

const (
	TYPE_DEFAULT CONFIG_TYPE = iota
)

const (
	PROCESS_NONE = iota
	PROCESS_COMMON
	PROCESS_PROPERTY
)

type (
	Common   interface{}
	Property map[string]string
	Default  map[string]Property
)

type Config struct {
	Type      CONFIG_TYPE
	Path      string
	Configure Common
}

var config *Config

const DEFAULT_CONFIG_FILE = "config.env"

func init() {
	config = NewDefaultConfig()
	if e := config.Load(); e != nil {
		config.Configure = make(Default)
	}
}

//GetSystemSeparator System Separator
func GetSystemSeparator() string {
	if runtime.GOOS == "windows" {
		return "\\"
	}
	return "/"
}

//NewDefaultConfig default config
func NewDefaultConfig() *Config {
	wd, err := os.Getwd()
	fp := ""
	if err == nil {
		fp = strings.Join([]string{wd, DEFAULT_CONFIG_FILE}, GetSystemSeparator())
	}

	return NewConfig(fp)
}

//NewConfig new config
func NewConfig(path string, args ...CONFIG_TYPE) *Config {
	defaultConfig := make(Default)

	configType := TYPE_DEFAULT
	if args != nil {
		configType = args[0]
	}

	conf := &Config{
		Type:      configType,
		Path:      path,
		Configure: (Common)(defaultConfig),
	}
	return conf
}

//Load default load
func Load() error {
	return config.Load()
}

//Load load
func (c *Config) Load() error {
	file, openErr := os.Open(c.Path)
	if openErr != nil {
		return ERROR_CONFIG_CANNOT_OPEN
	}
	defer file.Close()

	if e := envLoad(c, file); e != nil {
		return e
	}
	return nil
}

func envLoad(c *Config, f *os.File) error {
	if c.Type == TYPE_DEFAULT {
		return envDefault(c, f)
	}

	return nil
}

//Get default get
func Get(s string) (*Property, error) {
	return config.Get(s)
}

//Get config get
func (c *Config) Get(s string) (*Property, error) {
	if config.Type == TYPE_DEFAULT {
		p := envDefaultGet(s)
		if p != nil {
			return p, nil
		}
		return nil, ERROR_CONFIG_GET_PROPERTY
	}
	return nil, ERROR_CONFIG_GET_PROPERTY_TYPE
}

//Get property get
func (p *Property) Get(s string) (string, error) {

	if v, ok := (*p)[s]; ok {
		return v, nil
	}

	return "", ERROR_CONFIG_GET_PROPERTY_VALUE

}

//MustGet property get with default value
func (p *Property) MustGet(s, d string) string {
	if v, ok := (*p)[s]; ok {
		return v
	}
	return d
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net"
	"os"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gosuri/uiprogress"
	log "github.com/sirupsen/logrus"
)

var bars []*uiprogress.Bar

// runClient spawns threads for parallel uplink/downlink via TCP
func runClient(connectionType string, codePhrase string) {
	logger := log.WithFields(log.Fields{
		"codePhrase": codePhrase,
		"connection": connectionType,
	})
	var wg sync.WaitGroup
	wg.Add(numberConnections)

	uiprogress.Start()
	if !debugFlag {
		bars = make([]*uiprogress.Bar, numberConnections)
	}
	for id := 0; id < numberConnections; id++ {
		go func(id int) {
			defer wg.Done()
			port := strconv.Itoa(27001 + id)
			connection, err := net.Dial("tcp", serverAddress+":"+port)
			if err != nil {
				panic(err)
			}
			defer connection.Close()

			message := receiveMessage(connection)
			logger.Debugf("relay says: %s", message)
			logger.Debugf("telling relay: %s", connectionType+"."+codePhrase)

			sendMessage(connectionType+"."+Hash(codePhrase), connection)
			if connectionType == "s" { // this is a sender
				if id == 0 {
					fmt.Println("waiting for other to connect")
				}
				logger.Debug("waiting for ok from relay")
				message = receiveMessage(connection)
				logger.Debug("got ok from relay")
				// wait for pipe to be made
				time.Sleep(100 * time.Millisecond)
				// Write data from file
				logger.Debug("send file")
				sendFile(id, connection, codePhrase)
			} else { // this is a receiver
				// receive file
				logger.Debug("receive file")
				fileName, fileIV, fileSalt, fileHash = receiveFile(id, connection, codePhrase)
			}

		}(id)
	}
	wg.Wait()

	if connectionType == "r" {
		catFile(fileName)
		encrypted, err := ioutil.ReadFile(fileName + ".encrypted")
		if err != nil {
			log.Error(err)
			return
		}
		fmt.Println("\n\ndecrypting...")
		log.Debugf("codePhrase: %s", codePhrase)
		log.Debugf("filefileSaltIV: %s", fileSalt)
		log.Debugf("fileIV: %s", fileIV)
		decrypted, err := Decrypt(encrypted, codePhrase, fileSalt, fileIV)
		if err != nil {
			log.Error(err)
			return
		}
		ioutil.WriteFile(fileName, decrypted, 0644)
		os.Remove(fileName + ".encrypted")
		log.Debugf("\n\n\ndownloaded hash: %s", HashBytes(decrypted))
		log.Debugf("\n\n\nrelayed hash: %s", fileHash)

		if fileHash != HashBytes(decrypted) {
			fmt.Printf("\nUh oh! %s is corrupted! Sorry, try again.\n", fileName)
		} else {
			fmt.Printf("\nDownloaded %s!", fileName)
		}
	}
}

func catFile(fileNameToReceive string) {
	// cat the file
	os.Remove(fileNameToReceive)
	finished, err := os.Create(fileNameToReceive + ".encrypted")
	defer finished.Close()
	if err != nil {
		log.Fatal(err)
	}
	for id := 0; id < numberConnections; id++ {
		fh, err := os.Open(fileNameToReceive + "." + strconv.Itoa(id))
		if err != nil {
			log.Fatal(err)
		}

		_, err = io.Copy(finished, fh)
		if err != nil {
			log.Fatal(err)
		}
		fh.Close()
		os.Remove(fileNameToReceive + "." + strconv.Itoa(id))
	}

}

func receiveFile(id int, connection net.Conn, codePhrase string) (fileNameToReceive string, iv string, salt string, hashOfFile string) {
	logger := log.WithFields(log.Fields{
		"function": "receiveFile #" + strconv.Itoa(id),
	})

	logger.Debug("waiting for file size")

	bufferFileSize := make([]byte, 10)
	connection.Read(bufferFileSize)
	fileSize, _ := strconv.ParseInt(strings.Trim(string(bufferFileSize), ":"), 10, 64)
	logger.Debugf("filesize: %d", fileSize)

	bufferFileName := make([]byte, 64)
	connection.Read(bufferFileName)
	fileNameToReceive = strings.Trim(string(bufferFileName), ":")
	logger.Debugf("fileName: [%s]", fileNameToReceive)

	ivHex := make([]byte, BUFFERSIZE)
	connection.Read(ivHex)
	iv = strings.Trim(strings.TrimSpace(string(ivHex)), ":")
	iv = strings.Replace(iv, ":", "", -1)
	logger.Debugf("iv: [%s]", iv)

	saltHex := make([]byte, BUFFERSIZE)
	connection.Read(saltHex)
	salt = strings.Trim(strings.TrimSpace(string(saltHex)), ":")
	logger.Debugf("salt: [%s]", salt)

	hashOfFileBytes := make([]byte, BUFFERSIZE)
	connection.Read(hashOfFileBytes)
	hashOfFile = strings.Trim(strings.TrimSpace(string(hashOfFileBytes)), ":")
	logger.Debugf("hashOfFile: [%s]", hashOfFile)

	os.Remove(fileNameToReceive + "." + strconv.Itoa(id))
	newFile, err := os.Create(fileNameToReceive + "." + strconv.Itoa(id))
	if err != nil {
		panic(err)
	}
	defer newFile.Close()

	if !debugFlag {
		bars[id] = uiprogress.AddBar(int(fileSize)/1024 + 1).AppendCompleted().PrependElapsed()
	}

	logger.Debug("waiting for file")
	var receivedBytes int64
	for {
		if !debugFlag {
			bars[id].Incr()
		}
		if (fileSize - receivedBytes) < BUFFERSIZE {
			logger.Debug("at the end")
			io.CopyN(newFile, connection, (fileSize - receivedBytes))
			// Empty the remaining bytes that we don't need from the network buffer
			if (receivedBytes+BUFFERSIZE)-fileSize < BUFFERSIZE {
				logger.Debug("empty remaining bytes from network buffer")
				connection.Read(make([]byte, (receivedBytes+BUFFERSIZE)-fileSize))
			}
			break
		}
		io.CopyN(newFile, connection, BUFFERSIZE)
		//Increment the counter
		receivedBytes += BUFFERSIZE
	}
	logger.Debug("received file")
	return
}

func sendFile(id int, connection net.Conn, codePhrase string) {
	logger := log.WithFields(log.Fields{
		"function": "sendFile #" + strconv.Itoa(id),
	})
	defer connection.Close()

	var err error

	// // Open the file that needs to be send to the client
	// file, err := os.Open(fileName + ".encrypted")
	// if err != nil {
	// 	logger.Error(err)
	// 	return
	// }
	// defer file.Close()
	// // Get the filename and filesize
	// fileInfo, err := file.Stat()
	// if err != nil {
	// 	logger.Error(err)
	// 	return
	// }

	numChunks := math.Ceil(float64(len(fileBytes)) / float64(BUFFERSIZE))
	chunksPerWorker := int(math.Ceil(numChunks / float64(numberConnections)))

	bytesPerConnection := int64(chunksPerWorker * BUFFERSIZE)
	if id+1 == numberConnections {
		bytesPerConnection = int64(len(fileBytes)) - (numberConnections-1)*bytesPerConnection
	}
	fileSize := fillString(strconv.FormatInt(int64(bytesPerConnection), 10), 10)

	fileNameToSend := fillString(path.Base(fileName), 64)

	if id == 0 || id == numberConnections-1 {
		logger.Debugf("numChunks: %v", numChunks)
		logger.Debugf("chunksPerWorker: %v", chunksPerWorker)
		logger.Debugf("bytesPerConnection: %v", bytesPerConnection)
		logger.Debugf("fileNameToSend: %v", path.Base(fileName))
	}

	// send file size
	logger.Debugf("sending fileSize: %s", fileSize)
	connection.Write([]byte(fileSize))

	// send fileName
	logger.Debugf("sending fileNameToSend: %s", fileNameToSend)
	connection.Write([]byte(fileNameToSend))

	// send iv
	logger.Debugf("sending iv: %s", fileIV)
	connection.Write([]byte(fillString(fileIV, BUFFERSIZE)))

	// send salt
	logger.Debugf("sending salt: %s", fileSalt)
	connection.Write([]byte(fillString(fileSalt, BUFFERSIZE)))

	// send sha256sum of file
	logger.Debugf("sending sha256sum: %s", fileHash)
	connection.Write([]byte(fillString(fileHash, BUFFERSIZE)))

	sendBuffer := make([]byte, BUFFERSIZE)
	file := bytes.NewBuffer(fileBytes)
	chunkI := 0
	for {
		_, err = file.Read(sendBuffer)
		if err == io.EOF {
			//End of file reached, break out of for loop
			logger.Debug("EOF")
			break
		}
		if (chunkI >= chunksPerWorker*id && chunkI < chunksPerWorker*id+chunksPerWorker) || (id == numberConnections-1 && chunkI >= chunksPerWorker*id) {
			connection.Write(sendBuffer)
		}
		chunkI++
	}
	logger.Debug("file is sent")
	return
}
<commit_msg>Add more trimming<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net"
	"os"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gosuri/uiprogress"
	log "github.com/sirupsen/logrus"
)

var bars []*uiprogress.Bar

// runClient spawns threads for parallel uplink/downlink via TCP
func runClient(connectionType string, codePhrase string) {
	logger := log.WithFields(log.Fields{
		"codePhrase": codePhrase,
		"connection": connectionType,
	})
	var wg sync.WaitGroup
	wg.Add(numberConnections)

	uiprogress.Start()
	if !debugFlag {
		bars = make([]*uiprogress.Bar, numberConnections)
	}
	for id := 0; id < numberConnections; id++ {
		go func(id int) {
			defer wg.Done()
			port := strconv.Itoa(27001 + id)
			connection, err := net.Dial("tcp", serverAddress+":"+port)
			if err != nil {
				panic(err)
			}
			defer connection.Close()

			message := receiveMessage(connection)
			logger.Debugf("relay says: %s", message)
			logger.Debugf("telling relay: %s", connectionType+"."+codePhrase)

			sendMessage(connectionType+"."+Hash(codePhrase), connection)
			if connectionType == "s" { // this is a sender
				if id == 0 {
					fmt.Println("waiting for other to connect")
				}
				logger.Debug("waiting for ok from relay")
				message = receiveMessage(connection)
				logger.Debug("got ok from relay")
				// wait for pipe to be made
				time.Sleep(100 * time.Millisecond)
				// Write data from file
				logger.Debug("send file")
				sendFile(id, connection, codePhrase)
			} else { // this is a receiver
				// receive file
				logger.Debug("receive file")
				fileName, fileIV, fileSalt, fileHash = receiveFile(id, connection, codePhrase)
			}

		}(id)
	}
	wg.Wait()

	if connectionType == "r" {
		catFile(fileName)
		encrypted, err := ioutil.ReadFile(fileName + ".encrypted")
		if err != nil {
			log.Error(err)
			return
		}
		fmt.Println("\n\ndecrypting...")
		log.Debugf("codePhrase: [%s]", codePhrase)
		log.Debugf("fileSalt: [%s]", fileSalt)
		log.Debugf("fileIV: [%s]", fileIV)
		decrypted, err := Decrypt(encrypted, codePhrase, fileSalt, fileIV)
		if err != nil {
			log.Error(err)
			return
		}
		ioutil.WriteFile(fileName, decrypted, 0644)
		os.Remove(fileName + ".encrypted")
		log.Debugf("\n\n\ndownloaded hash: [%s]", HashBytes(decrypted))
		log.Debugf("\n\n\nrelayed hash: [%s]", fileHash)

		if fileHash != HashBytes(decrypted) {
			fmt.Printf("\nUh oh! %s is corrupted! Sorry, try again.\n", fileName)
		} else {
			fmt.Printf("\nDownloaded %s!", fileName)
		}
	}
}

func catFile(fileNameToReceive string) {
	// cat the file
	os.Remove(fileNameToReceive)
	finished, err := os.Create(fileNameToReceive + ".encrypted")
	defer finished.Close()
	if err != nil {
		log.Fatal(err)
	}
	for id := 0; id < numberConnections; id++ {
		fh, err := os.Open(fileNameToReceive + "." + strconv.Itoa(id))
		if err != nil {
			log.Fatal(err)
		}

		_, err = io.Copy(finished, fh)
		if err != nil {
			log.Fatal(err)
		}
		fh.Close()
		os.Remove(fileNameToReceive + "." + strconv.Itoa(id))
	}

}

func receiveFile(id int, connection net.Conn, codePhrase string) (fileNameToReceive string, iv string, salt string, hashOfFile string) {
	logger := log.WithFields(log.Fields{
		"function": "receiveFile #" + strconv.Itoa(id),
	})

	logger.Debug("waiting for file size")

	bufferFileSize := make([]byte, 10)
	connection.Read(bufferFileSize)
	fileSize, _ := strconv.ParseInt(strings.Trim(string(bufferFileSize), ":"), 10, 64)
	logger.Debugf("filesize: %d", fileSize)

	bufferFileName := make([]byte, 64)
	connection.Read(bufferFileName)
	fileNameToReceive = strings.Trim(string(bufferFileName), ":")
	logger.Debugf("fileName: [%s]", fileNameToReceive)

	ivHex := make([]byte, BUFFERSIZE)
	connection.Read(ivHex)
	iv = strings.Trim(strings.TrimSpace(string(ivHex)), ":")
	iv = strings.Replace(iv, ":", "", -1)
	logger.Debugf("iv: [%s]", iv)

	saltHex := make([]byte, BUFFERSIZE)
	connection.Read(saltHex)
	salt = strings.Trim(strings.TrimSpace(string(saltHex)), ":")
	logger.Debugf("salt: [%s]", salt)

	hashOfFileBytes := make([]byte, BUFFERSIZE)
	connection.Read(hashOfFileBytes)
	hashOfFile = strings.Trim(strings.TrimSpace(string(hashOfFileBytes)), ":")
	logger.Debugf("hashOfFile: [%s]", hashOfFile)

	os.Remove(fileNameToReceive + "." + strconv.Itoa(id))
	newFile, err := os.Create(fileNameToReceive + "." + strconv.Itoa(id))
	if err != nil {
		panic(err)
	}
	defer newFile.Close()

	if !debugFlag {
		bars[id] = uiprogress.AddBar(int(fileSize)/1024 + 1).AppendCompleted().PrependElapsed()
	}

	logger.Debug("waiting for file")
	var receivedBytes int64
	for {
		if !debugFlag {
			bars[id].Incr()
		}
		if (fileSize - receivedBytes) < BUFFERSIZE {
			logger.Debug("at the end")
			io.CopyN(newFile, connection, (fileSize - receivedBytes))
			// Empty the remaining bytes that we don't need from the network buffer
			if (receivedBytes+BUFFERSIZE)-fileSize < BUFFERSIZE {
				logger.Debug("empty remaining bytes from network buffer")
				connection.Read(make([]byte, (receivedBytes+BUFFERSIZE)-fileSize))
			}
			break
		}
		io.CopyN(newFile, connection, BUFFERSIZE)
		//Increment the counter
		receivedBytes += BUFFERSIZE
	}
	logger.Debug("received file")
	return
}

func sendFile(id int, connection net.Conn, codePhrase string) {
	logger := log.WithFields(log.Fields{
		"function": "sendFile #" + strconv.Itoa(id),
	})
	defer connection.Close()

	var err error

	// // Open the file that needs to be send to the client
	// file, err := os.Open(fileName + ".encrypted")
	// if err != nil {
	// 	logger.Error(err)
	// 	return
	// }
	// defer file.Close()
	// // Get the filename and filesize
	// fileInfo, err := file.Stat()
	// if err != nil {
	// 	logger.Error(err)
	// 	return
	// }

	numChunks := math.Ceil(float64(len(fileBytes)) / float64(BUFFERSIZE))
	chunksPerWorker := int(math.Ceil(numChunks / float64(numberConnections)))

	bytesPerConnection := int64(chunksPerWorker * BUFFERSIZE)
	if id+1 == numberConnections {
		bytesPerConnection = int64(len(fileBytes)) - (numberConnections-1)*bytesPerConnection
	}
	fileSize := fillString(strconv.FormatInt(int64(bytesPerConnection), 10), 10)

	fileNameToSend := fillString(path.Base(fileName), 64)

	if id == 0 || id == numberConnections-1 {
		logger.Debugf("numChunks: %v", numChunks)
		logger.Debugf("chunksPerWorker: %v", chunksPerWorker)
		logger.Debugf("bytesPerConnection: %v", bytesPerConnection)
		logger.Debugf("fileNameToSend: %v", path.Base(fileName))
	}

	// send file size
	logger.Debugf("sending fileSize: %s", fileSize)
	connection.Write([]byte(fileSize))

	// send fileName
	logger.Debugf("sending fileNameToSend: %s", fileNameToSend)
	connection.Write([]byte(fileNameToSend))

	// send iv
	logger.Debugf("sending iv: %s", fileIV)
	connection.Write([]byte(fillString(fileIV, BUFFERSIZE)))

	// send salt
	logger.Debugf("sending salt: %s", fileSalt)
	connection.Write([]byte(fillString(fileSalt, BUFFERSIZE)))

	// send sha256sum of file
	logger.Debugf("sending sha256sum: %s", fileHash)
	connection.Write([]byte(fillString(fileHash, BUFFERSIZE)))

	sendBuffer := make([]byte, BUFFERSIZE)
	file := bytes.NewBuffer(fileBytes)
	chunkI := 0
	for {
		_, err = file.Read(sendBuffer)
		if err == io.EOF {
			//End of file reached, break out of for loop
			logger.Debug("EOF")
			break
		}
		if (chunkI >= chunksPerWorker*id && chunkI < chunksPerWorker*id+chunksPerWorker) || (id == numberConnections-1 && chunkI >= chunksPerWorker*id) {
			connection.Write(sendBuffer)
		}
		chunkI++
	}
	logger.Debug("file is sent")
	return
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"time"

	"github.com/d2r2/go-max7219/max7219"
)

func main() {
	mtx := max7219.NewMatrix(1)
	err := mtx.Open(0, 0, 7)
	if err != nil {
		log.Fatal(err)
	}
	defer mtx.Close()
	var font max7219.Font
	// font = max7219.FontCP437
	// font = max7219.FontLCD
	// font = max7219.FontMSXRus
	// font = max7219.FontZXSpectrumRus
	// font = max7219.FontSinclair
	// font = max7219.FontTiny
	// font = max7219.FontVestaPK8000Rus
	font = max7219.FontCP437
	for i := 0; i <= len(font.GetLetterPatterns()); i++ {
		mtx.OutputAsciiCode(0, font, i, true)
		time.Sleep(500 * time.Millisecond)
	}
	// Output non-latin national char (russian for example)
	mtx.OutputChar(0, max7219.FontMSXRus, 'Я', true)
}
<commit_msg>Initial commit<commit_after>package main

import (
	"log"
	"time"

	"github.com/d2r2/go-max7219/max7219"
)

func main() {
	mtx := max7219.NewMatrix(1)
	err := mtx.Open(0, 0, 7)
	if err != nil {
		log.Fatal(err)
	}
	defer mtx.Close()

	var font max7219.Font

	// font = max7219.FontCP437
	// font = max7219.FontLCD
	// font = max7219.FontMSXRus
	// font = max7219.FontZXSpectrumRus
	// font = max7219.FontSinclair
	// font = max7219.FontTiny
	// font = max7219.FontVestaPK8000Rus

	// Output a sequence of ascii codes in a loop
	font = max7219.FontCP437
	for i := 0; i <= len(font.GetLetterPatterns()); i++ {
		mtx.OutputAsciiCode(0, font, i, true)
		time.Sleep(500 * time.Millisecond)
	}

	// Output non-latin national char (russian for example).
	// You should understand, that your national char should meet font code page.
	mtx.OutputChar(0, max7219.FontZXSpectrumRus, 'Я', true)
}
<|endoftext|>


<commit_before>package cart

import (
	"html/template"
	"net/http"
	"net/url"
	"github.com/gimke/cart/render"
	"io"
	"bytes"
	"strings"
	"net"
)

type Param struct {
	Key   string
	Value string
}

type Params []Param

func (ps Params) Get(name string) (string, bool) {
	for _, entry := range ps {
		if entry.Key == name {
			return entry.Value, true
		}
	}
	return "", false
}

type Context struct {
	response 	responseWriter
	Request   	*http.Request
	Response    ResponseWriter

	Router		*Router
	Params   	Params
	Keys     	map[string]interface{}
}

/*
reset Con
 */
func (c *Context) reset(w http.ResponseWriter, req *http.Request) {
	c.response.reset(w)
	c.Response = &c.response
	c.Request = req
	c.Params = c.Params[0:0]
	c.Keys = nil
}

//RESPONSE
func bodyAllowedForStatus(status int) bool {
	switch {
	case status >= 100 && status <= 199:
		return false
	case status == 204:
		return false
	case status == 304:
		return false
	}
	return true
}

// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
func (c *Context) AbortWithStatus(code int) {
	c.Status(code)
	c.Response.WriteHeaderNow()
}

func (c *Context) AbortRender(code int, request string, err interface{}) {
	stack := stack(3)
	if IsDebugging() {
		c.ErrorHTML(code,
			"Internal Server Error",
			"
"+request+"\n\n"+(err.(error)).Error()+"\n"+string(stack)+"
")
	} else {
		c.ErrorHTML(code,
			"Internal Server Error",
			"
"+(err.(error)).Error()+"
")
	}
}

// Header is a intelligent shortcut for c.Writer.Header().Set(key, value)
func (c *Context) Header(key, value string) {
	if len(value) == 0 {
		c.Response.Header().Del(key)
	} else {
		c.Response.Header().Set(key, value)
	}
}

// GetHeader returns value from request headers
func (c *Context) GetHeader(key string) string {
	return c.requestHeader(key)
}

func (c *Context) requestHeader(key string) string {
	if values, _ := c.Request.Header[key]; len(values) > 0 {
		return values[0]
	}
	return ""
}

func (c *Context) SetCookie(
	name string,
	value string,
	maxAge int,
	path string,
	domain string,
	secure bool,
	httpOnly bool,
) {
	if path == "" {
		path = "/"
	}
	http.SetCookie(c.Response, &http.Cookie{
		Name:     name,
		Value:    url.QueryEscape(value),
		MaxAge:   maxAge,
		Path:     path,
		Domain:   domain,
		Secure:   secure,
		HttpOnly: httpOnly,
	})
}

func (c *Context) Cookie(name string) (string, error) {
	cookie, err := c.Request.Cookie(name)
	if err != nil {
		return "", err
	}
	val, _ := url.QueryUnescape(cookie.Value)
	return val, nil
}

func (c *Context) Status(code int) {
	c.response.WriteHeader(code)
}

// ClientIP implements a best effort algorithm to return the real client IP, it parses
// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
// Use X-Forwarded-For before X-Real-Ip as nginx uses X-Real-Ip with the proxy's IP.
func (c *Context) ClientIP() string {
	if c.Router.engine.ForwardedByClientIP {
		clientIP := c.requestHeader("X-Forwarded-For")
		if index := strings.IndexByte(clientIP, ','); index >= 0 {
			clientIP = clientIP[0:index]
		}
		clientIP = strings.TrimSpace(clientIP)
		if len(clientIP) > 0 {
			return clientIP
		}
		clientIP = strings.TrimSpace(c.requestHeader("X-Real-Ip"))
		if len(clientIP) > 0 {
			return clientIP
		}
	}

	if c.Router.engine.AppEngine {
		if addr := c.Request.Header.Get("X-Appengine-Remote-Addr"); addr != "" {
			return addr
		}
	}

	if ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)); err == nil {
		return ip
	}

	return ""
}

// ContentType returns the Content-Type header of the request.
func (c *Context) ContentType() string {
	return filterFlags(c.requestHeader("Content-Type"))
}

func (c *Context) Render(code int, r render.Render) {
	c.response.writeNow = true
	c.Status(code)

	if !bodyAllowedForStatus(code) {
		r.WriteContentType(c.Response)
		c.Response.WriteHeaderNow()
		return
	}

	if err := r.Render(c.Response); err != nil {
		panic(err)
	}
}

// HTML renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, path string, obj interface{}) {
	if c.Router.engine.TemplatePath != "" {
		path = 	c.Router.engine.TemplatePath+path
	}
	tpl,err := template.ParseFiles(path)
	if err!=nil {
		panic(err)
	}
	c.Render(code, render.HTML{Template: tpl, Data:obj})
}

//
func (c *Context) HTMLLayout(code int, layout, path string, obj interface{}) {
	if c.Router.engine.TemplatePath != "" {
		layout = 	c.Router.engine.TemplatePath+layout
		path = 	c.Router.engine.TemplatePath+path
	}
	tpl,err := template.ParseFiles(path)
	if err!=nil {
		panic(err)
	}
	var buf bytes.Buffer
	tpl.Execute(&buf,obj);

	html := buf.String()

	tpllayout,errlayout := template.ParseFiles(layout)
	if errlayout!=nil {
		panic(err)
	}

	//rebuild obj
	tmp := obj.(H)
	tmp["__CONTENT"] = template.HTML(html)

	c.Render(code, render.HTML{Template: tpllayout, Data:tmp})
}

// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
// It also sets the Content-Type as "application/json".
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
// more CPU and bandwidth consuming. Use Context.JSON() instead.
func (c *Context) IndentedJSON(code int, obj interface{}) {
	c.Render(code, render.IndentedJSON{Data: obj})
}

// JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) {
	c.Render(code, render.JSON{Data: obj})
}

// XML serializes the given struct as XML into the response body.
// It also sets the Content-Type as "application/xml".
func (c *Context) XML(code int, obj interface{}) {
	c.Render(code, render.XML{Data: obj})
}

// String writes the given string into the response body.
func (c *Context) String(code int, format string, values ...interface{}) {
	c.Render(code, render.String{Format: format, Data: values})
}

// Redirect returns a HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) {
	c.Render(-1, render.Redirect{
		Code:     code,
		Location: location,
		Request:  c.Request,
	})
}

// Data writes some data into the body stream and updates the HTTP code.
func (c *Context) Data(code int, contentType string, data []byte) {
	c.Render(code, render.Data{
		ContentType: contentType,
		Data:        data,
	})
}

// File writes the specified file into the body stream in a efficient way.
func (c *Context) File(filepath string) {
	http.ServeFile(c.Response, c.Request, filepath)
}

func (c *Context) Stream(step func(w io.Writer) bool) {
	w := c.Response
	clientGone := w.CloseNotify()
	for {
		select {
		case <-clientGone:
			return
		default:
			keepOpen := step(w)
			w.Flush()
			if !keepOpen {
				return
			}
		}
	}
}

//error
func (c *Context) ErrorHTML(code int, title, content string) {
	tplString := `
<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>{{.Title}}</title>

{{.Title}}

{{.Content}}

	Powered by Cart
	<svg width="22" height="22" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>

	`
	tpl,err := template.New("ErrorHTML").Parse(tplString)
	if err!=nil {
		panic(err)
	}
	obj := H{
		"Title":title,
		"Content":template.HTML(content),
	}
	c.Render(code, render.HTML{Template: tpl, Data:obj})
}
<commit_msg>add html Layout<commit_after>package cart

import (
	"html/template"
	"net/http"
	"net/url"
	"github.com/gimke/cart/render"
	"io"
	"bytes"
	"strings"
	"net"
)

type Param struct {
	Key   string
	Value string
}

type Params []Param

func (ps Params) Get(name string) (string, bool) {
	for _, entry := range ps {
		if entry.Key == name {
			return entry.Value, true
		}
	}
	return "", false
}

type Context struct {
	response 	responseWriter
	Request   	*http.Request
	Response    ResponseWriter

	Router		*Router
	Params   	Params
	Keys     	map[string]interface{}
}

/*
reset Con
 */
func (c *Context) reset(w http.ResponseWriter, req *http.Request) {
	c.response.reset(w)
	c.Response = &c.response
	c.Request = req
	c.Params = c.Params[0:0]
	c.Keys = nil
}

//RESPONSE
func bodyAllowedForStatus(status int) bool {
	switch {
	case status >= 100 && status <= 199:
		return false
	case status == 204:
		return false
	case status == 304:
		return false
	}
	return true
}

// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
func (c *Context) AbortWithStatus(code int) {
	c.Status(code)
	c.Response.WriteHeaderNow()
}

func (c *Context) AbortRender(code int, request string, err interface{}) {
	stack := stack(3)
	if IsDebugging() {
		c.ErrorHTML(code,
			"Internal Server Error",
			"
"+request+"\n\n"+(err.(error)).Error()+"\n"+string(stack)+"
")
	} else {
		c.ErrorHTML(code,
			"Internal Server Error",
			"
"+(err.(error)).Error()+"
")
	}
}

// Header is a intelligent shortcut for c.Writer.Header().Set(key, value)
func (c *Context) Header(key, value string) {
	if len(value) == 0 {
		c.Response.Header().Del(key)
	} else {
		c.Response.Header().Set(key, value)
	}
}

// GetHeader returns value from request headers
func (c *Context) GetHeader(key string) string {
	return c.requestHeader(key)
}

func (c *Context) requestHeader(key string) string {
	if values, _ := c.Request.Header[key]; len(values) > 0 {
		return values[0]
	}
	return ""
}

func (c *Context) SetCookie(
	name string,
	value string,
	maxAge int,
	path string,
	domain string,
	secure bool,
	httpOnly bool,
) {
	if path == "" {
		path = "/"
	}
	http.SetCookie(c.Response, &http.Cookie{
		Name:     name,
		Value:    url.QueryEscape(value),
		MaxAge:   maxAge,
		Path:     path,
		Domain:   domain,
		Secure:   secure,
		HttpOnly: httpOnly,
	})
}

func (c *Context) Cookie(name string) (string, error) {
	cookie, err := c.Request.Cookie(name)
	if err != nil {
		return "", err
	}
	val, _ := url.QueryUnescape(cookie.Value)
	return val, nil
}

func (c *Context) Status(code int) {
	c.response.WriteHeader(code)
}

// ClientIP implements a best effort algorithm to return the real client IP, it parses
// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
// Use X-Forwarded-For before X-Real-Ip as nginx uses X-Real-Ip with the proxy's IP.
func (c *Context) ClientIP() string {
	if c.Router.engine.ForwardedByClientIP {
		clientIP := c.requestHeader("X-Forwarded-For")
		if index := strings.IndexByte(clientIP, ','); index >= 0 {
			clientIP = clientIP[0:index]
		}
		clientIP = strings.TrimSpace(clientIP)
		if len(clientIP) > 0 {
			return clientIP
		}
		clientIP = strings.TrimSpace(c.requestHeader("X-Real-Ip"))
		if len(clientIP) > 0 {
			return clientIP
		}
	}

	if c.Router.engine.AppEngine {
		if addr := c.Request.Header.Get("X-Appengine-Remote-Addr"); addr != "" {
			return addr
		}
	}

	if ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)); err == nil {
		return ip
	}

	return ""
}

// ContentType returns the Content-Type header of the request.
func (c *Context) ContentType() string {
	return filterFlags(c.requestHeader("Content-Type"))
}

func (c *Context) Render(code int, r render.Render) {
	c.response.writeNow = true
	c.Status(code)

	if !bodyAllowedForStatus(code) {
		r.WriteContentType(c.Response)
		c.Response.WriteHeaderNow()
		return
	}

	if err := r.Render(c.Response); err != nil {
		panic(err)
	}
}

// HTML renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, path string, obj interface{}) {
	if c.Router.engine.TemplatePath != "" {
		path = 	c.Router.engine.TemplatePath+path
	}
	tpl,err := template.ParseFiles(path)
	if err!=nil {
		panic(err)
	}
	c.Render(code, render.HTML{Template: tpl, Data:obj})
}

//
func (c *Context) HTMLLayout(code int, layout, path string, obj interface{}) {
	if c.Router.engine.TemplatePath != "" {
		layout = 	c.Router.engine.TemplatePath+layout
		path = 	c.Router.engine.TemplatePath+path
	}
	tpl,err := template.ParseFiles(path)
	if err!=nil {
		panic(err)
	}
	var buf bytes.Buffer
	tpl.Execute(&buf,obj);

	html := buf.String()

	tpllayout,errlayout := template.ParseFiles(layout)
	if errlayout!=nil {
		panic(err)
	}

	//rebuild obj
	tmp := obj.(H)
	tmp["__CONTENT"] = template.HTML(html)

	c.Render(code, render.HTML{Template: tpllayout, Data:tmp})
}

// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
// It also sets the Content-Type as "application/json".
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
// more CPU and bandwidth consuming. Use Context.JSON() instead.
func (c *Context) IndentedJSON(code int, obj interface{}) {
	c.Render(code, render.IndentedJSON{Data: obj})
}

// JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) {
	c.Render(code, render.JSON{Data: obj})
}

// XML serializes the given struct as XML into the response body.
// It also sets the Content-Type as "application/xml".
func (c *Context) XML(code int, obj interface{}) {
	c.Render(code, render.XML{Data: obj})
}

// String writes the given string into the response body.
func (c *Context) String(code int, format string, values ...interface{}) {
	c.Render(code, render.String{Format: format, Data: values})
}

// Redirect returns a HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) {
	c.Render(-1, render.Redirect{
		Code:     code,
		Location: location,
		Request:  c.Request,
	})
}

// Data writes some data into the body stream and updates the HTTP code.
func (c *Context) Data(code int, contentType string, data []byte) {
	c.Render(code, render.Data{
		ContentType: contentType,
		Data:        data,
	})
}

// File writes the specified file into the body stream in a efficient way.
func (c *Context) File(filepath string) {
	http.ServeFile(c.Response, c.Request, filepath)
}

func (c *Context) Stream(step func(w io.Writer) bool) {
	w := c.Response
	clientGone := w.CloseNotify()
	for {
		select {
		case <-clientGone:
			return
		default:
			keepOpen := step(w)
			w.Flush()
			if !keepOpen {
				return
			}
		}
	}
}

//error
func (c *Context) ErrorHTML(code int, title, content string) {
	tplString := `
<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>{{.Title}}</title>

{{.Title}}

{{.Content}}

	Powered by Cart
	<svg width="22" height="22" class="octicon octicon-mark-github" viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>

	`
	tpl,err := template.New("ErrorHTML").Parse(tplString)
	if err!=nil {
		panic(err)
	}
	obj := H{
		"Title":title,
		"Content":template.HTML(content),
	}
	c.Render(code, render.HTML{Template: tpl, Data:obj})
}
<|endoftext|>


<commit_before>package scheduler

import (
	"fmt"

	"code.google.com/p/go-uuid/uuid"
	"code.google.com/p/goprotobuf/proto"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	log "github.com/golang/glog"
	"github.com/mesos/mesos-go/mesos"
)

const (
	containerCpus = 0.25 // initial CPU allocated for executor
	containerMem  = 64   // initial MB of memory allocated for executor
)

// A struct that describes a pod task.
type PodTask struct {
	ID       string
	Pod      *api.Pod
	TaskInfo *mesos.TaskInfo
	Launched bool
	Offer    PerishableOffer
	podKey   string
}

func rangeResource(name string, ports []uint64) *mesos.Resource {
	if len(ports) == 0 {
		// pod may consist of a container that doesn't expose any ports on the host
		return nil
	}
	return &mesos.Resource{
		Name:   proto.String(name),
		Type:   mesos.Value_RANGES.Enum(),
		Ranges: NewRanges(ports),
	}
}

// func NewRange(begin uint64, end uint64) *mesos.Value_Ranges {
func NewRanges(ports []uint64) *mesos.Value_Ranges {
	r := make([]*mesos.Value_Range, 0)
	for _, port := range ports {
		r = append(r, &mesos.Value_Range{Begin: &port, End: &port})
	}
	return &mesos.Value_Ranges{Range: r}
}

func (t *PodTask) hasAcceptedOffer() bool {
	return t.TaskInfo.TaskId != nil
}

func (t *PodTask) GetOfferId() string {
	if t.Offer == nil {
		return ""
	}
	return t.Offer.Details().Id.GetValue()
}

// Fill the TaskInfo in the PodTask, should be called during k8s scheduling,
// before binding.
func (t *PodTask) FillTaskInfo(offer PerishableOffer) error {
	if offer == nil || offer.Details() == nil {
		return fmt.Errorf("Nil offer for task %v", t)
	}
	details := offer.Details()
	if details == nil {
		return fmt.Errorf("Illegal offer for task %v: %v", t, offer)
	}
	if t.Offer != nil && t.Offer != offer {
		return fmt.Errorf("Offer assignment must be idempotent with task %v: %v", t, offer)
	}
	t.Offer = offer
	log.V(3).Infof("Recording offer(s) %v against pod %v", details.Id, t.Pod.Name)

	t.TaskInfo.TaskId = &mesos.TaskID{Value: proto.String(t.ID)}
	t.TaskInfo.SlaveId = details.GetSlaveId()
	t.TaskInfo.Resources = []*mesos.Resource{
		mesos.ScalarResource("cpus", containerCpus),
		mesos.ScalarResource("mem", containerMem),
	}
	if ports := rangeResource("ports", t.Ports()); ports != nil {
		t.TaskInfo.Resources = append(t.TaskInfo.Resources, ports)
	}
	return nil
}

// Clear offer-related details from the task, should be called if/when an offer
// has already been assigned to a task but for some reason is no longer valid.
func (t *PodTask) ClearTaskInfo() {
	log.V(3).Infof("Clearing offer(s) from pod %v", t.Pod.Name)
	t.Offer = nil
	t.TaskInfo.TaskId = nil
	t.TaskInfo.SlaveId = nil
	t.TaskInfo.Resources = nil
	t.TaskInfo.Data = nil
}

func (t *PodTask) Ports() []uint64 {
	ports := make([]uint64, 0)
	for _, container := range t.Pod.Spec.Containers {
		// strip all port==0 from this array; k8s already knows what to do with zero-
		// ports (it does not create 'port bindings' on the minion-host); we need to
		// remove the wildcards from this array since they don't consume host resources
		for _, port := range container.Ports {
			// HostPort is int, not uint64.
			if port.HostPort != 0 {
				ports = append(ports, uint64(port.HostPort))
			}
		}
	}

	return ports
}

func (t *PodTask) AcceptOffer(offer *mesos.Offer) bool {
	var cpus float64 = 0
	var mem float64 = 0

	// Mimic set type
	requiredPorts := make(map[uint64]struct{})
	for _, port := range t.Ports() {
		requiredPorts[port] = struct{}{}
	}

	for _, resource := range offer.Resources {
		if resource.GetName() == "cpus" {
			cpus = *resource.GetScalar().Value
		}

		if resource.GetName() == "mem" {
			mem = *resource.GetScalar().Value
		}

		if resource.GetName() == "ports" {
			for _, r := range (*resource).GetRanges().Range {
				bp := r.GetBegin()
				ep := r.GetEnd()

				for port, _ := range requiredPorts {
					log.V(2).Infof("Evaluating port range {%d:%d} %d", bp, ep, port)

					if (bp <= port) && (port <= ep) {
						delete(requiredPorts, port)
					}
				}
			}
		}
	}

	unsatisfiedPorts := len(requiredPorts)
	if unsatisfiedPorts > 0 {
		log.V(2).Infof("Could not schedule pod %s: %d ports could not be allocated", t.Pod.Name, unsatisfiedPorts)
		return false
	}

	if (cpus < containerCpus) || (mem < containerMem) {
		log.V(2).Infof("Not enough resources: cpus: %f mem: %f", cpus, mem)
		return false
	}

	return true
}

func newPodTask(ctx api.Context, pod *api.Pod, executor *mesos.ExecutorInfo) (*PodTask, error) {
	key, err := makePodKey(ctx, pod.Name)
	if err != nil {
		return nil, err
	}
	taskId := uuid.NewUUID().String()
	task := &PodTask{
		ID:       taskId,
		Pod:      pod,
		TaskInfo: new(mesos.TaskInfo),
		Launched: false,
		podKey:   key,
	}
	task.TaskInfo.Name = proto.String("PodTask")
	task.TaskInfo.Executor = executor
	return task, nil
}

/**
HACK(jdef): we're not using etcd but k8s has implemented namespace support and
we're going to try to honor that by namespacing pod keys. Hence, the following
funcs that were stolen from:
    https://github.com/GoogleCloudPlatform/kubernetes/blob/release-0.5/pkg/registry/etcd/etcd.go
**/

const PodPath = "/pods"

// makeListKey constructs etcd paths to resource directories enforcing namespace rules
func makeListKey(ctx api.Context, prefix string) string {
	key := prefix
	ns, ok := api.NamespaceFrom(ctx)
	if ok && len(ns) > 0 {
		key = key + "/" + ns
	}
	return key
}

// makeItemKey constructs etcd paths to a resource relative to prefix enforcing namespace rules.  If no namespace is on context, it errors.
func makeItemKey(ctx api.Context, prefix string, id string) (string, error) {
	key := makeListKey(ctx, prefix)
	ns, ok := api.NamespaceFrom(ctx)
	if !ok || len(ns) == 0 {
		return "", fmt.Errorf("Invalid request.  Namespace parameter required.")
	}
	if len(id) == 0 {
		return "", fmt.Errorf("Invalid request.  Id parameter required.")
	}
	key = key + "/" + id
	return key, nil
}

// makePodListKey constructs etcd paths to pod directories enforcing namespace rules.
func makePodListKey(ctx api.Context) string {
	return makeListKey(ctx, PodPath)
}

// makePodKey constructs etcd paths to pod items enforcing namespace rules.
func makePodKey(ctx api.Context, id string) (string, error) {
	return makeItemKey(ctx, PodPath, id)
}
<commit_msg>resolve #118<commit_after>package scheduler

import (
	"fmt"

	"code.google.com/p/go-uuid/uuid"
	"code.google.com/p/goprotobuf/proto"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	log "github.com/golang/glog"
	"github.com/mesos/mesos-go/mesos"
)

const (
	containerCpus = 0.25 // initial CPU allocated for executor
	containerMem  = 64   // initial MB of memory allocated for executor
)

// A struct that describes a pod task.
type PodTask struct {
	ID       string
	Pod      *api.Pod
	TaskInfo *mesos.TaskInfo
	Launched bool
	Offer    PerishableOffer
	podKey   string
}

func rangeResource(name string, ports []uint64) *mesos.Resource {
	if len(ports) == 0 {
		// pod may consist of a container that doesn't expose any ports on the host
		return nil
	}
	return &mesos.Resource{
		Name:   proto.String(name),
		Type:   mesos.Value_RANGES.Enum(),
		Ranges: NewRanges(ports),
	}
}

// func NewRange(begin uint64, end uint64) *mesos.Value_Ranges {
func NewRanges(ports []uint64) *mesos.Value_Ranges {
	r := make([]*mesos.Value_Range, 0)
	for _, port := range ports {
		x := proto.Uint64(port)
		r = append(r, &mesos.Value_Range{Begin: x, End: x})
	}
	return &mesos.Value_Ranges{Range: r}
}

func (t *PodTask) hasAcceptedOffer() bool {
	return t.TaskInfo.TaskId != nil
}

func (t *PodTask) GetOfferId() string {
	if t.Offer == nil {
		return ""
	}
	return t.Offer.Details().Id.GetValue()
}

// Fill the TaskInfo in the PodTask, should be called during k8s scheduling,
// before binding.
func (t *PodTask) FillTaskInfo(offer PerishableOffer) error {
	if offer == nil || offer.Details() == nil {
		return fmt.Errorf("Nil offer for task %v", t)
	}
	details := offer.Details()
	if details == nil {
		return fmt.Errorf("Illegal offer for task %v: %v", t, offer)
	}
	if t.Offer != nil && t.Offer != offer {
		return fmt.Errorf("Offer assignment must be idempotent with task %v: %v", t, offer)
	}
	t.Offer = offer
	log.V(3).Infof("Recording offer(s) %v against pod %v", details.Id, t.Pod.Name)

	t.TaskInfo.TaskId = &mesos.TaskID{Value: proto.String(t.ID)}
	t.TaskInfo.SlaveId = details.GetSlaveId()
	t.TaskInfo.Resources = []*mesos.Resource{
		mesos.ScalarResource("cpus", containerCpus),
		mesos.ScalarResource("mem", containerMem),
	}
	if ports := rangeResource("ports", t.Ports()); ports != nil {
		t.TaskInfo.Resources = append(t.TaskInfo.Resources, ports)
	}
	return nil
}

// Clear offer-related details from the task, should be called if/when an offer
// has already been assigned to a task but for some reason is no longer valid.
func (t *PodTask) ClearTaskInfo() {
	log.V(3).Infof("Clearing offer(s) from pod %v", t.Pod.Name)
	t.Offer = nil
	t.TaskInfo.TaskId = nil
	t.TaskInfo.SlaveId = nil
	t.TaskInfo.Resources = nil
	t.TaskInfo.Data = nil
}

func (t *PodTask) Ports() []uint64 {
	ports := make([]uint64, 0)
	for _, container := range t.Pod.Spec.Containers {
		// strip all port==0 from this array; k8s already knows what to do with zero-
		// ports (it does not create 'port bindings' on the minion-host); we need to
		// remove the wildcards from this array since they don't consume host resources
		for _, port := range container.Ports {
			// HostPort is int, not uint64.
			if port.HostPort != 0 {
				ports = append(ports, uint64(port.HostPort))
			}
		}
	}

	return ports
}

func (t *PodTask) AcceptOffer(offer *mesos.Offer) bool {
	var cpus float64 = 0
	var mem float64 = 0

	// Mimic set type
	requiredPorts := make(map[uint64]struct{})
	for _, port := range t.Ports() {
		requiredPorts[port] = struct{}{}
	}

	for _, resource := range offer.Resources {
		if resource.GetName() == "cpus" {
			cpus = *resource.GetScalar().Value
		}

		if resource.GetName() == "mem" {
			mem = *resource.GetScalar().Value
		}

		if resource.GetName() == "ports" {
			for _, r := range (*resource).GetRanges().Range {
				bp := r.GetBegin()
				ep := r.GetEnd()

				for port, _ := range requiredPorts {
					log.V(2).Infof("Evaluating port range {%d:%d} %d", bp, ep, port)

					if (bp <= port) && (port <= ep) {
						delete(requiredPorts, port)
					}
				}
			}
		}
	}

	unsatisfiedPorts := len(requiredPorts)
	if unsatisfiedPorts > 0 {
		log.V(2).Infof("Could not schedule pod %s: %d ports could not be allocated", t.Pod.Name, unsatisfiedPorts)
		return false
	}

	if (cpus < containerCpus) || (mem < containerMem) {
		log.V(2).Infof("Not enough resources: cpus: %f mem: %f", cpus, mem)
		return false
	}

	return true
}

func newPodTask(ctx api.Context, pod *api.Pod, executor *mesos.ExecutorInfo) (*PodTask, error) {
	key, err := makePodKey(ctx, pod.Name)
	if err != nil {
		return nil, err
	}
	taskId := uuid.NewUUID().String()
	task := &PodTask{
		ID:       taskId,
		Pod:      pod,
		TaskInfo: new(mesos.TaskInfo),
		Launched: false,
		podKey:   key,
	}
	task.TaskInfo.Name = proto.String("PodTask")
	task.TaskInfo.Executor = executor
	return task, nil
}

/**
HACK(jdef): we're not using etcd but k8s has implemented namespace support and
we're going to try to honor that by namespacing pod keys. Hence, the following
funcs that were stolen from:
    https://github.com/GoogleCloudPlatform/kubernetes/blob/release-0.5/pkg/registry/etcd/etcd.go
**/

const PodPath = "/pods"

// makeListKey constructs etcd paths to resource directories enforcing namespace rules
func makeListKey(ctx api.Context, prefix string) string {
	key := prefix
	ns, ok := api.NamespaceFrom(ctx)
	if ok && len(ns) > 0 {
		key = key + "/" + ns
	}
	return key
}

// makeItemKey constructs etcd paths to a resource relative to prefix enforcing namespace rules.  If no namespace is on context, it errors.
func makeItemKey(ctx api.Context, prefix string, id string) (string, error) {
	key := makeListKey(ctx, prefix)
	ns, ok := api.NamespaceFrom(ctx)
	if !ok || len(ns) == 0 {
		return "", fmt.Errorf("Invalid request.  Namespace parameter required.")
	}
	if len(id) == 0 {
		return "", fmt.Errorf("Invalid request.  Id parameter required.")
	}
	key = key + "/" + id
	return key, nil
}

// makePodListKey constructs etcd paths to pod directories enforcing namespace rules.
func makePodListKey(ctx api.Context) string {
	return makeListKey(ctx, PodPath)
}

// makePodKey constructs etcd paths to pod items enforcing namespace rules.
func makePodKey(ctx api.Context, id string) (string, error) {
	return makeItemKey(ctx, PodPath, id)
}
<|endoftext|>


<commit_before>// Copyright 2017 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 main

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"strings"

	"github.com/Masterminds/vcs"
	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

// ctx defines the supporting context of the tool.
type ctx struct {
	GOPATH string // Go path
}

// newContext creates a struct with the project's GOPATH. It assumes
// that of your "GOPATH"'s we want the one we are currently in.
func newContext() (*ctx, error) {
	// this way we get the default GOPATH that was added in 1.8
	buildContext := build.Default
	wd, err := os.Getwd()
	if err != nil {
		return nil, errors.Wrap(err, "getting work directory")
	}
	for _, gp := range filepath.SplitList(buildContext.GOPATH) {
		if strings.HasPrefix(wd, gp) {
			return &ctx{GOPATH: gp}, nil
		}
	}

	return nil, errors.New("project not in a GOPATH")
}

func (c *ctx) sourceManager() (*gps.SourceMgr, error) {
	return gps.NewSourceManager(analyzer{}, filepath.Join(c.GOPATH, "pkg", "dep"))
}

// loadProject searches for a project root from the provided path, then loads
// the manifest and lock (if any) it finds there.
//
// If the provided path is empty, it will search from the path indicated by
// os.Getwd().
func (c *ctx) loadProject(path string) (*project, error) {
	var err error
	p := new(project)

	switch path {
	case "":
		p.absroot, err = findProjectRootFromWD()
	default:
		p.absroot, err = findProjectRoot(path)
	}

	if err != nil {
		return p, err
	}

	ip, err := c.splitAbsoluteProjectRoot(p.absroot)
	if err != nil {
		return nil, errors.Wrap(err, "split absolute project root")
	}
	p.importroot = gps.ProjectRoot(ip)

	mp := filepath.Join(p.absroot, manifestName)
	mf, err := os.Open(mp)
	if err != nil {
		if os.IsNotExist(err) {
			// TODO: list possible solutions? (dep init, cd $project)
			return nil, fmt.Errorf("no %v found in project root %v", manifestName, p.absroot)
		}
		// Unable to read the manifest file
		return nil, err
	}
	defer mf.Close()

	p.m, err = readManifest(mf)
	if err != nil {
		return nil, fmt.Errorf("error while parsing %s: %s", mp, err)
	}

	lp := filepath.Join(path, lockName)
	lf, err := os.Open(lp)
	if err != nil {
		if os.IsNotExist(err) {
			// It's fine for the lock not to exist
			return p, nil
		}
		// But if a lock does exist and we can't open it, that's a problem
		return nil, fmt.Errorf("could not open %s: %s", lp, err)
	}

	defer lf.Close()
	p.l, err = readLock(lf)
	if err != nil {
		return nil, fmt.Errorf("error while parsing %s: %s", lp, err)
	}

	return p, nil
}

// splitAbsoluteProjectRoot takes an absolute path and compares it against declared
// GOPATH(s) to determine what portion of the input path should be treated as an
// import path - as a project root.
//
// The second returned string indicates which GOPATH value was used.
func (c *ctx) splitAbsoluteProjectRoot(path string) (string, error) {
	srcprefix := filepath.Join(c.GOPATH, "src") + string(filepath.Separator)
	if strings.HasPrefix(path, srcprefix) {
		// filepath.ToSlash because we're dealing with an import path now,
		// not an fs path
		return filepath.ToSlash(strings.TrimPrefix(path, srcprefix)), nil
	}

	return "", fmt.Errorf("%s not in any $GOPATH", path)
}

// absoluteProjectRoot determines the absolute path to the project root
// including the $GOPATH. This will not work with stdlib packages and the
// package directory needs to exist.
func (c *ctx) absoluteProjectRoot(path string) (string, error) {
	posspath := filepath.Join(c.GOPATH, "src", path)
	dirOK, err := isDir(posspath)
	if err != nil {
		return "", errors.Wrapf(err, "checking if %s is a directory", posspath)
	}
	if !dirOK {
		return "", fmt.Errorf("%s does not exist", posspath)
	}
	return posspath, nil
}

func (c *ctx) versionInWorkspace(root gps.ProjectRoot) (gps.Version, error) {
	pr, err := c.absoluteProjectRoot(string(root))
	if err != nil {
		return nil, errors.Wrapf(err, "determine project root for %s", root)
	}

	repo, err := vcs.NewRepo("", pr)
	if err != nil {
		return nil, errors.Wrapf(err, "creating new repo for root: %s", pr)
	}

	ver, err := repo.Current()
	if err != nil {
		return nil, errors.Wrapf(err, "finding current branch/version for root: %s", pr)
	}

	rev, err := repo.Version()
	if err != nil {
		return nil, errors.Wrapf(err, "getting repo version for root: %s", pr)
	}

	// First look through tags.
	tags, err := repo.Tags()
	if err != nil {
		return nil, errors.Wrapf(err, "getting repo tags for root: %s", pr)
	}
	// Try to match the current version to a tag.
	if contains(tags, ver) {
		// Assume semver if it starts with a v.
		if strings.HasPrefix(ver, "v") {
			return gps.NewVersion(ver).Is(gps.Revision(rev)), nil
		}

		return nil, fmt.Errorf("version for root %s does not start with a v: %q", pr, ver)
	}

	// Look for the current branch.
	branches, err := repo.Branches()
	if err != nil {
		return nil, errors.Wrapf(err, "getting repo branch for root: %s")
	}
	// Try to match the current version to a branch.
	if contains(branches, ver) {
		return gps.NewBranch(ver).Is(gps.Revision(rev)), nil
	}

	return gps.Revision(rev), nil
}
<commit_msg>More readable<commit_after>// Copyright 2017 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 main

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"strings"

	"github.com/Masterminds/vcs"
	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

// ctx defines the supporting context of the tool.
type ctx struct {
	GOPATH string // Go path
}

// newContext creates a struct with the project's GOPATH. It assumes
// that of your "GOPATH"'s we want the one we are currently in.
func newContext() (*ctx, error) {
	// this way we get the default GOPATH that was added in 1.8
	buildContext := build.Default
	wd, err := os.Getwd()
	if err != nil {
		return nil, errors.Wrap(err, "getting work directory")
	}
	for _, gp := range filepath.SplitList(buildContext.GOPATH) {
		if strings.HasPrefix(wd, gp) {
			return &ctx{GOPATH: gp}, nil
		}
	}

	return nil, errors.New("project not in a GOPATH")
}

func (c *ctx) sourceManager() (*gps.SourceMgr, error) {
	return gps.NewSourceManager(analyzer{}, filepath.Join(c.GOPATH, "pkg", "dep"))
}

// loadProject searches for a project root from the provided path, then loads
// the manifest and lock (if any) it finds there.
//
// If the provided path is empty, it will search from the path indicated by
// os.Getwd().
func (c *ctx) loadProject(path string) (*project, error) {
	var err error
	p := new(project)

	switch path {
	case "":
		p.absroot, err = findProjectRootFromWD()
	default:
		p.absroot, err = findProjectRoot(path)
	}

	if err != nil {
		return p, err
	}

	ip, err := c.splitAbsoluteProjectRoot(p.absroot)
	if err != nil {
		return nil, errors.Wrap(err, "split absolute project root")
	}
	p.importroot = gps.ProjectRoot(ip)

	mp := filepath.Join(p.absroot, manifestName)
	mf, err := os.Open(mp)
	if err != nil {
		if os.IsNotExist(err) {
			// TODO: list possible solutions? (dep init, cd $project)
			return nil, fmt.Errorf("no %v found in project root %v", manifestName, p.absroot)
		}
		// Unable to read the manifest file
		return nil, err
	}
	defer mf.Close()

	p.m, err = readManifest(mf)
	if err != nil {
		return nil, fmt.Errorf("error while parsing %s: %s", mp, err)
	}

	lp := filepath.Join(path, lockName)
	lf, err := os.Open(lp)
	if err != nil {
		if os.IsNotExist(err) {
			// It's fine for the lock not to exist
			return p, nil
		}
		// But if a lock does exist and we can't open it, that's a problem
		return nil, fmt.Errorf("could not open %s: %s", lp, err)
	}
	defer lf.Close()

	p.l, err = readLock(lf)
	if err != nil {
		return nil, fmt.Errorf("error while parsing %s: %s", lp, err)
	}

	return p, nil
}

// splitAbsoluteProjectRoot takes an absolute path and compares it against declared
// GOPATH(s) to determine what portion of the input path should be treated as an
// import path - as a project root.
//
// The second returned string indicates which GOPATH value was used.
func (c *ctx) splitAbsoluteProjectRoot(path string) (string, error) {
	srcprefix := filepath.Join(c.GOPATH, "src") + string(filepath.Separator)
	if strings.HasPrefix(path, srcprefix) {
		// filepath.ToSlash because we're dealing with an import path now,
		// not an fs path
		return filepath.ToSlash(strings.TrimPrefix(path, srcprefix)), nil
	}

	return "", fmt.Errorf("%s not in any $GOPATH", path)
}

// absoluteProjectRoot determines the absolute path to the project root
// including the $GOPATH. This will not work with stdlib packages and the
// package directory needs to exist.
func (c *ctx) absoluteProjectRoot(path string) (string, error) {
	posspath := filepath.Join(c.GOPATH, "src", path)
	dirOK, err := isDir(posspath)
	if err != nil {
		return "", errors.Wrapf(err, "checking if %s is a directory", posspath)
	}
	if !dirOK {
		return "", fmt.Errorf("%s does not exist", posspath)
	}
	return posspath, nil
}

func (c *ctx) versionInWorkspace(root gps.ProjectRoot) (gps.Version, error) {
	pr, err := c.absoluteProjectRoot(string(root))
	if err != nil {
		return nil, errors.Wrapf(err, "determine project root for %s", root)
	}

	repo, err := vcs.NewRepo("", pr)
	if err != nil {
		return nil, errors.Wrapf(err, "creating new repo for root: %s", pr)
	}

	ver, err := repo.Current()
	if err != nil {
		return nil, errors.Wrapf(err, "finding current branch/version for root: %s", pr)
	}

	rev, err := repo.Version()
	if err != nil {
		return nil, errors.Wrapf(err, "getting repo version for root: %s", pr)
	}

	// First look through tags.
	tags, err := repo.Tags()
	if err != nil {
		return nil, errors.Wrapf(err, "getting repo tags for root: %s", pr)
	}
	// Try to match the current version to a tag.
	if contains(tags, ver) {
		// Assume semver if it starts with a v.
		if strings.HasPrefix(ver, "v") {
			return gps.NewVersion(ver).Is(gps.Revision(rev)), nil
		}

		return nil, fmt.Errorf("version for root %s does not start with a v: %q", pr, ver)
	}

	// Look for the current branch.
	branches, err := repo.Branches()
	if err != nil {
		return nil, errors.Wrapf(err, "getting repo branch for root: %s")
	}
	// Try to match the current version to a branch.
	if contains(branches, ver) {
		return gps.NewBranch(ver).Is(gps.Revision(rev)), nil
	}

	return gps.Revision(rev), nil
}
<|endoftext|>


<commit_before>// Copyright 2016, Joel Scoble. All rights reserved.
// Licensed under the MIT License. See the included LICENSE file.

// Package contour: a package for settings.
//
// Contour supports application settings, loading settings from a configuration
// file, environment variables, and flags. Where a setting can be set from is
// configurable at the per setting level. In addition to setting's
// overridability being configurable, the Settings behavior is also
// configurable.
//
// Application settings can either be core settings, not updateable once set,
// or they can be settings that can only be updated within the application
// using the Update methods; these settings are not exposed to configuration
// files, environment variables, or flags and cannot be modified by them.
//
// For flags, short flag aliases are also supported.
//
// The package global Settings uses the application's name as its name.
//
// All operations are thread-safe.
package contour

import (
	"fmt"
	"path/filepath"
	"strings"

	"github.com/mohae/appname"
)

var app = appname.Get()

const (
	// Unsupported configuration encoding format.
	Unsupported Format = iota
	// JSON encoding format.
	JSON
	// TOML encoding format.
	TOML
	// YAML encoding format
	YAML
)

// Format is the type of esupported encoding for configuration files.
type Format int

func (f Format) String() string {
	switch f {
	case JSON:
		return "json"
	case TOML:
		return "toml"
	case YAML:
		return "yaml"
	default:
		return "unsupported"
	}
}

// isSupported checks to see if the passed string represents a supported config
// format.
func (f Format) isSupported() bool {
	switch f {
	case YAML:
		return true
	case JSON:
		return true
	case TOML:
		return true
	}
	return false
}

// ParseFormat takes a string and returns the Format it represents or an
// UnsupportedFormatErr if it can't be matched to a supported format. The
// string is normalized to lower case before matching.
func ParseFormat(s string) (Format, error) {
	ls := strings.ToLower(s)
	switch ls {
	case "json", "jsn", "cjsn", "cjson":
		return JSON, nil
	case "toml", "tml":
		return TOML, nil
	case "yaml", "yml":
		return YAML, nil
	}
	return Unsupported, UnsupportedFormatErr{s}
}

// ParseFilenameFormat takes a string that represents a filename and returns
// the files format based on its extension. If the filename either doesn't have
// an extension or the extension is not one of a supported file format an
// UnsupportedFormatErr will be returned.
func ParseFilenameFormat(s string) (Format, error) {
	ext := strings.TrimPrefix(filepath.Ext(s), ".")
	return ParseFormat(ext)
}

const (
	_interface dataType = iota + 1
	_bool
	_int
	_int64
	_string
)

// dataType is the setting's data type.
type dataType int

func (t dataType) String() string {
	switch t {
	case _string:
		return "string"
	case _int:
		return "int"
	case _int64:
		return "int64"
	case _bool:
		return "bool"
	case _interface:
		return "interface{}"
	}
	return "unknown data type"
}

func parseDataType(s string) dataType {
	v := strings.ToLower(s)
	switch v {
	case "string":
		return _string
	case "int":
		return _int
	case "int64":
		return _int64
	case "bool":
		return _bool
	}
	// everything else is an interface{}, the user of the setting will be
	// expected to know what it is.
	return _interface
}

// DataTypeErr occurs when the requested setting's data type is different than
// the type requested.
type DataTypeErr struct {
	k   string
	is  string
	not dataType
}

func (e DataTypeErr) Error() string {
	return fmt.Sprintf("%s is %s, not %s", e.k, e.is, e.not)
}

// These settings are in order of precedence. Each setting type can be set by
// any of the types with higher precedence if contour is configured to use that
// type.
const (
	// Basic settings are settings that are none of the below. These are often
	// referred to as application settings: settings that can only be updated
	// within an application and not by configuration files, environment
	// variables, or flags. These settings do not have to be registered.
	Basic SettingType = iota + 1
	// Core settings are immutable once registered.
	Core
	// ConFileVar settings can be set from a configuration file.
	ConfFileVar
	// EnvVar settings can be set from a configuration file and an environment
	// variable; unless it has been explicitly set to not be updateable from a
	// configuration file.
	EnvVar
	// Flag settings can be set from a configuration file, an environment
	// variable, and a flag; unless it has been explicitly set to not be
	// updateable from either a configuration file or an environment variable.
	Flag
)

// SettingType is type of setting.
type SettingType int

func (t SettingType) String() string {
	switch t {
	case Basic:
		return "basic"
	case Core:
		return "core"
	case ConfFileVar:
		return "configuration file var"
	case EnvVar:
		return "env var"
	case Flag:
		return "flag"
	default:
		return "unknown"
	}
}

// settings: contour's global Settinngs set; contour functions operate on this.
var settings *Settings

func init() {
	settings = New(app)
}

// SettingNotFoundErr occurs when a setting isn't found.
type SettingNotFoundErr struct {
	settingType SettingType
	k           string
}

func (e SettingNotFoundErr) Error() string {
	if e.settingType <= 0 {
		return fmt.Sprintf("%s: setting not found", e.k)
	}
	return fmt.Sprintf("%s: %s setting not found", e.k, e.settingType)
}

// UnsupportedFormatErr occurs when the string cannot be matched to a
// supported configuration format.
type UnsupportedFormatErr struct {
	v string
}

func NewUnsupportedFormatErr(v string) UnsupportedFormatErr {
	return UnsupportedFormatErr{v}
}

func (e UnsupportedFormatErr) Error() string {
	return fmt.Sprintf("%s: unsupported configuration format", e.v)
}
<commit_msg>elide NewUnsupportedFormatErr: unnecessary and not used<commit_after>// Copyright 2016, Joel Scoble. All rights reserved.
// Licensed under the MIT License. See the included LICENSE file.

// Package contour: a package for settings.
//
// Contour supports application settings, loading settings from a configuration
// file, environment variables, and flags. Where a setting can be set from is
// configurable at the per setting level. In addition to setting's
// overridability being configurable, the Settings behavior is also
// configurable.
//
// Application settings can either be core settings, not updateable once set,
// or they can be settings that can only be updated within the application
// using the Update methods; these settings are not exposed to configuration
// files, environment variables, or flags and cannot be modified by them.
//
// For flags, short flag aliases are also supported.
//
// The package global Settings uses the application's name as its name.
//
// All operations are thread-safe.
package contour

import (
	"fmt"
	"path/filepath"
	"strings"

	"github.com/mohae/appname"
)

var app = appname.Get()

const (
	// Unsupported configuration encoding format.
	Unsupported Format = iota
	// JSON encoding format.
	JSON
	// TOML encoding format.
	TOML
	// YAML encoding format
	YAML
)

// Format is the type of esupported encoding for configuration files.
type Format int

func (f Format) String() string {
	switch f {
	case JSON:
		return "json"
	case TOML:
		return "toml"
	case YAML:
		return "yaml"
	default:
		return "unsupported"
	}
}

// isSupported checks to see if the passed string represents a supported config
// format.
func (f Format) isSupported() bool {
	switch f {
	case YAML:
		return true
	case JSON:
		return true
	case TOML:
		return true
	}
	return false
}

// ParseFormat takes a string and returns the Format it represents or an
// UnsupportedFormatErr if it can't be matched to a supported format. The
// string is normalized to lower case before matching.
func ParseFormat(s string) (Format, error) {
	ls := strings.ToLower(s)
	switch ls {
	case "json", "jsn", "cjsn", "cjson":
		return JSON, nil
	case "toml", "tml":
		return TOML, nil
	case "yaml", "yml":
		return YAML, nil
	}
	return Unsupported, UnsupportedFormatErr{s}
}

// ParseFilenameFormat takes a string that represents a filename and returns
// the files format based on its extension. If the filename either doesn't have
// an extension or the extension is not one of a supported file format an
// UnsupportedFormatErr will be returned.
func ParseFilenameFormat(s string) (Format, error) {
	ext := strings.TrimPrefix(filepath.Ext(s), ".")
	return ParseFormat(ext)
}

const (
	_interface dataType = iota + 1
	_bool
	_int
	_int64
	_string
)

// dataType is the setting's data type.
type dataType int

func (t dataType) String() string {
	switch t {
	case _string:
		return "string"
	case _int:
		return "int"
	case _int64:
		return "int64"
	case _bool:
		return "bool"
	case _interface:
		return "interface{}"
	}
	return "unknown data type"
}

func parseDataType(s string) dataType {
	v := strings.ToLower(s)
	switch v {
	case "string":
		return _string
	case "int":
		return _int
	case "int64":
		return _int64
	case "bool":
		return _bool
	}
	// everything else is an interface{}, the user of the setting will be
	// expected to know what it is.
	return _interface
}

// DataTypeErr occurs when the requested setting's data type is different than
// the type requested.
type DataTypeErr struct {
	k   string
	is  string
	not dataType
}

func (e DataTypeErr) Error() string {
	return fmt.Sprintf("%s is %s, not %s", e.k, e.is, e.not)
}

// These settings are in order of precedence. Each setting type can be set by
// any of the types with higher precedence if contour is configured to use that
// type.
const (
	// Basic settings are settings that are none of the below. These are often
	// referred to as application settings: settings that can only be updated
	// within an application and not by configuration files, environment
	// variables, or flags. These settings do not have to be registered.
	Basic SettingType = iota + 1
	// Core settings are immutable once registered.
	Core
	// ConFileVar settings can be set from a configuration file.
	ConfFileVar
	// EnvVar settings can be set from a configuration file and an environment
	// variable; unless it has been explicitly set to not be updateable from a
	// configuration file.
	EnvVar
	// Flag settings can be set from a configuration file, an environment
	// variable, and a flag; unless it has been explicitly set to not be
	// updateable from either a configuration file or an environment variable.
	Flag
)

// SettingType is type of setting.
type SettingType int

func (t SettingType) String() string {
	switch t {
	case Basic:
		return "basic"
	case Core:
		return "core"
	case ConfFileVar:
		return "configuration file var"
	case EnvVar:
		return "env var"
	case Flag:
		return "flag"
	default:
		return "unknown"
	}
}

// settings: contour's global Settinngs set; contour functions operate on this.
var settings *Settings

func init() {
	settings = New(app)
}

// SettingNotFoundErr occurs when a setting isn't found.
type SettingNotFoundErr struct {
	settingType SettingType
	k           string
}

func (e SettingNotFoundErr) Error() string {
	if e.settingType <= 0 {
		return fmt.Sprintf("%s: setting not found", e.k)
	}
	return fmt.Sprintf("%s: %s setting not found", e.k, e.settingType)
}

// UnsupportedFormatErr occurs when the string cannot be matched to a
// supported configuration format.
type UnsupportedFormatErr struct {
	v string
}

func (e UnsupportedFormatErr) Error() string {
	return fmt.Sprintf("%s: unsupported configuration format", e.v)
}
<|endoftext|>


<commit_before>// +build js

package http

import (
	"bufio"
	"bytes"
	"errors"
	"io/ioutil"
	"net/textproto"

	"github.com/gopherjs/gopherjs/js"
)

var DefaultTransport RoundTripper = &XHRTransport{}

type XHRTransport struct {
	inflight map[*Request]*js.Object
}

func (t *XHRTransport) RoundTrip(req *Request) (*Response, error) {
	xhrConstructor := js.Global.Get("XMLHttpRequest")
	if xhrConstructor == js.Undefined {
		return nil, errors.New("net/http: XMLHttpRequest not available")
	}
	xhr := xhrConstructor.New()
	xhr.Set("responseType", "arraybuffer")

	if t.inflight == nil {
		t.inflight = map[*Request]*js.Object{}
	}
	t.inflight[req] = xhr
	defer delete(t.inflight, req)

	respCh := make(chan *Response)
	errCh := make(chan error)

	xhr.Set("onload", func() {
		header, _ := textproto.NewReader(bufio.NewReader(bytes.NewReader([]byte(xhr.Call("getAllResponseHeaders").String() + "\n")))).ReadMIMEHeader()
		body := js.Global.Get("Uint8Array").New(xhr.Get("response")).Interface().([]byte)
		respCh <- &Response{
			Status:        xhr.Get("status").String() + " " + xhr.Get("statusText").String(),
			StatusCode:    xhr.Get("status").Int(),
			Header:        Header(header),
			ContentLength: int64(len(body)),
			Body:          ioutil.NopCloser(bytes.NewReader(body)),
			Request:       req,
		}
	})

	xhr.Set("onerror", func(e *js.Object) {
		errCh <- errors.New("net/http: XMLHttpRequest failed")
	})

	xhr.Set("onabort", func(e *js.Object) {
		errCh <- errors.New("net/http: request canceled")
	})

	xhr.Call("open", req.Method, req.URL.String())
	for key, values := range req.Header {
		for _, value := range values {
			xhr.Call("setRequestHeader", key, value)
		}
	}
	var body []byte
	if req.Body != nil {
		var err error
		body, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return nil, err
		}
	}
	xhr.Call("send", body)

	select {
	case resp := <-respCh:
		return resp, nil
	case err := <-errCh:
		return nil, err
	}
}

func (t *XHRTransport) CancelRequest(req *Request) {
	if xhr, ok := t.inflight[req]; ok {
		xhr.Call("abort")
	}
}
<commit_msg>natives/net/http: set response ContentLength from headers on HEAD requests<commit_after>// +build js

package http

import (
	"bufio"
	"bytes"
	"errors"
	"io/ioutil"
	"net/textproto"
	"strconv"

	"github.com/gopherjs/gopherjs/js"
)

var DefaultTransport RoundTripper = &XHRTransport{}

type XHRTransport struct {
	inflight map[*Request]*js.Object
}

func (t *XHRTransport) RoundTrip(req *Request) (*Response, error) {
	xhrConstructor := js.Global.Get("XMLHttpRequest")
	if xhrConstructor == js.Undefined {
		return nil, errors.New("net/http: XMLHttpRequest not available")
	}
	xhr := xhrConstructor.New()
	xhr.Set("responseType", "arraybuffer")

	if t.inflight == nil {
		t.inflight = map[*Request]*js.Object{}
	}
	t.inflight[req] = xhr
	defer delete(t.inflight, req)

	respCh := make(chan *Response)
	errCh := make(chan error)

	xhr.Set("onload", func() {
		header, _ := textproto.NewReader(bufio.NewReader(bytes.NewReader([]byte(xhr.Call("getAllResponseHeaders").String() + "\n")))).ReadMIMEHeader()
		body := js.Global.Get("Uint8Array").New(xhr.Get("response")).Interface().([]byte)

		contentLength := int64(-1)
		if req.Method == "HEAD" {
			i, err := strconv.ParseInt(header.Get("Content-Length"), 10, 64)
			if err == nil {
				contentLength = i
			}
		} else {
			contentLength = int64(len(body))
		}

		respCh <- &Response{
			Status:        xhr.Get("status").String() + " " + xhr.Get("statusText").String(),
			StatusCode:    xhr.Get("status").Int(),
			Header:        Header(header),
			ContentLength: contentLength,
			Body:          ioutil.NopCloser(bytes.NewReader(body)),
			Request:       req,
		}
	})

	xhr.Set("onerror", func(e *js.Object) {
		errCh <- errors.New("net/http: XMLHttpRequest failed")
	})

	xhr.Set("onabort", func(e *js.Object) {
		errCh <- errors.New("net/http: request canceled")
	})

	xhr.Call("open", req.Method, req.URL.String())
	for key, values := range req.Header {
		for _, value := range values {
			xhr.Call("setRequestHeader", key, value)
		}
	}
	var body []byte
	if req.Body != nil {
		var err error
		body, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return nil, err
		}
	}
	xhr.Call("send", body)

	select {
	case resp := <-respCh:
		return resp, nil
	case err := <-errCh:
		return nil, err
	}
}

func (t *XHRTransport) CancelRequest(req *Request) {
	if xhr, ok := t.inflight[req]; ok {
		xhr.Call("abort")
	}
}
<|endoftext|>