<commit_before>package structs

import "time"

// AuditLog is a structure for holding a log of the audit
type AuditLog struct {
	Date       time.Time `json:"date"`
	Action     string    `json:"action"`
	Level      string    `json:"level"`
	Output     string    `json:"output,omitempty"`
	RemoteAddr string    `json:"remoteaddr"`
	URL        string    `json:"url,omitempty"`
	User       string    `json:"user"`
}

// Auth struct contains the generic configuration and details
// about the authentication
type Auth struct {
	Driver     string
	PrivateKey string
	PublicKey  string
}

// CheckExecution struct contains the payload for issuing a
// check execution request to a Sensu API
type CheckExecution struct {
	Check       string   `json:"check"`
	Dc          string   `json:"dc"`
	Subscribers []string `json:"subscribers"`
}

// Data is a structure for holding public data fetched from the Sensu APIs and exposed by the endpoints
type Data struct {
	Aggregates    []interface{}
	Checks        []interface{}
	Clients       []interface{}
	Dc            []*Datacenter
	Events        []interface{}
	Health        Health
	Metrics       Metrics
	SEMetrics     SEMetrics
	SERawMetrics  SERawMetrics `json:"-"`
	Silenced      []interface{}
	Stashes       []interface{}
	Subscriptions []Subscription
}

// Datacenter is a structure for holding the information about a datacenter
type Datacenter struct {
	Name    string         `json:"name"`
	Info    Info           `json:"info"`
	Metrics map[string]int `json:"metrics"`
}

// Generic is a structure for holding a generic element
type Generic struct {
	Dc string `json:"dc"`
}

// GenericCheck is a structure for holding a generic check
type GenericCheck struct {
	Dc          string   `json:"dc"`
	Output      string   `json:"output"`
	Status      int      `json:"status"`
	Subscribers []string `json:"subscribers"`
}

// GenericClient is a structure for holding a generic client
type GenericClient struct {
	Dc            string   `json:"dc"`
	Name          string   `json:"name"`
	Subscriptions []string `json:"subscriptions"`
}

// GenericEvent is a structure for holding a generic event
type GenericEvent struct {
	Check  GenericCheck  `json:"check"`
	Client GenericClient `json:"client"`
	Dc     string        `json:"dc"`
}

// Health is a structure for holding health informaton about Sensu & Uchiwa
type Health struct {
	Sensu  map[string]SensuHealth `json:"sensu"`
	Uchiwa string                 `json:"uchiwa"`
}

// SensuHealth is a structure for holding health information about a specific sensu datacenter
type SensuHealth struct {
	Output string `json:"output"`
	Status int    `json:"status"`
}

// Info is a structure for holding the /info API information
type Info struct {
	Redis     Redis        `json:"redis"`
	Sensu     Sensu        `json:"sensu"`
	Servers   []InfoServer `json:"servers"`
	Transport transport    `json:"transport"`
}

type InfoServer struct {
	ID        string                        `json:"id"`
	Hostname  string                        `json:"hostname"`
	Address   string                        `json:"address"`
	IsLeader  bool                          `json:"is_leader"`
	Metrics   map[string]map[string]float32 `json:"metrics"`
	Timestamp int                           `json:"timestamp"`
}

// Redis is a structure for holding the redis status
type Redis struct {
	Connected bool `json:"connected"`
}

// Metrics is a structure for holding the metrics of the Sensu objects
type Metrics struct {
	Aggregates  StatusMetrics `json:"aggregates"`
	Checks      StatusMetrics `json:"checks"`
	Clients     StatusMetrics `json:"clients"`
	Datacenters StatusMetrics `json:"datacenters"`
	Events      StatusMetrics `json:"events"`
	Silenced    StatusMetrics `json:"silenced"`
	Stashes     StatusMetrics `json:"stashes"`
}

// StatusMetrics is a structure for holding the status count
type StatusMetrics struct {
	Critical int `json:"critical"`
	Healthy  int `json:"healthy"`
	Silenced int `json:"silenced"`
	Total    int `json:"total"`
	Unknown  int `json:"unknown"`
	Warning  int `json:"warning"`
}

// SEMetrics is a structure for holding the Sensu Enterprise metrics
type SEMetrics struct {
	Clients         *SEMetric   `json:"clients"`
	Events          []*SEMetric `json:"events"`
	KeepalivesAVG60 *SEMetric   `json:"keepalives_avg_60"`
	Requests        *SEMetric   `json:"requests"`
	Results         *SEMetric   `json:"results"`
}

// SEMetric is a structure for holding a Sensu Enterprise metric
type SEMetric struct {
	Data []XY   `json:"data"`
	Name string `json:"name"`
}

// SERawMetrics ...
type SERawMetrics struct {
	Clients         []*SERawMetric
	Events          []*SERawMetric
	KeepalivesAVG60 []*SERawMetric
	Requests        []*SERawMetric
	Results         []*SERawMetric
}

// SERawMetric ...
type SERawMetric struct {
	Name   string
	Points [][]interface{} `json:"points"`
}

// Sensu is a structure for holding the sensu version
type Sensu struct {
	Version string `json:"version"`
}

type transport struct {
	Connected  bool            `json:"connected"`
	Keepalives transportStatus `json:"keepalives"`
	Results    transportStatus `json:"results"`
}

type transportStatus struct {
	Messages  int `json:"messages"`
	Consumers int `json:"consumers"`
}

// Subscription is a structure for holding a single subscription
type Subscription struct {
	Dc   string `json:"dc"`
	Name string `json:"name"`
}

// XPagination is a structure for holding the x-pagination HTTP header
type XPagination struct {
	Limit  int
	Offset int
	Total  int
}

// XY is a structure for holding the coordinates of Sensu Enterprise metrics points
type XY struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}
<commit_msg>Add Sensu server tasks and more to datacenter view<commit_after>package structs

import "time"

// AuditLog is a structure for holding a log of the audit
type AuditLog struct {
	Date       time.Time `json:"date"`
	Action     string    `json:"action"`
	Level      string    `json:"level"`
	Output     string    `json:"output,omitempty"`
	RemoteAddr string    `json:"remoteaddr"`
	URL        string    `json:"url,omitempty"`
	User       string    `json:"user"`
}

// Auth struct contains the generic configuration and details
// about the authentication
type Auth struct {
	Driver     string
	PrivateKey string
	PublicKey  string
}

// CheckExecution struct contains the payload for issuing a
// check execution request to a Sensu API
type CheckExecution struct {
	Check       string   `json:"check"`
	Dc          string   `json:"dc"`
	Subscribers []string `json:"subscribers"`
}

// Data is a structure for holding public data fetched from the Sensu APIs and exposed by the endpoints
type Data struct {
	Aggregates    []interface{}
	Checks        []interface{}
	Clients       []interface{}
	Dc            []*Datacenter
	Events        []interface{}
	Health        Health
	Metrics       Metrics
	SEMetrics     SEMetrics
	SERawMetrics  SERawMetrics `json:"-"`
	Silenced      []interface{}
	Stashes       []interface{}
	Subscriptions []Subscription
}

// Datacenter is a structure for holding the information about a datacenter
type Datacenter struct {
	Name    string         `json:"name"`
	Info    Info           `json:"info"`
	Metrics map[string]int `json:"metrics"`
}

// Generic is a structure for holding a generic element
type Generic struct {
	Dc string `json:"dc"`
}

// GenericCheck is a structure for holding a generic check
type GenericCheck struct {
	Dc          string   `json:"dc"`
	Output      string   `json:"output"`
	Status      int      `json:"status"`
	Subscribers []string `json:"subscribers"`
}

// GenericClient is a structure for holding a generic client
type GenericClient struct {
	Dc            string   `json:"dc"`
	Name          string   `json:"name"`
	Subscriptions []string `json:"subscriptions"`
}

// GenericEvent is a structure for holding a generic event
type GenericEvent struct {
	Check  GenericCheck  `json:"check"`
	Client GenericClient `json:"client"`
	Dc     string        `json:"dc"`
}

// Health is a structure for holding health informaton about Sensu & Uchiwa
type Health struct {
	Sensu  map[string]SensuHealth `json:"sensu"`
	Uchiwa string                 `json:"uchiwa"`
}

// SensuHealth is a structure for holding health information about a specific sensu datacenter
type SensuHealth struct {
	Output string `json:"output"`
	Status int    `json:"status"`
}

// Info is a structure for holding the /info API information
type Info struct {
	Redis     Redis        `json:"redis"`
	Sensu     Sensu        `json:"sensu"`
	Servers   []InfoServer `json:"servers"`
	Transport transport    `json:"transport"`
}

type InfoServer struct {
	ID        string                        `json:"id"`
	Hostname  string                        `json:"hostname"`
	Address   string                        `json:"address"`
	IsLeader  bool                          `json:"is_leader,omitempty"`
	Metrics   map[string]map[string]float32 `json:"metrics"`
	Sensu     map[string]interface{}        `json:"sensu,omitempty"`
	Tasks     []string                      `json:"tasks,omitempty"`
	Timestamp int                           `json:"timestamp"`
}

// Redis is a structure for holding the redis status
type Redis struct {
	Connected bool `json:"connected"`
}

// Metrics is a structure for holding the metrics of the Sensu objects
type Metrics struct {
	Aggregates  StatusMetrics `json:"aggregates"`
	Checks      StatusMetrics `json:"checks"`
	Clients     StatusMetrics `json:"clients"`
	Datacenters StatusMetrics `json:"datacenters"`
	Events      StatusMetrics `json:"events"`
	Silenced    StatusMetrics `json:"silenced"`
	Stashes     StatusMetrics `json:"stashes"`
}

// StatusMetrics is a structure for holding the status count
type StatusMetrics struct {
	Critical int `json:"critical"`
	Healthy  int `json:"healthy"`
	Silenced int `json:"silenced"`
	Total    int `json:"total"`
	Unknown  int `json:"unknown"`
	Warning  int `json:"warning"`
}

// SEMetrics is a structure for holding the Sensu Enterprise metrics
type SEMetrics struct {
	Clients         *SEMetric   `json:"clients"`
	Events          []*SEMetric `json:"events"`
	KeepalivesAVG60 *SEMetric   `json:"keepalives_avg_60"`
	Requests        *SEMetric   `json:"requests"`
	Results         *SEMetric   `json:"results"`
}

// SEMetric is a structure for holding a Sensu Enterprise metric
type SEMetric struct {
	Data []XY   `json:"data"`
	Name string `json:"name"`
}

// SERawMetrics ...
type SERawMetrics struct {
	Clients         []*SERawMetric
	Events          []*SERawMetric
	KeepalivesAVG60 []*SERawMetric
	Requests        []*SERawMetric
	Results         []*SERawMetric
}

// SERawMetric ...
type SERawMetric struct {
	Name   string
	Points [][]interface{} `json:"points"`
}

// Sensu is a structure for holding the sensu version
type Sensu struct {
	Version string `json:"version"`
}

type transport struct {
	Connected  bool            `json:"connected"`
	Keepalives transportStatus `json:"keepalives"`
	Results    transportStatus `json:"results"`
}

type transportStatus struct {
	Messages  int `json:"messages"`
	Consumers int `json:"consumers"`
}

// Subscription is a structure for holding a single subscription
type Subscription struct {
	Dc   string `json:"dc"`
	Name string `json:"name"`
}

// XPagination is a structure for holding the x-pagination HTTP header
type XPagination struct {
	Limit  int
	Offset int
	Total  int
}

// XY is a structure for holding the coordinates of Sensu Enterprise metrics points
type XY struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}
<|endoftext|>


<commit_before>package fileutil

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"fmt"
	"github.com/APTrust/bagit/constants"
	"github.com/APTrust/bagit/errtypes"
	"golang.org/x/crypto/md4"
	"hash"
	"io"
	"os"
	"os/user"
	"path/filepath"
	"strings"
)

// FileExists returns true if the file at path exists.
func FileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}

// IsFile returns true if the object at filePath is a file.
func IsFile(filePath string) bool {
	stat, err := os.Stat(filePath)
	if err == nil && stat != nil {
		return !stat.IsDir()
	}
	return false
}

// IsDir returns true if the object at filePath is a directory.
func IsDir(filePath string) bool {
	stat, err := os.Stat(filePath)
	if err == nil && stat != nil {
		return stat.IsDir()
	}
	return false
}

// Expands the tilde in a directory path to the current
// user's home directory. For example, on Linux, ~/data
// would expand to something like /home/josie/data
func ExpandTilde(filePath string) (string, error) {
	if strings.Index(filePath, "~") < 0 {
		return filePath, nil
	}
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	separator := string(os.PathSeparator)
	homeDir := usr.HomeDir + separator
	expandedDir := strings.Replace(filePath, "~"+separator, homeDir, 1)
	return expandedDir, nil
}

// RecursiveFileList returns a list of all files in path dir
// and its subfolders. It does not return directories.
func RecursiveFileList(dir string) ([]string, error) {
	files := make([]string, 0)
	err := filepath.Walk(dir, func(filePath string, f os.FileInfo, err error) error {
		if f != nil && f.IsDir() == false {
			files = append(files, filePath)
		}
		return nil
	})
	return files, err
}

// Returns true if the path specified by dir has at least minLength
// characters and at least minSeparators path separators. This is
// for testing paths you want pass into os.RemoveAll(), so you don't
// wind up deleting "/" or "/etc" or something catastrophic like that.
func LooksSafeToDelete(dir string, minLength, minSeparators int) bool {
	separator := string(os.PathSeparator)
	separatorCount := (len(dir) - len(strings.Replace(dir, separator, "", -1)))
	return len(dir) >= minLength && separatorCount >= minSeparators
}

// ParseManifestName returns a manifestType and algorithm if filePath
// looks like a manifest name. For example, "tagmanifest-sha256.txt"
// would return constants.TAG_MANIFEST and "sha256", while
// "manifest-md5.txt" would return constants.PAYLOAD_MANIFEST, "md5".
// Non-manifest files will return two empty strings.
func ParseManifestName(filePath string) (manifestType string, algorithm string) {
	// Regex??
	if strings.Contains(filePath, "/") || strings.Contains(filePath, string(os.PathSeparator)) {
		return "", ""
	}
	parts := strings.Split(filePath, ".")
	if len(parts) > 1 && parts[1] == "txt" {
		if strings.HasPrefix(parts[0], "tagmanifest-") {
			manifestType = constants.TAG_MANIFEST
		} else if strings.HasPrefix(parts[0], "manifest-") {
			manifestType = constants.PAYLOAD_MANIFEST
		}
		nameAndAlg := strings.Split(parts[0], "-")
		if len(nameAndAlg) > 1 {
			algorithm = nameAndAlg[1]
		} else {
			manifestType = ""
		}
	}
	return manifestType, algorithm
}

// CalculateChecksums calculates checksums for a file, based on the algorithms
// specified in the algorithms param. Supported algorithm names are specified
// in constants.go. The return value is a map in which the key is the algorithm
// name and the value is the hash digest in the form of a hex string.
//
// This function will calculate all of the digests in a single read of the
// file.
//
// Example:
//
// CalculateChecksums("/path/to/file.txt", []string{ MD5, SHA256, SHA384 })
//
// Returns a map that looks like this:
//
// "md5"    => "0123456789ABCDEF"
// "sha256" => "FEDCBA0987654321"
// "sha512" => "ABCDEF1234567890"
func CalculateChecksums(reader io.Reader, algorithms []string) (map[string]string, error) {
	if len(algorithms) == 0 {
		return nil, errtypes.NewValueError("You must specify at least one algorithm.")
	}
	hashes := make([]io.Writer, len(algorithms))
	for i, alg := range algorithms {
		if !constants.IsSupportedAlgorithm(alg) {
			return nil, errtypes.NewValueError("Unsupported algorithm: %s", alg)
		}
		if alg == constants.MD4 {
			hashes[i] = md4.New()
		} else if alg == constants.MD5 {
			hashes[i] = md5.New()
		} else if alg == constants.SHA1 {
			hashes[i] = sha1.New()
		} else if alg == constants.SHA224 {
			hashes[i] = sha256.New224()
		} else if alg == constants.SHA256 {
			hashes[i] = sha256.New()
		} else if alg == constants.SHA384 {
			hashes[i] = sha512.New384()
		} else if alg == constants.SHA512 {
			hashes[i] = sha512.New()
		}
	}
	multiWriter := io.MultiWriter(hashes...)
	_, err := io.Copy(multiWriter, reader)
	if err != nil {
		return nil, err
	}
	digests := make(map[string]string)
	for i, alg := range algorithms {
		_hash := hashes[i].(hash.Hash)
		digests[alg] = fmt.Sprintf("%x", _hash.Sum(nil))
	}
	return digests, nil
}
<commit_msg>Added WriteWithChecksums<commit_after>package fileutil

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"fmt"
	"github.com/APTrust/bagit/constants"
	"github.com/APTrust/bagit/errtypes"
	"golang.org/x/crypto/md4"
	"hash"
	"io"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
)

// FileExists returns true if the file at path exists.
func FileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}

// IsFile returns true if the object at filePath is a file.
func IsFile(filePath string) bool {
	stat, err := os.Stat(filePath)
	if err == nil && stat != nil {
		return !stat.IsDir()
	}
	return false
}

// IsDir returns true if the object at filePath is a directory.
func IsDir(filePath string) bool {
	stat, err := os.Stat(filePath)
	if err == nil && stat != nil {
		return stat.IsDir()
	}
	return false
}

// Expands the tilde in a directory path to the current
// user's home directory. For example, on Linux, ~/data
// would expand to something like /home/josie/data
func ExpandTilde(filePath string) (string, error) {
	if strings.Index(filePath, "~") < 0 {
		return filePath, nil
	}
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	separator := string(os.PathSeparator)
	homeDir := usr.HomeDir + separator
	expandedDir := strings.Replace(filePath, "~"+separator, homeDir, 1)
	return expandedDir, nil
}

// RecursiveFileList returns a list of all files in path dir
// and its subfolders. It does not return directories.
func RecursiveFileList(dir string) ([]string, error) {
	files := make([]string, 0)
	err := filepath.Walk(dir, func(filePath string, f os.FileInfo, err error) error {
		if f != nil && f.IsDir() == false {
			files = append(files, filePath)
		}
		return nil
	})
	return files, err
}

// Returns true if the path specified by dir has at least minLength
// characters and at least minSeparators path separators. This is
// for testing paths you want pass into os.RemoveAll(), so you don't
// wind up deleting "/" or "/etc" or something catastrophic like that.
func LooksSafeToDelete(dir string, minLength, minSeparators int) bool {
	separator := string(os.PathSeparator)
	separatorCount := (len(dir) - len(strings.Replace(dir, separator, "", -1)))
	return len(dir) >= minLength && separatorCount >= minSeparators
}

// ParseManifestName returns a manifestType and algorithm if filePath
// looks like a manifest name. For example, "tagmanifest-sha256.txt"
// would return constants.TAG_MANIFEST and "sha256", while
// "manifest-md5.txt" would return constants.PAYLOAD_MANIFEST, "md5".
// Non-manifest files will return two empty strings.
func ParseManifestName(filePath string) (manifestType string, algorithm string) {
	// Regex??
	if strings.Contains(filePath, "/") || strings.Contains(filePath, string(os.PathSeparator)) {
		return "", ""
	}
	parts := strings.Split(filePath, ".")
	if len(parts) > 1 && parts[1] == "txt" {
		if strings.HasPrefix(parts[0], "tagmanifest-") {
			manifestType = constants.TAG_MANIFEST
		} else if strings.HasPrefix(parts[0], "manifest-") {
			manifestType = constants.PAYLOAD_MANIFEST
		}
		nameAndAlg := strings.Split(parts[0], "-")
		if len(nameAndAlg) > 1 {
			algorithm = nameAndAlg[1]
		} else {
			manifestType = ""
		}
	}
	return manifestType, algorithm
}

// CalculateChecksums calculates checksums for a file, based on the algorithms
// specified in the algorithms param. Supported algorithm names are specified
// in constants.go. The return value is a map in which the key is the algorithm
// name and the value is the hash digest in the form of a hex string.
//
// This function will calculate all of the digests in a single read of the
// file.
//
// Example:
//
// CalculateChecksums("/path/to/file.txt", []string{ MD5, SHA256, SHA384 })
//
// Returns a map that looks like this:
//
// "md5"    => "0123456789ABCDEF"
// "sha256" => "FEDCBA0987654321"
// "sha512" => "ABCDEF1234567890"
func CalculateChecksums(reader io.Reader, algorithms []string) (map[string]string, error) {
	return WriteWithChecksums(reader, ioutil.Discard, algorithms)
}

// WriteWithChecksums copies the contents of reader to writer,
// calculating the specified checksums in the process. It returns
// a map of the checksums in which the keys are the names of the
// hashing algorithms and the values are digests. For example,
// this call:
//
// checsums, err := WriteWithChecksums(file1, file2, []string{ "md5", "sha256"})
//
// will copy the contents of file1 to file2, and will calculate md5
// and sha256 digests on the contents, returning a map that looks like
// this:
//
// { "md5": "1234567", "sha256": "890abcd" }
func WriteWithChecksums(reader io.Reader, writer io.Writer, algorithms []string) (map[string]string, error) {
	if len(algorithms) == 0 {
		return nil, errtypes.NewValueError("You must specify at least one algorithm.")
	}
	writers := make([]io.Writer, len(algorithms)+1)
	writers[0] = writer
	for i, alg := range algorithms {
		if !constants.IsSupportedAlgorithm(alg) {
			return nil, errtypes.NewValueError("Unsupported algorithm: %s", alg)
		}
		if alg == constants.MD4 {
			writers[i+1] = md4.New()
		} else if alg == constants.MD5 {
			writers[i+1] = md5.New()
		} else if alg == constants.SHA1 {
			writers[i+1] = sha1.New()
		} else if alg == constants.SHA224 {
			writers[i+1] = sha256.New224()
		} else if alg == constants.SHA256 {
			writers[i+1] = sha256.New()
		} else if alg == constants.SHA384 {
			writers[i+1] = sha512.New384()
		} else if alg == constants.SHA512 {
			writers[i+1] = sha512.New()
		}
	}
	multiWriter := io.MultiWriter(writers...)
	_, err := io.Copy(multiWriter, reader)
	if err != nil {
		return nil, err
	}
	digests := make(map[string]string)
	for i, alg := range algorithms {
		_hash := writers[i+1].(hash.Hash)
		digests[alg] = fmt.Sprintf("%x", _hash.Sum(nil))
	}
	return digests, nil
}
<|endoftext|>


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

package xhttp

import (
	"gopkg.in/goyy/goyy.v0/data/domain"
	"gopkg.in/goyy/goyy.v0/data/entity"
	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/web/session"
	"net/http"
	"net/url"
)

func newContext(w http.ResponseWriter, s session.Interface, r *http.Request, vs url.Values, hs Handlers) Context {
	c := &context{}
	c.request = r
	c.session = s
	c.response = w
	c.params = vs
	c.attributes = make(map[string]interface{}, 0)
	c.handlers = hs
	return c
}

type context struct {
	request    *http.Request
	session    session.Interface
	response   http.ResponseWriter
	params     url.Values
	attributes map[string]interface{}
	handlers   Handlers
	index      int8
}

func (me *context) Request() *http.Request {
	return me.request
}

func (me *context) Session() session.Interface {
	return me.session
}

func (me *context) ResponseWriter() http.ResponseWriter {
	return me.response
}

func (me *context) Params() url.Values {
	return me.params
}

func (me *context) Param(key string) string {
	return me.params.Get(key)
}

func (me *context) Bind(out entity.Interface) error {
	sifts, err := domain.NewSifts(me.params, defaultEntityPrefix)
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	for _, sift := range sifts {
		out.SetString(sift.Key(), sift.Value())
	}
	return nil
}

func (me *context) Attribute(key string) interface{} {
	return me.attributes[key]
}

func (me *context) Attributes() map[string]interface{} {
	return me.attributes
}

func (me *context) SetAttribute(key string, value interface{}) {
	if strings.IsNotBlank(key) && value != nil {
		me.attributes[key] = value
	}
}

// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
func (me *context) Next() {
	s := int8(len(me.handlers))
	if s > 0 && me.index < s {
		i := me.index
		me.index++
		me.handlers[i](me)
	}
}

// Returns if the currect context was aborted.
func (me *context) IsAborted() bool {
	return me.index == AbortIndex
}

// Stops the system to continue calling the pending handlers in the chain.
// Let's say you have an authorization middleware that validates if the request is authorized
// if the authorization fails (the password does not match). This method (Abort()) should be called
// in order to stop the execution of the actual handler.
func (me *context) Abort() {
	me.index = AbortIndex
}

// It calls Abort() and writes the headers with the specified status code.
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
func (me *context) AbortWithStatus(code int) {
	me.response.WriteHeader(code)
	me.Abort()
}

func (me *context) HTML(status int, name string, v interface{}) error {
	return r.HTML(me.ResponseWriter(), status, name, v)
}

func (me *context) JSON(status int, v interface{}) error {
	return r.JSON(me.ResponseWriter(), status, v)
}

func (me *context) JSONP(status int, callback string, v interface{}) error {
	return r.JSONP(me.ResponseWriter(), status, callback, v)
}

func (me *context) XML(status int, v interface{}) error {
	return r.XML(me.ResponseWriter(), status, v)
}

func (me *context) Text(status int, format string, values ...interface{}) error {
	return r.Text(me.ResponseWriter(), status, format, values...)
}

func (me *context) Error(status int) error {
	return r.Error(me.ResponseWriter(), status)
}

func (me *context) Redirect(location string, status ...int) error {
	return r.Redirect(me.ResponseWriter(), me.Request(), location, status...)
}
<commit_msg>context.Param : use strings.JoinIgnoreBlank<commit_after>// Copyright 2014 The goyy Authors.  All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package xhttp

import (
	"gopkg.in/goyy/goyy.v0/data/domain"
	"gopkg.in/goyy/goyy.v0/data/entity"
	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/web/session"
	"net/http"
	"net/url"
)

func newContext(w http.ResponseWriter, s session.Interface, r *http.Request, vs url.Values, hs Handlers) Context {
	c := &context{}
	c.request = r
	c.session = s
	c.response = w
	c.params = vs
	c.attributes = make(map[string]interface{}, 0)
	c.handlers = hs
	return c
}

type context struct {
	request    *http.Request
	session    session.Interface
	response   http.ResponseWriter
	params     url.Values
	attributes map[string]interface{}
	handlers   Handlers
	index      int8
}

func (me *context) Request() *http.Request {
	return me.request
}

func (me *context) Session() session.Interface {
	return me.session
}

func (me *context) ResponseWriter() http.ResponseWriter {
	return me.response
}

func (me *context) Params() url.Values {
	return me.params
}

func (me *context) Param(key string) string {
	return strings.JoinIgnoreBlank(me.params[key], ",")
}

func (me *context) Bind(out entity.Interface) error {
	sifts, err := domain.NewSifts(me.params, defaultEntityPrefix)
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	for _, sift := range sifts {
		out.SetString(sift.Key(), sift.Value())
	}
	return nil
}

func (me *context) Attribute(key string) interface{} {
	return me.attributes[key]
}

func (me *context) Attributes() map[string]interface{} {
	return me.attributes
}

func (me *context) SetAttribute(key string, value interface{}) {
	if strings.IsNotBlank(key) && value != nil {
		me.attributes[key] = value
	}
}

// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
func (me *context) Next() {
	s := int8(len(me.handlers))
	if s > 0 && me.index < s {
		i := me.index
		me.index++
		me.handlers[i](me)
	}
}

// Returns if the currect context was aborted.
func (me *context) IsAborted() bool {
	return me.index == AbortIndex
}

// Stops the system to continue calling the pending handlers in the chain.
// Let's say you have an authorization middleware that validates if the request is authorized
// if the authorization fails (the password does not match). This method (Abort()) should be called
// in order to stop the execution of the actual handler.
func (me *context) Abort() {
	me.index = AbortIndex
}

// It calls Abort() and writes the headers with the specified status code.
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
func (me *context) AbortWithStatus(code int) {
	me.response.WriteHeader(code)
	me.Abort()
}

func (me *context) HTML(status int, name string, v interface{}) error {
	return r.HTML(me.ResponseWriter(), status, name, v)
}

func (me *context) JSON(status int, v interface{}) error {
	return r.JSON(me.ResponseWriter(), status, v)
}

func (me *context) JSONP(status int, callback string, v interface{}) error {
	return r.JSONP(me.ResponseWriter(), status, callback, v)
}

func (me *context) XML(status int, v interface{}) error {
	return r.XML(me.ResponseWriter(), status, v)
}

func (me *context) Text(status int, format string, values ...interface{}) error {
	return r.Text(me.ResponseWriter(), status, format, values...)
}

func (me *context) Error(status int) error {
	return r.Error(me.ResponseWriter(), status)
}

func (me *context) Redirect(location string, status ...int) error {
	return r.Redirect(me.ResponseWriter(), me.Request(), location, status...)
}
<|endoftext|>


<commit_before>package numeric

var (
	runeToInt64LookupTable = map[rune]int64{
		DigitZero  : 0,
		DigitOne   : 1,
		DigitTwo   : 2,
		DigitThree : 3,
		DigitFour  : 4,
		DigitFive  : 5,
		DigitSix   : 6,
		DigitSeven : 7,
		DigitEight : 8,
		DigitNine  : 9,

		ArabicIndicDigitZero  : 0,
		ArabicIndicDigitOne   : 1,
		ArabicIndicDigitTwo   : 2,
		ArabicIndicDigitThree : 3,
		ArabicIndicDigitFour  : 4,
		ArabicIndicDigitFive  : 5,
		ArabicIndicDigitSix   : 6,
		ArabicIndicDigitSeven : 7,
		ArabicIndicDigitEight : 8,
		ArabicIndicDigitNine  : 9,

		ExtendedArabicIndicDigitZero  : 0,
		ExtendedArabicIndicDigitOne   : 1,
		ExtendedArabicIndicDigitTwo   : 2,
		ExtendedArabicIndicDigitThree : 3,
		ExtendedArabicIndicDigitFour  : 4,
		ExtendedArabicIndicDigitFive  : 5,
		ExtendedArabicIndicDigitSix   : 6,
		ExtendedArabicIndicDigitSeven : 7,
		ExtendedArabicIndicDigitEight : 8,
		ExtendedArabicIndicDigitNine  : 9,

		SuperscriptZero  : 0,
		SuperscriptOne   : 1,
		SuperscriptTwo   : 2,
		SuperscriptThree : 3,
		SuperscriptFour  : 4,
		SuperscriptFive  : 5,
		SuperscriptSix   : 6,
		SuperscriptSeven : 7,
		SuperscriptEight : 8,
		SuperscriptNine  : 9,

		SubscriptZero  : 0,
		SubscriptOne   : 1,
		SubscriptTwo   : 2,
		SubscriptThree : 3,
		SubscriptFour  : 4,
		SubscriptFive  : 5,
		SubscriptSix   : 6,
		SubscriptSeven : 7,
		SubscriptEight : 8,
		SubscriptNine  : 9,

		FractionNumeratorOne : 0,

		RomanNumeralOne         : 1,
		RomanNumeralTwo         : 2,
		RomanNumeralThree       : 3,
		RomanNumeralFour        : 4,
		RomanNumeralFive        : 5,
		RomanNumeralSix         : 6,
		RomanNumeralSeven       : 7,
		RomanNumeralEight       : 8,
		RomanNumeralNine        : 9,
		RomanNumeralTen         : 10,
		RomanNumeralEleven      : 11,
		RomanNumeralTwelve      : 12,
		RomanNumeralFifty       : 50,
		RomanNumeralOneHundred  : 100,
		RomanNumeralFiveHundred : 500,
		RomanNumeralOneThousand : 1000,

		SmallRomanNumeralOne         : 1,
		SmallRomanNumeralTwo         : 2,
		SmallRomanNumeralThree       : 3,
		SmallRomanNumeralFour        : 4,
		SmallRomanNumeralFive        : 5,
		SmallRomanNumeralSix         : 6,
		SmallRomanNumeralSeven       : 7,
		SmallRomanNumeralEight       : 8,
		SmallRomanNumeralNine        : 9,
		SmallRomanNumeralTen         : 10,
		SmallRomanNumeralEleven      : 11,
		SmallRomanNumeralTwelve      : 12,
		SmallRomanNumeralFifty       : 50,
		SmallRomanNumeralOneHundred  : 100,
		SmallRomanNumeralFiveHundred : 500,
		SmallRomanNumeralOneThousand : 1000,

		RomanNumeralOneThousandCD      : 1000,
		RomanNumeralFiveThousand       : 5000,
		RomanNumeralTenThousand        : 10000,
		RomanNumeralReservedOneHundred : 100,
		LatinSmallLetterReversedC      : 100,
		RomanNumeralSixLateForm        : 6,
		RomanNumeralFiftyEarlyForm     : 50,
		RomanNumeralFiftyThousand      : 50000,
		RomanNumeralOneHundredThousand : 100000,

		VulgarFractionZeroThirds : 0,

		TurnedDigitTwo   : 10,
		TurnedDigitThree : 11,

		HangzhouNumeralOne    : 1,
		HangzhouNumeralTwo    : 2,
		HangzhouNumeralThree  : 3,
		HangzhouNumeralFour   : 4,
		HangzhouNumeralFive   : 5,
		HangzhouNumeralSix    : 6,
		HangzhouNumeralSeven  : 7,
		HangzhouNumeralEight  : 8,
		HangzhouNumeralNine   : 9,

		HangzhouNumeralTen    : 10,
		HangzhouNumeralTwenty : 20,

		HangzhouNumeralThirty : 30,

		OldPersianNumberOne     : 1,
		OldPersianNumberTwo     : 2,
		OldPersianNumberTen     : 10,
		OldPersianNumberTwenty  : 20,
		OldPersianNumberHundred : 100,
	}
)

// Int64 tries to convert the numeric value that a rune represents to an
// int64.
//
// Note, of course, not all runes represent numeric values. In those cases
// Int64 returns an error of type NotNumericComplainer.
//
// Also, if the rune is numeric but cannot be represented as an int64,
// then Int64 returns an error of type NotInRangeComplainer.
func Int64(r rune) (int64, error) {
	if x, ok := runeToInt64LookupTable[r]; !ok {
		if !IsNumeric(r) {
			return 0, errNotNumeric
		} else {
			return 0, errNotInRange
		}
	} else {
		return x, nil
	}
}

<commit_msg>removed tiny bit of whitespace.<commit_after>package numeric

var (
	runeToInt64LookupTable = map[rune]int64{
		DigitZero  : 0,
		DigitOne   : 1,
		DigitTwo   : 2,
		DigitThree : 3,
		DigitFour  : 4,
		DigitFive  : 5,
		DigitSix   : 6,
		DigitSeven : 7,
		DigitEight : 8,
		DigitNine  : 9,

		ArabicIndicDigitZero  : 0,
		ArabicIndicDigitOne   : 1,
		ArabicIndicDigitTwo   : 2,
		ArabicIndicDigitThree : 3,
		ArabicIndicDigitFour  : 4,
		ArabicIndicDigitFive  : 5,
		ArabicIndicDigitSix   : 6,
		ArabicIndicDigitSeven : 7,
		ArabicIndicDigitEight : 8,
		ArabicIndicDigitNine  : 9,

		ExtendedArabicIndicDigitZero  : 0,
		ExtendedArabicIndicDigitOne   : 1,
		ExtendedArabicIndicDigitTwo   : 2,
		ExtendedArabicIndicDigitThree : 3,
		ExtendedArabicIndicDigitFour  : 4,
		ExtendedArabicIndicDigitFive  : 5,
		ExtendedArabicIndicDigitSix   : 6,
		ExtendedArabicIndicDigitSeven : 7,
		ExtendedArabicIndicDigitEight : 8,
		ExtendedArabicIndicDigitNine  : 9,

		SuperscriptZero  : 0,
		SuperscriptOne   : 1,
		SuperscriptTwo   : 2,
		SuperscriptThree : 3,
		SuperscriptFour  : 4,
		SuperscriptFive  : 5,
		SuperscriptSix   : 6,
		SuperscriptSeven : 7,
		SuperscriptEight : 8,
		SuperscriptNine  : 9,

		SubscriptZero  : 0,
		SubscriptOne   : 1,
		SubscriptTwo   : 2,
		SubscriptThree : 3,
		SubscriptFour  : 4,
		SubscriptFive  : 5,
		SubscriptSix   : 6,
		SubscriptSeven : 7,
		SubscriptEight : 8,
		SubscriptNine  : 9,

		FractionNumeratorOne : 0,

		RomanNumeralOne         : 1,
		RomanNumeralTwo         : 2,
		RomanNumeralThree       : 3,
		RomanNumeralFour        : 4,
		RomanNumeralFive        : 5,
		RomanNumeralSix         : 6,
		RomanNumeralSeven       : 7,
		RomanNumeralEight       : 8,
		RomanNumeralNine        : 9,
		RomanNumeralTen         : 10,
		RomanNumeralEleven      : 11,
		RomanNumeralTwelve      : 12,
		RomanNumeralFifty       : 50,
		RomanNumeralOneHundred  : 100,
		RomanNumeralFiveHundred : 500,
		RomanNumeralOneThousand : 1000,

		SmallRomanNumeralOne         : 1,
		SmallRomanNumeralTwo         : 2,
		SmallRomanNumeralThree       : 3,
		SmallRomanNumeralFour        : 4,
		SmallRomanNumeralFive        : 5,
		SmallRomanNumeralSix         : 6,
		SmallRomanNumeralSeven       : 7,
		SmallRomanNumeralEight       : 8,
		SmallRomanNumeralNine        : 9,
		SmallRomanNumeralTen         : 10,
		SmallRomanNumeralEleven      : 11,
		SmallRomanNumeralTwelve      : 12,
		SmallRomanNumeralFifty       : 50,
		SmallRomanNumeralOneHundred  : 100,
		SmallRomanNumeralFiveHundred : 500,
		SmallRomanNumeralOneThousand : 1000,

		RomanNumeralOneThousandCD      : 1000,
		RomanNumeralFiveThousand       : 5000,
		RomanNumeralTenThousand        : 10000,
		RomanNumeralReservedOneHundred : 100,
		LatinSmallLetterReversedC      : 100,
		RomanNumeralSixLateForm        : 6,
		RomanNumeralFiftyEarlyForm     : 50,
		RomanNumeralFiftyThousand      : 50000,
		RomanNumeralOneHundredThousand : 100000,

		VulgarFractionZeroThirds : 0,

		TurnedDigitTwo   : 10,
		TurnedDigitThree : 11,

		HangzhouNumeralOne    : 1,
		HangzhouNumeralTwo    : 2,
		HangzhouNumeralThree  : 3,
		HangzhouNumeralFour   : 4,
		HangzhouNumeralFive   : 5,
		HangzhouNumeralSix    : 6,
		HangzhouNumeralSeven  : 7,
		HangzhouNumeralEight  : 8,
		HangzhouNumeralNine   : 9,

		HangzhouNumeralTen    : 10,
		HangzhouNumeralTwenty : 20,

		HangzhouNumeralThirty : 30,

		OldPersianNumberOne     : 1,
		OldPersianNumberTwo     : 2,
		OldPersianNumberTen     : 10,
		OldPersianNumberTwenty  : 20,
		OldPersianNumberHundred : 100,
	}
)

// Int64 tries to convert the numeric value that a rune represents to an
// int64.
//
// Note, of course, not all runes represent numeric values. In those cases
// Int64 returns an error of type NotNumericComplainer.
//
// Also, if the rune is numeric but cannot be represented as an int64,
// then Int64 returns an error of type NotInRangeComplainer.
func Int64(r rune) (int64, error) {
	if x, ok := runeToInt64LookupTable[r]; !ok {
		if !IsNumeric(r) {
			return 0, errNotNumeric
		} else {
			return 0, errNotInRange
		}
	} else {
		return x, nil
	}
}
<|endoftext|>


<commit_before>package junos

import (
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/Juniper/go-netconf/netconf"
	"io/ioutil"
	"log"
)

// Session holds the connection information to our Junos device.
type Junos struct {
	*netconf.Session
}

// rollbackXML parses our rollback diff configuration.
type rollbackXML struct {
	XMLName xml.Name `xml:"rollback-information"`
	Config  string   `xml:"configuration-information>configuration-output"`
}

// CommandXML parses our operational command responses.
type commandXML struct {
	Config string `xml:",innerxml"`
}

type software struct {
	RES []routingEngine `xml:"multi-routing-engine-item"`
}

type routingEngine struct {
	Name    string `xml:"re-name"`
	Model   string `xml:"software-information>product-model"`
	Type    string `xml:"software-information>package-information>name"`
	Version string `xml:"software-information>package-information>comment"`
}

// NewSession establishes a new connection to a Junos device that we will use
// to run our commands against.
func NewSession(host, user, password string) *Junos {
	s, err := netconf.DialSSH(host, netconf.SSHConfigPassword(user, password))
	if err != nil {
		log.Fatal(err)
	}

	return &Junos{
		s,
	}
}

// Commit commits the configuration.
func (j *Junos) Commit() error {
	reply, err := j.Exec(rpcCommand["commit"])
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Lock locks the candidate configuration.
func (j *Junos) Lock() error {
	reply, err := j.Exec(rpcCommand["lock"])
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Unlock unlocks the candidate configuration.
func (j *Junos) Unlock() error {
	resp, err := j.Exec(rpcCommand["unlock"])
	if err != nil {
		log.Fatal(err)
	}

	if resp.Ok == false {
		for _, m := range resp.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Configure loads a given configuration file where the commands are
// in "set" format.
func (j *Junos) Configure(file string) error {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatal(err)
	}

	command := fmt.Sprintf(rpcCommand["configure-set"], string(data))
	reply, err := j.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// RollbackConfig loads and commits the configuration of a given rollback or rescue state.
func (j *Junos) RollbackConfig(option interface{}) error {
	var command string
	switch option.(type) {
	case int:
		command = fmt.Sprintf(rpcCommand["rollback-config"], option)
	case string:
		command = fmt.Sprintf(rpcCommand["rescue-config"])
	}

	reply, err := j.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	err = j.Commit()
	if err != nil {
		return err
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// RollbackDiff compares the current active configuration to a given rollback configuration.
func (j *Junos) RollbackDiff(compare int) (string, error) {
	rb := &rollbackXML{}
	command := fmt.Sprintf(rpcCommand["get-rollback-information-compare"], compare)
	reply, err := j.Exec(command)

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rb)
	if err != nil {
		log.Fatal(err)
	}

	return rb.Config, nil
}

// Command runs any operational mode command, such as "show" or "request."
// Format is either "text" or "xml".
func (j *Junos) Command(cmd, format string) (string, error) {
	c := &commandXML{}
	var command string

	switch format {
	case "xml":
		command = fmt.Sprintf(rpcCommand["command-xml"], cmd)
	default:
		command = fmt.Sprintf(rpcCommand["command"], cmd)
	}
	reply, err := j.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), &c)
	if err != nil {
		log.Fatal(err)
	}

	if c.Config == "" {
		return "No output available.", nil
	}

	return c.Config, nil
}

// Close disconnects our session to the device.
func (j *Junos) Close() {
	j.Transport.Close()
}

// Facts displays basic information about the device, such as software, hardware, etc.
func (j *Junos) Software() (*software, error) {
	data := &software{}
	reply, err := j.Exec(rpcCommand["software"])
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return nil, errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), &data)
	if err != nil {
		log.Fatal(err)
	}

	return data, nil
}
<commit_msg>Allow the ability to load different config file types/paths<commit_after>package junos

import (
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/Juniper/go-netconf/netconf"
	"io/ioutil"
	"log"
	"strings"
)

// Session holds the connection information to our Junos device.
type Junos struct {
	*netconf.Session
}

// rollbackXML parses our rollback diff configuration.
type rollbackXML struct {
	XMLName xml.Name `xml:"rollback-information"`
	Config  string   `xml:"configuration-information>configuration-output"`
}

// CommandXML parses our operational command responses.
type commandXML struct {
	Config string `xml:",innerxml"`
}

type software struct {
	RES []routingEngine `xml:"multi-routing-engine-item"`
}

type routingEngine struct {
	Name    string `xml:"re-name"`
	Model   string `xml:"software-information>product-model"`
	Type    string `xml:"software-information>package-information>name"`
	Version string `xml:"software-information>package-information>comment"`
}

// NewSession establishes a new connection to a Junos device that we will use
// to run our commands against.
func NewSession(host, user, password string) *Junos {
	s, err := netconf.DialSSH(host, netconf.SSHConfigPassword(user, password))
	if err != nil {
		log.Fatal(err)
	}

	return &Junos{
		s,
	}
}

// Commit commits the configuration.
func (j *Junos) Commit() error {
	reply, err := j.Exec(rpcCommand["commit"])
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Lock locks the candidate configuration.
func (j *Junos) Lock() error {
	reply, err := j.Exec(rpcCommand["lock"])
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Unlock unlocks the candidate configuration.
func (j *Junos) Unlock() error {
	resp, err := j.Exec(rpcCommand["unlock"])
	if err != nil {
		log.Fatal(err)
	}

	if resp.Ok == false {
		for _, m := range resp.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// LoadConfig loads a given configuration file locally or from
// an FTP or HTTP server. Format is either "set" or "text."
func (j *Junos) LoadConfig(path, format string) error {
	var command string
	switch format {
	case "set":
		if strings.Contains(path, "tp://") {
			command = fmt.Sprintf(rpcCommand["load-config-url-set"], path)
		} else {
			data, err := ioutil.ReadFile(path)
			if err != nil {
				log.Fatal(err)
			}

			command = fmt.Sprintf(rpcCommand["load-config-local-set"], string(data))
		}
	case "text":
		if strings.Contains(path, "tp://") {
			command = fmt.Sprintf(rpcCommand["load-config-url-text"], path)
		} else {
			data, err := ioutil.ReadFile(path)
			if err != nil {
				log.Fatal(err)
			}

			command = fmt.Sprintf(rpcCommand["load-config-local-text"], string(data))
		}
	case "xml":
		if strings.Contains(path, "tp://") {
			command = fmt.Sprintf(rpcCommand["load-config-url-xml"], path)
		} else {
			data, err := ioutil.ReadFile(path)
			if err != nil {
				log.Fatal(err)
			}

			command = fmt.Sprintf(rpcCommand["load-config-local-xml"], string(data))
		}
	}

	reply, err := j.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// RollbackConfig loads and commits the configuration of a given rollback or rescue state.
func (j *Junos) RollbackConfig(option interface{}) error {
	var command string
	switch option.(type) {
	case int:
		command = fmt.Sprintf(rpcCommand["rollback-config"], option)
	case string:
		command = fmt.Sprintf(rpcCommand["rescue-config"])
	}

	reply, err := j.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	err = j.Commit()
	if err != nil {
		return err
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// RollbackDiff compares the current active configuration to a given rollback configuration.
func (j *Junos) RollbackDiff(compare int) (string, error) {
	rb := &rollbackXML{}
	command := fmt.Sprintf(rpcCommand["get-rollback-information-compare"], compare)
	reply, err := j.Exec(command)

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rb)
	if err != nil {
		log.Fatal(err)
	}

	return rb.Config, nil
}

// Command runs any operational mode command, such as "show" or "request."
// Format is either "text" or "xml".
func (j *Junos) Command(cmd, format string) (string, error) {
	c := &commandXML{}
	var command string

	switch format {
	case "xml":
		command = fmt.Sprintf(rpcCommand["command-xml"], cmd)
	default:
		command = fmt.Sprintf(rpcCommand["command"], cmd)
	}
	reply, err := j.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), &c)
	if err != nil {
		log.Fatal(err)
	}

	if c.Config == "" {
		return "No output available.", nil
	}

	return c.Config, nil
}

// Close disconnects our session to the device.
func (j *Junos) Close() {
	j.Transport.Close()
}

// Facts displays basic information about the device, such as software, hardware, etc.
func (j *Junos) Software() (*software, error) {
	data := &software{}
	reply, err := j.Exec(rpcCommand["software"])
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return nil, errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), &data)
	if err != nil {
		log.Fatal(err)
	}

	return data, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"runtime"
	"reflect"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"encoding/json"
	"sync"
)

func Kinesis() *kinesis.Kinesis {
	return kinesis.New(session.New(), &aws.Config{Region: aws.String("eu-west-1")})
}

func getStreamNames() []*string {
	svc := Kinesis();
	hasMoreItems := true;
	var streamNames []*string;

	for hasMoreItems {
		resp, err := svc.ListStreams(nil)
		if err != nil {
			panic(err)
		}
		hasMoreItems = *resp.HasMoreStreams
		fmt.Println(reflect.TypeOf(resp.StreamNames))
		//fmt.Println(*resp.StreamNames[0])
		streamNames = append(streamNames, resp.StreamNames...)
	}
	return streamNames
}

func getStreamShards(StreamName string) []*kinesis.Shard {
	svc := Kinesis();
	var hasMoreShards bool = true;
	var exclusiveStartShardId string;
	var streamShards []*kinesis.Shard;

	for hasMoreShards {
		params := &kinesis.DescribeStreamInput{
			StreamName:            aws.String(StreamName),
			Limit: aws.Int64(10),
		}

		if exclusiveStartShardId != "" {
			params.ExclusiveStartShardId = aws.String(exclusiveStartShardId)
		}

		resp, err := svc.DescribeStream(params)
		if err != nil {
			panic(err)
		}

		shardsPage := resp.StreamDescription.Shards
		streamShards = append(streamShards, shardsPage...)

		exclusiveStartShardId = *shardsPage[len(shardsPage)-1].ShardId
		hasMoreShards = *resp.StreamDescription.HasMoreShards
	}
	return streamShards
}

func getShardIterator(streamName string, shard kinesis.Shard) string {
	svc := Kinesis();

	params := &kinesis.GetShardIteratorInput{
		ShardId: aws.String(*shard.ShardId),
		ShardIteratorType: aws.String("TRIM_HORIZON"),
		StreamName: aws.String(streamName),
	}

	resp, err := svc.GetShardIterator(params)
	if err != nil {
		panic(err)
	}

	return *resp.ShardIterator
}

func readShard(streamName string, streamShard kinesis.Shard, messageChannel chan kinesis.Record) {
	svc := Kinesis();
	shardIterator := getShardIterator(streamName, streamShard)

	for shardIterator != "" {
		//fmt.Println("Reading shard:", *streamShard.ShardId)

		params := &kinesis.GetRecordsInput{
			ShardIterator: aws.String(shardIterator),
			Limit:         aws.Int64(10),
		}
		resp, err := svc.GetRecords(params)
		if err != nil {
			panic(err)
		}

		for _, record  := range resp.Records {
			messageChannel <- *record
		}

		if resp.NextShardIterator != nil {
			shardIterator = *resp.NextShardIterator
		} else {
			shardIterator = ""
		}

		time.Sleep(time.Second)
	}

}

func printMessages(messageChannel chan kinesis.Record) {
	for {
		select {
		case record := <-messageChannel:
			var event interface{};
			json.Unmarshal(record.Data, &event)
			fmt.Println(event)
			//for k,v := range event.(map[string]interface {}) {
			//	fmt.Println(k," : ",v)
			//}
			//fmt.Println(event)
		}
	}
}

func readStream(streamName string) {
	streamShards := getStreamShards(streamName)

	messageChannel := make(chan kinesis.Record, 10)
	var waitGroup sync.WaitGroup

	for _, streamShard := range streamShards {

		waitGroup.Add(1)

		go func(shard kinesis.Shard) {
			defer waitGroup.Done()
			readShard(streamName, shard, messageChannel)
		}(*streamShard)
	}

	printMessages(messageChannel)
	waitGroup.Wait()
}

func main() {
	fmt.Println("Will use", runtime.NumCPU(), "cpu threads")
	runtime.GOMAXPROCS(runtime.NumCPU())

	readStream("logging-demo-log-stream-kinesisStream")
}
<commit_msg>implement cli<commit_after>package main

import (
	"os"
	"fmt"
	"time"
	"runtime"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/codegangsta/cli"
	"encoding/json"
	"sync"
)

func Kinesis() *kinesis.Kinesis {
	return kinesis.New(session.New(), &aws.Config{Region: aws.String("eu-west-1")})
}

func getStreamNames() []*string {
	svc := Kinesis();
	hasMoreItems := true;
	var streamNames []*string;

	for hasMoreItems {
		resp, err := svc.ListStreams(nil)
		if err != nil {
			panic(err)
		}
		hasMoreItems = *resp.HasMoreStreams
		streamNames = append(streamNames, resp.StreamNames...)
	}
	return streamNames
}

func getStreamShards(StreamName string) []*kinesis.Shard {
	svc := Kinesis();
	var hasMoreShards bool = true;
	var exclusiveStartShardId string;
	var streamShards []*kinesis.Shard;

	for hasMoreShards {
		params := &kinesis.DescribeStreamInput{
			StreamName:            aws.String(StreamName),
			Limit: aws.Int64(10),
		}

		if exclusiveStartShardId != "" {
			params.ExclusiveStartShardId = aws.String(exclusiveStartShardId)
		}

		resp, err := svc.DescribeStream(params)
		if err != nil {
			panic(err)
		}

		shardsPage := resp.StreamDescription.Shards
		streamShards = append(streamShards, shardsPage...)

		exclusiveStartShardId = *shardsPage[len(shardsPage)-1].ShardId
		hasMoreShards = *resp.StreamDescription.HasMoreShards
	}
	return streamShards
}

func getShardIterator(streamName string, shard kinesis.Shard) string {
	svc := Kinesis();

	params := &kinesis.GetShardIteratorInput{
		ShardId: aws.String(*shard.ShardId),
		ShardIteratorType: aws.String("TRIM_HORIZON"),
		StreamName: aws.String(streamName),
	}

	resp, err := svc.GetShardIterator(params)
	if err != nil {
		panic(err)
	}

	return *resp.ShardIterator
}

func readShard(streamName string, streamShard kinesis.Shard, messageChannel chan kinesis.Record) {
	svc := Kinesis();
	shardIterator := getShardIterator(streamName, streamShard)

	for shardIterator != "" {
		params := &kinesis.GetRecordsInput{
			ShardIterator: aws.String(shardIterator),
			Limit:         aws.Int64(1000),
		}
		resp, err := svc.GetRecords(params)
		if err != nil {
			panic(err)
		}

		for _, record := range resp.Records {
			messageChannel <- *record
		}

		if resp.NextShardIterator != nil {
			shardIterator = *resp.NextShardIterator
		} else {
			shardIterator = ""
		}

		time.Sleep(time.Second)
	}

}

func printRecords(messageChannel chan kinesis.Record, fields []string) {
	for {
		select {
		case record := <-messageChannel:
			var event interface{}
			json.Unmarshal(record.Data, &event)

			eventMap := event.(map[string]interface{})

			if len(fields) > 0 {
				for _, field := range fields {
					fmt.Print(eventMap[field])
					fmt.Print("  ")
				}
				fmt.Println()
			} else {
				fmt.Println(event)
			}
		}
	}
}

func readStream(streamName string, fields []string) {
	streamShards := getStreamShards(streamName)

	messageChannel := make(chan kinesis.Record, 100)
	var waitGroup sync.WaitGroup

	for _, streamShard := range streamShards {

		waitGroup.Add(1)
		go func(shard kinesis.Shard) {
			defer waitGroup.Done()
			readShard(streamName, shard, messageChannel)
		}(*streamShard)
	}

	printRecords(messageChannel, fields)
	waitGroup.Wait()
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	app := cli.NewApp()
	app.EnableBashCompletion = true
	app.Name = "ktail"
	app.Usage = "read json messages from AWS Kinesis streams"
	app.Flags = []cli.Flag{
		cli.StringSliceFlag{
			Name:            "field",
			Usage:            "define field to print instead of the complete message",
		},
	}
	app.Action = func(c *cli.Context) {
		if len(c.Args()) == 0 {
			for _, streamName := range getStreamNames() {
				fmt.Println(*streamName)
			}
		} else if len(c.Args()) > 0 {
			streamName := c.Args()[0]
			filterFields := c.StringSlice("field")

			readStream(streamName, filterFields)
		}
	}

	app.Run(os.Args)
}

<|endoftext|>


<commit_before>package golatch

import (
	"fmt"
	"net/url"
	t "time"
)

type Latch struct {
	AppID     string
	SecretKey string
	LatchAPI
}

//Constructs a new Latch struct
func NewLatch(appID string, secretKey string) *Latch {
	return &Latch{
		AppID:     appID,
		SecretKey: secretKey,
	}
}

//Pairs an account with the provided pairing token
func (l *Latch) Pair(token string) (response *LatchPairResponse, err error) {
	var resp *LatchResponse
	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_PAIR_ACTION, "/", token)), nil, nil, t.Now()), &LatchPairResponse{}); err == nil {
		response = (*resp).(*LatchPairResponse)
	}
	return response, err
}

//Unpairs an account, given it's account ID
func (l *Latch) Unpair(accountId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_UNPAIR_ACTION, "/", accountId)), nil, nil, t.Now()), nil)
	return err
}

//Locks an account, given it's account ID
func (l *Latch) Lock(accountId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_LOCK_ACTION, "/", accountId)), nil, nil, t.Now()), nil)
	return err
}

//Unlocks an account, given it's account ID
func (l *Latch) Unlock(accountId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_UNLOCK_ACTION, "/", accountId)), nil, nil, t.Now()), nil)
	return err
}

//Locks an operation, given it's account ID and oeration ID
func (l *Latch) LockOperation(accountId string, operationId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_LOCK_ACTION, "/", accountId, "/op/", operationId)), nil, nil, t.Now()), nil)
	return err
}

//Unlocks an operation, given it's account ID and oeration ID
func (l *Latch) UnlockOperation(accountId string, operationId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_UNLOCK_ACTION, "/", accountId, "/op/", operationId)), nil, nil, t.Now()), nil)
	return err
}

//Adds a new operation
func (l *Latch) AddOperation(parentId string, name string, twoFactor string, lockOnRequest string) (response *LatchAddOperationResponse, err error) {
	var resp *LatchResponse

	params := url.Values{}
	params.Set("parentId", parentId)
	params.Set("name", name)
	params.Set("two_factor", twoFactor)
	params.Set("lock_on_request", lockOnRequest)

	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_PUT, GetLatchURL(API_OPERATION_ACTION), nil, params, t.Now()), &LatchAddOperationResponse{}); err == nil {
		response = (*resp).(*LatchAddOperationResponse)
	}
	return response, err
}

//Updates an existing operation
func (l *Latch) UpdateOperation(operationId string, name string, twoFactor string, lockOnRequest string) (err error) {
	params := url.Values{}
	params.Set("name", name)
	if twoFactor != NOT_SET {
		params.Set("two_factor", twoFactor)
	}
	if lockOnRequest != NOT_SET {
		params.Set("lock_on_request", lockOnRequest)
	}

	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_POST, GetLatchURL(fmt.Sprint(API_OPERATION_ACTION, "/", operationId)), nil, params, t.Now()), nil)
	return err
}

//Deletes an existing operation
func (l *Latch) DeleteOperation(operationId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_DELETE, GetLatchURL(fmt.Sprint(API_OPERATION_ACTION, "/", operationId)), nil, nil, t.Now()), nil)
	return err
}

//Shows operations information
//If operationId is empty this function will retrieve all the operations of the app
func (l *Latch) ShowOperation(operationId string) (response *LatchShowOperationResponse, err error) {
	var resp *LatchResponse
	var operation string

	if operationId != "" {
		operation += "/" + operationId
	}

	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_OPERATION_ACTION, operation)), nil, nil, t.Now()), &LatchShowOperationResponse{}); err == nil {
		response = (*resp).(*LatchShowOperationResponse)
	}
	return response, err
}

//Gets the status of an account, given it's account ID
//If nootp is true, the one time password won't be included in the response
//If silent is true Latch will not send push notifications to the client (requires SILVER, GOLD or PLATINUM subscription)
func (l *Latch) Status(accountId string, nootp bool, silent bool) (response *LatchStatusResponse, err error) {
	query := fmt.Sprint(API_CHECK_STATUS_ACTION, "/", accountId)
	if nootp {
		query = fmt.Sprint(query, API_NOOTP_SUFFIX)
	}
	if silent {
		query = fmt.Sprint(query, API_SILENT_SUFFIX)
	}

	return l.StatusRequest(query)
}

//Gets the status of an operation, given it's account ID and operation ID
//If nootp is true, the one time password won't be included in the response
//If silent is true Latch will not send push notifications to the client (requires SILVER, GOLD or PLATINUM subscription)
func (l *Latch) OperationStatus(accountId string, operationId string, nootp bool, silent bool) (response *LatchStatusResponse, err error) {
	query := fmt.Sprint(API_CHECK_STATUS_ACTION, "/", accountId, "/op/", operationId)
	if nootp {
		query = fmt.Sprint(query, API_NOOTP_SUFFIX)
	}
	if silent {
		query = fmt.Sprint(query, API_SILENT_SUFFIX)
	}

	return l.StatusRequest(query)
}

//Performs a status request (application or operation) against the query URL provided
//Returns a LatchStatusResponse struct on success
func (l *Latch) StatusRequest(query string) (response *LatchStatusResponse, err error) {
	var resp *LatchResponse
	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(query), nil, nil, t.Now()), &LatchStatusResponse{}); err == nil {
		response = (*resp).(*LatchStatusResponse)
	}
	return response, err
}

//Gets the account's history between the from and to dates
func (l *Latch) History(accountId string, from t.Time, to t.Time) (response *LatchHistoryResponse, err error) {
	var resp *LatchResponse

	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprintf("%s/%s/%d/%d", API_HISTORY_ACTION, accountId, from.UnixNano()/1000000, to.UnixNano()/1000000)), nil, nil, t.Now()), &LatchHistoryResponse{AppID: l.AppID}); err == nil {
		response = (*resp).(*LatchHistoryResponse)
	}
	return response, err
}
<commit_msg>Modified the History() function to accept time zero values.<commit_after>package golatch

import (
	"fmt"
	"net/url"
	t "time"
)

type Latch struct {
	AppID     string
	SecretKey string
	LatchAPI
}

//Constructs a new Latch struct
func NewLatch(appID string, secretKey string) *Latch {
	return &Latch{
		AppID:     appID,
		SecretKey: secretKey,
	}
}

//Pairs an account with the provided pairing token
func (l *Latch) Pair(token string) (response *LatchPairResponse, err error) {
	var resp *LatchResponse
	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_PAIR_ACTION, "/", token)), nil, nil, t.Now()), &LatchPairResponse{}); err == nil {
		response = (*resp).(*LatchPairResponse)
	}
	return response, err
}

//Unpairs an account, given it's account ID
func (l *Latch) Unpair(accountId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_UNPAIR_ACTION, "/", accountId)), nil, nil, t.Now()), nil)
	return err
}

//Locks an account, given it's account ID
func (l *Latch) Lock(accountId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_LOCK_ACTION, "/", accountId)), nil, nil, t.Now()), nil)
	return err
}

//Unlocks an account, given it's account ID
func (l *Latch) Unlock(accountId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_UNLOCK_ACTION, "/", accountId)), nil, nil, t.Now()), nil)
	return err
}

//Locks an operation, given it's account ID and oeration ID
func (l *Latch) LockOperation(accountId string, operationId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_LOCK_ACTION, "/", accountId, "/op/", operationId)), nil, nil, t.Now()), nil)
	return err
}

//Unlocks an operation, given it's account ID and oeration ID
func (l *Latch) UnlockOperation(accountId string, operationId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_UNLOCK_ACTION, "/", accountId, "/op/", operationId)), nil, nil, t.Now()), nil)
	return err
}

//Adds a new operation
func (l *Latch) AddOperation(parentId string, name string, twoFactor string, lockOnRequest string) (response *LatchAddOperationResponse, err error) {
	var resp *LatchResponse

	params := url.Values{}
	params.Set("parentId", parentId)
	params.Set("name", name)
	params.Set("two_factor", twoFactor)
	params.Set("lock_on_request", lockOnRequest)

	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_PUT, GetLatchURL(API_OPERATION_ACTION), nil, params, t.Now()), &LatchAddOperationResponse{}); err == nil {
		response = (*resp).(*LatchAddOperationResponse)
	}
	return response, err
}

//Updates an existing operation
func (l *Latch) UpdateOperation(operationId string, name string, twoFactor string, lockOnRequest string) (err error) {
	params := url.Values{}
	params.Set("name", name)
	if twoFactor != NOT_SET {
		params.Set("two_factor", twoFactor)
	}
	if lockOnRequest != NOT_SET {
		params.Set("lock_on_request", lockOnRequest)
	}

	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_POST, GetLatchURL(fmt.Sprint(API_OPERATION_ACTION, "/", operationId)), nil, params, t.Now()), nil)
	return err
}

//Deletes an existing operation
func (l *Latch) DeleteOperation(operationId string) (err error) {
	_, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_DELETE, GetLatchURL(fmt.Sprint(API_OPERATION_ACTION, "/", operationId)), nil, nil, t.Now()), nil)
	return err
}

//Shows operations information
//If operationId is empty this function will retrieve all the operations of the app
func (l *Latch) ShowOperation(operationId string) (response *LatchShowOperationResponse, err error) {
	var resp *LatchResponse
	var operation string

	if operationId != "" {
		operation += "/" + operationId
	}

	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(fmt.Sprint(API_OPERATION_ACTION, operation)), nil, nil, t.Now()), &LatchShowOperationResponse{}); err == nil {
		response = (*resp).(*LatchShowOperationResponse)
	}
	return response, err
}

//Gets the status of an account, given it's account ID
//If nootp is true, the one time password won't be included in the response
//If silent is true Latch will not send push notifications to the client (requires SILVER, GOLD or PLATINUM subscription)
func (l *Latch) Status(accountId string, nootp bool, silent bool) (response *LatchStatusResponse, err error) {
	query := fmt.Sprint(API_CHECK_STATUS_ACTION, "/", accountId)
	if nootp {
		query = fmt.Sprint(query, API_NOOTP_SUFFIX)
	}
	if silent {
		query = fmt.Sprint(query, API_SILENT_SUFFIX)
	}

	return l.StatusRequest(query)
}

//Gets the status of an operation, given it's account ID and operation ID
//If nootp is true, the one time password won't be included in the response
//If silent is true Latch will not send push notifications to the client (requires SILVER, GOLD or PLATINUM subscription)
func (l *Latch) OperationStatus(accountId string, operationId string, nootp bool, silent bool) (response *LatchStatusResponse, err error) {
	query := fmt.Sprint(API_CHECK_STATUS_ACTION, "/", accountId, "/op/", operationId)
	if nootp {
		query = fmt.Sprint(query, API_NOOTP_SUFFIX)
	}
	if silent {
		query = fmt.Sprint(query, API_SILENT_SUFFIX)
	}

	return l.StatusRequest(query)
}

//Performs a status request (application or operation) against the query URL provided
//Returns a LatchStatusResponse struct on success
func (l *Latch) StatusRequest(query string) (response *LatchStatusResponse, err error) {
	var resp *LatchResponse
	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(query), nil, nil, t.Now()), &LatchStatusResponse{}); err == nil {
		response = (*resp).(*LatchStatusResponse)
	}
	return response, err
}

//Gets the account's history between the from and to dates
func (l *Latch) History(accountId string, from t.Time, to t.Time) (response *LatchHistoryResponse, err error) {
	var resp *LatchResponse

	query := fmt.Sprintf("%s/%s", API_HISTORY_ACTION, accountId)
	if !from.IsZero() || !to.IsZero() {
		if !from.IsZero() {
			query = fmt.Sprint(query, fmt.Sprintf("/%d", from.UnixNano()/1000000))
		} else {
			query = fmt.Sprint(query, fmt.Sprintf("/%d", 0))
		}
	}
	if !to.IsZero() {
		query = fmt.Sprint(query, fmt.Sprintf("/%d", to.UnixNano()/1000000))
	}
	fmt.Println(query)
	if resp, err = l.DoRequest(NewLatchRequest(l.AppID, l.SecretKey, HTTP_METHOD_GET, GetLatchURL(query), nil, nil, t.Now()), &LatchHistoryResponse{AppID: l.AppID}); err == nil {
		response = (*resp).(*LatchHistoryResponse)
	}
	return response, err
}
<|endoftext|>


<commit_before>package latex

import (
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/jojomi/go-script"
)

// CompileTask holds the configuration of a compilation
// task
type CompileTask struct {
	scriptContext   *script.Context
	sourceDir       string
	compileDir      string
	compileFilename string
	resolveSymlinks bool
}

// NewCompileTask returns a default (empty) CompileTask
func NewCompileTask() CompileTask {
	return CompileTask{}
}

func (t *CompileTask) context() *script.Context {
	// lazy initialize script context
	if t.scriptContext == nil {
		t.scriptContext = script.NewContext()
	}
	return t.scriptContext
}

// ResolveSymlinks determines if symlinks will be resolved
func (t *CompileTask) ResolveSymlinks() bool {
	return t.resolveSymlinks
}

// SetResolveSymlinks sets if symlinks will be resolved
func (t *CompileTask) SetResolveSymlinks(resolveSymlinks bool) {
	t.resolveSymlinks = resolveSymlinks
}

// SourceDir returns the source directory for compilation
func (t *CompileTask) SourceDir() string {
	return t.sourceDir
}

// SetSourceDir sets the source directory for compilation
func (t *CompileTask) SetSourceDir(sourceDir string) {
	t.sourceDir = sourceDir
}

// CompileFilename returns the filename to be compiled.
// Makes sure the filename is ending with .tex.
func (t *CompileTask) CompileFilename() string {
	filename := t.compileFilename
	if !strings.HasSuffix(filename, ".tex") {
		return filename + ".tex"
	}
	return filename
}

// CompileFilenamePdf returns the filename of the pdf file
// to be expected after a pdflatex run.
func (t *CompileTask) CompileFilenamePdf() string {
	filename := t.CompileFilename()
	return t.texFilenameToPdf(filename)
}

// SetCompileFilename sets the name of the TeX file to be compiled.
func (t *CompileTask) SetCompileFilename(compileFilename string) {
	t.compileFilename = compileFilename
}

// SetCompileDir sets the directory used for compilation. If no parameter is
// supplied a random and unique temporary directory is used for compilation.
// Usually this is the preferable mode of operation because it ensures clean
// building state.
func (t *CompileTask) SetCompileDir(CompileDir string) {
	if CompileDir == "" {
		CompileDir = t.context().MustGetTempDir()
	}
	t.compileDir = CompileDir

	t.context().SetWorkingDir(t.CompileDirInternal())
}

// CopyToCompileDir copies the source files to the compilation directory.
func (t *CompileTask) CopyToCompileDir(CompileDir string) {
	t.SetCompileDir(CompileDir)

	os.RemoveAll(CompileDir)
	os.MkdirAll(CompileDir, 0700)
	sc := t.context()
	err := sc.CopyDir(t.SourceDir(), t.CompileDirInternal())
	if err != nil {
		panic(err)
	}

	if t.ResolveSymlinks() {
		sc.ResolveSymlinks(t.CompileDirInternal())
	}
}

// ClearCompileDir removes the compilation directory. Suitable to call using
// defer after CopyToCompileDir. Be careful not to remove your source directory
// when building there.
func (t *CompileTask) ClearCompileDir() {
	err := os.RemoveAll(t.CompileDir())
	if err != nil {
		panic(err)
	}
}

func (t *CompileTask) defaultCompileFilename(filename string) (file string) {
	if file == "" {
		file = t.CompileFilename()
	}
	return
}

func (t *CompileTask) texFilenameToPdf(filename string) string {
	return filename[0:len(filename)-4] + ".pdf"
}

func (t *CompileTask) defaultCompilePdfFilename(filename string) (file string) {
	file = t.defaultCompileFilename(filename)
	// replace .tex by .pdf
	file = t.texFilenameToPdf(file)
	return
}

func (t *CompileTask) latextool(toolname, file string, args ...string) error {
	sc := t.context()
	file = t.defaultCompileFilename(file)
	args = append(args, file)

	//fmt.Println(sc.CommandPath("lualatex"))
	sc.MustCommandExist(toolname)
	err := sc.ExecuteSilent(toolname, args...)
	if err != nil {
		fmt.Print(sc.LastOutput().String())
		fmt.Print(sc.LastError().String())
		os.Exit(1)
	}
	// TODO error handling
	return nil
}

// Pdflatex calls pdflatex with the file and arguments supplied. For standard
// invokation no arguments are needed.
func (t *CompileTask) Pdflatex(file string, args ...string) error {
	return t.latextool("pdflatex", file, args...)
}

// Xelatex calls xelatex with the file and arguments supplied. For standard
// invokation no arguments are needed.
func (t *CompileTask) Xelatex(file string, args ...string) error {
	return t.latextool("xelatex", file, args...)
}

// Lualatex calls lualatex with the file and arguments supplied. For standard
// invokation no arguments are needed.
func (t *CompileTask) Lualatex(file string, args ...string) error {
	return t.latextool("lualatex", file, args...)
}

// LillypondBook calls lillypond-book.
func (t *CompileTask) LillypondBook(latexToolname, file string, args ...string) error {
	binName := "lilypond-book"
	sc := t.context()
	file = sc.AbsPath(t.defaultCompileFilename(file))
	tempDir := t.context().MustGetTempDir()
	args = append(args, "--pdf")
	args = append(args, fmt.Sprintf("--output=%s", tempDir))
	args = append(args, file)
	defer os.RemoveAll(tempDir)

	sc.MustCommandExist(binName)
	err := sc.ExecuteFullySilent(binName, args...)
	if err != nil {
		return err
	}

	matches, err := filepath.Glob(filepath.Join(tempDir, "*"))
	if err != nil {
		return err
	}
	for _, match := range matches {
		fi, err := os.Stat(match)
		if err != nil {
			return err
		}
		from := match
		to := path.Join(t.CompileDirInternal(), filepath.Base(match))
		//fmt.Println(from, to)
		if fi.IsDir() {
			err := sc.CopyDir(from, to)
			if err != nil {
				return err
			}
		} else {
			err := sc.CopyFile(from, to)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// Optimize modifies a given PDF to reduce filesize for a certain output type.
// Valid values for channel are "screen", "printer", "prepress", "ebook",
// "default".
func (t *CompileTask) Optimize(file string, channel string) error {
	// minify pdf: http://tex.stackexchange.com/a/41273
	// http://stackoverflow.com/a/27454451
	// http://blog.rot13.org/2011/05/optimize-pdf-file-size-using-ghostscript.html
	if !contains([]string{"screen", "printer", "prepress", "ebook", "default"}, channel) {
		// TODO err?
		return nil
	}

	sc := t.context()
	if !sc.CommandExists("gs") {
		return nil
	}

	file = t.defaultCompilePdfFilename(file)
	tempFile := sc.MustGetTempFile()
	params := []string{
		"-sDEVICE=pdfwrite",
		"-dCompatibilityLevel=1.4",
		fmt.Sprintf("-dPDFSETTINGS=/%s", channel),
		"-o",
		tempFile.Name(),
		file,
	}
	sc.SetWorkingDir(t.CompileDirInternal())
	err := sc.ExecuteSilent("gs", params...)
	if err != nil {
		return err
	}
	sc.MoveFile(tempFile.Name(), file)
	return nil
}

// MoveToDest moves a file from compilation directory.
func (t *CompileTask) MoveToDest(from, to string) error {
	from = t.defaultCompilePdfFilename(from)
	from = path.Join(t.CompileDirInternal(), from)
	to, err := filepath.Abs(to)
	if err != nil {
		panic(err)
	}
	return t.context().MoveFile(from, to)
}

// CompileDir returns the current compilation directory.
func (t *CompileTask) CompileDir() string {
	if t.compileDir == "" {
		return t.sourceDir
	}
	return t.compileDir
}

// CompileDirInternal returns the current internal compilation directory.
func (t *CompileTask) CompileDirInternal() string {
	if t.CompileDir() == t.SourceDir() {
		return t.CompileDir()
	}
	return path.Join(t.CompileDir(), "input")
}

// ClearLatexTempFiles removes common temprary LaTeX files in a directory.
func (t *CompileTask) ClearLatexTempFiles(dir string) {
	// remove temp files
	extensions := []string{"aux", "log", "toc", "nav", "ind", "ilg", "idx"}
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		for _, ext := range extensions {
			if strings.HasSuffix(path, "."+ext) {
				os.Remove(path)
				return nil
			}
		}
		return nil
	})
}

// Template returns a text/template to base templating off.
func (t *CompileTask) Template(baseFilename string) (*template.Template, string) {
	sc := t.context()
	baseFilename = sc.AbsPath(t.defaultCompileFilename(baseFilename))
	templ := template.New("latex")
	return templ, baseFilename
}

// ExecuteTemplate executes a template on the source TeX files.
func (t *CompileTask) ExecuteTemplate(templ *template.Template, data interface{}, inputFilename string, outputFilename string) {
	sc := t.context()

	useTempFile := outputFilename == ""
	if useTempFile {
		outputFilename = sc.MustGetTempFile().Name()
	}
	inputFilename = sc.AbsPath(t.defaultCompileFilename(inputFilename))

	f, err := os.Create(sc.AbsPath(outputFilename))
	if err != nil {
		panic(err)
	}
	w := io.Writer(f)
	err = templ.ExecuteTemplate(w, filepath.Base(inputFilename), data)
	if err != nil {
		panic(err)
	}
	f.Close()

	if useTempFile {
		// copy back, remove temp
		err = os.Remove(inputFilename)
		if err != nil {
			panic(err)
		}
		err = sc.CopyFile(outputFilename, inputFilename)
		if err != nil {
			panic(err)
		}
	}
}

// auxiliary
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<commit_msg>Implement SetVerbosity also adapat to current version of go-script<commit_after>package latex

import (
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/jojomi/go-script"
)

// CompileTask holds the configuration of a compilation
// task
type CompileTask struct {
	scriptContext   *script.Context
	sourceDir       string
	compileDir      string
	compileFilename string
	resolveSymlinks bool
	verbosity       VerbosityLevel
}

type VerbosityLevel uint

const (
	VerbosityNone = iota
	VerbosityDefault
	VerbosityMore
	VerbosityAll
)

// NewCompileTask returns a default (empty) CompileTask
func NewCompileTask() CompileTask {
	return CompileTask{
		verbosity: VerbosityDefault,
	}
}

func (t *CompileTask) context() *script.Context {
	// lazy initialize script context
	if t.scriptContext == nil {
		t.scriptContext = script.NewContext()
	}
	return t.scriptContext
}

// ResolveSymlinks determines if symlinks will be resolved
func (t *CompileTask) ResolveSymlinks() bool {
	return t.resolveSymlinks
}

// SetResolveSymlinks sets if symlinks will be resolved
func (t *CompileTask) SetResolveSymlinks(resolveSymlinks bool) {
	t.resolveSymlinks = resolveSymlinks
}

// SetVerbosity is used to change the verbosity level
func (t *CompileTask) SetVerbosity(verbosity VerbosityLevel) {
	t.verbosity = verbosity
}

// SourceDir returns the source directory for compilation
func (t *CompileTask) SourceDir() string {
	return t.sourceDir
}

// SetSourceDir sets the source directory for compilation
func (t *CompileTask) SetSourceDir(sourceDir string) {
	t.sourceDir = sourceDir
}

// CompileFilename returns the filename to be compiled.
// Makes sure the filename is ending with .tex.
func (t *CompileTask) CompileFilename() string {
	filename := t.compileFilename
	if !strings.HasSuffix(filename, ".tex") {
		return filename + ".tex"
	}
	return filename
}

// CompileFilenamePdf returns the filename of the pdf file
// to be expected after a pdflatex run.
func (t *CompileTask) CompileFilenamePdf() string {
	filename := t.CompileFilename()
	return t.texFilenameToPdf(filename)
}

// SetCompileFilename sets the name of the TeX file to be compiled.
func (t *CompileTask) SetCompileFilename(compileFilename string) {
	t.compileFilename = compileFilename
}

// SetCompileDir sets the directory used for compilation. If no parameter is
// supplied a random and unique temporary directory is used for compilation.
// Usually this is the preferable mode of operation because it ensures clean
// building state.
func (t *CompileTask) SetCompileDir(CompileDir string) {
	if CompileDir == "" {
		CompileDir = t.context().MustGetTempDir()
	}
	t.compileDir = CompileDir

	t.context().SetWorkingDir(t.CompileDirInternal())
}

// CopyToCompileDir copies the source files to the compilation directory.
func (t *CompileTask) CopyToCompileDir(CompileDir string) {
	t.SetCompileDir(CompileDir)

	os.RemoveAll(CompileDir)
	os.MkdirAll(CompileDir, 0700)
	sc := t.context()
	err := sc.CopyDir(t.SourceDir(), t.CompileDirInternal())
	if err != nil {
		panic(err)
	}

	if t.ResolveSymlinks() {
		sc.ResolveSymlinks(t.CompileDirInternal())
	}
}

// ClearCompileDir removes the compilation directory. Suitable to call using
// defer after CopyToCompileDir. Be careful not to remove your source directory
// when building there.
func (t *CompileTask) ClearCompileDir() {
	err := os.RemoveAll(t.CompileDir())
	if err != nil {
		panic(err)
	}
}

func (t *CompileTask) defaultCompileFilename(filename string) (file string) {
	if file == "" {
		file = t.CompileFilename()
	}
	return
}

func (t *CompileTask) texFilenameToPdf(filename string) string {
	return filename[0:len(filename)-4] + ".pdf"
}

func (t *CompileTask) defaultCompilePdfFilename(filename string) (file string) {
	file = t.defaultCompileFilename(filename)
	// replace .tex by .pdf
	file = t.texFilenameToPdf(file)
	return
}

func (t *CompileTask) latextool(toolname, file string, args ...string) error {
	sc := t.context()
	file = t.defaultCompileFilename(file)
	args = append(args, file)

	//fmt.Println(sc.CommandPath("lualatex"))
	sc.MustCommandExist(toolname)
	var execFunction func(string, ...string) error
	switch t.verbosity {
	case VerbosityNone:
		execFunction = sc.ExecuteFullySilent
	case VerbosityMore:
		fallthrough
	case VerbosityAll:
		execFunction = sc.ExecuteDebug
	case VerbosityDefault:
		fallthrough
	default:
		execFunction = sc.ExecuteSilent
	}
	err := execFunction(toolname, args...)
	if err != nil {
		fmt.Print(sc.LastOutput())
		fmt.Print(sc.LastError())
		os.Exit(1)
	}
	return nil
}

// Pdflatex calls pdflatex with the file and arguments supplied. For standard
// invokation no arguments are needed.
func (t *CompileTask) Pdflatex(file string, args ...string) error {
	return t.latextool("pdflatex", file, args...)
}

// Xelatex calls xelatex with the file and arguments supplied. For standard
// invokation no arguments are needed.
func (t *CompileTask) Xelatex(file string, args ...string) error {
	return t.latextool("xelatex", file, args...)
}

// Lualatex calls lualatex with the file and arguments supplied. For standard
// invokation no arguments are needed.
func (t *CompileTask) Lualatex(file string, args ...string) error {
	return t.latextool("lualatex", file, args...)
}

// LillypondBook calls lillypond-book.
func (t *CompileTask) LillypondBook(latexToolname, file string, args ...string) error {
	binName := "lilypond-book"
	sc := t.context()
	file = sc.AbsPath(t.defaultCompileFilename(file))
	tempDir := t.context().MustGetTempDir()
	args = append(args, "--pdf")
	args = append(args, fmt.Sprintf("--output=%s", tempDir))
	args = append(args, file)
	defer os.RemoveAll(tempDir)

	sc.MustCommandExist(binName)
	err := sc.ExecuteFullySilent(binName, args...)
	if err != nil {
		return err
	}

	matches, err := filepath.Glob(filepath.Join(tempDir, "*"))
	if err != nil {
		return err
	}
	for _, match := range matches {
		fi, err := os.Stat(match)
		if err != nil {
			return err
		}
		from := match
		to := path.Join(t.CompileDirInternal(), filepath.Base(match))
		//fmt.Println(from, to)
		if fi.IsDir() {
			err := sc.CopyDir(from, to)
			if err != nil {
				return err
			}
		} else {
			err := sc.CopyFile(from, to)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// Optimize modifies a given PDF to reduce filesize for a certain output type.
// Valid values for channel are "screen", "printer", "prepress", "ebook",
// "default".
func (t *CompileTask) Optimize(file string, channel string) error {
	// minify pdf: http://tex.stackexchange.com/a/41273
	// http://stackoverflow.com/a/27454451
	// http://blog.rot13.org/2011/05/optimize-pdf-file-size-using-ghostscript.html
	if !contains([]string{"screen", "printer", "prepress", "ebook", "default"}, channel) {
		// TODO err?
		return nil
	}

	sc := t.context()
	if !sc.CommandExists("gs") {
		return nil
	}

	file = t.defaultCompilePdfFilename(file)
	tempFile := sc.MustGetTempFile()
	params := []string{
		"-sDEVICE=pdfwrite",
		"-dCompatibilityLevel=1.4",
		fmt.Sprintf("-dPDFSETTINGS=/%s", channel),
		"-o",
		tempFile.Name(),
		file,
	}
	sc.SetWorkingDir(t.CompileDirInternal())
	err := sc.ExecuteSilent("gs", params...)
	if err != nil {
		return err
	}
	sc.MoveFile(tempFile.Name(), file)
	return nil
}

// MoveToDest moves a file from compilation directory.
func (t *CompileTask) MoveToDest(from, to string) error {
	from = t.defaultCompilePdfFilename(from)
	from = path.Join(t.CompileDirInternal(), from)
	to, err := filepath.Abs(to)
	if err != nil {
		panic(err)
	}
	return t.context().MoveFile(from, to)
}

// CompileDir returns the current compilation directory.
func (t *CompileTask) CompileDir() string {
	if t.compileDir == "" {
		return t.sourceDir
	}
	return t.compileDir
}

// CompileDirInternal returns the current internal compilation directory.
func (t *CompileTask) CompileDirInternal() string {
	if t.CompileDir() == t.SourceDir() {
		return t.CompileDir()
	}
	return path.Join(t.CompileDir(), "input")
}

// ClearLatexTempFiles removes common temprary LaTeX files in a directory.
func (t *CompileTask) ClearLatexTempFiles(dir string) {
	// remove temp files
	extensions := []string{"aux", "log", "toc", "nav", "ind", "ilg", "idx"}
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		for _, ext := range extensions {
			if strings.HasSuffix(path, "."+ext) {
				os.Remove(path)
				return nil
			}
		}
		return nil
	})
}

// Template returns a text/template to base templating off.
func (t *CompileTask) Template(baseFilename string) (*template.Template, string) {
	sc := t.context()
	baseFilename = sc.AbsPath(t.defaultCompileFilename(baseFilename))
	templ := template.New("latex")
	return templ, baseFilename
}

// ExecuteTemplate executes a template on the source TeX files.
func (t *CompileTask) ExecuteTemplate(templ *template.Template, data interface{}, inputFilename string, outputFilename string) {
	sc := t.context()

	useTempFile := outputFilename == ""
	if useTempFile {
		outputFilename = sc.MustGetTempFile().Name()
	}
	inputFilename = sc.AbsPath(t.defaultCompileFilename(inputFilename))

	f, err := os.Create(sc.AbsPath(outputFilename))
	if err != nil {
		panic(err)
	}
	w := io.Writer(f)
	err = templ.ExecuteTemplate(w, filepath.Base(inputFilename), data)
	if err != nil {
		panic(err)
	}
	f.Close()

	if useTempFile {
		// copy back, remove temp
		err = os.Remove(inputFilename)
		if err != nil {
			panic(err)
		}
		err = sc.CopyFile(outputFilename, inputFilename)
		if err != nil {
			panic(err)
		}
	}
}

// auxiliary
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"log"
	"os"
	"strings"

	"github.com/optiopay/kafka"
	"github.com/optiopay/kafka/proto"
)

const (
	topic     = "my-replicated-topic"
	partition = 0
)

var kafkaAddrs = []string{"localhost:9092", "localhost:9093", "localhost:9094"}

// printConsumed read messages from kafka and print them out
func printConsumed(broker kafka.Client) {
	conf := kafka.NewConsumerConf(topic, partition)
	conf.StartOffset = kafka.StartOffsetOldest
	consumer, err := broker.Consumer(conf)
	if err != nil {
		log.Fatalf("cannot create kafka consumer for %s:%d: %s", topic, partition, err)
	}

	for {
		msg, err := consumer.Consume()
		if err != nil {
			if err != kafka.ErrNoData {
				log.Printf("cannot consume %q topic message: %s", topic, err)
			}
			break
		}
		log.Printf("message %d: %s", msg.Offset, msg.Value)
	}
	log.Print("consumer quit")
}

// produceStdin read stdin and send every non empty line as message
func produceStdin(broker kafka.Client) {
	producer := broker.Producer(kafka.NewProducerConf())
	input := bufio.NewReader(os.Stdin)
	for {
		line, err := input.ReadString('\n')
		if err != nil {
			log.Fatalf("input error: %s", err)
		}
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		msg := &proto.Message{Value: []byte(line)}
		if _, err := producer.Produce(topic, partition, msg); err != nil {
			log.Fatalf("cannot produce message to %s:%d: %s", topic, partition, err)
		}
	}
}

func main() {
	// connect to kafka cluster
	broker, err := kafka.Dial(kafkaAddrs, kafka.NewBrokerConf("go-client"))
	if err != nil {
		log.Fatalf("cannot connect to kafka cluster: %s", err)
	}
	defer broker.Close()

	go printConsumed(broker)
	produceStdin(broker)
}
<commit_msg>update kafka.go kafka tester with much more docker awesome-sauce<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types"
	"github.com/optiopay/kafka"
	"github.com/optiopay/kafka/proto"
	"golang.org/x/net/context"
)

const (
	topic     = "test-topic"
	partition = 0
)

// printConsumed read messages from kafka and print them out
func printConsumed(broker kafka.Client) {
	conf := kafka.NewConsumerConf(topic, partition)
	conf.StartOffset = kafka.StartOffsetOldest
	consumer, err := broker.Consumer(conf)
	if err != nil {
		log.Fatalf("cannot create kafka consumer for %s:%d: %s", topic, partition, err)
	}

	for {
		msg, err := consumer.Consume()
		if err != nil {
			if err != kafka.ErrNoData {
				log.Printf("cannot consume %q topic message: %s", topic, err)
			}
			break
		}
		log.Printf("message %d: %s", msg.Offset, msg.Value)
	}
	log.Print("consumer quit")
}

// produceStdin read stdin and send every non empty line as message
func produceStdin(broker kafka.Client) {
	producer := broker.Producer(kafka.NewProducerConf())
	input := bufio.NewReader(os.Stdin)
	for {
		line, err := input.ReadString('\n')
		if err != nil {
			log.Fatalf("input error: %s", err)
		}
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		msg := &proto.Message{Value: []byte(line)}
		if _, err := producer.Produce(topic, partition, msg); err != nil {
			log.Fatalf("cannot produce message to %s:%d: %s", topic, partition, err)
		}
	}
}

func main() {
	cli, err := client.NewEnvClient()

	options := types.ContainerListOptions{All: true}
	containers, err := cli.ContainerList(context.Background(), options)
	if err != nil {
		log.Fatal(err)
	}
	kafkaAddrs := []string{}

	for _, container := range containers {
		if strings.Contains(container.Names[0], "kafka") {
			ports := container.Ports
			kafkaAddrs = append(kafkaAddrs, "192.168.99.100:"+strconv.Itoa(ports[0].PublicPort))
		}
	}

	fmt.Println("Kafka Hosts: ", kafkaAddrs)

	// connect to kafka cluster
	broker, err := kafka.Dial(kafkaAddrs, kafka.NewBrokerConf("go-client"))
	if err != nil {
		log.Fatalf("cannot connect to kafka cluster: %s", err)
	}
	defer broker.Close()

	go printConsumed(broker)
	produceStdin(broker)
}
<|endoftext|>