<commit_before>package auth

import (
	"bytes"
	"encoding/json"
	"github.com/guregu/kami"
	"github.com/the-information/ori/account"
	"github.com/the-information/ori/config"
	"github.com/the-information/ori/rest"
	"golang.org/x/net/context"
	"google.golang.org/appengine/log"
	"io/ioutil"
	"net/http"
)

var authKey = "__auth_ctx"

// Middleware sets up the request context so account information can be
// retrieved with auth.GetAccount(ctx). It panics if config.Get(ctx) fails.
func Middleware(ctx context.Context, w http.ResponseWriter, r *http.Request) context.Context {

	var conf config.Global
	if err := config.Get(ctx, &conf); err != nil {
		panic("Could not get AuthSecret: " + err.Error())
	}
	claimSet, err := Decode([]byte(r.Header.Get("Authorization")), []byte(conf.AuthSecret))
	if err != nil {
		return context.WithValue(ctx, authKey, err)
	} else if claimSet == SuperClaimSet {
		return context.WithValue(ctx, authKey, &account.Super)
	} else if claimSet == NobodyClaimSet {
		return context.WithValue(ctx, authKey, &account.Nobody)
	}

	var acct account.Account
	if err := account.Get(ctx, claimSet.Sub, &acct); err != nil {
		rest.WriteJSON(w, &rest.Error{
			Code:    http.StatusUnauthorized,
			Message: "Could not retrieve account with key " + claimSet.Sub + ": " + err.Error(),
		})
		return nil
	} else {
		return context.WithValue(ctx, authKey, &acct)
	}

}

var forbiddenMessage = "You do not have permission to access this resource."

type key int

// An AuthCheck is a handler-like function that determines whether a given HTTP request ought to be
// allowed to continue executing based on the request's authentication status. They can be
// used with Check to check credentials on a route without having to do so in the
// core HTTP handler for the route, which is very convenient.
type AuthCheck func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool

// Super is an AuthCheck that grants access to the superuser (that is, the user
// identified by `Authorization: <secret>`).
func Super(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

	var acct account.Account
	GetAccount(ctx, &acct)
	return acct.Super()

}

// HasRole returns an AuthCheck that grants access if `account.HasRole(role)` is true.
func HasRole(role string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

		var acct account.Account
		GetAccount(ctx, &acct)
		return acct.HasRole(role)

	}

}

// AccountMatchesParam returns an AuthCheck that grants access if paramName is the same
// as the account's ID; so, for instance, on a route to /accounts/:accountId, with
// a request to /accounts/asdf, the AuthCheck will return true if the account's ID is asdf.
func AccountMatchesParam(paramName string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

		var acct account.Account
		err := GetAccount(ctx, &acct)
		return err == nil && acct.Key() == kami.Param(ctx, paramName)

	}

}

// AccountOwnsObject returns an AuthCheck that reads the request body and grants
// access if the request body is an object that has the property `property` and its
// value is the same as the account's ID. So, for instance, on a request with a body shaped
// like `{"owner": "asdf"}`, AccountOwnsObject("owner") will return true if
// the authorized account's ID is `asdf`.
func AccountOwnsObject(property string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

		if r.Body == nil {
			return false
		}

		var acct account.Account
		err := GetAccount(ctx, &acct)
		if err != nil {
			return false
		} else if acct.Super() {
			return true
		}

		// buffer the http body so we can look at it
		buf := bytes.Buffer{}
		buf.ReadFrom(r.Body)

		r.Body = ioutil.NopCloser(&buf)
		data := buf.Bytes()

		props := make(map[string]interface{}, 8)

		if err := json.Unmarshal(data, props); err != nil {
			return false
		}

		val, ok := props[property]
		if !ok {
			return false
		}

		return val.(string) == acct.Key()
	}

}

// Checker is an object returned by auth.Check.
type Checker struct {
	checks []AuthCheck
}

// Check produces a Checker for a set of AuthChecks. If all of the AuthChecks
// fail, Checker.Then will return a 403 to the user and prevent the underlying
// handler from being called.
func Check(checks ...AuthCheck) *Checker {
	return &Checker{checks: checks}
}

// Then produces a kami.Handler that wraps another handler with authentication magic.
// If every AuthCheck associated with the Checker fails, Then will reject the HTTP request
// with a 403. If even one of them passes, Then will call h.
// This produces a very pleasant syntax for authenticating routes:
// 	func listAccounts(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//		w.Write([]byte("[]"))
//	}
//
// 	kami.Get("/accounts", auth.Check(auth.Super, auth.HasRole("admin")).Then(listAccounts))
func (c *Checker) Then(h kami.HandlerFunc) kami.HandlerFunc {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {

		var acct account.Account
		GetAccount(ctx, &acct)

		// run the checks
		passed := false
		for _, check := range c.checks {
			if check(ctx, w, r) {
				passed = true
			}
		}

		// did one of them pass?
		if passed {
			log.Infof(ctx, "%s: access granted", acct.Email)
			h(ctx, w, r)
		} else {

			log.Warningf(ctx, "%s: access denied", acct.Email)
			rest.WriteJSON(w, &rest.Error{
				Code:    http.StatusForbidden,
				Message: forbiddenMessage,
			})

		}

	}

}

// GetAccount retrieves the authorized account for ctx and copies it into account.
// It returns the error if one was encountered.
// Note that for special user types (account.Nobody and account.Super) both
// the returned key and error will be nil.
func GetAccount(ctx context.Context, acct *account.Account) error {

	switch t := ctx.Value(authKey).(type) {
	case error:
		return t
	case *account.Account:
		*acct = *t
		return nil
	default:
		panic("Type assertion failed, we should never get here")
	}

}
<commit_msg>removed a couple loose references to rest.Error<commit_after>package auth

import (
	"bytes"
	"encoding/json"
	"github.com/guregu/kami"
	"github.com/the-information/ori/account"
	"github.com/the-information/ori/config"
	"github.com/the-information/ori/rest"
	"golang.org/x/net/context"
	"google.golang.org/appengine/log"
	"io/ioutil"
	"net/http"
)

var authKey = "__auth_ctx"

// Middleware sets up the request context so account information can be
// retrieved with auth.GetAccount(ctx). It panics if config.Get(ctx) fails.
func Middleware(ctx context.Context, w http.ResponseWriter, r *http.Request) context.Context {

	var conf config.Global
	if err := config.Get(ctx, &conf); err != nil {
		panic("Could not get AuthSecret: " + err.Error())
	}
	claimSet, err := Decode([]byte(r.Header.Get("Authorization")), []byte(conf.AuthSecret))
	if err != nil {
		return context.WithValue(ctx, authKey, err)
	} else if claimSet == SuperClaimSet {
		return context.WithValue(ctx, authKey, &account.Super)
	} else if claimSet == NobodyClaimSet {
		return context.WithValue(ctx, authKey, &account.Nobody)
	}

	var acct account.Account
	if err := account.Get(ctx, claimSet.Sub, &acct); err != nil {
		rest.WriteJSON(w, &rest.Response{
			Code: http.StatusUnauthorized,
			Body: &rest.Message{"Could not retrieve account with key " + claimSet.Sub + ": " + err.Error()},
		})
		return nil
	} else {
		return context.WithValue(ctx, authKey, &acct)
	}

}

var forbiddenMessage = "You do not have permission to access this resource."

type key int

// An AuthCheck is a handler-like function that determines whether a given HTTP request ought to be
// allowed to continue executing based on the request's authentication status. They can be
// used with Check to check credentials on a route without having to do so in the
// core HTTP handler for the route, which is very convenient.
type AuthCheck func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool

// Super is an AuthCheck that grants access to the superuser (that is, the user
// identified by `Authorization: <secret>`).
func Super(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

	var acct account.Account
	GetAccount(ctx, &acct)
	return acct.Super()

}

// HasRole returns an AuthCheck that grants access if `account.HasRole(role)` is true.
func HasRole(role string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

		var acct account.Account
		GetAccount(ctx, &acct)
		return acct.HasRole(role)

	}

}

// AccountMatchesParam returns an AuthCheck that grants access if paramName is the same
// as the account's ID; so, for instance, on a route to /accounts/:accountId, with
// a request to /accounts/asdf, the AuthCheck will return true if the account's ID is asdf.
func AccountMatchesParam(paramName string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

		var acct account.Account
		err := GetAccount(ctx, &acct)
		return err == nil && acct.Key() == kami.Param(ctx, paramName)

	}

}

// AccountOwnsObject returns an AuthCheck that reads the request body and grants
// access if the request body is an object that has the property `property` and its
// value is the same as the account's ID. So, for instance, on a request with a body shaped
// like `{"owner": "asdf"}`, AccountOwnsObject("owner") will return true if
// the authorized account's ID is `asdf`.
func AccountOwnsObject(property string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) bool {

		if r.Body == nil {
			return false
		}

		var acct account.Account
		err := GetAccount(ctx, &acct)
		if err != nil {
			return false
		} else if acct.Super() {
			return true
		}

		// buffer the http body so we can look at it
		buf := bytes.Buffer{}
		buf.ReadFrom(r.Body)

		r.Body = ioutil.NopCloser(&buf)
		data := buf.Bytes()

		props := make(map[string]interface{}, 8)

		if err := json.Unmarshal(data, props); err != nil {
			return false
		}

		val, ok := props[property]
		if !ok {
			return false
		}

		return val.(string) == acct.Key()
	}

}

// Checker is an object returned by auth.Check.
type Checker struct {
	checks []AuthCheck
}

// Check produces a Checker for a set of AuthChecks. If all of the AuthChecks
// fail, Checker.Then will return a 403 to the user and prevent the underlying
// handler from being called.
func Check(checks ...AuthCheck) *Checker {
	return &Checker{checks: checks}
}

// Then produces a kami.Handler that wraps another handler with authentication magic.
// If every AuthCheck associated with the Checker fails, Then will reject the HTTP request
// with a 403. If even one of them passes, Then will call h.
// This produces a very pleasant syntax for authenticating routes:
// 	func listAccounts(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//		w.Write([]byte("[]"))
//	}
//
// 	kami.Get("/accounts", auth.Check(auth.Super, auth.HasRole("admin")).Then(listAccounts))
func (c *Checker) Then(h kami.HandlerFunc) kami.HandlerFunc {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {

		var acct account.Account
		GetAccount(ctx, &acct)

		// run the checks
		passed := false
		for _, check := range c.checks {
			if check(ctx, w, r) {
				passed = true
			}
		}

		// did one of them pass?
		if passed {
			log.Infof(ctx, "%s: access granted", acct.Email)
			h(ctx, w, r)
		} else {

			log.Warningf(ctx, "%s: access denied", acct.Email)
			rest.WriteJSON(w, &rest.Response{
				Code: http.StatusForbidden,
				Body: &rest.Message{forbiddenMessage},
			})

		}

	}

}

// GetAccount retrieves the authorized account for ctx and copies it into account.
// It returns the error if one was encountered.
// Note that for special user types (account.Nobody and account.Super) both
// the returned key and error will be nil.
func GetAccount(ctx context.Context, acct *account.Account) error {

	switch t := ctx.Value(authKey).(type) {
	case error:
		return t
	case *account.Account:
		*acct = *t
		return nil
	default:
		panic("Type assertion failed, we should never get here")
	}

}
<|endoftext|>


<commit_before>package rtnetlink

import "bytes"
import "netlink"
import "os"

type Message struct {
  Header Header
  Attributes []netlink.Attribute
}

func NewMessage(h Header, attrs []netlink.Attribute)(*Message){
  return &Message{Header:h, Attributes: attrs}
}

func (self Message)MarshalNetlink(pad int)(out []byte, err os.Error){
  buff := bytes.NewBuffer(nil)
  bb, err := self.Header.MarshalNetlink(pad)
  if err == nil {
    buff.Write(bb)
    bb, err = netlink.MarshalAttributes(self.Attributes, pad)
    if err == nil {
      buff.Write(bb)
    }
  }
  out = netlink.PadBytes(buff.Bytes(), pad)
  return
}

func (self *Message)UnmarshalNetlink(in []byte, pad int)(err os.Error){
  if len(in) < self.Header.Len() {
    return os.NewError("Insufficient data for unmarshal of Header")
  }
  err = self.Header.UnmarshalNetlink(in[0:self.Header.Len()], pad)
  if err == nil {
    pos := netlink.Reposition(self.Header.Len(), pad)
    if len(in) > pos {
      self.Attributes, err = netlink.UnmarshalAttributes(in[pos:], pad)
    }
  }
  return
}
<commit_msg>add Get/Set attribute helpers<commit_after>package rtnetlink

import "bytes"
import "netlink"
import "os"

type Message struct {
  Header Header
  Attributes []netlink.Attribute
}

func NewMessage(h Header, attrs []netlink.Attribute)(*Message){
  return &Message{Header:h, Attributes: attrs}
}

func (self *Message)SetAttribute(attr netlink.Attribute){
  t := attr.AttributeType()
  for i := range(self.Attributes){
    if t == self.Attributes[i].AttributeType() {
      self.Attributes[i] = attr
      return
    }
  }
  self.Attributes = append(self.Attributes, attr)
  return
}

func (self Message)GetAttribute(t netlink.AttributeType)(attr netlink.Attribute, err os.Error){
  for i := range(self.Attributes){
    if t == self.Attributes[i].AttributeType() {
      attr = self.Attributes[i]
      return
    }
  }
  err = os.NewError("Attribute not found")
  return
}

func (self Message)MarshalNetlink(pad int)(out []byte, err os.Error){
  buff := bytes.NewBuffer(nil)
  bb, err := self.Header.MarshalNetlink(pad)
  if err == nil {
    buff.Write(bb)
    bb, err = netlink.MarshalAttributes(self.Attributes, pad)
    if err == nil {
      buff.Write(bb)
    }
  }
  out = netlink.PadBytes(buff.Bytes(), pad)
  return
}

func (self *Message)UnmarshalNetlink(in []byte, pad int)(err os.Error){
  if len(in) < self.Header.Len() {
    return os.NewError("Insufficient data for unmarshal of Header")
  }
  err = self.Header.UnmarshalNetlink(in[0:self.Header.Len()], pad)
  if err == nil {
    pos := netlink.Reposition(self.Header.Len(), pad)
    if len(in) > pos {
      self.Attributes, err = netlink.UnmarshalAttributes(in[pos:], pad)
    }
  }
  return
}
<|endoftext|>


<commit_before>// generated by stringer -type=Type; DO NOT EDIT

package eval

import "fmt"

const _Type_name = "invalidTypestringTypeexitusTypeboolTypetableTypecallableTyperatType"

var _Type_index = [...]uint8{0, 11, 21, 31, 39, 48, 60, 67}

func (i Type) String() string {
	if i < 0 || i+1 >= Type(len(_Type_index)) {
		return fmt.Sprintf("Type(%d)", i)
	}
	return _Type_name[_Type_index[i]:_Type_index[i+1]]
}
<commit_msg>Regenerate eval/type_string.go.<commit_after>// generated by stringer -type=Type; DO NOT EDIT

package eval

import "fmt"

const _Type_name = "TInvalidTStringTErrorTBoolTListTMapTFnTRat"

var _Type_index = [...]uint8{0, 8, 15, 21, 26, 31, 35, 38, 42}

func (i Type) String() string {
	if i < 0 || i+1 >= Type(len(_Type_index)) {
		return fmt.Sprintf("Type(%d)", i)
	}
	return _Type_name[_Type_index[i]:_Type_index[i+1]]
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/zfjagann/golang-ring"
	"net/http"
	"sync"
)

type Api struct {
	Config   *config.Protocol
	Remote   chan config.Message
	Account  string
	Messages ring.Ring
	sync.RWMutex
}

type ApiMessage struct {
	Text     string `json:"text"`
	Username string `json:"username"`
	UserID   string `json:"userid"`
	Avatar   string `json:"avatar"`
	Gateway  string `json:"gateway"`
}

var flog *log.Entry
var protocol = "api"

func init() {
	flog = log.WithFields(log.Fields{"module": protocol})
}

func New(cfg config.Protocol, account string, c chan config.Message) *Api {
	b := &Api{}
	e := echo.New()
	b.Messages = ring.Ring{}
	b.Messages.SetCapacity(cfg.Buffer)
	b.Config = &cfg
	b.Account = account
	b.Remote = c
	if b.Config.Token != "" {
		e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
			return key == b.Config.Token, nil
		}))
	}
	e.GET("/api/messages", b.handleMessages)
	e.POST("/api/message", b.handlePostMessage)
	go func() {
		flog.Fatal(e.Start(cfg.BindAddress))
	}()
	return b
}

func (b *Api) Connect() error {
	return nil
}
func (b *Api) Disconnect() error {
	return nil

}
func (b *Api) JoinChannel(channel config.ChannelInfo) error {
	return nil

}

func (b *Api) Send(msg config.Message) (string, error) {
	b.Lock()
	defer b.Unlock()
	// ignore delete messages
	if msg.Event == config.EVENT_MSG_DELETE {
		return "", nil
	}
	b.Messages.Enqueue(&msg)
	return "", nil
}

func (b *Api) handlePostMessage(c echo.Context) error {
	message := &ApiMessage{}
	if err := c.Bind(message); err != nil {
		return err
	}
	flog.Debugf("Sending message from %s on %s to gateway", message.Username, "api")
	b.Remote <- config.Message{
		Text:     message.Text,
		Username: message.Username,
		UserID:   message.UserID,
		Channel:  "api",
		Avatar:   message.Avatar,
		Account:  b.Account,
		Gateway:  message.Gateway,
		Protocol: "api",
	}
	return c.JSON(http.StatusOK, message)
}

func (b *Api) handleMessages(c echo.Context) error {
	b.Lock()
	defer b.Unlock()
	c.JSONPretty(http.StatusOK, b.Messages.Values(), " ")
	b.Messages = ring.Ring{}
	return nil
}
<commit_msg>Add (simple, one listener) long-polling support (api). Closes #307<commit_after>package api

import (
	"encoding/json"
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/zfjagann/golang-ring"
	"net/http"
	"sync"
	"time"
)

type Api struct {
	Config   *config.Protocol
	Remote   chan config.Message
	Account  string
	Messages ring.Ring
	sync.RWMutex
}

type ApiMessage struct {
	Text     string `json:"text"`
	Username string `json:"username"`
	UserID   string `json:"userid"`
	Avatar   string `json:"avatar"`
	Gateway  string `json:"gateway"`
}

var flog *log.Entry
var protocol = "api"

func init() {
	flog = log.WithFields(log.Fields{"module": protocol})
}

func New(cfg config.Protocol, account string, c chan config.Message) *Api {
	b := &Api{}
	e := echo.New()
	b.Messages = ring.Ring{}
	b.Messages.SetCapacity(cfg.Buffer)
	b.Config = &cfg
	b.Account = account
	b.Remote = c
	if b.Config.Token != "" {
		e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
			return key == b.Config.Token, nil
		}))
	}
	e.GET("/api/messages", b.handleMessages)
	e.GET("/api/stream", b.handleStream)
	e.POST("/api/message", b.handlePostMessage)
	go func() {
		flog.Fatal(e.Start(cfg.BindAddress))
	}()
	return b
}

func (b *Api) Connect() error {
	return nil
}
func (b *Api) Disconnect() error {
	return nil

}
func (b *Api) JoinChannel(channel config.ChannelInfo) error {
	return nil

}

func (b *Api) Send(msg config.Message) (string, error) {
	b.Lock()
	defer b.Unlock()
	// ignore delete messages
	if msg.Event == config.EVENT_MSG_DELETE {
		return "", nil
	}
	b.Messages.Enqueue(&msg)
	return "", nil
}

func (b *Api) handlePostMessage(c echo.Context) error {
	message := &ApiMessage{}
	if err := c.Bind(message); err != nil {
		return err
	}
	flog.Debugf("Sending message from %s on %s to gateway", message.Username, "api")
	b.Remote <- config.Message{
		Text:     message.Text,
		Username: message.Username,
		UserID:   message.UserID,
		Channel:  "api",
		Avatar:   message.Avatar,
		Account:  b.Account,
		Gateway:  message.Gateway,
		Protocol: "api",
	}
	return c.JSON(http.StatusOK, message)
}

func (b *Api) handleMessages(c echo.Context) error {
	b.Lock()
	defer b.Unlock()
	c.JSONPretty(http.StatusOK, b.Messages.Values(), " ")
	b.Messages = ring.Ring{}
	return nil
}

func (b *Api) handleStream(c echo.Context) error {
	c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
	c.Response().WriteHeader(http.StatusOK)
	closeNotifier := c.Response().CloseNotify()
	for {
		select {
		case <-closeNotifier:
			return nil
		default:
			msg := b.Messages.Dequeue()
			if msg != nil {
				if err := json.NewEncoder(c.Response()).Encode(msg); err != nil {
					return err
				}
				c.Response().Flush()
			}
			time.Sleep(200 * time.Millisecond)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"math/rand"
	"sync"
	"time"

	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

func main() {
	p := mpb.New(mpb.PopCompletedMode())

	total, numBars := 100, 2
	for i := 0; i < numBars; i++ {
		name := fmt.Sprintf("Bar#%d:", i)
		bar := p.AddBar(int64(total),
			mpb.BarNoPop(),
			mpb.PrependDecorators(
				decor.Name(name),
				decor.Percentage(decor.WCSyncSpace),
			),
			mpb.AppendDecorators(
				decor.OnComplete(
					decor.EwmaETA(decor.ET_STYLE_GO, 60), "done!",
				),
			),
		)
		// simulating some work
		go func() {
			rng := rand.New(rand.NewSource(time.Now().UnixNano()))
			max := 100 * time.Millisecond
			for i := 0; i < total; i++ {
				// start variable is solely for EWMA calculation
				// EWMA's unit of measure is an iteration's duration
				start := time.Now()
				time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
				bar.Increment()
				// we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract
				bar.DecoratorEwmaUpdate(time.Since(start))
			}
		}()
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		rng := rand.New(rand.NewSource(time.Now().UnixNano()))
		max := 3000 * time.Millisecond
		for i := 0; i < 10; i++ {
			filler := makeLogBar(fmt.Sprintf("some log: %d", i))
			p.Add(0, filler).SetTotal(0, true)
			time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
		}
	}()

	wg.Wait()
	p.Wait()
}

func makeLogBar(msg string) mpb.BarFiller {
	limit := "%%.%ds"
	return mpb.BarFillerFunc(func(w io.Writer, _ int, st decor.Statistics) {
		fmt.Fprintf(w, fmt.Sprintf(limit, st.AvailableWidth), msg)
	})
}
<commit_msg>simplify poplog example<commit_after>package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

func main() {
	p := mpb.New(mpb.PopCompletedMode())

	total, numBars := 100, 4
	for i := 0; i < numBars; i++ {
		name := fmt.Sprintf("Bar#%d:", i)
		bar := p.AddBar(int64(total),
			mpb.BarFillerOnComplete(fmt.Sprintf("%s has been completed", name)),
			mpb.BarFillerTrim(),
			mpb.PrependDecorators(
				decor.OnComplete(decor.Name(name), ""),
				decor.OnComplete(decor.NewPercentage(" % d "), ""),
			),
			mpb.AppendDecorators(
				decor.OnComplete(decor.Name(" "), ""),
				decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), ""),
			),
		)
		// simulating some work
		rng := rand.New(rand.NewSource(time.Now().UnixNano()))
		max := 100 * time.Millisecond
		for i := 0; i < total; i++ {
			// start variable is solely for EWMA calculation
			// EWMA's unit of measure is an iteration's duration
			start := time.Now()
			time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
			bar.Increment()
			// we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract
			bar.DecoratorEwmaUpdate(time.Since(start))
		}
	}

	p.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"log"
	"net/url"
	"os"
	"strings"
)

var (
	EuropeEcAsics = []string{"http://www.asics.com/gb/en-gb", "http://www.asics.com/fr/fr-fr", "http://www.asics.com/es/es-es", "http://www.asics.com/it/it-it"}

	NoEcAsics = []string{"https://www.asics.co.za/", "https://www.asics.pl", "https://de.asics.ch"}
)

type ParseData struct {
	Locale string
	Header []Link
	Footer []Link
}

type Link struct {
	Title   string
	Url     string
	Name    string
	Index   int
	Img     string `json:"Img,omitempty"`
	ImgSize string `json:"ImgSize,omitempty"`
	//the value of imgsize represent the type of the image, small | medium | big
	SingleRow bool
	//when the value of SingleRow is false, there will have two link in a row.
	Items []interface{}
}

type ItemLink struct {
	Title   string
	Url     string
	Name    string
	Index   int
	Img     string `json:"Img,omitempty"`
	ImgSize string `json:"ImgSize,omitempty"`
}

func ParseECHtml(url_string string) {

	target_url, _ := url.Parse(url_string)
	doc, err := goquery.NewDocument(url_string)
	if err != nil {
		log.Fatal(err)
	}

	parsedata := ParseData{
		Locale: strings.Split(target_url.Path, "/")[2],
	}

	//parse the header
	doc.Find("#main-menu").Children().Not(".mobile").Not("div").Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().Filter("h4").First().AttrOr("title", ""),
			Url:       target_url.Scheme + "://" + target_url.Host + s.Children().First().AttrOr("href", "#"),
			Name:      s.Children().Filter("h4").First().Text(),
			Index:     i + 1,
			SingleRow: true,
		}

		s.Find("ul").Each(func(i int, s *goquery.Selection) {
			if s.Children().Size() == 2 {

				firstlink := Link{
					Title:     s.Find("h5").First().AttrOr("title", ""),
					Url:       "#",
					Name:      s.Find("h5").First().Text(),
					Index:     i + 1,
					SingleRow: true,
				}

				secondlink := Link{
					Title:     s.Find("span").First().AttrOr("title", ""),
					Url:       "#",
					Name:      s.Find("span").First().Text(),
					Index:     i + 1,
					SingleRow: true,
				}

				is_first := true
				s.Find(".yCmsComponent").Each(func(i int, s *goquery.Selection) {
					if s.Children().First().Is("span") {
						is_first = false

					} else {
						itemlink := ItemLink{
							Title: s.Children().First().AttrOr("title", ""),
							Name:  s.Children().First().Text(),
							Url:   target_url.Scheme + "://" + target_url.Host + s.Children().First().AttrOr("href", "#"),
							Index: i + 1,
						}
						if s.Children().First().Children().First().Is("img") {
							itemlink.Img = s.Children().First().Children().First().AttrOr("src", "#")
						}

						if is_first {
							firstlink.Items = append(firstlink.Items, itemlink)
						} else {
							secondlink.Items = append(secondlink.Items, itemlink)

						}
					}
				})
				link.Items = append(link.Items, firstlink)
				link.Items = append(link.Items, secondlink)

			} else {

				firstlink := Link{
					Title:     s.Find("h5").First().AttrOr("title", ""),
					Url:       "#",
					Name:      s.Find("h5").First().Text(),
					Index:     i + 1,
					SingleRow: true,
				}
				s.Find(".yCmsComponent").Each(func(i int, s *goquery.Selection) {

					itemlink := ItemLink{
						Title: s.Children().First().AttrOr("title", ""),
						Name:  s.Children().First().Text(),
						Url:   target_url.Scheme + "://" + target_url.Host + s.Children().First().AttrOr("href", "#"),
						Index: i + 1,
					}
					if s.Children().First().Children().First().Is("img") {
						itemlink.Img = s.Children().First().Children().First().AttrOr("src", "#")
					}

					firstlink.Items = append(firstlink.Items, itemlink)

				})
				link.Items = append(link.Items, firstlink)
			}
		})
		parsedata.Header = append(parsedata.Header, link)
	})

	//parse the footer
	doc.Find("footer").Children().Filter(".tiger-clearfix-toggle").Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title: s.Children().Filter("h4").First().AttrOr("title", ""),
			Url:   "#",
			Name:  s.Children().Filter("h4").First().Text(),
			Index: i + 1,
		}

		s.Children().Filter("ul").Children().Each(func(i int, s *goquery.Selection) {
			itemlink := ItemLink{
				Title: s.Children().First().AttrOr("title", ""),
				Name:  s.Children().First().Text(),
				Url:   target_url.Scheme + "://" + target_url.Host + s.Children().First().AttrOr("href", "#"),
				Index: i + 1,
			}
			link.Items = append(link.Items, itemlink)
		})
		parsedata.Footer = append(parsedata.Footer, link)
	})

	jsondata, _ := json.Marshal(parsedata)

	file, _ := os.OpenFile(strings.Split(target_url.Path, "/")[2]+".json", os.O_WRONLY|os.O_CREATE, 0666)
	file.Write(jsondata)

	fmt.Println(string(jsondata))

}

func ParseNoECHtml(url_string string) {

	target_url, _ := url.Parse(url_string)
	doc, err := goquery.NewDocument(url_string)
	if err != nil {
		log.Fatal(err)
	}

	locale := strings.Split(target_url.Host, ".")[0] + "-" + strings.Split(target_url.Host, ".")[2]
	parsedata := ParseData{
		Locale: locale,
	}

	//parse the header
	doc.Find("header #asicsAreas").Children().Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().First().AttrOr("title", ""),
			Name:      s.Children().First().Children().First().Text(),
			SingleRow: true,
			Url:       "#",
			Index:     i + 1,
		}
		if i != 3 {
			doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsListing").Each(func(ii int, ss *goquery.Selection) {
				secend_link := Link{
					Title:     doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().End().AttrOr("title", ""),
					Name:      strings.TrimSpace(doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().End().Text()),
					Url:       doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().End().AttrOr("href", "#"),
					Img:       doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().First().Children().First().AttrOr("src", "#"),
					ImgSize:   "small",
					Index:     i + 1,
					SingleRow: true,
				}
				ss.Children().Filter("ul").Children().Each(func(iii int, s *goquery.Selection) {
					itemlink := ItemLink{
						Title: s.Children().First().AttrOr("title", ""),
						Url:   s.Children().First().AttrOr("href", "#"),
						Name:  s.Children().First().Text(),
						Index: iii + 1,
					}

					secend_link.Items = append(secend_link.Items, itemlink)
				})

				link.Items = append(link.Items, secend_link)

			})

		}

		parsedata.Header = append(parsedata.Header, link)
	})

	//parse the footer
	doc.Find(".footer #tertiary section").Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().First().AttrOr("title", ""),
			Name:      s.Children().First().Text(),
			Url:       "#",
			Index:     i + 1,
			SingleRow: true,
		}

		s.Children().Filter("ul").Children().Each(func(i int, s *goquery.Selection) {
			itemlink := ItemLink{
				Title: s.Children().First().AttrOr("title", ""),
				Url:   s.Children().First().AttrOr("href", "#"),
				Name:  s.Children().First().Text(),
				Index: i + 1,
			}
			link.Items = append(link.Items, itemlink)
		})
		parsedata.Footer = append(parsedata.Footer, link)
	})

	jsondata, _ := json.Marshal(parsedata)

	file, _ := os.OpenFile(locale, os.O_WRONLY|os.O_CREATE, 0666)
	file.Write(jsondata)

	fmt.Println(string(jsondata))

}

func main() {
	for _, url := range EuropeEcAsics {
		ParseECHtml(url)
	}
	for _, url := range NoEcAsics {
		ParseNoECHtml(url)
	}

	// ParseECHtml("http://www.asics.com/gb/en-gb")
	// ParseNoECHtml("https://www.asics.co.za/")

}
<commit_msg>adjust the url of img and the link dependen on the current url<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"log"
	"net/url"
	"os"
	"regexp"
	"strings"
)

var (
	EuropeEcAsics = []string{"http://www.asics.com/gb/en-gb", "http://www.asics.com/fr/fr-fr", "http://www.asics.com/es/es-es", "http://www.asics.com/it/it-it"}
	NoEcAsics     = []string{"https://www.asics.co.za/", "https://www.asics.pl", "https://de.asics.ch"}
)

type ParseData struct {
	Locale string
	Header []Link
	Footer []Link
}

type Link struct {
	Title   string
	Url     string
	Name    string
	Index   int
	Img     string `json:"Img,omitempty"`
	ImgSize string `json:"ImgSize,omitempty"`
	//the value of imgsize represent the type of the image, small | medium | big
	SingleRow bool
	//when the value of SingleRow is false, there will have two link in a row.
	Items []interface{}
}

type ItemLink struct {
	Title   string
	Url     string
	Name    string
	Index   int
	Img     string `json:"Img,omitempty"`
	ImgSize string `json:"ImgSize,omitempty"`
}

func ParseECHtml(url_string string) {

	target_url, _ := url.Parse(url_string)
	doc, err := goquery.NewDocument(url_string)
	if err != nil {
		log.Fatal(err)
	}

	parsedata := ParseData{
		Locale: strings.Split(target_url.Path, "/")[2],
	}

	//parse the header
	doc.Find("#main-menu").Children().Not(".mobile").Not("div").Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().First().AttrOr("title", ""),
			Url:       paser_url(target_url, s.Children().First().AttrOr("href", "#")),
			Name:      s.Children().First().Text(),
			Index:     i + 1,
			SingleRow: true,
		}

		s.Find("ul").Each(func(i int, s *goquery.Selection) {
			if s.Children().Size() == 2 {

				firstlink := Link{
					Title:     s.Find("h5").First().AttrOr("title", ""),
					Url:       "#",
					Name:      s.Find("h5").First().Text(),
					Index:     1,
					SingleRow: false,
				}

				secondlink := Link{
					Title:     s.Find(".empty-nav-item").Last().AttrOr("title", ""),
					Url:       "#",
					Name:      s.Find(".empty-nav-item").Last().Text(),
					Index:     2,
					SingleRow: false,
				}

				is_first := true
				s.Find(".yCmsComponent").Each(func(i int, s *goquery.Selection) {
					// fmt.Println(i)
					// fmt.Println(s.Children().First().Html())
					if s.Children().First().Is("span") {
						if s.Children().First().Text() != "" {
							is_first = false
						}

					} else {
						itemlink := ItemLink{
							Title: s.Children().First().AttrOr("title", ""),
							Name:  s.Children().First().Text(),
							Url:   paser_url(target_url, s.Children().First().AttrOr("href", "#")),
							Index: i + 1,
						}
						if s.Children().First().Children().First().Is("img") {
							itemlink.Img = paser_url(target_url, s.Children().First().Children().First().AttrOr("src", "#"))
						}

						if is_first {
							firstlink.Items = append(firstlink.Items, itemlink)
						} else {
							secondlink.Items = append(secondlink.Items, itemlink)

						}
					}
				})
				link.Items = append(link.Items, firstlink)
				link.Items = append(link.Items, secondlink)

			} else {

				firstlink := Link{
					Title:     s.Find("h5").First().AttrOr("title", ""),
					Url:       "#",
					Name:      s.Find("h5").First().Text(),
					Index:     i + 1,
					SingleRow: true,
				}
				s.Find(".yCmsComponent").Each(func(i int, s *goquery.Selection) {

					itemlink := ItemLink{
						Title: s.Children().First().AttrOr("title", ""),
						Name:  s.Children().First().Text(),
						Url:   paser_url(target_url, s.Children().First().AttrOr("href", "#")),
						Index: i + 1,
					}
					if s.Children().First().Children().First().Is("img") {
						itemlink.Img = paser_url(target_url, s.Children().First().Children().First().AttrOr("src", "#"))
					}

					firstlink.Items = append(firstlink.Items, itemlink)

				})
				link.Items = append(link.Items, firstlink)
			}
		})
		parsedata.Header = append(parsedata.Header, link)
	})

	//parse the footer
	doc.Find("footer").Children().Filter(".tiger-clearfix-toggle").Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().Filter("h4").First().AttrOr("title", ""),
			Url:       "#",
			Name:      s.Children().Filter("h4").First().Text(),
			Index:     i + 1,
			SingleRow: true,
		}

		s.Children().Filter("ul").Children().Each(func(i int, s *goquery.Selection) {
			itemlink := ItemLink{
				Title: s.Children().First().AttrOr("title", ""),
				Name:  s.Children().First().Text(),
				Url:   paser_url(target_url, s.Children().First().AttrOr("href", "#")),
				Index: i + 1,
			}
			link.Items = append(link.Items, itemlink)
		})
		parsedata.Footer = append(parsedata.Footer, link)
	})

	jsondata, _ := json.Marshal(parsedata)

	file, _ := os.OpenFile(strings.Split(target_url.Path, "/")[2]+".json", os.O_WRONLY|os.O_CREATE, 0666)
	file.Write(jsondata)

	fmt.Println(string(jsondata))

}

func ParseNoECHtml(url_string string) {

	target_url, _ := url.Parse(url_string)
	doc, err := goquery.NewDocument(url_string)
	if err != nil {
		log.Fatal(err)
	}

	locale := strings.Split(target_url.Host, ".")[0] + "-" + strings.Split(target_url.Host, ".")[2]
	parsedata := ParseData{
		Locale: locale,
	}

	//parse the header
	doc.Find("header #asicsAreas").Children().Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().First().AttrOr("title", ""),
			Name:      s.Children().First().Children().First().Text(),
			SingleRow: true,
			Url:       "#",
			Index:     i + 1,
		}
		if i != 3 {
			doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsListing").Each(func(ii int, ss *goquery.Selection) {
				secend_link := Link{
					Title:     doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().End().AttrOr("title", ""),
					Name:      strings.TrimSpace(doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().End().Text()),
					Url:       doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().End().AttrOr("href", "#"),
					Img:       paser_url(target_url, doc.Find("header #asicsPanels").Children().Slice(i, i+1).Children().First().Children().Filter(".asicsFeatured").Children().First().Children().Slice(ii, ii+1).Children().First().Children().First().AttrOr("src", "#")),
					ImgSize:   "small",
					Index:     i + 1,
					SingleRow: true,
				}
				ss.Children().Filter("ul").Children().Each(func(iii int, s *goquery.Selection) {
					itemlink := ItemLink{
						Title: s.Children().First().AttrOr("title", ""),
						Url:   paser_url(target_url, s.Children().First().AttrOr("href", "#")),
						Name:  s.Children().First().Text(),
						Index: iii + 1,
					}

					secend_link.Items = append(secend_link.Items, itemlink)
				})

				link.Items = append(link.Items, secend_link)

			})

		}

		parsedata.Header = append(parsedata.Header, link)
	})

	//parse the footer
	doc.Find(".footer #tertiary section").Each(func(i int, s *goquery.Selection) {
		link := Link{
			Title:     s.Children().First().AttrOr("title", ""),
			Name:      s.Children().First().Text(),
			Url:       "#",
			Index:     i + 1,
			SingleRow: true,
		}

		s.Children().Filter("ul").Children().Each(func(i int, s *goquery.Selection) {
			itemlink := ItemLink{
				Title: s.Children().First().AttrOr("title", ""),
				Url:   paser_url(target_url, s.Children().First().AttrOr("href", "#")),
				Name:  s.Children().First().Text(),
				Index: i + 1,
			}
			link.Items = append(link.Items, itemlink)
		})
		parsedata.Footer = append(parsedata.Footer, link)
	})

	jsondata, _ := json.Marshal(parsedata)

	file, _ := os.OpenFile(locale, os.O_WRONLY|os.O_CREATE, 0666)
	file.Write(jsondata)

	fmt.Println(string(jsondata))

}

func paser_url(target_url *url.URL, url string) (return_url string) {

	if matched, err := regexp.Match(`http`, []byte(url)); matched && err == nil {
		return_url = url
	} else {
		return_url = target_url.Scheme + "://" + target_url.Host + url
	}
	return
}

func main() {
	for _, url := range EuropeEcAsics {
		ParseECHtml(url)
	}
	for _, url := range NoEcAsics {
		ParseNoECHtml(url)
	}

}
<|endoftext|>


<commit_before>/**
 * Copyright 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"fmt"

	"github.ibm.com/riethm/gopherlayer/datatypes"
	"github.ibm.com/riethm/gopherlayer/service"
	"github.ibm.com/riethm/gopherlayer/sl"
	"reflect"
	"time"
)

func main() {
	session := service.NewSession("username", "apikey") // default endpoint

	session.Debug = true

	// List all Virtual Guests for an account
	//doListAccountVMsTest(&session)

	// Execute a remote script on a Virtual Guest
	//doExecuteRemoteScriptTest(&session)

	// Example: Provision and destroy a Virtual Guest
	//doCreateVMTest(&session)

	// Example: Get disk usage metrics by date
	//doGetDiskUsageMetricsTest(&session)

	// Example: Get the last bill date
	//doGetLatestBillDate(&session)
}

func doListAccountVMsTest(session *service.Session) {
	// Get the Account service
	service := session.GetAccountService()

	//Set an object mask and a result limit
	service.Mask("id;hostname;domain").Limit(10)

	// List VMs
	vms, err := service.GetVirtualGuests()
	if err != nil {
		fmt.Printf("Error retrieving Virtual Guests from Account: %s\n", err)
		return
	} else {
		fmt.Println("VMs under Account:")
	}

	for _, vm := range vms {
		fmt.Printf("\t[%d]%s.%s\n", *vm.Id, *vm.Hostname, *vm.Domain)
	}
}

func doExecuteRemoteScriptTest(session *service.Session) {
	// Get the VirtualGuest service
	service := session.GetVirtualGuestService()

	// Set the object ID for the service to act upon
	service.Id(22870595)

	// Execute the remote script
	err := service.ExecuteRemoteScript(sl.String("http://example.com"))
	if err != nil {
		fmt.Printf("Error executing remote script on VM: %s", err)
	} else {
		fmt.Println("Remote script sent for execution on VM")
	}
}

func doCreateVMTest(session *service.Session) {
	service := session.GetVirtualGuestService()

	// Create a Virtual_Guest instance as a template
	vGuestTemplate := datatypes.Virtual_Guest{}

	//Set Creation values - use helpers from the sl package to set pointer values
	vGuestTemplate.Hostname = sl.String("sample")
	vGuestTemplate.Domain = sl.String("example.com")
	vGuestTemplate.MaxMemory = sl.Int(4096)
	vGuestTemplate.StartCpus = sl.Int(1)
	vGuestTemplate.Datacenter = &datatypes.Location{Name: sl.String("wdc01")}
	vGuestTemplate.OperatingSystemReferenceCode = sl.String("UBUNTU_LATEST")
	vGuestTemplate.LocalDiskFlag = sl.Bool(true)

	service.Mask("id;domain")

	vGuest, err := service.CreateObject(&vGuestTemplate)
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	} else {
		fmt.Printf("\nNew Virtual Guest created with ID %d\n", *vGuest.Id)
		fmt.Printf("Domain: %s\n", *vGuest.Domain)
	}

	// Wait for transactions to finish
	fmt.Printf("Waiting for transactions to complete before destroying.")
	service.Id(*vGuest.Id)

	// Delay to allow transactions to be registered
	time.Sleep(10 * time.Second)

	for transactions, _ := service.GetActiveTransactions(); len(transactions) > 0; {
		fmt.Print(".")
		time.Sleep(10 * time.Second)
		transactions, err = service.GetActiveTransactions()
	}

	fmt.Println("Deleting virtual guest")

	success, err := service.DeleteObject()
	if err != nil {
		fmt.Printf("Error deleting virtual guest: %s", err)
	} else if success == false {
		fmt.Printf("Error deleting virtual guest")
	} else {
		fmt.Printf("Virtual Guest deleted successfully")
	}
}

func doGetDiskUsageMetricsTest(session *service.Session) {
	service := session.GetAccountService()

	tEnd := sl.Time(time.Now())
	tStart := sl.Time(tEnd.AddDate(0, -6, 0))

	data, err := service.GetDiskUsageMetricDataByDate(tStart, tEnd)
	if err != nil {
		fmt.Println("Error calling GetDiskUsageMetricDataByDate: ", err)
		return
	}

	fmt.Printf("Number of elements returned: %d\n", len(data))

	// Retrieve and print a DateTime (sl.Time) value
	if len(data) > 0 {
		fmt.Printf("item.DateTime = %s\n", data[0].DateTime)
	}
}

func doGetLatestBillDate(session *service.Session) {
	service := session.GetAccountService()

	d, _ := service.GetLatestBillDate()

	fmt.Printf("date of last bill: %s\n", d)
	fmt.Printf("type of date field: %s\n", reflect.TypeOf(d))
}
<commit_msg>Update test.go to reflect new services package name<commit_after>/**
 * Copyright 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"fmt"

	"github.ibm.com/riethm/gopherlayer/datatypes"
	"github.ibm.com/riethm/gopherlayer/services"
	"github.ibm.com/riethm/gopherlayer/sl"
	"reflect"
	"time"
)

func main() {
	session := service.NewSession("username", "apikey") // default endpoint

	session.Debug = true

	// List all Virtual Guests for an account
	//doListAccountVMsTest(&session)

	// Execute a remote script on a Virtual Guest
	//doExecuteRemoteScriptTest(&session)

	// Example: Provision and destroy a Virtual Guest
	//doCreateVMTest(&session)

	// Example: Get disk usage metrics by date
	//doGetDiskUsageMetricsTest(&session)

	// Example: Get the last bill date
	//doGetLatestBillDate(&session)
}

func doListAccountVMsTest(session *services.Session) {
	// Get the Account service
	service := session.GetAccountService()

	//Set an object mask and a result limit
	service.Mask("id;hostname;domain").Limit(10)

	// List VMs
	vms, err := service.GetVirtualGuests()
	if err != nil {
		fmt.Printf("Error retrieving Virtual Guests from Account: %s\n", err)
		return
	} else {
		fmt.Println("VMs under Account:")
	}

	for _, vm := range vms {
		fmt.Printf("\t[%d]%s.%s\n", *vm.Id, *vm.Hostname, *vm.Domain)
	}
}

func doExecuteRemoteScriptTest(session *services.Session) {
	// Get the VirtualGuest service
	service := session.GetVirtualGuestService()

	// Set the object ID for the service to act upon
	service.Id(22870595)

	// Execute the remote script
	err := service.ExecuteRemoteScript(sl.String("http://example.com"))
	if err != nil {
		fmt.Printf("Error executing remote script on VM: %s", err)
	} else {
		fmt.Println("Remote script sent for execution on VM")
	}
}

func doCreateVMTest(session *services.Session) {
	service := session.GetVirtualGuestService()

	// Create a Virtual_Guest instance as a template
	vGuestTemplate := datatypes.Virtual_Guest{}

	//Set Creation values - use helpers from the sl package to set pointer values
	vGuestTemplate.Hostname = sl.String("sample")
	vGuestTemplate.Domain = sl.String("example.com")
	vGuestTemplate.MaxMemory = sl.Int(4096)
	vGuestTemplate.StartCpus = sl.Int(1)
	vGuestTemplate.Datacenter = &datatypes.Location{Name: sl.String("wdc01")}
	vGuestTemplate.OperatingSystemReferenceCode = sl.String("UBUNTU_LATEST")
	vGuestTemplate.LocalDiskFlag = sl.Bool(true)

	service.Mask("id;domain")

	vGuest, err := service.CreateObject(&vGuestTemplate)
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	} else {
		fmt.Printf("\nNew Virtual Guest created with ID %d\n", *vGuest.Id)
		fmt.Printf("Domain: %s\n", *vGuest.Domain)
	}

	// Wait for transactions to finish
	fmt.Printf("Waiting for transactions to complete before destroying.")
	service.Id(*vGuest.Id)

	// Delay to allow transactions to be registered
	time.Sleep(10 * time.Second)

	for transactions, _ := service.GetActiveTransactions(); len(transactions) > 0; {
		fmt.Print(".")
		time.Sleep(10 * time.Second)
		transactions, err = service.GetActiveTransactions()
	}

	fmt.Println("Deleting virtual guest")

	success, err := service.DeleteObject()
	if err != nil {
		fmt.Printf("Error deleting virtual guest: %s", err)
	} else if success == false {
		fmt.Printf("Error deleting virtual guest")
	} else {
		fmt.Printf("Virtual Guest deleted successfully")
	}
}

func doGetDiskUsageMetricsTest(session *services.Session) {
	service := session.GetAccountService()

	tEnd := sl.Time(time.Now())
	tStart := sl.Time(tEnd.AddDate(0, -6, 0))

	data, err := service.GetDiskUsageMetricDataByDate(tStart, tEnd)
	if err != nil {
		fmt.Println("Error calling GetDiskUsageMetricDataByDate: ", err)
		return
	}

	fmt.Printf("Number of elements returned: %d\n", len(data))

	// Retrieve and print a DateTime (sl.Time) value
	if len(data) > 0 {
		fmt.Printf("item.DateTime = %s\n", data[0].DateTime)
	}
}

func doGetLatestBillDate(session *services.Session) {
	service := session.GetAccountService()

	d, _ := service.GetLatestBillDate()

	fmt.Printf("date of last bill: %s\n", d)
	fmt.Printf("type of date field: %s\n", reflect.TypeOf(d))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

func (p *Log) SetLevel(level uint) (err error) {
	p.Level = level
	return
}

func (p *Log) GetLevel() (level uint, err error) {
	return p.Level, err
}

func (p *Log) SetPath(path string) (err error) {
	p.Path = path
	return
}

func (p *Log) GetPath() (path string, err error) {
	return p.Path, err
}

func (p *Log) Write(level uint,format string, args ...interface{}) (err error) {
	var x string
	if level < p.Level {
		return
	}
	if args == nil {
		x = fmt.Sprintf(format)
	} else {
		x = fmt.Sprintf(format, args)
	}
	p.cache = append(p.cache, x)
	p.cacheLine = p.cacheLine + 1
	if p.cacheLine > p.MaxCache {
		p.Flush()
	}
	return
}

func (p *Log) Flush() (err error) {
	for _, r := range p.cache {
		fmt.Printf("%s\n", r)
	}
	p.cacheLine = 0
	return
}

func NewLog() (log Log, err error) {
	log.Level = LOG_ERR
	log.Path = LOG_PATH
	log.AccessLog = log.Path + "/" + LOG_ACCESS
	log.ErrorLog = log.Path + "/" + LOG_ERROR
	log.MaxCache = LOG_MAX_CACHE
	err = os.MkdirAll(log.Path, 0755)
	if err != nil {
		println(err.Error())
	}

	log.accessLog, err = os.OpenFile(log.AccessLog, os.O_RDWR | os.O_APPEND | os.O_CREATE, 0640)
	if err != nil {
		return
	}
	log.errorLog, err = os.OpenFile(log.ErrorLog, os.O_RDWR | os.O_APPEND | os.O_CREATE, 0640)
	if err != nil {
		return
	}

	return
}

func (p *Log) Init() (err error) {
	return
}

type Log struct {
	Level       uint   `json:"level" bson:"level"`
	Path        string `json:"path" bson:"path"`
	AccessLog	string `json:"accesslog" bson:"accesslog"`
	ErrorLog	string `json:"errorlog" bson:"errorlog"`
	MaxCache	int
	cache		[]string
	cacheLine int
	accessLog *os.File
	errorLog *os.File
}

const (
	LOG_STDERR    =  0
	LOG_EMERG     =  1
	LOG_ALERT     =  2
	LOG_CRIT      =  3
	LOG_ERR       =  4
	LOG_WARN      =  5
	LOG_NOTICE    =  6
	LOG_INFO      =  7
	LOG_DEBUG     =  8
	LOG_PATH      =  "log"
	LOG_ACCESS	  =  "access.log"
	LOG_ERROR	  =  "error.log"
	LOG_MAX_CACHE =  100
)
<commit_msg>Delete log.go<commit_after><|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package e2e_node

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

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/client/restclient"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/stats"

	"github.com/davecgh/go-spew/spew"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Kubelet", func() {
	var cl *client.Client
	BeforeEach(func() {
		// Setup the apiserver client
		cl = client.NewOrDie(&restclient.Config{Host: *apiServerAddress})
	})

	Describe("pod scheduling", func() {
		Context("when scheduling a busybox command in a pod", func() {
			It("it should return succes", func() {
				pod := &api.Pod{
					ObjectMeta: api.ObjectMeta{
						Name:      "busybox",
						Namespace: api.NamespaceDefault,
					},
					Spec: api.PodSpec{
						// Force the Pod to schedule to the node without a scheduler running
						NodeName: *nodeName,
						// Don't restart the Pod since it is expected to exit
						RestartPolicy: api.RestartPolicyNever,
						Containers: []api.Container{
							{
								Image:   "gcr.io/google_containers/busybox",
								Name:    "busybox",
								Command: []string{"echo", "'Hello World'"},
							},
						},
					},
				}
				_, err := cl.Pods(api.NamespaceDefault).Create(pod)
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})

			It("it should print the output to logs", func() {
				Eventually(func() string {
					sinceTime := unversioned.NewTime(time.Now().Add(time.Duration(-1 * time.Hour)))
					rc, err := cl.Pods(api.NamespaceDefault).GetLogs("busybox", &api.PodLogOptions{SinceTime: &sinceTime}).Stream()
					if err != nil {
						return ""
					}
					defer rc.Close()
					buf := new(bytes.Buffer)
					buf.ReadFrom(rc)
					return buf.String()
				}, time.Second*30, time.Second*4).Should(Equal("'Hello World'\n"))
			})

			It("it should be possible to delete", func() {
				err := cl.Pods(api.NamespaceDefault).Delete("busybox", &api.DeleteOptions{})
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})
		})

		Context("when scheduling a read only busybox container", func() {
			It("it should return success", func() {
				isReadOnly := true
				pod := &api.Pod{
					ObjectMeta: api.ObjectMeta{
						Name:      "busybox",
						Namespace: api.NamespaceDefault,
					},
					Spec: api.PodSpec{
						// Force the Pod to schedule to the node without a scheduler running
						NodeName: *nodeName,
						// Don't restart the Pod since it is expected to exit
						RestartPolicy: api.RestartPolicyNever,
						Containers: []api.Container{
							{
								Image:   "gcr.io/google_containers/busybox",
								Name:    "busybox",
								Command: []string{"sh", "-c", "echo test > /file"},
								SecurityContext: &api.SecurityContext{
									ReadOnlyRootFilesystem: &isReadOnly,
								},
							},
						},
					},
				}
				_, err := cl.Pods(api.NamespaceDefault).Create(pod)
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})

			It("it should not write to the root filesystem", func() {
				Eventually(func() string {
					rc, err := cl.Pods(api.NamespaceDefault).GetLogs("busybox", &api.PodLogOptions{}).Stream()
					if err != nil {
						return ""
					}
					defer rc.Close()
					buf := new(bytes.Buffer)
					buf.ReadFrom(rc)
					return buf.String()
				}, time.Second*30, time.Second*4).Should(Equal("sh: can't create /file: Read-only file system\n"))
			})

			It("it should be possible to delete", func() {
				err := cl.Pods(api.NamespaceDefault).Delete("busybox", &api.DeleteOptions{})
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})
		})
	})

	Describe("metrics api", func() {
		statsPrefix := "stats-busybox-"
		podNames := []string{}
		podCount := 2
		for i := 0; i < podCount; i++ {
			podNames = append(podNames, fmt.Sprintf("%s%v", statsPrefix, i))
		}
		BeforeEach(func() {
			for _, podName := range podNames {
				createPod(cl, podName, []api.Container{
					{
						Image:   "gcr.io/google_containers/busybox",
						Command: []string{"sh", "-c", "echo 'Hello World' | tee ~/file | tee /test-empty-dir-mnt | sleep 60"},
						Name:    podName + containerSuffix,
						VolumeMounts: []api.VolumeMount{
							{MountPath: "/test-empty-dir-mnt", Name: "test-empty-dir"},
						},
					},
				}, []api.Volume{
					// TODO: Test secret volumes
					// TODO: Test hostpath volumes
					{Name: "test-empty-dir", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
				})
			}

			// Sleep long enough for cadvisor to see the pod and calculate all of its metrics
			time.Sleep(60 * time.Second)
		})

		Context("when querying /stats/summary", func() {
			It("it should report resource usage through the stats api", func() {
				By("Returning stats summary")
				resp, err := http.Get(*kubeletAddress + "/stats/summary")
				Expect(err).To(BeNil(), fmt.Sprintf("Failed to get /stats/summary"))
				summary := stats.Summary{}
				contentsBytes, err := ioutil.ReadAll(resp.Body)
				Expect(err).To(BeNil(), fmt.Sprintf("Failed to read /stats/summary: %+v", resp))
				contents := string(contentsBytes)
				decoder := json.NewDecoder(strings.NewReader(contents))
				err = decoder.Decode(&summary)
				Expect(err).To(BeNil(), fmt.Sprintf("Failed to parse /stats/summary to go struct: %+v", resp))

				By("Having resources for node")
				Expect(summary.Node.NodeName).To(Equal(*nodeName))
				Expect(summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeNil())
				Expect(*summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeZero())

				Expect(summary.Node.Memory.UsageBytes).NotTo(BeNil())
				Expect(*summary.Node.Memory.UsageBytes).NotTo(BeZero())

				Expect(summary.Node.Memory.WorkingSetBytes).NotTo(BeNil())
				Expect(*summary.Node.Memory.WorkingSetBytes).NotTo(BeZero())

				Expect(summary.Node.Fs.AvailableBytes).NotTo(BeNil())
				Expect(*summary.Node.Fs.AvailableBytes).NotTo(BeZero())
				Expect(summary.Node.Fs.CapacityBytes).NotTo(BeNil())
				Expect(*summary.Node.Fs.CapacityBytes).NotTo(BeZero())
				Expect(summary.Node.Fs.UsedBytes).NotTo(BeNil())
				Expect(*summary.Node.Fs.UsedBytes).NotTo(BeZero())

				// TODO: Enable this test when #22198 is resolved.
				//				By("Having resources for kubelet and runtime system containers")
				//				sysContainers := map[string]stats.ContainerStats{}
				//				sysContainersList := []string{}
				//				for _, container := range summary.Node.SystemContainers {
				//					sysContainers[container.Name] = container
				//					sysContainersList = append(sysContainersList, container.Name)
				//					ExpectContainerStatsNotEmpty(&container)
				//				}
				//				Expect(sysContainersList).To(ConsistOf("kubelet", "runtime"))

				// Verify Pods Stats are present
				podsList := []string{}
				By("Having resources for pods")
				for _, pod := range summary.Pods {
					if !strings.HasPrefix(pod.PodRef.Name, statsPrefix) {
						// Ignore pods created outside this test
						continue
					}

					podsList = append(podsList, pod.PodRef.Name)

					Expect(pod.Containers).To(HaveLen(1))
					container := pod.Containers[0]
					Expect(container.Name).To(Equal(pod.PodRef.Name + containerSuffix))

					ExpectContainerStatsNotEmpty(&container)

					// emptydir volume
					volumeNames := []string{}
					for _, vs := range pod.VolumeStats {
						Expect(vs.CapacityBytes).NotTo(BeZero())
						Expect(vs.AvailableBytes).NotTo(BeZero())
						Expect(vs.UsedBytes).NotTo(BeZero())
						volumeNames = append(volumeNames, vs.Name)
					}
					Expect(volumeNames).To(ConsistOf("test-empty-dir"))

					// fs usage (not for system containers)
					Expect(container.Rootfs).NotTo(BeNil(), spew.Sdump(container))
					Expect(container.Rootfs.AvailableBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Rootfs.AvailableBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Rootfs.CapacityBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Rootfs.CapacityBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Rootfs.UsedBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Rootfs.UsedBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Logs).NotTo(BeNil(), spew.Sdump(container))
					Expect(container.Logs.AvailableBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Logs.AvailableBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Logs.CapacityBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Logs.CapacityBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Logs.UsedBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Logs.UsedBytes).NotTo(BeZero(), spew.Sdump(container))

				}
				Expect(podsList).To(ConsistOf(podNames), spew.Sdump(summary))
			})
		})

		AfterEach(func() {
			for _, podName := range podNames {
				err := cl.Pods(api.NamespaceDefault).Delete(podName, &api.DeleteOptions{})
				Expect(err).To(BeNil(), fmt.Sprintf("Error deleting Pod %v", podName))
			}
		})
	})
})

func ExpectContainerStatsNotEmpty(container *stats.ContainerStats) {
	// TODO: Test Network

	Expect(container.CPU).NotTo(BeNil(), spew.Sdump(container))
	Expect(container.CPU.UsageCoreNanoSeconds).NotTo(BeNil(), spew.Sdump(container))
	Expect(*container.CPU.UsageCoreNanoSeconds).NotTo(BeZero(), spew.Sdump(container))

	Expect(container.Memory).NotTo(BeNil(), spew.Sdump(container))
	Expect(container.Memory.UsageBytes).NotTo(BeNil(), spew.Sdump(container))
	Expect(*container.Memory.UsageBytes).NotTo(BeZero(), spew.Sdump(container))
	Expect(container.Memory.WorkingSetBytes).NotTo(BeNil(), spew.Sdump(container))
	Expect(*container.Memory.WorkingSetBytes).NotTo(BeZero(), spew.Sdump(container))
}

const (
	containerSuffix = "-c"
)

func createPod(cl *client.Client, podName string, containers []api.Container, volumes []api.Volume) {
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name:      podName,
			Namespace: api.NamespaceDefault,
		},
		Spec: api.PodSpec{
			// Force the Pod to schedule to the node without a scheduler running
			NodeName: *nodeName,
			// Don't restart the Pod since it is expected to exit
			RestartPolicy: api.RestartPolicyNever,
			Containers:    containers,
			Volumes:       volumes,
		},
	}
	_, err := cl.Pods(api.NamespaceDefault).Create(pod)
	Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
}
<commit_msg>use different pod names and namespaces<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package e2e_node

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

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/client/restclient"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/stats"

	"github.com/davecgh/go-spew/spew"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Kubelet", func() {
	var cl *client.Client
	BeforeEach(func() {
		// Setup the apiserver client
		cl = client.NewOrDie(&restclient.Config{Host: *apiServerAddress})
	})

	Describe("pod scheduling", func() {
		namespace := "pod-scheduling"
		Context("when scheduling a busybox command in a pod", func() {
			podName := "busybox-scheduling"
			It("it should return succes", func() {
				pod := &api.Pod{
					ObjectMeta: api.ObjectMeta{
						Name:      podName,
						Namespace: namespace,
					},
					Spec: api.PodSpec{
						// Force the Pod to schedule to the node without a scheduler running
						NodeName: *nodeName,
						// Don't restart the Pod since it is expected to exit
						RestartPolicy: api.RestartPolicyNever,
						Containers: []api.Container{
							{
								Image:   "gcr.io/google_containers/busybox",
								Name:    podName,
								Command: []string{"echo", "'Hello World'"},
							},
						},
					},
				}
				_, err := cl.Pods(namespace).Create(pod)
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})

			It("it should print the output to logs", func() {
				Eventually(func() string {
					sinceTime := unversioned.NewTime(time.Now().Add(time.Duration(-1 * time.Hour)))
					rc, err := cl.Pods(namespace).GetLogs(podName, &api.PodLogOptions{SinceTime: &sinceTime}).Stream()
					if err != nil {
						return ""
					}
					defer rc.Close()
					buf := new(bytes.Buffer)
					buf.ReadFrom(rc)
					return buf.String()
				}, time.Second*30, time.Second*4).Should(Equal("'Hello World'\n"))
			})

			It("it should be possible to delete", func() {
				err := cl.Pods(namespace).Delete(podName, &api.DeleteOptions{})
				Expect(err).To(BeNil(), fmt.Sprintf("Error deleting Pod %v", err))
			})
		})

		Context("when scheduling a read only busybox container", func() {
			podName := "busybox-readonly-fs"
			It("it should return success", func() {
				isReadOnly := true
				pod := &api.Pod{
					ObjectMeta: api.ObjectMeta{
						Name:      podName,
						Namespace: namespace,
					},
					Spec: api.PodSpec{
						// Force the Pod to schedule to the node without a scheduler running
						NodeName: *nodeName,
						// Don't restart the Pod since it is expected to exit
						RestartPolicy: api.RestartPolicyNever,
						Containers: []api.Container{
							{
								Image:   "gcr.io/google_containers/busybox",
								Name:    podName,
								Command: []string{"sh", "-c", "echo test > /file"},
								SecurityContext: &api.SecurityContext{
									ReadOnlyRootFilesystem: &isReadOnly,
								},
							},
						},
					},
				}
				_, err := cl.Pods(namespace).Create(pod)
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})

			It("it should not write to the root filesystem", func() {
				Eventually(func() string {
					rc, err := cl.Pods(namespace).GetLogs(podName, &api.PodLogOptions{}).Stream()
					if err != nil {
						return ""
					}
					defer rc.Close()
					buf := new(bytes.Buffer)
					buf.ReadFrom(rc)
					return buf.String()
				}, time.Second*30, time.Second*4).Should(Equal("sh: can't create /file: Read-only file system\n"))
			})

			It("it should be possible to delete", func() {
				err := cl.Pods(namespace).Delete(podName, &api.DeleteOptions{})
				Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
			})
		})
	})

	Describe("metrics api", func() {
		namespace := "kubelet-metrics-api"
		statsPrefix := "stats-busybox-"
		podNames := []string{}
		podCount := 2
		for i := 0; i < podCount; i++ {
			podNames = append(podNames, fmt.Sprintf("%s%v", statsPrefix, i))
		}
		BeforeEach(func() {
			for _, podName := range podNames {
				createPod(cl, podName, namespace, []api.Container{
					{
						Image:   "gcr.io/google_containers/busybox",
						Command: []string{"sh", "-c", "echo 'Hello World' | tee ~/file | tee /test-empty-dir-mnt | sleep 60"},
						Name:    podName + containerSuffix,
						VolumeMounts: []api.VolumeMount{
							{MountPath: "/test-empty-dir-mnt", Name: "test-empty-dir"},
						},
					},
				}, []api.Volume{
					// TODO: Test secret volumes
					// TODO: Test hostpath volumes
					{Name: "test-empty-dir", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
				})
			}

			// Sleep long enough for cadvisor to see the pod and calculate all of its metrics
			time.Sleep(60 * time.Second)
		})

		Context("when querying /stats/summary", func() {
			It("it should report resource usage through the stats api", func() {
				By("Returning stats summary")
				resp, err := http.Get(*kubeletAddress + "/stats/summary")
				Expect(err).To(BeNil(), fmt.Sprintf("Failed to get /stats/summary"))
				summary := stats.Summary{}
				contentsBytes, err := ioutil.ReadAll(resp.Body)
				Expect(err).To(BeNil(), fmt.Sprintf("Failed to read /stats/summary: %+v", resp))
				contents := string(contentsBytes)
				decoder := json.NewDecoder(strings.NewReader(contents))
				err = decoder.Decode(&summary)
				Expect(err).To(BeNil(), fmt.Sprintf("Failed to parse /stats/summary to go struct: %+v", resp))

				By("Having resources for node")
				Expect(summary.Node.NodeName).To(Equal(*nodeName))
				Expect(summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeNil())
				Expect(*summary.Node.CPU.UsageCoreNanoSeconds).NotTo(BeZero())

				Expect(summary.Node.Memory.UsageBytes).NotTo(BeNil())
				Expect(*summary.Node.Memory.UsageBytes).NotTo(BeZero())

				Expect(summary.Node.Memory.WorkingSetBytes).NotTo(BeNil())
				Expect(*summary.Node.Memory.WorkingSetBytes).NotTo(BeZero())

				Expect(summary.Node.Fs.AvailableBytes).NotTo(BeNil())
				Expect(*summary.Node.Fs.AvailableBytes).NotTo(BeZero())
				Expect(summary.Node.Fs.CapacityBytes).NotTo(BeNil())
				Expect(*summary.Node.Fs.CapacityBytes).NotTo(BeZero())
				Expect(summary.Node.Fs.UsedBytes).NotTo(BeNil())
				Expect(*summary.Node.Fs.UsedBytes).NotTo(BeZero())

				// TODO: Enable this test when #22198 is resolved.
				//				By("Having resources for kubelet and runtime system containers")
				//				sysContainers := map[string]stats.ContainerStats{}
				//				sysContainersList := []string{}
				//				for _, container := range summary.Node.SystemContainers {
				//					sysContainers[container.Name] = container
				//					sysContainersList = append(sysContainersList, container.Name)
				//					ExpectContainerStatsNotEmpty(&container)
				//				}
				//				Expect(sysContainersList).To(ConsistOf("kubelet", "runtime"))

				// Verify Pods Stats are present
				podsList := []string{}
				By("Having resources for pods")
				for _, pod := range summary.Pods {
					if !strings.HasPrefix(pod.PodRef.Name, statsPrefix) {
						// Ignore pods created outside this test
						continue
					}

					podsList = append(podsList, pod.PodRef.Name)

					Expect(pod.Containers).To(HaveLen(1))
					container := pod.Containers[0]
					Expect(container.Name).To(Equal(pod.PodRef.Name + containerSuffix))

					ExpectContainerStatsNotEmpty(&container)

					// emptydir volume
					volumeNames := []string{}
					for _, vs := range pod.VolumeStats {
						Expect(vs.CapacityBytes).NotTo(BeZero())
						Expect(vs.AvailableBytes).NotTo(BeZero())
						Expect(vs.UsedBytes).NotTo(BeZero())
						volumeNames = append(volumeNames, vs.Name)
					}
					Expect(volumeNames).To(ConsistOf("test-empty-dir"))

					// fs usage (not for system containers)
					Expect(container.Rootfs).NotTo(BeNil(), spew.Sdump(container))
					Expect(container.Rootfs.AvailableBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Rootfs.AvailableBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Rootfs.CapacityBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Rootfs.CapacityBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Rootfs.UsedBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Rootfs.UsedBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Logs).NotTo(BeNil(), spew.Sdump(container))
					Expect(container.Logs.AvailableBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Logs.AvailableBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Logs.CapacityBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Logs.CapacityBytes).NotTo(BeZero(), spew.Sdump(container))
					Expect(container.Logs.UsedBytes).NotTo(BeNil(), spew.Sdump(container))
					Expect(*container.Logs.UsedBytes).NotTo(BeZero(), spew.Sdump(container))

				}
				Expect(podsList).To(ConsistOf(podNames), spew.Sdump(summary))
			})
		})

		AfterEach(func() {
			for _, podName := range podNames {
				err := cl.Pods(namespace).Delete(podName, &api.DeleteOptions{})
				Expect(err).To(BeNil(), fmt.Sprintf("Error deleting Pod %v", podName))
			}
		})
	})
})

func ExpectContainerStatsNotEmpty(container *stats.ContainerStats) {
	// TODO: Test Network

	Expect(container.CPU).NotTo(BeNil(), spew.Sdump(container))
	Expect(container.CPU.UsageCoreNanoSeconds).NotTo(BeNil(), spew.Sdump(container))
	Expect(*container.CPU.UsageCoreNanoSeconds).NotTo(BeZero(), spew.Sdump(container))

	Expect(container.Memory).NotTo(BeNil(), spew.Sdump(container))
	Expect(container.Memory.UsageBytes).NotTo(BeNil(), spew.Sdump(container))
	Expect(*container.Memory.UsageBytes).NotTo(BeZero(), spew.Sdump(container))
	Expect(container.Memory.WorkingSetBytes).NotTo(BeNil(), spew.Sdump(container))
	Expect(*container.Memory.WorkingSetBytes).NotTo(BeZero(), spew.Sdump(container))
}

const (
	containerSuffix = "-c"
)

func createPod(cl *client.Client, podName string, namespace string, containers []api.Container, volumes []api.Volume) {
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name:      podName,
			Namespace: namespace,
		},
		Spec: api.PodSpec{
			// Force the Pod to schedule to the node without a scheduler running
			NodeName: *nodeName,
			// Don't restart the Pod since it is expected to exit
			RestartPolicy: api.RestartPolicyNever,
			Containers:    containers,
			Volumes:       volumes,
		},
	}
	_, err := cl.Pods(namespace).Create(pod)
	Expect(err).To(BeNil(), fmt.Sprintf("Error creating Pod %v", err))
}
<|endoftext|>


<commit_before>package tracking

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

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
)

//  represents a single position observed for a Vehicle from the data feed.
type VehicleUpdate struct {
	VehicleID string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	Lat       string    `json:"lat"         bson:"lat"`
	Lng       string    `json:"lng"         bson:"lng"`
	Heading   string    `json:"heading"     bson:"heading"`
	Speed     string    `json:"speed"       bson:"speed"`
	Lock      string    `json:"lock"        bson:"lock"`
	Time      string    `json:"time"        bson:"time"`
	Date      string    `json:"date"        bson:"date"`
	Status    string    `json:"status"      bson:"status"`
	Created   time.Time `json:"created"     bson:"created"`
	Segment   string    `json:"segment" bson:"segment"` // the segment that a vehicle resides on
}

// Vehicle represents an object being tracked.
type Vehicle struct {
	VehicleID   string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	VehicleName string    `json:"vehicleName" bson:"vehicleName"`
	Created     time.Time `bson:"created"`
	Updated     time.Time `bson:"updated"`
}

// Status contains a detailed message on the tracked object's status
type Status struct {
	Public  bool      `bson:"public"`
	Message string    `json:"message" bson:"message"`
	Created time.Time `bson:"created"`
	Updated time.Time `bson:"updated"`
}

var (
	// Match each API field with any number (+)
	//   of the previous expressions (\d digit, \. escaped period, - negative number)
	//   Specify named capturing groups to store each field from data feed
	dataRe    = regexp.MustCompile(`(?P<id>Vehicle ID:([\d\.]+)) (?P<lat>lat:([\d\.-]+)) (?P<lng>lon:([\d\.-]+)) (?P<heading>dir:([\d\.-]+)) (?P<speed>spd:([\d\.-]+)) (?P<lock>lck:([\d\.-]+)) (?P<time>time:([\d]+)) (?P<date>date:([\d]+)) (?P<status>trig:([\d]+))`)
	dataNames = dataRe.SubexpNames()
)

var ShuttleInactivityCounter = make(map[string]int);

// UpdateShuttles send a request to iTrak API, gets updated shuttle info, and
// finally store updated records in db.
func (App *App) UpdateShuttles(dataFeed string, updateInterval int) {
	var st time.Duration
	for {

		// Sleep for n seconds before updating again
		log.Debugf("sleeping for %v", st)
		time.Sleep(st)
		if st == 0 {
			// Initialize the sleep timer after the first sleep.  This lets us sleep during errors
			// when we 'continue' back to the top of the loop without waiting to sleep for the first
			// update run.
			st = time.Duration(updateInterval) * time.Second
		}

		// Make request to our tracking data feed
		resp, err := http.Get(dataFeed)
		if err != nil {
			log.Errorf("error getting data feed: %v", err)
			continue
		}
		defer resp.Body.Close()

		// Read response body content
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Errorf("error reading data feed: %v", err)
			continue
		}

		delim := "eof"
		// split the body of response by delimiter
		vehiclesData := strings.Split(string(body), delim)
		// BUG: if the request fails, it will give undefined result

		// TODO: Figure out if this handles == 1 vehicle correctly or always assumes > 1.
		if len(vehiclesData) <= 1 {
			log.Warnf("found no vehicles delineated by '%s'", delim)
		}

		updated := 0
		// for parsed data, update each vehicle
		for i := 0; i < len(vehiclesData)-1; i++ {
			match := dataRe.FindAllStringSubmatch(vehiclesData[i], -1)[0]
			// Store named capturing group and matching expression as a key value pair
			result := map[string]string{}
			for i, item := range match {
				result[dataNames[i]] = item
			}

			// Create new vehicle update & insert update into database
			// add computation of segment that the shuttle resides on and the arrival time to next N stops [here]

			update := VehicleUpdate{
				VehicleID: strings.Replace(result["id"], "Vehicle ID:", "", -1),
				Lat:       strings.Replace(result["lat"], "lat:", "", -1),
				Lng:       strings.Replace(result["lng"], "lon:", "", -1),
				Heading:   strings.Replace(result["heading"], "dir:", "", -1),
				Speed:     strings.Replace(result["speed"], "spd:", "", -1),
				Lock:      strings.Replace(result["lock"], "lck:", "", -1),
				Time:      strings.Replace(result["time"], "time:", "", -1),
				Date:      strings.Replace(result["date"], "date:", "", -1),
				Status:    strings.Replace(result["status"], "trig:", "", -1),
				Created:   time.Now()}

			//if a shuttle hasnt gone over 3 miles per hour in 5 minutes, it is probably inactive, and we shouldnt show it.
			spd, err := strconv.ParseFloat(update.Speed, 64)
			if(err != nil){
				log.Errorf("error finding speed");
			}
			if(spd < 3){
				ShuttleInactivityCounter[(strings.Replace(result["id"], "Vehicle ID:","",-1))] += 1;
				fmt.Printf(update.Status);
			}else{
					ShuttleInactivityCounter[(strings.Replace(result["id"], "Vehicle ID:","",-1))] = 0;
			}
			if(ShuttleInactivityCounter[(strings.Replace(result["id"], "Vehicle ID:","",-1))] > 0){
				update.Speed = "-1";
			}

			if err := App.Updates.Insert(&update); err != nil {
				log.Errorf("error inserting vehicle update(%v): %v", update, err)
			} else {
				updated++
			}

			// here if parsing error, updated will be incremented, wait, the whole thing will crash, isn't it?
		}
		log.Infof("sucessfully updated %d/%d vehicles", updated, len(vehiclesData)-1)
	}
}

// VehiclesHandler finds all the vehicles in the database.
func (App *App) VehiclesHandler(w http.ResponseWriter, r *http.Request) {
	// Find all vehicles in database
	var vehicles []Vehicle
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Send each vehicle to client as JSON
	WriteJSON(w, vehicles)
}

// VehiclesCreateHandler adds a new vehicle to the database.
func (App *App) VehiclesCreateHandler(w http.ResponseWriter, r *http.Request) {
	// Create new vehicle object using request fields
	vehicle := Vehicle{}
	vehicle.Created = time.Now()
	vehicle.Updated = time.Now()
	vehicleData := json.NewDecoder(r.Body)
	err := vehicleData.Decode(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Store new vehicle under vehicles collection
	err = App.Vehicles.Insert(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (App *App) VehiclesEditHandler(w http.ResponseWriter, r *http.Request) {

}

func (App *App) VehiclesDeleteHandler(w http.ResponseWriter, r *http.Request) {
	// Delete vehicle from Vehicles collection
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Vehicles.Remove(bson.M{"vehicleID": vars["id"]})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Here's my view, keep every name the same meaning, otherwise, choose another.
// UpdatesHandler get the most recent update for each vehicle in the vehicles collection.
func (App *App) UpdatesHandler(w http.ResponseWriter, r *http.Request) {
	// Store updates for each vehicle
	var vehicles []Vehicle
	var updates []VehicleUpdate
	var update VehicleUpdate
	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates for each vehicle
	for _, vehicle := range vehicles {
		// here, huge waste of computational power, you record every shit inside the Updates table and using sort, I don't know what the hell is going on
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)

		if err == nil {
			updates = append(updates, update)
		}
	}
	// Convert updates to JSON
	WriteJSON(w, updates) // it's good to take some REST in our server :)
}

// UpdateMessageHandler generates a message about an update for a vehicle
func (App *App) UpdateMessageHandler(w http.ResponseWriter, r *http.Request) {
	// For each vehicle/update, store message as a string
	var messages []string
	var message string
	var vehicles []Vehicle
	var update VehicleUpdate

	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates and generate message
	for _, vehicle := range vehicles {
		// find 10 most recent records
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)
		if err == nil {
			// Use first 4 char substring of update.Speed
			speed := update.Speed
			if len(speed) > 4 {
				speed = speed[0:4]
			}
			//nextArrival := GetArrivalTime(&update, App.Routes, App.Stops)
			message = fmt.Sprintf("%s
Traveling %s at
 %s mph as of %s", vehicle.VehicleName, CardinalDirection(&update.Heading), speed, update.Created.Format("3:04PM")/*, nextArrival*/)
			messages = append(messages, message)
		}
	}
	// Convert to JSON
	WriteJSON(w, messages)
}

// CardinalDirection figures out the cardinal direction of a vehicle's heading
func CardinalDirection(h *string) string {
	heading, err := strconv.ParseFloat(*h, 64)
	if err != nil {
		fmt.Println("ERROR", err.Error())
		return "North"
	}
	switch {
	case (heading >= 22.5 && heading < 67.5):
		return "North-East"
	case (heading >= 67.5 && heading < 112.5):
		return "East"
	case (heading >= 112.5 && heading < 157.5):
		return "South-East"
	case (heading >= 157.5 && heading < 202.5):
		return "South"
	case (heading >= 202.5 && heading < 247.5):
		return "South-West"
	case (heading >= 247.5 && heading < 292.5):
		return "West"
	case (heading >= 292.5 && heading < 337.5):
		return "North-West"
	default:
		return "North"
	}
}
<commit_msg>changed inactive timeout to 5 minutes<commit_after>package tracking

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

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
)

//  represents a single position observed for a Vehicle from the data feed.
type VehicleUpdate struct {
	VehicleID string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	Lat       string    `json:"lat"         bson:"lat"`
	Lng       string    `json:"lng"         bson:"lng"`
	Heading   string    `json:"heading"     bson:"heading"`
	Speed     string    `json:"speed"       bson:"speed"`
	Lock      string    `json:"lock"        bson:"lock"`
	Time      string    `json:"time"        bson:"time"`
	Date      string    `json:"date"        bson:"date"`
	Status    string    `json:"status"      bson:"status"`
	Created   time.Time `json:"created"     bson:"created"`
	Segment   string    `json:"segment" bson:"segment"` // the segment that a vehicle resides on
}

// Vehicle represents an object being tracked.
type Vehicle struct {
	VehicleID   string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	VehicleName string    `json:"vehicleName" bson:"vehicleName"`
	Created     time.Time `bson:"created"`
	Updated     time.Time `bson:"updated"`
}

// Status contains a detailed message on the tracked object's status
type Status struct {
	Public  bool      `bson:"public"`
	Message string    `json:"message" bson:"message"`
	Created time.Time `bson:"created"`
	Updated time.Time `bson:"updated"`
}

var (
	// Match each API field with any number (+)
	//   of the previous expressions (\d digit, \. escaped period, - negative number)
	//   Specify named capturing groups to store each field from data feed
	dataRe    = regexp.MustCompile(`(?P<id>Vehicle ID:([\d\.]+)) (?P<lat>lat:([\d\.-]+)) (?P<lng>lon:([\d\.-]+)) (?P<heading>dir:([\d\.-]+)) (?P<speed>spd:([\d\.-]+)) (?P<lock>lck:([\d\.-]+)) (?P<time>time:([\d]+)) (?P<date>date:([\d]+)) (?P<status>trig:([\d]+))`)
	dataNames = dataRe.SubexpNames()
)

var ShuttleInactivityCounter = make(map[string]int);

// UpdateShuttles send a request to iTrak API, gets updated shuttle info, and
// finally store updated records in db.
func (App *App) UpdateShuttles(dataFeed string, updateInterval int) {
	var st time.Duration
	for {

		// Sleep for n seconds before updating again
		log.Debugf("sleeping for %v", st)
		time.Sleep(st)
		if st == 0 {
			// Initialize the sleep timer after the first sleep.  This lets us sleep during errors
			// when we 'continue' back to the top of the loop without waiting to sleep for the first
			// update run.
			st = time.Duration(updateInterval) * time.Second
		}

		// Make request to our tracking data feed
		resp, err := http.Get(dataFeed)
		if err != nil {
			log.Errorf("error getting data feed: %v", err)
			continue
		}
		defer resp.Body.Close()

		// Read response body content
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Errorf("error reading data feed: %v", err)
			continue
		}

		delim := "eof"
		// split the body of response by delimiter
		vehiclesData := strings.Split(string(body), delim)
		// BUG: if the request fails, it will give undefined result

		// TODO: Figure out if this handles == 1 vehicle correctly or always assumes > 1.
		if len(vehiclesData) <= 1 {
			log.Warnf("found no vehicles delineated by '%s'", delim)
		}

		updated := 0
		// for parsed data, update each vehicle
		for i := 0; i < len(vehiclesData)-1; i++ {
			match := dataRe.FindAllStringSubmatch(vehiclesData[i], -1)[0]
			// Store named capturing group and matching expression as a key value pair
			result := map[string]string{}
			for i, item := range match {
				result[dataNames[i]] = item
			}

			// Create new vehicle update & insert update into database
			// add computation of segment that the shuttle resides on and the arrival time to next N stops [here]

			update := VehicleUpdate{
				VehicleID: strings.Replace(result["id"], "Vehicle ID:", "", -1),
				Lat:       strings.Replace(result["lat"], "lat:", "", -1),
				Lng:       strings.Replace(result["lng"], "lon:", "", -1),
				Heading:   strings.Replace(result["heading"], "dir:", "", -1),
				Speed:     strings.Replace(result["speed"], "spd:", "", -1),
				Lock:      strings.Replace(result["lock"], "lck:", "", -1),
				Time:      strings.Replace(result["time"], "time:", "", -1),
				Date:      strings.Replace(result["date"], "date:", "", -1),
				Status:    strings.Replace(result["status"], "trig:", "", -1),
				Created:   time.Now()}

			//if a shuttle hasnt gone over 3 miles per hour in 5 minutes, it is probably inactive, and we shouldnt show it.
			spd, err := strconv.ParseFloat(update.Speed, 64)
			if(err != nil){
				log.Errorf("error finding speed");
			}
			if(spd < 3){
				ShuttleInactivityCounter[(strings.Replace(result["id"], "Vehicle ID:","",-1))] += 1;
				fmt.Printf(update.Status);
			}else{
					ShuttleInactivityCounter[(strings.Replace(result["id"], "Vehicle ID:","",-1))] = 0;
			}
			if(ShuttleInactivityCounter[(strings.Replace(result["id"], "Vehicle ID:","",-1))] > 20){
				update.Speed = "-1";
			}

			if err := App.Updates.Insert(&update); err != nil {
				log.Errorf("error inserting vehicle update(%v): %v", update, err)
			} else {
				updated++
			}

			// here if parsing error, updated will be incremented, wait, the whole thing will crash, isn't it?
		}
		log.Infof("sucessfully updated %d/%d vehicles", updated, len(vehiclesData)-1)
	}
}

// VehiclesHandler finds all the vehicles in the database.
func (App *App) VehiclesHandler(w http.ResponseWriter, r *http.Request) {
	// Find all vehicles in database
	var vehicles []Vehicle
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Send each vehicle to client as JSON
	WriteJSON(w, vehicles)
}

// VehiclesCreateHandler adds a new vehicle to the database.
func (App *App) VehiclesCreateHandler(w http.ResponseWriter, r *http.Request) {
	// Create new vehicle object using request fields
	vehicle := Vehicle{}
	vehicle.Created = time.Now()
	vehicle.Updated = time.Now()
	vehicleData := json.NewDecoder(r.Body)
	err := vehicleData.Decode(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Store new vehicle under vehicles collection
	err = App.Vehicles.Insert(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (App *App) VehiclesEditHandler(w http.ResponseWriter, r *http.Request) {

}

func (App *App) VehiclesDeleteHandler(w http.ResponseWriter, r *http.Request) {
	// Delete vehicle from Vehicles collection
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Vehicles.Remove(bson.M{"vehicleID": vars["id"]})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Here's my view, keep every name the same meaning, otherwise, choose another.
// UpdatesHandler get the most recent update for each vehicle in the vehicles collection.
func (App *App) UpdatesHandler(w http.ResponseWriter, r *http.Request) {
	// Store updates for each vehicle
	var vehicles []Vehicle
	var updates []VehicleUpdate
	var update VehicleUpdate
	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates for each vehicle
	for _, vehicle := range vehicles {
		// here, huge waste of computational power, you record every shit inside the Updates table and using sort, I don't know what the hell is going on
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)

		if err == nil {
			updates = append(updates, update)
		}
	}
	// Convert updates to JSON
	WriteJSON(w, updates) // it's good to take some REST in our server :)
}

// UpdateMessageHandler generates a message about an update for a vehicle
func (App *App) UpdateMessageHandler(w http.ResponseWriter, r *http.Request) {
	// For each vehicle/update, store message as a string
	var messages []string
	var message string
	var vehicles []Vehicle
	var update VehicleUpdate

	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates and generate message
	for _, vehicle := range vehicles {
		// find 10 most recent records
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)
		if err == nil {
			// Use first 4 char substring of update.Speed
			speed := update.Speed
			if len(speed) > 4 {
				speed = speed[0:4]
			}
			//nextArrival := GetArrivalTime(&update, App.Routes, App.Stops)
			message = fmt.Sprintf("%s
Traveling %s at
 %s mph as of %s", vehicle.VehicleName, CardinalDirection(&update.Heading), speed, update.Created.Format("3:04PM")/*, nextArrival*/)
			messages = append(messages, message)
		}
	}
	// Convert to JSON
	WriteJSON(w, messages)
}

// CardinalDirection figures out the cardinal direction of a vehicle's heading
func CardinalDirection(h *string) string {
	heading, err := strconv.ParseFloat(*h, 64)
	if err != nil {
		fmt.Println("ERROR", err.Error())
		return "North"
	}
	switch {
	case (heading >= 22.5 && heading < 67.5):
		return "North-East"
	case (heading >= 67.5 && heading < 112.5):
		return "East"
	case (heading >= 112.5 && heading < 157.5):
		return "South-East"
	case (heading >= 157.5 && heading < 202.5):
		return "South"
	case (heading >= 202.5 && heading < 247.5):
		return "South-West"
	case (heading >= 247.5 && heading < 292.5):
		return "West"
	case (heading >= 292.5 && heading < 337.5):
		return "North-West"
	default:
		return "North"
	}
}
<|endoftext|>