<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"sort"
	"strconv"
	"syscall"
	"time"
)

const MAXDIRREAD int = 50

var uwidth int
var gwidth int
var swidth int

var (
	usedir   = flag.Bool("d", false, "List a directory instead of its contents.")
	long     = flag.Bool("l", false, "Long format list.")
	usrname  = flag.Bool("m", false, "List the user who last modified the file.")
	nosort   = flag.Bool("n", false, "Don't sort the list.")
	nopath   = flag.Bool("p", false, "Only print the last path element.")
	reverse  = flag.Bool("r", false, "Reverse the sorting order.")
	kbytes   = flag.Bool("s", false, "Give size in KBytes for each file.")
	timesort = flag.Bool("t", false, "Sort by latest-modified first.")
	useatime = flag.Bool("u", false, "If -t sort by access time; if -u print "+
		"last access time.")
	tlslash = flag.Bool("F", false, "Add / after all directories and * after "+
		"all executables.")
)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: ls [-dlmnprstuF] [file ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func error(s string) {
	fmt.Fprint(os.Stderr, s, "\n")
	os.Exit(1)
}

type dent struct {
	mode string
	p    string
	u    string
	Atim syscall.Timespec
	Ctim syscall.Timespec
	t    time.Time
	qver int32
	qpth uint64
	g    uint32
	s    int64
	n    string
	d    bool
	e    bool
}

func (self *dent) getInfo(fi os.FileInfo) {
	self.n = fi.Name()
	self.s = fi.Size()

	l := len(strconv.Itoa(int(self.s)))
	if l > swidth {
		swidth = l
	}

	self.mode = fi.Mode().String()
	self.d = fi.Mode().IsDir()
	self.t = fi.ModTime()

	if fi.Mode().Perm()&0111 != 0 && !self.d {
		self.e = true
	}

	/* The following is probably not portable */
	s := fi.Sys().(*syscall.Stat_t)

	self.Ctim = s.Ctim
	self.Atim = s.Atim
	self.qver = s.Mtim.Sec + s.Ctim.Sec
	self.qpth = s.Ino

	if *useatime {
		self.t = time.Unix(int64(self.Atim.Sec), int64(self.Atim.Nsec))
	}

	u, _ := user.LookupId(strconv.Itoa(int(s.Uid)))

	if len(u.Username) > uwidth {
		uwidth = len(u.Username)
	}

	gl := strconv.Itoa(int(s.Gid))
	if len(gl) > gwidth {
		gwidth = len(gl)
	}

	self.u = u.Username
	self.g = s.Gid
}

func (self *dent) String() string {
	/* Put the time parsing here so we can sort easier elsewhere */
	yr := self.t.Year()
	mon := self.t.Format("Jan")
	day := self.t.Day()
	hr, min, _ := self.t.Clock()
	var m string

	if time.Now().Year() == yr {
		m = fmt.Sprintf("%s %2d %02d:%02d", mon, day, hr, min)
	} else {
		m = fmt.Sprintf("%s %2d %5d", mon, day, yr)
	}

	return fmt.Sprintf("%s %*s %*d %*d %s",
		self.mode,
		uwidth, self.u,
		gwidth, self.g,
		swidth, self.s,
		m)
}

/* Sorting Helpers */
type dents []*dent

func (d dents) Len() int      { return len(d) }
func (d dents) Swap(i, j int) { d[i], d[j] = d[j], d[i] }

type ByName struct{ dents }

func (s ByName) Less(i, j int) bool { return s.dents[i].n < s.dents[j].n }

type ByMTime struct{ dents }

func (s ByMTime) Less(i, j int) bool {
	return s.dents[i].t.Unix() > s.dents[j].t.Unix()
}

type Reverse struct{ sort.Interface }

func (r Reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }

func ls(path string) {
	dents := make([]*dent, 0, MAXDIRREAD)

	addDent := func(d *dent) {
		l := len(dents)
		if l+1 > cap(dents) {
			n_dents := make([]*dent, l+MAXDIRREAD)
			copy(n_dents, dents)
			dents = n_dents
		}
		dents = dents[0 : l+1]
		dents[l] = d
	}

	printFName := func(d *dent) {
		fmt.Printf("%s%s", d.p, d.n)
		if *tlslash {
			if d.d {
				fmt.Print("/")
			} else if d.e {
				fmt.Print("*")
			}
		}
		fmt.Print("\n")
	}

	processDent := func(file os.FileInfo, p string) {
		d := new(dent)

		if *nopath {
			p = ""
		}
		d.p = p
		if p != "" {
			d.p += "/"
		}

		d.getInfo(file)
		addDent(d)
	}

	var pth string
	if path == "" {
		pth = "."
	} else {
		pth = path
	}

	f, err := os.Open(pth)
	if err != nil {
		error(fmt.Sprintf("%s", err))
	}

	s, err := f.Stat()
	if err != nil {
		error(fmt.Sprintf("%s", err))
	}

	if !s.Mode().IsDir() || *usedir {
		processDent(s, "")
	} else {
		for {
			fi, err := f.Readdir(MAXDIRREAD)
			if err != nil {
				if err == io.EOF {
					break
				} else {
					error(fmt.Sprint("%s", err))
				}
			}

			for _, file := range fi {
				processDent(file, path)
			}
		}

		if !*nosort {
			if !*timesort {
				if !*reverse {
					sort.Sort(ByName{dents})
				} else {
					sort.Sort(Reverse{ByName{dents}})
				}
			} else {
				if !*reverse {
					sort.Sort(ByMTime{dents})
				} else {
					sort.Sort(Reverse{ByMTime{dents}})
				}
			}
		}
	}

	for _, d := range dents {
		if *kbytes {
			nswidth := swidth - 3
			if nswidth < 1 {
				nswidth = 1
			}
			fmt.Printf("%*d ", nswidth, d.s/1024)
		}

		/* Provided for compatibility only */
		if *usrname {
			fmt.Print("[] ")
		}

		if *long {
			fmt.Printf("%s ", d.String())
		}
		printFName(d)
	}
}

func main() {
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()

	if len(args) == 0 {
		ls("")
	} else {
		for _, path := range args {
			ls(path)
		}
	}

	os.Exit(0)
}
<commit_msg>Tiny cleanup and a comment<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"sort"
	"strconv"
	"syscall"
	"time"
)

/*
 * We only read in a certain number of dirents at a time, which should make
 * things a little more robust on unreliable file systems.
 */
const MAXDIRREAD int = 50

var uwidth int
var gwidth int
var swidth int

var (
	usedir   = flag.Bool("d", false, "List a directory instead of its contents.")
	long     = flag.Bool("l", false, "Long format list.")
	usrname  = flag.Bool("m", false, "List the user who last modified the file.")
	nosort   = flag.Bool("n", false, "Don't sort the list.")
	nopath   = flag.Bool("p", false, "Only print the last path element.")
	reverse  = flag.Bool("r", false, "Reverse the sorting order.")
	kbytes   = flag.Bool("s", false, "Give size in KBytes for each file.")
	timesort = flag.Bool("t", false, "Sort by latest-modified first.")
	useatime = flag.Bool("u", false, "If -t sort by access time; if -u print "+
		"last access time.")
	tlslash = flag.Bool("F", false, "Add / after all directories and * after "+
		"all executables.")
)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: ls [-dlmnprstuF] [file ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func error(s string) {
	fmt.Fprint(os.Stderr, s, "\n")
	os.Exit(1)
}

func main() {
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()

	if len(args) == 0 {
		ls("")
	} else {
		for _, path := range args {
			ls(path)
		}
	}

	os.Exit(0)
}

type dent struct {
	mode string
	p    string
	u    string
	Atim syscall.Timespec
	Ctim syscall.Timespec
	t    time.Time
	qver int32
	qpth uint64
	g    uint32
	s    int64
	n    string
	d    bool
	e    bool
}

func (self *dent) getInfo(fi os.FileInfo) {
	self.n = fi.Name()
	self.s = fi.Size()

	l := len(strconv.Itoa(int(self.s)))
	if l > swidth {
		swidth = l
	}

	self.mode = fi.Mode().String()
	self.d = fi.Mode().IsDir()
	self.t = fi.ModTime()

	if fi.Mode().Perm()&0111 != 0 && !self.d {
		self.e = true
	}

	/* The following is probably not portable */
	s := fi.Sys().(*syscall.Stat_t)

	self.Ctim = s.Ctim
	self.Atim = s.Atim
	self.qver = s.Mtim.Sec + s.Ctim.Sec
	self.qpth = s.Ino

	if *useatime {
		self.t = time.Unix(int64(self.Atim.Sec), int64(self.Atim.Nsec))
	}

	u, _ := user.LookupId(strconv.Itoa(int(s.Uid)))

	if len(u.Username) > uwidth {
		uwidth = len(u.Username)
	}

	gl := strconv.Itoa(int(s.Gid))
	if len(gl) > gwidth {
		gwidth = len(gl)
	}

	self.u = u.Username
	self.g = s.Gid
}

func (self *dent) String() string {
	/* Put the time parsing here so we can sort easier elsewhere */
	yr := self.t.Year()
	mon := self.t.Format("Jan")
	day := self.t.Day()
	hr, min, _ := self.t.Clock()
	var m string

	if time.Now().Year() == yr {
		m = fmt.Sprintf("%s %2d %02d:%02d", mon, day, hr, min)
	} else {
		m = fmt.Sprintf("%s %2d %5d", mon, day, yr)
	}

	return fmt.Sprintf("%s %*s %*d %*d %s",
		self.mode,
		uwidth, self.u,
		gwidth, self.g,
		swidth, self.s,
		m)
}

/* Sorting Helpers */
type dents []*dent

func (d dents) Len() int      { return len(d) }
func (d dents) Swap(i, j int) { d[i], d[j] = d[j], d[i] }

type ByName struct{ dents }

func (s ByName) Less(i, j int) bool { return s.dents[i].n < s.dents[j].n }

type ByMTime struct{ dents }

func (s ByMTime) Less(i, j int) bool {
	return s.dents[i].t.Unix() > s.dents[j].t.Unix()
}

type Reverse struct{ sort.Interface }

func (r Reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }

func ls(path string) {
	dents := make([]*dent, 0, MAXDIRREAD)

	addDent := func(d *dent) {
		l := len(dents)
		if l+1 > cap(dents) {
			n_dents := make([]*dent, l+MAXDIRREAD)
			copy(n_dents, dents)
			dents = n_dents
		}
		dents = dents[0 : l+1]
		dents[l] = d
	}

	printFName := func(d *dent) {
		fmt.Printf("%s%s", d.p, d.n)
		if *tlslash {
			if d.d {
				fmt.Print("/")
			} else if d.e {
				fmt.Print("*")
			}
		}
		fmt.Print("\n")
	}

	processDent := func(file os.FileInfo, p string) {
		d := new(dent)

		if *nopath {
			p = ""
		}
		d.p = p
		if p != "" {
			d.p += "/"
		}

		d.getInfo(file)
		addDent(d)
	}

	var pth string
	if path == "" {
		pth = "."
	} else {
		pth = path
	}

	f, err := os.Open(pth)
	if err != nil {
		error(fmt.Sprintf("%s", err))
	}

	s, err := f.Stat()
	if err != nil {
		error(fmt.Sprintf("%s", err))
	}

	if !s.Mode().IsDir() || *usedir {
		processDent(s, "")
	} else {
		for {
			fi, err := f.Readdir(MAXDIRREAD)
			if err != nil {
				if err == io.EOF {
					break
				} else {
					error(fmt.Sprint("%s", err))
				}
			}

			for _, file := range fi {
				processDent(file, path)
			}
		}

		if !*nosort {
			if !*timesort {
				if !*reverse {
					sort.Sort(ByName{dents})
				} else {
					sort.Sort(Reverse{ByName{dents}})
				}
			} else {
				if !*reverse {
					sort.Sort(ByMTime{dents})
				} else {
					sort.Sort(Reverse{ByMTime{dents}})
				}
			}
		}
	}

	for _, d := range dents {
		if *kbytes {
			nswidth := swidth - 3
			if nswidth < 1 {
				nswidth = 1
			}
			fmt.Printf("%*d ", nswidth, d.s/1024)
		}

		/* Provided for compatibility only */
		if *usrname {
			fmt.Print("[] ")
		}

		if *long {
			fmt.Printf("%s ", d.String())
		}

		printFName(d)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"strings"
)

// StorageService holds information about how to connect to a remote
// storage service.
type StorageService struct {
	Id             int64  `db:"id" form_options:"skip"`
	Name           string `db:"name"`
	Description    string `db:"description"`
	Protocol       string `db:"protocol"`
	URL            string `db:"url"`
	BucketOrFolder string `db:"bucket_or_folder"`
	CredentialsId  *int64 `db:"credentials_id"`
	errors         []string
}

// GetStorageService returns the service with the specified id, or an error if the
// service does not exist.
func GetStorageService(id int64) (*StorageService, error) {
	service := &StorageService{Id: id}
	query := SelectByIdQuery(service)
	db := GetConnection(DEFAULT_CONNECTION)
	err := db.Get(service, query, id)
	if err == nil {
		return service, err
	}
	return nil, err
}

// GetStorageServices returns the services matching the criteria specified in where.
// The values param should be a map of values reference in the
// where clause.
//
// For example:
//
// where := "name = ? and age = ?"
// values := []interface{} { "Billy Bob Thornton", 62 }
// services, err := GetStorageServices(where, values)
func GetStorageServices(where string, values []interface{}) ([]*StorageService, error) {
	service := &StorageService{}
	var query string
	if strings.TrimSpace(where) != "" {
		query = SelectWhere(service, where)
	} else {
		query = SelectQuery(service)
	}
	services := make([]*StorageService, 0)
	db := GetConnection(DEFAULT_CONNECTION)
	err := db.Select(&services, query, values...)
	return services, err
}

// Save saves the object to the database. If validate is true,
// it validates before saving. After a successful save, the object
// will have a non-zero Id. If this returns false, check Errors().
func (service *StorageService) Save(validate bool) bool {
	return SaveObject(service)
}

// GetId() returns this object's Id, to conform to the Model interface.
func (service *StorageService) GetId() int64 {
	return service.Id
}

// SetId() sets this object's Id.
func (service *StorageService) SetId(id int64) {
	service.Id = id
}

// TableName returns the name of the database table where this model's
// records are stored.
func (service *StorageService) TableName() string {
	return "storage_services"
}

// Validate runs validation checks on the object and returns true if
// the object is valid. If this returns false, check Errors().
func (service *StorageService) Validate() bool {
	service.initErrors(true)
	return true
}

// Errors returns a list of errors that occurred after a call to Validate()
// or Save().
func (service *StorageService) Errors() []string {
	service.initErrors(false)
	return service.errors
}

// initErrors initializes the errors list. If param clearExistingList
// is true, it replaces the existing errors list with a blank list.
func (service *StorageService) initErrors(clearExistingList bool) {
	if service.errors == nil || clearExistingList {
		service.errors = make([]string, 0)
	}
}

// AddError adds an error message to the errors list.
func (service *StorageService) AddError(message string) {
	service.errors = append(service.errors, message)
}

func (service *StorageService) Credentials() (*Credentials, error) {
	if service.CredentialsId != nil && *service.CredentialsId != 0 {
		return GetCredential(*service.CredentialsId)
	}
	return nil, nil
}
<commit_msg>Don't show credentials id on form<commit_after>package models

import (
	"strings"
)

// StorageService holds information about how to connect to a remote
// storage service.
type StorageService struct {
	Id             int64    `db:"id" form_options:"skip"`
	Name           string   `db:"name"`
	Description    string   `db:"description"`
	Protocol       string   `db:"protocol"`
	URL            string   `db:"url"`
	BucketOrFolder string   `db:"bucket_or_folder"`
	CredentialsId  *int64   `db:"credentials_id" form_options:"skip"`
	errors         []string `form_options:"skip"`
}

// GetStorageService returns the service with the specified id, or an error if the
// service does not exist.
func GetStorageService(id int64) (*StorageService, error) {
	service := &StorageService{Id: id}
	query := SelectByIdQuery(service)
	db := GetConnection(DEFAULT_CONNECTION)
	err := db.Get(service, query, id)
	if err == nil {
		return service, err
	}
	return nil, err
}

// GetStorageServices returns the services matching the criteria specified in where.
// The values param should be a map of values reference in the
// where clause.
//
// For example:
//
// where := "name = ? and age = ?"
// values := []interface{} { "Billy Bob Thornton", 62 }
// services, err := GetStorageServices(where, values)
func GetStorageServices(where string, values []interface{}) ([]*StorageService, error) {
	service := &StorageService{}
	var query string
	if strings.TrimSpace(where) != "" {
		query = SelectWhere(service, where)
	} else {
		query = SelectQuery(service)
	}
	services := make([]*StorageService, 0)
	db := GetConnection(DEFAULT_CONNECTION)
	err := db.Select(&services, query, values...)
	return services, err
}

// Save saves the object to the database. If validate is true,
// it validates before saving. After a successful save, the object
// will have a non-zero Id. If this returns false, check Errors().
func (service *StorageService) Save(validate bool) bool {
	return SaveObject(service)
}

// GetId() returns this object's Id, to conform to the Model interface.
func (service *StorageService) GetId() int64 {
	return service.Id
}

// SetId() sets this object's Id.
func (service *StorageService) SetId(id int64) {
	service.Id = id
}

// TableName returns the name of the database table where this model's
// records are stored.
func (service *StorageService) TableName() string {
	return "storage_services"
}

// Validate runs validation checks on the object and returns true if
// the object is valid. If this returns false, check Errors().
func (service *StorageService) Validate() bool {
	service.initErrors(true)
	return true
}

// Errors returns a list of errors that occurred after a call to Validate()
// or Save().
func (service *StorageService) Errors() []string {
	service.initErrors(false)
	return service.errors
}

// initErrors initializes the errors list. If param clearExistingList
// is true, it replaces the existing errors list with a blank list.
func (service *StorageService) initErrors(clearExistingList bool) {
	if service.errors == nil || clearExistingList {
		service.errors = make([]string, 0)
	}
}

// AddError adds an error message to the errors list.
func (service *StorageService) AddError(message string) {
	service.errors = append(service.errors, message)
}

func (service *StorageService) Credentials() (*Credentials, error) {
	if service.CredentialsId != nil && *service.CredentialsId != 0 {
		return GetCredential(*service.CredentialsId)
	}
	return nil, nil
}
<|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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"sync"
	"time"

	log "github.com/couchbaselabs/clog"
)

type ManagerEventHandlers interface {
	OnRegisterPIndex(pindex *PIndex)
	OnUnregisterPIndex(pindex *PIndex)
}

type Manager struct {
	uuid      string // Unique to every Manager process instance.
	startTime time.Time
	version   string // Our software VERSION.
	cfg       Cfg
	bindAddr  string
	dataDir   string
	server    string // The datasource that cbft will index.
	m         sync.Mutex
	feeds     map[string]Feed
	pindexes  map[string]*PIndex
	plannerCh chan string // Used to kick the planner that there's more work.
	janitorCh chan string // Used to kick the janitor that there's more work.
	meh       ManagerEventHandlers
}

func NewManager(version string, cfg Cfg, bindAddr, dataDir string,
	server string, meh ManagerEventHandlers) *Manager {
	return &Manager{
		uuid:      NewUUID(),
		startTime: time.Now(),
		version:   version,
		cfg:       cfg,
		bindAddr:  bindAddr,
		dataDir:   dataDir,
		server:    server,
		feeds:     make(map[string]Feed),
		pindexes:  make(map[string]*PIndex),
		plannerCh: make(chan string),
		janitorCh: make(chan string),
		meh:       meh,
	}
}

func (mgr *Manager) Start() error {
	// TODO: Write our cbft-ID into the cfg.

	if err := mgr.LoadDataDir(); err != nil {
		return err
	}

	// Save our nodeDef into the Cfg.
	if err := mgr.SaveNodeDef(); err != nil {
		return err
	}

	go mgr.PlannerLoop()
	mgr.plannerCh <- "start"

	go mgr.JanitorLoop()
	mgr.janitorCh <- "start"

	return nil
}

func (mgr *Manager) LoadDataDir() error {
	// walk the data dir and register pindexes
	log.Printf("loading dataDir...")
	dirEntries, err := ioutil.ReadDir(mgr.dataDir)
	if err != nil {
		return fmt.Errorf("error: could not read dataDir: %s, err: %v",
			mgr.dataDir, err)
	}

	for _, dirInfo := range dirEntries {
		path := mgr.dataDir + string(os.PathSeparator) + dirInfo.Name()
		name, ok := mgr.ParsePIndexPath(path)
		if !ok {
			log.Printf("  skipping: %s", dirInfo.Name())
			continue
		}

		log.Printf("  opening pindex: %s", name)
		pindex, err := OpenPIndex(name, path)
		if err != nil {
			log.Printf("error: could not open pindex: %s, err: %v",
				path, err)
			continue
		}

		mgr.RegisterPIndex(pindex)
	}

	return nil
}

func (mgr *Manager) SaveNodeDef() error {
	if mgr.cfg == nil {
		return nil // Occurs during testing.
	}

	nodeDefs, cas, err := CfgGetNodeDefs(mgr.cfg, NODE_DEFS_KNOWN)
	if err != nil {
		return err
	}
	if nodeDefs == nil {
		nodeDefs = NewNodeDefs(mgr.version)
	}
	nodeDef, exists := nodeDefs.NodeDefs[mgr.bindAddr]
	if !exists {
		nodeDef = &NodeDef{
			HostPort:    mgr.bindAddr, // TODO: need FQDN:port instead of ":8095".
			UUID:        mgr.uuid,
			ImplVersion: mgr.version,
		}

		nodeDefs.UUID = NewUUID()
		nodeDefs.NodeDefs[mgr.bindAddr] = nodeDef
		nodeDefs.ImplVersion = mgr.version

		_, err = CfgSetNodeDefs(mgr.cfg, NODE_DEFS_KNOWN, nodeDefs, cas)
		if err != nil {
			return err
		}
	}

	if nodeDef.UUID != mgr.uuid {
		// TODO: Check if our UUID (in dataDir) matches nodeDef.
	}

	return nil
}

func (mgr *Manager) RegisterFeed(feed Feed) error {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	if _, exists := mgr.feeds[feed.Name()]; exists {
		return fmt.Errorf("error: registered feed already exists, name: %s",
			feed.Name())
	}
	mgr.feeds[feed.Name()] = feed
	return nil
}

func (mgr *Manager) UnregisterFeed(name string) Feed {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	rv, ok := mgr.feeds[name]
	if ok {
		delete(mgr.feeds, name)
		return rv
	}
	return nil
}

func (mgr *Manager) RegisterPIndex(pindex *PIndex) error {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	if _, exists := mgr.pindexes[pindex.Name()]; exists {
		return fmt.Errorf("error: registered pindex already exists, name: %s",
			pindex.Name())
	}
	mgr.pindexes[pindex.Name()] = pindex
	if mgr.meh != nil {
		mgr.meh.OnRegisterPIndex(pindex)
	}
	return nil
}

func (mgr *Manager) UnregisterPIndex(name string) *PIndex {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	pindex, ok := mgr.pindexes[name]
	if ok {
		delete(mgr.pindexes, name)
		if mgr.meh != nil {
			mgr.meh.OnUnregisterPIndex(pindex)
		}
		return pindex
	}
	return nil
}

// Returns a snapshot copy of the current feeds and pindexes.
func (mgr *Manager) CurrentMaps() (map[string]Feed, map[string]*PIndex) {
	feeds := make(map[string]Feed)
	pindexes := make(map[string]*PIndex)

	mgr.m.Lock()
	defer mgr.m.Unlock()

	for k, v := range mgr.feeds {
		feeds[k] = v
	}
	for k, v := range mgr.pindexes {
		pindexes[k] = v
	}
	return feeds, pindexes
}

func (mgr *Manager) PIndexPath(pindexName string) string {
	return PIndexPath(mgr.dataDir, pindexName)
}

func (mgr *Manager) ParsePIndexPath(pindexPath string) (string, bool) {
	return ParsePIndexPath(mgr.dataDir, pindexPath)
}

func (mgr *Manager) DataDir() string {
	return mgr.dataDir
}
<commit_msg>parametrized SaveNodeDefs()<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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"sync"
	"time"

	log "github.com/couchbaselabs/clog"
)

type ManagerEventHandlers interface {
	OnRegisterPIndex(pindex *PIndex)
	OnUnregisterPIndex(pindex *PIndex)
}

type Manager struct {
	uuid      string // Unique to every Manager process instance.
	startTime time.Time
	version   string // Our software VERSION.
	cfg       Cfg
	bindAddr  string
	dataDir   string
	server    string // The datasource that cbft will index.
	m         sync.Mutex
	feeds     map[string]Feed
	pindexes  map[string]*PIndex
	plannerCh chan string // Used to kick the planner that there's more work.
	janitorCh chan string // Used to kick the janitor that there's more work.
	meh       ManagerEventHandlers
}

func NewManager(version string, cfg Cfg, bindAddr, dataDir string,
	server string, meh ManagerEventHandlers) *Manager {
	return &Manager{
		uuid:      NewUUID(),
		startTime: time.Now(),
		version:   version,
		cfg:       cfg,
		bindAddr:  bindAddr,
		dataDir:   dataDir,
		server:    server,
		feeds:     make(map[string]Feed),
		pindexes:  make(map[string]*PIndex),
		plannerCh: make(chan string),
		janitorCh: make(chan string),
		meh:       meh,
	}
}

func (mgr *Manager) Start() error {
	// TODO: Write our cbft-ID into the cfg.

	if err := mgr.LoadDataDir(); err != nil {
		return err
	}

	// Save our nodeDef into the Cfg.
	if err := mgr.SaveNodeDef(NODE_DEFS_KNOWN); err != nil {
		return err
	}

	go mgr.PlannerLoop()
	mgr.plannerCh <- "start"

	go mgr.JanitorLoop()
	mgr.janitorCh <- "start"

	return nil
}

func (mgr *Manager) LoadDataDir() error {
	// walk the data dir and register pindexes
	log.Printf("loading dataDir...")
	dirEntries, err := ioutil.ReadDir(mgr.dataDir)
	if err != nil {
		return fmt.Errorf("error: could not read dataDir: %s, err: %v",
			mgr.dataDir, err)
	}

	for _, dirInfo := range dirEntries {
		path := mgr.dataDir + string(os.PathSeparator) + dirInfo.Name()
		name, ok := mgr.ParsePIndexPath(path)
		if !ok {
			log.Printf("  skipping: %s", dirInfo.Name())
			continue
		}

		log.Printf("  opening pindex: %s", name)
		pindex, err := OpenPIndex(name, path)
		if err != nil {
			log.Printf("error: could not open pindex: %s, err: %v",
				path, err)
			continue
		}

		mgr.RegisterPIndex(pindex)
	}

	return nil
}

func (mgr *Manager) SaveNodeDef(kind string) error {
	if mgr.cfg == nil {
		return nil // Occurs during testing.
	}

	nodeDefs, cas, err := CfgGetNodeDefs(mgr.cfg, kind)
	if err != nil {
		return err
	}
	if nodeDefs == nil {
		nodeDefs = NewNodeDefs(mgr.version)
	}
	nodeDef, exists := nodeDefs.NodeDefs[mgr.bindAddr]
	if !exists {
		nodeDef = &NodeDef{
			HostPort:    mgr.bindAddr, // TODO: need FQDN:port instead of ":8095".
			UUID:        mgr.uuid,
			ImplVersion: mgr.version,
		}

		nodeDefs.UUID = NewUUID()
		nodeDefs.NodeDefs[mgr.bindAddr] = nodeDef
		nodeDefs.ImplVersion = mgr.version

		_, err = CfgSetNodeDefs(mgr.cfg, kind, nodeDefs, cas)
		if err != nil {
			return err
		}
	}

	if nodeDef.UUID != mgr.uuid {
		// TODO: Check if our UUID (in dataDir) matches nodeDef.
	}

	return nil
}

func (mgr *Manager) RegisterFeed(feed Feed) error {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	if _, exists := mgr.feeds[feed.Name()]; exists {
		return fmt.Errorf("error: registered feed already exists, name: %s",
			feed.Name())
	}
	mgr.feeds[feed.Name()] = feed
	return nil
}

func (mgr *Manager) UnregisterFeed(name string) Feed {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	rv, ok := mgr.feeds[name]
	if ok {
		delete(mgr.feeds, name)
		return rv
	}
	return nil
}

func (mgr *Manager) RegisterPIndex(pindex *PIndex) error {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	if _, exists := mgr.pindexes[pindex.Name()]; exists {
		return fmt.Errorf("error: registered pindex already exists, name: %s",
			pindex.Name())
	}
	mgr.pindexes[pindex.Name()] = pindex
	if mgr.meh != nil {
		mgr.meh.OnRegisterPIndex(pindex)
	}
	return nil
}

func (mgr *Manager) UnregisterPIndex(name string) *PIndex {
	mgr.m.Lock()
	defer mgr.m.Unlock()

	pindex, ok := mgr.pindexes[name]
	if ok {
		delete(mgr.pindexes, name)
		if mgr.meh != nil {
			mgr.meh.OnUnregisterPIndex(pindex)
		}
		return pindex
	}
	return nil
}

// Returns a snapshot copy of the current feeds and pindexes.
func (mgr *Manager) CurrentMaps() (map[string]Feed, map[string]*PIndex) {
	feeds := make(map[string]Feed)
	pindexes := make(map[string]*PIndex)

	mgr.m.Lock()
	defer mgr.m.Unlock()

	for k, v := range mgr.feeds {
		feeds[k] = v
	}
	for k, v := range mgr.pindexes {
		pindexes[k] = v
	}
	return feeds, pindexes
}

func (mgr *Manager) PIndexPath(pindexName string) string {
	return PIndexPath(mgr.dataDir, pindexName)
}

func (mgr *Manager) ParsePIndexPath(pindexPath string) (string, bool) {
	return ParsePIndexPath(mgr.dataDir, pindexPath)
}

func (mgr *Manager) DataDir() string {
	return mgr.dataDir
}
<|endoftext|>


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

// Package rand implements a cryptographically secure
// random number generator.
package rand

import "io"

// Reader is a global, shared instance of a cryptographically
// secure random number generator.
//
// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
// On OpenBSD, Reader uses getentropy(2).
// On other Unix-like systems, Reader reads from /dev/urandom.
// On Windows systems, Reader uses the RtlGenRandom API.
// On Wasm, Reader uses the Web Crypto API.
var Reader io.Reader

// Read is a helper function that calls Reader.Read using io.ReadFull.
// On return, n == len(b) if and only if err == nil.
func Read(b []byte) (n int, err error) {
	return io.ReadFull(Reader, b)
}
<commit_msg>crypto/rand: document additional getrandom/getentropy support in Reader<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package rand implements a cryptographically secure
// random number generator.
package rand

import "io"

// Reader is a global, shared instance of a cryptographically
// secure random number generator.
//
// On Linux, FreeBSD, Dragonfly and Solaris, Reader uses getrandom(2) if
// available, /dev/urandom otherwise.
// On OpenBSD and macOS, Reader uses getentropy(2).
// On other Unix-like systems, Reader reads from /dev/urandom.
// On Windows systems, Reader uses the RtlGenRandom API.
// On Wasm, Reader uses the Web Crypto API.
var Reader io.Reader

// Read is a helper function that calls Reader.Read using io.ReadFull.
// On return, n == len(b) if and only if err == nil.
func Read(b []byte) (n int, err error) {
	return io.ReadFull(Reader, b)
}
<|endoftext|>


<commit_before>// +build !as_performance

// Copyright 2013-2019 Aerospike, 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 aerospike

import (
	"fmt"
	"math"
	"reflect"
	"strings"
	"sync"
	"time"
)

var aerospikeTag = "as"

const (
	aerospikeMetaTag    = "asm"
	aerospikeMetaTagGen = "gen"
	aerospikeMetaTagTTL = "ttl"
)

// This method is copied verbatim from https://golang.org/src/encoding/json/encode.go
// to ensure compatibility with the json package.
func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}

	return false
}

// SetAerospikeTag sets the bin tag to the specified tag.
// This will be useful for when a user wants to use the same tag name for two different concerns.
// For example, one will be able to use the same tag name for both json and aerospike bin name.
func SetAerospikeTag(tag string) {
	aerospikeTag = tag
}

func valueToInterface(f reflect.Value, clusterSupportsFloat bool) interface{} {
	// get to the core value
	for f.Kind() == reflect.Ptr {
		if f.IsNil() {
			return nil
		}
		f = reflect.Indirect(f)
	}

	switch f.Kind() {
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		return IntegerValue(f.Int())
	case reflect.Uint64, reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint16:
		return int64(f.Uint())
	case reflect.Float64, reflect.Float32:
		// support floats through integer encoding if
		// server doesn't support floats
		if clusterSupportsFloat {
			return FloatValue(f.Float())
		}
		return IntegerValue(math.Float64bits(f.Float()))

	case reflect.Struct:
		if f.Type().PkgPath() == "time" && f.Type().Name() == "Time" {
			return f.Interface().(time.Time).UTC().UnixNano()
		}
		return structToMap(f, clusterSupportsFloat)
	case reflect.Bool:
		if f.Bool() {
			return IntegerValue(1)
		}
		return IntegerValue(0)
	case reflect.Map:
		if f.IsNil() {
			return nil
		}

		newMap := make(map[interface{}]interface{}, f.Len())
		for _, mk := range f.MapKeys() {
			newMap[valueToInterface(mk, clusterSupportsFloat)] = valueToInterface(f.MapIndex(mk), clusterSupportsFloat)
		}

		return newMap
	case reflect.Slice, reflect.Array:
		if f.Kind() == reflect.Slice && f.IsNil() {
			return nil
		}
		if f.Kind() == reflect.Slice && reflect.TypeOf(f.Interface()).Elem().Kind() == reflect.Uint8 {
			// handle blobs
			return f.Interface().([]byte)
		}
		// convert to primitives recursively
		newSlice := make([]interface{}, f.Len(), f.Cap())
		for i := 0; i < len(newSlice); i++ {
			newSlice[i] = valueToInterface(f.Index(i), clusterSupportsFloat)
		}
		return newSlice
	case reflect.Interface:
		if f.IsNil() {
			return nullValue
		}
		return f.Interface()
	default:
		return f.Interface()
	}
}

func fieldIsMetadata(f reflect.StructField) bool {
	meta := f.Tag.Get(aerospikeMetaTag)
	return strings.Trim(meta, " ") != ""
}

func fieldIsOmitOnEmpty(f reflect.StructField) bool {
	tag := f.Tag.Get(aerospikeTag)
	return strings.Contains(tag, ",omitempty")
}

func stripOptions(tag string) string {
	i := strings.Index(tag, ",")
	if i < 0 {
		return tag
	}
	return string(tag[:i])
}

func fieldAlias(f reflect.StructField) string {
	alias := strings.Trim(stripOptions(f.Tag.Get(aerospikeTag)), " ")
	if alias != "" {
		// if tag is -, the field should not be persisted
		if alias == "-" {
			return ""
		}
		return alias
	}
	return f.Name
}

func setBinMap(s reflect.Value, clusterSupportsFloat bool, typeOfT reflect.Type, binMap BinMap, index []int) {
	numFields := typeOfT.NumField()
	var fld reflect.StructField

	for i := 0; i < numFields; i++ {
		fld = typeOfT.Field(i)

		fldIndex := append(index, fld.Index...)

		if fld.Anonymous && fld.Type.Kind() == reflect.Struct {
			setBinMap(s, clusterSupportsFloat, fld.Type, binMap, fldIndex)
			continue
		}

		// skip unexported fields
		if fld.PkgPath != "" {
			continue
		}

		if fieldIsMetadata(fld) {
			continue
		}

		// skip transient fields tagged `-`
		alias := fieldAlias(fld)
		if alias == "" {
			continue
		}

		if fieldIsOmitOnEmpty(fld) && isEmptyValue(s.FieldByIndex(fldIndex)) {
			continue
		}

		binValue := valueToInterface(s.FieldByIndex(fldIndex), clusterSupportsFloat)

		if _, ok := binMap[alias]; ok {
			panic(fmt.Sprintf("ambiguous fields with the same name or alias: %s", alias))
		}
		binMap[alias] = binValue
	}
}

func structToMap(s reflect.Value, clusterSupportsFloat bool) BinMap {
	if !s.IsValid() {
		return nil
	}

	var binMap BinMap = make(BinMap, s.NumField())

	setBinMap(s, clusterSupportsFloat, s.Type(), binMap, nil)

	return binMap
}

func marshal(v interface{}, clusterSupportsFloat bool) BinMap {
	s := indirect(reflect.ValueOf(v))
	return structToMap(s, clusterSupportsFloat)
}

type syncMap struct {
	objectMappings map[reflect.Type]map[string][]int
	objectFields   map[reflect.Type][]string
	objectTTLs     map[reflect.Type][][]int
	objectGen      map[reflect.Type][][]int
	mutex          sync.RWMutex
}

func (sm *syncMap) setMapping(objType reflect.Type, mapping map[string][]int, fields []string, ttl, gen [][]int) {
	sm.mutex.Lock()
	sm.objectMappings[objType] = mapping
	sm.objectFields[objType] = fields
	sm.objectTTLs[objType] = ttl
	sm.objectGen[objType] = gen
	sm.mutex.Unlock()
}

func indirect(obj reflect.Value) reflect.Value {
	for obj.Kind() == reflect.Ptr {
		if obj.IsNil() {
			return obj
		}
		obj = obj.Elem()
	}
	return obj
}

func indirectT(objType reflect.Type) reflect.Type {
	for objType.Kind() == reflect.Ptr {
		objType = objType.Elem()
	}
	return objType
}

func (sm *syncMap) mappingExists(objType reflect.Type) (map[string][]int, bool) {
	sm.mutex.RLock()
	mapping, exists := sm.objectMappings[objType]
	sm.mutex.RUnlock()
	return mapping, exists
}

func (sm *syncMap) getMapping(objType reflect.Type) map[string][]int {
	objType = indirectT(objType)
	mapping, exists := sm.mappingExists(objType)
	if !exists {
		cacheObjectTags(objType)
		mapping, _ = sm.mappingExists(objType)
	}

	return mapping
}

func (sm *syncMap) getMetaMappings(objType reflect.Type) (ttl, gen [][]int) {
	objType = indirectT(objType)
	if _, exists := sm.mappingExists(objType); !exists {
		cacheObjectTags(objType)
	}

	sm.mutex.RLock()
	ttl = sm.objectTTLs[objType]
	gen = sm.objectGen[objType]
	sm.mutex.RUnlock()
	return ttl, gen
}

func (sm *syncMap) fieldsExists(objType reflect.Type) ([]string, bool) {
	sm.mutex.RLock()
	mapping, exists := sm.objectFields[objType]
	sm.mutex.RUnlock()
	return mapping, exists
}

func (sm *syncMap) getFields(objType reflect.Type) []string {
	objType = indirectT(objType)
	fields, exists := sm.fieldsExists(objType)
	if !exists {
		cacheObjectTags(objType)
		fields, _ = sm.fieldsExists(objType)
	}

	return fields
}

var objectMappings = &syncMap{
	objectMappings: map[reflect.Type]map[string][]int{},
	objectFields:   map[reflect.Type][]string{},
	objectTTLs:     map[reflect.Type][][]int{},
	objectGen:      map[reflect.Type][][]int{},
}

func fillMapping(objType reflect.Type, mapping map[string][]int, fields []string, ttl, gen [][]int, index []int) ([]string, [][]int, [][]int) {
	numFields := objType.NumField()
	for i := 0; i < numFields; i++ {
		f := objType.Field(i)
		fIndex := append(index, f.Index...)
		if f.Anonymous && f.Type.Kind() == reflect.Struct {
			fields, ttl, gen = fillMapping(f.Type, mapping, fields, ttl, gen, fIndex)
			continue
		}

		// skip unexported fields
		if f.PkgPath != "" {
			continue
		}

		tag := strings.Trim(stripOptions(f.Tag.Get(aerospikeTag)), " ")
		tagM := strings.Trim(f.Tag.Get(aerospikeMetaTag), " ")

		if tag != "" && tagM != "" {
			panic(fmt.Sprintf("Cannot accept both data and metadata tags on the same attribute on struct: %s.%s", objType.Name(), f.Name))
		}

		if tag != "-" && tagM == "" {
			if tag == "" {
				tag = f.Name
			}
			if _, ok := mapping[tag]; ok {
				panic(fmt.Sprintf("ambiguous fields with the same name or alias: %s", tag))
			}
			mapping[tag] = fIndex
			fields = append(fields, tag)
		}

		if tagM == aerospikeMetaTagTTL {
			ttl = append(ttl, fIndex)
		} else if tagM == aerospikeMetaTagGen {
			gen = append(gen, fIndex)
		} else if tagM != "" {
			panic(fmt.Sprintf("Invalid metadata tag `%s` on struct attribute: %s.%s", tagM, objType.Name(), f.Name))
		}
	}
	return fields, ttl, gen
}

func cacheObjectTags(objType reflect.Type) {
	mapping := map[string][]int{}
	fields, ttl, gen := fillMapping(objType, mapping, []string{}, [][]int{}, [][]int{}, nil)
	objectMappings.setMapping(objType, mapping, fields, ttl, gen)
}
<commit_msg>Optimize the code a little<commit_after>// +build !as_performance

// Copyright 2013-2019 Aerospike, 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 aerospike

import (
	"fmt"
	"math"
	"reflect"
	"strings"
	"sync"
	"time"
)

var aerospikeTag = "as"

const (
	aerospikeMetaTag    = "asm"
	aerospikeMetaTagGen = "gen"
	aerospikeMetaTagTTL = "ttl"
)

// This method is copied verbatim from https://golang.org/src/encoding/json/encode.go
// to ensure compatibility with the json package.
func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}

	return false
}

// SetAerospikeTag sets the bin tag to the specified tag.
// This will be useful for when a user wants to use the same tag name for two different concerns.
// For example, one will be able to use the same tag name for both json and aerospike bin name.
func SetAerospikeTag(tag string) {
	aerospikeTag = tag
}

func valueToInterface(f reflect.Value, clusterSupportsFloat bool) interface{} {
	// get to the core value
	for f.Kind() == reflect.Ptr {
		if f.IsNil() {
			return nil
		}
		f = reflect.Indirect(f)
	}

	switch f.Kind() {
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		return IntegerValue(f.Int())
	case reflect.Uint64, reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint16:
		return int64(f.Uint())
	case reflect.Float64, reflect.Float32:
		// support floats through integer encoding if
		// server doesn't support floats
		if clusterSupportsFloat {
			return FloatValue(f.Float())
		}
		return IntegerValue(math.Float64bits(f.Float()))

	case reflect.Struct:
		if f.Type().PkgPath() == "time" && f.Type().Name() == "Time" {
			return f.Interface().(time.Time).UTC().UnixNano()
		}
		return structToMap(f, clusterSupportsFloat)
	case reflect.Bool:
		if f.Bool() {
			return IntegerValue(1)
		}
		return IntegerValue(0)
	case reflect.Map:
		if f.IsNil() {
			return nil
		}

		newMap := make(map[interface{}]interface{}, f.Len())
		for _, mk := range f.MapKeys() {
			newMap[valueToInterface(mk, clusterSupportsFloat)] = valueToInterface(f.MapIndex(mk), clusterSupportsFloat)
		}

		return newMap
	case reflect.Slice, reflect.Array:
		if f.Kind() == reflect.Slice && f.IsNil() {
			return nil
		}
		if f.Kind() == reflect.Slice && reflect.TypeOf(f.Interface()).Elem().Kind() == reflect.Uint8 {
			// handle blobs
			return f.Interface().([]byte)
		}
		// convert to primitives recursively
		newSlice := make([]interface{}, f.Len(), f.Cap())
		for i := 0; i < len(newSlice); i++ {
			newSlice[i] = valueToInterface(f.Index(i), clusterSupportsFloat)
		}
		return newSlice
	case reflect.Interface:
		if f.IsNil() {
			return nullValue
		}
		return f.Interface()
	default:
		return f.Interface()
	}
}

func fieldIsMetadata(f reflect.StructField) bool {
	meta := f.Tag.Get(aerospikeMetaTag)
	return strings.Trim(meta, " ") != ""
}

func fieldIsOmitOnEmpty(f reflect.StructField) bool {
	tag := f.Tag.Get(aerospikeTag)
	return strings.Contains(tag, ",omitempty")
}

func stripOptions(tag string) string {
	i := strings.Index(tag, ",")
	if i < 0 {
		return tag
	}
	return string(tag[:i])
}

func fieldAlias(f reflect.StructField) string {
	alias := strings.Trim(stripOptions(f.Tag.Get(aerospikeTag)), " ")
	if alias != "" {
		// if tag is -, the field should not be persisted
		if alias == "-" {
			return ""
		}
		return alias
	}
	return f.Name
}

func setBinMap(s reflect.Value, clusterSupportsFloat bool, typeOfT reflect.Type, binMap BinMap, index []int) {
	numFields := typeOfT.NumField()
	var fld reflect.StructField
	for i := 0; i < numFields; i++ {
		fld = typeOfT.Field(i)

		fldIndex := append(index, fld.Index...)

		if fld.Anonymous && fld.Type.Kind() == reflect.Struct {
			setBinMap(s, clusterSupportsFloat, fld.Type, binMap, fldIndex)
			continue
		}

		// skip unexported fields
		if fld.PkgPath != "" {
			continue
		}

		if fieldIsMetadata(fld) {
			continue
		}

		// skip transient fields tagged `-`
		alias := fieldAlias(fld)
		if alias == "" {
			continue
		}

		value := s.FieldByIndex(fldIndex)
		if fieldIsOmitOnEmpty(fld) && isEmptyValue(value) {
			continue
		}

		binValue := valueToInterface(value, clusterSupportsFloat)

		if _, ok := binMap[alias]; ok {
			panic(fmt.Sprintf("ambiguous fields with the same name or alias: %s", alias))
		}
		binMap[alias] = binValue
	}
}

func structToMap(s reflect.Value, clusterSupportsFloat bool) BinMap {
	if !s.IsValid() {
		return nil
	}

	var binMap BinMap = make(BinMap, s.NumField())

	setBinMap(s, clusterSupportsFloat, s.Type(), binMap, nil)

	return binMap
}

func marshal(v interface{}, clusterSupportsFloat bool) BinMap {
	s := indirect(reflect.ValueOf(v))
	return structToMap(s, clusterSupportsFloat)
}

type syncMap struct {
	objectMappings map[reflect.Type]map[string][]int
	objectFields   map[reflect.Type][]string
	objectTTLs     map[reflect.Type][][]int
	objectGen      map[reflect.Type][][]int
	mutex          sync.RWMutex
}

func (sm *syncMap) setMapping(objType reflect.Type, mapping map[string][]int, fields []string, ttl, gen [][]int) {
	sm.mutex.Lock()
	sm.objectMappings[objType] = mapping
	sm.objectFields[objType] = fields
	sm.objectTTLs[objType] = ttl
	sm.objectGen[objType] = gen
	sm.mutex.Unlock()
}

func indirect(obj reflect.Value) reflect.Value {
	for obj.Kind() == reflect.Ptr {
		if obj.IsNil() {
			return obj
		}
		obj = obj.Elem()
	}
	return obj
}

func indirectT(objType reflect.Type) reflect.Type {
	for objType.Kind() == reflect.Ptr {
		objType = objType.Elem()
	}
	return objType
}

func (sm *syncMap) mappingExists(objType reflect.Type) (map[string][]int, bool) {
	sm.mutex.RLock()
	mapping, exists := sm.objectMappings[objType]
	sm.mutex.RUnlock()
	return mapping, exists
}

func (sm *syncMap) getMapping(objType reflect.Type) map[string][]int {
	objType = indirectT(objType)
	mapping, exists := sm.mappingExists(objType)
	if !exists {
		cacheObjectTags(objType)
		mapping, _ = sm.mappingExists(objType)
	}

	return mapping
}

func (sm *syncMap) getMetaMappings(objType reflect.Type) (ttl, gen [][]int) {
	objType = indirectT(objType)
	if _, exists := sm.mappingExists(objType); !exists {
		cacheObjectTags(objType)
	}

	sm.mutex.RLock()
	ttl = sm.objectTTLs[objType]
	gen = sm.objectGen[objType]
	sm.mutex.RUnlock()
	return ttl, gen
}

func (sm *syncMap) fieldsExists(objType reflect.Type) ([]string, bool) {
	sm.mutex.RLock()
	mapping, exists := sm.objectFields[objType]
	sm.mutex.RUnlock()
	return mapping, exists
}

func (sm *syncMap) getFields(objType reflect.Type) []string {
	objType = indirectT(objType)
	fields, exists := sm.fieldsExists(objType)
	if !exists {
		cacheObjectTags(objType)
		fields, _ = sm.fieldsExists(objType)
	}

	return fields
}

var objectMappings = &syncMap{
	objectMappings: map[reflect.Type]map[string][]int{},
	objectFields:   map[reflect.Type][]string{},
	objectTTLs:     map[reflect.Type][][]int{},
	objectGen:      map[reflect.Type][][]int{},
}

func fillMapping(objType reflect.Type, mapping map[string][]int, fields []string, ttl, gen [][]int, index []int) ([]string, [][]int, [][]int) {
	numFields := objType.NumField()
	for i := 0; i < numFields; i++ {
		f := objType.Field(i)
		fIndex := append(index, f.Index...)
		if f.Anonymous && f.Type.Kind() == reflect.Struct {
			fields, ttl, gen = fillMapping(f.Type, mapping, fields, ttl, gen, fIndex)
			continue
		}

		// skip unexported fields
		if f.PkgPath != "" {
			continue
		}

		tag := strings.Trim(stripOptions(f.Tag.Get(aerospikeTag)), " ")
		tagM := strings.Trim(f.Tag.Get(aerospikeMetaTag), " ")

		if tag != "" && tagM != "" {
			panic(fmt.Sprintf("Cannot accept both data and metadata tags on the same attribute on struct: %s.%s", objType.Name(), f.Name))
		}

		if tag != "-" && tagM == "" {
			if tag == "" {
				tag = f.Name
			}
			if _, ok := mapping[tag]; ok {
				panic(fmt.Sprintf("ambiguous fields with the same name or alias: %s", tag))
			}
			mapping[tag] = fIndex
			fields = append(fields, tag)
		}

		if tagM == aerospikeMetaTagTTL {
			ttl = append(ttl, fIndex)
		} else if tagM == aerospikeMetaTagGen {
			gen = append(gen, fIndex)
		} else if tagM != "" {
			panic(fmt.Sprintf("Invalid metadata tag `%s` on struct attribute: %s.%s", tagM, objType.Name(), f.Name))
		}
	}
	return fields, ttl, gen
}

func cacheObjectTags(objType reflect.Type) {
	mapping := map[string][]int{}
	fields, ttl, gen := fillMapping(objType, mapping, []string{}, nil, nil, nil)
	objectMappings.setMapping(objType, mapping, fields, ttl, gen)
}
<|endoftext|>


<commit_before>package api2go

import (
	"encoding/json"
	"errors"
	"reflect"
	"strconv"
	"strings"
)

type marshalingContext struct {
	root     map[string]interface{}
	rootName string
}

func makeContext(rootName string) *marshalingContext {
	ctx := &marshalingContext{}
	ctx.rootName = rootName
	ctx.root = map[string]interface{}{}
	ctx.root[rootName] = []interface{}{}
	return ctx
}

// Marshal takes a struct (or slice of structs) and marshals them to a json encodable interface{} value
func Marshal(data interface{}) (interface{}, error) {
	var ctx *marshalingContext

	if reflect.TypeOf(data).Kind() == reflect.Slice {
		// We were passed a slice
		// Using Elem() here to get the slice's element type
		rootName := pluralize(jsonify(reflect.TypeOf(data).Elem().Name()))

		// Panic if empty string, i.e. passed []interface{}
		if rootName == "" {
			panic("You passed a slice of interfaces []interface{}{...} to Marshal. We cannot determine key names from that. Use []YourObjectName{...} instead.")
		}
		ctx = makeContext(rootName)

		// Marshal all elements
		// We iterate using reflections to save copying the slice to a []interface{}
		sliceValue := reflect.ValueOf(data)
		for i := 0; i < sliceValue.Len(); i++ {
			if err := ctx.marshalStruct(sliceValue.Index(i)); err != nil {
				return nil, err
			}
		}
	} else {
		// We were passed a single object
		rootName := pluralize(jsonify(reflect.TypeOf(data).Name()))
		ctx = makeContext(rootName)

		// Marshal the value
		if err := ctx.marshalStruct(reflect.ValueOf(data)); err != nil {
			return nil, err
		}
	}

	return ctx.root, nil
}

// marshalStruct marshals a struct and places it in the context's root
func (ctx *marshalingContext) marshalStruct(val reflect.Value) error {
	result := map[string]interface{}{}
	linksMap := map[string][]interface{}{}

	valType := val.Type()
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		keyName := jsonify(valType.Field(i).Name)

		if field.Kind() == reflect.Slice {
			// A slice indicates nested objects.

			// First, check whether this is a slice of structs which we need to nest
			if field.Type().Elem().Kind() == reflect.Struct {
				ids := []interface{}{}
				for i := 0; i < field.Len(); i++ {
					if idVal := field.Index(i).FieldByName("ID"); idVal.IsValid() {
						idString, err := toID(idVal)
						if err != nil {
							return err
						}
						ids = append(ids, idString)
					} else {
						panic("structs passed to Marshal need to contain ID fields")
					}

					if err := ctx.marshalStruct(field.Index(i)); err != nil {
						return err
					}
				}
				linksMap[keyName] = ids
			} else {
				// Treat slices of non-struct type as lists of IDs
				keyName = strings.TrimSuffix(keyName, "IDs")
				// Don't overwrite any existing links, since they came from nested structs
				if linksMap[keyName] == nil || len(linksMap[keyName]) == 0 {
					ids := []interface{}{}
					for i := 0; i < field.Len(); i++ {
						id, err := toID(field.Index(i))
						if err != nil {
							return err
						}
						ids = append(ids, id)
					}
					linksMap[keyName] = ids
				}
			}

		} else if keyName == "id" {
			// ID needs to be converted to string
			id, err := toID(field)
			if err != nil {
				return err
			}
			result[keyName] = id
		} else {
			result[keyName] = field.Interface()
		}
	}

	if len(linksMap) > 0 {
		result["links"] = linksMap
	}

	ctx.addValue(pluralize(jsonify(valType.Name())), result)
	return nil
}

// addValue adds an object to the context's root
// `name` should be the pluralized and underscorized object type.
func (ctx *marshalingContext) addValue(name string, val map[string]interface{}) {
	if name == ctx.rootName {
		// Root objects are placed directly into the root doc
		// BUG(lucas): If an object links to its own type, linked objects must be placed into the linked map.
		ctx.root[name] = append(ctx.root[name].([]interface{}), val)
	} else {
		// Linked objects are placed in a map under the `linked` key
		var linkedMap map[string][]interface{}
		if ctx.root["linked"] == nil {
			linkedMap = map[string][]interface{}{}
			ctx.root["linked"] = linkedMap
		} else {
			linkedMap = ctx.root["linked"].(map[string][]interface{})
		}
		if s := linkedMap[name]; s != nil {
			// check if already in linked list
			alreadyLinked := false
			for _, linked := range s {
				m := reflect.ValueOf(linked).Interface().(map[string]interface{})
				if val["id"] == m["id"] {
					alreadyLinked = true
				}
			}
			if !alreadyLinked {
				linkedMap[name] = append(s, val)
			}
		} else {
			linkedMap[name] = []interface{}{val}
		}
	}
}

// toID converts a value to a ID string
func toID(v reflect.Value) (string, error) {
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(v.Int(), 10), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(v.Uint(), 10), nil
	case reflect.String:
		return v.String(), nil
	default:
		return "", errors.New("need int or string as type of ID")
	}
}

// MarshalToJSON takes a struct and marshals it to JSONAPI compliant JSON
func MarshalToJSON(val interface{}) ([]byte, error) {
	result, err := Marshal(val)
	if err != nil {
		return nil, err
	}
	return json.Marshal(result)
}
<commit_msg>handle nil values passed to marshal<commit_after>package api2go

import (
	"encoding/json"
	"errors"
	"reflect"
	"strconv"
	"strings"
)

type marshalingContext struct {
	root     map[string]interface{}
	rootName string
}

func makeContext(rootName string) *marshalingContext {
	ctx := &marshalingContext{}
	ctx.rootName = rootName
	ctx.root = map[string]interface{}{}
	ctx.root[rootName] = []interface{}{}
	return ctx
}

// Marshal takes a struct (or slice of structs) and marshals them to a json encodable interface{} value
func Marshal(data interface{}) (interface{}, error) {
	if data == nil {
		panic("nil passed to Marshal")
	}

	var ctx *marshalingContext

	if reflect.TypeOf(data).Kind() == reflect.Slice {
		// We were passed a slice
		// Using Elem() here to get the slice's element type
		rootName := pluralize(jsonify(reflect.TypeOf(data).Elem().Name()))

		// Panic if empty string, i.e. passed []interface{}
		if rootName == "" {
			panic("You passed a slice of interfaces []interface{}{...} to Marshal. We cannot determine key names from that. Use []YourObjectName{...} instead.")
		}
		ctx = makeContext(rootName)

		// Marshal all elements
		// We iterate using reflections to save copying the slice to a []interface{}
		sliceValue := reflect.ValueOf(data)
		for i := 0; i < sliceValue.Len(); i++ {
			if err := ctx.marshalStruct(sliceValue.Index(i)); err != nil {
				return nil, err
			}
		}
	} else {
		// We were passed a single object
		rootName := pluralize(jsonify(reflect.TypeOf(data).Name()))
		ctx = makeContext(rootName)

		// Marshal the value
		if err := ctx.marshalStruct(reflect.ValueOf(data)); err != nil {
			return nil, err
		}
	}

	return ctx.root, nil
}

// marshalStruct marshals a struct and places it in the context's root
func (ctx *marshalingContext) marshalStruct(val reflect.Value) error {
	result := map[string]interface{}{}
	linksMap := map[string][]interface{}{}

	valType := val.Type()
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		keyName := jsonify(valType.Field(i).Name)

		if field.Kind() == reflect.Slice {
			// A slice indicates nested objects.

			// First, check whether this is a slice of structs which we need to nest
			if field.Type().Elem().Kind() == reflect.Struct {
				ids := []interface{}{}
				for i := 0; i < field.Len(); i++ {
					if idVal := field.Index(i).FieldByName("ID"); idVal.IsValid() {
						idString, err := toID(idVal)
						if err != nil {
							return err
						}
						ids = append(ids, idString)
					} else {
						panic("structs passed to Marshal need to contain ID fields")
					}

					if err := ctx.marshalStruct(field.Index(i)); err != nil {
						return err
					}
				}
				linksMap[keyName] = ids
			} else {
				// Treat slices of non-struct type as lists of IDs
				keyName = strings.TrimSuffix(keyName, "IDs")
				// Don't overwrite any existing links, since they came from nested structs
				if linksMap[keyName] == nil || len(linksMap[keyName]) == 0 {
					ids := []interface{}{}
					for i := 0; i < field.Len(); i++ {
						id, err := toID(field.Index(i))
						if err != nil {
							return err
						}
						ids = append(ids, id)
					}
					linksMap[keyName] = ids
				}
			}

		} else if keyName == "id" {
			// ID needs to be converted to string
			id, err := toID(field)
			if err != nil {
				return err
			}
			result[keyName] = id
		} else {
			result[keyName] = field.Interface()
		}
	}

	if len(linksMap) > 0 {
		result["links"] = linksMap
	}

	ctx.addValue(pluralize(jsonify(valType.Name())), result)
	return nil
}

// addValue adds an object to the context's root
// `name` should be the pluralized and underscorized object type.
func (ctx *marshalingContext) addValue(name string, val map[string]interface{}) {
	if name == ctx.rootName {
		// Root objects are placed directly into the root doc
		// BUG(lucas): If an object links to its own type, linked objects must be placed into the linked map.
		ctx.root[name] = append(ctx.root[name].([]interface{}), val)
	} else {
		// Linked objects are placed in a map under the `linked` key
		var linkedMap map[string][]interface{}
		if ctx.root["linked"] == nil {
			linkedMap = map[string][]interface{}{}
			ctx.root["linked"] = linkedMap
		} else {
			linkedMap = ctx.root["linked"].(map[string][]interface{})
		}
		if s := linkedMap[name]; s != nil {
			// check if already in linked list
			alreadyLinked := false
			for _, linked := range s {
				m := reflect.ValueOf(linked).Interface().(map[string]interface{})
				if val["id"] == m["id"] {
					alreadyLinked = true
				}
			}
			if !alreadyLinked {
				linkedMap[name] = append(s, val)
			}
		} else {
			linkedMap[name] = []interface{}{val}
		}
	}
}

// toID converts a value to a ID string
func toID(v reflect.Value) (string, error) {
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(v.Int(), 10), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(v.Uint(), 10), nil
	case reflect.String:
		return v.String(), nil
	default:
		return "", errors.New("need int or string as type of ID")
	}
}

// MarshalToJSON takes a struct and marshals it to JSONAPI compliant JSON
func MarshalToJSON(val interface{}) ([]byte, error) {
	result, err := Marshal(val)
	if err != nil {
		return nil, err
	}
	return json.Marshal(result)
}
<|endoftext|>


<commit_before>package mailbox

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/mail"
	"net/smtp"
	"path/filepath"
	"strings"
)

const boundary = "2a1ef074a9c58c3205dd2611e439701bc68318"

type Credentials struct {
	serverAddress string
	auth          smtp.Auth
}

func NewCredentials(serverAddress string) *Credentials {
	creds := new(Credentials)
	creds.serverAddress = serverAddress
	return creds
}

func (creds *Credentials) SetPasswordAuth(login, password string) {
	sa := strings.Split(creds.serverAddress, ":")
	creds.auth = smtp.PlainAuth("", login, password, sa[0])
}

type Message struct {
	from        mail.Address
	to          []mail.Address
	subject     string
	body        string
	attachments map[string][]byte
}

func (m *Message) From(name, address string) *Message {
	m.from = mail.Address{name, address}
	return m
}

func (m *Message) To(name, address string) *Message {
	m.to = append(m.to, mail.Address{name, address})
	return m
}

func (m *Message) Subject(subject string) *Message {
	m.subject = subject
	return m
}

func (m *Message) Body(body string) *Message {
	m.body = body
	return m
}

func (m *Message) Attach(filePath string) error {
	bs, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}

	_, fileName := filepath.Split(filePath)
	if m.attachments == nil {
		m.attachments = make(map[string][]byte, 3)
	}
	m.attachments[fileName] = bs
	return nil
}

func (m *Message) getToAddresses() []string {
	var addrs []string
	for _, toa := range m.to {
		addrs = append(addrs, toa.Address)
	}
	return addrs
}

func SendMessage(creds *Credentials, m *Message) error {
	switch {
	case creds == nil:
		return fmt.Errorf("Message not sent: Input credentials must not be nil.")
	case m == nil:
		return fmt.Errorf("Message not sent: Input message must not be nil.")
	}

	buf := new(bytes.Buffer)
	buf.WriteString("From: " + m.from.String() + "\n")
	buf.WriteString("To: " + m.to[0].String())
	for i := 1; i < len(m.to); i++ {
		buf.WriteString("," + m.to[i].String())
	}
	buf.WriteString("\nSubject: " + strings.Trim((&mail.Address{m.subject, ""}).String(), " <>") + "\n")
	buf.WriteString("MIME-Version: 1.0\n")

	if m.attachments != nil {
		buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\n")
		buf.WriteString("--" + boundary + "\n")
	}

	buf.WriteString("Content-Type: text/plain; charset=\"utf-8\"\n")
	buf.WriteString("Content-Transfer-Encoding: base64\n")
	buf.WriteString("\n" + base64.StdEncoding.EncodeToString([]byte(m.body)))

	if m.attachments != nil {
		for fn, fbs := range m.attachments {
			buf.WriteString("\n\n--" + boundary + "\n")
			buf.WriteString("Content-Type: application/octet-stream\n")
			buf.WriteString("Content-Transfer-Encoding: base64\n")
			buf.WriteString("Content-Disposition: attachment; filename=\"" + fn + "\"\n\n")

			b := make([]byte, base64.StdEncoding.EncodedLen(len(fbs)))
			base64.StdEncoding.Encode(b, fbs)
			if _, err := buf.Write(b); err != nil {
				return fmt.Errorf("Could not attach %s: %s", fn, err.Error())
			}
			buf.WriteString("\n--" + boundary)
		}

		buf.WriteString("--")
	}

	return smtp.SendMail(creds.serverAddress, creds.auth, m.from.Address, m.getToAddresses(), buf.Bytes())
}
<commit_msg> Changed method name: SetPasswordAuth -> SetPLAINAuth<commit_after>package mailbox

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/mail"
	"net/smtp"
	"path/filepath"
	"strings"
)

const boundary = "2a1ef074a9c58c3205dd2611e439701bc68318"

type Credentials struct {
	serverAddress string
	auth          smtp.Auth
}

func NewCredentials(serverAddress string) *Credentials {
	creds := new(Credentials)
	creds.serverAddress = serverAddress
	return creds
}

func (creds *Credentials) SetPLAINAuth(login, password string) {
	sa := strings.Split(creds.serverAddress, ":")
	creds.auth = smtp.PlainAuth("", login, password, sa[0])
}

type Message struct {
	from        mail.Address
	to          []mail.Address
	subject     string
	body        string
	attachments map[string][]byte
}

func (m *Message) From(name, address string) *Message {
	m.from = mail.Address{name, address}
	return m
}

func (m *Message) To(name, address string) *Message {
	m.to = append(m.to, mail.Address{name, address})
	return m
}

func (m *Message) Subject(subject string) *Message {
	m.subject = subject
	return m
}

func (m *Message) Body(body string) *Message {
	m.body = body
	return m
}

func (m *Message) Attach(filePath string) error {
	bs, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}

	_, fileName := filepath.Split(filePath)
	if m.attachments == nil {
		m.attachments = make(map[string][]byte, 3)
	}
	m.attachments[fileName] = bs
	return nil
}

func (m *Message) getToAddresses() []string {
	var addrs []string
	for _, toa := range m.to {
		addrs = append(addrs, toa.Address)
	}
	return addrs
}

func SendMessage(creds *Credentials, m *Message) error {
	switch {
	case creds == nil:
		return fmt.Errorf("Message not sent: Input credentials must not be nil.")
	case m == nil:
		return fmt.Errorf("Message not sent: Input message must not be nil.")
	}

	buf := new(bytes.Buffer)
	buf.WriteString("From: " + m.from.String() + "\n")
	buf.WriteString("To: " + m.to[0].String())
	for i := 1; i < len(m.to); i++ {
		buf.WriteString("," + m.to[i].String())
	}
	buf.WriteString("\nSubject: " + strings.Trim((&mail.Address{m.subject, ""}).String(), " <>") + "\n")
	buf.WriteString("MIME-Version: 1.0\n")

	if m.attachments != nil {
		buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\n")
		buf.WriteString("--" + boundary + "\n")
	}

	buf.WriteString("Content-Type: text/plain; charset=\"utf-8\"\n")
	buf.WriteString("Content-Transfer-Encoding: base64\n")
	buf.WriteString("\n" + base64.StdEncoding.EncodeToString([]byte(m.body)))

	if m.attachments != nil {
		for fn, fbs := range m.attachments {
			buf.WriteString("\n\n--" + boundary + "\n")
			buf.WriteString("Content-Type: application/octet-stream\n")
			buf.WriteString("Content-Transfer-Encoding: base64\n")
			buf.WriteString("Content-Disposition: attachment; filename=\"" + fn + "\"\n\n")

			b := make([]byte, base64.StdEncoding.EncodedLen(len(fbs)))
			base64.StdEncoding.Encode(b, fbs)
			if _, err := buf.Write(b); err != nil {
				return fmt.Errorf("Could not attach %s: %s", fn, err.Error())
			}
			buf.WriteString("\n--" + boundary)
		}

		buf.WriteString("--")
	}

	return smtp.SendMail(creds.serverAddress, creds.auth, m.from.Address, m.getToAddresses(), buf.Bytes())
}
<|endoftext|>


<commit_before>package mal

import (
	"net/http"
	"log"
	"fmt"
	"encoding/base64"
	"strings"
	"encoding/xml"
	"io"
	"text/template"
	"bytes"
	"net/url"
	"io/ioutil"
)

const (
	BaseMALAddress            = "https://myanimelist.net"
	ApiEndpoint               = BaseMALAddress + "/api"
	VerifyCredentialsEndpoint = ApiEndpoint + "/account/verify_credentials.xml"
)

//For using as a printf format
const (
	UpdateEndpoint = ApiEndpoint + "/animelist/update/%d.xml" //%d - anime database ID

	UserAnimeListEndpoint = BaseMALAddress + "/malappinfo.php?u=%s&status=%s&type=anime" //%s - username %s - status
)

type Client struct {
	Username    string
	credentials string

	ID          string `xml:"user_id"`
	Watching    int    `xml:"user_watching"`
	Completed   int    `xml:"user_completed"`
	OnHold      int    `xml:"user_onhold"`
	Dropped     int    `xml:"user_dropped"`
	PlanToWatch int    `xml:"user_plantowatch"`

	DaysSpentWatching float64 `xml:"user_days_spent_watching"`
}

func NewClient(credentials string) *Client {
	c := &Client{}

	if !verifyCredentials(credentials) {
		return nil
	}

	credentialsBytes, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(credentials, "Basic "))
	if err != nil {
		log.Printf("Decoding credentials failed: %v", err)
	}
	decodedCredentials := strings.Split(string(credentialsBytes), ":")
	c.Username = decodedCredentials[0]
	c.credentials = credentials

	return c
}

func verifyCredentials(credentials string) bool {
	req := newRequest(VerifyCredentialsEndpoint, credentials, http.MethodGet)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Printf("Response error: %v", err)
		return false
	}
	log.Printf("Credentials verification status: %v", resp.Status)

	return resp.StatusCode == 200
}

func newRequest(url, credentials, method string) *http.Request {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		log.Printf("Request creation error: %v", err)
		return nil
	}
	req.Header.Add("Authorization", credentials)
	return req
}

func (c *Client) AnimeList(status myStatus) []*Anime {
	url := fmt.Sprintf(UserAnimeListEndpoint, c.Username, "all") //Anything other than `all` doesn't really work

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Printf("Request error: %v", err)
		return nil
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Printf("List list getting error: %v", err)
	}

	decoder := xml.NewDecoder(resp.Body)
	decoder.Strict = false

	list := make([]*Anime, 0)

	for t, err := decoder.Token(); err != io.EOF; t, err = decoder.Token() {
		if t, ok := t.(xml.StartElement); ok {
			switch t.Name.Local {
			case "myinfo":
				decoder.DecodeElement(&c, &t)
			case "anime":
				anime := new(Anime)
				decoder.DecodeElement(&anime, &t)
				if anime.MyStatus == status || status == All {
					list = append(list, anime)
				}
			}
		}
	}

	return list
}

func (c *Client) Update(entry *Anime) bool {
	buf := &bytes.Buffer{}

	template.Must(
		template.New("animeXML").
			Parse(AnimeXMLTemplate)).
		Execute(buf, entry)

	payload := url.Values{}
	payload.Set("data", buf.String())

	req, err := http.NewRequest(
		http.MethodPost,
		fmt.Sprintf(UpdateEndpoint, entry.ID),
		strings.NewReader(payload.Encode()),
	)

	if err != nil {
		log.Printf("Error creating http request: %v", err)
		return false
	}
	req.Header.Set("Authorization", c.credentials)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Printf("Error getting response for %d - %s update: %v", entry.ID, entry.Title, err)
		return false
	}

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Error reading body: %v", err)
	}
	body := string(bodyBytes)

	if body != "Updated" || resp.StatusCode != 200 {
		log.Printf("Body: %v\nStatus: %s", body, resp.Status)
		return false
	}
	return true
}
<commit_msg>Don't show credentials verification status on successfull authorization<commit_after>package mal

import (
	"net/http"
	"log"
	"fmt"
	"encoding/base64"
	"strings"
	"encoding/xml"
	"io"
	"text/template"
	"bytes"
	"io/ioutil"
	"net/url"
)

const (
	BaseMALAddress            = "https://myanimelist.net"
	ApiEndpoint               = BaseMALAddress + "/api"
	VerifyCredentialsEndpoint = ApiEndpoint + "/account/verify_credentials.xml"
)

//For using as a printf format
const (
	UpdateEndpoint = ApiEndpoint + "/animelist/update/%d.xml" //%d - anime database ID

	UserAnimeListEndpoint = BaseMALAddress + "/malappinfo.php?u=%s&status=%s&type=anime" //%s - username %s - status
)

type Client struct {
	Username    string
	credentials string

	ID          string `xml:"user_id"`
	Watching    int    `xml:"user_watching"`
	Completed   int    `xml:"user_completed"`
	OnHold      int    `xml:"user_onhold"`
	Dropped     int    `xml:"user_dropped"`
	PlanToWatch int    `xml:"user_plantowatch"`

	DaysSpentWatching float64 `xml:"user_days_spent_watching"`
}

func NewClient(credentials string) *Client {
	c := &Client{}

	if !verifyCredentials(credentials) {
		return nil
	}

	credentialsBytes, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(credentials, "Basic "))
	if err != nil {
		log.Printf("Decoding credentials failed: %v", err)
	}
	decodedCredentials := strings.Split(string(credentialsBytes), ":")
	c.Username = decodedCredentials[0]
	c.credentials = credentials

	return c
}

func verifyCredentials(credentials string) bool {
	req := newRequest(VerifyCredentialsEndpoint, credentials, http.MethodGet)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Printf("Response error: %v", err)
		return false
	}

	if resp.StatusCode != 200 {
		log.Printf("Credentials verification status: %v", resp.Status)
	}

	return resp.StatusCode == 200
}

func newRequest(url, credentials, method string) *http.Request {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		log.Printf("Request creation error: %v", err)
		return nil
	}
	req.Header.Add("Authorization", credentials)
	return req
}

func (c *Client) AnimeList(status myStatus) []*Anime {
	url := fmt.Sprintf(UserAnimeListEndpoint, c.Username, "all") //Anything other than `all` doesn't really work

	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Printf("Request error: %v", err)
		return nil
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Printf("List list getting error: %v", err)
	}

	decoder := xml.NewDecoder(resp.Body)
	decoder.Strict = false

	list := make([]*Anime, 0)

	for t, err := decoder.Token(); err != io.EOF; t, err = decoder.Token() {
		if t, ok := t.(xml.StartElement); ok {
			switch t.Name.Local {
			case "myinfo":
				decoder.DecodeElement(&c, &t)
			case "anime":
				anime := new(Anime)
				decoder.DecodeElement(&anime, &t)
				if anime.MyStatus == status || status == All {
					list = append(list, anime)
				}
			}
		}
	}

	return list
}

func (c *Client) Update(entry *Anime) bool {
	buf := &bytes.Buffer{}

	template.Must(
		template.New("animeXML").
			Parse(AnimeXMLTemplate)).
		Execute(buf, entry)

	payload := url.Values{}
	payload.Set("data", buf.String())

	req, err := http.NewRequest(
		http.MethodPost,
		fmt.Sprintf(UpdateEndpoint, entry.ID),
		strings.NewReader(payload.Encode()),
	)

	if err != nil {
		log.Printf("Error creating http request: %v", err)
		return false
	}
	req.Header.Set("Authorization", c.credentials)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Printf("Error getting response for %d - %s update: %v", entry.ID, entry.Title, err)
		return false
	}

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Error reading body: %v", err)
	}
	body := string(bodyBytes)

	if body != "Updated" || resp.StatusCode != 200 {
		log.Printf("Body: %v\nStatus: %s", body, resp.Status)
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/russross/blackfriday"
)

var bind = flag.String("bind", "127.0.0.1:19000", "port to run the server on")

func main() {
	flag.Parse()

	httpdir := http.Dir(".")
	handler := renderer{httpdir, http.FileServer(httpdir)}

	fmt.Println("Serving")
	log.Fatal(http.ListenAndServe(*bind, handler))
}

var outputTemplate = template.Must(template.New("base").Parse(`
<html>
  <head>
    <title>{{ .Path }}</title>
  </head>
  <body>
    {{ .Body }}
  </body>
</html>
`))

type renderer struct {
	d http.Dir
	h http.Handler
}

func (r renderer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if !strings.HasSuffix(req.URL.Path, ".md") {
		r.h.ServeHTTP(rw, req)
		return
	}

	// net/http is already running a path.Clean on the req.URL.Path,
	// so this is not a directory traversal, at least by my testing
	var pathErr *os.PathError
	input, err := ioutil.ReadFile("." + req.URL.Path)
	if errors.As(err, &pathErr) {
		http.Error(rw, http.StatusText(http.StatusNotFound)+": "+req.URL.Path, http.StatusNotFound)
		log.Printf("file not found: %s", err)
		return
	}

	if err != nil {
		http.Error(rw, "Internal Server Error: "+err.Error(), 500)
		log.Printf("Couldn't read path %s: %v (%T)", req.URL.Path, err, err)
		return
	}

	output := blackfriday.MarkdownCommon(input)

	rw.Header().Set("Content-Type", "text/html")

	outputTemplate.Execute(rw, struct {
		Path string
		Body template.HTML
	}{
		Path: req.URL.Path,
		Body: template.HTML(string(output)),
	})

}
<commit_msg>Log listening address<commit_after>package main

import (
	"errors"
	"flag"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/russross/blackfriday"
)

var bind = flag.String("bind", "127.0.0.1:19000", "port to run the server on")

func main() {
	flag.Parse()

	httpdir := http.Dir(".")
	handler := renderer{httpdir, http.FileServer(httpdir)}

	log.Println("Serving on http://" + *bind)
	log.Fatal(http.ListenAndServe(*bind, handler))
}

var outputTemplate = template.Must(template.New("base").Parse(`
<html>
  <head>
    <title>{{ .Path }}</title>
  </head>
  <body>
    {{ .Body }}
  </body>
</html>
`))

type renderer struct {
	d http.Dir
	h http.Handler
}

func (r renderer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if !strings.HasSuffix(req.URL.Path, ".md") {
		r.h.ServeHTTP(rw, req)
		return
	}

	// net/http is already running a path.Clean on the req.URL.Path,
	// so this is not a directory traversal, at least by my testing
	var pathErr *os.PathError
	input, err := ioutil.ReadFile("." + req.URL.Path)
	if errors.As(err, &pathErr) {
		http.Error(rw, http.StatusText(http.StatusNotFound)+": "+req.URL.Path, http.StatusNotFound)
		log.Printf("file not found: %s", err)
		return
	}

	if err != nil {
		http.Error(rw, "Internal Server Error: "+err.Error(), 500)
		log.Printf("Couldn't read path %s: %v (%T)", req.URL.Path, err, err)
		return
	}

	output := blackfriday.MarkdownCommon(input)

	rw.Header().Set("Content-Type", "text/html")

	outputTemplate.Execute(rw, struct {
		Path string
		Body template.HTML
	}{
		Path: req.URL.Path,
		Body: template.HTML(string(output)),
	})

}
<|endoftext|>


<commit_before>package gock

import "net/http"

// MatchersHeader exposes an slice of HTTP header specific mock matchers.
var MatchersHeader = []MatchFunc{
	MatchMethod,
	MatchHost,
	MatchPath,
	MatchHeaders,
}

// MatcherBody exposes an slice of HTTP body specific built-in mock matchers.
var MatchersBody = []MatchFunc{
	MatchBody,
}

// Matchers stores all the built-in mock matchers.
var Matchers = append(MatchersHeader, MatchersBody...)

// DefaultMatcher stores the default Matcher instance used to match mocks.
var DefaultMatcher = NewMatcher()

// MatchFunc represents the required function
// interface implemented by matchers.
type MatchFunc func(*http.Request, *Request) (bool, error)

// Matcher represents the required interface implemented by mock matchers.
type Matcher interface {
	// Get returns a slice of registered function matchers.
	Get() []MatchFunc

	// Add adds a new matcher function.
	Add(MatchFunc)

	// Set sets the matchers functions stack.
	Set([]MatchFunc)

	// Flush flushes the current matchers function stack.
	Flush()

	// Match matches the given http.Request with a mock Request.
	Match(*http.Request, *Request) (bool, error)
}

// MockMatcher implements a mock matcher
type MockMatcher struct {
	Matchers []MatchFunc
}

// NewMatcher creates a new mock matcher
// using the default matcher functions.
func NewMatcher() *MockMatcher {
	return &MockMatcher{Matchers: Matchers}
}

// NewBasicMatcher creates a new matcher with header only mock matchers.
func NewBasicMatcher() *MockMatcher {
	return &MockMatcher{Matchers: MatchersHeader}
}

// NewEmptyMatcher creates a new empty matcher with out default amtchers.
func NewEmptyMatcher() *MockMatcher {
	return &MockMatcher{Matchers: []MatchFunc{}}
}

// Get returns a slice of registered function matchers.
func (m *MockMatcher) Get() []MatchFunc {
	return m.Matchers
}

// Add adds a new function matcher.
func (m *MockMatcher) Add(fn MatchFunc) {
	m.Matchers = append(m.Matchers, fn)
}

// Set sets a new stack of matchers functions.
func (m *MockMatcher) Set(stack []MatchFunc) {
	m.Matchers = stack
}

// Flush flushes the current matcher
func (m *MockMatcher) Flush() {
	m.Matchers = []MatchFunc{}
}

// Match matches the given http.Request with a mock request
// returning true in case that the request matches, otherwise false.
func (m *MockMatcher) Match(req *http.Request, ereq *Request) (bool, error) {
	for _, matcher := range m.Matchers {
		matches, err := matcher(req, ereq)
		if err != nil {
			return false, err
		}
		if !matches {
			return false, nil
		}
	}
	return true, nil
}

// MatchMock is a helper function that matches the given http.Request
// in the list of registered mocks, returning it if matches or error if it fails.
func MatchMock(req *http.Request) (Mock, error) {
	for _, mock := range GetAll() {
		matches, err := mock.Match(req)
		if err != nil {
			return nil, err
		}
		if matches {
			return mock, nil
		}
	}
	return nil, nil
}
<commit_msg>fix(docs): comment<commit_after>package gock

import "net/http"

// MatchersHeader exposes an slice of HTTP header specific mock matchers.
var MatchersHeader = []MatchFunc{
	MatchMethod,
	MatchHost,
	MatchPath,
	MatchHeaders,
}

// MatchersBody exposes an slice of HTTP body specific built-in mock matchers.
var MatchersBody = []MatchFunc{
	MatchBody,
}

// Matchers stores all the built-in mock matchers.
var Matchers = append(MatchersHeader, MatchersBody...)

// DefaultMatcher stores the default Matcher instance used to match mocks.
var DefaultMatcher = NewMatcher()

// MatchFunc represents the required function
// interface implemented by matchers.
type MatchFunc func(*http.Request, *Request) (bool, error)

// Matcher represents the required interface implemented by mock matchers.
type Matcher interface {
	// Get returns a slice of registered function matchers.
	Get() []MatchFunc

	// Add adds a new matcher function.
	Add(MatchFunc)

	// Set sets the matchers functions stack.
	Set([]MatchFunc)

	// Flush flushes the current matchers function stack.
	Flush()

	// Match matches the given http.Request with a mock Request.
	Match(*http.Request, *Request) (bool, error)
}

// MockMatcher implements a mock matcher
type MockMatcher struct {
	Matchers []MatchFunc
}

// NewMatcher creates a new mock matcher
// using the default matcher functions.
func NewMatcher() *MockMatcher {
	return &MockMatcher{Matchers: Matchers}
}

// NewBasicMatcher creates a new matcher with header only mock matchers.
func NewBasicMatcher() *MockMatcher {
	return &MockMatcher{Matchers: MatchersHeader}
}

// NewEmptyMatcher creates a new empty matcher with out default amtchers.
func NewEmptyMatcher() *MockMatcher {
	return &MockMatcher{Matchers: []MatchFunc{}}
}

// Get returns a slice of registered function matchers.
func (m *MockMatcher) Get() []MatchFunc {
	return m.Matchers
}

// Add adds a new function matcher.
func (m *MockMatcher) Add(fn MatchFunc) {
	m.Matchers = append(m.Matchers, fn)
}

// Set sets a new stack of matchers functions.
func (m *MockMatcher) Set(stack []MatchFunc) {
	m.Matchers = stack
}

// Flush flushes the current matcher
func (m *MockMatcher) Flush() {
	m.Matchers = []MatchFunc{}
}

// Match matches the given http.Request with a mock request
// returning true in case that the request matches, otherwise false.
func (m *MockMatcher) Match(req *http.Request, ereq *Request) (bool, error) {
	for _, matcher := range m.Matchers {
		matches, err := matcher(req, ereq)
		if err != nil {
			return false, err
		}
		if !matches {
			return false, nil
		}
	}
	return true, nil
}

// MatchMock is a helper function that matches the given http.Request
// in the list of registered mocks, returning it if matches or error if it fails.
func MatchMock(req *http.Request) (Mock, error) {
	for _, mock := range GetAll() {
		matches, err := mock.Match(req)
		if err != nil {
			return nil, err
		}
		if matches {
			return mock, nil
		}
	}
	return nil, nil
}
<|endoftext|>


<commit_before>//  This Source Code Form is subject to the terms of the Mozilla Public
//  License, v. 2.0. If a copy of the MPL was not distributed with this
//  file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

// A Vector -> Vector transformation
type Transform interface {
	Transform(Vector) Vector
}

// A translation transform
type Translation struct {
	By Vector
}

// Translates a Vector by t.By.
func (t Translation) Transform(v Vector) Vector {

	return t.By.Plus(v)
}
<commit_msg>Add dacart.AxisAngleRotation<commit_after>//  This Source Code Form is subject to the terms of the Mozilla Public
//  License, v. 2.0. If a copy of the MPL was not distributed with this
//  file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"math"
)

// A Vector -> Vector transformation
type Transform interface {
	Transform(Vector) Vector
}

// A translation transform
type Translation struct {
	By Vector
}

// Translates a Vector by t.By.
func (t Translation) Transform(v Vector) Vector {

	return t.By.Plus(v)
}

// A rotation transform
type AxisAngleRotation struct {
	Axis  Vector
	Angle float64
}

// Rotates a vector by aar.Angle around an axis parallel to aar.Axis going
// through the origin point
func (aar AxisAngleRotation) Transform(v Vector) (vRot Vector) {

	cos, sin := math.Cos(aar.Angle), math.Sin(aar.Angle)
	unit := aar.Axis.Unit()

	vRot = NewZeroVector()

	vRot = vRot.Plus(v.Scale(cos))
	vRot = vRot.Plus(unit.Cross(v).Scale(sin))
	vRot = vRot.Plus(unit.Scale(unit.Dot(v) * (1 - cos)))

	return vRot
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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
//
//     https://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 badger providers a Badger-backed implementation of kv.Txn.
package badger

import (
	"fmt"
	"io"
	"log"

	"github.com/dgraph-io/badger"
	"github.com/google/note-maps/kv"
)

var (
	entitySequenceKey = []byte{1}
)

// DB holds some kv-specific state in addition to mixing in a badger.DB.
type DB struct {
	*badger.DB
	seq *badger.Sequence
}

// DefaultOptions returns a recommended default Options value for a database
// rooted at dir.
func DefaultOptions(dir string) badger.Options {
	return badger.DefaultOptions(dir)
}

// Open creates a new DB with the given options.
func Open(opt badger.Options) (*DB, error) {
	bdb, err := badger.Open(opt)
	if err != nil {
		return nil, err
	}

	seq, err := bdb.GetSequence(entitySequenceKey, 128)
	if err != nil {
		bdb.Close()
		return nil, err
	}

	return &DB{bdb, seq}, nil
}

func (db *DB) Dump(w io.Writer) {
	txn := db.NewTransaction(false)
	defer txn.Discard()
	opts := badger.DefaultIteratorOptions
	iter := txn.NewIterator(opts)
	defer iter.Close()
	count := 0
	for iter.Seek([]byte{0}); iter.Valid(); iter.Next() {
		item := iter.Item()
		key := item.Key()
		value, err := item.ValueCopy(nil)
		if err != nil {
			fmt.Fprintf(w, "%x\t%v", key, err)
			break
		}
		fmt.Fprintf(w, "%x\t%x\n", key, value)
		count++
	}
	fmt.Fprintf(w, "%v keys\n", count)
}

// Close releases unallocated Entity values and closes the database.
func (db *DB) Close() error {
	if db == nil {
		return nil
	}
	if db.seq != nil {
		db.seq.Release()
	}
	return db.DB.Close()
}

// NewTxn creates a new kv.Txn.
func (db *DB) NewTxn(update bool) kv.TxnCommitDiscarder {
	btxn := db.DB.NewTransaction(update)
	return txn{db: db, tx: btxn}
}

type txn struct {
	db *DB
	tx *badger.Txn
}

func (s txn) Alloc() (kv.Entity, error) {
	u64, err := s.db.seq.Next()
	if u64 == 0 {
		u64, err = s.db.seq.Next()
		if u64 == 0 {
			return 0, fmt.Errorf("Alloc returned zero twice in a row")
		}
	}
	return kv.Entity(u64), err
}

func (s txn) Set(key, value []byte) error { return s.tx.Set(key, value) }

func (s txn) Get(key []byte, f func([]byte) error) error {
	item, err := s.tx.Get(key)
	if err == badger.ErrKeyNotFound {
		return f(nil)
	} else if err != nil {
		return err
	} else {
		return item.Value(f)
	}
}

func (s txn) PrefixIterator(prefix []byte) kv.Iterator {
	opts := badger.DefaultIteratorOptions
	opts.Prefix = prefix
	return iterator{
		s.tx.NewIterator(opts),
		prefix,
	}
}

func (s txn) Commit() error {
	if err := s.tx.Commit(); err != nil {
		return err
	}
	if err := s.db.Sync(); err != nil {
		// An error from Sync is important, but it does not indicate that the
		// commit failed.
		log.Println("txn.Commit: db.Sync:", err)
	}
	return nil
}

func (s txn) Discard() {
	s.tx.Discard()
}

type iterator struct {
	*badger.Iterator
	prefix []byte
}

func (i iterator) Seek(key []byte) { i.Iterator.Seek(append(i.prefix, key...)) }

func (i iterator) Key() []byte { return i.Item().Key()[len(i.prefix):] }

func (i iterator) Value(f func([]byte) error) error { return i.Item().Value(f) }

func (i iterator) Discard() { i.Close() }
<commit_msg>Work around BadgerDB issue with prefix iterators<commit_after>// Copyright 2019 Google LLC
//
// 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
//
//     https://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 badger providers a Badger-backed implementation of kv.Txn.
package badger

import (
	"bytes"
	"fmt"
	"io"
	"log"

	"github.com/dgraph-io/badger"
	"github.com/google/note-maps/kv"
)

var (
	entitySequenceKey = []byte{1}
)

// DB holds some kv-specific state in addition to mixing in a badger.DB.
type DB struct {
	*badger.DB
	seq *badger.Sequence
}

// DefaultOptions returns a recommended default Options value for a database
// rooted at dir.
func DefaultOptions(dir string) badger.Options {
	return badger.DefaultOptions(dir)
}

// Open creates a new DB with the given options.
func Open(opt badger.Options) (*DB, error) {
	bdb, err := badger.Open(opt)
	if err != nil {
		return nil, err
	}

	seq, err := bdb.GetSequence(entitySequenceKey, 128)
	if err != nil {
		bdb.Close()
		return nil, err
	}

	return &DB{bdb, seq}, nil
}

func (db *DB) Dump(w io.Writer) {
	txn := db.NewTransaction(false)
	defer txn.Discard()
	opts := badger.DefaultIteratorOptions
	iter := txn.NewIterator(opts)
	defer iter.Close()
	count := 0
	for iter.Seek([]byte{0}); iter.Valid(); iter.Next() {
		item := iter.Item()
		key := item.Key()
		value, err := item.ValueCopy(nil)
		if err != nil {
			fmt.Fprintf(w, "%x\t%v", key, err)
			break
		}
		fmt.Fprintf(w, "%x\t%x\n", key, value)
		count++
	}
	fmt.Fprintf(w, "%v keys\n", count)
}

// Close releases unallocated Entity values and closes the database.
func (db *DB) Close() error {
	if db == nil {
		return nil
	}
	if db.seq != nil {
		db.seq.Release()
	}
	return db.DB.Close()
}

// NewTxn creates a new kv.Txn.
func (db *DB) NewTxn(update bool) kv.TxnCommitDiscarder {
	btxn := db.DB.NewTransaction(update)
	return txn{db: db, tx: btxn}
}

type txn struct {
	db *DB
	tx *badger.Txn
}

func (s txn) Alloc() (kv.Entity, error) {
	u64, err := s.db.seq.Next()
	if u64 == 0 {
		u64, err = s.db.seq.Next()
		if u64 == 0 {
			return 0, fmt.Errorf("Alloc returned zero twice in a row")
		}
	}
	return kv.Entity(u64), err
}

func (s txn) Set(key, value []byte) error { return s.tx.Set(key, value) }

func (s txn) Get(key []byte, f func([]byte) error) error {
	item, err := s.tx.Get(key)
	if err == badger.ErrKeyNotFound {
		return f(nil)
	} else if err != nil {
		return err
	} else {
		return item.Value(f)
	}
}

func (s txn) PrefixIterator(prefix []byte) kv.Iterator {
	opts := badger.DefaultIteratorOptions
	// Work around https://github.com/dgraph-io/badger/issues/992 by *not*
	// setting opts.Prefix = prefix. We will do our own prefix logic in this
	// module.
	return iterator{
		s.tx.NewIterator(opts),
		prefix,
	}
}

func (s txn) Commit() error {
	if err := s.tx.Commit(); err != nil {
		return err
	}
	if err := s.db.Sync(); err != nil {
		// An error from Sync is important, but it does not indicate that the
		// commit failed.
		log.Println("txn.Commit: db.Sync:", err)
	}
	return nil
}

func (s txn) Discard() {
	s.tx.Discard()
}

type iterator struct {
	*badger.Iterator
	prefix []byte
}

func (i iterator) Seek(key []byte) { i.Iterator.Seek(append(i.prefix, key...)) }

func (i iterator) Key() []byte { return i.Item().Key()[len(i.prefix):] }

func (i iterator) Valid() bool { return i.Iterator.Valid() && bytes.HasPrefix(i.Item().Key(), i.prefix) }

func (i iterator) Value(f func([]byte) error) error { return i.Item().Value(f) }

func (i iterator) Discard() { i.Close() }
<|endoftext|>