<commit_before>package controllers

import (
	"crypto/sha1"
	"encoding/xml"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/missdeer/KellyWechat/models"
	"io/ioutil"
	"regexp"
	"sort"
	"strings"
	"time"
)

var (
	TOKEN = "yiiliwechattoken"
)

type MainController struct {
	beego.Controller
}

func (this *MainController) Get() {
	signature := this.Input().Get("signature")
	beego.Info("signature:" + signature)
	timestamp := this.Input().Get("timestamp")
	beego.Info("timestamp:" + timestamp)
	nonce := this.Input().Get("nonce")
	beego.Info("nonce:" + nonce)
	echostr := this.Input().Get("echostr")
	beego.Info("echostr:" + echostr)
	beego.Info(Signature(timestamp, nonce))
	if Signature(timestamp, nonce) == signature {
		beego.Info("signature matched")
		this.Ctx.WriteString(echostr)
	} else {
		beego.Info("signature not matched")
		this.Ctx.WriteString("")
	}
}

func (this *MainController) Post() {
	body, err := ioutil.ReadAll(this.Ctx.Request.Body)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(string(body))
	var wreq *models.Request
	if wreq, err = DecodeRequest(body); err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(wreq.Content)
	wresp, err := dealwith(wreq)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	data, err := wresp.Encode()
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	this.Ctx.WriteString(string(data))
	return
}

func dealwith(req *models.Request) (resp *models.Response, err error) {
	resp = NewResponse()
	resp.ToUserName = req.FromUserName
	resp.FromUserName = req.ToUserName
	resp.MsgType = models.Text
	beego.Info(req.MsgType)
	beego.Info(req.Content)
	if req.MsgType == models.Text {
		userInputText := strings.Trim(strings.ToLower(req.Content), " ")
		switch userInputText {
		case "help", `帮助`:
			models.Help(req, resp)
		case "wd", `微店`:
			models.WeiDian(req, resp)
		case "mm", `面膜`:
			models.FacialMask(req, resp)
		case "nv", "yf", "yifu", `女装`, `衣服`:
			models.Clothes(req, resp)
		default:
			matched, err := regexp.MatchString("[0-9]+", userInputText)
			if err == nil && matched == true {
				models.ItemId(req, resp)
				break
			}
			if strings.HasPrefix(userInputText, `wz`) ||
				strings.HasPrefix(userInputText, `文章`) ||
				strings.HasPrefix(userInputText, `article`) {
				models.Article(req, resp)
				break
			}
			resp.Content = "衣丽已经很努力地在学习了，但仍然不能理解您的需求，请您输入help查看衣丽能懂的一些命令吧:("
		}
	} else {
		resp.Content = "暂时还不支持其他的命令类型，请输入help查看说明。"
	}
	return resp, nil
}

func Signature(timestamp, nonce string) string {
	strs := sort.StringSlice{TOKEN, timestamp, nonce}
	sort.Strings(strs)
	str := ""
	for _, s := range strs {
		str += s
	}
	h := sha1.New()
	h.Write([]byte(str))
	return fmt.Sprintf("%x", h.Sum(nil))
}

func DecodeRequest(data []byte) (req *models.Request, err error) {
	req = &models.Request{}
	if err = xml.Unmarshal(data, req); err != nil {
		return
	}
	req.CreateTime *= time.Second
	return
}

func NewResponse() (resp *models.Response) {
	resp = &models.Response{}
	resp.CreateTime = time.Duration(time.Now().Unix())
	return
}
<commit_msg>(*)fixed build error<commit_after>package controllers

import (
	"crypto/sha1"
	"encoding/xml"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/missdeer/KellyWechat/models"
	"io/ioutil"
	"regexp"
	"sort"
	"strings"
	"time"
)

var (
	TOKEN = "yiiliwechattoken"
)

type MainController struct {
	beego.Controller
}

func (this *MainController) Get() {
	signature := this.Input().Get("signature")
	beego.Info("signature:" + signature)
	timestamp := this.Input().Get("timestamp")
	beego.Info("timestamp:" + timestamp)
	nonce := this.Input().Get("nonce")
	beego.Info("nonce:" + nonce)
	echostr := this.Input().Get("echostr")
	beego.Info("echostr:" + echostr)
	beego.Info(Signature(timestamp, nonce))
	if Signature(timestamp, nonce) == signature {
		beego.Info("signature matched")
		this.Ctx.WriteString(echostr)
	} else {
		beego.Info("signature not matched")
		this.Ctx.WriteString("")
	}
}

func (this *MainController) Post() {
	body, err := ioutil.ReadAll(this.Ctx.Request.Body)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(string(body))
	var wreq *models.Request
	if wreq, err = DecodeRequest(body); err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(wreq.Content)
	wresp, err := dealwith(wreq)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	data, err := wresp.Encode()
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	this.Ctx.WriteString(string(data))
	return
}

func dealwith(req *models.Request) (resp *models.Response, err error) {
	resp = NewResponse()
	resp.ToUserName = req.FromUserName
	resp.FromUserName = req.ToUserName
	resp.MsgType = models.Text
	beego.Info(req.MsgType)
	beego.Info(req.Content)
	if req.MsgType == models.Text {
		userInputText := strings.Trim(strings.ToLower(req.Content), " ")
		switch userInputText {
		case "help", `帮助`:
			models.Help(req, resp)
		case "wd", `微店`:
			models.WeiDian(req, resp)
		case "mm", `面膜`:
			models.FacialMask(req, resp)
		case "nv", "yf", "yifu", `女装`, `衣服`:
			models.Clothes(req, resp)
		default:
			matched, err := regexp.MatchString("[0-9]+", userInputText)
			if err == nil && matched == true {
				models.ItemId(req, resp)
				break
			}
			if strings.HasPrefix(userInputText, `wz`) ||
				strings.HasPrefix(userInputText, `文章`) ||
				strings.HasPrefix(userInputText, `article`) {
				models.Articles(req, resp)
				break
			}
			resp.Content = "衣丽已经很努力地在学习了，但仍然不能理解您的需求，请您输入help查看衣丽能懂的一些命令吧:("
		}
	} else {
		resp.Content = "暂时还不支持其他的命令类型，请输入help查看说明。"
	}
	return resp, nil
}

func Signature(timestamp, nonce string) string {
	strs := sort.StringSlice{TOKEN, timestamp, nonce}
	sort.Strings(strs)
	str := ""
	for _, s := range strs {
		str += s
	}
	h := sha1.New()
	h.Write([]byte(str))
	return fmt.Sprintf("%x", h.Sum(nil))
}

func DecodeRequest(data []byte) (req *models.Request, err error) {
	req = &models.Request{}
	if err = xml.Unmarshal(data, req); err != nil {
		return
	}
	req.CreateTime *= time.Second
	return
}

func NewResponse() (resp *models.Response) {
	resp = &models.Response{}
	resp.CreateTime = time.Duration(time.Now().Unix())
	return
}
<|endoftext|>


<commit_before>package controllers

import (
	"crypto/sha1"
	"encoding/xml"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/missdeer/KellyWechat/models"
	"io/ioutil"
	"regexp"
	"sort"
	"strings"
	"time"
)

var (
	TOKEN = "yiiliwechattoken"
)

type MainController struct {
	beego.Controller
}

func (this *MainController) Get() {
	signature := this.Input().Get("signature")
	beego.Info("signature:" + signature)
	timestamp := this.Input().Get("timestamp")
	beego.Info("timestamp:" + timestamp)
	nonce := this.Input().Get("nonce")
	beego.Info("nonce:" + nonce)
	echostr := this.Input().Get("echostr")
	beego.Info("echostr:" + echostr)
	beego.Info(Signature(timestamp, nonce))
	if Signature(timestamp, nonce) == signature {
		beego.Info("signature matched")
		this.Ctx.WriteString(echostr)
	} else {
		beego.Info("signature not matched")
		this.Ctx.WriteString("")
	}
}

func (this *MainController) Post() {
	body, err := ioutil.ReadAll(this.Ctx.Request.Body)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(string(body))
	var wreq *models.Request
	if wreq, err = DecodeRequest(body); err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(wreq.Content)
	wresp, err := dealwith(wreq)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	data, err := wresp.Encode()
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	this.Ctx.WriteString(string(data))
	return
}

func dealwith(req *models.Request) (resp *models.Response, err error) {
	resp = NewResponse()
	resp.ToUserName = req.FromUserName
	resp.FromUserName = req.ToUserName
	resp.MsgType = models.Text
	beego.Info(req.MsgType)
	beego.Info(req.Content)
	if req.MsgType == models.Text {
		userInputText := strings.Trim(strings.ToLower(req.Content), " ")
		if userInputText == "help" || userInputText == `帮助` {
			models.Help(req, resp)
			return resp, nil
		}
		if userInputText == "wd" || userInputText == `微店` {
			models.WeiDian(req, resp)
			return resp, nil
		}
		if userInputText == "mm" || userInputText == `面膜` {
			models.FacialMask(req, resp)
			return resp, nil
		}
		matched, err := regexp.MatchString("[0-9]+", userInputText)
		if err == nil && matched == true {
			models.ItemId(req, resp)
			return resp, nil
		}

		resp.Content = "衣丽已经很努力地在学习了，但仍然不能理解您的需求，请您输入help查看衣丽能懂的一些命令吧:("
	} else {
		resp.Content = "暂时还不支持其他的命令类型，请输入help查看说明。"
	}
	return resp, nil
}

func Signature(timestamp, nonce string) string {
	strs := sort.StringSlice{TOKEN, timestamp, nonce}
	sort.Strings(strs)
	str := ""
	for _, s := range strs {
		str += s
	}
	h := sha1.New()
	h.Write([]byte(str))
	return fmt.Sprintf("%x", h.Sum(nil))
}

func DecodeRequest(data []byte) (req *models.Request, err error) {
	req = &models.Request{}
	if err = xml.Unmarshal(data, req); err != nil {
		return
	}
	req.CreateTime *= time.Second
	return
}

func NewResponse() (resp *models.Response) {
	resp = &models.Response{}
	resp.CreateTime = time.Duration(time.Now().Unix())
	return
}
<commit_msg>(*)use switch-case instead of if-else<commit_after>package controllers

import (
	"crypto/sha1"
	"encoding/xml"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/missdeer/KellyWechat/models"
	"io/ioutil"
	"regexp"
	"sort"
	"strings"
	"time"
)

var (
	TOKEN = "yiiliwechattoken"
)

type MainController struct {
	beego.Controller
}

func (this *MainController) Get() {
	signature := this.Input().Get("signature")
	beego.Info("signature:" + signature)
	timestamp := this.Input().Get("timestamp")
	beego.Info("timestamp:" + timestamp)
	nonce := this.Input().Get("nonce")
	beego.Info("nonce:" + nonce)
	echostr := this.Input().Get("echostr")
	beego.Info("echostr:" + echostr)
	beego.Info(Signature(timestamp, nonce))
	if Signature(timestamp, nonce) == signature {
		beego.Info("signature matched")
		this.Ctx.WriteString(echostr)
	} else {
		beego.Info("signature not matched")
		this.Ctx.WriteString("")
	}
}

func (this *MainController) Post() {
	body, err := ioutil.ReadAll(this.Ctx.Request.Body)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(string(body))
	var wreq *models.Request
	if wreq, err = DecodeRequest(body); err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	beego.Info(wreq.Content)
	wresp, err := dealwith(wreq)
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	data, err := wresp.Encode()
	if err != nil {
		beego.Error(err)
		this.Ctx.ResponseWriter.WriteHeader(500)
		return
	}
	this.Ctx.WriteString(string(data))
	return
}

func dealwith(req *models.Request) (resp *models.Response, err error) {
	resp = NewResponse()
	resp.ToUserName = req.FromUserName
	resp.FromUserName = req.ToUserName
	resp.MsgType = models.Text
	beego.Info(req.MsgType)
	beego.Info(req.Content)
	if req.MsgType == models.Text {
		userInputText := strings.Trim(strings.ToLower(req.Content), " ")
		switch userInputText {
		case "help", `帮助`:
			models.Help(req, resp)
			return resp, nil
		case "wd", `微店`:
			models.WeiDian(req, resp)
			return resp, nil
		case "mm", `面膜`:
			models.FacialMask(req, resp)
			return resp, nil
		default:
			matched, err := regexp.MatchString("[0-9]+", userInputText)
			if err == nil && matched == true {
				models.ItemId(req, resp)
				return resp, nil
			}
		}

		resp.Content = "衣丽已经很努力地在学习了，但仍然不能理解您的需求，请您输入help查看衣丽能懂的一些命令吧:("
	} else {
		resp.Content = "暂时还不支持其他的命令类型，请输入help查看说明。"
	}
	return resp, nil
}

func Signature(timestamp, nonce string) string {
	strs := sort.StringSlice{TOKEN, timestamp, nonce}
	sort.Strings(strs)
	str := ""
	for _, s := range strs {
		str += s
	}
	h := sha1.New()
	h.Write([]byte(str))
	return fmt.Sprintf("%x", h.Sum(nil))
}

func DecodeRequest(data []byte) (req *models.Request, err error) {
	req = &models.Request{}
	if err = xml.Unmarshal(data, req); err != nil {
		return
	}
	req.CreateTime *= time.Second
	return
}

func NewResponse() (resp *models.Response) {
	resp = &models.Response{}
	resp.CreateTime = time.Duration(time.Now().Unix())
	return
}
<|endoftext|>


<commit_before>package consul

import (
	"fmt"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/consul/state"
	"github.com/hashicorp/consul/consul/structs"
	"github.com/hashicorp/go-memdb"
	"github.com/hashicorp/go-uuid"
)

// Session endpoint is used to manipulate sessions for KV
type Session struct {
	srv *Server
}

// Apply is used to apply a modifying request to the data store. This should
// only be used for operations that modify the data
func (s *Session) Apply(args *structs.SessionRequest, reply *string) error {
	if done, err := s.srv.forward("Session.Apply", args, args, reply); done {
		return err
	}
	defer metrics.MeasureSince([]string{"consul", "session", "apply"}, time.Now())

	// Verify the args
	if args.Session.ID == "" && args.Op == structs.SessionDestroy {
		return fmt.Errorf("Must provide ID")
	}
	if args.Session.Node == "" && args.Op == structs.SessionCreate {
		return fmt.Errorf("Must provide Node")
	}

	// Fetch the ACL token, if any, and apply the policy.
	acl, err := s.srv.resolveToken(args.Token)
	if err != nil {
		return err
	}
	if acl != nil && s.srv.config.ACLEnforceVersion8 {
		switch args.Op {
		case structs.SessionDestroy:
			state := s.srv.fsm.State()
			_, existing, err := state.SessionGet(nil, args.Session.ID)
			if err != nil {
				return fmt.Errorf("Unknown session %q", args.Session.ID)
			}
			if !acl.SessionWrite(existing.Node) {
				return permissionDeniedErr
			}

		case structs.SessionCreate:
			if !acl.SessionWrite(args.Session.Node) {
				return permissionDeniedErr
			}

		default:
			return fmt.Errorf("Invalid session operation %q", args.Op)
		}
	}

	// Ensure that the specified behavior is allowed
	switch args.Session.Behavior {
	case "":
		// Default behavior to Release for backwards compatibility
		args.Session.Behavior = structs.SessionKeysRelease
	case structs.SessionKeysRelease:
	case structs.SessionKeysDelete:
	default:
		return fmt.Errorf("Invalid Behavior setting '%s'", args.Session.Behavior)
	}

	// Ensure the Session TTL is valid if provided
	if args.Session.TTL != "" {
		ttl, err := time.ParseDuration(args.Session.TTL)
		if err != nil {
			return fmt.Errorf("Session TTL '%s' invalid: %v", args.Session.TTL, err)
		}

		if ttl != 0 && (ttl < s.srv.config.SessionTTLMin || ttl > structs.SessionTTLMax) {
			return fmt.Errorf("Invalid Session TTL '%d', must be between [%v=%v]",
				ttl, s.srv.config.SessionTTLMin, structs.SessionTTLMax)
		}
	}

	// If this is a create, we must generate the Session ID. This must
	// be done prior to appending to the raft log, because the ID is not
	// deterministic. Once the entry is in the log, the state update MUST
	// be deterministic or the followers will not converge.
	if args.Op == structs.SessionCreate {
		// Generate a new session ID, verify uniqueness
		state := s.srv.fsm.State()
		for {
			var err error
			if args.Session.ID, err = uuid.GenerateUUID(); err != nil {
				s.srv.logger.Printf("[ERR] consul.session: UUID generation failed: %v", err)
				return err
			}
			_, sess, err := state.SessionGet(nil, args.Session.ID)
			if err != nil {
				s.srv.logger.Printf("[ERR] consul.session: Session lookup failed: %v", err)
				return err
			}
			if sess == nil {
				break
			}
		}
	}

	// Apply the update
	resp, err := s.srv.raftApply(structs.SessionRequestType, args)
	if err != nil {
		s.srv.logger.Printf("[ERR] consul.session: Apply failed: %v", err)
		return err
	}

	if args.Op == structs.SessionCreate && args.Session.TTL != "" {
		// If we created a session with a TTL, reset the expiration timer
		s.srv.resetSessionTimer(args.Session.ID, &args.Session)
	} else if args.Op == structs.SessionDestroy {
		// If we destroyed a session, it might potentially have a TTL,
		// and we need to clear the timer
		s.srv.clearSessionTimer(args.Session.ID)
	}

	if respErr, ok := resp.(error); ok {
		return respErr
	}

	// Check if the return type is a string
	if respString, ok := resp.(string); ok {
		*reply = respString
	}
	return nil
}

// Get is used to retrieve a single session
func (s *Session) Get(args *structs.SessionSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.Get", args, args, reply); done {
		return err
	}

	return s.srv.blockingQuery(
		&args.QueryOptions,
		&reply.QueryMeta,
		func(ws memdb.WatchSet, state *state.StateStore) error {
			index, session, err := state.SessionGet(ws, args.Session)
			if err != nil {
				return err
			}

			reply.Index = index
			if session != nil {
				reply.Sessions = structs.Sessions{session}
			} else {
				reply.Sessions = nil
			}
			if err := s.srv.filterACL(args.Token, reply); err != nil {
				return err
			}
			return nil
		})
}

// List is used to list all the active sessions
func (s *Session) List(args *structs.DCSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.List", args, args, reply); done {
		return err
	}

	return s.srv.blockingQuery(
		&args.QueryOptions,
		&reply.QueryMeta,
		func(ws memdb.WatchSet, state *state.StateStore) error {
			index, sessions, err := state.SessionList(ws)
			if err != nil {
				return err
			}

			reply.Index, reply.Sessions = index, sessions
			if err := s.srv.filterACL(args.Token, reply); err != nil {
				return err
			}
			return nil
		})
}

// NodeSessions is used to get all the sessions for a particular node
func (s *Session) NodeSessions(args *structs.NodeSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.NodeSessions", args, args, reply); done {
		return err
	}

	return s.srv.blockingQuery(
		&args.QueryOptions,
		&reply.QueryMeta,
		func(ws memdb.WatchSet, state *state.StateStore) error {
			index, sessions, err := state.NodeSessions(ws, args.Node)
			if err != nil {
				return err
			}

			reply.Index, reply.Sessions = index, sessions
			if err := s.srv.filterACL(args.Token, reply); err != nil {
				return err
			}
			return nil
		})
}

// Renew is used to renew the TTL on a single session
func (s *Session) Renew(args *structs.SessionSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.Renew", args, args, reply); done {
		return err
	}
	defer metrics.MeasureSince([]string{"consul", "session", "renew"}, time.Now())

	// Get the session, from local state.
	state := s.srv.fsm.State()
	index, session, err := state.SessionGet(nil, args.Session)
	if err != nil {
		return err
	}

	reply.Index = index
	if session == nil {
		return nil
	}

	// Fetch the ACL token, if any, and apply the policy.
	acl, err := s.srv.resolveToken(args.Token)
	if err != nil {
		return err
	}
	if acl != nil && s.srv.config.ACLEnforceVersion8 {
		if !acl.SessionWrite(session.Node) {
			return permissionDeniedErr
		}
	}

	// Reset the session TTL timer.
	reply.Sessions = structs.Sessions{session}
	if err := s.srv.resetSessionTimer(args.Session, session); err != nil {
		s.srv.logger.Printf("[ERR] consul.session: Session renew failed: %v", err)
		return err
	}

	return nil
}
<commit_msg>Adds guard in session ACL check in case session is not found.<commit_after>package consul

import (
	"fmt"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/consul/state"
	"github.com/hashicorp/consul/consul/structs"
	"github.com/hashicorp/go-memdb"
	"github.com/hashicorp/go-uuid"
)

// Session endpoint is used to manipulate sessions for KV
type Session struct {
	srv *Server
}

// Apply is used to apply a modifying request to the data store. This should
// only be used for operations that modify the data
func (s *Session) Apply(args *structs.SessionRequest, reply *string) error {
	if done, err := s.srv.forward("Session.Apply", args, args, reply); done {
		return err
	}
	defer metrics.MeasureSince([]string{"consul", "session", "apply"}, time.Now())

	// Verify the args
	if args.Session.ID == "" && args.Op == structs.SessionDestroy {
		return fmt.Errorf("Must provide ID")
	}
	if args.Session.Node == "" && args.Op == structs.SessionCreate {
		return fmt.Errorf("Must provide Node")
	}

	// Fetch the ACL token, if any, and apply the policy.
	acl, err := s.srv.resolveToken(args.Token)
	if err != nil {
		return err
	}
	if acl != nil && s.srv.config.ACLEnforceVersion8 {
		switch args.Op {
		case structs.SessionDestroy:
			state := s.srv.fsm.State()
			_, existing, err := state.SessionGet(nil, args.Session.ID)
			if err != nil {
				return fmt.Errorf("Session lookup failed: %v", err)
			}
			if existing == nil {
				return fmt.Errorf("Unknown session %q", args.Session.ID)
			}
			if !acl.SessionWrite(existing.Node) {
				return permissionDeniedErr
			}

		case structs.SessionCreate:
			if !acl.SessionWrite(args.Session.Node) {
				return permissionDeniedErr
			}

		default:
			return fmt.Errorf("Invalid session operation %q", args.Op)
		}
	}

	// Ensure that the specified behavior is allowed
	switch args.Session.Behavior {
	case "":
		// Default behavior to Release for backwards compatibility
		args.Session.Behavior = structs.SessionKeysRelease
	case structs.SessionKeysRelease:
	case structs.SessionKeysDelete:
	default:
		return fmt.Errorf("Invalid Behavior setting '%s'", args.Session.Behavior)
	}

	// Ensure the Session TTL is valid if provided
	if args.Session.TTL != "" {
		ttl, err := time.ParseDuration(args.Session.TTL)
		if err != nil {
			return fmt.Errorf("Session TTL '%s' invalid: %v", args.Session.TTL, err)
		}

		if ttl != 0 && (ttl < s.srv.config.SessionTTLMin || ttl > structs.SessionTTLMax) {
			return fmt.Errorf("Invalid Session TTL '%d', must be between [%v=%v]",
				ttl, s.srv.config.SessionTTLMin, structs.SessionTTLMax)
		}
	}

	// If this is a create, we must generate the Session ID. This must
	// be done prior to appending to the raft log, because the ID is not
	// deterministic. Once the entry is in the log, the state update MUST
	// be deterministic or the followers will not converge.
	if args.Op == structs.SessionCreate {
		// Generate a new session ID, verify uniqueness
		state := s.srv.fsm.State()
		for {
			var err error
			if args.Session.ID, err = uuid.GenerateUUID(); err != nil {
				s.srv.logger.Printf("[ERR] consul.session: UUID generation failed: %v", err)
				return err
			}
			_, sess, err := state.SessionGet(nil, args.Session.ID)
			if err != nil {
				s.srv.logger.Printf("[ERR] consul.session: Session lookup failed: %v", err)
				return err
			}
			if sess == nil {
				break
			}
		}
	}

	// Apply the update
	resp, err := s.srv.raftApply(structs.SessionRequestType, args)
	if err != nil {
		s.srv.logger.Printf("[ERR] consul.session: Apply failed: %v", err)
		return err
	}

	if args.Op == structs.SessionCreate && args.Session.TTL != "" {
		// If we created a session with a TTL, reset the expiration timer
		s.srv.resetSessionTimer(args.Session.ID, &args.Session)
	} else if args.Op == structs.SessionDestroy {
		// If we destroyed a session, it might potentially have a TTL,
		// and we need to clear the timer
		s.srv.clearSessionTimer(args.Session.ID)
	}

	if respErr, ok := resp.(error); ok {
		return respErr
	}

	// Check if the return type is a string
	if respString, ok := resp.(string); ok {
		*reply = respString
	}
	return nil
}

// Get is used to retrieve a single session
func (s *Session) Get(args *structs.SessionSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.Get", args, args, reply); done {
		return err
	}

	return s.srv.blockingQuery(
		&args.QueryOptions,
		&reply.QueryMeta,
		func(ws memdb.WatchSet, state *state.StateStore) error {
			index, session, err := state.SessionGet(ws, args.Session)
			if err != nil {
				return err
			}

			reply.Index = index
			if session != nil {
				reply.Sessions = structs.Sessions{session}
			} else {
				reply.Sessions = nil
			}
			if err := s.srv.filterACL(args.Token, reply); err != nil {
				return err
			}
			return nil
		})
}

// List is used to list all the active sessions
func (s *Session) List(args *structs.DCSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.List", args, args, reply); done {
		return err
	}

	return s.srv.blockingQuery(
		&args.QueryOptions,
		&reply.QueryMeta,
		func(ws memdb.WatchSet, state *state.StateStore) error {
			index, sessions, err := state.SessionList(ws)
			if err != nil {
				return err
			}

			reply.Index, reply.Sessions = index, sessions
			if err := s.srv.filterACL(args.Token, reply); err != nil {
				return err
			}
			return nil
		})
}

// NodeSessions is used to get all the sessions for a particular node
func (s *Session) NodeSessions(args *structs.NodeSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.NodeSessions", args, args, reply); done {
		return err
	}

	return s.srv.blockingQuery(
		&args.QueryOptions,
		&reply.QueryMeta,
		func(ws memdb.WatchSet, state *state.StateStore) error {
			index, sessions, err := state.NodeSessions(ws, args.Node)
			if err != nil {
				return err
			}

			reply.Index, reply.Sessions = index, sessions
			if err := s.srv.filterACL(args.Token, reply); err != nil {
				return err
			}
			return nil
		})
}

// Renew is used to renew the TTL on a single session
func (s *Session) Renew(args *structs.SessionSpecificRequest,
	reply *structs.IndexedSessions) error {
	if done, err := s.srv.forward("Session.Renew", args, args, reply); done {
		return err
	}
	defer metrics.MeasureSince([]string{"consul", "session", "renew"}, time.Now())

	// Get the session, from local state.
	state := s.srv.fsm.State()
	index, session, err := state.SessionGet(nil, args.Session)
	if err != nil {
		return err
	}

	reply.Index = index
	if session == nil {
		return nil
	}

	// Fetch the ACL token, if any, and apply the policy.
	acl, err := s.srv.resolveToken(args.Token)
	if err != nil {
		return err
	}
	if acl != nil && s.srv.config.ACLEnforceVersion8 {
		if !acl.SessionWrite(session.Node) {
			return permissionDeniedErr
		}
	}

	// Reset the session TTL timer.
	reply.Sessions = structs.Sessions{session}
	if err := s.srv.resetSessionTimer(args.Session, session); err != nil {
		s.srv.logger.Printf("[ERR] consul.session: Session renew failed: %v", err)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"errors"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/MJKWoolnough/byteio"
)

func setupServer(f *os.File, r *byteio.StickyReader, w *byteio.StickyWriter) error {
	stat, err := f.Stat()
	if err != nil {
		return err
	}
	zr, err := zip.NewReader(f, stat.Size())
	if err != nil {
		return err
	}
	w.WriteUint8(1)
	l := r.ReadUint8()
	name := make([]byte, l)
	r.Read(name)
	jars := make([]*zip.File, 0, 16)
	for _, file := range zr.File {
		if strings.HasSuffix(file.Name, ".jar") {
			jars = append(jars, file)
		}
	}
	d, err := setupServerDir()
	if len(jars) == 0 {
		err = os.Rename(f.Name(), path.Join(d, "server.jar"))
	} else {
		if len(jars) > 1 {
			w.WriteUint8(1)
			w.WriteInt16(int16(len(jars)))
			for _, jar := range jars {
				writeString(w, jar.Name)
			}
			p := r.ReadUint16()
			if int(p) >= len(jars) {
				err = ErrNoServer
			}
			jars[0] = jars[p]
		}
		if err == nil {
			err = unzip(zr, d)
			if err == nil {
				err = os.Rename(path.Join(d, jars[0].Name), path.Join(d, "server.jar"))
			}
		}
	}
	if err != nil {
		os.RemoveAll(d)
		return err
	}
	config.createServer(string(name), d)
	return nil
}

func setupServerDir() (string, error) {
	num := 0
	for {
		dir := path.Join(config.ServersDir, strconv.Itoa(num))
		err := os.MkdirAll(dir, 0777)
		if err == nil {
			return dir, nil
		}
		if !os.IsExist(err) {
			return "", err
		}
		num++
	}
}

// Errors
var (
	ErrNoName   = errors.New("no name received")
	ErrNoServer = errors.New("no server found")
)
<commit_msg>Added missing lt0 check<commit_after>package main

import (
	"archive/zip"
	"errors"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/MJKWoolnough/byteio"
)

func setupServer(f *os.File, r *byteio.StickyReader, w *byteio.StickyWriter) error {
	stat, err := f.Stat()
	if err != nil {
		return err
	}
	zr, err := zip.NewReader(f, stat.Size())
	if err != nil {
		return err
	}
	w.WriteUint8(1)
	l := r.ReadUint8()
	name := make([]byte, l)
	r.Read(name)
	jars := make([]*zip.File, 0, 16)
	for _, file := range zr.File {
		if strings.HasSuffix(file.Name, ".jar") {
			jars = append(jars, file)
		}
	}
	d, err := setupServerDir()
	if len(jars) == 0 {
		err = os.Rename(f.Name(), path.Join(d, "server.jar"))
	} else {
		if len(jars) > 1 {
			w.WriteUint8(1)
			w.WriteInt16(int16(len(jars)))
			for _, jar := range jars {
				writeString(w, jar.Name)
			}
			p := r.ReadUint16()
			if int(p) >= len(jars) || p < 0 {
				err = ErrNoServer
			}
			jars[0] = jars[p]
		}
		if err == nil {
			err = unzip(zr, d)
			if err == nil {
				err = os.Rename(path.Join(d, jars[0].Name), path.Join(d, "server.jar"))
			}
		}
	}
	if err != nil {
		os.RemoveAll(d)
		return err
	}
	config.createServer(string(name), d)
	return nil
}

func setupServerDir() (string, error) {
	num := 0
	for {
		dir := path.Join(config.ServersDir, strconv.Itoa(num))
		err := os.MkdirAll(dir, 0777)
		if err == nil {
			return dir, nil
		}
		if !os.IsExist(err) {
			return "", err
		}
		num++
	}
}

// Errors
var (
	ErrNoName   = errors.New("no name received")
	ErrNoServer = errors.New("no server found")
)
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. 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 prometheus provides a Prometheus-based implementation of the
// MetricFactory abstraction.
package prometheus

import (
	"fmt"
	"math"

	"github.com/golang/glog"
	"github.com/google/trillian/monitoring"
	"github.com/prometheus/client_golang/prometheus"
	dto "github.com/prometheus/client_model/go"
)

// MetricFactory allows the creation of Prometheus-based metrics.
type MetricFactory struct {
	Prefix string
}

// NewCounter creates a new Counter object backed by Prometheus.
func (pmf MetricFactory) NewCounter(name, help string, labelNames ...string) monitoring.Counter {
	if len(labelNames) == 0 {
		counter := prometheus.NewCounter(
			prometheus.CounterOpts{
				Name: pmf.Prefix + name,
				Help: help,
			})
		prometheus.MustRegister(counter)
		return &Counter{single: counter}
	}

	vec := prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: pmf.Prefix + name,
			Help: help,
		},
		labelNames)
	prometheus.MustRegister(vec)
	return &Counter{labelNames: labelNames, vec: vec}
}

// NewGauge creates a new Gauge object backed by Prometheus.
func (pmf MetricFactory) NewGauge(name, help string, labelNames ...string) monitoring.Gauge {
	if len(labelNames) == 0 {
		gauge := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Name: pmf.Prefix + name,
				Help: help,
			})
		prometheus.MustRegister(gauge)
		return &Gauge{single: gauge}
	}
	vec := prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: pmf.Prefix + name,
			Help: help,
		},
		labelNames)
	prometheus.MustRegister(vec)
	return &Gauge{labelNames: labelNames, vec: vec}
}

// buckets returns a reasonable range of histogram upper limits for most
// latency-in-seconds usecases.
func buckets() []float64 {
	// These parameters give an exponential range from 0.04 seconds to ~1 day.
	num := 300
	b := 1.05
	scale := 0.04

	r := make([]float64, 0, num)
	for i := range r {
		r = append(r, math.Pow(b, float64(i))*scale)
	}
	return r
}

// NewHistogram creates a new Histogram object backed by Prometheus.
func (pmf MetricFactory) NewHistogram(name, help string, labelNames ...string) monitoring.Histogram {
	if len(labelNames) == 0 {
		histogram := prometheus.NewHistogram(
			prometheus.HistogramOpts{
				Name:    pmf.Prefix + name,
				Help:    help,
				Buckets: buckets(),
			})
		prometheus.MustRegister(histogram)
		return &Histogram{single: histogram}
	}
	vec := prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    pmf.Prefix + name,
			Help:    help,
			Buckets: buckets(),
		},
		labelNames)
	prometheus.MustRegister(vec)
	return &Histogram{labelNames: labelNames, vec: vec}
}

// Counter is a wrapper around a Prometheus Counter or CounterVec object.
type Counter struct {
	labelNames []string
	single     prometheus.Counter
	vec        *prometheus.CounterVec
}

// Inc adds 1 to a counter.
func (m *Counter) Inc(labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Inc()
	} else {
		m.single.Inc()
	}
}

// Add adds the given amount to a counter.
func (m *Counter) Add(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Add(val)
	} else {
		m.single.Add(val)
	}
}

// Value returns the current amount of a counter.
func (m *Counter) Value(labelVals ...string) float64 {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return 0.0
	}
	var metric prometheus.Metric
	if m.vec != nil {
		metric = m.vec.With(labels)
	} else {
		metric = m.single
	}
	var metricpb dto.Metric
	if err := metric.Write(&metricpb); err != nil {
		glog.Errorf("failed to Write metric: %v", err)
		return 0.0
	}
	if metricpb.Counter == nil {
		glog.Errorf("counter field missing")
		return 0.0
	}
	return metricpb.Counter.GetValue()
}

// Gauge is a wrapper around a Prometheus Gauge or GaugeVec object.
type Gauge struct {
	labelNames []string
	single     prometheus.Gauge
	vec        *prometheus.GaugeVec
}

// Inc adds 1 to a gauge.
func (m *Gauge) Inc(labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Inc()
	} else {
		m.single.Inc()
	}
}

// Dec subtracts 1 from a gauge.
func (m *Gauge) Dec(labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Dec()
	} else {
		m.single.Dec()
	}
}

// Add adds given value to a gauge.
func (m *Gauge) Add(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Add(val)
	} else {
		m.single.Add(val)
	}
}

// Set sets the value of a gauge.
func (m *Gauge) Set(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Set(val)
	} else {
		m.single.Set(val)
	}
}

// Value returns the current amount of a gauge.
func (m *Gauge) Value(labelVals ...string) float64 {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return 0.0
	}
	var metric prometheus.Metric
	if m.vec != nil {
		metric = m.vec.With(labels)
	} else {
		metric = m.single
	}
	var metricpb dto.Metric
	if err := metric.Write(&metricpb); err != nil {
		glog.Errorf("failed to Write metric: %v", err)
		return 0.0
	}
	if metricpb.Gauge == nil {
		glog.Errorf("gauge field missing")
		return 0.0
	}
	return metricpb.Gauge.GetValue()
}

// Histogram is a wrapper around a Prometheus Histogram or HistogramVec object.
type Histogram struct {
	labelNames []string
	single     prometheus.Histogram
	vec        *prometheus.HistogramVec
}

// Observe adds a single observation to the histogram.
func (m *Histogram) Observe(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Observe(val)
	} else {
		m.single.Observe(val)
	}
}

// Info returns the count and sum of observations for the histogram.
func (m *Histogram) Info(labelVals ...string) (uint64, float64) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return 0, 0.0
	}
	var metric prometheus.Metric
	if m.vec != nil {
		metric = m.vec.With(labels).(prometheus.Metric)
	} else {
		metric = m.single
	}
	var metricpb dto.Metric
	if err := metric.Write(&metricpb); err != nil {
		glog.Errorf("failed to Write metric: %v", err)
		return 0, 0.0
	}
	histVal := metricpb.GetHistogram()
	if histVal == nil {
		glog.Errorf("histogram field missing")
		return 0, 0.0
	}
	return histVal.GetSampleCount(), histVal.GetSampleSum()
}

func labelsFor(names, values []string) (prometheus.Labels, error) {
	if len(names) != len(values) {
		return nil, fmt.Errorf("got %d (%v) values for %d labels (%v)", len(values), values, len(names), names)
	}
	if len(names) == 0 {
		return nil, nil
	}
	labels := make(prometheus.Labels)
	for i, name := range names {
		labels[name] = values[i]
	}
	return labels, nil
}
<commit_msg>Fix histogram buckets (#1081)<commit_after>// Copyright 2017 Google Inc. 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 prometheus provides a Prometheus-based implementation of the
// MetricFactory abstraction.
package prometheus

import (
	"fmt"
	"math"

	"github.com/golang/glog"
	"github.com/google/trillian/monitoring"
	"github.com/prometheus/client_golang/prometheus"
	dto "github.com/prometheus/client_model/go"
)

// MetricFactory allows the creation of Prometheus-based metrics.
type MetricFactory struct {
	Prefix string
}

// NewCounter creates a new Counter object backed by Prometheus.
func (pmf MetricFactory) NewCounter(name, help string, labelNames ...string) monitoring.Counter {
	if len(labelNames) == 0 {
		counter := prometheus.NewCounter(
			prometheus.CounterOpts{
				Name: pmf.Prefix + name,
				Help: help,
			})
		prometheus.MustRegister(counter)
		return &Counter{single: counter}
	}

	vec := prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: pmf.Prefix + name,
			Help: help,
		},
		labelNames)
	prometheus.MustRegister(vec)
	return &Counter{labelNames: labelNames, vec: vec}
}

// NewGauge creates a new Gauge object backed by Prometheus.
func (pmf MetricFactory) NewGauge(name, help string, labelNames ...string) monitoring.Gauge {
	if len(labelNames) == 0 {
		gauge := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Name: pmf.Prefix + name,
				Help: help,
			})
		prometheus.MustRegister(gauge)
		return &Gauge{single: gauge}
	}
	vec := prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: pmf.Prefix + name,
			Help: help,
		},
		labelNames)
	prometheus.MustRegister(vec)
	return &Gauge{labelNames: labelNames, vec: vec}
}

// buckets returns a reasonable range of histogram upper limits for most
// latency-in-seconds usecases.
func buckets() []float64 {
	// These parameters give an exponential range from 0.04 seconds to ~1 day.
	num := 300
	b := 1.05
	scale := 0.04

	r := make([]float64, 0, num)
	for i := 0; i < num; i++ {
		r = append(r, math.Pow(b, float64(i))*scale)
	}
	return r
}

// NewHistogram creates a new Histogram object backed by Prometheus.
func (pmf MetricFactory) NewHistogram(name, help string, labelNames ...string) monitoring.Histogram {
	if len(labelNames) == 0 {
		histogram := prometheus.NewHistogram(
			prometheus.HistogramOpts{
				Name:    pmf.Prefix + name,
				Help:    help,
				Buckets: buckets(),
			})
		prometheus.MustRegister(histogram)
		return &Histogram{single: histogram}
	}
	vec := prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Name:    pmf.Prefix + name,
			Help:    help,
			Buckets: buckets(),
		},
		labelNames)
	prometheus.MustRegister(vec)
	return &Histogram{labelNames: labelNames, vec: vec}
}

// Counter is a wrapper around a Prometheus Counter or CounterVec object.
type Counter struct {
	labelNames []string
	single     prometheus.Counter
	vec        *prometheus.CounterVec
}

// Inc adds 1 to a counter.
func (m *Counter) Inc(labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Inc()
	} else {
		m.single.Inc()
	}
}

// Add adds the given amount to a counter.
func (m *Counter) Add(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Add(val)
	} else {
		m.single.Add(val)
	}
}

// Value returns the current amount of a counter.
func (m *Counter) Value(labelVals ...string) float64 {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return 0.0
	}
	var metric prometheus.Metric
	if m.vec != nil {
		metric = m.vec.With(labels)
	} else {
		metric = m.single
	}
	var metricpb dto.Metric
	if err := metric.Write(&metricpb); err != nil {
		glog.Errorf("failed to Write metric: %v", err)
		return 0.0
	}
	if metricpb.Counter == nil {
		glog.Errorf("counter field missing")
		return 0.0
	}
	return metricpb.Counter.GetValue()
}

// Gauge is a wrapper around a Prometheus Gauge or GaugeVec object.
type Gauge struct {
	labelNames []string
	single     prometheus.Gauge
	vec        *prometheus.GaugeVec
}

// Inc adds 1 to a gauge.
func (m *Gauge) Inc(labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Inc()
	} else {
		m.single.Inc()
	}
}

// Dec subtracts 1 from a gauge.
func (m *Gauge) Dec(labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Dec()
	} else {
		m.single.Dec()
	}
}

// Add adds given value to a gauge.
func (m *Gauge) Add(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Add(val)
	} else {
		m.single.Add(val)
	}
}

// Set sets the value of a gauge.
func (m *Gauge) Set(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Set(val)
	} else {
		m.single.Set(val)
	}
}

// Value returns the current amount of a gauge.
func (m *Gauge) Value(labelVals ...string) float64 {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return 0.0
	}
	var metric prometheus.Metric
	if m.vec != nil {
		metric = m.vec.With(labels)
	} else {
		metric = m.single
	}
	var metricpb dto.Metric
	if err := metric.Write(&metricpb); err != nil {
		glog.Errorf("failed to Write metric: %v", err)
		return 0.0
	}
	if metricpb.Gauge == nil {
		glog.Errorf("gauge field missing")
		return 0.0
	}
	return metricpb.Gauge.GetValue()
}

// Histogram is a wrapper around a Prometheus Histogram or HistogramVec object.
type Histogram struct {
	labelNames []string
	single     prometheus.Histogram
	vec        *prometheus.HistogramVec
}

// Observe adds a single observation to the histogram.
func (m *Histogram) Observe(val float64, labelVals ...string) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return
	}
	if m.vec != nil {
		m.vec.With(labels).Observe(val)
	} else {
		m.single.Observe(val)
	}
}

// Info returns the count and sum of observations for the histogram.
func (m *Histogram) Info(labelVals ...string) (uint64, float64) {
	labels, err := labelsFor(m.labelNames, labelVals)
	if err != nil {
		glog.Error(err.Error())
		return 0, 0.0
	}
	var metric prometheus.Metric
	if m.vec != nil {
		metric = m.vec.With(labels).(prometheus.Metric)
	} else {
		metric = m.single
	}
	var metricpb dto.Metric
	if err := metric.Write(&metricpb); err != nil {
		glog.Errorf("failed to Write metric: %v", err)
		return 0, 0.0
	}
	histVal := metricpb.GetHistogram()
	if histVal == nil {
		glog.Errorf("histogram field missing")
		return 0, 0.0
	}
	return histVal.GetSampleCount(), histVal.GetSampleSum()
}

func labelsFor(names, values []string) (prometheus.Labels, error) {
	if len(names) != len(values) {
		return nil, fmt.Errorf("got %d (%v) values for %d labels (%v)", len(values), values, len(names), names)
	}
	if len(names) == 0 {
		return nil, nil
	}
	labels := make(prometheus.Labels)
	for i, name := range names {
		labels[name] = values[i]
	}
	return labels, nil
}
<|endoftext|>


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

package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/matm/go-cloudinary"
	"github.com/outofpluto/goconfig/config"
	"net/url"
	"os"
)

type Config struct {
	CloudinaryURI *url.URL
	MongoURI      *url.URL
}

var service *cloudinary.Service

// LoadConfig parses a config file and sets global settings
// variables to be used at runtime. Note that returning an error
// will cause the application to exit with code error 1.
func LoadConfig(path string) (*Config, error) {
	settings := &Config{}

	c, err := config.ReadDefault(path)
	if err != nil {
		return nil, err
	}

	// Cloudinary settings
	var cURI *url.URL
	var uri string

	if uri, err = c.String("cloudinary", "uri"); err != nil {
		return nil, err
	}
	if cURI, err = url.Parse(uri); err != nil {
		return nil, errors.New(fmt.Sprint("cloudinary URI: ", err.Error()))
	}
	settings.CloudinaryURI = cURI
	return settings, nil
}

func fatal(msg string) {
	fmt.Fprintf(os.Stderr, "Error: %s\n", msg)
	os.Exit(1)
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, fmt.Sprintf("Usage: %s [options] settings.conf \n", os.Args[0]))
		fmt.Fprintf(os.Stderr, `
Without any option supplied, it will read the config file and check
ressource (cloudinary, mongodb) availability.

`)
		fmt.Fprintf(os.Stderr, "Options:\n")
		flag.PrintDefaults()
		os.Exit(2)
	}

	uploadAsRaw := flag.String("uploadasraw", "", "path to the file or directory to upload as raw files")
	uploadAsImg := flag.String("uploadasimg", "", "path to the file or directory to upload as image files")
	deleteId := flag.String("drop", "", "delete remote file by upload_id")
	dropAll := flag.Bool("dropall", false, "delete all (images and raw) remote files")
	dropAllImages := flag.Bool("dropallimages", false, "delete all remote images files")
	dropAllRaws := flag.Bool("dropallraws", false, "delete all remote raw files")
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Fprint(os.Stderr, "Missing config file\n")
		flag.Usage()
	}

	settings, err := LoadConfig(flag.Arg(0))
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %s\n", flag.Arg(0), err.Error())
		os.Exit(1)
	}

	service, err = cloudinary.Dial(settings.CloudinaryURI.String())
	if err != nil {
		fatal(err.Error())
	}

	// Upload file
	if *uploadAsRaw != "" {
		fmt.Println("Uploading as raw data ...")
		if err := service.Upload(*uploadAsRaw, false, cloudinary.RawType); err != nil {
			fatal(err.Error())
		}
	} else if *uploadAsImg != "" {
		fmt.Println("Uploading as images ...")
		if err := service.Upload(*uploadAsImg, false, cloudinary.ImageType); err != nil {
			fatal(err.Error())
		}
	} else if *deleteId != "" {
		fmt.Printf("Deleting %s ...\n", *deleteId)
		if err := service.Delete(*deleteId, cloudinary.ImageType); err != nil {
			fatal(err.Error())
		}
	} else if *dropAll {
		fmt.Println("Drop all")
		if err := service.DropAll(os.Stdout); err != nil {
			fatal(err.Error())
		}
	} else if *dropAllImages {
		fmt.Println("Drop all images")
		if err := service.DropAllImages(os.Stdout); err != nil {
			fatal(err.Error())
		}
	} else if *dropAllRaws {
		fmt.Println("Drop all raw files")
		if err := service.DropAllRaws(os.Stdout); err != nil {
			fatal(err.Error())
		}
	}
}
<commit_msg>Explicitly drop raw or images from Cloudinary<commit_after>// Copyright 2013 Mathias Monnerville. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/matm/go-cloudinary"
	"github.com/outofpluto/goconfig/config"
	"net/url"
	"os"
)

type Config struct {
	CloudinaryURI *url.URL
	MongoURI      *url.URL
}

var service *cloudinary.Service

// LoadConfig parses a config file and sets global settings
// variables to be used at runtime. Note that returning an error
// will cause the application to exit with code error 1.
func LoadConfig(path string) (*Config, error) {
	settings := &Config{}

	c, err := config.ReadDefault(path)
	if err != nil {
		return nil, err
	}

	// Cloudinary settings
	var cURI *url.URL
	var uri string

	if uri, err = c.String("cloudinary", "uri"); err != nil {
		return nil, err
	}
	if cURI, err = url.Parse(uri); err != nil {
		return nil, errors.New(fmt.Sprint("cloudinary URI: ", err.Error()))
	}
	settings.CloudinaryURI = cURI
	return settings, nil
}

func fatal(msg string) {
	fmt.Fprintf(os.Stderr, "Error: %s\n", msg)
	os.Exit(1)
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, fmt.Sprintf("Usage: %s [options] settings.conf \n", os.Args[0]))
		fmt.Fprintf(os.Stderr, `
Without any option supplied, it will read the config file and check
ressource (cloudinary, mongodb) availability.

`)
		fmt.Fprintf(os.Stderr, "Options:\n")
		flag.PrintDefaults()
		os.Exit(2)
	}

	uploadAsRaw := flag.String("uploadasraw", "", "path to the file or directory to upload as raw files")
	uploadAsImg := flag.String("uploadasimg", "", "path to the file or directory to upload as image files")
	dropImg := flag.String("dropimg", "", "delete remote image by public_id")
	dropRaw := flag.String("dropraw", "", "delete remote raw file by public_id")
	dropAll := flag.Bool("dropall", false, "delete all (images and raw) remote files")
	dropAllImages := flag.Bool("dropallimages", false, "delete all remote images files")
	dropAllRaws := flag.Bool("dropallraws", false, "delete all remote raw files")
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Fprint(os.Stderr, "Missing config file\n")
		flag.Usage()
	}

	settings, err := LoadConfig(flag.Arg(0))
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %s\n", flag.Arg(0), err.Error())
		os.Exit(1)
	}

	service, err = cloudinary.Dial(settings.CloudinaryURI.String())
	if err != nil {
		fatal(err.Error())
	}

	// Upload file
	if *uploadAsRaw != "" {
		fmt.Println("Uploading as raw data ...")
		if err := service.Upload(*uploadAsRaw, false, cloudinary.RawType); err != nil {
			fatal(err.Error())
		}
	} else if *uploadAsImg != "" {
		fmt.Println("Uploading as images ...")
		if err := service.Upload(*uploadAsImg, false, cloudinary.ImageType); err != nil {
			fatal(err.Error())
		}
	} else if *dropImg != "" {
		fmt.Printf("Deleting image %s ...\n", *dropImg)
		if err := service.Delete(*dropImg, cloudinary.ImageType); err != nil {
			fatal(err.Error())
		}
	} else if *dropRaw != "" {
		fmt.Printf("Deleting raw file %s ...\n", *dropRaw)
		if err := service.Delete(*dropRaw, cloudinary.RawType); err != nil {
			fatal(err.Error())
		}
	} else if *dropAll {
		fmt.Println("Drop all")
		if err := service.DropAll(os.Stdout); err != nil {
			fatal(err.Error())
		}
	} else if *dropAllImages {
		fmt.Println("Drop all images")
		if err := service.DropAllImages(os.Stdout); err != nil {
			fatal(err.Error())
		}
	} else if *dropAllRaws {
		fmt.Println("Drop all raw files")
		if err := service.DropAllRaws(os.Stdout); err != nil {
			fatal(err.Error())
		}
	}
}
<|endoftext|>


<commit_before>// Copyright © 2012-2013, Greg Ward. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE.txt file.

package dag

import (
	"fmt"
	"os"
	"strings"

	"code.google.com/p/go-bit/bit"

	"fubsy/log"
)

type BuildState struct {
	dag     *DAG
	options BuildOptions
}

// user options, typically from the command line
type BuildOptions struct {
	// keep building even after one target fails (default: stop on
	// first failure)
	KeepGoing bool

	// pessimistically assume that someone might have modified
	// intermediate targets behind our back (default: check only
	// original sources)
	CheckAll bool
}

type BuildError struct {
	// nodes that failed to build
	failed []Node

	// total number of nodes that we attempted to build
	attempts int
}

// The heart of Fubsy: do a depth-first walk of the dependency graph
// to discover nodes in topological order, then (re)build nodes that
// are stale or missing. Skip target nodes that are "tainted" by
// upstream failure. Returns a single error object summarizing what
// (if anything) went wrong; error details are reported "live" as
// builds fail (e.g. to the console or a GUI window) so the user gets
// timely feedback.
func (self *BuildState) BuildTargets(targets NodeSet) error {
	// What sort of nodes do we check for changes?
	changestates := self.getChangeStates()
	//fmt.Printf("BuildTargets():\n")

	builderr := new(BuildError)
	visit := func(id int) error {
		node := self.dag.nodes[id]
		//fmt.Printf("  visiting node %d (%s)\n", id, node)
		if node.State() == SOURCE {
			// can't build original source nodes!
			return nil
		}

		checkInitialState(node)

		// do we need to build this node? can we?
		missing, stale, tainted, err :=
			self.inspectParents(changestates, id, node)
		//fmt.Printf("  missing=%v, stale=%v, tainted=%v, err=%v\n",
		//	missing, stale, tainted, err)
		if err != nil {
			return err
		}

		if tainted {
			node.SetState(TAINTED)
		} else if missing || stale {
			ok := self.buildNode(id, node, builderr)
			if !ok && !self.keepGoing() {
				// attempts counter is not very useful when we break
				// out of the build early
				builderr.attempts = -1
				return builderr
			}
		}
		return nil
	}
	err := self.dag.DFS(targets, visit)
	if err == nil && len(builderr.failed) > 0 {
		// build failures in keep-going mode
		err = builderr
	}
	return err
}

func (self *BuildState) getChangeStates() map[NodeState]bool {
	// Default is like tup: only check original source nodes and nodes
	// that have just been built.
	changestates := make(map[NodeState]bool)
	changestates[SOURCE] = true
	changestates[BUILT] = true
	if self.checkAll() {
		// Optional SCons-like behaviour: assume the user has been
		// sneaking around and modifying .o or .class files behind our
		// back and check everything. (N.B. this is unnecessary if the
		// user sneakily *removes* intermediate targets; that case
		// should be handled just fine by default.)
		changestates[UNKNOWN] = true
	}
	return changestates
}

// panic if node is in an impossible state for starting its visit
func checkInitialState(node Node) {
	if node.State() != UNKNOWN {
		// we just skipped SOURCE nodes, the other states are only set
		// while visiting a node, and we should only visit each node
		// once
		panic(fmt.Sprintf(
			"visiting node %v, state = %d (should be UNKNOWN = %d)",
			node, node.State(), UNKNOWN))
	}
}

// Inspect node and its parents to see if we need to build it. Return
// tainted=true if we should skip building this node due to upstream
// failure. Return stale=true if we should build this node because at
// least one of its parents has changed. Return missing=true if we
// should build this node because its resource is missing. Return
// non-nil err if there were unexpected node errors (error checking
// existence or change status).
func (self *BuildState) inspectParents(
	changestates map[NodeState]bool, id int, node Node) (
	missing, stale, tainted bool, err error) {

	var exists, changed bool
	exists, err = node.Exists() // obvious rebuild (unless tainted)
	if err != nil {
		return
	}
	missing = !exists
	stale = false   // need to rebuild this node
	tainted = false // failures upstream: do not rebuild

	parentnodes := self.dag.parentNodes(id)
	for _, parent := range parentnodes {
		pstate := parent.State()
		if pstate == FAILED || pstate == TAINTED {
			tainted = true
			return // no further inspection required
		}

		// Try *really hard* to avoid calling parent.Changed(), because
		// it's likely to do I/O: prone to fail, slow, etc.
		if missing || stale || !changestates[pstate] {
			continue
		}
		changed, err = parent.Changed()
		if err != nil {
			// This should not happen: parent should exist and be readable,
			// since we've already visited it earlier in the build and we
			// avoid looking at failed/tainted parents.
			return
		}
		if changed {
			stale = true
			// Do NOT return here: we need to continue inspecting parents
			// to make sure they don't taint this node with upstream
			// failure.
		}
	}
	return
}

// Build the specified node (caller has determined that it should be
// built and can be built). On failure, report the error (e.g. to the
// console, a GUI window, ...) and return false. On success, return
// true.
func (self *BuildState) buildNode(
	id int, node Node, builderr *BuildError) bool {
	rule := node.BuildRule()
	log.Verbose("building node %d: %s, action=%s\n",
		id, node, rule.ActionString())
	node.SetState(BUILDING)
	builderr.attempts++
	targets, errs := rule.Execute()
	if len(errs) > 0 {
		// Normal, everyday build failure: report the precise problem
		// immediately, and accumulate summary info in the caller.
		for _, tnode := range targets {
			tnode.SetState(FAILED)
		}
		self.reportFailure(errs)
		builderr.addFailure(node)
		return false
	}
	for _, tnode := range targets {
		tnode.SetState(BUILT)
	}
	return true
}

func (self *BuildState) reportFailure(errs []error) {
	for _, err := range errs {
		fmt.Fprintf(os.Stderr, "build failure: %s\n", err)
	}
}

func (self *BuildState) keepGoing() bool {
	return self.options.KeepGoing
}

func (self *BuildState) checkAll() bool {
	return self.options.CheckAll
}

func (self *BuildError) addFailure(node Node) {
	self.failed = append(self.failed, node)
}

func (self *BuildError) Error() string {
	if len(self.failed) == 0 {
		panic("called Error() on a BuildError with no failures: " +
			"there is no error here!")
	}

	if self.attempts > 0 {
		failed := joinNodes(", ", 10, self.failed)
		return fmt.Sprintf(
			"failed to build %d of %d targets: %s",
			len(self.failed), self.attempts, failed)
	}
	return fmt.Sprintf("failed to build target: %s", self.failed[0])
}

// (hopefully) temporary, pending acceptance of my patches to go-bit
func setToSlice(set *bit.Set) []int {
	result := make([]int, set.Size())
	j := 0
	set.Do(func(n int) {
		result[j] = n
		j++
	})
	return result
}

func joinNodes(delim string, max int, nodes []Node) string {
	if len(nodes) < max {
		max = len(nodes)
	}
	svalues := make([]string, max)
	for i := 0; i < max; i++ {
		svalues[i] = nodes[i].String()
	}
	if len(nodes) > max {
		svalues[max-1] = "..."
	}
	return strings.Join(svalues, delim)
}
<commit_msg>dag: remove unused setToSlice() helper<commit_after>// Copyright © 2012-2013, Greg Ward. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE.txt file.

package dag

import (
	"fmt"
	"os"
	"strings"

	"fubsy/log"
)

type BuildState struct {
	dag     *DAG
	options BuildOptions
}

// user options, typically from the command line
type BuildOptions struct {
	// keep building even after one target fails (default: stop on
	// first failure)
	KeepGoing bool

	// pessimistically assume that someone might have modified
	// intermediate targets behind our back (default: check only
	// original sources)
	CheckAll bool
}

type BuildError struct {
	// nodes that failed to build
	failed []Node

	// total number of nodes that we attempted to build
	attempts int
}

// The heart of Fubsy: do a depth-first walk of the dependency graph
// to discover nodes in topological order, then (re)build nodes that
// are stale or missing. Skip target nodes that are "tainted" by
// upstream failure. Returns a single error object summarizing what
// (if anything) went wrong; error details are reported "live" as
// builds fail (e.g. to the console or a GUI window) so the user gets
// timely feedback.
func (self *BuildState) BuildTargets(targets NodeSet) error {
	// What sort of nodes do we check for changes?
	changestates := self.getChangeStates()
	//fmt.Printf("BuildTargets():\n")

	builderr := new(BuildError)
	visit := func(id int) error {
		node := self.dag.nodes[id]
		//fmt.Printf("  visiting node %d (%s)\n", id, node)
		if node.State() == SOURCE {
			// can't build original source nodes!
			return nil
		}

		checkInitialState(node)

		// do we need to build this node? can we?
		missing, stale, tainted, err :=
			self.inspectParents(changestates, id, node)
		//fmt.Printf("  missing=%v, stale=%v, tainted=%v, err=%v\n",
		//	missing, stale, tainted, err)
		if err != nil {
			return err
		}

		if tainted {
			node.SetState(TAINTED)
		} else if missing || stale {
			ok := self.buildNode(id, node, builderr)
			if !ok && !self.keepGoing() {
				// attempts counter is not very useful when we break
				// out of the build early
				builderr.attempts = -1
				return builderr
			}
		}
		return nil
	}
	err := self.dag.DFS(targets, visit)
	if err == nil && len(builderr.failed) > 0 {
		// build failures in keep-going mode
		err = builderr
	}
	return err
}

func (self *BuildState) getChangeStates() map[NodeState]bool {
	// Default is like tup: only check original source nodes and nodes
	// that have just been built.
	changestates := make(map[NodeState]bool)
	changestates[SOURCE] = true
	changestates[BUILT] = true
	if self.checkAll() {
		// Optional SCons-like behaviour: assume the user has been
		// sneaking around and modifying .o or .class files behind our
		// back and check everything. (N.B. this is unnecessary if the
		// user sneakily *removes* intermediate targets; that case
		// should be handled just fine by default.)
		changestates[UNKNOWN] = true
	}
	return changestates
}

// panic if node is in an impossible state for starting its visit
func checkInitialState(node Node) {
	if node.State() != UNKNOWN {
		// we just skipped SOURCE nodes, the other states are only set
		// while visiting a node, and we should only visit each node
		// once
		panic(fmt.Sprintf(
			"visiting node %v, state = %d (should be UNKNOWN = %d)",
			node, node.State(), UNKNOWN))
	}
}

// Inspect node and its parents to see if we need to build it. Return
// tainted=true if we should skip building this node due to upstream
// failure. Return stale=true if we should build this node because at
// least one of its parents has changed. Return missing=true if we
// should build this node because its resource is missing. Return
// non-nil err if there were unexpected node errors (error checking
// existence or change status).
func (self *BuildState) inspectParents(
	changestates map[NodeState]bool, id int, node Node) (
	missing, stale, tainted bool, err error) {

	var exists, changed bool
	exists, err = node.Exists() // obvious rebuild (unless tainted)
	if err != nil {
		return
	}
	missing = !exists
	stale = false   // need to rebuild this node
	tainted = false // failures upstream: do not rebuild

	parentnodes := self.dag.parentNodes(id)
	for _, parent := range parentnodes {
		pstate := parent.State()
		if pstate == FAILED || pstate == TAINTED {
			tainted = true
			return // no further inspection required
		}

		// Try *really hard* to avoid calling parent.Changed(), because
		// it's likely to do I/O: prone to fail, slow, etc.
		if missing || stale || !changestates[pstate] {
			continue
		}
		changed, err = parent.Changed()
		if err != nil {
			// This should not happen: parent should exist and be readable,
			// since we've already visited it earlier in the build and we
			// avoid looking at failed/tainted parents.
			return
		}
		if changed {
			stale = true
			// Do NOT return here: we need to continue inspecting parents
			// to make sure they don't taint this node with upstream
			// failure.
		}
	}
	return
}

// Build the specified node (caller has determined that it should be
// built and can be built). On failure, report the error (e.g. to the
// console, a GUI window, ...) and return false. On success, return
// true.
func (self *BuildState) buildNode(
	id int, node Node, builderr *BuildError) bool {
	rule := node.BuildRule()
	log.Verbose("building node %d: %s, action=%s\n",
		id, node, rule.ActionString())
	node.SetState(BUILDING)
	builderr.attempts++
	targets, errs := rule.Execute()
	if len(errs) > 0 {
		// Normal, everyday build failure: report the precise problem
		// immediately, and accumulate summary info in the caller.
		for _, tnode := range targets {
			tnode.SetState(FAILED)
		}
		self.reportFailure(errs)
		builderr.addFailure(node)
		return false
	}
	for _, tnode := range targets {
		tnode.SetState(BUILT)
	}
	return true
}

func (self *BuildState) reportFailure(errs []error) {
	for _, err := range errs {
		fmt.Fprintf(os.Stderr, "build failure: %s\n", err)
	}
}

func (self *BuildState) keepGoing() bool {
	return self.options.KeepGoing
}

func (self *BuildState) checkAll() bool {
	return self.options.CheckAll
}

func (self *BuildError) addFailure(node Node) {
	self.failed = append(self.failed, node)
}

func (self *BuildError) Error() string {
	if len(self.failed) == 0 {
		panic("called Error() on a BuildError with no failures: " +
			"there is no error here!")
	}

	if self.attempts > 0 {
		failed := joinNodes(", ", 10, self.failed)
		return fmt.Sprintf(
			"failed to build %d of %d targets: %s",
			len(self.failed), self.attempts, failed)
	}
	return fmt.Sprintf("failed to build target: %s", self.failed[0])
}

func joinNodes(delim string, max int, nodes []Node) string {
	if len(nodes) < max {
		max = len(nodes)
	}
	svalues := make([]string, max)
	for i := 0; i < max; i++ {
		svalues[i] = nodes[i].String()
	}
	if len(nodes) > max {
		svalues[max-1] = "..."
	}
	return strings.Join(svalues, delim)
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. 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 render

import (
	"bytes"
	"fmt"
	"io"
	"path"
	"sort"
	"strconv"
	"strings"

	"github.com/googlecodelabs/tools/claat/types"
)

// MD renders nodes as markdown for the target env.
func MD(env string, nodes ...types.Node) (string, error) {
	var buf bytes.Buffer
	if err := WriteMD(&buf, env, nodes...); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// WriteMD does the same as MD but outputs rendered markup to w.
func WriteMD(w io.Writer, env string, nodes ...types.Node) error {
	mw := mdWriter{w: w, env: env, Prefix: ""}
	return mw.write(nodes...)
}

type mdWriter struct {
	w         io.Writer // output writer
	env       string    // target environment
	err       error     // error during any writeXxx methods
	lineStart bool
	isWritingTableCell bool // used to override lineStart for correct cell formatting
	Prefix    string    // prefix for e.g. blockquote content
}

func (mw *mdWriter) writeBytes(b []byte) {
	if mw.err != nil {
		return
	}
	mw.lineStart = len(b) > 0 && b[len(b)-1] == '\n'
	_, mw.err = mw.w.Write(b)
}

func (mw *mdWriter) writeString(s string) {
	if mw.lineStart {
		s = mw.Prefix + s
	}
	mw.writeBytes([]byte(s))
}

func (mw *mdWriter) space() {
	if !mw.lineStart {
		mw.writeString(" ")
	}
}

func (mw *mdWriter) newBlock() {
	if !mw.lineStart {
		mw.writeBytes(newLine)
	}
	mw.writeBytes(newLine)
}

func (mw *mdWriter) matchEnv(v []string) bool {
	if len(v) == 0 || mw.env == "" {
		return true
	}
	i := sort.SearchStrings(v, mw.env)
	return i < len(v) && v[i] == mw.env
}

func (mw *mdWriter) write(nodes ...types.Node) error {
	for _, n := range nodes {
		if !mw.matchEnv(n.Env()) {
			continue
		}
		switch n := n.(type) {
		case *types.TextNode:
			mw.text(n)
		case *types.ImageNode:
			mw.image(n)
		case *types.URLNode:
			mw.url(n)
		case *types.ButtonNode:
			mw.write(n.Content.Nodes...)
		case *types.CodeNode:
			mw.code(n)
		case *types.ListNode:
			mw.list(n)
		case *types.ImportNode:
			if len(n.Content.Nodes) == 0 {
				break
			}
			mw.write(n.Content.Nodes...)
		case *types.ItemsListNode:
			mw.itemsList(n)
		case *types.GridNode:
			mw.table(n)
		case *types.InfoboxNode:
			mw.infobox(n)
		//case *types.SurveyNode:
		//	mw.survey(n)
		case *types.HeaderNode:
			mw.header(n)
		case *types.YouTubeNode:
			mw.youtube(n)
		}
		if mw.err != nil {
			return mw.err
		}
	}
	return nil
}

func (mw *mdWriter) text(n *types.TextNode) {
	t := strings.TrimSpace(n.Value)
	tl := len([]rune(t))
	nl := len([]rune(n.Value))
	ls := nl - len([]rune(strings.TrimLeft(n.Value, " ")))
	// Don't just copy above and TrimRight instead of TrimLeft to avoid " " counting as 1
	// left space and 1 right space. Instead, number of right spaces is
	// length of whole string - length of string with spaces trimmed - number of left spaces.
	rs := nl - tl - ls

	mw.writeString(strings.Repeat(" ", ls))
	if tl > 0 {
		if n.Bold {
			mw.writeString("**")
		}
		if n.Italic {
			mw.writeString("*")
		}
		if n.Code {
			mw.writeString("`")
		}
	}

	mw.writeString(t)

	if tl > 0 {
		if n.Code {
			mw.writeString("`")
		}
		if n.Italic {
			mw.writeString("*")
		}
		if n.Bold {
			mw.writeString("**")
		}
	}
	mw.writeString(strings.Repeat(" ", rs))
}

func (mw *mdWriter) image(n *types.ImageNode) {
	mw.space()
	mw.writeString("<img ")
	mw.writeString(fmt.Sprintf("src=\"%s\" ", n.Src))

	if n.Alt != "" {
		mw.writeString(fmt.Sprintf("alt=\"%s\" ", n.Alt))
	} else {
		mw.writeString(fmt.Sprintf("alt=\"%s\" ", path.Base(n.Src)))
	}

	if n.Title != "" {
		mw.writeString(fmt.Sprintf("title=\"%q\" ", n.Title))
	}

	// If available append width to the src string of the image.
	if n.Width > 0 {
		mw.writeString(fmt.Sprintf(" width=\"%.2f\" ", n.Width))
	}

	mw.writeString("/>")
}

func (mw *mdWriter) url(n *types.URLNode) {
	mw.space()
	if n.URL != "" {
		// Look-ahead for button syntax.
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			mw.writeString("<button>")
		}
		mw.writeString("[")
	}
	mw.write(n.Content.Nodes...)
	if n.URL != "" {
		mw.writeString("](")
		mw.writeString(n.URL)
		mw.writeString(")")
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			// Look-ahead for button syntax.
			mw.writeString("</button>")
		}
	}
}

func (mw *mdWriter) code(n *types.CodeNode) {
	mw.newBlock()
	defer mw.writeBytes(newLine)
	mw.writeString("```")
	if n.Term {
		mw.writeString("console")
	} else if (len(n.Lang) > 0) {
		mw.writeString(n.Lang)
	} else {
		mw.writeString("auto")
	}
	mw.writeBytes(newLine)
	mw.writeString(n.Value)
	if !mw.lineStart {
		mw.writeBytes(newLine)
	}
	mw.writeString("```")
}

func (mw *mdWriter) list(n *types.ListNode) {
	if n.Block() == true {
		mw.newBlock()
	}
	mw.write(n.Nodes...)
	if !mw.lineStart && !mw.isWritingTableCell {
		mw.writeBytes(newLine)
	}
}

func (mw *mdWriter) itemsList(n *types.ItemsListNode) {
	if n.Block() == true {
		mw.newBlock()
	}
	for i, item := range n.Items {
		s := "* "
		if n.Type() == types.NodeItemsList && n.Start > 0 {
			s = strconv.Itoa(i+n.Start) + ". "
		}
		mw.writeString(s)
		mw.write(item.Nodes...)
		if !mw.lineStart {
			mw.writeBytes(newLine)
		}
	}
}

func (mw *mdWriter) infobox(n *types.InfoboxNode) {
	// InfoBoxes are comprised of a ListNode with the contents of the InfoBox.
	// Writing the ListNode directly results in extra newlines in the md output
	// which breaks the formatting. So instead, write the ListNode's children
	// directly and don't write the ListNode itself.
	mw.newBlock()
	k := "aside positive"
	if n.Kind == types.InfoboxNegative {
		k = "aside negative"
	}
	mw.Prefix = "> "
	mw.writeString(k)
	mw.writeString("\n")

	for _, cn := range n.Content.Nodes {
		cn.MutateBlock(false)
		mw.write(cn)
	}

	mw.Prefix = ""
}

func (mw *mdWriter) header(n *types.HeaderNode) {
	mw.newBlock()
	mw.writeString(strings.Repeat("#", n.Level+1))
	mw.writeString(" ")
	mw.write(n.Content.Nodes...)
	if !mw.lineStart {
		mw.writeBytes(newLine)
	}
}

func (mw *mdWriter) youtube(n *types.YouTubeNode) {
	mw.newBlock()
	mw.writeString(fmt.Sprintf(`<video id="%s"></video>`, n.VideoID))
}

func (mw *mdWriter) table(n *types.GridNode) {
	for rowIndex, row := range n.Rows {
		for cellIndex, cell := range row {
			mw.isWritingTableCell = true

			for _, cn := range cell.Content.Nodes {
				cn.MutateBlock(false) // don't treat content as a new block
				mw.write(cn)
			}

			// Write cell separator
			if(cellIndex != len(row) - 1){
				mw.writeString(" | ")
			} else {
				mw.writeBytes(newLine)
			}
		}

		// Write header bottom border
		if(rowIndex == 0){
			for index, _ := range row {
				mw.writeString("---")
				if(index != len(row) - 1){
					mw.writeString(" | ")
				}
			}
			mw.writeBytes(newLine)
		}

		mw.isWritingTableCell = false
	}
}<commit_msg>Removing workarround for blackfriday<commit_after>// Copyright 2016 Google Inc. 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 render

import (
	"bytes"
	"fmt"
	"io"
	"path"
	"sort"
	"strconv"
	"strings"

	"github.com/googlecodelabs/tools/claat/types"
)

// MD renders nodes as markdown for the target env.
func MD(env string, nodes ...types.Node) (string, error) {
	var buf bytes.Buffer
	if err := WriteMD(&buf, env, nodes...); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// WriteMD does the same as MD but outputs rendered markup to w.
func WriteMD(w io.Writer, env string, nodes ...types.Node) error {
	mw := mdWriter{w: w, env: env, Prefix: ""}
	return mw.write(nodes...)
}

type mdWriter struct {
	w         io.Writer // output writer
	env       string    // target environment
	err       error     // error during any writeXxx methods
	lineStart bool
	isWritingTableCell bool // used to override lineStart for correct cell formatting
	Prefix    string    // prefix for e.g. blockquote content
}

func (mw *mdWriter) writeBytes(b []byte) {
	if mw.err != nil {
		return
	}
	mw.lineStart = len(b) > 0 && b[len(b)-1] == '\n'
	_, mw.err = mw.w.Write(b)
}

func (mw *mdWriter) writeString(s string) {
	if mw.lineStart {
		s = mw.Prefix + s
	}
	mw.writeBytes([]byte(s))
}

func (mw *mdWriter) space() {
	if !mw.lineStart {
		mw.writeString(" ")
	}
}

func (mw *mdWriter) newBlock() {
	if !mw.lineStart {
		mw.writeBytes(newLine)
	}
	mw.writeBytes(newLine)
}

func (mw *mdWriter) matchEnv(v []string) bool {
	if len(v) == 0 || mw.env == "" {
		return true
	}
	i := sort.SearchStrings(v, mw.env)
	return i < len(v) && v[i] == mw.env
}

func (mw *mdWriter) write(nodes ...types.Node) error {
	for _, n := range nodes {
		if !mw.matchEnv(n.Env()) {
			continue
		}
		switch n := n.(type) {
		case *types.TextNode:
			mw.text(n)
		case *types.ImageNode:
			mw.image(n)
		case *types.URLNode:
			mw.url(n)
		case *types.ButtonNode:
			mw.write(n.Content.Nodes...)
		case *types.CodeNode:
			mw.code(n)
		case *types.ListNode:
			mw.list(n)
		case *types.ImportNode:
			if len(n.Content.Nodes) == 0 {
				break
			}
			mw.write(n.Content.Nodes...)
		case *types.ItemsListNode:
			mw.itemsList(n)
		case *types.GridNode:
			mw.table(n)
		case *types.InfoboxNode:
			mw.infobox(n)
		//case *types.SurveyNode:
		//	mw.survey(n)
		case *types.HeaderNode:
			mw.header(n)
		case *types.YouTubeNode:
			mw.youtube(n)
		}
		if mw.err != nil {
			return mw.err
		}
	}
	return nil
}

func (mw *mdWriter) text(n *types.TextNode) {
	t := strings.TrimSpace(n.Value)
	tl := len([]rune(t))
	nl := len([]rune(n.Value))
	ls := nl - len([]rune(strings.TrimLeft(n.Value, " ")))
	// Don't just copy above and TrimRight instead of TrimLeft to avoid " " counting as 1
	// left space and 1 right space. Instead, number of right spaces is
	// length of whole string - length of string with spaces trimmed - number of left spaces.
	rs := nl - tl - ls

	mw.writeString(strings.Repeat(" ", ls))
	if tl > 0 {
		if n.Bold {
			mw.writeString("**")
		}
		if n.Italic {
			mw.writeString("*")
		}
		if n.Code {
			mw.writeString("`")
		}
	}

	mw.writeString(t)

	if tl > 0 {
		if n.Code {
			mw.writeString("`")
		}
		if n.Italic {
			mw.writeString("*")
		}
		if n.Bold {
			mw.writeString("**")
		}
	}
	mw.writeString(strings.Repeat(" ", rs))
}

func (mw *mdWriter) image(n *types.ImageNode) {
	mw.space()
	mw.writeString("<img ")
	mw.writeString(fmt.Sprintf("src=\"%s\" ", n.Src))

	if n.Alt != "" {
		mw.writeString(fmt.Sprintf("alt=\"%s\" ", n.Alt))
	} else {
		mw.writeString(fmt.Sprintf("alt=\"%s\" ", path.Base(n.Src)))
	}

	if n.Title != "" {
		mw.writeString(fmt.Sprintf("title=\"%q\" ", n.Title))
	}

	// If available append width to the src string of the image.
	if n.Width > 0 {
		mw.writeString(fmt.Sprintf(" width=\"%.2f\" ", n.Width))
	}

	mw.writeString("/>")
}

func (mw *mdWriter) url(n *types.URLNode) {
	mw.space()
	if n.URL != "" {
		// Look-ahead for button syntax.
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			mw.writeString("<button>")
		}
		mw.writeString("[")
	}
	mw.write(n.Content.Nodes...)
	if n.URL != "" {
		mw.writeString("](")
		mw.writeString(n.URL)
		mw.writeString(")")
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			// Look-ahead for button syntax.
			mw.writeString("</button>")
		}
	}
}

func (mw *mdWriter) code(n *types.CodeNode) {
	mw.newBlock()
	defer mw.writeBytes(newLine)
	mw.writeString("```")
	if n.Term {
		mw.writeString("console")
	} else {
		mw.writeString(n.Lang)
	}
	mw.writeBytes(newLine)
	mw.writeString(n.Value)
	if !mw.lineStart {
		mw.writeBytes(newLine)
	}
	mw.writeString("```")
}

func (mw *mdWriter) list(n *types.ListNode) {
	if n.Block() == true {
		mw.newBlock()
	}
	mw.write(n.Nodes...)
	if !mw.lineStart && !mw.isWritingTableCell {
		mw.writeBytes(newLine)
	}
}

func (mw *mdWriter) itemsList(n *types.ItemsListNode) {
	if n.Block() == true {
		mw.newBlock()
	}
	for i, item := range n.Items {
		s := "* "
		if n.Type() == types.NodeItemsList && n.Start > 0 {
			s = strconv.Itoa(i+n.Start) + ". "
		}
		mw.writeString(s)
		mw.write(item.Nodes...)
		if !mw.lineStart {
			mw.writeBytes(newLine)
		}
	}
}

func (mw *mdWriter) infobox(n *types.InfoboxNode) {
	// InfoBoxes are comprised of a ListNode with the contents of the InfoBox.
	// Writing the ListNode directly results in extra newlines in the md output
	// which breaks the formatting. So instead, write the ListNode's children
	// directly and don't write the ListNode itself.
	mw.newBlock()
	k := "aside positive"
	if n.Kind == types.InfoboxNegative {
		k = "aside negative"
	}
	mw.Prefix = "> "
	mw.writeString(k)
	mw.writeString("\n")

	for _, cn := range n.Content.Nodes {
		cn.MutateBlock(false)
		mw.write(cn)
	}

	mw.Prefix = ""
}

func (mw *mdWriter) header(n *types.HeaderNode) {
	mw.newBlock()
	mw.writeString(strings.Repeat("#", n.Level+1))
	mw.writeString(" ")
	mw.write(n.Content.Nodes...)
	if !mw.lineStart {
		mw.writeBytes(newLine)
	}
}

func (mw *mdWriter) youtube(n *types.YouTubeNode) {
	mw.newBlock()
	mw.writeString(fmt.Sprintf(`<video id="%s"></video>`, n.VideoID))
}

func (mw *mdWriter) table(n *types.GridNode) {
	for rowIndex, row := range n.Rows {
		for cellIndex, cell := range row {
			mw.isWritingTableCell = true

			for _, cn := range cell.Content.Nodes {
				cn.MutateBlock(false) // don't treat content as a new block
				mw.write(cn)
			}

			// Write cell separator
			if(cellIndex != len(row) - 1){
				mw.writeString(" | ")
			} else {
				mw.writeBytes(newLine)
			}
		}

		// Write header bottom border
		if(rowIndex == 0){
			for index, _ := range row {
				mw.writeString("---")
				if(index != len(row) - 1){
					mw.writeString(" | ")
				}
			}
			mw.writeBytes(newLine)
		}

		mw.isWritingTableCell = false
	}
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 mappings

import (
	"time"

	"github.com/pmylund/go-cache"

	"github.com/redhat-cip/skydive/config"
	"github.com/redhat-cip/skydive/flow"
	"github.com/redhat-cip/skydive/logging"
	"github.com/redhat-cip/skydive/topology"
	"github.com/redhat-cip/skydive/topology/graph"
)

type GraphFlowEnhancer struct {
	Graph            *graph.Graph
	cache            *cache.Cache
	cacheUpdaterChan chan string
}

func (gfe *GraphFlowEnhancer) cacheUpdater() {
	logging.GetLogger().Debug("Start GraphFlowEnhancer cache updater")

	var mac string
	for {
		mac = <-gfe.cacheUpdaterChan

		logging.GetLogger().Debugf("GraphFlowEnhancer request received: %s", mac)

		gfe.Graph.Lock()
		intfs := gfe.Graph.LookupNodes(graph.Metadata{"MAC": mac})

		if len(intfs) > 1 {
			logging.GetLogger().Infof("GraphFlowEnhancer found more than one interface for the mac: %s", mac)
			continue
		}

		if len(intfs) == 1 {
			nodes := gfe.Graph.LookupShortestPath(intfs[0], graph.Metadata{"Type": "host"}, topology.IsOwnershipEdge)
			if len(nodes) > 0 {
				gfe.cache.Set(mac, topology.NodePath{nodes}.Marshal(), cache.DefaultExpiration)
			}
		}
		gfe.Graph.Unlock()
	}
}

func (gfe *GraphFlowEnhancer) getPath(mac string) string {
	if mac == "ff:ff:ff:ff:ff:ff" {
		return ""
	}

	p, f := gfe.cache.Get(mac)
	if f {
		path := p.(string)
		gfe.cache.Set(mac, path, cache.DefaultExpiration)
		return path
	}

	gfe.cacheUpdaterChan <- mac

	return ""
}

func (gfe *GraphFlowEnhancer) Enhance(f *flow.Flow) {
	if f.IfSrcGraphPath == "" {
		f.IfSrcGraphPath = gfe.getPath(f.GetStatistics().Endpoints[flow.FlowEndpointType_ETHERNET.Value()].AB.Value)
	}
	if f.IfDstGraphPath == "" {
		f.IfDstGraphPath = gfe.getPath(f.GetStatistics().Endpoints[flow.FlowEndpointType_ETHERNET.Value()].BA.Value)
	}
}

func NewGraphFlowEnhancer(g *graph.Graph) (*GraphFlowEnhancer, error) {
	mapper := &GraphFlowEnhancer{
		Graph: g,
	}

	expire := config.GetConfig().GetInt("cache.expire")
	cleanup := config.GetConfig().GetInt("cache.cleanup")
	mapper.cache = cache.New(time.Duration(expire)*time.Second, time.Duration(cleanup)*time.Second)

	mapper.cacheUpdaterChan = make(chan string, 200)
	go mapper.cacheUpdater()

	return mapper, nil
}
<commit_msg>flow: fix dead lock in graph enhancer<commit_after>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 mappings

import (
	"time"

	"github.com/pmylund/go-cache"

	"github.com/redhat-cip/skydive/config"
	"github.com/redhat-cip/skydive/flow"
	"github.com/redhat-cip/skydive/logging"
	"github.com/redhat-cip/skydive/topology"
	"github.com/redhat-cip/skydive/topology/graph"
)

type GraphFlowEnhancer struct {
	Graph            *graph.Graph
	cache            *cache.Cache
	cacheUpdaterChan chan string
}

func (gfe *GraphFlowEnhancer) cacheUpdater() {
	logging.GetLogger().Debug("Start GraphFlowEnhancer cache updater")

	var mac string
	for {
		mac = <-gfe.cacheUpdaterChan

		logging.GetLogger().Debugf("GraphFlowEnhancer request received: %s", mac)

		gfe.Graph.Lock()
		intfs := gfe.Graph.LookupNodes(graph.Metadata{"MAC": mac})

		if len(intfs) > 1 {
			logging.GetLogger().Infof("GraphFlowEnhancer found more than one interface for the mac: %s", mac)
		} else if len(intfs) == 1 {
			nodes := gfe.Graph.LookupShortestPath(intfs[0], graph.Metadata{"Type": "host"}, topology.IsOwnershipEdge)
			if len(nodes) > 0 {
				gfe.cache.Set(mac, topology.NodePath{nodes}.Marshal(), cache.DefaultExpiration)
			}
		}
		gfe.Graph.Unlock()
	}
}

func (gfe *GraphFlowEnhancer) getPath(mac string) string {
	if mac == "ff:ff:ff:ff:ff:ff" {
		return ""
	}

	p, f := gfe.cache.Get(mac)
	if f {
		path := p.(string)
		gfe.cache.Set(mac, path, cache.DefaultExpiration)
		return path
	}

	gfe.cacheUpdaterChan <- mac

	return ""
}

func (gfe *GraphFlowEnhancer) Enhance(f *flow.Flow) {
	if f.IfSrcGraphPath == "" {
		f.IfSrcGraphPath = gfe.getPath(f.GetStatistics().Endpoints[flow.FlowEndpointType_ETHERNET.Value()].AB.Value)
	}
	if f.IfDstGraphPath == "" {
		f.IfDstGraphPath = gfe.getPath(f.GetStatistics().Endpoints[flow.FlowEndpointType_ETHERNET.Value()].BA.Value)
	}
}

func NewGraphFlowEnhancer(g *graph.Graph) (*GraphFlowEnhancer, error) {
	mapper := &GraphFlowEnhancer{
		Graph: g,
	}

	expire := config.GetConfig().GetInt("cache.expire")
	cleanup := config.GetConfig().GetInt("cache.cleanup")
	mapper.cache = cache.New(time.Duration(expire)*time.Second, time.Duration(cleanup)*time.Second)

	mapper.cacheUpdaterChan = make(chan string, 200)
	go mapper.cacheUpdater()

	return mapper, nil
}
<|endoftext|>


<commit_before>package instances

type Instance interface {
	GetID() string
	SetID(string)
	GetType() string
	SetValues(values []interface{})
	GetValues() []interface{}
}
<commit_msg>Add general instance pointer<commit_after>package instances

type Instance interface {
	GetID() string
	SetID(string)
	GetType() string
	SetValues(values []interface{})
	GetValues() []interface{}
}

type InstancePointer struct {
	ID   *string `json:"id"`
	Type string  `json:"type"`
}

func (ip *InstancePointer) GetID() string {
	if ip.ID == nil {
		return ""
	}
	return *ip.ID
}
func (ip *InstancePointer) SetID(id string) {
	ip.ID = &id
}
func (ip *InstancePointer) GetType() string {
	return ip.Type
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"fmt"
	"github.com/timakin/ts/loader"
	"github.com/codegangsta/cli"
)

var Commands = []cli.Command{
	commandAll,
	commandBiz,
	commandHack,
}

var commandAll = cli.Command{
	Name:  "all",
	Usage: "",
	Description: `
`,
	Action: doAll,
}

var commandBiz = cli.Command{
	Name:  "biz",
	Usage: "",
	Description: `
`,
	Action: doBiz,
}

var commandHack = cli.Command{
	Name:  "hack",
	Usage: "",
	Description: `
`,
	Action: doHack,
}

func debug(v ...interface{}) {
	if os.Getenv("DEBUG") != "" {
		log.Println(v...)
	}
}

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

func doAll(c *cli.Context) {
	test := make(chan int)
	test2 := make(chan int)
	hn := make(chan string)
	go loader.GoRouTest(test)
	go loader.GoRouTestTwo(test2)
	go loader.GetPHFeed(hn)
	fmt.Printf("print all\n")
	result := <- test
	resTwo := <- test2
	phres := <- hn
	fmt.Printf("%d%d\n", result, resTwo)
	fmt.Printf(phres)
}

func doBiz(c *cli.Context) {
}

func doHack(c *cli.Context) {
}
<commit_msg>Rename PH to HN<commit_after>package main

import (
	"log"
	"os"
	"fmt"
	"github.com/timakin/ts/loader"
	"github.com/codegangsta/cli"
)

var Commands = []cli.Command{
	commandAll,
	commandBiz,
	commandHack,
}

var commandAll = cli.Command{
	Name:  "all",
	Usage: "",
	Description: `
`,
	Action: doAll,
}

var commandBiz = cli.Command{
	Name:  "biz",
	Usage: "",
	Description: `
`,
	Action: doBiz,
}

var commandHack = cli.Command{
	Name:  "hack",
	Usage: "",
	Description: `
`,
	Action: doHack,
}

func debug(v ...interface{}) {
	if os.Getenv("DEBUG") != "" {
		log.Println(v...)
	}
}

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

func doAll(c *cli.Context) {
	test := make(chan int)
	test2 := make(chan int)
	hn := make(chan string)
	go loader.GoRouTest(test)
	go loader.GoRouTestTwo(test2)
	go loader.GetHNFeed(hn)
	fmt.Printf("print all\n")
	result := <- test
	resTwo := <- test2
	phres := <- hn
	fmt.Printf("%d%d\n", result, resTwo)
	fmt.Printf(phres)
}

func doBiz(c *cli.Context) {
}

func doHack(c *cli.Context) {
}
<|endoftext|>


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

package http2amqp

import (
	"errors"
	"log"
	"strconv"
	"time"

	"encoding/json"

	"github.com/aleasoluciones/goaleasoluciones/safemap"
	"github.com/aleasoluciones/simpleamqp"
)

const (
	responsesQueue = "queries_responses"
	responseTopic  = "queries.response"
)

// NewService return the http2amqp service. This service publish a amqp message for each http request
// and process the corresponding amqp responses to answer to the original http request
func NewService(brokerURI, exchange string, timeout time.Duration) *Service {

	service := Service{
		amqpConsumer:   simpleamqp.NewAmqpConsumer(brokerURI),
		amqpPublisher:  simpleamqp.NewAmqpPublisher(brokerURI, exchange),
		idsGenerator:   NewUUIDIdsGenerator(),
		exchange:       exchange,
		queryTimeout:   timeout,
		queryResponses: safemap.NewSafeMap(),
	}

	go service.receiveResponses(service.amqpConsumer.ReceiveWithoutTimeout(
		service.exchange,
		[]string{responseTopic},
		responsesQueue,
		simpleamqp.QueueOptions{Durable: false, Delete: true, Exclusive: true}))

	return &service
}

// Service http2amqp service
type Service struct {
	amqpConsumer   simpleamqp.AMQPConsumer
	amqpPublisher  simpleamqp.AMQPPublisher
	idsGenerator   IdsGenerator
	exchange       string
	queryTimeout   time.Duration
	queryResponses safemap.SafeMap
}

func (service *Service) receiveResponses(amqpResponses chan simpleamqp.AmqpMessage) {
	var deserialized AmqpResponseMessage
	var value safemap.Value
	var responses chan Response
	var found bool

	for message := range amqpResponses {
		err := json.Unmarshal([]byte(message.Body), &deserialized)

		if err != nil {
			log.Println("Error unmarshaling json response:", err)
			continue
		}

		log.Println("Response received", deserialized.ID)
		value, found = service.queryResponses.Find(deserialized.ID)
		if found {
			log.Println("Pending request found for", deserialized.ID)
			responses = value.(chan Response)
			responses <- deserialized.Response
		}
	}
}

func (service *Service) publishQuery(id string, topic string, request Request, ttl time.Duration) {
	serialized, _ := json.Marshal(AmqpRequestMessage{
		ID:            id,
		Request:       request,
		ResponseTopic: responseTopic,
	})
	log.Println("[queries_service] Query id:", id, "topic:", topic, "request:", request, "ttl:", ttl)
	service.amqpPublisher.PublishWithTTL(topic, serialized, durationToMilliseconds(ttl))
}

func durationToMilliseconds(value time.Duration) int {
	return int(value.Nanoseconds() / 1000000)
}

// DispatchHTTPRequest process a request. Send the request to the broker using the
// given topic and wait for the response (or the timeout)
func (service *Service) DispatchHTTPRequest(topic string, request Request) (Response, error) {
	id := service.idsGenerator.Next()
	responses := make(chan Response)
	service.queryResponses.Insert(id, responses)
	defer service.queryResponses.Delete(id)

	timeout := service.queryTimeout
	for k, v := range request.URL.Query() {
		if k == "timeout" {
			milliseconds, _ := strconv.Atoi(v[0])
			timeout = time.Duration(milliseconds) * time.Millisecond
		}
	}

	service.publishQuery(id, topic, request, timeout)
	log.Println("Request published", id)

	timeoutTicker := time.NewTicker(timeout)
	defer timeoutTicker.Stop()
	afterTimeout := timeoutTicker.C

	select {
	case response := <-responses:
		return response, nil
	case <-afterTimeout:
		log.Println("[queries_service] Timeout for query id:", id)
		return Response{}, errors.New("Timeout")
	}
}
<commit_msg>more trace added<commit_after>// Copyright 2015 The http2amqp Authors. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package http2amqp

import (
	"errors"
	"log"
	"strconv"
	"time"

	"encoding/json"

	"github.com/aleasoluciones/goaleasoluciones/safemap"
	"github.com/aleasoluciones/simpleamqp"
)

const (
	responsesQueue = "queries_responses"
	responseTopic  = "queries.response"
)

// NewService return the http2amqp service. This service publish a amqp message for each http request
// and process the corresponding amqp responses to answer to the original http request
func NewService(brokerURI, exchange string, timeout time.Duration) *Service {

	service := Service{
		amqpConsumer:   simpleamqp.NewAmqpConsumer(brokerURI),
		amqpPublisher:  simpleamqp.NewAmqpPublisher(brokerURI, exchange),
		idsGenerator:   NewUUIDIdsGenerator(),
		exchange:       exchange,
		queryTimeout:   timeout,
		queryResponses: safemap.NewSafeMap(),
	}

	go service.receiveResponses(service.amqpConsumer.ReceiveWithoutTimeout(
		service.exchange,
		[]string{responseTopic},
		responsesQueue,
		simpleamqp.QueueOptions{Durable: false, Delete: true, Exclusive: true}))

	return &service
}

// Service http2amqp service
type Service struct {
	amqpConsumer   simpleamqp.AMQPConsumer
	amqpPublisher  simpleamqp.AMQPPublisher
	idsGenerator   IdsGenerator
	exchange       string
	queryTimeout   time.Duration
	queryResponses safemap.SafeMap
}

func (service *Service) receiveResponses(amqpResponses chan simpleamqp.AmqpMessage) {
	var deserialized AmqpResponseMessage
	var value safemap.Value
	var responses chan Response
	var found bool

	for message := range amqpResponses {
		log.Println("Response received")
		err := json.Unmarshal([]byte(message.Body), &deserialized)

		if err != nil {
			log.Println("Error unmarshaling json response:", err)
			continue
		}

		log.Println("Response received ID:", deserialized.ID)
		value, found = service.queryResponses.Find(deserialized.ID)
		if found {
			log.Println("Pending request found for", deserialized.ID)
			responses = value.(chan Response)
			responses <- deserialized.Response
		}
	}
}

func (service *Service) publishQuery(id string, topic string, request Request, ttl time.Duration) {
	serialized, _ := json.Marshal(AmqpRequestMessage{
		ID:            id,
		Request:       request,
		ResponseTopic: responseTopic,
	})
	log.Println("[queries_service] Query id:", id, "topic:", topic, "request:", request, "ttl:", ttl)
	service.amqpPublisher.PublishWithTTL(topic, serialized, durationToMilliseconds(ttl))
}

func durationToMilliseconds(value time.Duration) int {
	return int(value.Nanoseconds() / 1000000)
}

// DispatchHTTPRequest process a request. Send the request to the broker using the
// given topic and wait for the response (or the timeout)
func (service *Service) DispatchHTTPRequest(topic string, request Request) (Response, error) {
	id := service.idsGenerator.Next()
	responses := make(chan Response)
	service.queryResponses.Insert(id, responses)
	defer service.queryResponses.Delete(id)

	timeout := service.queryTimeout
	for k, v := range request.URL.Query() {
		if k == "timeout" {
			milliseconds, _ := strconv.Atoi(v[0])
			timeout = time.Duration(milliseconds) * time.Millisecond
		}
	}

	service.publishQuery(id, topic, request, timeout)
	log.Println("Request published", id)

	timeoutTicker := time.NewTicker(timeout)
	defer timeoutTicker.Stop()
	afterTimeout := timeoutTicker.C

	select {
	case response := <-responses:
		return response, nil
	case <-afterTimeout:
		log.Println("[queries_service] Timeout for query id:", id)
		return Response{}, errors.New("Timeout")
	}
}
<|endoftext|>