<commit_before>//go:build linux && cgo && !agent

package sys

import (
	"os/user"
	"path/filepath"
	"strconv"
	"sync"

	"github.com/mdlayher/vsock"

	"github.com/lxc/lxd/lxd/cgroup"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/storage/filesystem"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/idmap"
	"github.com/lxc/lxd/shared/logger"
)

// InotifyTargetInfo records the inotify information associated with a given
// inotify target
type InotifyTargetInfo struct {
	Mask uint32
	Wd   int
	Path string
}

// InotifyInfo records the inotify information associated with a given
// inotify instance
type InotifyInfo struct {
	Fd int
	sync.RWMutex
	Targets map[string]*InotifyTargetInfo
}

// OS is a high-level facade for accessing all operating-system
// level functionality that LXD uses.
type OS struct {
	// Directories
	CacheDir string // Cache directory (e.g. /var/cache/lxd/).
	LogDir   string // Log directory (e.g. /var/log/lxd).
	VarDir   string // Data directory (e.g. /var/lib/lxd/).

	// Daemon environment
	Architectures   []int           // Cache of detected system architectures
	BackingFS       string          // Backing filesystem of $LXD_DIR/containers
	ExecPath        string          // Absolute path to the LXD executable
	IdmapSet        *idmap.IdmapSet // Information about user/group ID mapping
	InotifyWatch    InotifyInfo
	LxcPath         string // Path to the $LXD_DIR/containers directory
	MockMode        bool   // If true some APIs will be mocked (for testing)
	Nodev           bool
	RunningInUserNS bool

	// Privilege dropping
	UnprivUser  string
	UnprivUID   uint32
	UnprivGroup string
	UnprivGID   uint32

	// Apparmor features
	AppArmorAdmin     bool
	AppArmorAvailable bool
	AppArmorConfined  bool
	AppArmorStacked   bool
	AppArmorStacking  bool

	// Cgroup features
	CGInfo cgroup.Info

	// Kernel features
	CloseRange              bool
	CoreScheduling          bool
	IdmappedMounts          bool
	NetnsGetifaddrs         bool
	PidFdSetns              bool
	SeccompListener         bool
	SeccompListenerContinue bool
	Shiftfs                 bool
	UeventInjection         bool
	VFS3Fscaps              bool

	ContainerCoreScheduling bool
	NativeTerminals         bool
	PidFds                  bool
	SeccompListenerAddfd    bool

	// LXC features
	LXCFeatures map[string]bool

	// VM features
	VsockID uint32
}

// DefaultOS returns a fresh uninitialized OS instance with default values.
func DefaultOS() *OS {
	newOS := &OS{
		VarDir:   shared.VarPath(),
		CacheDir: shared.CachePath(),
		LogDir:   shared.LogPath(),
	}
	newOS.InotifyWatch.Fd = -1
	newOS.InotifyWatch.Targets = make(map[string]*InotifyTargetInfo)
	return newOS
}

// Init our internal data structures.
func (s *OS) Init() ([]db.Warning, error) {
	var dbWarnings []db.Warning

	err := s.initDirs()
	if err != nil {
		return nil, err
	}

	s.Architectures, err = util.GetArchitectures()
	if err != nil {
		return nil, err
	}

	s.LxcPath = filepath.Join(s.VarDir, "containers")

	s.BackingFS, err = filesystem.Detect(s.LxcPath)
	if err != nil {
		logger.Error("Error detecting backing fs", logger.Ctx{"err": err})
	}

	// Detect if it is possible to run daemons as an unprivileged user and group.
	for _, userName := range []string{"lxd", "nobody"} {
		u, err := user.Lookup(userName)
		if err != nil {
			continue
		}

		uid, err := strconv.ParseUint(u.Uid, 10, 32)
		if err != nil {
			return nil, err
		}

		s.UnprivUser = userName
		s.UnprivUID = uint32(uid)
		break
	}

	for _, groupName := range []string{"lxd", "nogroup"} {
		g, err := user.LookupGroup(groupName)
		if err != nil {
			continue
		}

		gid, err := strconv.ParseUint(g.Gid, 10, 32)
		if err != nil {
			return nil, err
		}

		s.UnprivGroup = groupName
		s.UnprivGID = uint32(gid)
		break
	}

	s.IdmapSet = idmap.GetIdmapSet()
	s.ExecPath = util.GetExecPath()
	s.RunningInUserNS = shared.RunningInUserNS()

	dbWarnings = s.initAppArmor()
	cgroup.Init()
	s.CGInfo = cgroup.GetInfo()

	// Fill in the VsockID.
	util.LoadModule("vhost_vsock")
	vsockID, err := vsock.ContextID()
	if err != nil || vsockID > 2147483647 {
		// Fallback to the default ID for a host system if we're getting
		// an error or are getting a clearly invalid value.
		vsockID = 2
	}

	s.VsockID = vsockID

	return dbWarnings, nil
}

// InitStorage initialises the storage layer after it has been mounted.
func (s *OS) InitStorage() error {
	return s.initStorageDirs()
}
<commit_msg>lxd/sys: Checks or explicitly ignores errors.<commit_after>//go:build linux && cgo && !agent

package sys

import (
	"os/user"
	"path/filepath"
	"strconv"
	"sync"

	"github.com/mdlayher/vsock"

	"github.com/lxc/lxd/lxd/cgroup"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/storage/filesystem"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/idmap"
	"github.com/lxc/lxd/shared/logger"
)

// InotifyTargetInfo records the inotify information associated with a given
// inotify target
type InotifyTargetInfo struct {
	Mask uint32
	Wd   int
	Path string
}

// InotifyInfo records the inotify information associated with a given
// inotify instance
type InotifyInfo struct {
	Fd int
	sync.RWMutex
	Targets map[string]*InotifyTargetInfo
}

// OS is a high-level facade for accessing all operating-system
// level functionality that LXD uses.
type OS struct {
	// Directories
	CacheDir string // Cache directory (e.g. /var/cache/lxd/).
	LogDir   string // Log directory (e.g. /var/log/lxd).
	VarDir   string // Data directory (e.g. /var/lib/lxd/).

	// Daemon environment
	Architectures   []int           // Cache of detected system architectures
	BackingFS       string          // Backing filesystem of $LXD_DIR/containers
	ExecPath        string          // Absolute path to the LXD executable
	IdmapSet        *idmap.IdmapSet // Information about user/group ID mapping
	InotifyWatch    InotifyInfo
	LxcPath         string // Path to the $LXD_DIR/containers directory
	MockMode        bool   // If true some APIs will be mocked (for testing)
	Nodev           bool
	RunningInUserNS bool

	// Privilege dropping
	UnprivUser  string
	UnprivUID   uint32
	UnprivGroup string
	UnprivGID   uint32

	// Apparmor features
	AppArmorAdmin     bool
	AppArmorAvailable bool
	AppArmorConfined  bool
	AppArmorStacked   bool
	AppArmorStacking  bool

	// Cgroup features
	CGInfo cgroup.Info

	// Kernel features
	CloseRange              bool
	CoreScheduling          bool
	IdmappedMounts          bool
	NetnsGetifaddrs         bool
	PidFdSetns              bool
	SeccompListener         bool
	SeccompListenerContinue bool
	Shiftfs                 bool
	UeventInjection         bool
	VFS3Fscaps              bool

	ContainerCoreScheduling bool
	NativeTerminals         bool
	PidFds                  bool
	SeccompListenerAddfd    bool

	// LXC features
	LXCFeatures map[string]bool

	// VM features
	VsockID uint32
}

// DefaultOS returns a fresh uninitialized OS instance with default values.
func DefaultOS() *OS {
	newOS := &OS{
		VarDir:   shared.VarPath(),
		CacheDir: shared.CachePath(),
		LogDir:   shared.LogPath(),
	}
	newOS.InotifyWatch.Fd = -1
	newOS.InotifyWatch.Targets = make(map[string]*InotifyTargetInfo)
	return newOS
}

// Init our internal data structures.
func (s *OS) Init() ([]db.Warning, error) {
	var dbWarnings []db.Warning

	err := s.initDirs()
	if err != nil {
		return nil, err
	}

	s.Architectures, err = util.GetArchitectures()
	if err != nil {
		return nil, err
	}

	s.LxcPath = filepath.Join(s.VarDir, "containers")

	s.BackingFS, err = filesystem.Detect(s.LxcPath)
	if err != nil {
		logger.Error("Error detecting backing fs", logger.Ctx{"err": err})
	}

	// Detect if it is possible to run daemons as an unprivileged user and group.
	for _, userName := range []string{"lxd", "nobody"} {
		u, err := user.Lookup(userName)
		if err != nil {
			continue
		}

		uid, err := strconv.ParseUint(u.Uid, 10, 32)
		if err != nil {
			return nil, err
		}

		s.UnprivUser = userName
		s.UnprivUID = uint32(uid)
		break
	}

	for _, groupName := range []string{"lxd", "nogroup"} {
		g, err := user.LookupGroup(groupName)
		if err != nil {
			continue
		}

		gid, err := strconv.ParseUint(g.Gid, 10, 32)
		if err != nil {
			return nil, err
		}

		s.UnprivGroup = groupName
		s.UnprivGID = uint32(gid)
		break
	}

	s.IdmapSet = idmap.GetIdmapSet()
	s.ExecPath = util.GetExecPath()
	s.RunningInUserNS = shared.RunningInUserNS()

	dbWarnings = s.initAppArmor()
	cgroup.Init()
	s.CGInfo = cgroup.GetInfo()

	// Fill in the VsockID.
	_ = util.LoadModule("vhost_vsock")

	vsockID, err := vsock.ContextID()
	if err != nil || vsockID > 2147483647 {
		// Fallback to the default ID for a host system if we're getting
		// an error or are getting a clearly invalid value.
		vsockID = 2
	}

	s.VsockID = vsockID

	return dbWarnings, nil
}

// InitStorage initialises the storage layer after it has been mounted.
func (s *OS) InitStorage() error {
	return s.initStorageDirs()
}
<|endoftext|>


<commit_before>package lzma2

// Maximum and minimum supported dictionary size.
const (
	MinDictSize = 1 << 12
	MaxDictSize = 1<<32 - 1
)

// errDist indicates that the distance is out of range.
var errDist = newError("distance out of range")

// readerDict represents the dictionary for reading. It is a ring buffer using
// the end field as head for the dictionary.
type readerDict struct {
	buffer
	bufferSize int64
}

// newReaderDict creates a new reader dictionary. The capacity of the ring
// buffer will be the maximum of historySize and bufferSize.
func newReaderDict(historySize, bufferSize int64) (rd *readerDict, err error) {
	if !(1 <= historySize && historySize < MaxDictSize) {
		return nil, newError("historySize out of range")
	}
	if bufferSize <= 0 {
		return nil, newError("bufferSize must be greater than zero")
	}
	capacity := historySize
	if bufferSize > capacity {
		capacity = bufferSize
	}
	rd = &readerDict{bufferSize: bufferSize}
	err = initBuffer(&rd.buffer, capacity)
	return
}

// Offset returns the offset of the dictionary head.
func (rd *readerDict) Offset() int64 {
	return rd.end
}

// WriteRep writes a repetition with the given distance. While distance is
// given here as int64 the actual limit is the maximum of the int type.
func (rd *readerDict) WriteRep(dist int64, n int) (written int, err error) {
	if !(1 <= dist && dist <= int64(rd.Len())) {
		return 0, errDist
	}
	return rd.WriteRepOff(n, rd.end-dist)
}

// Byte returns a byte at the given distance.
func (rd *readerDict) Byte(dist int64) byte {
	c, _ := rd.ReadByteAt(rd.end - dist)
	return c
}

// writerDict is the dictionary used for writing. It includes also a hashtable.
// It is a ring buffer using the cursor offset for the dictionary head. The
// capacity for the buffer is the sum of historySize and bufferSize.
//
// The actual writer uses encoderDict, which is an extension of writerDict to
// support the finding of string sequences in the history.
type writerDict struct {
	buffer
	bufferSize int64
	t4         *hashTable
}

// initWriterDict initializes a writer dictionary.
func initWriterDict(wd *writerDict, historySize, bufferSize int64) error {
	if !(1 <= historySize && historySize < MaxDictSize) {
		return newError("historySize out of range")
	}
	if bufferSize <= 0 {
		return newError("bufferSize must be greater than zero")
	}
	capacity := historySize + bufferSize
	*wd = writerDict{bufferSize: bufferSize}
	err := initBuffer(&wd.buffer, capacity)
	if err != nil {
		return err
	}
	wd.writeLimit = bufferSize
	wd.t4, err = newHashTable(historySize, 4)
	return err
}

// newWriterDict creates a new writer dictionary.
func newWriterDict(historySize, bufferSize int64) (wd *writerDict, err error) {
	wd = new(writerDict)
	err = initWriterDict(wd, historySize, bufferSize)
	return
}

// HistorySize returns the history length.
func (wd *writerDict) HistorySize() int64 {
	return wd.Cap() - wd.bufferSize
}

// Returns the byte at the given distance to the dictionary head.
func (wd *writerDict) Byte(dist int) byte {
	c, _ := wd.ReadByteAt(wd.cursor - int64(dist))
	return c
}

// Offset returns the offset of the head.
func (wd *writerDict) Offset() int64 {
	return wd.cursor
}

func (wd *writerDict) PeekHead(p []byte) (n int, err error) {
	return wd.ReadAt(p, wd.cursor)
}

// AdvanceHead moves the head n bytes forward.
func (wd *writerDict) AdvanceHead(n int) (advanced int, err error) {
	return wd.Copy(wd.t4, n)
}
<commit_msg>lzma2: added documentation to writerDict.PeekHead<commit_after>package lzma2

// Maximum and minimum supported dictionary size.
const (
	MinDictSize = 1 << 12
	MaxDictSize = 1<<32 - 1
)

// errDist indicates that the distance is out of range.
var errDist = newError("distance out of range")

// readerDict represents the dictionary for reading. It is a ring buffer using
// the end field as head for the dictionary.
type readerDict struct {
	buffer
	bufferSize int64
}

// newReaderDict creates a new reader dictionary. The capacity of the ring
// buffer will be the maximum of historySize and bufferSize.
func newReaderDict(historySize, bufferSize int64) (rd *readerDict, err error) {
	if !(1 <= historySize && historySize < MaxDictSize) {
		return nil, newError("historySize out of range")
	}
	if bufferSize <= 0 {
		return nil, newError("bufferSize must be greater than zero")
	}
	capacity := historySize
	if bufferSize > capacity {
		capacity = bufferSize
	}
	rd = &readerDict{bufferSize: bufferSize}
	err = initBuffer(&rd.buffer, capacity)
	return
}

// Offset returns the offset of the dictionary head.
func (rd *readerDict) Offset() int64 {
	return rd.end
}

// WriteRep writes a repetition with the given distance. While distance is
// given here as int64 the actual limit is the maximum of the int type.
func (rd *readerDict) WriteRep(dist int64, n int) (written int, err error) {
	if !(1 <= dist && dist <= int64(rd.Len())) {
		return 0, errDist
	}
	return rd.WriteRepOff(n, rd.end-dist)
}

// Byte returns a byte at the given distance.
func (rd *readerDict) Byte(dist int64) byte {
	c, _ := rd.ReadByteAt(rd.end - dist)
	return c
}

// writerDict is the dictionary used for writing. It includes also a hashtable.
// It is a ring buffer using the cursor offset for the dictionary head. The
// capacity for the buffer is the sum of historySize and bufferSize.
//
// The actual writer uses encoderDict, which is an extension of writerDict to
// support the finding of string sequences in the history.
type writerDict struct {
	buffer
	bufferSize int64
	t4         *hashTable
}

// initWriterDict initializes a writer dictionary.
func initWriterDict(wd *writerDict, historySize, bufferSize int64) error {
	if !(1 <= historySize && historySize < MaxDictSize) {
		return newError("historySize out of range")
	}
	if bufferSize <= 0 {
		return newError("bufferSize must be greater than zero")
	}
	capacity := historySize + bufferSize
	*wd = writerDict{bufferSize: bufferSize}
	err := initBuffer(&wd.buffer, capacity)
	if err != nil {
		return err
	}
	wd.writeLimit = bufferSize
	wd.t4, err = newHashTable(historySize, 4)
	return err
}

// newWriterDict creates a new writer dictionary.
func newWriterDict(historySize, bufferSize int64) (wd *writerDict, err error) {
	wd = new(writerDict)
	err = initWriterDict(wd, historySize, bufferSize)
	return
}

// HistorySize returns the history length.
func (wd *writerDict) HistorySize() int64 {
	return wd.Cap() - wd.bufferSize
}

// Returns the byte at the given distance to the dictionary head.
func (wd *writerDict) Byte(dist int) byte {
	c, _ := wd.ReadByteAt(wd.cursor - int64(dist))
	return c
}

// Offset returns the offset of the head.
func (wd *writerDict) Offset() int64 {
	return wd.cursor
}

// PeekHead reads bytes from the Head without moving it.
func (wd *writerDict) PeekHead(p []byte) (n int, err error) {
	return wd.ReadAt(p, wd.cursor)
}

// AdvanceHead moves the head n bytes forward.
func (wd *writerDict) AdvanceHead(n int) (advanced int, err error) {
	return wd.Copy(wd.t4, n)
}
<|endoftext|>


<commit_before>package mussed

import "strings"

type stash struct {
	tree       *protoTree
	content    string
	started    bool
	commenting bool
}

func (s *stash) needsMoreText() bool {
	normalOpen := strings.Index(s.content, s.tree.localLeft)
	normalUnescape := strings.Index(s.content, LeftEscapeDelim)

	if normalUnescape >= 0 && normalUnescape < normalOpen {
		closeIndex := strings.Index(s.content, RightEscapeDelim)
		return !(closeIndex >= 0 && closeIndex > normalUnescape)
	}
	if normalOpen >= 0 {
		closeIndex := strings.Index(s.content, s.tree.localRight)
		return !(closeIndex >= 0 && closeIndex > normalOpen)
	}

	return false
}

func (s *stash) Append(t string) {
	ts := strings.TrimSpace(t)
	//standalone comments
	if s.commenting {
		if strings.HasSuffix(ts, s.tree.localRight) {
			s.commenting = false
		}
		return
	}
	if strings.HasPrefix(ts, s.tree.localLeft) && strings.Count(ts, s.tree.localLeft) == 1 {
		if strings.TrimSpace(ts[len(s.tree.localLeft):])[0] == '!' {
			if strings.HasSuffix(ts, s.tree.localRight) {
				return
			} else {
				s.commenting = true
				return
			}
		}
	}
	// sections opening and closing
	if strings.HasPrefix(ts, s.tree.localLeft) && strings.Count(ts, s.tree.localLeft) == 1 {
		if strings.HasSuffix(ts, s.tree.localRight) {
			switch strings.TrimSpace(ts[len(s.tree.localLeft):])[0] {
			case '#':
				s.content = s.content + ts
				t = ""
			case '/':
				s.content = s.content + ts
				t = ""
			}
		}
	}
	if s.started {
		s.content = s.content + t
	} else {
		s.content = t
		s.started = true
	}
}
func (s *stash) hasAction() bool {
	return strings.Contains(s.content, s.tree.localLeft) ||
		strings.Contains(s.content, LeftEscapeDelim)
}

func (s *stash) pullToAction() (string, string) {
	var text, action string
	loc, abnormal := s.nextActionLocation()
	text = s.content[:loc]
	s.content = s.content[loc:]
	if abnormal {
		action = s.content[:len(LeftEscapeDelim)]
		s.content = s.content[len(LeftEscapeDelim):]
		closeLocation := strings.Index(s.content, RightEscapeDelim)
		action += s.content[:closeLocation+len(RightEscapeDelim)]
		s.content = s.content[closeLocation+len(RightEscapeDelim):]
	} else {
		action = s.content[:len(s.tree.localLeft)]
		s.content = s.content[len(s.tree.localLeft):]
		closeLocation := strings.Index(s.content, s.tree.localRight)
		action += s.content[:closeLocation+len(s.tree.localRight)]
		s.content = s.content[closeLocation+len(s.tree.localRight):]
	}
	return text, action
}

func (s *stash) nextActionLocation() (int, bool) {
	normalOpen := strings.Index(s.content, s.tree.localLeft)
	normalUnescape := strings.Index(s.content, LeftEscapeDelim)

	if normalUnescape >= 0 && normalUnescape < normalOpen {
		return normalUnescape, true
	}
	if normalOpen >= 0 {
		return normalOpen, false
	}
	return -1, false
}
<commit_msg>Fix final section test<commit_after>package mussed

import "strings"

type stash struct {
	tree       *protoTree
	content    string
	started    bool
	commenting bool
}

func (s *stash) needsMoreText() bool {
	normalOpen := strings.Index(s.content, s.tree.localLeft)
	normalUnescape := strings.Index(s.content, LeftEscapeDelim)

	if normalUnescape >= 0 && normalUnescape < normalOpen {
		closeIndex := strings.Index(s.content, RightEscapeDelim)
		return !(closeIndex >= 0 && closeIndex > normalUnescape)
	}
	if normalOpen >= 0 {
		closeIndex := strings.Index(s.content, s.tree.localRight)
		return !(closeIndex >= 0 && closeIndex > normalOpen)
	}

	return false
}

func (s *stash) Append(t string) {
	ts := strings.TrimSpace(t)
	//standalone comments
	if s.commenting {
		if strings.HasSuffix(ts, s.tree.localRight) {
			s.commenting = false
		}
		return
	}
	if strings.HasPrefix(ts, s.tree.localLeft) && strings.Count(ts, s.tree.localLeft) == 1 {
		if strings.TrimSpace(ts[len(s.tree.localLeft):])[0] == '!' {
			if strings.HasSuffix(ts, s.tree.localRight) {
				return
			} else {
				s.commenting = true
				return
			}
		}
	}
	// sections opening and closing
	if strings.HasPrefix(ts, s.tree.localLeft) && strings.Count(ts, s.tree.localLeft) == 1 {
		if strings.HasSuffix(ts, s.tree.localRight) {
			switch strings.TrimSpace(ts[len(s.tree.localLeft):])[0] {
			case '#':
				s.content = s.content + ts
				t = ""
			case '/':
				s.content = s.content + ts
				t = ""
			}
		}
	}
	s.content = s.content + t
}
func (s *stash) hasAction() bool {
	return strings.Contains(s.content, s.tree.localLeft) ||
		strings.Contains(s.content, LeftEscapeDelim)
}

func (s *stash) pullToAction() (string, string) {
	var text, action string
	loc, abnormal := s.nextActionLocation()
	text = s.content[:loc]
	s.content = s.content[loc:]
	if abnormal {
		action = s.content[:len(LeftEscapeDelim)]
		s.content = s.content[len(LeftEscapeDelim):]
		closeLocation := strings.Index(s.content, RightEscapeDelim)
		action += s.content[:closeLocation+len(RightEscapeDelim)]
		s.content = s.content[closeLocation+len(RightEscapeDelim):]
	} else {
		action = s.content[:len(s.tree.localLeft)]
		s.content = s.content[len(s.tree.localLeft):]
		closeLocation := strings.Index(s.content, s.tree.localRight)
		action += s.content[:closeLocation+len(s.tree.localRight)]
		s.content = s.content[closeLocation+len(s.tree.localRight):]
	}
	return text, action
}

func (s *stash) nextActionLocation() (int, bool) {
	normalOpen := strings.Index(s.content, s.tree.localLeft)
	normalUnescape := strings.Index(s.content, LeftEscapeDelim)

	if normalUnescape >= 0 && normalUnescape < normalOpen {
		return normalUnescape, true
	}
	if normalOpen >= 0 {
		return normalOpen, false
	}
	return -1, false
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/labstack/echo/v4"
)

type (
	// JWTConfig defines the config for JWT middleware.
	JWTConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper Skipper

		// BeforeFunc defines a function which is executed just before the middleware.
		BeforeFunc BeforeFunc

		// SuccessHandler defines a function which is executed for a valid token.
		SuccessHandler JWTSuccessHandler

		// ErrorHandler defines a function which is executed for an invalid token.
		// It may be used to define a custom JWT error.
		ErrorHandler JWTErrorHandler

		// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
		ErrorHandlerWithContext JWTErrorHandlerWithContext

		// Signing key to validate token. Used as fallback if SigningKeys has length 0.
		// Required. This or SigningKeys.
		SigningKey interface{}

		// Map of signing keys to validate token with kid field usage.
		// Required. This or SigningKey.
		SigningKeys map[string]interface{}

		// Signing method, used to check token signing method.
		// Optional. Default value HS256.
		SigningMethod string

		// Context key to store user information from the token into context.
		// Optional. Default value "user".
		ContextKey string

		// Claims are extendable claims data defining token content.
		// Optional. Default value jwt.MapClaims
		Claims jwt.Claims

		// TokenLookup is a string in the form of "<source>:<name>" that is used
		// to extract token from the request.
		// Optional. Default value "header:Authorization".
		// Possible values:
		// - "header:<name>"
		// - "query:<name>"
		// - "param:<name>"
		// - "cookie:<name>"
		TokenLookup string

		// AuthScheme to be used in the Authorization header.
		// Optional. Default value "Bearer".
		AuthScheme string

		keyFunc jwt.Keyfunc
	}

	// JWTSuccessHandler defines a function which is executed for a valid token.
	JWTSuccessHandler func(echo.Context)

	// JWTErrorHandler defines a function which is executed for an invalid token.
	JWTErrorHandler func(error) error

	// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
	JWTErrorHandlerWithContext func(error, echo.Context) error

	jwtExtractor func(echo.Context) (string, error)
)

// Algorithms
const (
	AlgorithmHS256 = "HS256"
)

// Errors
var (
	ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
)

var (
	// DefaultJWTConfig is the default JWT auth middleware config.
	DefaultJWTConfig = JWTConfig{
		Skipper:       DefaultSkipper,
		SigningMethod: AlgorithmHS256,
		ContextKey:    "user",
		TokenLookup:   "header:" + echo.HeaderAuthorization,
		AuthScheme:    "Bearer",
		Claims:        jwt.MapClaims{},
	}
)

// JWT returns a JSON Web Token (JWT) auth middleware.
//
// For valid token, it sets the user in context and calls next handler.
// For invalid token, it returns "401 - Unauthorized" error.
// For missing token, it returns "400 - Bad Request" error.
//
// See: https://jwt.io/introduction
// See `JWTConfig.TokenLookup`
func JWT(key interface{}) echo.MiddlewareFunc {
	c := DefaultJWTConfig
	c.SigningKey = key
	return JWTWithConfig(c)
}

// JWTWithConfig returns a JWT auth middleware with config.
// See: `JWT()`.
func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Skipper == nil {
		config.Skipper = DefaultJWTConfig.Skipper
	}
	if config.SigningKey == nil && len(config.SigningKeys) == 0 {
		panic("echo: jwt middleware requires signing key")
	}
	if config.SigningMethod == "" {
		config.SigningMethod = DefaultJWTConfig.SigningMethod
	}
	if config.ContextKey == "" {
		config.ContextKey = DefaultJWTConfig.ContextKey
	}
	if config.Claims == nil {
		config.Claims = DefaultJWTConfig.Claims
	}
	if config.TokenLookup == "" {
		config.TokenLookup = DefaultJWTConfig.TokenLookup
	}
	if config.AuthScheme == "" {
		config.AuthScheme = DefaultJWTConfig.AuthScheme
	}
	config.keyFunc = func(t *jwt.Token) (interface{}, error) {
		// Check the signing method
		if t.Method.Alg() != config.SigningMethod {
			return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
		}
		if len(config.SigningKeys) > 0 {
			if kid, ok := t.Header["kid"].(string); ok {
				if key, ok := config.SigningKeys[kid]; ok {
					return key, nil
				}
			}
			return nil, fmt.Errorf("unexpected jwt key id=%v", t.Header["kid"])
		}

		return config.SigningKey, nil
	}

	// Initialize
	parts := strings.Split(config.TokenLookup, ":")
	extractor := jwtFromHeader(parts[1], config.AuthScheme)
	switch parts[0] {
	case "query":
		extractor = jwtFromQuery(parts[1])
	case "param":
		extractor = jwtFromParam(parts[1])
	case "cookie":
		extractor = jwtFromCookie(parts[1])
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			if config.BeforeFunc != nil {
				config.BeforeFunc(c)
			}

			auth, err := extractor(c)
			if err != nil {
				if config.ErrorHandler != nil {
					return config.ErrorHandler(err)
				}

				if config.ErrorHandlerWithContext != nil {
					return config.ErrorHandlerWithContext(err, c)
				}
				return err
			}
			token := new(jwt.Token)
			// Issue #647, #656
			if _, ok := config.Claims.(jwt.MapClaims); ok {
				token, err = jwt.Parse(auth, config.keyFunc)
			} else {
				t := reflect.ValueOf(config.Claims).Type().Elem()
				claims := reflect.New(t).Interface().(jwt.Claims)
				token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
			}
			if err == nil && token.Valid {
				// Store user information from token into context.
				c.Set(config.ContextKey, token)
				if config.SuccessHandler != nil {
					config.SuccessHandler(c)
				}
				return next(c)
			}
			if config.ErrorHandler != nil {
				return config.ErrorHandler(err)
			}
			if config.ErrorHandlerWithContext != nil {
				return config.ErrorHandlerWithContext(err, c)
			}
			return &echo.HTTPError{
				Code:     http.StatusUnauthorized,
				Message:  "invalid or expired jwt",
				Internal: err,
			}
		}
	}
}

// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
func jwtFromHeader(header string, authScheme string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		auth := c.Request().Header.Get(header)
		l := len(authScheme)
		if len(auth) > l+1 && auth[:l] == authScheme {
			return auth[l+1:], nil
		}
		return "", ErrJWTMissing
	}
}

// jwtFromQuery returns a `jwtExtractor` that extracts token from the query string.
func jwtFromQuery(param string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		token := c.QueryParam(param)
		if token == "" {
			return "", ErrJWTMissing
		}
		return token, nil
	}
}

// jwtFromParam returns a `jwtExtractor` that extracts token from the url param string.
func jwtFromParam(param string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		token := c.Param(param)
		if token == "" {
			return "", ErrJWTMissing
		}
		return token, nil
	}
}

// jwtFromCookie returns a `jwtExtractor` that extracts token from the named cookie.
func jwtFromCookie(name string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		cookie, err := c.Cookie(name)
		if err != nil {
			return "", ErrJWTMissing
		}
		return cookie.Value, nil
	}
}
<commit_msg>Create ErrJWTInvalid variable<commit_after>package middleware

import (
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/labstack/echo/v4"
)

type (
	// JWTConfig defines the config for JWT middleware.
	JWTConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper Skipper

		// BeforeFunc defines a function which is executed just before the middleware.
		BeforeFunc BeforeFunc

		// SuccessHandler defines a function which is executed for a valid token.
		SuccessHandler JWTSuccessHandler

		// ErrorHandler defines a function which is executed for an invalid token.
		// It may be used to define a custom JWT error.
		ErrorHandler JWTErrorHandler

		// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
		ErrorHandlerWithContext JWTErrorHandlerWithContext

		// Signing key to validate token. Used as fallback if SigningKeys has length 0.
		// Required. This or SigningKeys.
		SigningKey interface{}

		// Map of signing keys to validate token with kid field usage.
		// Required. This or SigningKey.
		SigningKeys map[string]interface{}

		// Signing method, used to check token signing method.
		// Optional. Default value HS256.
		SigningMethod string

		// Context key to store user information from the token into context.
		// Optional. Default value "user".
		ContextKey string

		// Claims are extendable claims data defining token content.
		// Optional. Default value jwt.MapClaims
		Claims jwt.Claims

		// TokenLookup is a string in the form of "<source>:<name>" that is used
		// to extract token from the request.
		// Optional. Default value "header:Authorization".
		// Possible values:
		// - "header:<name>"
		// - "query:<name>"
		// - "param:<name>"
		// - "cookie:<name>"
		TokenLookup string

		// AuthScheme to be used in the Authorization header.
		// Optional. Default value "Bearer".
		AuthScheme string

		keyFunc jwt.Keyfunc
	}

	// JWTSuccessHandler defines a function which is executed for a valid token.
	JWTSuccessHandler func(echo.Context)

	// JWTErrorHandler defines a function which is executed for an invalid token.
	JWTErrorHandler func(error) error

	// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
	JWTErrorHandlerWithContext func(error, echo.Context) error

	jwtExtractor func(echo.Context) (string, error)
)

// Algorithms
const (
	AlgorithmHS256 = "HS256"
)

// Errors
var (
	ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
	ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
)

var (
	// DefaultJWTConfig is the default JWT auth middleware config.
	DefaultJWTConfig = JWTConfig{
		Skipper:       DefaultSkipper,
		SigningMethod: AlgorithmHS256,
		ContextKey:    "user",
		TokenLookup:   "header:" + echo.HeaderAuthorization,
		AuthScheme:    "Bearer",
		Claims:        jwt.MapClaims{},
	}
)

// JWT returns a JSON Web Token (JWT) auth middleware.
//
// For valid token, it sets the user in context and calls next handler.
// For invalid token, it returns "401 - Unauthorized" error.
// For missing token, it returns "400 - Bad Request" error.
//
// See: https://jwt.io/introduction
// See `JWTConfig.TokenLookup`
func JWT(key interface{}) echo.MiddlewareFunc {
	c := DefaultJWTConfig
	c.SigningKey = key
	return JWTWithConfig(c)
}

// JWTWithConfig returns a JWT auth middleware with config.
// See: `JWT()`.
func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Skipper == nil {
		config.Skipper = DefaultJWTConfig.Skipper
	}
	if config.SigningKey == nil && len(config.SigningKeys) == 0 {
		panic("echo: jwt middleware requires signing key")
	}
	if config.SigningMethod == "" {
		config.SigningMethod = DefaultJWTConfig.SigningMethod
	}
	if config.ContextKey == "" {
		config.ContextKey = DefaultJWTConfig.ContextKey
	}
	if config.Claims == nil {
		config.Claims = DefaultJWTConfig.Claims
	}
	if config.TokenLookup == "" {
		config.TokenLookup = DefaultJWTConfig.TokenLookup
	}
	if config.AuthScheme == "" {
		config.AuthScheme = DefaultJWTConfig.AuthScheme
	}
	config.keyFunc = func(t *jwt.Token) (interface{}, error) {
		// Check the signing method
		if t.Method.Alg() != config.SigningMethod {
			return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
		}
		if len(config.SigningKeys) > 0 {
			if kid, ok := t.Header["kid"].(string); ok {
				if key, ok := config.SigningKeys[kid]; ok {
					return key, nil
				}
			}
			return nil, fmt.Errorf("unexpected jwt key id=%v", t.Header["kid"])
		}

		return config.SigningKey, nil
	}

	// Initialize
	parts := strings.Split(config.TokenLookup, ":")
	extractor := jwtFromHeader(parts[1], config.AuthScheme)
	switch parts[0] {
	case "query":
		extractor = jwtFromQuery(parts[1])
	case "param":
		extractor = jwtFromParam(parts[1])
	case "cookie":
		extractor = jwtFromCookie(parts[1])
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			if config.BeforeFunc != nil {
				config.BeforeFunc(c)
			}

			auth, err := extractor(c)
			if err != nil {
				if config.ErrorHandler != nil {
					return config.ErrorHandler(err)
				}

				if config.ErrorHandlerWithContext != nil {
					return config.ErrorHandlerWithContext(err, c)
				}
				return err
			}
			token := new(jwt.Token)
			// Issue #647, #656
			if _, ok := config.Claims.(jwt.MapClaims); ok {
				token, err = jwt.Parse(auth, config.keyFunc)
			} else {
				t := reflect.ValueOf(config.Claims).Type().Elem()
				claims := reflect.New(t).Interface().(jwt.Claims)
				token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
			}
			if err == nil && token.Valid {
				// Store user information from token into context.
				c.Set(config.ContextKey, token)
				if config.SuccessHandler != nil {
					config.SuccessHandler(c)
				}
				return next(c)
			}
			if config.ErrorHandler != nil {
				return config.ErrorHandler(err)
			}
			if config.ErrorHandlerWithContext != nil {
				return config.ErrorHandlerWithContext(err, c)
			}
			return &echo.HTTPError{
				Code:     ErrJWTInvalid.Code,
				Message:  ErrJWTInvalid.Message,
				Internal: err,
			}
		}
	}
}

// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
func jwtFromHeader(header string, authScheme string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		auth := c.Request().Header.Get(header)
		l := len(authScheme)
		if len(auth) > l+1 && auth[:l] == authScheme {
			return auth[l+1:], nil
		}
		return "", ErrJWTMissing
	}
}

// jwtFromQuery returns a `jwtExtractor` that extracts token from the query string.
func jwtFromQuery(param string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		token := c.QueryParam(param)
		if token == "" {
			return "", ErrJWTMissing
		}
		return token, nil
	}
}

// jwtFromParam returns a `jwtExtractor` that extracts token from the url param string.
func jwtFromParam(param string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		token := c.Param(param)
		if token == "" {
			return "", ErrJWTMissing
		}
		return token, nil
	}
}

// jwtFromCookie returns a `jwtExtractor` that extracts token from the named cookie.
func jwtFromCookie(name string) jwtExtractor {
	return func(c echo.Context) (string, error) {
		cookie, err := c.Cookie(name)
		if err != nil {
			return "", ErrJWTMissing
		}
		return cookie.Value, nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
	"strings"

	"github.com/cespare/argf"
	"github.com/cespare/stats/b"
)

type Stats struct {
	Count      float64
	min        float64
	max        float64
	sum        float64
	sumSquares float64
	sorted     []float64
}

func (s *Stats) Mean() float64 {
	return s.sum / s.Count
}

func (s *Stats) Stdev() float64 {
	return math.Sqrt(s.Count*s.sumSquares-(s.sum*s.sum)) / s.Count
}

func (s *Stats) Quant(q float64) float64 {
	if q < 0 || q > 1 {
		panic("bad quantile")
	}
	i := round((s.Count - 1) * q)
	return s.sorted[i]
}

func round(f float64) int { return int(f + 0.5) }

func printStat(name string, value float64) {
	fmt.Printf("%-15s %7.3f\n", name, value)
}

func StatsFromBtree(btree *b.Tree) *Stats {
	enum, err := btree.SeekFirst()
	if err != nil {
		panic(err)
	}
	s := &Stats{sorted: make([]float64, 0, btree.Len())}
	for {
		k, c, err := enum.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			panic(err)
		}
		if s.Count == 0 || k < s.min {
			s.min = k
		}
		if s.Count == 0 || k > s.max {
			s.max = k
		}
		for i := 0; i < int(c); i++ {
			s.sorted = append(s.sorted, k)
			s.Count++
			s.sum += k
			s.sumSquares += k * k
		}
	}
	return s
}

func main() {
	quantStr := flag.String("quantiles", "0.5,0.9,0.99", "Quantiles to record")
	printHist := flag.Bool("hist", false, "Print a histogram")
	histBuckets := flag.Int("buckets", 10, "How many buckets for the histogram")
	flag.Parse()

	if *histBuckets <= 1 {
		fmt.Fprintf(os.Stderr, "%d is an invalid number of buckets\n", *histBuckets)
	}

	var quants []float64
	for _, qs := range strings.Split(*quantStr, ",") {
		qs = strings.TrimSpace(qs)
		f, err := strconv.ParseFloat(qs, 64)
		if err != nil {
			fatal(err)
		}
		if f <= 0 || f >= 1 {
			fatal(fmt.Errorf("quantile values must be in (0, 1); got %f", f))
		}
		quants = append(quants, f)
	}

	btree := NewBTree()
	var nonNumericFound int64
	argf.Init(flag.Args())
	for argf.Scan() {
		s := argf.String()
		if s == "" {
			continue
		}
		v, err := strconv.ParseFloat(s, 64)
		if err != nil {
			nonNumericFound++
			continue
		}
		btree.Put(v, func(c uint, _ bool) (newC uint, write bool) { return c + 1, true })
	}
	if err := argf.Error(); err != nil {
		fatal(err)
	}
	if nonNumericFound > 0 {
		fmt.Fprintf(os.Stderr, "Warning: found %d non-numeric lines of input\n", nonNumericFound)
		return
	}
	if btree.Len() == 0 {
		fmt.Fprintln(os.Stderr, "Warning: no numbers given")
		return
	}
	stats := StatsFromBtree(btree)
	printStat("count", stats.Count)
	printStat("min", stats.min)
	printStat("max", stats.max)
	printStat("mean", stats.Mean())
	printStat("std. dev.", stats.Stdev())
	for _, q := range quants {
		name := fmt.Sprintf("quantile %f", q)
		name = strings.TrimRight(name, "0")
		printStat(name, stats.Quant(q))
	}
	if *printHist {
		fmt.Println(stats.Hist(*histBuckets))
	}
}

func fatal(err error) {
	fmt.Println(err)
	os.Exit(1)
}

func NewBTree() *b.Tree {
	return b.TreeNew(func(a, b float64) int {
		if a < b {
			return -1
		}
		if a == b {
			return 0
		}
		return 1
	})
}
<commit_msg>Fix some warning/error cases<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
	"strings"

	"github.com/cespare/argf"
	"github.com/cespare/stats/b"
)

type Stats struct {
	Count      float64
	min        float64
	max        float64
	sum        float64
	sumSquares float64
	sorted     []float64
}

func (s *Stats) Mean() float64 {
	return s.sum / s.Count
}

func (s *Stats) Stdev() float64 {
	return math.Sqrt(s.Count*s.sumSquares-(s.sum*s.sum)) / s.Count
}

func (s *Stats) Quant(q float64) float64 {
	if q < 0 || q > 1 {
		panic("bad quantile")
	}
	i := round((s.Count - 1) * q)
	return s.sorted[i]
}

func round(f float64) int { return int(f + 0.5) }

func printStat(name string, value float64) {
	fmt.Printf("%-15s %7.3f\n", name, value)
}

func StatsFromBtree(btree *b.Tree) *Stats {
	enum, err := btree.SeekFirst()
	if err != nil {
		panic(err)
	}
	s := &Stats{sorted: make([]float64, 0, btree.Len())}
	for {
		k, c, err := enum.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			panic(err)
		}
		if s.Count == 0 || k < s.min {
			s.min = k
		}
		if s.Count == 0 || k > s.max {
			s.max = k
		}
		for i := 0; i < int(c); i++ {
			s.sorted = append(s.sorted, k)
			s.Count++
			s.sum += k
			s.sumSquares += k * k
		}
	}
	return s
}

func main() {
	quantStr := flag.String("quantiles", "0.5,0.9,0.99", "Quantiles to record")
	printHist := flag.Bool("hist", false, "Print a histogram")
	histBuckets := flag.Int("buckets", 10, "How many buckets for the histogram")
	flag.Parse()

	if *histBuckets <= 1 {
		fmt.Fprintf(os.Stderr, "%d is an invalid number of buckets\n", *histBuckets)
	}

	var quants []float64
	for _, qs := range strings.Split(*quantStr, ",") {
		qs = strings.TrimSpace(qs)
		f, err := strconv.ParseFloat(qs, 64)
		if err != nil {
			fatal(err)
		}
		if f <= 0 || f >= 1 {
			fatal(fmt.Errorf("quantile values must be in (0, 1); got %f", f))
		}
		quants = append(quants, f)
	}

	btree := NewBTree()
	var nonNumericFound int64
	argf.Init(flag.Args())
	for argf.Scan() {
		s := argf.String()
		if s == "" {
			continue
		}
		v, err := strconv.ParseFloat(s, 64)
		if err != nil {
			nonNumericFound++
			continue
		}
		btree.Put(v, func(c uint, _ bool) (newC uint, write bool) { return c + 1, true })
	}
	if err := argf.Error(); err != nil {
		fatal(err)
	}
	if nonNumericFound > 0 {
		fmt.Fprintf(os.Stderr, "Warning: found %d non-numeric lines of input\n", nonNumericFound)
	}
	if btree.Len() == 0 {
		fmt.Fprintln(os.Stderr, "No numbers given")
		return
	}
	stats := StatsFromBtree(btree)
	printStat("count", stats.Count)
	printStat("min", stats.min)
	printStat("max", stats.max)
	printStat("mean", stats.Mean())
	printStat("std. dev.", stats.Stdev())
	for _, q := range quants {
		name := fmt.Sprintf("quantile %f", q)
		name = strings.TrimRight(name, "0")
		printStat(name, stats.Quant(q))
	}
	if *printHist {
		fmt.Println(stats.Hist(*histBuckets))
	}
}

func fatal(err error) {
	fmt.Println(err)
	os.Exit(1)
}

func NewBTree() *b.Tree {
	return b.TreeNew(func(a, b float64) int {
		if a < b {
			return -1
		}
		if a == b {
			return 0
		}
		return 1
	})
}
<|endoftext|>


<commit_before>package ultron

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"sync"
	"time"

	"go.uber.org/zap"
)

type (
	// RoundedMillisecond 将time.Duration四舍五入到ms后的对象
	RoundedMillisecond int64

	statsEntry struct {
		name              string                       // 统计对象名称
		numRequests       int64                        // 成功请求次数
		numFailures       int64                        // 失败次数
		totalResponseTime time.Duration                // 成功请求的response time总和，基于原始的响应时间
		minResponseTime   time.Duration                // 最快的响应时间
		maxResponseTime   time.Duration                // 最慢的响应时间
		trend             map[int64]int64              // 按时间轴（秒级）记录成功请求次数
		failuresTrend     map[int64]int64              // 按时间轴（妙计）记录错误的请求次数
		responseTimes     map[RoundedMillisecond]int64 // 按优化后的响应时间记录成功请求次数
		failuresTimes     map[string]int64             // 记录不同错误的次数
		startTime         time.Time                    // 第一次收到请求的时间
		lastRequestTime   time.Time                    // 最后一次收到请求的时间
		interval          time.Duration                // 统计时间间隔，影响 CurrentQPS()
		lock              *sync.RWMutex
	}

	// StatsCollector 统计集合
	StatsCollector struct {
		entries  map[string]*statsEntry
		receiver chan *TransactionResult
		ctx      context.Context
	}

	// StatsReport 输出报告
	StatsReport struct {
		Name          string           `json:"name"`
		Requests      int64            `json:"requests"`
		Min           int64            `json:"min"`
		Max           int64            `json:"max"`
		Median        int64            `json:"median"`
		Average       int64            `json:"average"`
		QPS           float64          `json:"qps"`
		Distributions map[string]int64 `json:"distributions"`
		Failures      map[string]int64 `json:"failure"`
		FullHistory   bool             `json:"full_history"`
		FailRation    float64          `json:"fail_ration"`
	}

	// TransactionResult 事务执行结果
	TransactionResult struct {
		Name     string
		Duration time.Duration
		Err      error
	}
)

func newStatsEntry(n string) *statsEntry {
	return &statsEntry{
		name:          n,
		trend:         map[int64]int64{},
		failuresTrend: map[int64]int64{},
		responseTimes: map[RoundedMillisecond]int64{},
		failuresTimes: map[string]int64{},
		interval:      time.Second * 5,
		lock:          &sync.RWMutex{},
	}
}

func (s *statsEntry) logSuccess(t time.Duration) {
	s.lock.Lock()
	defer s.lock.Unlock()

	s.numRequests++

	now := time.Now()
	if s.lastRequestTime.IsZero() {
		s.minResponseTime = t
		s.startTime = now
	}
	s.lastRequestTime = now

	if t < s.minResponseTime {
		s.minResponseTime = t
	}
	if t > s.maxResponseTime {
		s.maxResponseTime = t
	}
	s.totalResponseTime += t

	sec := now.Unix()
	if _, ok := s.trend[sec]; ok {
		s.trend[sec]++
	} else {
		s.trend[sec] = 1
	}

	rm := timeDurationToRoudedMillisecond(t)
	if _, ok := s.responseTimes[rm]; ok {
		s.responseTimes[rm]++
	} else {
		s.responseTimes[rm] = 1
	}
}

func (s *statsEntry) logFailure(e error) {
	s.lock.Lock()
	defer s.lock.Unlock()

	sec := time.Now().Unix()
	s.numFailures++
	info := e.Error()

	if _, ok := s.failuresTimes[info]; ok {
		s.failuresTimes[info]++
	} else {
		s.failuresTimes[info] = 1
	}

	if _, ok := s.failuresTrend[sec]; ok {
		s.failuresTrend[sec]++
	} else {
		s.failuresTrend[sec] = 1
	}
}

// TotalQPS 获取总的QPS
func (s *statsEntry) TotalQPS() float64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	return float64(s.numRequests) / s.lastRequestTime.Sub(s.startTime).Seconds()
}

// CurrentQPS 最近5秒的QPS
func (s *statsEntry) CurrentQPS() float64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	if s.lastRequestTime.IsZero() {
		return 0
	}
	end := s.lastRequestTime.Unix()
	start := s.lastRequestTime.Add(-s.interval).Unix()
	var total int64

	for k, v := range s.trend {
		if k >= start && k <= end {
			total += v
		}
	}
	return float64(total) / float64(s.interval/time.Second)
}

// Percentile 获取x%的响应时间
func (s *statsEntry) Percentile(f float64) time.Duration {
	s.lock.RLock()
	defer s.lock.RUnlock()

	if f <= 0.0 {
		return s.minResponseTime
	}

	if f >= 1.0 {
		return s.maxResponseTime
	}

	hint := int64(float64(s.numRequests)*f + .5)
	if hint == s.numRequests {
		return s.maxResponseTime
	}

	var times []RoundedMillisecond
	for k := range s.responseTimes {
		times = append(times, k)
	}

	sort.Slice(times, func(i, j int) bool { return times[i] < times[j] })
	for _, val := range times {
		counts := s.responseTimes[val]
		hint -= counts
		if hint <= 0 {
			return roundedMillisecondToDuration(val)
		}
	}
	Logger.Warn("occer error", zap.Int64("hint", hint))
	return time.Nanosecond // occur error
}

// Min 最快响应时间
func (s *statsEntry) Min() time.Duration {
	return s.minResponseTime
}

// Max 最慢响应时间
func (s *statsEntry) Max() time.Duration {
	return s.maxResponseTime
}

// Average 平均响应时间
func (s *statsEntry) Average() time.Duration {
	return time.Duration(int64(s.totalResponseTime) / int64(s.numRequests))
}

// Median 响应时间中位数
func (s *statsEntry) Median() time.Duration {
	return s.Percentile(.5)
}

// FailRation 错误率
func (s *statsEntry) FailRation() float64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	return float64(s.numFailures) / float64(s.numRequests+s.numFailures)
}

// Report 打印统计结果
func (s *statsEntry) Report(full bool) string {
	s.lock.RLock()
	defer s.lock.RUnlock()

	r := &StatsReport{
		Name:          s.name,
		Requests:      s.numRequests,
		Min:           timeDurationToMillsecond(s.Min()),
		Max:           timeDurationToMillsecond(s.Max()),
		Median:        timeDurationToMillsecond(s.Median()),
		Average:       timeDurationToMillsecond(s.Average()),
		Distributions: map[string]int64{},
		Failures:      s.failuresTimes,
		FullHistory:   full,
		FailRation:    s.FailRation(),
	}

	if full {
		r.QPS = s.TotalQPS()
	} else {
		r.QPS = s.CurrentQPS()
	}

	for _, percent := range []float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.97, 0.98, 0.99, 1.0} {
		r.Distributions[strconv.FormatFloat(percent, 'f', 2, 64)] = timeDurationToMillsecond(s.Percentile(percent))
	}

	b, _ := json.Marshal(r)
	ret := string(b)
	Logger.Info(fmt.Sprintf("StatsEntry - %s - %s", s.name, ret))
	return ret
}

// NewStatsCollector 实例化StatsCollector
func NewStatsCollector(ctx context.Context) *StatsCollector {
	return &StatsCollector{
		entries:  map[string]*statsEntry{},
		receiver: make(chan *TransactionResult),
		ctx:      ctx,
	}
}

func (c *StatsCollector) logSuccess(name string, t time.Duration) {
	if _, ok := c.entries[name]; !ok {
		c.entries[name] = newStatsEntry(name)
	}
	c.entries[name].logSuccess(t)
}

func (c *StatsCollector) logFailure(name string, err error) {
	if _, ok := c.entries[name]; !ok {
		c.entries[name] = newStatsEntry(name)
	}
	c.entries[name].logFailure(err)
}

// Receiving 主函数，监听channel进行统计
func (c *StatsCollector) Receiving() {
	for r := range c.receiver {
		// Todo: ctx
		if r.Err == nil {
			c.logSuccess(r.Name, r.Duration)
		} else {
			c.logFailure(r.Name, r.Err)
		}
	}
}

// Receiver 返回接收事务结果通道
func (c *StatsCollector) Receiver() chan<- *TransactionResult {
	return c.receiver
}
<commit_msg>update<commit_after>package ultron

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"sync"
	"time"

	"go.uber.org/zap"
)

var timeDistributions = [10]float64{0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.97, 0.98, 0.99, 1.0}

type (
	// RoundedMillisecond 将time.Duration四舍五入到ms后的对象
	RoundedMillisecond int64

	statsEntry struct {
		name              string                       // 统计对象名称
		numRequests       int64                        // 成功请求次数
		numFailures       int64                        // 失败次数
		totalResponseTime time.Duration                // 成功请求的response time总和，基于原始的响应时间
		minResponseTime   time.Duration                // 最快的响应时间
		maxResponseTime   time.Duration                // 最慢的响应时间
		trend             map[int64]int64              // 按时间轴（秒级）记录成功请求次数
		failuresTrend     map[int64]int64              // 按时间轴（妙计）记录错误的请求次数
		responseTimes     map[RoundedMillisecond]int64 // 按优化后的响应时间记录成功请求次数
		failuresTimes     map[string]int64             // 记录不同错误的次数
		startTime         time.Time                    // 第一次收到请求的时间
		lastRequestTime   time.Time                    // 最后一次收到请求的时间
		interval          time.Duration                // 统计时间间隔，影响 CurrentQPS()
		lock              *sync.RWMutex
	}

	// StatsCollector 统计集合
	StatsCollector struct {
		entries  map[string]*statsEntry
		receiver chan *TransactionResult
		ctx      context.Context
	}

	// StatsReport 输出报告
	StatsReport struct {
		Name          string           `json:"name"`
		Requests      int64            `json:"requests"`
		Min           int64            `json:"min"`
		Max           int64            `json:"max"`
		Median        int64            `json:"median"`
		Average       int64            `json:"average"`
		QPS           float64          `json:"qps"`
		Distributions map[string]int64 `json:"distributions"`
		Failures      map[string]int64 `json:"failure"`
		FullHistory   bool             `json:"full_history"`
		FailRation    float64          `json:"fail_ration"`
	}

	// TransactionResult 事务执行结果
	TransactionResult struct {
		Name     string
		Duration time.Duration
		Err      error
	}
)

func newStatsEntry(n string) *statsEntry {
	return &statsEntry{
		name:          n,
		trend:         map[int64]int64{},
		failuresTrend: map[int64]int64{},
		responseTimes: map[RoundedMillisecond]int64{},
		failuresTimes: map[string]int64{},
		interval:      time.Second * 5,
		lock:          &sync.RWMutex{},
	}
}

func (s *statsEntry) logSuccess(t time.Duration) {
	s.lock.Lock()
	defer s.lock.Unlock()

	s.numRequests++

	now := time.Now()
	if s.lastRequestTime.IsZero() {
		s.minResponseTime = t
		s.startTime = now
	}
	s.lastRequestTime = now

	if t < s.minResponseTime {
		s.minResponseTime = t
	}
	if t > s.maxResponseTime {
		s.maxResponseTime = t
	}
	s.totalResponseTime += t

	sec := now.Unix()
	if _, ok := s.trend[sec]; ok {
		s.trend[sec]++
	} else {
		s.trend[sec] = 1
	}

	rm := timeDurationToRoudedMillisecond(t)
	if _, ok := s.responseTimes[rm]; ok {
		s.responseTimes[rm]++
	} else {
		s.responseTimes[rm] = 1
	}
}

func (s *statsEntry) logFailure(e error) {
	s.lock.Lock()
	defer s.lock.Unlock()

	sec := time.Now().Unix()
	s.numFailures++
	info := e.Error()

	if _, ok := s.failuresTimes[info]; ok {
		s.failuresTimes[info]++
	} else {
		s.failuresTimes[info] = 1
	}

	if _, ok := s.failuresTrend[sec]; ok {
		s.failuresTrend[sec]++
	} else {
		s.failuresTrend[sec] = 1
	}
}

// TotalQPS 获取总的QPS
func (s *statsEntry) TotalQPS() float64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	return float64(s.numRequests) / s.lastRequestTime.Sub(s.startTime).Seconds()
}

// CurrentQPS 最近5秒的QPS
func (s *statsEntry) CurrentQPS() float64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	if s.lastRequestTime.IsZero() {
		return 0
	}
	end := s.lastRequestTime.Unix()
	start := s.lastRequestTime.Add(-s.interval).Unix()
	var total int64

	for k, v := range s.trend {
		if k >= start && k <= end {
			total += v
		}
	}
	return float64(total) / float64(s.interval/time.Second)
}

// Percentile 获取x%的响应时间
func (s *statsEntry) Percentile(f float64) time.Duration {
	s.lock.RLock()
	defer s.lock.RUnlock()

	if f <= 0.0 {
		return s.minResponseTime
	}

	if f >= 1.0 {
		return s.maxResponseTime
	}

	hint := int64(float64(s.numRequests)*f + .5)
	if hint == s.numRequests {
		return s.maxResponseTime
	}

	var times []RoundedMillisecond
	for k := range s.responseTimes {
		times = append(times, k)
	}

	sort.Slice(times, func(i, j int) bool { return times[i] < times[j] })
	for _, val := range times {
		counts := s.responseTimes[val]
		hint -= counts
		if hint <= 0 {
			return roundedMillisecondToDuration(val)
		}
	}
	Logger.Warn("occer error", zap.Int64("hint", hint))
	return time.Nanosecond // occur error
}

// Min 最快响应时间
func (s *statsEntry) Min() time.Duration {
	return s.minResponseTime
}

// Max 最慢响应时间
func (s *statsEntry) Max() time.Duration {
	return s.maxResponseTime
}

// Average 平均响应时间
func (s *statsEntry) Average() time.Duration {
	return time.Duration(int64(s.totalResponseTime) / int64(s.numRequests))
}

// Median 响应时间中位数
func (s *statsEntry) Median() time.Duration {
	return s.Percentile(.5)
}

// FailRation 错误率
func (s *statsEntry) FailRation() float64 {
	s.lock.RLock()
	defer s.lock.RUnlock()

	return float64(s.numFailures) / float64(s.numRequests+s.numFailures)
}

// Report 打印统计结果
func (s *statsEntry) Report(full bool) string {
	s.lock.RLock()
	defer s.lock.RUnlock()

	r := &StatsReport{
		Name:          s.name,
		Requests:      s.numRequests,
		Min:           timeDurationToMillsecond(s.Min()),
		Max:           timeDurationToMillsecond(s.Max()),
		Median:        timeDurationToMillsecond(s.Median()),
		Average:       timeDurationToMillsecond(s.Average()),
		Distributions: map[string]int64{},
		Failures:      s.failuresTimes,
		FullHistory:   full,
		FailRation:    s.FailRation(),
	}

	if full {
		r.QPS = s.TotalQPS()
	} else {
		r.QPS = s.CurrentQPS()
	}

	for _, percent := range timeDistributions {
		r.Distributions[strconv.FormatFloat(percent, 'f', 2, 64)] = timeDurationToMillsecond(s.Percentile(percent))
	}

	b, _ := json.Marshal(r)
	ret := string(b)
	Logger.Info(fmt.Sprintf("StatsEntry - %s - %s", s.name, ret))
	return ret
}

// NewStatsCollector 实例化StatsCollector
func NewStatsCollector(ctx context.Context) *StatsCollector {
	return &StatsCollector{
		entries:  map[string]*statsEntry{},
		receiver: make(chan *TransactionResult),
		ctx:      ctx,
	}
}

func (c *StatsCollector) logSuccess(name string, t time.Duration) {
	if _, ok := c.entries[name]; !ok {
		c.entries[name] = newStatsEntry(name)
	}
	c.entries[name].logSuccess(t)
}

func (c *StatsCollector) logFailure(name string, err error) {
	if _, ok := c.entries[name]; !ok {
		c.entries[name] = newStatsEntry(name)
	}
	c.entries[name].logFailure(err)
}

// Receiving 主函数，监听channel进行统计
func (c *StatsCollector) Receiving() {
	for r := range c.receiver {
		// Todo: ctx
		if r.Err == nil {
			c.logSuccess(r.Name, r.Duration)
		} else {
			c.logFailure(r.Name, r.Err)
		}
	}
}

// Receiver 返回接收事务结果通道
func (c *StatsCollector) Receiver() chan<- *TransactionResult {
	return c.receiver
}
<|endoftext|>


<commit_before>package stats

import (
	"sort"
)

func Mean(input []float64) (mean float64) {

	// Easy as pie, this one
	if len(input) == 0 {
		return 0.0
	}

	// Add the total up
	for _, n := range input {
		mean += float64(n)
	}

	// Return the mean average
	return mean / float64(len(input))
}

func Median(input []float64) (median float64) {

	// Sort the numbers
	sort.Float64s(input)

	// Get the length
	l := len(input)

	// No math needed
	if l == 0 {
		return 0.0

		// For even numbers we add the two middle numbers
		// and divide by two using the mean function above
	} else if l%2 == 0 {
		median = Mean(input[l/2-1 : l/2+1])

		// For odd numbers we just use the middle number
	} else {
		median = float64(input[l/2])
	}

	return median
}

func Mode(input []float64) []float64 {

	// Create a map to hold the counts
	m := make(map[float64]int)
	for _, v := range input {
		m[v]++
	}

	// Find the highest counts to return as a slice
	// of ints to accomodate duplicate counts
	var mode []float64
	var current int
	for k, v := range m {

		// Depending if the count is lower, higher
		// or equal to the current numbers count
		// we return nothing, start a new mode or
		// append to the current mode
		switch {
		case v < current:
		case v > current:
			current = v
			mode = append(mode[:0], k)
		default:
			mode = append(mode, k)
		}
	}

	// Finally we check to see if there actually was
	// a mode by checking the length of the input and
	// mode against eachother
	l := len(input)
	lm := len(mode)

	if l == lm {
		return []float64{}
	} else {
		return mode
	}
}

func Min(input []float64) (min float64) {
	if len(input) > 0 {
		min = input[0]
	}
	for i := 1; i < len(input); i++ {
		if input[i] < min {
			min = input[i]
		}
	}
	return min
}

func Max(input []float64) (max float64) {
	if len(input) > 0 {
		max = input[0]
	}
	for i := 1; i < len(input); i++ {
		if input[i] > max {
			max = input[i]
		}
	}
	return max
}
<commit_msg>Simplify min/max function<commit_after>package stats

import (
	"sort"
)

func Mean(input []float64) (mean float64) {

	// Easy as pie, this one
	if len(input) == 0 {
		return 0.0
	}

	// Add the total up
	for _, n := range input {
		mean += float64(n)
	}

	// Return the mean average
	return mean / float64(len(input))
}

func Median(input []float64) (median float64) {

	// Sort the numbers
	sort.Float64s(input)

	// Get the length
	l := len(input)

	// No math needed
	if l == 0 {
		return 0.0

		// For even numbers we add the two middle numbers
		// and divide by two using the mean function above
	} else if l%2 == 0 {
		median = Mean(input[l/2-1 : l/2+1])

		// For odd numbers we just use the middle number
	} else {
		median = float64(input[l/2])
	}

	return median
}

func Mode(input []float64) []float64 {

	// Create a map to hold the counts
	m := make(map[float64]int)
	for _, v := range input {
		m[v]++
	}

	// Find the highest counts to return as a slice
	// of ints to accomodate duplicate counts
	var mode []float64
	var current int
	for k, v := range m {

		// Depending if the count is lower, higher
		// or equal to the current numbers count
		// we return nothing, start a new mode or
		// append to the current mode
		switch {
		case v < current:
		case v > current:
			current = v
			mode = append(mode[:0], k)
		default:
			mode = append(mode, k)
		}
	}

	// Finally we check to see if there actually was
	// a mode by checking the length of the input and
	// mode against eachother
	l := len(input)
	lm := len(mode)

	if l == lm {
		return []float64{}
	} else {
		return mode
	}
}

func Min(input []float64) (min float64) {
	sort.Float64s(input)
	return input[0]
}

func Max(input []float64) (max float64) {
	sort.Float64s(input)
	return input[len(input)-1]
}
<|endoftext|>


<commit_before>package zalando

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

	"github.com/gin-gonic/gin"
	"github.com/golang/glog"
	"github.com/zalando-techmonkeys/gin-oauth2"
	"golang.org/x/oauth2"
)

type TeamInfo struct {
	Id      string
	Id_name string
	Team_id string
	Type    string
	Name    string
	Mail    []string
}

type AccessTuple struct {
	Realm string // p.e. "employees", "services"
	Uid   string // UnixName
	Cn    string // RealName
}

var OAuth2Endpoint = oauth2.Endpoint{
	AuthURL:  "https://token.auth.zalando.com/access_token",
	TokenURL: "https://auth.zalando.com/z/oauth2/tokeninfo",
}

var TeamAPI string = "https://teams.auth.zalando.com/api/teams"

var AccessTuples []AccessTuple

func RequestTeamInfo(tc *ginoauth2.TokenContainer, uri string) ([]byte, error) {
	var uv = make(url.Values)
	uv.Set("member", tc.Scopes["uid"].(string))
	info_url := uri + "?" + uv.Encode()
	client := &http.Client{Transport: &ginoauth2.Transport}
	req, err := http.NewRequest("GET", info_url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tc.Token.AccessToken))

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

func GroupCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		glog.Error("failed to get team info, caused by: ", err)
		return false
	}
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
		return false
	}
	for _, teamInfo := range data {
		for idx := range AccessTuples {
			at := AccessTuples[idx]
			if teamInfo.Id == at.Uid {
				ctx.Set("uid", tc.Scopes["uid"].(string))
				ctx.Set("team", teamInfo.Id)
				glog.Infof("Grant access to %s as team member of \"%s\"\n", tc.Scopes["uid"].(string), teamInfo.Id)
				return true
			}
		}
	}

	return false
}

// Authorization function that checks UID scope
// TokenContainer must be Valid
// gin.Context gin contex
func UidCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	uid := tc.Scopes["uid"].(string)
	for idx := range AccessTuples {
		at := AccessTuples[idx]
		if uid == at.Uid {
			ctx.Set("uid", uid) //in this way I can set the authorized uid
			glog.Infof("Grant access to %s\n", uid)
			return true
		}
	}

	return false
}

//NoAuthorization sets "team" and "uid" in the context without checking if the user/team is authorized
func NoAuthorization(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
	}
	for _, teamInfo := range data {
		ctx.Set("uid", tc.Scopes["uid"].(string))
		ctx.Set("team", teamInfo.Id)
	}
	return true
}
<commit_msg>Fixed zalando team auth functions<commit_after>package zalando

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

	"github.com/gin-gonic/gin"
	"github.com/golang/glog"
	"github.com/zalando-techmonkeys/gin-oauth2"
	"golang.org/x/oauth2"
)

type TeamInfo struct {
	Id      string
	Id_name string
	Team_id string
	Type    string
	Name    string
	Mail    []string
}

type AccessTuple struct {
	Realm string // p.e. "employees", "services"
	Uid   string // UnixName
	Cn    string // RealName
}

var OAuth2Endpoint = oauth2.Endpoint{
	AuthURL:  "https://token.auth.zalando.com/access_token",
	TokenURL: "https://auth.zalando.com/z/oauth2/tokeninfo",
}

var TeamAPI string = "https://teams.auth.zalando.com/api/teams"

var AccessTuples []AccessTuple

func RequestTeamInfo(tc *ginoauth2.TokenContainer, uri string) ([]byte, error) {
	var uv = make(url.Values)
	uv.Set("member", tc.Scopes["uid"].(string))
	info_url := uri + "?" + uv.Encode()
	client := &http.Client{Transport: &ginoauth2.Transport}
	req, err := http.NewRequest("GET", info_url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tc.Token.AccessToken))

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

func GroupCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		glog.Error("failed to get team info, caused by: ", err)
		return false
	}
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
		return false
	}
	granted := false
	for _, teamInfo := range data {
		for idx := range AccessTuples {
			at := AccessTuples[idx]
			if teamInfo.Id == at.Uid {
				granted = true
				glog.Infof("Grant access to %s as team member of \"%s\"\n", tc.Scopes["uid"].(string), teamInfo.Id)
			}
			if teamInfo.Type == "official" {
				ctx.Set("uid", tc.Scopes["uid"].(string))
				ctx.Set("team", teamInfo.Id)
			}
		}
	}
	return granted
}

// Authorization function that checks UID scope
// TokenContainer must be Valid
// gin.Context gin contex
func UidCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	uid := tc.Scopes["uid"].(string)
	for idx := range AccessTuples {
		at := AccessTuples[idx]
		if uid == at.Uid {
			ctx.Set("uid", uid) //in this way I can set the authorized uid
			glog.Infof("Grant access to %s\n", uid)
			return true
		}
	}

	return false
}

//NoAuthorization sets "team" and "uid" in the context without checking if the user/team is authorized
func NoAuthorization(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
	}
	for _, teamInfo := range data {
		if teamInfo.Type == "official" {
			ctx.Set("uid", tc.Scopes["uid"].(string))
			ctx.Set("team", teamInfo.Id)
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"gob"
	"io"
	"os"
	"sync"
)

type Store struct {
	urls  map[string]string
	count int64
	mu    sync.Mutex
}

func NewStore() *Store {
	return &Store{urls: make(map[string]string)}
}

func (s *Store) Get(key string) string {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.urls[key]
}

func (s *Store) Set(target string) string {
	s.mu.Lock()
	defer s.mu.Unlock()
	var key string
	for {
		key = base36(s.count)
		s.count++
		if _, ok := s.urls[key]; !ok {
			break
		}
	}
	s.urls[key] = target
	return key
}

func (s *Store) SetCustom(key, target string) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.urls[key] = target
}

func (s *Store) WriteTo(w io.Writer) os.Error {
	e := gob.NewEncoder(w)
	s.mu.Lock()
	defer s.mu.Unlock()
	return e.Encode(s)
}

func (s *Store) ReadFrom(r io.Reader) os.Error {
	d := gob.NewDecoder(r)
	s.mu.Lock()
	defer s.mu.Unlock()
	return d.Decode(s)
}

var base36Char = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func base36(n int64) string {
	if n == 0 {
		return string(base36Char[0])
	}
	s := make([]byte, 20)
	i := len(s)
	for n > 0 && i >= 0 {
		i--
		j := n % 36
		n = (n - j) / 36
		s[i] = base36Char[j]
	}
	return string(s[i:])
}
<commit_msg>fix key function<commit_after>package main

import (
	"gob"
	"io"
	"os"
	"sync"
)

type Store struct {
	urls  map[string]string
	count int64
	mu    sync.Mutex
}

func NewStore() *Store {
	return &Store{urls: make(map[string]string)}
}

func (s *Store) Get(key string) string {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.urls[key]
}

func (s *Store) Set(target string) string {
	s.mu.Lock()
	defer s.mu.Unlock()
	var key string
	for {
		key = genKey(s.count)
		s.count++
		if _, ok := s.urls[key]; !ok {
			break
		}
	}
	s.urls[key] = target
	return key
}

func (s *Store) SetCustom(key, target string) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.urls[key] = target
}

func (s *Store) WriteTo(w io.Writer) os.Error {
	e := gob.NewEncoder(w)
	s.mu.Lock()
	defer s.mu.Unlock()
	return e.Encode(s)
}

func (s *Store) ReadFrom(r io.Reader) os.Error {
	d := gob.NewDecoder(r)
	s.mu.Lock()
	defer s.mu.Unlock()
	return d.Decode(s)
}

var keyChar = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func genKey(n int64) string {
	if n == 0 {
		return string(keyChar[0])
	}
	l := int64(len(keyChar))
	s := make([]byte, 20) // FIXME: will overflow. eventually.
	i := len(s)
	for n > 0 && i >= 0 {
		i--
		j := n % l
		n = (n - j) / l
		s[i] = keyChar[j]
	}
	return string(s[i:])
}
<|endoftext|>


<commit_before>package fwk

import (
	"reflect"
)

type achan chan interface{}

type datastore struct {
	SvcBase
	store map[string]achan
	quit  chan struct{}
}

func (ds *datastore) Configure(ctx Context) error {
	return nil
}

func (ds *datastore) Get(k string) (interface{}, error) {
	ch, ok := ds.store[k]
	if !ok {
		return nil, Errorf("Store.Get: no such key [%v]", k)
	}
	select {
	case v, ok := <-ch:
		if !ok {
			return nil, Errorf("%s: closed channel for key [%s]", ds.Name(), k)
		}
		ch <- v
		return v, nil
	case <-ds.quit:
		return nil, Errorf("%s: timeout to get [%s]", ds.Name(), k)
	}
}

func (ds *datastore) Put(k string, v interface{}) error {
	select {
	case ds.store[k] <- v:
		return nil
	case <-ds.quit:
		return Errorf("%s: timeout to put [%s]", ds.Name(), k)
	}
}

func (ds *datastore) Has(k string) bool {
	_, ok := ds.store[k]
	return ok
}

func (ds *datastore) StartSvc(ctx Context) error {
	ds.store = make(map[string]achan)
	return nil
}

func (ds *datastore) StopSvc(ctx Context) error {
	ds.store = nil
	return nil
}

// reset deletes the payload and resets the associated channel
func (ds *datastore) reset(keys []string) error {
	var err error
	for _, k := range keys {
		ch, ok := ds.store[k]
		if ok {
			select {
			case vv := <-ch:
				if vv, ok := vv.(Deleter); ok {
					err = vv.Delete()
					if err != nil {
						return err
					}
				}
			default:
			}
		}
		ds.store[k] = make(achan, 1)
	}
	ds.quit = make(chan struct{})
	return err
}

// close notifies components hanging on store.Get or .Put that event has been aborted
func (ds *datastore) close() {
	close(ds.quit)
}

func init() {
	Register(reflect.TypeOf(datastore{}),
		func(typ, name string, mgr App) (Component, error) {
			return &datastore{
				SvcBase: NewSvc(typ, name, mgr),
				store:   make(map[string]achan),
				quit:    make(chan struct{}),
			}, nil
		},
	)
}

// interface tests
var _ Store = (*datastore)(nil)

// EOF
<commit_msg>store: StopSvc now just reinitialize underlying store<commit_after>package fwk

import (
	"reflect"
)

type achan chan interface{}

type datastore struct {
	SvcBase
	store map[string]achan
	quit  chan struct{}
}

func (ds *datastore) Configure(ctx Context) error {
	return nil
}

func (ds *datastore) Get(k string) (interface{}, error) {
	ch, ok := ds.store[k]
	if !ok {
		return nil, Errorf("Store.Get: no such key [%v]", k)
	}
	select {
	case v, ok := <-ch:
		if !ok {
			return nil, Errorf("%s: closed channel for key [%s]", ds.Name(), k)
		}
		ch <- v
		return v, nil
	case <-ds.quit:
		return nil, Errorf("%s: timeout to get [%s]", ds.Name(), k)
	}
}

func (ds *datastore) Put(k string, v interface{}) error {
	select {
	case ds.store[k] <- v:
		return nil
	case <-ds.quit:
		return Errorf("%s: timeout to put [%s]", ds.Name(), k)
	}
}

func (ds *datastore) Has(k string) bool {
	_, ok := ds.store[k]
	return ok
}

func (ds *datastore) StartSvc(ctx Context) error {
	ds.store = make(map[string]achan)
	return nil
}

func (ds *datastore) StopSvc(ctx Context) error {
	ds.store = make(map[string]achan)
	return nil
}

// reset deletes the payload and resets the associated channel
func (ds *datastore) reset(keys []string) error {
	var err error
	for _, k := range keys {
		ch, ok := ds.store[k]
		if ok {
			select {
			case vv := <-ch:
				if vv, ok := vv.(Deleter); ok {
					err = vv.Delete()
					if err != nil {
						return err
					}
				}
			default:
			}
		}
		ds.store[k] = make(achan, 1)
	}
	ds.quit = make(chan struct{})
	return err
}

// close notifies components hanging on store.Get or .Put that event has been aborted
func (ds *datastore) close() {
	close(ds.quit)
}

func init() {
	Register(reflect.TypeOf(datastore{}),
		func(typ, name string, mgr App) (Component, error) {
			return &datastore{
				SvcBase: NewSvc(typ, name, mgr),
				store:   make(map[string]achan),
				quit:    make(chan struct{}),
			}, nil
		},
	)
}

// interface tests
var _ Store = (*datastore)(nil)

// EOF
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"os"

	//_ "github.com/mattn/go-sqlite3"

	_ "github.com/lib/pq"
	"github.com/shopspring/decimal"
)

const DebitCreditPrecision int32 = 2

var accounts map[int64]*Account

var shares map[string]*Share

var netWorth decimal.Decimal

var db *sql.DB
var err error

var cfg Config

type Config struct {
	Listen string
	DSN    string
}

func main() {
	log.SetFlags(log.LstdFlags | log.Llongfile)
	// Data
	accounts = make(map[int64]*Account)
	shares = make(map[string]*Share)

	parseConfig()

	setupDB()

	loadData()

	r := setupRouting()

	// Bind to a port and pass our router in
	listen := cfg.Listen
	log.Printf("Starting server on %s\n", listen)
	r.Run(listen)
}

func parseConfig() {
	file, _ := os.Open("lunchmoney.json")
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&cfg)
	if err != nil {
		fmt.Println("error:", err)
	}
}

func setupDB() {
	// db, err = sql.Open("sqlite3", "./lunchmoney.db")
	db, err = sql.Open("postgres", cfg.DSN)
	if err != nil {
		log.Printf("Error connect to the db: %s\n", err)
	}

	err = db.Ping()
	if err != nil {
		log.Fatal("Error connecting to the db: %s\n", err)
	}
}

func loadData() {
	query := `SELECT
		id,
		name,
		currency_code,
		currency_symbol_left,
		currency_symbol_right,
		decimal_places,
		icon,
		is_active,
		cleared_total,
		total
	FROM accounts`

	var id int64
	var cleared_total, total decimal.Decimal
	var decimal_places int32
	var name, currency_code, currency_symbol_left, currency_symbol_right, icon string
	var is_active bool

	rows, err := db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&id,
			&name,
			&currency_code,
			&currency_symbol_left,
			&currency_symbol_right,
			&decimal_places,
			&icon,
			&is_active,
			&cleared_total,
			&total,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		acc := &Account{
			ID:                  id,
			Name:                name,
			CurrencyCode:        currency_code,
			CurrencySymbolLeft:  currency_symbol_left,
			CurrencySymbolRight: currency_symbol_right,
			DecimalPlaces:       decimal_places,
			Icon:                icon,
			IsActive:            is_active,
			clearedTotal:        cleared_total,
			Total:               total,
		}

		acc.LoadTransactions()

		netWorth = netWorth.Add(acc.GetTotal())
		// log.Printf("%v\n", acc)
		accounts[acc.ID] = acc
	}
	err = rows.Err()
	if err != nil {
		log.Printf("%s\n", err)
		return
	}

	query = `SELECT stockcode, qty FROM shares`

	var stockcode string
	var qty int64

	rows, err = db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&stockcode,
			&qty,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		share := &Share{
			Code: stockcode,
			Qty:  qty,
		}
		share.GetValue()
		// log.Println(share)

		shares[stockcode] = share

		netWorth = netWorth.Add(share.Value)
	}

}
<commit_msg>Allow a config file as the first argument to the app<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"

	//_ "github.com/mattn/go-sqlite3"

	_ "github.com/lib/pq"
	"github.com/shopspring/decimal"
)

const DebitCreditPrecision int32 = 2

var accounts map[int64]*Account

var shares map[string]*Share

var netWorth decimal.Decimal

var db *sql.DB
var err error

var configfile string

var cfg Config

type Config struct {
	Listen string
	DSN    string
}

func main() {
	log.SetFlags(log.LstdFlags | log.Llongfile)

	flag.Parse()
	configfile = flag.Arg(0)
	if configfile == "" {
		configfile = "lunchmoney.json"
	}

	file, _ := os.Open(configfile)
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&cfg)
	if err != nil {
		fmt.Println("error:", err)
	}

	// Data
	accounts = make(map[int64]*Account)
	shares = make(map[string]*Share)

	setupDB()

	loadData()

	r := setupRouting()

	// Bind to a port and pass our router in
	listen := cfg.Listen
	log.Printf("Starting server on %s\n", listen)
	r.Run(listen)
}

func setupDB() {
	// db, err = sql.Open("sqlite3", "./lunchmoney.db")
	db, err = sql.Open("postgres", cfg.DSN)
	if err != nil {
		log.Printf("Error connect to the db: %s\n", err)
	}

	err = db.Ping()
	if err != nil {
		log.Fatal("Error connecting to the db: %s\n", err)
	}
}

func loadData() {
	query := `SELECT
		id,
		name,
		currency_code,
		currency_symbol_left,
		currency_symbol_right,
		decimal_places,
		icon,
		is_active,
		cleared_total,
		total
	FROM accounts`

	var id int64
	var cleared_total, total decimal.Decimal
	var decimal_places int32
	var name, currency_code, currency_symbol_left, currency_symbol_right, icon string
	var is_active bool

	rows, err := db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&id,
			&name,
			&currency_code,
			&currency_symbol_left,
			&currency_symbol_right,
			&decimal_places,
			&icon,
			&is_active,
			&cleared_total,
			&total,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		acc := &Account{
			ID:                  id,
			Name:                name,
			CurrencyCode:        currency_code,
			CurrencySymbolLeft:  currency_symbol_left,
			CurrencySymbolRight: currency_symbol_right,
			DecimalPlaces:       decimal_places,
			Icon:                icon,
			IsActive:            is_active,
			clearedTotal:        cleared_total,
			Total:               total,
		}

		acc.LoadTransactions()

		netWorth = netWorth.Add(acc.GetTotal())
		// log.Printf("%v\n", acc)
		accounts[acc.ID] = acc
	}
	err = rows.Err()
	if err != nil {
		log.Printf("%s\n", err)
		return
	}

	query = `SELECT stockcode, qty FROM shares`

	var stockcode string
	var qty int64

	rows, err = db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&stockcode,
			&qty,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		share := &Share{
			Code: stockcode,
			Qty:  qty,
		}
		share.GetValue()
		// log.Println(share)

		shares[stockcode] = share

		netWorth = netWorth.Add(share.Value)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

// Start
type cmdStart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("start")
	cmd.Use = usage("start", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Start instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Start instances`))

	return cmd
}

// Pause
type cmdPause struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdPause) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("pause")
	cmd.Use = usage("pause", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Pause instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Pause instances`))
	cmd.Hidden = true

	return cmd
}

// Restart
type cmdRestart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdRestart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("restart")
	cmd.Use = usage("restart", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Restart instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Restart instances

The opposite of "lxc pause" is "lxc start".`))

	return cmd
}

// Stop
type cmdStop struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStop) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("stop")
	cmd.Use = usage("stop", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Stop instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Stop instances`))

	return cmd
}

type cmdAction struct {
	global *cmdGlobal

	flagAll       bool
	flagConsole   string
	flagForce     bool
	flagStateful  bool
	flagStateless bool
	flagTimeout   int
}

func (c *cmdAction) Command(action string) *cobra.Command {
	cmd := &cobra.Command{}
	cmd.RunE = c.Run

	cmd.Flags().BoolVar(&c.flagAll, "all", false, i18n.G("Run against all instances"))

	if action == "stop" {
		cmd.Flags().BoolVar(&c.flagStateful, "stateful", false, i18n.G("Store the instance state"))
	} else if action == "start" {
		cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Ignore the instance state"))
	}

	if shared.StringInSlice(action, []string{"start", "restart"}) {
		cmd.Flags().StringVar(&c.flagConsole, "console", "", i18n.G("Immediately attach to the console"))
		cmd.Flags().Lookup("console").NoOptDefVal = "console"
	}

	if shared.StringInSlice(action, []string{"restart", "stop"}) {
		cmd.Flags().BoolVarP(&c.flagForce, "force", "f", false, i18n.G("Force the instance to shutdown"))
		cmd.Flags().IntVar(&c.flagTimeout, "timeout", -1, i18n.G("Time to wait for the instance before killing it")+"``")
	}

	return cmd
}

func (c *cmdAction) doActionAll(action string, resource remoteResource) error {
	if resource.name != "" {
		// both --all and instance name given.
		return fmt.Errorf(i18n.G("Both --all and instance name given"))
	}

	remote := resource.remote
	d, err := c.global.conf.GetInstanceServer(remote)
	if err != nil {
		return err
	}

	// Pause is called freeze.
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to.
	state := false
	if action == "stop" && c.flagStateful {
		state = true
	}

	req := api.InstancesPut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	// Update all instances.
	op, err := d.UpdateInstances(req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{
		Quiet: c.global.flagQuiet,
	}

	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return err
	}

	progress.Done("")

	return nil
}

func (c *cmdAction) doAction(action string, conf *config.Config, nameArg string) error {
	state := false

	// Pause is called freeze
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to
	if action == "stop" && c.flagStateful {
		state = true
	}

	remote, name, err := conf.ParseRemote(nameArg)
	if err != nil {
		return err
	}

	d, err := conf.GetInstanceServer(remote)
	if err != nil {
		return err
	}

	if name == "" {
		return fmt.Errorf(i18n.G("Must supply instance name for: ")+"\"%s\"", nameArg)
	}

	if action == "start" {
		current, _, err := d.GetInstance(name)
		if err != nil {
			return err
		}

		// "start" for a frozen instance means "unfreeze"
		if current.StatusCode == api.Frozen {
			action = "unfreeze"
		}

		// Always restore state (if present) unless asked not to
		if action == "start" && current.Stateful && !c.flagStateless {
			state = true
		}
	}

	req := api.InstanceStatePut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	op, err := d.UpdateInstanceState(name, req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{
		Quiet: c.global.flagQuiet,
	}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	// Wait for operation to finish
	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
	}

	progress.Done("")

	// Handle console attach
	if c.flagConsole != "" {
		console := cmdConsole{}
		console.global = c.global
		console.flagType = c.flagConsole
		return console.Console(d, name)
	}

	return nil
}

func (c *cmdAction) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	var names []string
	if c.flagAll {
		// If no server passed, use current default.
		if len(args) == 0 {
			args = []string{fmt.Sprintf("%s:", conf.DefaultRemote)}
		}

		// Get all the servers.
		resources, err := c.global.ParseServers(args...)
		if err != nil {
			return err
		}

		for _, resource := range resources {
			// We don't allow instance names with --all.
			if resource.name != "" {
				return fmt.Errorf(i18n.G("Both --all and instance name given"))
			}

			// See if we can use the bulk API.
			if resource.server.HasExtension("instance_bulk_state_change") {
				err = c.doActionAll(cmd.Name(), resource)
				if err != nil {
					return fmt.Errorf("%s: %v", resource.remote, err)
				}

				continue
			}

			ctslist, err := resource.server.GetInstances(api.InstanceTypeAny)
			if err != nil {
				return err
			}

			for _, ct := range ctslist {
				switch cmd.Name() {
				case "start":
					if ct.StatusCode == api.Running {
						continue
					}
				case "stop":
					if ct.StatusCode == api.Stopped {
						continue
					}
				}
				names = append(names, fmt.Sprintf("%s:%s", resource.remote, ct.Name))
			}
		}
	} else {
		names = args

		if len(args) == 0 {
			cmd.Usage()
			return nil
		}
	}

	if c.flagConsole != "" {
		if c.flagAll {
			return fmt.Errorf(i18n.G("--console can't be used with --all"))
		}

		if len(names) != 1 {
			return fmt.Errorf(i18n.G("--console only works with a single instance"))
		}
	}

	// Run the action for every listed instance
	results := runBatch(names, func(name string) error { return c.doAction(cmd.Name(), conf, name) })

	// Single instance is easy
	if len(results) == 1 {
		return results[0].err
	}

	// Do fancier rendering for batches
	success := true

	for _, result := range results {
		if result.err == nil {
			continue
		}

		success = false
		msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
		for _, line := range strings.Split(msg, "\n") {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
		}
	}

	if !success {
		fmt.Fprintln(os.Stderr, "")
		return fmt.Errorf(i18n.G("Some instances failed to %s"), cmd.Name())
	}

	return nil
}
<commit_msg>lxc/action: Update to new InstancesPut<commit_after>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

// Start
type cmdStart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("start")
	cmd.Use = usage("start", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Start instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Start instances`))

	return cmd
}

// Pause
type cmdPause struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdPause) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("pause")
	cmd.Use = usage("pause", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Pause instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Pause instances`))
	cmd.Hidden = true

	return cmd
}

// Restart
type cmdRestart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdRestart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("restart")
	cmd.Use = usage("restart", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Restart instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Restart instances

The opposite of "lxc pause" is "lxc start".`))

	return cmd
}

// Stop
type cmdStop struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStop) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("stop")
	cmd.Use = usage("stop", i18n.G("[<remote>:]<instance> [[<remote>:]<instance>...]"))
	cmd.Short = i18n.G("Stop instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Stop instances`))

	return cmd
}

type cmdAction struct {
	global *cmdGlobal

	flagAll       bool
	flagConsole   string
	flagForce     bool
	flagStateful  bool
	flagStateless bool
	flagTimeout   int
}

func (c *cmdAction) Command(action string) *cobra.Command {
	cmd := &cobra.Command{}
	cmd.RunE = c.Run

	cmd.Flags().BoolVar(&c.flagAll, "all", false, i18n.G("Run against all instances"))

	if action == "stop" {
		cmd.Flags().BoolVar(&c.flagStateful, "stateful", false, i18n.G("Store the instance state"))
	} else if action == "start" {
		cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Ignore the instance state"))
	}

	if shared.StringInSlice(action, []string{"start", "restart"}) {
		cmd.Flags().StringVar(&c.flagConsole, "console", "", i18n.G("Immediately attach to the console"))
		cmd.Flags().Lookup("console").NoOptDefVal = "console"
	}

	if shared.StringInSlice(action, []string{"restart", "stop"}) {
		cmd.Flags().BoolVarP(&c.flagForce, "force", "f", false, i18n.G("Force the instance to shutdown"))
		cmd.Flags().IntVar(&c.flagTimeout, "timeout", -1, i18n.G("Time to wait for the instance before killing it")+"``")
	}

	return cmd
}

func (c *cmdAction) doActionAll(action string, resource remoteResource) error {
	if resource.name != "" {
		// both --all and instance name given.
		return fmt.Errorf(i18n.G("Both --all and instance name given"))
	}

	remote := resource.remote
	d, err := c.global.conf.GetInstanceServer(remote)
	if err != nil {
		return err
	}

	// Pause is called freeze.
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to.
	state := false
	if action == "stop" && c.flagStateful {
		state = true
	}

	req := api.InstancesPut{
		State: &api.InstanceStatePut{
			Action:   action,
			Timeout:  c.flagTimeout,
			Force:    c.flagForce,
			Stateful: state,
		},
	}

	// Update all instances.
	op, err := d.UpdateInstances(req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{
		Quiet: c.global.flagQuiet,
	}

	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return err
	}

	progress.Done("")

	return nil
}

func (c *cmdAction) doAction(action string, conf *config.Config, nameArg string) error {
	state := false

	// Pause is called freeze
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to
	if action == "stop" && c.flagStateful {
		state = true
	}

	remote, name, err := conf.ParseRemote(nameArg)
	if err != nil {
		return err
	}

	d, err := conf.GetInstanceServer(remote)
	if err != nil {
		return err
	}

	if name == "" {
		return fmt.Errorf(i18n.G("Must supply instance name for: ")+"\"%s\"", nameArg)
	}

	if action == "start" {
		current, _, err := d.GetInstance(name)
		if err != nil {
			return err
		}

		// "start" for a frozen instance means "unfreeze"
		if current.StatusCode == api.Frozen {
			action = "unfreeze"
		}

		// Always restore state (if present) unless asked not to
		if action == "start" && current.Stateful && !c.flagStateless {
			state = true
		}
	}

	req := api.InstanceStatePut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	op, err := d.UpdateInstanceState(name, req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{
		Quiet: c.global.flagQuiet,
	}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	// Wait for operation to finish
	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
	}

	progress.Done("")

	// Handle console attach
	if c.flagConsole != "" {
		console := cmdConsole{}
		console.global = c.global
		console.flagType = c.flagConsole
		return console.Console(d, name)
	}

	return nil
}

func (c *cmdAction) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	var names []string
	if c.flagAll {
		// If no server passed, use current default.
		if len(args) == 0 {
			args = []string{fmt.Sprintf("%s:", conf.DefaultRemote)}
		}

		// Get all the servers.
		resources, err := c.global.ParseServers(args...)
		if err != nil {
			return err
		}

		for _, resource := range resources {
			// We don't allow instance names with --all.
			if resource.name != "" {
				return fmt.Errorf(i18n.G("Both --all and instance name given"))
			}

			// See if we can use the bulk API.
			if resource.server.HasExtension("instance_bulk_state_change") {
				err = c.doActionAll(cmd.Name(), resource)
				if err != nil {
					return fmt.Errorf("%s: %v", resource.remote, err)
				}

				continue
			}

			ctslist, err := resource.server.GetInstances(api.InstanceTypeAny)
			if err != nil {
				return err
			}

			for _, ct := range ctslist {
				switch cmd.Name() {
				case "start":
					if ct.StatusCode == api.Running {
						continue
					}
				case "stop":
					if ct.StatusCode == api.Stopped {
						continue
					}
				}
				names = append(names, fmt.Sprintf("%s:%s", resource.remote, ct.Name))
			}
		}
	} else {
		names = args

		if len(args) == 0 {
			cmd.Usage()
			return nil
		}
	}

	if c.flagConsole != "" {
		if c.flagAll {
			return fmt.Errorf(i18n.G("--console can't be used with --all"))
		}

		if len(names) != 1 {
			return fmt.Errorf(i18n.G("--console only works with a single instance"))
		}
	}

	// Run the action for every listed instance
	results := runBatch(names, func(name string) error { return c.doAction(cmd.Name(), conf, name) })

	// Single instance is easy
	if len(results) == 1 {
		return results[0].err
	}

	// Do fancier rendering for batches
	success := true

	for _, result := range results {
		if result.err == nil {
			continue
		}

		success = false
		msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
		for _, line := range strings.Split(msg, "\n") {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
		}
	}

	if !success {
		fmt.Fprintln(os.Stderr, "")
		return fmt.Errorf(i18n.G("Some instances failed to %s"), cmd.Name())
	}

	return nil
}
<|endoftext|>