<commit_before>package paths

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

	"github.com/VonC/godbg"
)

// Path represents a path always '/' separated.
// Either filename or http://...
type Path struct {
	path string
}

// NewPath creates a new path.
// If it is a folder, it will end with a trailing '/'
func NewPath(p string) *Path {
	res := &Path{path: p}
	if strings.HasPrefix(res.path, "http") == false {
		res.path = filepath.FromSlash(p)
		// fmt.Printf("p '%s' vs. res.path '%s'\n", p, res.path)
		// If there is no trailing '/' (after the filepath.FromSlash() call),
		// check if one should be added:
		if !strings.HasSuffix(res.path, string(filepath.Separator)) && res.path != "" {
			if res.Exists() && res.IsDir() {
				res.path = res.path + string(filepath.Separator)
			}
		}
	}
	return res
}

// NewPathDir will create a Path *always* terminated with a traling '/'.
// Handy for folders which doesn't exist yet
func NewPathDir(p string) *Path {
	res := &Path{}
	res.path = filepath.FromSlash(p)
	if !strings.HasSuffix(res.path, string(filepath.Separator)) {
		res.path = res.path + string(filepath.Separator)
	}
	return res
}

// EndsWithSeparator checks if Paths ends with a filepath separator
func (p *Path) EndsWithSeparator() bool {
	if strings.HasSuffix(p.path, string(filepath.Separator)) {
		return true
	}
	return false
}

var fstat func(f *os.File) (fi os.FileInfo, err error)

func ifstat(f *os.File) (fi os.FileInfo, err error) {
	return f.Stat()
}

// IsDir checks is a path is an existing directory.
// If there is any error, it is printed on Stderr, but not returned.
func (p *Path) IsDir() bool {
	f, err := os.Open(p.path)
	if err != nil {
		fmt.Fprintln(godbg.Err(), err)
		return false
	}
	defer f.Close()
	fi, err := fstat(f)
	if err != nil {
		fmt.Fprintln(godbg.Err(), err)
		return false
	}
	switch mode := fi.Mode(); {
	case mode.IsDir():
		return true
	}
	return false
}

// SetDir makes sure a Path represents a folder (existing or not)
// That means it ends with a path separator
func (p *Path) SetDir() *Path {
	if p.EndsWithSeparator() {
		return p
	}
	return NewPathDir(p.path)
}

// Add adds a string path to a Path
// Makes sure the current path represents a folder first
// (existing or not it: just means making sure it ends with file separator)
func (p *Path) Add(s string) *Path {
	pp := p.SetDir()
	return NewPath(pp.path + s)
}

// Add adds a Path to a Path
// no check is done regarding the absolute path of the argument
func (p *Path) AddP(path *Path) *Path {
	return p.Add(path.path)
}

// NoSep makes sure the path doesn't end with a file separator.
// If it already was not ending with the file separator, it returns the same object. If it was, it returns a new Path.
func (p *Path) NoSep() *Path {
	if !p.EndsWithSeparator() {
		return p
	}
	pp := p.path
	for strings.HasSuffix(pp, string(filepath.Separator)) {
		pp = pp[:len(pp)-1]
	}
	res := &Path{}
	res.path = filepath.FromSlash(pp)
	return res
}

// AddNoSep adds a string path to a Path with no triling separator
func (p *Path) AddNoSep(s string) *Path {
	pp := p.NoSep()
	return NewPath(pp.path + s)
}

// Add adds a Path to a Path, making sure the resulting path doesn't end with a file separator
// no check is done regarding the absolute path of the argument
func (p *Path) AddPNoSep(path *Path) *Path {
	return p.AddNoSep(path.String())
}

var fosstat func(name string) (fi os.FileInfo, err error)

func ifosstat(name string) (fi os.FileInfo, err error) {
	return os.Stat(name)
}

// Exists returns whether the given file or directory exists or not
// http://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-denoted-by-a-path-exists-in-golang
func (p *Path) Exists() bool {
	path := filepath.FromSlash(p.path)
	_, err := fosstat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	//pdbg("Error while checking if '%v' exists: '%v'\n", path, err)
	//debug.PrintStack()
	//os.Exit(0)
	fmt.Fprintln(godbg.Err(), err)
	return false
}

// String display a (possibly abbreviated) string version of a Path.
// If nil, returns <nil>
// if too long (>200), display only the first 20 plus its length
func (p *Path) String() string {
	if p == nil {
		return "<nil>"
	}
	res := fmt.Sprint(p.path)
	if len(res) > 200 {
		res = res[:20] + fmt.Sprintf(" (%v)", len(res))
	}
	return res
}

var fosmkdirall func(path string, perm os.FileMode) error

func ifosmkdirall(path string, perm os.FileMode) error {
	return os.MkdirAll(path, perm)
}

// MkDir creates a directory named path, along with any necessary parents,
// and return true if created, false otherwise.
// Any error is printed on Stderr
func (p *Path) MkdirAll() bool {
	err := fosmkdirall(p.path, 0755)
	if err != nil {
		fmt.Fprintf(godbg.Err(), "Error creating folder for path '%v': '%v'\n", p.path, err)
		return false
	}
	return true
}

var fosopenfile func(name string, flag int, perm os.FileMode) (file *os.File, err error)

func ifosopenfile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
	return os.OpenFile(name, flag, perm)
}

var fosremove func(name string) error

func ifosremove(name string) error {
	return os.Remove(name)
}

// MustOpenFile create or append a file, or panic if issue.
// If the Path is a Dir, returns nil.
// The caller is responsible for closing the file
func (p *Path) MustOpenFile(append bool) (file *os.File) {
	if p.IsDir() {
		return nil
	}
	var err error
	if p.Exists() {
		if append {
			file, err = fosopenfile(p.path, os.O_APPEND|os.O_WRONLY, 0600)
		} else {
			err = fosremove(p.path)
		}
		if err != nil {
			panic(err)
		}
	}
	if file == nil {
		if file, err = fosopenfile(p.path, os.O_CREATE|os.O_WRONLY, 0600); err != nil {
			panic(err)
		}
	}
	return file
}

var ffpabs func(path string) (string, error)

func iffpabs(path string) (string, error) {
	return filepath.Abs(path)
}

// Abs returns the absolute path if it can, or nil if error
// The error is printed on stderr
// If the path ends with a separator, said separator is preserved
func (p *Path) Abs() *Path {
	res, err := ffpabs(p.path)
	if err != nil {
		fmt.Fprintf(godbg.Err(), "Unable to get full absollute path for '%v'\n%v\n", p.path, err)
		return nil
	}
	if strings.HasSuffix(p.path, string(filepath.Separator)) {
		return NewPathDir(res)
	}
	return NewPath(res)
}

// Dir is filepath.Dir() for Path:
// It returns all but the last element of path, typically the path's directory
// Its result still ends with a file separator
func (p *Path) Dir() *Path {
	pp := p.path
	for strings.HasSuffix(pp, string(filepath.Separator)) {
		pp = pp[:len(pp)-1]
	}
	return NewPathDir(filepath.Dir(pp))
}

// Base is filepath.Base():
// It returns the last element of path.
// Trailing path separators are removed before extracting the last element.
func (p *Path) Base() string {
	pp := p.path
	for strings.HasSuffix(pp, string(filepath.Separator)) {
		pp = pp[:len(pp)-1]
	}
	return filepath.Base(pp)
}

// Dot return a path prefixed with ".\" (dot plus file separator)
// If it already starts with ./, returns the same path
func (p *Path) Dot() *Path {
	if strings.HasPrefix(p.path, "."+string(filepath.Separator)) {
		return p
	}
	return NewPath("." + string(filepath.Separator) + p.path)
}

func init() {
	fstat = ifstat
	fosstat = ifosstat
	fosmkdirall = ifosmkdirall
	fosopenfile = ifosopenfile
	ffpabs = iffpabs
}
<commit_msg>[golint] fix comments<commit_after>package paths

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

	"github.com/VonC/godbg"
)

// Path represents a path always '/' separated.
// Either filename or http://...
type Path struct {
	path string
}

// NewPath creates a new path.
// If it is a folder, it will end with a trailing '/'
func NewPath(p string) *Path {
	res := &Path{path: p}
	if strings.HasPrefix(res.path, "http") == false {
		res.path = filepath.FromSlash(p)
		// fmt.Printf("p '%s' vs. res.path '%s'\n", p, res.path)
		// If there is no trailing '/' (after the filepath.FromSlash() call),
		// check if one should be added:
		if !strings.HasSuffix(res.path, string(filepath.Separator)) && res.path != "" {
			if res.Exists() && res.IsDir() {
				res.path = res.path + string(filepath.Separator)
			}
		}
	}
	return res
}

// NewPathDir will create a Path *always* terminated with a traling '/'.
// Handy for folders which doesn't exist yet
func NewPathDir(p string) *Path {
	res := &Path{}
	res.path = filepath.FromSlash(p)
	if !strings.HasSuffix(res.path, string(filepath.Separator)) {
		res.path = res.path + string(filepath.Separator)
	}
	return res
}

// EndsWithSeparator checks if Paths ends with a filepath separator
func (p *Path) EndsWithSeparator() bool {
	if strings.HasSuffix(p.path, string(filepath.Separator)) {
		return true
	}
	return false
}

var fstat func(f *os.File) (fi os.FileInfo, err error)

func ifstat(f *os.File) (fi os.FileInfo, err error) {
	return f.Stat()
}

// IsDir checks is a path is an existing directory.
// If there is any error, it is printed on Stderr, but not returned.
func (p *Path) IsDir() bool {
	f, err := os.Open(p.path)
	if err != nil {
		fmt.Fprintln(godbg.Err(), err)
		return false
	}
	defer f.Close()
	fi, err := fstat(f)
	if err != nil {
		fmt.Fprintln(godbg.Err(), err)
		return false
	}
	switch mode := fi.Mode(); {
	case mode.IsDir():
		return true
	}
	return false
}

// SetDir makes sure a Path represents a folder (existing or not)
// That means it ends with a path separator
func (p *Path) SetDir() *Path {
	if p.EndsWithSeparator() {
		return p
	}
	return NewPathDir(p.path)
}

// Add adds a string path to a Path
// Makes sure the current path represents a folder first
// (existing or not it: just means making sure it ends with file separator)
func (p *Path) Add(s string) *Path {
	pp := p.SetDir()
	return NewPath(pp.path + s)
}

// AddP adds a Path to a Path
// no check is done regarding the absolute path of the argument
func (p *Path) AddP(path *Path) *Path {
	return p.Add(path.path)
}

// NoSep makes sure the path doesn't end with a file separator.
// If it already was not ending with the file separator, it returns the same object. If it was, it returns a new Path.
func (p *Path) NoSep() *Path {
	if !p.EndsWithSeparator() {
		return p
	}
	pp := p.path
	for strings.HasSuffix(pp, string(filepath.Separator)) {
		pp = pp[:len(pp)-1]
	}
	res := &Path{}
	res.path = filepath.FromSlash(pp)
	return res
}

// AddNoSep adds a string path to a Path with no triling separator
func (p *Path) AddNoSep(s string) *Path {
	pp := p.NoSep()
	return NewPath(pp.path + s)
}

// AddPNoSep adds a Path to a Path, making sure the resulting path doesn't end with a file separator
// no check is done regarding the absolute path of the argument
func (p *Path) AddPNoSep(path *Path) *Path {
	return p.AddNoSep(path.String())
}

var fosstat func(name string) (fi os.FileInfo, err error)

func ifosstat(name string) (fi os.FileInfo, err error) {
	return os.Stat(name)
}

// Exists returns whether the given file or directory exists or not
// http://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-denoted-by-a-path-exists-in-golang
func (p *Path) Exists() bool {
	path := filepath.FromSlash(p.path)
	_, err := fosstat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	//pdbg("Error while checking if '%v' exists: '%v'\n", path, err)
	//debug.PrintStack()
	//os.Exit(0)
	fmt.Fprintln(godbg.Err(), err)
	return false
}

// String display a (possibly abbreviated) string version of a Path.
// If nil, returns <nil>
// if too long (>200), display only the first 20 plus its length
func (p *Path) String() string {
	if p == nil {
		return "<nil>"
	}
	res := fmt.Sprint(p.path)
	if len(res) > 200 {
		res = res[:20] + fmt.Sprintf(" (%v)", len(res))
	}
	return res
}

var fosmkdirall func(path string, perm os.FileMode) error

func ifosmkdirall(path string, perm os.FileMode) error {
	return os.MkdirAll(path, perm)
}

// MkdirAll creates a directory named path, along with any necessary parents,
// and return true if created, false otherwise.
// Any error is printed on Stderr
func (p *Path) MkdirAll() bool {
	err := fosmkdirall(p.path, 0755)
	if err != nil {
		fmt.Fprintf(godbg.Err(), "Error creating folder for path '%v': '%v'\n", p.path, err)
		return false
	}
	return true
}

var fosopenfile func(name string, flag int, perm os.FileMode) (file *os.File, err error)

func ifosopenfile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
	return os.OpenFile(name, flag, perm)
}

var fosremove func(name string) error

func ifosremove(name string) error {
	return os.Remove(name)
}

// MustOpenFile create or append a file, or panic if issue.
// If the Path is a Dir, returns nil.
// The caller is responsible for closing the file
func (p *Path) MustOpenFile(append bool) (file *os.File) {
	if p.IsDir() {
		return nil
	}
	var err error
	if p.Exists() {
		if append {
			file, err = fosopenfile(p.path, os.O_APPEND|os.O_WRONLY, 0600)
		} else {
			err = fosremove(p.path)
		}
		if err != nil {
			panic(err)
		}
	}
	if file == nil {
		if file, err = fosopenfile(p.path, os.O_CREATE|os.O_WRONLY, 0600); err != nil {
			panic(err)
		}
	}
	return file
}

var ffpabs func(path string) (string, error)

func iffpabs(path string) (string, error) {
	return filepath.Abs(path)
}

// Abs returns the absolute path if it can, or nil if error
// The error is printed on stderr
// If the path ends with a separator, said separator is preserved
func (p *Path) Abs() *Path {
	res, err := ffpabs(p.path)
	if err != nil {
		fmt.Fprintf(godbg.Err(), "Unable to get full absollute path for '%v'\n%v\n", p.path, err)
		return nil
	}
	if strings.HasSuffix(p.path, string(filepath.Separator)) {
		return NewPathDir(res)
	}
	return NewPath(res)
}

// Dir is filepath.Dir() for Path:
// It returns all but the last element of path, typically the path's directory
// Its result still ends with a file separator
func (p *Path) Dir() *Path {
	pp := p.path
	for strings.HasSuffix(pp, string(filepath.Separator)) {
		pp = pp[:len(pp)-1]
	}
	return NewPathDir(filepath.Dir(pp))
}

// Base is filepath.Base():
// It returns the last element of path.
// Trailing path separators are removed before extracting the last element.
func (p *Path) Base() string {
	pp := p.path
	for strings.HasSuffix(pp, string(filepath.Separator)) {
		pp = pp[:len(pp)-1]
	}
	return filepath.Base(pp)
}

// Dot return a path prefixed with ".\" (dot plus file separator)
// If it already starts with ./, returns the same path
func (p *Path) Dot() *Path {
	if strings.HasPrefix(p.path, "."+string(filepath.Separator)) {
		return p
	}
	return NewPath("." + string(filepath.Separator) + p.path)
}

func init() {
	fstat = ifstat
	fosstat = ifosstat
	fosmkdirall = ifosmkdirall
	fosopenfile = ifosopenfile
	ffpabs = iffpabs
}
<|endoftext|>


<commit_before>package listener

import (
	"github.com/bwmarrin/discordgo"
	"github.com/xackery/discordeq/discord"
	"github.com/xackery/eqemuconfig"
	"log"
	"strings"
	//"time"
)

func ListenToDiscord(config *eqemuconfig.Config, disco *discord.Discord) {

	var session *discordgo.Session
	var guild *discordgo.Guild
	var err error

	session = disco.GetSession()
	guild, err = session.Guild(config.Discord.ServerID)
	log.Println(guild.Name)
	log.Println(guild.Members)
	if err != nil {
		log.Println("Error getting srver", config.Discord.ServerID, "with error:", err.Error())
		return
	}
	//var err error
	session.StateEnabled = true

	session.OnMessageCreate = func(s *discordgo.Session, m *discordgo.Message) {
		log.Println(m.ChannelID, config.Discord.ChannelID)
		if m.ChannelID != config.Discord.ChannelID {
			return
		}

		ign := ""
		member, err := session.State.Member(config.Discord.ServerID, m.Author.ID)
		if err != nil {
			log.Println("Error getting member:", err.Error())
			return
		}

		roles, err := session.GuildRoles(config.Discord.ServerID)
		if err != nil {
			log.Println("Error getting roles:", err.Error())
			return
		}
		for _, role := range member.Roles {
			for _, gRole := range roles {
				if strings.TrimSpace(gRole.ID) == strings.TrimSpace(role) {
					if strings.Contains(gRole.Name, "IGN:") {
						splitStr := strings.Split(gRole.Name, "IGN:")
						if len(splitStr) > 1 {
							ign = strings.TrimSpace(splitStr[1])
						}
					}
				}
			}
		}
		if ign == "" {
			return
		}
		log.Println(ign, m.Content)

	}

	select {}
}
<commit_msg>removed unused log<commit_after>package listener

import (
	"github.com/bwmarrin/discordgo"
	"github.com/xackery/discordeq/discord"
	"github.com/xackery/eqemuconfig"
	"log"
	"strings"
	//"time"
)

func ListenToDiscord(config *eqemuconfig.Config, disco *discord.Discord) {

	var session *discordgo.Session
	var guild *discordgo.Guild
	var err error

	session = disco.GetSession()
	guild, err = session.Guild(config.Discord.ServerID)
	log.Println(guild.Name)
	log.Println(guild.Members)
	if err != nil {
		log.Println("Error getting srver", config.Discord.ServerID, "with error:", err.Error())
		return
	}
	//var err error
	session.StateEnabled = true

	session.OnMessageCreate = func(s *discordgo.Session, m *discordgo.Message) {
		if m.ChannelID != config.Discord.ChannelID {
			return
		}

		ign := ""
		member, err := session.State.Member(config.Discord.ServerID, m.Author.ID)
		if err != nil {
			log.Println("Error getting member:", err.Error())
			return
		}

		roles, err := session.GuildRoles(config.Discord.ServerID)
		if err != nil {
			log.Println("Error getting roles:", err.Error())
			return
		}
		for _, role := range member.Roles {
			for _, gRole := range roles {
				if strings.TrimSpace(gRole.ID) == strings.TrimSpace(role) {
					if strings.Contains(gRole.Name, "IGN:") {
						splitStr := strings.Split(gRole.Name, "IGN:")
						if len(splitStr) > 1 {
							ign = strings.TrimSpace(splitStr[1])
						}
					}
				}
			}
		}
		if ign == "" {
			return
		}
		log.Println(ign, m.Content)

	}

	select {}
}
<|endoftext|>


<commit_before>package lite

import (
	"encoding/hex"
	"sort"

	liteErr "github.com/tendermint/tendermint/lite/errors"
)

type memStoreProvider struct {
	// byHeight is always sorted by Height... need to support range search (nil, h]
	// btree would be more efficient for larger sets
	byHeight fullCommits
	byHash   map[string]FullCommit
}

// fullCommits just exists to allow easy sorting
type fullCommits []FullCommit

func (s fullCommits) Len() int      { return len(s) }
func (s fullCommits) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s fullCommits) Less(i, j int) bool {
	return s[i].Height() < s[j].Height()
}

// NewMemStoreProvider returns a new in-memory provider.
func NewMemStoreProvider() Provider {
	return &memStoreProvider{
		byHeight: fullCommits{},
		byHash:   map[string]FullCommit{},
	}
}

func (m *memStoreProvider) encodeHash(hash []byte) string {
	return hex.EncodeToString(hash)
}

// StoreCommit stores a FullCommit after verifying it.
func (m *memStoreProvider) StoreCommit(fc FullCommit) error {
	// make sure the fc is self-consistent before saving
	err := fc.ValidateBasic(fc.Commit.Header.ChainID)
	if err != nil {
		return err
	}

	// store the valid fc
	key := m.encodeHash(fc.ValidatorsHash())
	m.byHash[key] = fc
	m.byHeight = append(m.byHeight, fc)
	sort.Sort(m.byHeight)
	return nil
}

// GetByHeight returns the FullCommit for height h or an error if the commit is not found.
func (m *memStoreProvider) GetByHeight(h int64) (FullCommit, error) {
	// search from highest to lowest
	for i := len(m.byHeight) - 1; i >= 0; i-- {
		fc := m.byHeight[i]
		if fc.Height() <= h {
			return fc, nil
		}
	}
	return FullCommit{}, liteErr.ErrCommitNotFound()
}

// GetByHash returns the FullCommit for the hash or an error if the commit is not found.
func (m *memStoreProvider) GetByHash(hash []byte) (FullCommit, error) {
	var err error
	fc, ok := m.byHash[m.encodeHash(hash)]
	if !ok {
		err = liteErr.ErrCommitNotFound()
	}
	return fc, err
}

// LatestCommit returns the latest FullCommit or an error if no commits exist.
func (m *memStoreProvider) LatestCommit() (FullCommit, error) {
	l := len(m.byHeight)
	if l == 0 {
		return FullCommit{}, liteErr.ErrCommitNotFound()
	}
	return m.byHeight[l-1], nil
}
<commit_msg>add mutex to memStoreProvider<commit_after>package lite

import (
	"encoding/hex"
	"sort"
	"sync"

	liteErr "github.com/tendermint/tendermint/lite/errors"
)

type memStoreProvider struct {
	mtx sync.RWMutex
	// byHeight is always sorted by Height... need to support range search (nil, h]
	// btree would be more efficient for larger sets
	byHeight fullCommits
	byHash   map[string]FullCommit
}

// fullCommits just exists to allow easy sorting
type fullCommits []FullCommit

func (s fullCommits) Len() int      { return len(s) }
func (s fullCommits) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s fullCommits) Less(i, j int) bool {
	return s[i].Height() < s[j].Height()
}

// NewMemStoreProvider returns a new in-memory provider.
func NewMemStoreProvider() Provider {
	return &memStoreProvider{
		byHeight: fullCommits{},
		byHash:   map[string]FullCommit{},
	}
}

func (m *memStoreProvider) encodeHash(hash []byte) string {
	return hex.EncodeToString(hash)
}

// StoreCommit stores a FullCommit after verifying it.
func (m *memStoreProvider) StoreCommit(fc FullCommit) error {
	// make sure the fc is self-consistent before saving
	err := fc.ValidateBasic(fc.Commit.Header.ChainID)
	if err != nil {
		return err
	}

	// store the valid fc
	key := m.encodeHash(fc.ValidatorsHash())

	m.mtx.Lock()
	defer m.mtx.Unlock()
	m.byHash[key] = fc
	m.byHeight = append(m.byHeight, fc)
	sort.Sort(m.byHeight)
	return nil
}

// GetByHeight returns the FullCommit for height h or an error if the commit is not found.
func (m *memStoreProvider) GetByHeight(h int64) (FullCommit, error) {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	// search from highest to lowest
	for i := len(m.byHeight) - 1; i >= 0; i-- {
		fc := m.byHeight[i]
		if fc.Height() <= h {
			return fc, nil
		}
	}
	return FullCommit{}, liteErr.ErrCommitNotFound()
}

// GetByHash returns the FullCommit for the hash or an error if the commit is not found.
func (m *memStoreProvider) GetByHash(hash []byte) (FullCommit, error) {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	fc, ok := m.byHash[m.encodeHash(hash)]
	if !ok {
		return fc, liteErr.ErrCommitNotFound()
	}
	return fc, nil
}

// LatestCommit returns the latest FullCommit or an error if no commits exist.
func (m *memStoreProvider) LatestCommit() (FullCommit, error) {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	l := len(m.byHeight)
	if l == 0 {
		return FullCommit{}, liteErr.ErrCommitNotFound()
	}
	return m.byHeight[l-1], nil
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	"compress/flate"
	"compress/zlib"
	"encoding/base64"
	"encoding/hex"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/encoding/unicode"
	"golang.org/x/text/transform"
	"html"
	"io"
	"io/ioutil"
	"net/url"
	"strings"
)

func Base64Enc(a []byte) string {
	return base64.StdEncoding.EncodeToString(a)
}
func Base64Dec(a string) ([]byte, error) {
	b, err := base64.StdEncoding.DecodeString(a)
	return b, err
}

func HexEnc(a []byte) string {
	return hex.EncodeToString(a)
}
func HexDec(a string) ([]byte, error) {
	b, err := hex.DecodeString(a)
	return b, err
}
func URLEnc(v string) string {
	return url.QueryEscape(v)
}
func URLDec(v string) (string, error) {
	return url.QueryUnescape(v)
}

func Base64ZlibEnc(a []byte) string {
	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(a)
	w.Close()
	return base64.StdEncoding.EncodeToString(b.Bytes())
}
func Base64ZlibDec(a string) ([]byte, error) {
	bv, err := base64.StdEncoding.DecodeString(a)
	if err != nil {
		return []byte{}, err
	}
	r, err := zlib.NewReader(bytes.NewReader(bv))
	if err != nil {
		return []byte{}, err
	}
	var ba bytes.Buffer
	ba.ReadFrom(r)
	r.Close()
	return ba.Bytes(), nil

}
func Base64FlateDec(a string) ([]byte, error) {
	bv, err := base64.StdEncoding.DecodeString(a)
	if err != nil {
		return []byte{}, err
	}
	r := flate.NewReader(bytes.NewReader(bv))
	var ba bytes.Buffer
	ba.ReadFrom(r)
	r.Close()
	return ba.Bytes(), nil
}

func HTMLDec(v string) (string, error) {
	return html.UnescapeString(v), nil
}
func HTMLEnc(v string) string {
	return html.EscapeString(v)
}

func Base64TwoZlibEnc(a []byte) string {
	var b, b2 bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(a)
	w.Close()

	w = zlib.NewWriter(&b2)
	w.Write(b.Bytes())
	w.Close()
	return base64.StdEncoding.EncodeToString(b2.Bytes())
}
func Base64TwoZlibDec(v string) ([]byte, error) {
	bv, err := base64.StdEncoding.DecodeString(v)
	if err != nil {
		return []byte{}, err
	}
	r, err := zlib.NewReader(bytes.NewReader(bv))
	if err != nil {
		return []byte{}, err
	}
	var ba bytes.Buffer
	ba.ReadFrom(r)
	r.Close()
	r, err = zlib.NewReader(bytes.NewReader(ba.Bytes()))
	if err != nil {
		return []byte{}, err
	}
	ba.Reset()
	ba.ReadFrom(r)
	r.Close()
	return ba.Bytes(), nil
}

func UTF16EncStr(v string) string {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM).NewEncoder()))
	if err != nil {
		return ""
	}
	return string(b)
}
func UTF16DecStr(v string) (string, error) {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM).NewDecoder()))
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func GB2312EncStr(v string) string {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), simplifiedchinese.HZGB2312.NewEncoder()))
	if err != nil {
		return ""
	}
	return string(b)
}
func GB2312DecStr(v string) (string, error) {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), simplifiedchinese.HZGB2312.NewDecoder()))
	if err != nil {
		return "", err
	}
	return string(b), nil
}
func GB18030EncStr(v string) string {
	b, err := ToGB18030Str(v)
	if err != nil {
		return ""
	}
	return string(b)
}
func GB18030DecStr(v string) (string, error) {
	tr := GB18030Dec(strings.NewReader(v))
	b, err := ioutil.ReadAll(tr)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func GBKEncStr(v string) string {
	b, err := ToGBKStr(v)
	if err != nil {
		return ""
	}
	return string(b)
}
func GBKDecStr(v string) (string, error) {
	tr := GbkDec(strings.NewReader(v))
	b, err := ioutil.ReadAll(tr)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func GbkEnc(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GBK.NewEncoder())
}
func GbkDec(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GBK.NewDecoder())
}
func GB18030Dec(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GB18030.NewDecoder())
}

func ToGBKStr(s string) ([]byte, error) {
	tr := GbkEnc(strings.NewReader(s))
	return ioutil.ReadAll(tr)
}
func GB18030Enc(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GB18030.NewEncoder())
}
func ToGB18030Str(s string) ([]byte, error) {
	tr := GB18030Enc(strings.NewReader(s))
	return ioutil.ReadAll(tr)
}
<commit_msg>调整 Base64Dec直接返回<commit_after>package utils

import (
	"bytes"
	"compress/flate"
	"compress/zlib"
	"encoding/base64"
	"encoding/hex"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/encoding/unicode"
	"golang.org/x/text/transform"
	"html"
	"io"
	"io/ioutil"
	"net/url"
	"strings"
)

func Base64Enc(a []byte) string {
	return base64.StdEncoding.EncodeToString(a)
}
func Base64Dec(a string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(a)
}

func HexEnc(a []byte) string {
	return hex.EncodeToString(a)
}
func HexDec(a string) ([]byte, error) {
	b, err := hex.DecodeString(a)
	return b, err
}
func URLEnc(v string) string {
	return url.QueryEscape(v)
}
func URLDec(v string) (string, error) {
	return url.QueryUnescape(v)
}

func Base64ZlibEnc(a []byte) string {
	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(a)
	w.Close()
	return base64.StdEncoding.EncodeToString(b.Bytes())
}
func Base64ZlibDec(a string) ([]byte, error) {
	bv, err := base64.StdEncoding.DecodeString(a)
	if err != nil {
		return []byte{}, err
	}
	r, err := zlib.NewReader(bytes.NewReader(bv))
	if err != nil {
		return []byte{}, err
	}
	var ba bytes.Buffer
	ba.ReadFrom(r)
	r.Close()
	return ba.Bytes(), nil

}
func Base64FlateDec(a string) ([]byte, error) {
	bv, err := base64.StdEncoding.DecodeString(a)
	if err != nil {
		return []byte{}, err
	}
	r := flate.NewReader(bytes.NewReader(bv))
	var ba bytes.Buffer
	ba.ReadFrom(r)
	r.Close()
	return ba.Bytes(), nil
}

func HTMLDec(v string) (string, error) {
	return html.UnescapeString(v), nil
}
func HTMLEnc(v string) string {
	return html.EscapeString(v)
}

func Base64TwoZlibEnc(a []byte) string {
	var b, b2 bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(a)
	w.Close()

	w = zlib.NewWriter(&b2)
	w.Write(b.Bytes())
	w.Close()
	return base64.StdEncoding.EncodeToString(b2.Bytes())
}
func Base64TwoZlibDec(v string) ([]byte, error) {
	bv, err := base64.StdEncoding.DecodeString(v)
	if err != nil {
		return []byte{}, err
	}
	r, err := zlib.NewReader(bytes.NewReader(bv))
	if err != nil {
		return []byte{}, err
	}
	var ba bytes.Buffer
	ba.ReadFrom(r)
	r.Close()
	r, err = zlib.NewReader(bytes.NewReader(ba.Bytes()))
	if err != nil {
		return []byte{}, err
	}
	ba.Reset()
	ba.ReadFrom(r)
	r.Close()
	return ba.Bytes(), nil
}

func UTF16EncStr(v string) string {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM).NewEncoder()))
	if err != nil {
		return ""
	}
	return string(b)
}
func UTF16DecStr(v string) (string, error) {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM).NewDecoder()))
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func GB2312EncStr(v string) string {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), simplifiedchinese.HZGB2312.NewEncoder()))
	if err != nil {
		return ""
	}
	return string(b)
}
func GB2312DecStr(v string) (string, error) {
	b, err := ioutil.ReadAll(transform.NewReader(strings.NewReader(v), simplifiedchinese.HZGB2312.NewDecoder()))
	if err != nil {
		return "", err
	}
	return string(b), nil
}
func GB18030EncStr(v string) string {
	b, err := ToGB18030Str(v)
	if err != nil {
		return ""
	}
	return string(b)
}
func GB18030DecStr(v string) (string, error) {
	tr := GB18030Dec(strings.NewReader(v))
	b, err := ioutil.ReadAll(tr)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func GBKEncStr(v string) string {
	b, err := ToGBKStr(v)
	if err != nil {
		return ""
	}
	return string(b)
}
func GBKDecStr(v string) (string, error) {
	tr := GbkDec(strings.NewReader(v))
	b, err := ioutil.ReadAll(tr)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func GbkEnc(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GBK.NewEncoder())
}
func GbkDec(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GBK.NewDecoder())
}
func GB18030Dec(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GB18030.NewDecoder())
}

func ToGBKStr(s string) ([]byte, error) {
	tr := GbkEnc(strings.NewReader(s))
	return ioutil.ReadAll(tr)
}
func GB18030Enc(r io.Reader) *transform.Reader {
	return transform.NewReader(r, simplifiedchinese.GB18030.NewEncoder())
}
func ToGB18030Str(s string) ([]byte, error) {
	tr := GB18030Enc(strings.NewReader(s))
	return ioutil.ReadAll(tr)
}
<|endoftext|>


<commit_before>package es

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

const (
	OK  = '2'
	AND = "AND"
	OR  = "OR"
)

type Term map[string]interface{}

type Terms map[string][]interface{}

type Filter struct {
	And   []*Filter         `json:"and,omitempty`
	Term  *Term             `json:"term,omitempty"`
	Terms *Terms            `json:"term,omitempty"`
	Range map[string]*Range `json:"range,omitempty"`
}

type Range struct {
	From interface{}
	To   interface{}
}

type Filtered struct {
	Filter *Filter
}

type QueryString struct {
	Query           string `json:"query,omitempty"`
	DefaultOperator string `json:"default_operator,omitempty"`
}

type Query struct {
	Filtered    *Filtered    `json:"filtered,omitempty"`
	QueryString *QueryString `json:"query_string,omitempty"`
}

var query = Query{
	Filtered: &Filtered{
		Filter: &Filter{
			And: []*Filter{
				{
					Term: &Term{
						"Device": "Anrdoi",
					},
				},
				{
					Terms: &Terms{
						"Action": []interface{}{
							"api/v1/my/photos#create",
							"api/v1/photos#create",
						},
					},
					Range: map[string]*Range{
						"Time": {
							From: "",
						},
					},
				},
			},
		},
	},
}

type BulkIndexJob struct {
	Key    string
	Record interface{}
}

type Index struct {
	Host          string
	Port          int
	Index         string
	Type          string
	bulkIndexJobs []*BulkIndexJob
	BatchSize     int
	Debug         bool
}

func (index *Index) EnqueueBulkIndex(key string, record interface{}) (bool, error) {
	if index.BatchSize == 0 {
		index.BatchSize = 100
	}
	if cap(index.bulkIndexJobs) == 0 {
		index.ResetQueue()
	}
	index.bulkIndexJobs = append(index.bulkIndexJobs, &BulkIndexJob{
		Key: key, Record: record,
	})
	if len(index.bulkIndexJobs) >= index.BatchSize {
		return true, index.RunBatchIndex()
	}
	return false, nil
}

func (index *Index) DeleteIndex() error {
	req, e := http.NewRequest("DELETE", index.TypeUrl(), nil)
	if e != nil {
		return e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		return fmt.Errorf("Error delting index at %s: %s", index.TypeUrl(), rsp.Status)
	}
	return nil
}

func (index *Index) Refresh() error {
	rsp, e := index.request("POST", index.IndexUrl()+"/_refresh", nil)
	if e != nil {
		return e
	}
	if rsp.Status[0] != '2' {
		return fmt.Errorf("Error refreshing index: %s", rsp.Status)
	}
	return nil
}

func (index *Index) RunBatchIndex() error {
	started := time.Now()
	buf := &bytes.Buffer{}
	enc := json.NewEncoder(buf)
	for _, r := range index.bulkIndexJobs {
		enc.Encode(map[string]map[string]string{
			"index": map[string]string{
				"_index": index.Index,
				"_type":  index.Type,
				"_id":    r.Key,
			},
		})
		enc.Encode(r.Record)
	}
	rsp, e := http.Post(index.BaseUrl()+"/_bulk", "application/json", buf)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	b, _ := ioutil.ReadAll(rsp.Body)
	if rsp.Status[0] != OK {
		return fmt.Errorf("Error sending bulk request: %s %s", rsp.Status, string(b))
	}
	perSecond := float64(len(index.bulkIndexJobs)) / time.Now().Sub(started).Seconds()
	if index.Debug {
		fmt.Printf("indexed %d, %.1f/second\n", len(index.bulkIndexJobs), perSecond)
	}
	index.ResetQueue()
	return nil
}

func (index *Index) ResetQueue() {
	index.bulkIndexJobs = make([]*BulkIndexJob, 0, index.BatchSize)
}

type IndexStatus struct {
	Index  string `json:"_index"`
	Type   string `json:"_type"`
	Id     string `json:"_id"`
	Exists bool   `json:"exists"`
}

func (index *Index) Status() (status *IndexStatus, e error) {
	rsp, e := http.Get(index.BaseUrl() + "/_status")
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	status = &IndexStatus{}
	e = json.Unmarshal(b, status)
	return status, e
}

func (index *Index) Mapping() (i interface{}, e error) {
	u := index.IndexUrl() + "/_mapping"
	log.Printf("checking for url %s", u)
	rsp, e := index.request("GET", u, i)
	if rsp != nil && rsp.StatusCode == 404 {
		return nil, nil
	} else if e != nil {
		return nil, e
	}
	e = json.Unmarshal(rsp.Body, &i)
	if e != nil {
		return nil, e
	}
	return i, nil
}

func (index *Index) PutMapping(mapping interface{}) (rsp *HttpResponse, e error) {
	return index.request("PUT", index.IndexUrl()+"/", mapping)
}

func (index *Index) BaseUrl() string {
	if index.Port == 0 {
		index.Port = 9200
	}
	return fmt.Sprintf("http://%s:%d", index.Host, index.Port)
}

func (index *Index) IndexUrl() string {
	if index.Index != "" {
		return index.BaseUrl() + "/" + index.Index
	}
	return ""
}

func (index *Index) TypeUrl() string {
	if base := index.IndexUrl(); base != "" && index.Type != "" {
		return base + "/" + index.Type
	}
	return ""
	return ""
}

func (index *Index) Search(req *Request) (rsp *Response, e error) {
	writer := &bytes.Buffer{}
	js := json.NewEncoder(writer)
	e = js.Encode(req)
	if e != nil {
		return nil, e
	}
	u := index.TypeUrl()
	if !strings.HasSuffix(u, "/") {
		u += "/"
	}
	u += "/_search"
	httpRequest, e := http.NewRequest("POST", u, writer)
	if e != nil {
		return nil, e
	}
	httpResponse, e := http.DefaultClient.Do(httpRequest)
	if e != nil {
		return nil, e
	}
	defer httpResponse.Body.Close()
	dec := json.NewDecoder(httpResponse.Body)
	rsp = &Response{}
	e = dec.Decode(rsp)
	if e != nil {
		return nil, e
	}
	return rsp, nil
}

func (index *Index) Post(u string, i interface{}) (*HttpResponse, error) {
	return index.request("POST", u, i)
}

func (index *Index) PutObject(id string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", index.TypeUrl()+"/"+id, i)
}

func (index *Index) Put(u string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", u, i)
}

type HttpResponse struct {
	*http.Response
	Body []byte
}

func (index *Index) request(method string, u string, i interface{}) (httpResponse *HttpResponse, e error) {
	var req *http.Request
	if i != nil {
		buf := &bytes.Buffer{}
		encoder := json.NewEncoder(buf)
		if e := encoder.Encode(i); e != nil {
			return nil, e
		}
		req, e = http.NewRequest(method, u, buf)
	} else {
		req, e = http.NewRequest(method, u, nil)
	}
	if e != nil {
		return nil, e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	httpResponse = &HttpResponse{
		Response: rsp,
		Body:     b,
	}
	if e != nil {
		return httpResponse, e
	}
	if rsp.Status[0] != OK {
		return httpResponse, fmt.Errorf("error indexing: %s %s", rsp.Status, string(b))
	}
	return httpResponse, nil
}
<commit_msg>add method DeleteByQuery<commit_after>package es

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

const (
	OK  = '2'
	AND = "AND"
	OR  = "OR"
)

type Term map[string]interface{}

type Terms map[string][]interface{}

type Filter struct {
	And   []*Filter         `json:"and,omitempty`
	Term  *Term             `json:"term,omitempty"`
	Terms *Terms            `json:"term,omitempty"`
	Range map[string]*Range `json:"range,omitempty"`
}

type Range struct {
	From interface{}
	To   interface{}
}

type Filtered struct {
	Filter *Filter
}

type QueryString struct {
	Query           string `json:"query,omitempty"`
	DefaultOperator string `json:"default_operator,omitempty"`
}

type Query struct {
	Filtered    *Filtered    `json:"filtered,omitempty"`
	QueryString *QueryString `json:"query_string,omitempty"`
}

var query = Query{
	Filtered: &Filtered{
		Filter: &Filter{
			And: []*Filter{
				{
					Term: &Term{
						"Device": "Anrdoi",
					},
				},
				{
					Terms: &Terms{
						"Action": []interface{}{
							"api/v1/my/photos#create",
							"api/v1/photos#create",
						},
					},
					Range: map[string]*Range{
						"Time": {
							From: "",
						},
					},
				},
			},
		},
	},
}

type BulkIndexJob struct {
	Key    string
	Record interface{}
}

type Index struct {
	Host          string
	Port          int
	Index         string
	Type          string
	bulkIndexJobs []*BulkIndexJob
	BatchSize     int
	Debug         bool
}

func (index *Index) EnqueueBulkIndex(key string, record interface{}) (bool, error) {
	if index.BatchSize == 0 {
		index.BatchSize = 100
	}
	if cap(index.bulkIndexJobs) == 0 {
		index.ResetQueue()
	}
	index.bulkIndexJobs = append(index.bulkIndexJobs, &BulkIndexJob{
		Key: key, Record: record,
	})
	if len(index.bulkIndexJobs) >= index.BatchSize {
		return true, index.RunBatchIndex()
	}
	return false, nil
}

func (index *Index) DeleteIndex() error {
	req, e := http.NewRequest("DELETE", index.TypeUrl(), nil)
	if e != nil {
		return e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		return fmt.Errorf("Error delting index at %s: %s", index.TypeUrl(), rsp.Status)
	}
	return nil
}

func (index *Index) Refresh() error {
	rsp, e := index.request("POST", index.IndexUrl()+"/_refresh", nil)
	if e != nil {
		return e
	}
	if rsp.Status[0] != '2' {
		return fmt.Errorf("Error refreshing index: %s", rsp.Status)
	}
	return nil
}

func (index *Index) RunBatchIndex() error {
	started := time.Now()
	buf := &bytes.Buffer{}
	enc := json.NewEncoder(buf)
	for _, r := range index.bulkIndexJobs {
		enc.Encode(map[string]map[string]string{
			"index": map[string]string{
				"_index": index.Index,
				"_type":  index.Type,
				"_id":    r.Key,
			},
		})
		enc.Encode(r.Record)
	}
	rsp, e := http.Post(index.BaseUrl()+"/_bulk", "application/json", buf)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	b, _ := ioutil.ReadAll(rsp.Body)
	if rsp.Status[0] != OK {
		return fmt.Errorf("Error sending bulk request: %s %s", rsp.Status, string(b))
	}
	perSecond := float64(len(index.bulkIndexJobs)) / time.Now().Sub(started).Seconds()
	if index.Debug {
		fmt.Printf("indexed %d, %.1f/second\n", len(index.bulkIndexJobs), perSecond)
	}
	index.ResetQueue()
	return nil
}

func (index *Index) ResetQueue() {
	index.bulkIndexJobs = make([]*BulkIndexJob, 0, index.BatchSize)
}

type IndexStatus struct {
	Index  string `json:"_index"`
	Type   string `json:"_type"`
	Id     string `json:"_id"`
	Exists bool   `json:"exists"`
}

func (index *Index) Status() (status *IndexStatus, e error) {
	rsp, e := http.Get(index.BaseUrl() + "/_status")
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	status = &IndexStatus{}
	e = json.Unmarshal(b, status)
	return status, e
}

func (index *Index) Mapping() (i interface{}, e error) {
	u := index.IndexUrl() + "/_mapping"
	log.Printf("checking for url %s", u)
	rsp, e := index.request("GET", u, i)
	if rsp != nil && rsp.StatusCode == 404 {
		return nil, nil
	} else if e != nil {
		return nil, e
	}
	e = json.Unmarshal(rsp.Body, &i)
	if e != nil {
		return nil, e
	}
	return i, nil
}

func (index *Index) PutMapping(mapping interface{}) (rsp *HttpResponse, e error) {
	return index.request("PUT", index.IndexUrl()+"/", mapping)
}

func (index *Index) BaseUrl() string {
	if index.Port == 0 {
		index.Port = 9200
	}
	return fmt.Sprintf("http://%s:%d", index.Host, index.Port)
}

func (index *Index) IndexUrl() string {
	if index.Index != "" {
		return index.BaseUrl() + "/" + index.Index
	}
	return ""
}

func (index *Index) TypeUrl() string {
	if base := index.IndexUrl(); base != "" && index.Type != "" {
		return base + "/" + index.Type
	}
	return ""
}

func (index *Index) DeleteByQuery(query string) error {
	q := &url.Values{}
	q.Add("q", query)
	rsp, e := index.request("DELETE", index.TypeUrl()+"/_query?"+q.Encode(), nil)
	if e != nil {
		return e
	}
	if rsp.Status[0] != '2' {
		return fmt.Errorf("error deleting with query: %s", rsp.Status)
	}
	return nil
}

func (index *Index) Search(req *Request) (rsp *Response, e error) {
	writer := &bytes.Buffer{}
	js := json.NewEncoder(writer)
	e = js.Encode(req)
	if e != nil {
		return nil, e
	}
	u := index.TypeUrl()
	if !strings.HasSuffix(u, "/") {
		u += "/"
	}
	u += "/_search"
	httpRequest, e := http.NewRequest("POST", u, writer)
	if e != nil {
		return nil, e
	}
	httpResponse, e := http.DefaultClient.Do(httpRequest)
	if e != nil {
		return nil, e
	}
	defer httpResponse.Body.Close()
	dec := json.NewDecoder(httpResponse.Body)
	rsp = &Response{}
	e = dec.Decode(rsp)
	if e != nil {
		return nil, e
	}
	return rsp, nil
}

func (index *Index) Post(u string, i interface{}) (*HttpResponse, error) {
	return index.request("POST", u, i)
}

func (index *Index) PutObject(id string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", index.TypeUrl()+"/"+id, i)
}

func (index *Index) Put(u string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", u, i)
}

type HttpResponse struct {
	*http.Response
	Body []byte
}

func (index *Index) request(method string, u string, i interface{}) (httpResponse *HttpResponse, e error) {
	var req *http.Request
	if i != nil {
		buf := &bytes.Buffer{}
		encoder := json.NewEncoder(buf)
		if e := encoder.Encode(i); e != nil {
			return nil, e
		}
		req, e = http.NewRequest(method, u, buf)
	} else {
		req, e = http.NewRequest(method, u, nil)
	}
	if e != nil {
		return nil, e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	httpResponse = &HttpResponse{
		Response: rsp,
		Body:     b,
	}
	if e != nil {
		return httpResponse, e
	}
	if rsp.Status[0] != OK {
		return httpResponse, fmt.Errorf("error indexing: %s %s", rsp.Status, string(b))
	}
	return httpResponse, nil
}
<|endoftext|>


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

package repo

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/context"
	"net/http"
	"strconv"
)

// AddTimeManual tracks time manually
func AddTimeManual(c *context.Context) {
	hours, err := strconv.ParseInt(c.Req.PostForm.Get("hours"), 10, 64)
	if err != nil {
		if c.Req.PostForm.Get("hours") != "" {
			c.Handle(http.StatusInternalServerError, "hours is not numeric", err)
			return
		}
	}
	minutes, err := strconv.ParseInt(c.Req.PostForm.Get("minutes"), 10, 64)
	if err != nil {
		if c.Req.PostForm.Get("minutes") != "" {
			c.Handle(http.StatusInternalServerError, "minutes is not numeric", err)
			return
		}
	}
	seconds, err := strconv.ParseInt(c.Req.PostForm.Get("seconds"), 10, 64)
	if err != nil {
		if c.Req.PostForm.Get("seconds") != "" {
			c.Handle(http.StatusInternalServerError, "seconds is not numeric", err)
			return
		}
	}

	totalInSeconds := seconds + minutes*60 + hours*60*60

	if totalInSeconds <= 0 {
		c.Handle(http.StatusInternalServerError, "sum of seconds <= 0", nil)
		return
	}

	issueIndex := c.ParamsInt64("index")
	issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, issueIndex)
	if err != nil {
		c.Handle(http.StatusInternalServerError, "GetIssueByIndex", err)
		return
	}

	if err := models.AddTime(c.User.ID, issue.ID, totalInSeconds); err != nil {
		c.Handle(http.StatusInternalServerError, "AddTime", err)
		return
	}

	url := issue.HTMLURL()
	c.Redirect(url, http.StatusSeeOther)
}
<commit_msg>Adding @sapks 's changes, refactoring<commit_after>// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repo

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/context"
	"net/http"
	"time"
	"fmt"
)

// AddTimeManual tracks time manually
func AddTimeManual(c *context.Context) {

	h, err := parseTimeTrackingWithDuration(c.Req.PostForm.Get("hours"), "h")
	if err != nil {
		fmt.Println("hours is not numeric", err)
		c.Handle(http.StatusBadRequest, "hours is not numeric", err)
		return
	}

	m, err := parseTimeTrackingWithDuration(c.Req.PostForm.Get("minutes"), "m")
	if err != nil {
		fmt.Println("minutes is not numeric", err)
		c.Handle(http.StatusBadRequest, "minutes is not numeric", err)
		return
	}

	s, err := parseTimeTrackingWithDuration(c.Req.PostForm.Get("seconds"), "s")
	if err != nil {
		fmt.Println("seconds is not numeric", err)
		c.Handle(http.StatusBadRequest, "seconds is not numeric", err)
		return
	}

	totalInSeconds := h.Seconds() + m.Seconds() + s.Seconds()

	if totalInSeconds <= 0 {
		c.Handle(http.StatusBadRequest, "sum of seconds <= 0", nil)
		return
	}

	issueIndex := c.ParamsInt64("index")
	issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, issueIndex)
	if err != nil {
		c.Handle(http.StatusInternalServerError, "GetIssueByIndex", err)
		return
	}

	if err := models.AddTime(c.User.ID, issue.ID, int64(totalInSeconds)); err != nil {
		c.Handle(http.StatusInternalServerError, "AddTime", err)
		return
	}

	url := issue.HTMLURL()
	c.Redirect(url, http.StatusSeeOther)
}

func parseTimeTrackingWithDuration(value, space string) (time.Duration, error) {
	if value == "" {
		return 0, nil
	}
	return time.ParseDuration(value + space)
}

<|endoftext|>


<commit_before>package main

import "bufio"

type RefVarPrinter interface {
  Header(out *bufio.Writer) error
  Print(vartype int, ref_start, ref_len int, refseq []byte, altseq [][]byte, out *bufio.Writer) error
  Pasta(line string, ref_stream *bufio.Reader, out *bufio.Writer) error
  PastaBegin(out *bufio.Writer) error
  PastaEnd(out *bufio.Writer) error
  Chrom(chr string)
  Pos(pos int)
  Init()
}
<commit_msg>PrintEnd function<commit_after>package main

import "bufio"

type RefVarPrinter interface {
  Header(out *bufio.Writer) error
  Print(vartype int, ref_start, ref_len int, refseq []byte, altseq [][]byte, out *bufio.Writer) error
  PrintEnd(out *bufio.Writer) error
  Pasta(line string, ref_stream *bufio.Reader, out *bufio.Writer) error
  PastaBegin(out *bufio.Writer) error
  PastaEnd(out *bufio.Writer) error
  Chrom(chr string)
  Pos(pos int)
  Init()
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"encoding/json"
	"io"
	"net/http"

	"time"

	"github.com/uber-go/zap"
)

// ServerHTTPResponse struct manages request
type ServerHTTPResponse struct {
	responseWriter http.ResponseWriter
	req            *ServerHTTPRequest
	gateway        *Gateway
	finishTime     time.Time
	finished       bool
	metrics        *EndpointMetrics

	StatusCode int
}

// NewServerHTTPResponse is helper function to alloc ServerHTTPResponse
func NewServerHTTPResponse(
	w http.ResponseWriter, req *ServerHTTPRequest,
) *ServerHTTPResponse {
	res := &ServerHTTPResponse{
		gateway:        req.gateway,
		req:            req,
		responseWriter: w,
		StatusCode:     200,
		metrics:        req.metrics,
	}

	return res
}

// finish will handle final logic, like metrics
func (res *ServerHTTPResponse) finish() {
	if !res.req.started {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Forgot to start incoming request",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}
	if res.finished {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Finished an incoming request twice",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}

	res.finished = true
	res.finishTime = time.Now()

	counter := res.metrics.statusCodes[res.StatusCode]
	if counter == nil {
		res.req.Logger.Error(
			"Could not emit statusCode metric",
			zap.Int("UnexpectedStatusCode", res.StatusCode),
		)
	} else {
		counter.Inc(1)
	}

	res.metrics.requestLatency.Record(
		res.finishTime.Sub(res.req.startTime),
	)
}

// SendError helper to send an error
func (res *ServerHTTPResponse) SendError(statusCode int, err error) {
	res.SendErrorString(statusCode, err.Error())
}

// SendErrorString helper to send an error string
func (res *ServerHTTPResponse) SendErrorString(
	statusCode int, err string,
) {
	res.req.Logger.Warn(
		"Sending error for endpoint request",
		zap.String("error", err),
		zap.String("path", res.req.URL.Path),
	)

	res.writeHeader(statusCode)
	res.writeString(err)

	res.finish()
}

// CopyJSON will copy json bytes from a Reader
func (res *ServerHTTPResponse) CopyJSON(statusCode int, src io.Reader) {
	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	_, err := io.Copy(res.responseWriter, src)
	if err != nil {
		res.req.Logger.Error("Could not copy bytes",
			zap.String("error", err.Error()),
		)
	}

	res.finish()
}

// WriteJSONBytes writes a byte[] slice that is valid json to Response
func (res *ServerHTTPResponse) WriteJSONBytes(
	statusCode int, bytes []byte,
) {
	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

// WriteJSON writes a json serializable struct to Response
func (res *ServerHTTPResponse) WriteJSON(
	statusCode int, body json.Marshaler,
) {
	if body == nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize nil pointer body")
		return
	}

	bytes, err := body.MarshalJSON()
	if err != nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize json response",
			zap.String("error", err.Error()),
		)
		return
	}

	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

func (res *ServerHTTPResponse) writeHeader(statusCode int) {
	res.StatusCode = statusCode
	res.responseWriter.WriteHeader(statusCode)
}

// WriteBytes writes raw bytes to output
func (res *ServerHTTPResponse) writeBytes(bytes []byte) {
	_, err := res.responseWriter.Write(bytes)
	if err != nil {
		res.req.Logger.Error("Could not write string to resp body",
			zap.String("error", err.Error()),
		)
	}
}

// WriteHeader writes the header to http respnse.
func (res *ServerHTTPResponse) WriteHeader(statusCode int) {
	res.writeHeader(statusCode)
}

// WriteString helper just writes a string to the response
func (res *ServerHTTPResponse) writeString(text string) {
	res.writeBytes([]byte(text))
}

// IsOKResponse checks if the status code is OK.
func (res *ServerHTTPResponse) IsOKResponse(
	statusCode int, okResponses []int,
) bool {
	for _, r := range okResponses {
		if statusCode == r {
			return true
		}
	}
	return false
}
<commit_msg>runtime/ServerResponse remove CopyJSON<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"encoding/json"
	"net/http"

	"time"

	"github.com/uber-go/zap"
)

// ServerHTTPResponse struct manages request
type ServerHTTPResponse struct {
	responseWriter http.ResponseWriter
	req            *ServerHTTPRequest
	gateway        *Gateway
	finishTime     time.Time
	finished       bool
	metrics        *EndpointMetrics

	StatusCode int
}

// NewServerHTTPResponse is helper function to alloc ServerHTTPResponse
func NewServerHTTPResponse(
	w http.ResponseWriter, req *ServerHTTPRequest,
) *ServerHTTPResponse {
	res := &ServerHTTPResponse{
		gateway:        req.gateway,
		req:            req,
		responseWriter: w,
		StatusCode:     200,
		metrics:        req.metrics,
	}

	return res
}

// finish will handle final logic, like metrics
func (res *ServerHTTPResponse) finish() {
	if !res.req.started {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Forgot to start incoming request",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}
	if res.finished {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Finished an incoming request twice",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}

	res.finished = true
	res.finishTime = time.Now()

	counter := res.metrics.statusCodes[res.StatusCode]
	if counter == nil {
		res.req.Logger.Error(
			"Could not emit statusCode metric",
			zap.Int("UnexpectedStatusCode", res.StatusCode),
		)
	} else {
		counter.Inc(1)
	}

	res.metrics.requestLatency.Record(
		res.finishTime.Sub(res.req.startTime),
	)
}

// SendError helper to send an error
func (res *ServerHTTPResponse) SendError(statusCode int, err error) {
	res.SendErrorString(statusCode, err.Error())
}

// SendErrorString helper to send an error string
func (res *ServerHTTPResponse) SendErrorString(
	statusCode int, err string,
) {
	res.req.Logger.Warn(
		"Sending error for endpoint request",
		zap.String("error", err),
		zap.String("path", res.req.URL.Path),
	)

	res.writeHeader(statusCode)
	res.writeString(err)

	res.finish()
}

// WriteJSONBytes writes a byte[] slice that is valid json to Response
func (res *ServerHTTPResponse) WriteJSONBytes(
	statusCode int, bytes []byte,
) {
	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

// WriteJSON writes a json serializable struct to Response
func (res *ServerHTTPResponse) WriteJSON(
	statusCode int, body json.Marshaler,
) {
	if body == nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize nil pointer body")
		return
	}

	bytes, err := body.MarshalJSON()
	if err != nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize json response",
			zap.String("error", err.Error()),
		)
		return
	}

	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

func (res *ServerHTTPResponse) writeHeader(statusCode int) {
	res.StatusCode = statusCode
	res.responseWriter.WriteHeader(statusCode)
}

// WriteBytes writes raw bytes to output
func (res *ServerHTTPResponse) writeBytes(bytes []byte) {
	_, err := res.responseWriter.Write(bytes)
	if err != nil {
		res.req.Logger.Error("Could not write string to resp body",
			zap.String("error", err.Error()),
		)
	}
}

// WriteHeader writes the header to http respnse.
func (res *ServerHTTPResponse) WriteHeader(statusCode int) {
	res.writeHeader(statusCode)
}

// WriteString helper just writes a string to the response
func (res *ServerHTTPResponse) writeString(text string) {
	res.writeBytes([]byte(text))
}

// IsOKResponse checks if the status code is OK.
func (res *ServerHTTPResponse) IsOKResponse(
	statusCode int, okResponses []int,
) bool {
	for _, r := range okResponses {
		if statusCode == r {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Package cli implements a generic interactive line editor.
package cli

import (
	"io"
	"os"
	"sync"
	"syscall"

	"src.elv.sh/pkg/cli/term"
	"src.elv.sh/pkg/cli/tk"
	"src.elv.sh/pkg/sys"
)

// App represents a CLI app.
type App interface {
	// MutateState mutates the state of the app.
	MutateState(f func(*State))
	// CopyState returns a copy of the a state.
	CopyState() State
	// CodeArea returns the codearea widget of the app.
	CodeArea() tk.CodeArea
	// ReadCode requests the App to read code from the terminal by running an
	// event loop. This function is not re-entrant.
	ReadCode() (string, error)
	// Redraw requests a redraw. It never blocks and can be called regardless of
	// whether the App is active or not.
	Redraw()
	// RedrawFull requests a full redraw. It never blocks and can be called
	// regardless of whether the App is active or not.
	RedrawFull()
	// CommitEOF causes the main loop to exit with EOF. If this method is called
	// when an event is being handled, the main loop will exit after the handler
	// returns.
	CommitEOF()
	// CommitCode causes the main loop to exit with the current code content. If
	// this method is called when an event is being handled, the main loop will
	// exit after the handler returns.
	CommitCode()
	// Notify adds a note and requests a redraw.
	Notify(note string)
}

type app struct {
	loop    *loop
	reqRead chan struct{}

	TTY               TTY
	MaxHeight         func() int
	RPromptPersistent func() bool
	BeforeReadline    []func()
	AfterReadline     []func(string)
	Highlighter       Highlighter
	Prompt            Prompt
	RPrompt           Prompt

	StateMutex sync.RWMutex
	State      State

	codeArea tk.CodeArea
}

// State represents mutable state of an App.
type State struct {
	// Notes that have been added since the last redraw.
	Notes []string
	// An addon widget. When non-nil, it is shown under the codearea widget and
	// terminal events are handled by it.
	//
	// The cursor is placed on the addon by default. If the addon widget
	// implements interface{ Focus() bool }, the Focus method is called to
	// determine that instead.
	Addon tk.Widget
}

type focuser interface {
	Focus() bool
}

// NewApp creates a new App from the given specification.
func NewApp(spec AppSpec) App {
	lp := newLoop()
	a := app{
		loop:              lp,
		TTY:               spec.TTY,
		MaxHeight:         spec.MaxHeight,
		RPromptPersistent: spec.RPromptPersistent,
		BeforeReadline:    spec.BeforeReadline,
		AfterReadline:     spec.AfterReadline,
		Highlighter:       spec.Highlighter,
		Prompt:            spec.Prompt,
		RPrompt:           spec.RPrompt,
		State:             spec.State,
	}
	if a.TTY == nil {
		a.TTY = NewTTY(os.Stdin, os.Stderr)
	}
	if a.MaxHeight == nil {
		a.MaxHeight = func() int { return -1 }
	}
	if a.RPromptPersistent == nil {
		a.RPromptPersistent = func() bool { return false }
	}
	if a.Highlighter == nil {
		a.Highlighter = dummyHighlighter{}
	}
	if a.Prompt == nil {
		a.Prompt = NewConstPrompt(nil)
	}
	if a.RPrompt == nil {
		a.RPrompt = NewConstPrompt(nil)
	}
	lp.HandleCb(a.handle)
	lp.RedrawCb(a.redraw)

	a.codeArea = tk.NewCodeArea(tk.CodeAreaSpec{
		OverlayHandler: spec.OverlayHandler,
		Highlighter:    a.Highlighter.Get,
		Prompt:         a.Prompt.Get,
		RPrompt:        a.RPrompt.Get,
		Abbreviations:  spec.Abbreviations,
		QuotePaste:     spec.QuotePaste,
		OnSubmit:       a.CommitCode,
		State:          spec.CodeAreaState,

		SmallWordAbbreviations: spec.SmallWordAbbreviations,
	})

	return &a
}

func (a *app) MutateState(f func(*State)) {
	a.StateMutex.Lock()
	defer a.StateMutex.Unlock()
	f(&a.State)
}

func (a *app) CopyState() State {
	a.StateMutex.RLock()
	defer a.StateMutex.RUnlock()
	return a.State
}

func (a *app) CodeArea() tk.CodeArea {
	return a.codeArea
}

func (a *app) resetAllStates() {
	a.MutateState(func(s *State) { *s = State{} })
	a.codeArea.MutateState(
		func(s *tk.CodeAreaState) { *s = tk.CodeAreaState{} })
}

func (a *app) handle(e event) {
	switch e := e.(type) {
	case os.Signal:
		switch e {
		case syscall.SIGHUP:
			a.loop.Return("", io.EOF)
		case syscall.SIGINT:
			a.resetAllStates()
			a.triggerPrompts(true)
		case sys.SIGWINCH:
			a.RedrawFull()
		}
	case term.Event:
		if listing := a.CopyState().Addon; listing != nil {
			listing.Handle(e)
		} else {
			a.codeArea.Handle(e)
		}
		if !a.loop.HasReturned() {
			a.triggerPrompts(false)
			a.reqRead <- struct{}{}
		}
	}
}

func (a *app) triggerPrompts(force bool) {
	a.Prompt.Trigger(force)
	a.RPrompt.Trigger(force)
}

func (a *app) redraw(flag redrawFlag) {
	// Get the dimensions available.
	height, width := a.TTY.Size()
	if maxHeight := a.MaxHeight(); maxHeight > 0 && maxHeight < height {
		height = maxHeight
	}

	var notes []string
	var addon tk.Renderer
	a.MutateState(func(s *State) {
		notes, addon = s.Notes, s.Addon
		s.Notes = nil
	})

	bufNotes := renderNotes(notes, width)
	isFinalRedraw := flag&finalRedraw != 0
	if isFinalRedraw {
		hideRPrompt := !a.RPromptPersistent()
		if hideRPrompt {
			a.codeArea.MutateState(func(s *tk.CodeAreaState) { s.HideRPrompt = true })
		}
		bufMain := renderApp(a.codeArea, nil /* addon */, width, height)
		if hideRPrompt {
			a.codeArea.MutateState(func(s *tk.CodeAreaState) { s.HideRPrompt = false })
		}
		// Insert a newline after the buffer and position the cursor there.
		bufMain.Extend(term.NewBuffer(width), true)

		a.TTY.UpdateBuffer(bufNotes, bufMain, flag&fullRedraw != 0)
		a.TTY.ResetBuffer()
	} else {
		bufMain := renderApp(a.codeArea, addon, width, height)
		a.TTY.UpdateBuffer(bufNotes, bufMain, flag&fullRedraw != 0)
	}
}

// Renders notes. This does not respect height so that overflow notes end up in
// the scrollback buffer.
func renderNotes(notes []string, width int) *term.Buffer {
	if len(notes) == 0 {
		return nil
	}
	bb := term.NewBufferBuilder(width)
	for i, note := range notes {
		if i > 0 {
			bb.Newline()
		}
		bb.Write(note)
	}
	return bb.Buffer()
}

// Renders the codearea, and uses the rest of the height for the listing.
func renderApp(codeArea, addon tk.Renderer, width, height int) *term.Buffer {
	buf := codeArea.Render(width, height)
	if addon != nil && len(buf.Lines) < height {
		bufListing := addon.Render(width, height-len(buf.Lines))
		focus := true
		if focuser, ok := addon.(focuser); ok {
			focus = focuser.Focus()
		}
		buf.Extend(bufListing, focus)
	}
	return buf
}

func (a *app) ReadCode() (string, error) {
	for _, f := range a.BeforeReadline {
		f()
	}
	defer func() {
		content := a.codeArea.CopyState().Buffer.Content
		for _, f := range a.AfterReadline {
			f(content)
		}
		a.resetAllStates()
	}()

	restore, err := a.TTY.Setup()
	if err != nil {
		return "", err
	}
	defer restore()

	var wg sync.WaitGroup
	defer wg.Wait()

	// Relay input events.
	a.reqRead = make(chan struct{}, 1)
	a.reqRead <- struct{}{}
	defer close(a.reqRead)
	defer a.TTY.StopInput()
	wg.Add(1)
	go func() {
		defer wg.Done()
		for range a.reqRead {
			event, err := a.TTY.ReadEvent()
			if err == nil {
				a.loop.Input(event)
			} else if err == term.ErrStopped {
				return
			} else if term.IsReadErrorRecoverable(err) {
				a.loop.Input(term.NonfatalErrorEvent{Err: err})
			} else {
				a.loop.Input(term.FatalErrorEvent{Err: err})
				return
			}
		}
	}()

	// Relay signals.
	sigCh := a.TTY.NotifySignals()
	defer a.TTY.StopSignals()
	wg.Add(1)
	go func() {
		for sig := range sigCh {
			a.loop.Input(sig)
		}
		wg.Done()
	}()

	// Relay late updates from prompt, rprompt and highlighter.
	stopRelayLateUpdates := make(chan struct{})
	defer close(stopRelayLateUpdates)
	relayLateUpdates := func(ch <-chan struct{}) {
		if ch == nil {
			return
		}
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				select {
				case <-ch:
					a.Redraw()
				case <-stopRelayLateUpdates:
					return
				}
			}
		}()
	}

	relayLateUpdates(a.Prompt.LateUpdates())
	relayLateUpdates(a.RPrompt.LateUpdates())
	relayLateUpdates(a.Highlighter.LateUpdates())

	// Trigger an initial prompt update.
	a.triggerPrompts(true)

	return a.loop.Run()
}

func (a *app) Redraw() {
	a.loop.Redraw(false)
}

func (a *app) RedrawFull() {
	a.loop.Redraw(true)
}

func (a *app) CommitEOF() {
	a.loop.Return("", io.EOF)
}

func (a *app) CommitCode() {
	code := a.codeArea.CopyState().Buffer.Content
	a.loop.Return(code, nil)
}

func (a *app) Notify(note string) {
	a.MutateState(func(s *State) { s.Notes = append(s.Notes, note) })
	a.Redraw()
}
<commit_msg>pkg/cli: Reorder the methods in App.<commit_after>// Package cli implements a generic interactive line editor.
package cli

import (
	"io"
	"os"
	"sync"
	"syscall"

	"src.elv.sh/pkg/cli/term"
	"src.elv.sh/pkg/cli/tk"
	"src.elv.sh/pkg/sys"
)

// App represents a CLI app.
type App interface {
	// ReadCode requests the App to read code from the terminal by running an
	// event loop. This function is not re-entrant.
	ReadCode() (string, error)

	// MutateState mutates the state of the app.
	MutateState(f func(*State))
	// CopyState returns a copy of the a state.
	CopyState() State
	// CodeArea returns the codearea widget of the app.
	CodeArea() tk.CodeArea

	// CommitEOF causes the main loop to exit with EOF. If this method is called
	// when an event is being handled, the main loop will exit after the handler
	// returns.
	CommitEOF()
	// CommitCode causes the main loop to exit with the current code content. If
	// this method is called when an event is being handled, the main loop will
	// exit after the handler returns.
	CommitCode()

	// Redraw requests a redraw. It never blocks and can be called regardless of
	// whether the App is active or not.
	Redraw()
	// RedrawFull requests a full redraw. It never blocks and can be called
	// regardless of whether the App is active or not.
	RedrawFull()
	// Notify adds a note and requests a redraw.
	Notify(note string)
}

type app struct {
	loop    *loop
	reqRead chan struct{}

	TTY               TTY
	MaxHeight         func() int
	RPromptPersistent func() bool
	BeforeReadline    []func()
	AfterReadline     []func(string)
	Highlighter       Highlighter
	Prompt            Prompt
	RPrompt           Prompt

	StateMutex sync.RWMutex
	State      State

	codeArea tk.CodeArea
}

// State represents mutable state of an App.
type State struct {
	// Notes that have been added since the last redraw.
	Notes []string
	// An addon widget. When non-nil, it is shown under the codearea widget and
	// terminal events are handled by it.
	//
	// The cursor is placed on the addon by default. If the addon widget
	// implements interface{ Focus() bool }, the Focus method is called to
	// determine that instead.
	Addon tk.Widget
}

type focuser interface {
	Focus() bool
}

// NewApp creates a new App from the given specification.
func NewApp(spec AppSpec) App {
	lp := newLoop()
	a := app{
		loop:              lp,
		TTY:               spec.TTY,
		MaxHeight:         spec.MaxHeight,
		RPromptPersistent: spec.RPromptPersistent,
		BeforeReadline:    spec.BeforeReadline,
		AfterReadline:     spec.AfterReadline,
		Highlighter:       spec.Highlighter,
		Prompt:            spec.Prompt,
		RPrompt:           spec.RPrompt,
		State:             spec.State,
	}
	if a.TTY == nil {
		a.TTY = NewTTY(os.Stdin, os.Stderr)
	}
	if a.MaxHeight == nil {
		a.MaxHeight = func() int { return -1 }
	}
	if a.RPromptPersistent == nil {
		a.RPromptPersistent = func() bool { return false }
	}
	if a.Highlighter == nil {
		a.Highlighter = dummyHighlighter{}
	}
	if a.Prompt == nil {
		a.Prompt = NewConstPrompt(nil)
	}
	if a.RPrompt == nil {
		a.RPrompt = NewConstPrompt(nil)
	}
	lp.HandleCb(a.handle)
	lp.RedrawCb(a.redraw)

	a.codeArea = tk.NewCodeArea(tk.CodeAreaSpec{
		OverlayHandler: spec.OverlayHandler,
		Highlighter:    a.Highlighter.Get,
		Prompt:         a.Prompt.Get,
		RPrompt:        a.RPrompt.Get,
		Abbreviations:  spec.Abbreviations,
		QuotePaste:     spec.QuotePaste,
		OnSubmit:       a.CommitCode,
		State:          spec.CodeAreaState,

		SmallWordAbbreviations: spec.SmallWordAbbreviations,
	})

	return &a
}

func (a *app) MutateState(f func(*State)) {
	a.StateMutex.Lock()
	defer a.StateMutex.Unlock()
	f(&a.State)
}

func (a *app) CopyState() State {
	a.StateMutex.RLock()
	defer a.StateMutex.RUnlock()
	return a.State
}

func (a *app) CodeArea() tk.CodeArea {
	return a.codeArea
}

func (a *app) resetAllStates() {
	a.MutateState(func(s *State) { *s = State{} })
	a.codeArea.MutateState(
		func(s *tk.CodeAreaState) { *s = tk.CodeAreaState{} })
}

func (a *app) handle(e event) {
	switch e := e.(type) {
	case os.Signal:
		switch e {
		case syscall.SIGHUP:
			a.loop.Return("", io.EOF)
		case syscall.SIGINT:
			a.resetAllStates()
			a.triggerPrompts(true)
		case sys.SIGWINCH:
			a.RedrawFull()
		}
	case term.Event:
		if listing := a.CopyState().Addon; listing != nil {
			listing.Handle(e)
		} else {
			a.codeArea.Handle(e)
		}
		if !a.loop.HasReturned() {
			a.triggerPrompts(false)
			a.reqRead <- struct{}{}
		}
	}
}

func (a *app) triggerPrompts(force bool) {
	a.Prompt.Trigger(force)
	a.RPrompt.Trigger(force)
}

func (a *app) redraw(flag redrawFlag) {
	// Get the dimensions available.
	height, width := a.TTY.Size()
	if maxHeight := a.MaxHeight(); maxHeight > 0 && maxHeight < height {
		height = maxHeight
	}

	var notes []string
	var addon tk.Renderer
	a.MutateState(func(s *State) {
		notes, addon = s.Notes, s.Addon
		s.Notes = nil
	})

	bufNotes := renderNotes(notes, width)
	isFinalRedraw := flag&finalRedraw != 0
	if isFinalRedraw {
		hideRPrompt := !a.RPromptPersistent()
		if hideRPrompt {
			a.codeArea.MutateState(func(s *tk.CodeAreaState) { s.HideRPrompt = true })
		}
		bufMain := renderApp(a.codeArea, nil /* addon */, width, height)
		if hideRPrompt {
			a.codeArea.MutateState(func(s *tk.CodeAreaState) { s.HideRPrompt = false })
		}
		// Insert a newline after the buffer and position the cursor there.
		bufMain.Extend(term.NewBuffer(width), true)

		a.TTY.UpdateBuffer(bufNotes, bufMain, flag&fullRedraw != 0)
		a.TTY.ResetBuffer()
	} else {
		bufMain := renderApp(a.codeArea, addon, width, height)
		a.TTY.UpdateBuffer(bufNotes, bufMain, flag&fullRedraw != 0)
	}
}

// Renders notes. This does not respect height so that overflow notes end up in
// the scrollback buffer.
func renderNotes(notes []string, width int) *term.Buffer {
	if len(notes) == 0 {
		return nil
	}
	bb := term.NewBufferBuilder(width)
	for i, note := range notes {
		if i > 0 {
			bb.Newline()
		}
		bb.Write(note)
	}
	return bb.Buffer()
}

// Renders the codearea, and uses the rest of the height for the listing.
func renderApp(codeArea, addon tk.Renderer, width, height int) *term.Buffer {
	buf := codeArea.Render(width, height)
	if addon != nil && len(buf.Lines) < height {
		bufListing := addon.Render(width, height-len(buf.Lines))
		focus := true
		if focuser, ok := addon.(focuser); ok {
			focus = focuser.Focus()
		}
		buf.Extend(bufListing, focus)
	}
	return buf
}

func (a *app) ReadCode() (string, error) {
	for _, f := range a.BeforeReadline {
		f()
	}
	defer func() {
		content := a.codeArea.CopyState().Buffer.Content
		for _, f := range a.AfterReadline {
			f(content)
		}
		a.resetAllStates()
	}()

	restore, err := a.TTY.Setup()
	if err != nil {
		return "", err
	}
	defer restore()

	var wg sync.WaitGroup
	defer wg.Wait()

	// Relay input events.
	a.reqRead = make(chan struct{}, 1)
	a.reqRead <- struct{}{}
	defer close(a.reqRead)
	defer a.TTY.StopInput()
	wg.Add(1)
	go func() {
		defer wg.Done()
		for range a.reqRead {
			event, err := a.TTY.ReadEvent()
			if err == nil {
				a.loop.Input(event)
			} else if err == term.ErrStopped {
				return
			} else if term.IsReadErrorRecoverable(err) {
				a.loop.Input(term.NonfatalErrorEvent{Err: err})
			} else {
				a.loop.Input(term.FatalErrorEvent{Err: err})
				return
			}
		}
	}()

	// Relay signals.
	sigCh := a.TTY.NotifySignals()
	defer a.TTY.StopSignals()
	wg.Add(1)
	go func() {
		for sig := range sigCh {
			a.loop.Input(sig)
		}
		wg.Done()
	}()

	// Relay late updates from prompt, rprompt and highlighter.
	stopRelayLateUpdates := make(chan struct{})
	defer close(stopRelayLateUpdates)
	relayLateUpdates := func(ch <-chan struct{}) {
		if ch == nil {
			return
		}
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				select {
				case <-ch:
					a.Redraw()
				case <-stopRelayLateUpdates:
					return
				}
			}
		}()
	}

	relayLateUpdates(a.Prompt.LateUpdates())
	relayLateUpdates(a.RPrompt.LateUpdates())
	relayLateUpdates(a.Highlighter.LateUpdates())

	// Trigger an initial prompt update.
	a.triggerPrompts(true)

	return a.loop.Run()
}

func (a *app) Redraw() {
	a.loop.Redraw(false)
}

func (a *app) RedrawFull() {
	a.loop.Redraw(true)
}

func (a *app) CommitEOF() {
	a.loop.Return("", io.EOF)
}

func (a *app) CommitCode() {
	code := a.codeArea.CopyState().Buffer.Content
	a.loop.Return(code, nil)
}

func (a *app) Notify(note string) {
	a.MutateState(func(s *State) { s.Notes = append(s.Notes, note) })
	a.Redraw()
}
<|endoftext|>


<commit_before>/*
Copyright 2021 Intel Corporation

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

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

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

package sst

import (
	"fmt"
	stdlog "log"
	"os"

	grclog "github.com/intel/goresctrl/pkg/log"
	"github.com/intel/goresctrl/pkg/utils"
)

// SstPackageInfo contains status of Intel Speed Select Technologies (SST)
// for one CPU package
type SstPackageInfo struct {
	// Gereric PP info
	PPSupported    bool
	PPLocked       bool
	PPVersion      int
	PPCurrentLevel int
	PPMaxLevel     int

	// Information about the currently active PP level
	CPSupported bool
	CPEnabled   bool
	CPPriority  CPPriorityType
	BFSupported bool
	BFEnabled   bool
	BFCores     utils.IDSet
	TFSupported bool
	TFEnabled   bool

	ClosInfo [NumClos]SstClosInfo
}

// NumClos is the number of CLOSes suported by SST-CP
const NumClos = 4

// SstClosInfo contains parameters of one CLOS of SST-CP
type SstClosInfo struct {
	EPP                  int
	ProportionalPriority int
	MinFreq              int
	MaxFreq              int
	DesiredFreq          int
}

// CPPriorityType denotes the type CLOS priority ordering used in SST-CP
type CPPriorityType int

const (
	Proportional CPPriorityType = 0
	Ordered      CPPriorityType = 1
)

const isstDevPath = "/dev/isst_interface"

var sstlog grclog.Logger = grclog.NewLoggerWrapper(stdlog.New(os.Stderr, "[ sst ] ", 0))

// SstSupported returns true if Intel Speed Select Technologies (SST) is supported
// by the system and can be interfaced via the Linux kernel device
func SstSupported() bool {
	if _, err := os.Stat(isstDevPath); err != nil {
		if !os.IsNotExist(err) {
			sstlog.Warnf("failed to access sst device %q: %v", isstDevPath, err)
		} else {
			sstlog.Debugf("sst device %q does not exist", isstDevPath)
		}
		return false
	}
	return true
}

// GetPackageInfo returns information of the SST configuration of one cpu
// package.
func GetPackageInfo(pkgId utils.ID) (SstPackageInfo, error) {
	info := SstPackageInfo{}

	// Get topology information from sysfs
	packages, err := getOnlineCpuPackages()
	if err != nil {
		return info, fmt.Errorf("failed to determine cpu topology: %w", err)
	}
	pkg, ok := packages[pkgId]
	if !ok {
		return info, fmt.Errorf("cpu package %d not present", pkgId)
	}
	cpu := pkg.cpus[0] // We just need to pass one logical cpu from the pkg as an arg

	var rsp uint32

	// Read perf-profile feature info
	if rsp, err = sendMboxCmd(cpu, CONFIG_TDP, CONFIG_TDP_GET_LEVELS_INFO, 0); err != nil {
		return info, fmt.Errorf("failed to read SST PP info: %v", err)
	}
	info.PPSupported = getBits(rsp, 31, 31) != 0
	info.PPLocked = getBits(rsp, 24, 24) != 0
	info.PPCurrentLevel = int(getBits(rsp, 16, 23))
	info.PPMaxLevel = int(getBits(rsp, 8, 15))
	info.PPVersion = int(getBits(rsp, 0, 7))

	// Forget about older hw with partial/convoluted support
	if info.PPVersion < 3 {
		sstlog.Infof("SST PP version %d (less than 3), giving up...")
		return info, nil
	}

	// Read the status of currently active perf-profile
	if info.PPSupported {
		if rsp, err = sendMboxCmd(cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_CONTROL, uint32(info.PPCurrentLevel)); err != nil {
			return info, fmt.Errorf("failed to read SST BF/TF status: %v", err)
		}

		info.BFSupported = isBitSet(rsp, 1)
		info.BFEnabled = isBitSet(rsp, 17)

		info.TFSupported = isBitSet(rsp, 0)
		info.TFEnabled = isBitSet(rsp, 16)

	}

	// Read base-frequency info
	if info.BFSupported {
		info.BFCores = utils.IDSet{}

		punitCoreIDs := make(map[utils.ID]utils.IDSet, len(pkg.cpus))
		var maxPunitCore utils.ID
		for _, id := range pkg.cpus {
			pc, err := punitCPU(id)
			if err != nil {
				return info, err
			}
			punitCore := pc >> 1
			if _, ok := punitCoreIDs[punitCore]; !ok {
				punitCoreIDs[punitCore] = utils.IDSet{}
			}
			punitCoreIDs[punitCore].Add(id)
			if punitCore > maxPunitCore {
				maxPunitCore = punitCore
			}
		}

		// Read out core masks in batches of 32 (32 bits per response)
		for i := 0; i <= int(maxPunitCore)/32; i++ {
			if rsp, err = sendMboxCmd(cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_CORE_MASK_INFO, uint32(info.PPCurrentLevel+(i<<8))); err != nil {
				return info, fmt.Errorf("failed to read SST BF core mask (#%d): %v", i, err)
			}
			for bit := 0; bit < 32; bit++ {
				if isBitSet(rsp, uint32(bit)) {
					info.BFCores.Add(punitCoreIDs[utils.ID(i*32+bit)].Members()...)
				}
			}
		}
	}

	// Read core-power feature info
	if rsp, err = sendMboxCmd(cpu, READ_PM_CONFIG, PM_FEATURE, 0); err != nil {
		return info, fmt.Errorf("failed to read SST CP info: %v", err)
	}

	info.CPSupported = isBitSet(rsp, 0)
	info.CPEnabled = isBitSet(rsp, 16)

	if info.CPSupported {
		if rsp, err = sendMboxCmd(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0); err != nil {
			return info, fmt.Errorf("failed to read SST CP status: %v", err)
		}

		closEnabled := isBitSet(rsp, 1)
		if closEnabled != info.CPEnabled {
			sstlog.Warnf("SST firmware returned conflicting CP enabled status %v vs. %v", info.CPEnabled, closEnabled)
		}
		info.CPEnabled = closEnabled
		info.CPPriority = CPPriorityType(getBits(rsp, 2, 2))

		for i := uint32(0); i < NumClos; i++ {
			if rsp, err = sendMMIOCmd(cpu, (i<<2)+PM_CLOS_OFFSET); err != nil {
				return info, fmt.Errorf("failed to read SST CLOS #%d info: %v", i, err)
			}
			info.ClosInfo[i] = SstClosInfo{
				EPP:                  int(getBits(rsp, 0, 3)),
				ProportionalPriority: int(getBits(rsp, 4, 7)),
				MinFreq:              int(getBits(rsp, 8, 15)),
				MaxFreq:              int(getBits(rsp, 16, 23)),
				DesiredFreq:          int(getBits(rsp, 24, 31)),
			}
		}
	}

	return info, nil
}

// GetCPUClosID returns the SST-CP CLOS id that a cpu is associated with.
func GetCPUClosID(cpu utils.ID) (int, error) {
	p, err := punitCPU(cpu)
	if err != nil {
		return -1, err
	}
	punitCore := uint32(p) >> 1

	rsp, err := sendMMIOCmd(cpu, (punitCore<<2)+PQR_ASSOC_OFFSET)
	if err != nil {
		return 0, fmt.Errorf("failed to read CLOS number of cpu %d: %v", cpu, err)
	}
	return int(getBits(rsp, 16, 17)), nil
}

func getBits(val, i, j uint32) uint32 {
	lsb := i
	msb := j
	if i > j {
		lsb = j
		msb = i
	}
	return (val >> lsb) & ((1 << (msb - lsb + 1)) - 1)
}

func isBitSet(val, n uint32) bool {
	return val&(1<<n) != 0
}
<commit_msg>sst: detect bf and tf even if pp not supported<commit_after>/*
Copyright 2021 Intel Corporation

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

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

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

package sst

import (
	"fmt"
	stdlog "log"
	"os"

	grclog "github.com/intel/goresctrl/pkg/log"
	"github.com/intel/goresctrl/pkg/utils"
)

// SstPackageInfo contains status of Intel Speed Select Technologies (SST)
// for one CPU package
type SstPackageInfo struct {
	// Gereric PP info
	PPSupported    bool
	PPLocked       bool
	PPVersion      int
	PPCurrentLevel int
	PPMaxLevel     int

	// Information about the currently active PP level
	CPSupported bool
	CPEnabled   bool
	CPPriority  CPPriorityType
	BFSupported bool
	BFEnabled   bool
	BFCores     utils.IDSet
	TFSupported bool
	TFEnabled   bool

	ClosInfo [NumClos]SstClosInfo
}

// NumClos is the number of CLOSes suported by SST-CP
const NumClos = 4

// SstClosInfo contains parameters of one CLOS of SST-CP
type SstClosInfo struct {
	EPP                  int
	ProportionalPriority int
	MinFreq              int
	MaxFreq              int
	DesiredFreq          int
}

// CPPriorityType denotes the type CLOS priority ordering used in SST-CP
type CPPriorityType int

const (
	Proportional CPPriorityType = 0
	Ordered      CPPriorityType = 1
)

const isstDevPath = "/dev/isst_interface"

var sstlog grclog.Logger = grclog.NewLoggerWrapper(stdlog.New(os.Stderr, "[ sst ] ", 0))

// SstSupported returns true if Intel Speed Select Technologies (SST) is supported
// by the system and can be interfaced via the Linux kernel device
func SstSupported() bool {
	if _, err := os.Stat(isstDevPath); err != nil {
		if !os.IsNotExist(err) {
			sstlog.Warnf("failed to access sst device %q: %v", isstDevPath, err)
		} else {
			sstlog.Debugf("sst device %q does not exist", isstDevPath)
		}
		return false
	}
	return true
}

// GetPackageInfo returns information of the SST configuration of one cpu
// package.
func GetPackageInfo(pkgId utils.ID) (SstPackageInfo, error) {
	info := SstPackageInfo{}

	// Get topology information from sysfs
	packages, err := getOnlineCpuPackages()
	if err != nil {
		return info, fmt.Errorf("failed to determine cpu topology: %w", err)
	}
	pkg, ok := packages[pkgId]
	if !ok {
		return info, fmt.Errorf("cpu package %d not present", pkgId)
	}
	cpu := pkg.cpus[0] // We just need to pass one logical cpu from the pkg as an arg

	var rsp uint32

	// Read perf-profile feature info
	if rsp, err = sendMboxCmd(cpu, CONFIG_TDP, CONFIG_TDP_GET_LEVELS_INFO, 0); err != nil {
		return info, fmt.Errorf("failed to read SST PP info: %v", err)
	}
	info.PPSupported = getBits(rsp, 31, 31) != 0
	info.PPLocked = getBits(rsp, 24, 24) != 0
	info.PPCurrentLevel = int(getBits(rsp, 16, 23))
	info.PPMaxLevel = int(getBits(rsp, 8, 15))
	info.PPVersion = int(getBits(rsp, 0, 7))

	// Forget about older hw with partial/convoluted support
	if info.PPVersion < 3 {
		sstlog.Infof("SST PP version %d (less than 3), giving up...")
		return info, nil
	}

	// Read the status of currently active perf-profile
	if !info.PPSupported {
		sstlog.Debugf("SST PP feature not supported, only profile level %d is valid", info.PPCurrentLevel)
	}

	if rsp, err = sendMboxCmd(cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_CONTROL, uint32(info.PPCurrentLevel)); err != nil {
		return info, fmt.Errorf("failed to read SST BF/TF status: %v", err)
	}

	info.BFSupported = isBitSet(rsp, 1)
	info.BFEnabled = isBitSet(rsp, 17)

	info.TFSupported = isBitSet(rsp, 0)
	info.TFEnabled = isBitSet(rsp, 16)

	// Read base-frequency info
	if info.BFSupported {
		info.BFCores = utils.IDSet{}

		punitCoreIDs := make(map[utils.ID]utils.IDSet, len(pkg.cpus))
		var maxPunitCore utils.ID
		for _, id := range pkg.cpus {
			pc, err := punitCPU(id)
			if err != nil {
				return info, err
			}
			punitCore := pc >> 1
			if _, ok := punitCoreIDs[punitCore]; !ok {
				punitCoreIDs[punitCore] = utils.IDSet{}
			}
			punitCoreIDs[punitCore].Add(id)
			if punitCore > maxPunitCore {
				maxPunitCore = punitCore
			}
		}

		// Read out core masks in batches of 32 (32 bits per response)
		for i := 0; i <= int(maxPunitCore)/32; i++ {
			if rsp, err = sendMboxCmd(cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_CORE_MASK_INFO, uint32(info.PPCurrentLevel+(i<<8))); err != nil {
				return info, fmt.Errorf("failed to read SST BF core mask (#%d): %v", i, err)
			}
			for bit := 0; bit < 32; bit++ {
				if isBitSet(rsp, uint32(bit)) {
					info.BFCores.Add(punitCoreIDs[utils.ID(i*32+bit)].Members()...)
				}
			}
		}
	}

	// Read core-power feature info
	if rsp, err = sendMboxCmd(cpu, READ_PM_CONFIG, PM_FEATURE, 0); err != nil {
		return info, fmt.Errorf("failed to read SST CP info: %v", err)
	}

	info.CPSupported = isBitSet(rsp, 0)
	info.CPEnabled = isBitSet(rsp, 16)

	if info.CPSupported {
		if rsp, err = sendMboxCmd(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0); err != nil {
			return info, fmt.Errorf("failed to read SST CP status: %v", err)
		}

		closEnabled := isBitSet(rsp, 1)
		if closEnabled != info.CPEnabled {
			sstlog.Warnf("SST firmware returned conflicting CP enabled status %v vs. %v", info.CPEnabled, closEnabled)
		}
		info.CPEnabled = closEnabled
		info.CPPriority = CPPriorityType(getBits(rsp, 2, 2))

		for i := uint32(0); i < NumClos; i++ {
			if rsp, err = sendMMIOCmd(cpu, (i<<2)+PM_CLOS_OFFSET); err != nil {
				return info, fmt.Errorf("failed to read SST CLOS #%d info: %v", i, err)
			}
			info.ClosInfo[i] = SstClosInfo{
				EPP:                  int(getBits(rsp, 0, 3)),
				ProportionalPriority: int(getBits(rsp, 4, 7)),
				MinFreq:              int(getBits(rsp, 8, 15)),
				MaxFreq:              int(getBits(rsp, 16, 23)),
				DesiredFreq:          int(getBits(rsp, 24, 31)),
			}
		}
	}

	return info, nil
}

// GetCPUClosID returns the SST-CP CLOS id that a cpu is associated with.
func GetCPUClosID(cpu utils.ID) (int, error) {
	p, err := punitCPU(cpu)
	if err != nil {
		return -1, err
	}
	punitCore := uint32(p) >> 1

	rsp, err := sendMMIOCmd(cpu, (punitCore<<2)+PQR_ASSOC_OFFSET)
	if err != nil {
		return 0, fmt.Errorf("failed to read CLOS number of cpu %d: %v", cpu, err)
	}
	return int(getBits(rsp, 16, 17)), nil
}

func getBits(val, i, j uint32) uint32 {
	lsb := i
	msb := j
	if i > j {
		lsb = j
		msb = i
	}
	return (val >> lsb) & ((1 << (msb - lsb + 1)) - 1)
}

func isBitSet(val, n uint32) bool {
	return val&(1<<n) != 0
}
<|endoftext|>


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

package cbft

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

func init() {
	RegisterPIndexImplType("blackhole", &PIndexImplType{
		New:  NewBlackHolePIndexImpl,
		Open: OpenBlackHolePIndexImpl,
		Count: func(mgr *Manager, indexName, indexUUID string) (uint64, error) {
			return 0, fmt.Errorf("blackhole is uncountable")
		},
		Query: func(mgr *Manager, indexName, indexUUID string,
			req []byte, res io.Writer) error {
			return fmt.Errorf("blackhole is unqueryable")
		},
		Description: "blackhole - ignores all incoming data" +
			" and is not queryable; used for testing",
	})
}

func NewBlackHolePIndexImpl(indexType, indexParams, path string, restart func()) (
	PIndexImpl, Dest, error) {
	err := os.MkdirAll(path, 0700)
	if err != nil {
		return nil, nil, err
	}

	err = ioutil.WriteFile(path+string(os.PathSeparator)+"black.hole",
		[]byte{}, 0600)
	if err != nil {
		return nil, nil, err
	}

	dest := &BlackHole{path: path}
	return dest, dest, nil
}

func OpenBlackHolePIndexImpl(indexType, path string, restart func()) (
	PIndexImpl, Dest, error) {
	buf, err := ioutil.ReadFile(path + string(os.PathSeparator) + "black.hole")
	if err != nil {
		return nil, nil, err
	}
	if len(buf) > 0 {
		return nil, nil, fmt.Errorf("expected black.hole to be empty")
	}

	dest := &BlackHole{path: path}
	return dest, dest, nil
}

// ---------------------------------------------------------

// Implements both Dest and PIndexImpl interfaces.
type BlackHole struct {
	path string
}

func (t *BlackHole) Close() error {
	return nil
}

func (t *BlackHole) OnDataUpdate(partition string,
	key []byte, seq uint64, val []byte) error {
	return nil
}

func (t *BlackHole) OnDataDelete(partition string,
	key []byte, seq uint64) error {
	return nil
}

func (t *BlackHole) OnSnapshotStart(partition string,
	snapStart, snapEnd uint64) error {
	return nil
}

func (t *BlackHole) SetOpaque(partition string, value []byte) error {
	return nil
}

func (t *BlackHole) GetOpaque(partition string) (
	value []byte, lastSeq uint64, err error) {
	return nil, 0, nil
}

func (t *BlackHole) Rollback(partition string, rollbackSeq uint64) error {
	return nil
}

func (t *BlackHole) ConsistencyWait(partition string,
	consistencyLevel string,
	consistencySeq uint64,
	cancelCh chan struct{}) error {
	return nil
}

func (t *BlackHole) Count(pindex *PIndex,
	cancelCh chan struct{}) (uint64, error) {
	return 0, nil
}

func (t *BlackHole) Query(pindex *PIndex, req []byte, w io.Writer,
	cancelCh chan struct{}) error {
	return nil
}
<commit_msg>added totUpdate/totDelete fields to blackhole<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package cbft

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sync/atomic"
)

func init() {
	RegisterPIndexImplType("blackhole", &PIndexImplType{
		New:  NewBlackHolePIndexImpl,
		Open: OpenBlackHolePIndexImpl,
		Count: func(mgr *Manager, indexName, indexUUID string) (uint64, error) {
			return 0, fmt.Errorf("blackhole is uncountable")
		},
		Query: func(mgr *Manager, indexName, indexUUID string,
			req []byte, res io.Writer) error {
			return fmt.Errorf("blackhole is unqueryable")
		},
		Description: "blackhole - ignores all incoming data" +
			" and is not queryable; used for testing",
	})
}

func NewBlackHolePIndexImpl(indexType, indexParams, path string, restart func()) (
	PIndexImpl, Dest, error) {
	err := os.MkdirAll(path, 0700)
	if err != nil {
		return nil, nil, err
	}

	err = ioutil.WriteFile(path+string(os.PathSeparator)+"black.hole",
		[]byte{}, 0600)
	if err != nil {
		return nil, nil, err
	}

	dest := &BlackHole{path: path}
	return dest, dest, nil
}

func OpenBlackHolePIndexImpl(indexType, path string, restart func()) (
	PIndexImpl, Dest, error) {
	buf, err := ioutil.ReadFile(path + string(os.PathSeparator) + "black.hole")
	if err != nil {
		return nil, nil, err
	}
	if len(buf) > 0 {
		return nil, nil, fmt.Errorf("expected black.hole to be empty")
	}

	dest := &BlackHole{path: path}
	return dest, dest, nil
}

// ---------------------------------------------------------

// Implements both Dest and PIndexImpl interfaces.
type BlackHole struct {
	path string

	totUpdate uint64
	totDelete uint64
}

func (t *BlackHole) Close() error {
	return nil
}

func (t *BlackHole) OnDataUpdate(partition string,
	key []byte, seq uint64, val []byte) error {
	atomic.AddUint64(&t.totUpdate, 1)
	return nil
}

func (t *BlackHole) OnDataDelete(partition string,
	key []byte, seq uint64) error {
	atomic.AddUint64(&t.totDelete, 1)
	return nil
}

func (t *BlackHole) OnSnapshotStart(partition string,
	snapStart, snapEnd uint64) error {
	return nil
}

func (t *BlackHole) SetOpaque(partition string, value []byte) error {
	return nil
}

func (t *BlackHole) GetOpaque(partition string) (
	value []byte, lastSeq uint64, err error) {
	return nil, 0, nil
}

func (t *BlackHole) Rollback(partition string, rollbackSeq uint64) error {
	return nil
}

func (t *BlackHole) ConsistencyWait(partition string,
	consistencyLevel string,
	consistencySeq uint64,
	cancelCh chan struct{}) error {
	return nil
}

func (t *BlackHole) Count(pindex *PIndex,
	cancelCh chan struct{}) (uint64, error) {
	return 0, nil
}

func (t *BlackHole) Query(pindex *PIndex, req []byte, w io.Writer,
	cancelCh chan struct{}) error {
	return nil
}
<|endoftext|>