<commit_before>package vfs

import (
	"bytes"
	"image"
	"io"
	"io/ioutil"
	"time"

	// Packages image/... are not used explicitly in the code below,
	// but are imported for its initialization side-effect
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"

	// Same for image/webp
	_ "golang.org/x/image/webp"

	"github.com/cozy/goexif2/exif"
	"github.com/dhowden/tag"
)

// MetadataExtractorVersion is the version number of the metadata extractor.
// It will be used later to know which files can be re-examined to get more
// metadata when the extractor is improved.
const MetadataExtractorVersion = 2

// Metadata is a list of metadata specific to each mimetype:
// id3 for music, exif for jpegs, etc.
type Metadata map[string]interface{}

// NewMetadata returns a new metadata object, with the version field set
func NewMetadata() Metadata {
	m := Metadata{}
	m["extractor_version"] = MetadataExtractorVersion
	return m
}

// MetaExtractor is an interface for extracting metadata from a file
type MetaExtractor interface {
	io.WriteCloser
	Abort(error)
	Result() Metadata
}

// NewMetaExtractor returns an extractor for metadata if the mime type has one,
// or null else
func NewMetaExtractor(doc *FileDoc) *MetaExtractor {
	var e MetaExtractor
	switch doc.Mime {
	case "image/jpeg":
		e = NewExifExtractor()
	case "image/png", "image/gif":
		e = NewImageExtractor()
	case "audio/mp3", "audio/mpeg", "audio/ogg", "audio/x-m4a", "audio/flac":
		e = NewAudioExtractor()
	}
	if e != nil {
		return &e
	}
	return nil
}

// ImageExtractor is used to extract width/height from images
type ImageExtractor struct {
	w  *io.PipeWriter
	r  *io.PipeReader
	ch chan interface{}
}

// NewImageExtractor returns an extractor for images
func NewImageExtractor() *ImageExtractor {
	e := &ImageExtractor{}
	e.r, e.w = io.Pipe()
	e.ch = make(chan interface{})
	go e.Start()
	return e
}

// Start is used in a goroutine to start the metadata extraction
func (e *ImageExtractor) Start() {
	cfg, _, err := image.DecodeConfig(e.r)
	e.r.Close()
	if err != nil {
		e.ch <- err
	} else {
		e.ch <- cfg
	}
}

// Write is called to push some bytes to the extractor
func (e *ImageExtractor) Write(p []byte) (n int, err error) {
	return e.w.Write(p)
}

// Close is called when all the bytes has been pushed, to finalize the extraction
func (e *ImageExtractor) Close() error {
	err := e.w.Close()
	if err != nil {
		<-e.ch
	}
	return err
}

// Abort is called when the extractor can be discarded
func (e *ImageExtractor) Abort(err error) {
	e.w.CloseWithError(err)
	<-e.ch
}

// Result is called to get the extracted metadata
func (e *ImageExtractor) Result() Metadata {
	m := NewMetadata()
	m["datetime"] = time.Now()
	cfg := <-e.ch
	switch cfg := cfg.(type) {
	case image.Config:
		m["width"] = cfg.Width
		m["height"] = cfg.Height
	}
	return m
}

// ExifExtractor is used to extract EXIF metadata from jpegs
type ExifExtractor struct {
	w  *io.PipeWriter
	r  *io.PipeReader
	im *ImageExtractor
	ch chan interface{}
}

// NewExifExtractor returns an extractor for EXIF metadata
func NewExifExtractor() *ExifExtractor {
	e := &ExifExtractor{}
	e.im = NewImageExtractor()
	e.r, e.w = io.Pipe()
	e.ch = make(chan interface{})
	go e.Start()
	return e
}

// Start is used in a goroutine to start the metadata extraction
func (e *ExifExtractor) Start() {
	x, err := exif.Decode(e.r)
	e.r.Close()
	if err != nil {
		e.ch <- err
	} else {
		e.ch <- x
	}
}

// Write is called to push some bytes to the extractor
func (e *ExifExtractor) Write(p []byte) (n int, err error) {
	e.im.Write(p)
	return e.w.Write(p)
}

// Close is called when all the bytes has been pushed, to finalize the extraction
func (e *ExifExtractor) Close() error {
	e.im.Close()
	return e.w.Close()
}

// Abort is called when the extractor can be discarded
func (e *ExifExtractor) Abort(err error) {
	e.im.Abort(err)
	e.w.CloseWithError(err)
	<-e.ch
}

// Result is called to get the extracted metadata
func (e *ExifExtractor) Result() Metadata {
	m := e.im.Result()
	x := <-e.ch
	switch x := x.(type) {
	case *exif.Exif:
		if dt, err := x.DateTime(); err == nil {
			m["datetime"] = dt
		}
		if flash, err := x.Flash(); err == nil {
			m["flash"] = flash
		}
		if lat, long, err := x.LatLong(); err == nil {
			m["gps"] = map[string]float64{
				"lat":  lat,
				"long": long,
			}
		}
		if o, err := x.Get("Orientation"); err == nil {
			if orientation, err := o.Int(0); err == nil {
				m["orientation"] = orientation
				if orientation > 4 {
					m["width"], m["height"] = m["height"], m["width"]
				}
			}
		}
	}
	return m
}

// AudioExtractor is used to extract album/artist/etc. from audio
type AudioExtractor struct {
	w  *io.PipeWriter
	r  *io.PipeReader
	ch chan interface{}
}

// NewAudioExtractor returns an extractor for audio
func NewAudioExtractor() *AudioExtractor {
	e := &AudioExtractor{}
	e.r, e.w = io.Pipe()
	e.ch = make(chan interface{})
	go e.Start()
	return e
}

// Start is used in a goroutine to start the metadata extraction
func (e *AudioExtractor) Start() {
	buf, err := ioutil.ReadAll(e.r)
	if err != nil {
		e.ch <- err
		return
	}
	tags, err := tag.ReadFrom(bytes.NewReader(buf))
	e.r.Close()
	if err != nil {
		e.ch <- err
	} else {
		e.ch <- tags
	}
}

// Write is called to push some bytes to the extractor
func (e *AudioExtractor) Write(p []byte) (n int, err error) {
	return e.w.Write(p)
}

// Close is called when all the bytes has been pushed, to finalize the extraction
func (e *AudioExtractor) Close() error {
	return e.w.Close()
}

// Abort is called when the extractor can be discarded
func (e *AudioExtractor) Abort(err error) {
	e.w.CloseWithError(err)
	<-e.ch
}

// Result is called to get the extracted metadata
func (e *AudioExtractor) Result() Metadata {
	m := NewMetadata()
	tags := <-e.ch
	switch tags := tags.(type) {
	case tag.Metadata:
		if album := tags.Album(); album != "" {
			m["album"] = album
		}
		if artist := tags.Artist(); artist != "" {
			m["artist"] = artist
		}
		if composer := tags.Composer(); composer != "" {
			m["composer"] = composer
		}
		if genre := tags.Genre(); genre != "" {
			m["genre"] = genre
		}
		if title := tags.Title(); title != "" {
			m["title"] = title
		}
		if year := tags.Year(); year != 0 {
			m["year"] = year
		}
		if track, _ := tags.Track(); track != 0 {
			m["track"] = track
		}
	}
	return m
}
<commit_msg>Add exif parsing for heic images<commit_after>package vfs

import (
	"bytes"
	"image"
	"io"
	"io/ioutil"
	"time"

	// Packages image/... are not used explicitly in the code below,
	// but are imported for its initialization side-effect
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"

	// Same for image/webp
	_ "golang.org/x/image/webp"

	"github.com/cozy/goexif2/exif"
	"github.com/dhowden/tag"
)

// MetadataExtractorVersion is the version number of the metadata extractor.
// It will be used later to know which files can be re-examined to get more
// metadata when the extractor is improved.
const MetadataExtractorVersion = 2

// Metadata is a list of metadata specific to each mimetype:
// id3 for music, exif for jpegs, etc.
type Metadata map[string]interface{}

// NewMetadata returns a new metadata object, with the version field set
func NewMetadata() Metadata {
	m := Metadata{}
	m["extractor_version"] = MetadataExtractorVersion
	return m
}

// MetaExtractor is an interface for extracting metadata from a file
type MetaExtractor interface {
	io.WriteCloser
	Abort(error)
	Result() Metadata
}

// NewMetaExtractor returns an extractor for metadata if the mime type has one,
// or null else
func NewMetaExtractor(doc *FileDoc) *MetaExtractor {
	var e MetaExtractor
	switch doc.Mime {
	case "image/jpeg", "image/heic", "image/heif":
		e = NewExifExtractor()
	case "image/png", "image/gif":
		e = NewImageExtractor()
	case "audio/mp3", "audio/mpeg", "audio/ogg", "audio/x-m4a", "audio/flac":
		e = NewAudioExtractor()
	}
	if e != nil {
		return &e
	}
	return nil
}

// ImageExtractor is used to extract width/height from images
type ImageExtractor struct {
	w  *io.PipeWriter
	r  *io.PipeReader
	ch chan interface{}
}

// NewImageExtractor returns an extractor for images
func NewImageExtractor() *ImageExtractor {
	e := &ImageExtractor{}
	e.r, e.w = io.Pipe()
	e.ch = make(chan interface{})
	go e.Start()
	return e
}

// Start is used in a goroutine to start the metadata extraction
func (e *ImageExtractor) Start() {
	cfg, _, err := image.DecodeConfig(e.r)
	e.r.Close()
	if err != nil {
		e.ch <- err
	} else {
		e.ch <- cfg
	}
}

// Write is called to push some bytes to the extractor
func (e *ImageExtractor) Write(p []byte) (n int, err error) {
	return e.w.Write(p)
}

// Close is called when all the bytes has been pushed, to finalize the extraction
func (e *ImageExtractor) Close() error {
	err := e.w.Close()
	if err != nil {
		<-e.ch
	}
	return err
}

// Abort is called when the extractor can be discarded
func (e *ImageExtractor) Abort(err error) {
	e.w.CloseWithError(err)
	<-e.ch
}

// Result is called to get the extracted metadata
func (e *ImageExtractor) Result() Metadata {
	m := NewMetadata()
	m["datetime"] = time.Now()
	cfg := <-e.ch
	switch cfg := cfg.(type) {
	case image.Config:
		m["width"] = cfg.Width
		m["height"] = cfg.Height
	}
	return m
}

// ExifExtractor is used to extract EXIF metadata from jpegs
type ExifExtractor struct {
	w  *io.PipeWriter
	r  *io.PipeReader
	im *ImageExtractor
	ch chan interface{}
}

// NewExifExtractor returns an extractor for EXIF metadata
func NewExifExtractor() *ExifExtractor {
	e := &ExifExtractor{}
	e.im = NewImageExtractor()
	e.r, e.w = io.Pipe()
	e.ch = make(chan interface{})
	go e.Start()
	return e
}

// Start is used in a goroutine to start the metadata extraction
func (e *ExifExtractor) Start() {
	x, err := exif.Decode(e.r)
	e.r.Close()
	if err != nil {
		e.ch <- err
	} else {
		e.ch <- x
	}
}

// Write is called to push some bytes to the extractor
func (e *ExifExtractor) Write(p []byte) (n int, err error) {
	e.im.Write(p)
	return e.w.Write(p)
}

// Close is called when all the bytes has been pushed, to finalize the extraction
func (e *ExifExtractor) Close() error {
	e.im.Close()
	return e.w.Close()
}

// Abort is called when the extractor can be discarded
func (e *ExifExtractor) Abort(err error) {
	e.im.Abort(err)
	e.w.CloseWithError(err)
	<-e.ch
}

// Result is called to get the extracted metadata
func (e *ExifExtractor) Result() Metadata {
	m := e.im.Result()
	x := <-e.ch
	switch x := x.(type) {
	case *exif.Exif:
		if dt, err := x.DateTime(); err == nil {
			m["datetime"] = dt
		}
		if flash, err := x.Flash(); err == nil {
			m["flash"] = flash
		}
		if lat, long, err := x.LatLong(); err == nil {
			m["gps"] = map[string]float64{
				"lat":  lat,
				"long": long,
			}
		}
		if o, err := x.Get("Orientation"); err == nil {
			if orientation, err := o.Int(0); err == nil {
				m["orientation"] = orientation
				if orientation > 4 {
					m["width"], m["height"] = m["height"], m["width"]
				}
			}
		}
	}
	return m
}

// AudioExtractor is used to extract album/artist/etc. from audio
type AudioExtractor struct {
	w  *io.PipeWriter
	r  *io.PipeReader
	ch chan interface{}
}

// NewAudioExtractor returns an extractor for audio
func NewAudioExtractor() *AudioExtractor {
	e := &AudioExtractor{}
	e.r, e.w = io.Pipe()
	e.ch = make(chan interface{})
	go e.Start()
	return e
}

// Start is used in a goroutine to start the metadata extraction
func (e *AudioExtractor) Start() {
	buf, err := ioutil.ReadAll(e.r)
	if err != nil {
		e.ch <- err
		return
	}
	tags, err := tag.ReadFrom(bytes.NewReader(buf))
	e.r.Close()
	if err != nil {
		e.ch <- err
	} else {
		e.ch <- tags
	}
}

// Write is called to push some bytes to the extractor
func (e *AudioExtractor) Write(p []byte) (n int, err error) {
	return e.w.Write(p)
}

// Close is called when all the bytes has been pushed, to finalize the extraction
func (e *AudioExtractor) Close() error {
	return e.w.Close()
}

// Abort is called when the extractor can be discarded
func (e *AudioExtractor) Abort(err error) {
	e.w.CloseWithError(err)
	<-e.ch
}

// Result is called to get the extracted metadata
func (e *AudioExtractor) Result() Metadata {
	m := NewMetadata()
	tags := <-e.ch
	switch tags := tags.(type) {
	case tag.Metadata:
		if album := tags.Album(); album != "" {
			m["album"] = album
		}
		if artist := tags.Artist(); artist != "" {
			m["artist"] = artist
		}
		if composer := tags.Composer(); composer != "" {
			m["composer"] = composer
		}
		if genre := tags.Genre(); genre != "" {
			m["genre"] = genre
		}
		if title := tags.Title(); title != "" {
			m["title"] = title
		}
		if year := tags.Year(); year != 0 {
			m["year"] = year
		}
		if track, _ := tags.Track(); track != 0 {
			m["track"] = track
		}
	}
	return m
}
<|endoftext|>


<commit_before>package virtctl

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

	"github.com/spf13/cobra"

	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/client-go/log"
	"kubevirt.io/kubevirt/pkg/virtctl/console"
	"kubevirt.io/kubevirt/pkg/virtctl/expose"
	"kubevirt.io/kubevirt/pkg/virtctl/imageupload"
	"kubevirt.io/kubevirt/pkg/virtctl/templates"
	"kubevirt.io/kubevirt/pkg/virtctl/version"
	"kubevirt.io/kubevirt/pkg/virtctl/vm"
	"kubevirt.io/kubevirt/pkg/virtctl/vnc"
)

var programName string

func NewVirtctlCommand() *cobra.Command {
	programName = strings.Replace(filepath.Base(os.Args[0]), "-", " ", -1)

	cobra.AddTemplateFunc("ProgramName", func() string { return programName })
	cobra.AddTemplateFunc("prepare", func(s string) string { return strings.Replace(s, "{{ProgramName}}", programName, -1) })

	rootCmd := &cobra.Command{
		Use:           programName,
		Short:         programName + " controls virtual machine related operations on your kubernetes cluster.",
		SilenceUsage:  true,
		SilenceErrors: true,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
		},
	}

	optionsCmd := &cobra.Command{
		Use:    "options",
		Hidden: true,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
		},
	}
	optionsCmd.SetUsageTemplate(templates.OptionsUsageTemplate())
	//TODO: Add a ClientConfigFactory which allows substituting the KubeVirt client with a mock for unit testing
	clientConfig := kubecli.DefaultClientConfig(rootCmd.PersistentFlags())
	AddGlogFlags(rootCmd.PersistentFlags())
	rootCmd.SetUsageTemplate(templates.MainUsageTemplate())
	rootCmd.AddCommand(
		console.NewCommand(clientConfig),
		vnc.NewCommand(clientConfig),
		vm.NewStartCommand(clientConfig),
		vm.NewStopCommand(clientConfig),
		vm.NewRestartCommand(clientConfig),
		expose.NewExposeCommand(clientConfig),
		version.VersionCommand(clientConfig),
		imageupload.NewImageUploadCommand(clientConfig),
		optionsCmd,
	)
	return rootCmd
}

func Execute() {
	log.InitializeLogging(programName)
	if err := NewVirtctlCommand().Execute(); err != nil {
		fmt.Println(strings.TrimSpace(err.Error()))
		os.Exit(1)
	}
}
<commit_msg>Change programName only for basename kubectl-virt<commit_after>package virtctl

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

	"github.com/spf13/cobra"

	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/client-go/log"
	"kubevirt.io/kubevirt/pkg/virtctl/console"
	"kubevirt.io/kubevirt/pkg/virtctl/expose"
	"kubevirt.io/kubevirt/pkg/virtctl/imageupload"
	"kubevirt.io/kubevirt/pkg/virtctl/templates"
	"kubevirt.io/kubevirt/pkg/virtctl/version"
	"kubevirt.io/kubevirt/pkg/virtctl/vm"
	"kubevirt.io/kubevirt/pkg/virtctl/vnc"
)

var programName string

func NewVirtctlCommand() *cobra.Command {
	programName = "virtctl"
	if filepath.Base(os.Args[0]) == "kubectl-virt" {
		programName = "kubectl virt"
	}

	cobra.AddTemplateFunc("ProgramName", func() string { return programName })
	cobra.AddTemplateFunc("prepare", func(s string) string { return strings.Replace(s, "{{ProgramName}}", programName, -1) })

	rootCmd := &cobra.Command{
		Use:           programName,
		Short:         programName + " controls virtual machine related operations on your kubernetes cluster.",
		SilenceUsage:  true,
		SilenceErrors: true,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
		},
	}

	optionsCmd := &cobra.Command{
		Use:    "options",
		Hidden: true,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprint(cmd.OutOrStderr(), cmd.UsageString())
		},
	}
	optionsCmd.SetUsageTemplate(templates.OptionsUsageTemplate())
	//TODO: Add a ClientConfigFactory which allows substituting the KubeVirt client with a mock for unit testing
	clientConfig := kubecli.DefaultClientConfig(rootCmd.PersistentFlags())
	AddGlogFlags(rootCmd.PersistentFlags())
	rootCmd.SetUsageTemplate(templates.MainUsageTemplate())
	rootCmd.AddCommand(
		console.NewCommand(clientConfig),
		vnc.NewCommand(clientConfig),
		vm.NewStartCommand(clientConfig),
		vm.NewStopCommand(clientConfig),
		vm.NewRestartCommand(clientConfig),
		expose.NewExposeCommand(clientConfig),
		version.VersionCommand(clientConfig),
		imageupload.NewImageUploadCommand(clientConfig),
		optionsCmd,
	)
	return rootCmd
}

func Execute() {
	log.InitializeLogging(programName)
	if err := NewVirtctlCommand().Execute(); err != nil {
		fmt.Println(strings.TrimSpace(err.Error()))
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package u

import (
	"bufio"
	"io"
	"io/ioutil"
	"os"
	"regexp"
)

func U(err error) {
	if err != nil {
		panic(err)
	}
}

func ReplaceAll(target, regex, replace string) string {
	return regexp.MustCompile(regex).ReplaceAllString(target, replace)
}

func Match(target, regex string) bool {
	return regexp.MustCompile(regex).MatchString(target)
}

func MatchAny(target string, list ...string) bool {
	for _, regex := range list {
		if Match(target, regex) {
			return true
		}
	}
	return false
}

func Include(arr []int, value int) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

func Read(path string) (string, error) {
	file, err := os.Open(path)
	defer file.Close()
	if err != nil {
		return "", err
	}

	result := ""
	reader := bufio.NewReaderSize(file, 4096)
	for {
		line, _, err := reader.ReadLine()
		if err == nil {
			result += string(line) + "\n"
		} else if err == io.EOF {
			return result, nil
		} else {
			return "", err
		}
	}
}

func Write(path, content string) {
	err := ioutil.WriteFile(path, []byte(content), os.ModePerm)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Add POST request hander.<commit_after>package u

import (
	"time"
	"bufio"
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"regexp"
)

func U(err error) {
	if err != nil {
		panic(err)
	}
}

func ReplaceAll(target, regex, replace string) string {
	return regexp.MustCompile(regex).ReplaceAllString(target, replace)
}

func Match(target, regex string) bool {
	return regexp.MustCompile(regex).MatchString(target)
}

func MatchAny(target string, list ...string) bool {
	for _, regex := range list {
		if Match(target, regex) {
			return true
		}
	}
	return false
}

func Include(arr []int, value int) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

func Read(path string) (string, error) {
	file, err := os.Open(path)
	defer file.Close()
	if err != nil {
		return "", err
	}

	result := ""
	reader := bufio.NewReaderSize(file, 4096)
	for {
		line, _, err := reader.ReadLine()
		if err == nil {
			result += string(line) + "\n"
		} else if err == io.EOF {
			return result, nil
		} else {
			return "", err
		}
	}
}

func Write(path, content string) error {
	return ioutil.WriteFile(path, []byte(content), os.ModePerm)
}

type HttpClient struct { http.Client }

var defaultClient = func() *HttpClient {
	jar, _ := cookiejar.New(nil)

	return &HttpClient{http.Client{
		Jar: jar,
		Timeout: time.Duration(10) * time.Second,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return errors.New("redirect")
		},
	}}
}()

type HttpRequest struct {
	values url.Values
	files map[string]string
}

func (req *HttpRequest) Add(key, value string) {
	req.values.Add(key, value)
}

func (req *HttpRequest) AddFile(key, fileName string) {
	req.files[key] = fileName
}

func Post(url string, req *HttpRequest) (string, error) {
	return defaultClient.Post(url, req)
}

func (c *HttpClient) Post(url string, req *HttpRequest) (string, error) {
	var resp *http.Response
	var err error
	if len(req.files) == 0 {
		resp, err = c.PostForm(url, req.values)
	} else {
		bodyBuf := &bytes.Buffer{}
		bodyWriter := multipart.NewWriter(bodyBuf)

		for key, fileName := range req.files {
			fileWriter, err := bodyWriter.CreateFormFile(key, fileName)
			if err != nil {
				return "", err
			}

			fh, err := os.Open(fileName)
			if err != nil {
				return "", err
			}
			defer fh.Close()

			_, err = io.Copy(fileWriter, fh)
			if err != nil {
				return "", err
			}
		}

		for key := range req.values {
			bodyWriter.WriteField(key, req.values.Get(key))
		}

		contentType := bodyWriter.FormDataContentType()
		bodyWriter.Close()

		resp, err = c.Client.Post(url, contentType, bodyBuf)
	}

	if err != nil {
		return "", err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}
<|endoftext|>


<commit_before>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax.
//
// Use MakeWrapper to expose methods to JavaScript. Use MakeFullWrapper to expose methods AND fields to JavaScript. When passing values directly, the following type conversions are performed:
//
//  | Go type               | JavaScript type       | Conversions back to interface{} |
//  | --------------------- | --------------------- | ------------------------------- |
//  | bool                  | Boolean               | bool                            |
//  | integers and floats   | Number                | float64                         |
//  | string                | String                | string                          |
//  | []int8                | Int8Array             | []int8                          |
//  | []int16               | Int16Array            | []int16                         |
//  | []int32, []int        | Int32Array            | []int                           |
//  | []uint8               | Uint8Array            | []uint8                         |
//  | []uint16              | Uint16Array           | []uint16                        |
//  | []uint32, []uint      | Uint32Array           | []uint                          |
//  | []float32             | Float32Array          | []float32                       |
//  | []float64             | Float64Array          | []float64                       |
//  | all other slices      | Array                 | []interface{}                   |
//  | arrays                | see slice type        | see slice type                  |
//  | functions             | Function              | func(...interface{}) *js.Object |
//  | time.Time             | Date                  | time.Time                       |
//  | -                     | instanceof Node       | *js.Object                      |
//  | maps, structs         | instanceof Object     | map[string]interface{}          |
//
// Additionally, for a struct containing a *js.Object field, only the content of the field will be passed to JavaScript and vice versa.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. A nil pointer to Object is equal to JavaScript's "null". Object can not be used as a map key.
type Object struct{ object *Object }

// Get returns the object's property with the given key.
func (o *Object) Get(key string) *Object { return o.object.Get(key) }

// Set assigns the value to the object's property with the given key.
func (o *Object) Set(key string, value interface{}) { o.object.Set(key, value) }

// Delete removes the object's property with the given key.
func (o *Object) Delete(key string) { o.object.Delete(key) }

// Length returns the object's "length" property, converted to int.
func (o *Object) Length() int { return o.object.Length() }

// Index returns the i'th element of an array.
func (o *Object) Index(i int) *Object { return o.object.Index(i) }

// SetIndex sets the i'th element of an array.
func (o *Object) SetIndex(i int, value interface{}) { o.object.SetIndex(i, value) }

// Call calls the object's method with the given name.
func (o *Object) Call(name string, args ...interface{}) *Object { return o.object.Call(name, args...) }

// Invoke calls the object itself. This will fail if it is not a function.
func (o *Object) Invoke(args ...interface{}) *Object { return o.object.Invoke(args...) }

// New creates a new instance of this type object. This will fail if it not a function (constructor).
func (o *Object) New(args ...interface{}) *Object { return o.object.New(args...) }

// Bool returns the object converted to bool according to JavaScript type conversions.
func (o *Object) Bool() bool { return o.object.Bool() }

// String returns the object converted to string according to JavaScript type conversions.
func (o *Object) String() string { return o.object.String() }

// Int returns the object converted to int according to JavaScript type conversions (parseInt).
func (o *Object) Int() int { return o.object.Int() }

// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
func (o *Object) Int64() int64 { return o.object.Int64() }

// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
func (o *Object) Uint64() uint64 { return o.object.Uint64() }

// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
func (o *Object) Float() float64 { return o.object.Float() }

// Interface returns the object converted to interface{}. See table in package comment for details.
func (o *Object) Interface() interface{} { return o.object.Interface() }

// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
func (o *Object) Unsafe() uintptr { return o.object.Unsafe() }

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be recovered, giving an *Error that holds the JavaScript error object.
type Error struct {
	*Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").String()
}

// Stack returns the stack property of the encapsulated JavaScript error object.
func (err *Error) Stack() string {
	return err.Get("stack").String()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js).
var Global *Object

// Module gives the value of the "module" variable set by Node.js. Hint: Set a
// module export with 'js.Module.Get("exports").Set("exportName", ...)'.
//
// Note that js.Module is only defined in runtimes which support CommonJS
// modules (https://nodejs.org/api/modules.html). NodeJS supports it natively,
// but in browsers it can only be used if GopherJS output is passed through a
// bundler which implements CommonJS (for example, webpack or esbuild).
var Module *Object

// Undefined gives the JavaScript value "undefined".
var Undefined *Object

// Debugger gets compiled to JavaScript's "debugger;" statement.
func Debugger() {}

// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) *Object {
	return nil
}

// MakeFunc wraps a function and gives access to the values of JavaScript's "this" and "arguments" keywords.
func MakeFunc(fn func(this *Object, arguments []*Object) interface{}) *Object {
	return Global.Call("$makeFunc", InternalObject(fn))
}

// Keys returns the keys of the given JavaScript object.
func Keys(o *Object) []string {
	if o == nil || o == Undefined {
		return nil
	}
	a := Global.Get("Object").Call("keys", o)
	s := make([]string, a.Length())
	for i := 0; i < a.Length(); i++ {
		s[i] = a.Index(i).String()
	}
	return s
}

// MakeWrapper creates a JavaScript object which has wrappers for the exported methods of i. Use explicit getter and setter methods to expose struct fields to JavaScript.
func MakeWrapper(i interface{}) *Object {
	v := InternalObject(i)
	o := Global.Get("Object").New()
	o.Set("__internal_object__", v)
	methods := v.Get("constructor").Get("methods")
	for i := 0; i < methods.Length(); i++ {
		m := methods.Index(i)
		if m.Get("pkg").String() != "" { // not exported
			continue
		}
		o.Set(m.Get("name").String(), func(args ...*Object) *Object {
			return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true).Call("apply", v, args)
		})
	}
	return o
}

// MakeFullWrapper creates a JavaScript object which has wrappers for the exported
// methods of i, and, where i is a (pointer to a) struct value, wrapped getters
// and setters
// (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
// for the non-embedded exported fields of i. Values accessed via these methods
// and getters are themsevles wrapped when accessed, but an important point to
// note is that a new wrapped value is created on each access.
func MakeFullWrapper(i interface{}) *Object {
	v := InternalObject(i)
	c := v.Get("constructor")

	o := Global.Get("Object").New()

	defineProperty := func(k string, fns ...func(*Object)) {
		op := Global.Get("Object").New()
		for _, f := range fns {
			f(op)
		}
		Global.Get("Object").Call("defineProperty", o, k, op)
	}

	defineProperty("__internal_object__", func(op *Object) {
		op.Set("value", v)
	})

	{
		// caculate a sensible type string

		// we don't want to import any packages in this package
		// so we do some string operations by hand

		typ := c.Get("string").String()
		pkg := c.Get("pkg").String()

		ptr := ""
		if typ[0] == '*' {
			ptr = "*"
		}

		for i := 0; i < len(typ); i++ {
			if typ[i] == '.' {
				typ = typ[i+1:]
				break
			}
		}

		pkgTyp := pkg + "." + ptr + typ
		defineProperty("$type", func(op *Object) {
			op.Set("value", pkgTyp)
		})
	}

	var fields *Object
	methods := Global.Get("Array").New()
	if ms := c.Get("methods"); ms != Undefined {
		methods = methods.Call("concat", ms)
	}
	// if we are a pointer value then add fields from element
	// else the constructor itself will have them
	if e := c.Get("elem"); e != Undefined {
		fields = e.Get("fields")
		methods = methods.Call("concat", e.Get("methods"))
	} else {
		fields = c.Get("fields")
	}
	for i := 0; i < methods.Length(); i++ {
		m := methods.Index(i)
		if m.Get("pkg").String() != "" { // not exported
			continue
		}
		defineProperty(m.Get("prop").String(), func(op *Object) {
			op.Set("value", func(args ...*Object) *Object {
				return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true, InternalObject(MakeFullWrapper)).Call("apply", v, args)
			})
		})
	}
	if fields != Undefined {
		for i := 0; i < fields.Length(); i++ {
			f := fields.Index(i)
			if !f.Get("exported").Bool() {
				continue
			}
			defineProperty(f.Get("prop").String(), func(op *Object) {
				op.Set("get", func() *Object {
					vc := Global.Call("$copyIfRequired", v.Get("$val").Get(f.Get("prop").String()), f.Get("typ"))
					return Global.Call("$externalize", vc, f.Get("typ"), InternalObject(MakeFullWrapper))
				})
				op.Set("set", func(jv *Object) {
					gv := Global.Call("$internalize", jv, f.Get("typ"), InternalObject(MakeFullWrapper))
					v.Get("$val").Set(f.Get("prop").String(), gv)
				})
			})
		}
	}
	return o
}

// NewArrayBuffer creates a JavaScript ArrayBuffer from a byte slice.
func NewArrayBuffer(b []byte) *Object {
	slice := InternalObject(b)
	offset := slice.Get("$offset").Int()
	length := slice.Get("$length").Int()
	return slice.Get("$array").Get("buffer").Call("slice", offset, offset+length)
}

// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
type M map[string]interface{}

// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
type S []interface{}

func init() {
	// avoid dead code elimination
	e := Error{}
	_ = e
}
<commit_msg>refactor: address code reviews<commit_after>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax.
//
// Use MakeWrapper to expose methods to JavaScript. Use MakeFullWrapper to expose methods AND fields to JavaScript. When passing values directly, the following type conversions are performed:
//
//  | Go type               | JavaScript type       | Conversions back to interface{} |
//  | --------------------- | --------------------- | ------------------------------- |
//  | bool                  | Boolean               | bool                            |
//  | integers and floats   | Number                | float64                         |
//  | string                | String                | string                          |
//  | []int8                | Int8Array             | []int8                          |
//  | []int16               | Int16Array            | []int16                         |
//  | []int32, []int        | Int32Array            | []int                           |
//  | []uint8               | Uint8Array            | []uint8                         |
//  | []uint16              | Uint16Array           | []uint16                        |
//  | []uint32, []uint      | Uint32Array           | []uint                          |
//  | []float32             | Float32Array          | []float32                       |
//  | []float64             | Float64Array          | []float64                       |
//  | all other slices      | Array                 | []interface{}                   |
//  | arrays                | see slice type        | see slice type                  |
//  | functions             | Function              | func(...interface{}) *js.Object |
//  | time.Time             | Date                  | time.Time                       |
//  | -                     | instanceof Node       | *js.Object                      |
//  | maps, structs         | instanceof Object     | map[string]interface{}          |
//
// Additionally, for a struct containing a *js.Object field, only the content of the field will be passed to JavaScript and vice versa.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. A nil pointer to Object is equal to JavaScript's "null". Object can not be used as a map key.
type Object struct{ object *Object }

// Get returns the object's property with the given key.
func (o *Object) Get(key string) *Object { return o.object.Get(key) }

// Set assigns the value to the object's property with the given key.
func (o *Object) Set(key string, value interface{}) { o.object.Set(key, value) }

// Delete removes the object's property with the given key.
func (o *Object) Delete(key string) { o.object.Delete(key) }

// Length returns the object's "length" property, converted to int.
func (o *Object) Length() int { return o.object.Length() }

// Index returns the i'th element of an array.
func (o *Object) Index(i int) *Object { return o.object.Index(i) }

// SetIndex sets the i'th element of an array.
func (o *Object) SetIndex(i int, value interface{}) { o.object.SetIndex(i, value) }

// Call calls the object's method with the given name.
func (o *Object) Call(name string, args ...interface{}) *Object { return o.object.Call(name, args...) }

// Invoke calls the object itself. This will fail if it is not a function.
func (o *Object) Invoke(args ...interface{}) *Object { return o.object.Invoke(args...) }

// New creates a new instance of this type object. This will fail if it not a function (constructor).
func (o *Object) New(args ...interface{}) *Object { return o.object.New(args...) }

// Bool returns the object converted to bool according to JavaScript type conversions.
func (o *Object) Bool() bool { return o.object.Bool() }

// String returns the object converted to string according to JavaScript type conversions.
func (o *Object) String() string { return o.object.String() }

// Int returns the object converted to int according to JavaScript type conversions (parseInt).
func (o *Object) Int() int { return o.object.Int() }

// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
func (o *Object) Int64() int64 { return o.object.Int64() }

// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
func (o *Object) Uint64() uint64 { return o.object.Uint64() }

// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
func (o *Object) Float() float64 { return o.object.Float() }

// Interface returns the object converted to interface{}. See table in package comment for details.
func (o *Object) Interface() interface{} { return o.object.Interface() }

// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
func (o *Object) Unsafe() uintptr { return o.object.Unsafe() }

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be recovered, giving an *Error that holds the JavaScript error object.
type Error struct {
	*Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").String()
}

// Stack returns the stack property of the encapsulated JavaScript error object.
func (err *Error) Stack() string {
	return err.Get("stack").String()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js).
var Global *Object

// Module gives the value of the "module" variable set by Node.js. Hint: Set a
// module export with 'js.Module.Get("exports").Set("exportName", ...)'.
//
// Note that js.Module is only defined in runtimes which support CommonJS
// modules (https://nodejs.org/api/modules.html). NodeJS supports it natively,
// but in browsers it can only be used if GopherJS output is passed through a
// bundler which implements CommonJS (for example, webpack or esbuild).
var Module *Object

// Undefined gives the JavaScript value "undefined".
var Undefined *Object

// Debugger gets compiled to JavaScript's "debugger;" statement.
func Debugger() {}

// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) *Object {
	return nil
}

// MakeFunc wraps a function and gives access to the values of JavaScript's "this" and "arguments" keywords.
func MakeFunc(fn func(this *Object, arguments []*Object) interface{}) *Object {
	return Global.Call("$makeFunc", InternalObject(fn))
}

// Keys returns the keys of the given JavaScript object.
func Keys(o *Object) []string {
	if o == nil || o == Undefined {
		return nil
	}
	a := Global.Get("Object").Call("keys", o)
	s := make([]string, a.Length())
	for i := 0; i < a.Length(); i++ {
		s[i] = a.Index(i).String()
	}
	return s
}

// MakeWrapper creates a JavaScript object which has wrappers for the exported methods of i. Use explicit getter and setter methods to expose struct fields to JavaScript.
func MakeWrapper(i interface{}) *Object {
	v := InternalObject(i)
	o := Global.Get("Object").New()
	o.Set("__internal_object__", v)
	methods := v.Get("constructor").Get("methods")
	for i := 0; i < methods.Length(); i++ {
		m := methods.Index(i)
		if m.Get("pkg").String() != "" { // not exported
			continue
		}
		o.Set(m.Get("name").String(), func(args ...*Object) *Object {
			return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true).Call("apply", v, args)
		})
	}
	return o
}

// MakeFullWrapper creates a JavaScript object which has wrappers for the exported
// methods of i, and, where i is a (pointer to a) struct value, wrapped getters
// and setters
// (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
// for the non-embedded exported fields of i. Values accessed via these methods
// and getters are themsevles wrapped when accessed, but an important point to
// note is that a new wrapped value is created on each access.
func MakeFullWrapper(i interface{}) *Object {
	internalObj := InternalObject(i)
	constructor := internalObj.Get("constructor")

	wrapperObj := Global.Get("Object").New()

	defineProperty := func(key string, descriptor M) {
		Global.Get("Object").Call("defineProperty", wrapperObj, key, descriptor)
	}

	defineProperty("__internal_object__", M{
		"value": internalObj,
	})

	{
		// Calculate a sensible type string.

		// We don't want to import any packages in this package,
		// so we do some string operations by hand.

		typ := constructor.Get("string").String()
		pkg := constructor.Get("pkg").String()

		ptr := ""
		if typ[0] == '*' {
			ptr = "*"
		}

		for i := 0; i < len(typ); i++ {
			if typ[i] == '.' {
				typ = typ[i+1:]
				break
			}
		}

		pkgTyp := pkg + "." + ptr + typ
		defineProperty("$type", M{
			"value": pkgTyp,
		})
	}

	var fields *Object
	methods := Global.Get("Array").New()
	if ms := constructor.Get("methods"); ms != Undefined {
		methods = methods.Call("concat", ms)
	}
	// If we are a pointer value then add fields from element,
	// else the constructor itself will have them.
	if e := constructor.Get("elem"); e != Undefined {
		fields = e.Get("fields")
		methods = methods.Call("concat", e.Get("methods"))
	} else {
		fields = constructor.Get("fields")
	}
	for i := 0; i < methods.Length(); i++ {
		m := methods.Index(i)
		if m.Get("pkg").String() != "" { // not exported
			continue
		}
		defineProperty(m.Get("prop").String(), M{
			"value": func(args ...*Object) *Object {
				return Global.Call("$externalizeFunction", internalObj.Get(m.Get("prop").String()), m.Get("typ"), true, InternalObject(MakeFullWrapper)).Call("apply", internalObj, args)
			},
		})
	}
	if fields != Undefined {
		for i := 0; i < fields.Length(); i++ {
			f := fields.Index(i)
			if !f.Get("exported").Bool() {
				continue
			}
			defineProperty(f.Get("prop").String(), M{
				"get": func() *Object {
					vc := Global.Call("$copyIfRequired", internalObj.Get("$val").Get(f.Get("prop").String()), f.Get("typ"))
					return Global.Call("$externalize", vc, f.Get("typ"), InternalObject(MakeFullWrapper))
				},
				"set": func(jv *Object) {
					gv := Global.Call("$internalize", jv, f.Get("typ"), InternalObject(MakeFullWrapper))
					internalObj.Get("$val").Set(f.Get("prop").String(), gv)
				},
			})
		}
	}
	return wrapperObj
}

// NewArrayBuffer creates a JavaScript ArrayBuffer from a byte slice.
func NewArrayBuffer(b []byte) *Object {
	slice := InternalObject(b)
	offset := slice.Get("$offset").Int()
	length := slice.Get("$length").Int()
	return slice.Get("$array").Get("buffer").Call("slice", offset, offset+length)
}

// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
type M map[string]interface{}

// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
type S []interface{}

func init() {
	// Avoid dead code elimination.
	e := Error{}
	_ = e
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/nlopes/slack"
)

const (
	SyntheticUserImageUrlTemplate = "https://i1.wp.com/slack.global.ssl.fastly.net/66f9/img/avatars/ava_0025-%d.png?ssl=1"
	SyntheticBotUserImageUrl = "https://slack.global.ssl.fastly.net/66f9/img/default_application_icon.png"
)

type UserLookup struct {
	slackClient *slack.Client
	usersById   map[string]*slack.User
}

func newUserLookup(slackClient *slack.Client) (*UserLookup, error) {
	// Fetch all users in bulk so that we don't need to get them one at a time
	// for each channel message or DM conversation.
	users, err := slackClient.GetUsers()
	if err != nil {
		return nil, err
	}
	usersById := make(map[string]*slack.User)
	for i := range users {
		usersById[users[i].ID] = &users[i]
	}
	return &UserLookup{slackClient, usersById}, nil
}

func (lookup *UserLookup) GetUser(userId string) (*slack.User, error) {
	user, ok := lookup.usersById[userId]
	if !ok {
		user, err := lookup.slackClient.GetUserInfo(userId)
		if err != nil {
			return nil, err
		}
		lookup.usersById[userId] = user
	}
	return user, nil
}

func (lookup *UserLookup) GetUserByName(name string) *slack.User {
	for _, user := range lookup.usersById {
		// Use a case-insensitive comparison, we get names with different
		// capitalization in bot messages vs. user profiles.
		if strings.EqualFold(name, user.Name) {
			return user
		}
	}
	return nil
}

func (lookup *UserLookup) GetUserForMessage(message *slack.Message) (*slack.User, error) {
	var err error
	if message.User != "" {
		messageAuthor, err := lookup.GetUser(message.User)
		if err == nil {
			return messageAuthor, nil
		}
	}
	if message.BotID != "" {
		messageAuthor, err := lookup.GetUser(message.BotID)
		if err == nil {
			return messageAuthor, nil
		}
	}
	if message.Username != "" {
		messageAuthor := lookup.GetUserByName(message.Username)
		if messageAuthor == nil {
			// Synthesize a slack.User from just the given username.
			// It would be nice to also include the profile picture, but the
			// Go library and the Slack API do not agree about how it is
			// represented.
			return newSyntheticUser(message.Username), nil
		}
	}
	// Fall back on a synthetic user with the ID, it's better than nothing.
	if message.User != "" {
		return newSyntheticUser(message.User), nil
	}
	if message.BotID != "" {
		return newSyntheticBotUser(message.BotID), nil
	}

	return nil, err
}

func newSyntheticUser(name string) *slack.User {
	return &slack.User{
		ID:   fmt.Sprintf("synthetic-%s", name),
		Name: name,
		Profile: slack.UserProfile{
			Image24:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 24),
			Image32:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 32),
			Image48:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 48),
			Image72:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 72),
			Image192: fmt.Sprintf(SyntheticUserImageUrlTemplate, 192),
		},
	}
}

func newSyntheticBotUser(name string) *slack.User {
	return &slack.User{
		ID:   fmt.Sprintf("synthetic-%s", name),
		Name: name,
		Profile: slack.UserProfile{
			Image24:  SyntheticBotUserImageUrl,
			Image32:  SyntheticBotUserImageUrl,
			Image48:  SyntheticBotUserImageUrl,
			Image72:  SyntheticBotUserImageUrl,
			Image192: SyntheticBotUserImageUrl,
		},
	}
}
<commit_msg>gofmt<commit_after>package main

import (
	"fmt"
	"strings"

	"github.com/nlopes/slack"
)

const (
	SyntheticUserImageUrlTemplate = "https://i1.wp.com/slack.global.ssl.fastly.net/66f9/img/avatars/ava_0025-%d.png?ssl=1"
	SyntheticBotUserImageUrl      = "https://slack.global.ssl.fastly.net/66f9/img/default_application_icon.png"
)

type UserLookup struct {
	slackClient *slack.Client
	usersById   map[string]*slack.User
}

func newUserLookup(slackClient *slack.Client) (*UserLookup, error) {
	// Fetch all users in bulk so that we don't need to get them one at a time
	// for each channel message or DM conversation.
	users, err := slackClient.GetUsers()
	if err != nil {
		return nil, err
	}
	usersById := make(map[string]*slack.User)
	for i := range users {
		usersById[users[i].ID] = &users[i]
	}
	return &UserLookup{slackClient, usersById}, nil
}

func (lookup *UserLookup) GetUser(userId string) (*slack.User, error) {
	user, ok := lookup.usersById[userId]
	if !ok {
		user, err := lookup.slackClient.GetUserInfo(userId)
		if err != nil {
			return nil, err
		}
		lookup.usersById[userId] = user
	}
	return user, nil
}

func (lookup *UserLookup) GetUserByName(name string) *slack.User {
	for _, user := range lookup.usersById {
		// Use a case-insensitive comparison, we get names with different
		// capitalization in bot messages vs. user profiles.
		if strings.EqualFold(name, user.Name) {
			return user
		}
	}
	return nil
}

func (lookup *UserLookup) GetUserForMessage(message *slack.Message) (*slack.User, error) {
	var err error
	if message.User != "" {
		messageAuthor, err := lookup.GetUser(message.User)
		if err == nil {
			return messageAuthor, nil
		}
	}
	if message.BotID != "" {
		messageAuthor, err := lookup.GetUser(message.BotID)
		if err == nil {
			return messageAuthor, nil
		}
	}
	if message.Username != "" {
		messageAuthor := lookup.GetUserByName(message.Username)
		if messageAuthor == nil {
			// Synthesize a slack.User from just the given username.
			// It would be nice to also include the profile picture, but the
			// Go library and the Slack API do not agree about how it is
			// represented.
			return newSyntheticUser(message.Username), nil
		}
	}
	// Fall back on a synthetic user with the ID, it's better than nothing.
	if message.User != "" {
		return newSyntheticUser(message.User), nil
	}
	if message.BotID != "" {
		return newSyntheticBotUser(message.BotID), nil
	}

	return nil, err
}

func newSyntheticUser(name string) *slack.User {
	return &slack.User{
		ID:   fmt.Sprintf("synthetic-%s", name),
		Name: name,
		Profile: slack.UserProfile{
			Image24:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 24),
			Image32:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 32),
			Image48:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 48),
			Image72:  fmt.Sprintf(SyntheticUserImageUrlTemplate, 72),
			Image192: fmt.Sprintf(SyntheticUserImageUrlTemplate, 192),
		},
	}
}

func newSyntheticBotUser(name string) *slack.User {
	return &slack.User{
		ID:   fmt.Sprintf("synthetic-%s", name),
		Name: name,
		Profile: slack.UserProfile{
			Image24:  SyntheticBotUserImageUrl,
			Image32:  SyntheticBotUserImageUrl,
			Image48:  SyntheticBotUserImageUrl,
			Image72:  SyntheticBotUserImageUrl,
			Image192: SyntheticBotUserImageUrl,
		},
	}
}
<|endoftext|>


<commit_before>// +build linux,cgo,!agent

package sys

import (
	"os"
	"path/filepath"

	"github.com/pkg/errors"
)

// LocalDatabasePath returns the path of the local database file.
func (s *OS) LocalDatabasePath() string {
	return filepath.Join(s.VarDir, "database", "local.db")
}

// LegacyLocalDatabasePath returns the path of legacy local database file.
func (s *OS) LegacyLocalDatabasePath() string {
	return filepath.Join(s.VarDir, "lxd.db")
}

// GlobalDatabaseDir returns the path of the global database directory.
func (s *OS) GlobalDatabaseDir() string {
	return filepath.Join(s.VarDir, "database", "global")
}

// GlobalDatabasePath returns the path of the global database SQLite file
// managed by dqlite.
func (s *OS) GlobalDatabasePath() string {
	return filepath.Join(s.GlobalDatabaseDir(), "db.bin")
}

// LegacyGlobalDatabasePath returns the path of legacy global database file.
func (s *OS) LegacyGlobalDatabasePath() string {
	return filepath.Join(s.VarDir, "raft", "db.bin")
}

// Make sure all our directories are available.
func (s *OS) initDirs() error {
	dirs := []struct {
		path string
		mode os.FileMode
	}{
		{s.VarDir, 0711},
		{filepath.Join(s.VarDir, "backups"), 0700},
		{s.CacheDir, 0700},
		// containers is 0711 because liblxc needs to traverse dir to get to each container.
		{filepath.Join(s.VarDir, "containers"), 0711},
		{filepath.Join(s.VarDir, "virtual-machines"), 0711},
		{filepath.Join(s.VarDir, "database"), 0700},
		{filepath.Join(s.VarDir, "devices"), 0711},
		{filepath.Join(s.VarDir, "devlxd"), 0755},
		{filepath.Join(s.VarDir, "disks"), 0700},
		{filepath.Join(s.VarDir, "images"), 0700},
		{s.LogDir, 0700},
		{filepath.Join(s.VarDir, "networks"), 0711},
		{filepath.Join(s.VarDir, "security"), 0700},
		{filepath.Join(s.VarDir, "shmounts"), 0711},
		// snapshots is 0700 as liblxc does not need to access this.
		{filepath.Join(s.VarDir, "snapshots"), 0700},
		{filepath.Join(s.VarDir, "virtual-machines-snapshots"), 0700},
		{filepath.Join(s.VarDir, "storage-pools"), 0711},
	}

	for _, dir := range dirs {
		err := os.Mkdir(dir.path, dir.mode)
		if err != nil {
			if !os.IsExist(err) {
				return errors.Wrapf(err, "Failed to init dir %s", dir.path)
			}

			err = os.Chmod(dir.path, dir.mode)
			if err != nil {
				return errors.Wrapf(err, "Failed to chmod dir %s", dir.path)
			}
		}
	}

	return nil
}
<commit_msg>lxd/sys: Don't fail chmod on unresolvable symlinks<commit_after>// +build linux,cgo,!agent

package sys

import (
	"os"
	"path/filepath"

	"github.com/pkg/errors"
)

// LocalDatabasePath returns the path of the local database file.
func (s *OS) LocalDatabasePath() string {
	return filepath.Join(s.VarDir, "database", "local.db")
}

// LegacyLocalDatabasePath returns the path of legacy local database file.
func (s *OS) LegacyLocalDatabasePath() string {
	return filepath.Join(s.VarDir, "lxd.db")
}

// GlobalDatabaseDir returns the path of the global database directory.
func (s *OS) GlobalDatabaseDir() string {
	return filepath.Join(s.VarDir, "database", "global")
}

// GlobalDatabasePath returns the path of the global database SQLite file
// managed by dqlite.
func (s *OS) GlobalDatabasePath() string {
	return filepath.Join(s.GlobalDatabaseDir(), "db.bin")
}

// LegacyGlobalDatabasePath returns the path of legacy global database file.
func (s *OS) LegacyGlobalDatabasePath() string {
	return filepath.Join(s.VarDir, "raft", "db.bin")
}

// Make sure all our directories are available.
func (s *OS) initDirs() error {
	dirs := []struct {
		path string
		mode os.FileMode
	}{
		{s.VarDir, 0711},
		{filepath.Join(s.VarDir, "backups"), 0700},
		{s.CacheDir, 0700},
		// containers is 0711 because liblxc needs to traverse dir to get to each container.
		{filepath.Join(s.VarDir, "containers"), 0711},
		{filepath.Join(s.VarDir, "virtual-machines"), 0711},
		{filepath.Join(s.VarDir, "database"), 0700},
		{filepath.Join(s.VarDir, "devices"), 0711},
		{filepath.Join(s.VarDir, "devlxd"), 0755},
		{filepath.Join(s.VarDir, "disks"), 0700},
		{filepath.Join(s.VarDir, "images"), 0700},
		{s.LogDir, 0700},
		{filepath.Join(s.VarDir, "networks"), 0711},
		{filepath.Join(s.VarDir, "security"), 0700},
		{filepath.Join(s.VarDir, "shmounts"), 0711},
		// snapshots is 0700 as liblxc does not need to access this.
		{filepath.Join(s.VarDir, "snapshots"), 0700},
		{filepath.Join(s.VarDir, "virtual-machines-snapshots"), 0700},
		{filepath.Join(s.VarDir, "storage-pools"), 0711},
	}

	for _, dir := range dirs {
		err := os.Mkdir(dir.path, dir.mode)
		if err != nil {
			if !os.IsExist(err) {
				return errors.Wrapf(err, "Failed to init dir %s", dir.path)
			}

			err = os.Chmod(dir.path, dir.mode)
			if err != nil && !os.IsNotExist(err) {
				return errors.Wrapf(err, "Failed to chmod dir %s", dir.path)
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package net

import (
	"errors"
	"sort"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/sahib/brig/net/backend"
)

var (
	ErrPingMapClosed = errors.New("Pinger Map was already closed")
	ErrNoSuchAddr    = errors.New("No such addr known to ping map")
)

type PingMap struct {
	mu    sync.Mutex
	tickr *time.Ticker
	peers map[string]backend.Pinger
	netBk backend.Backend
}

func NewPingMap(netBk backend.Backend) *PingMap {
	pm := &PingMap{
		peers: make(map[string]backend.Pinger),
		netBk: netBk,
		tickr: time.NewTicker(30 * time.Second),
	}

	go pm.updateLoop()
	return pm
}

func (pm *PingMap) updateLoop() {
	for range pm.tickr.C {
		pm.doUpdate()
	}
}

func (pm *PingMap) doUpdate() {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.peers == nil {
		return
	}

	log.Infof("Updating pinger entries...")

	for addr, pinger := range pm.peers {
		if pinger == nil {
			// Try to get a pinger in the background:
			go pm.doUpdateSingle(addr)
			continue
		}

		// Maybe the pinger errored in between?
		if err := pinger.Err(); err != nil {
			log.Warningf("Pinger %s failed: %v", addr, err)
			pinger.Close()
			pm.peers[addr] = nil
		}
	}
}

func (pm *PingMap) doUpdateSingle(addr string) {
	pinger, err := pm.netBk.Ping(addr)
	if err != nil {
		log.Infof("Pinger %s still not reachable: %v", addr, err)
		if pinger != nil {
			pinger.Close()
		}
		return
	}

	// We fixed this addr. Yay.
	log.Infof("Pinger %s recovered", addr)

	// Only do the map update in parallel:
	pm.mu.Lock()
	defer pm.mu.Unlock()

	pm.peers[addr] = pinger
}

// Sync makes sure all addresses in `addrs` are being watched.
// All currently watched addrs that are not in `addrs` are removed.
// This method does not block until all pingers have been updated.
func (pm *PingMap) Sync(addrs []string) error {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.peers == nil {
		return ErrPingMapClosed
	}

	log.Infof("Syncing ping entries... %d", len(addrs), len(pm.peers))

	// Remember to schedule an update right after sync.
	// This will only run after Sync() due the common lock.
	go pm.doUpdate()

	// Needed for sort.Search below.
	sort.Strings(addrs)

	for _, addr := range addrs {
		if _, ok := pm.peers[addr]; !ok {
			// Just remember that we need to create a pinger for this addr.
			pm.peers[addr] = nil
		}
	}

	// Do the opposite check and see if any addrs in pm.peers
	// are not in `addrs`. If so, remove them out.
	for addr, pinger := range pm.peers {
		if pinger == nil {
			continue
		}

		idx := sort.SearchStrings(addrs, addr)
		if idx < len(addrs) && addrs[idx] == addr {
			continue
		}

		// This addr does not exist anymore.
		log.Debugf("Closing pinger for %v %v", addr, pinger)
		if err := pinger.Close(); err != nil {
			return err
		}
	}

	log.Infof("Finished syncing pinger entries...")
	return nil
}

func (pm *PingMap) For(addr string) (backend.Pinger, error) {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.peers == nil {
		return nil, ErrPingMapClosed
	}

	pinger, ok := pm.peers[addr]
	if !ok {
		return nil, ErrNoSuchAddr
	}

	return pinger, nil
}

func (pm *PingMap) Close() error {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	// Stop updateLoop as a side effect:
	pm.tickr.Stop()

	for _, pinger := range pm.peers {
		if pinger == nil {
			continue
		}

		if err := pinger.Close(); err != nil {
			return err
		}
	}

	pm.peers = nil
	return nil
}
<commit_msg>net: fix bad log message<commit_after>package net

import (
	"errors"
	"sort"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/sahib/brig/net/backend"
)

var (
	ErrPingMapClosed = errors.New("Pinger Map was already closed")
	ErrNoSuchAddr    = errors.New("No such addr known to ping map")
)

type PingMap struct {
	mu    sync.Mutex
	tickr *time.Ticker
	peers map[string]backend.Pinger
	netBk backend.Backend
}

func NewPingMap(netBk backend.Backend) *PingMap {
	pm := &PingMap{
		peers: make(map[string]backend.Pinger),
		netBk: netBk,
		tickr: time.NewTicker(30 * time.Second),
	}

	go pm.updateLoop()
	return pm
}

func (pm *PingMap) updateLoop() {
	for range pm.tickr.C {
		pm.doUpdate()
	}
}

func (pm *PingMap) doUpdate() {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.peers == nil {
		return
	}

	log.Infof("Updating pinger entries...")

	for addr, pinger := range pm.peers {
		if pinger == nil {
			// Try to get a pinger in the background:
			go pm.doUpdateSingle(addr)
			continue
		}

		// Maybe the pinger errored in between?
		if err := pinger.Err(); err != nil {
			log.Warningf("Pinger %s failed: %v", addr, err)
			pinger.Close()
			pm.peers[addr] = nil
		}
	}
}

func (pm *PingMap) doUpdateSingle(addr string) {
	pinger, err := pm.netBk.Ping(addr)
	if err != nil {
		log.Infof("Pinger %s still not reachable: %v", addr, err)
		if pinger != nil {
			pinger.Close()
		}
		return
	}

	// We fixed this addr. Yay.
	log.Infof("Pinger %s recovered", addr)

	// Only do the map update in parallel:
	pm.mu.Lock()
	defer pm.mu.Unlock()

	pm.peers[addr] = pinger
}

// Sync makes sure all addresses in `addrs` are being watched.
// All currently watched addrs that are not in `addrs` are removed.
// This method does not block until all pingers have been updated.
func (pm *PingMap) Sync(addrs []string) error {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.peers == nil {
		return ErrPingMapClosed
	}

	log.Infof("Syncing ping map entries...")

	// Remember to schedule an update right after sync.
	// This will only run after Sync() due the common lock.
	go pm.doUpdate()

	// Needed for sort.Search below.
	sort.Strings(addrs)

	for _, addr := range addrs {
		if _, ok := pm.peers[addr]; !ok {
			// Just remember that we need to create a pinger for this addr.
			pm.peers[addr] = nil
		}
	}

	// Do the opposite check and see if any addrs in pm.peers
	// are not in `addrs`. If so, remove them out.
	for addr, pinger := range pm.peers {
		if pinger == nil {
			continue
		}

		idx := sort.SearchStrings(addrs, addr)
		if idx < len(addrs) && addrs[idx] == addr {
			continue
		}

		// This addr does not exist anymore.
		log.Debugf("Closing pinger for %v %v", addr, pinger)
		if err := pinger.Close(); err != nil {
			return err
		}
	}

	log.Infof("Finished syncing pinger entries...")
	return nil
}

func (pm *PingMap) For(addr string) (backend.Pinger, error) {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	if pm.peers == nil {
		return nil, ErrPingMapClosed
	}

	pinger, ok := pm.peers[addr]
	if !ok {
		return nil, ErrNoSuchAddr
	}

	return pinger, nil
}

func (pm *PingMap) Close() error {
	pm.mu.Lock()
	defer pm.mu.Unlock()

	// Stop updateLoop as a side effect:
	pm.tickr.Stop()

	for _, pinger := range pm.peers {
		if pinger == nil {
			continue
		}

		if err := pinger.Close(); err != nil {
			return err
		}
	}

	pm.peers = nil
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package kv

import (
	"bytes"
	"math"

	"github.com/juju/errors"
)

// Key represents high-level Key type.
type Key []byte

// Next returns the next key in byte-order.
func (k Key) Next() Key {
	// add 0x0 to the end of key
	buf := make([]byte, len([]byte(k))+1)
	copy(buf, []byte(k))
	return buf
}

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k Key) Cmp(another Key) int {
	return bytes.Compare(k, another)
}

// EncodedKey represents encoded key in low-level storage engine.
type EncodedKey []byte

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k EncodedKey) Cmp(another EncodedKey) int {
	return bytes.Compare(k, another)
}

// Next returns the next key in byte-order.
func (k EncodedKey) Next() EncodedKey {
	return EncodedKey(bytes.Join([][]byte{k, Key{0}}, nil))
}

// VersionProvider provides increasing IDs.
type VersionProvider interface {
	CurrentVersion() (Version, error)
}

// Version is the wrapper of KV's version.
type Version struct {
	Ver uint64
}

var (
	// MaxVersion is the maximum version, notice that it's not a valid version.
	MaxVersion = Version{Ver: math.MaxUint64}
	// MinVersion is the minimum version, it's not a valid version, too.
	MinVersion = Version{Ver: 0}
)

// NewVersion creates a new Version struct.
func NewVersion(v uint64) Version {
	return Version{
		Ver: v,
	}
}

// Cmp returns the comparison result of two versions.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (v Version) Cmp(another Version) int {
	if v.Ver > another.Ver {
		return 1
	} else if v.Ver < another.Ver {
		return -1
	}
	return 0
}

// DecodeFn is a function that decodes data after fetching from store.
type DecodeFn func(raw interface{}) (interface{}, error)

// EncodeFn is a function that encodes data before putting into store.
type EncodeFn func(raw interface{}) (interface{}, error)

// ErrNotCommitted is the error returned by CommitVersion when this
// transaction is not committed.
var ErrNotCommitted = errors.New("this transaction is not committed")

// Option is used for customizing kv store's behaviors during a transaction.
type Option int

// Options is an interface of a set of options. Each option is associated with a value.
type Options interface {
	// Get gets an option value.
	Get(opt Option) (v interface{}, ok bool)
}

const (
	// RangePrefetchOnCacheMiss directives that when dealing with a Get operation and failed to read data from cache,
	// it will launch a RangePrefetch to underlying storage instead of Get. The range starts from requested key and
	// has a limit of the option value. The feature is disabled if option value <= 0 or value type is not int.
	// This option is particularly useful when we have to do sequential Gets, e.g. table scans.
	RangePrefetchOnCacheMiss Option = iota + 1

	// PresumeKeyNotExists directives that when dealing with a Get operation and failed to read data from cache,
	// we presume that the key does not exist in Store. The actual existences will be checked before the
	// transaction's commit.
	// This option is an optimization for frequent checks during a transaction, e.g. batch inserts.
	PresumeKeyNotExists
)

// Transaction defines the interface for operations inside a Transaction.
// This is not thread safe.
type Transaction interface {
	// Get gets the value for key k from KV store.
	Get(k Key) ([]byte, error)
	// BatchPrefetch fetches values from KV storage to cache for later use.
	BatchPrefetch(keys []Key) error
	// RangePrefetch fetches values in the range [start, end] from KV storage
	// to cache for later use. Maximum number of values is up to limit.
	RangePrefetch(start, end Key, limit int) error
	// Set sets the value for key k as v into KV store.
	Set(k Key, v []byte) error
	// Seek searches for the entry with key k in KV store.
	Seek(k Key) (Iterator, error)
	// Inc increases the value for key k in KV store by step.
	Inc(k Key, step int64) (int64, error)
	// GetInt64 get int64 which created by Inc method.
	GetInt64(k Key) (int64, error)
	// Delete removes the entry for key k from KV store.
	Delete(k Key) error
	// Commit commits the transaction operations to KV store.
	Commit() error
	// CommittedVersion returns the version of this committed transaction. If this
	// transaction has not been committed, returns ErrNotCommitted error.
	CommittedVersion() (Version, error)
	// Rollback undoes the transaction operations to KV store.
	Rollback() error
	// String implements fmt.Stringer interface.
	String() string
	// LockKeys tries to lock the entries with the keys in KV store.
	LockKeys(keys ...Key) error
	// SetOption sets an option with a value, when val is nil, uses the default
	// value of this option.
	SetOption(opt Option, val interface{})
	// DelOption deletes an option.
	DelOption(opt Option)
}

// MvccSnapshot is used to get/seek a specific version in a snapshot.
type MvccSnapshot interface {
	// MvccGet returns the specific version of given key, if the version doesn't
	// exist, returns the nearest(lower) version's data.
	MvccGet(k Key, ver Version) ([]byte, error)
	// MvccIterator seeks to the key in the specific version's snapshot, if the
	// version doesn't exist, returns the nearest(lower) version's snaphot.
	NewMvccIterator(k Key, ver Version) Iterator
	// Release releases this snapshot.
	MvccRelease()
}

// Snapshot defines the interface for the snapshot fetched from KV store.
type Snapshot interface {
	// Get gets the value for key k from snapshot.
	Get(k Key) ([]byte, error)
	// BatchGet gets a batch of values from snapshot.
	BatchGet(keys []Key) (map[string][]byte, error)
	// RangeGet gets values in the range [start, end] from snapshot. Maximum
	// number of values is up to limit.
	RangeGet(start, end Key, limit int) (map[string][]byte, error)
	// NewIterator gets a new iterator on the snapshot.
	NewIterator(param interface{}) Iterator
	// Release releases the snapshot to store.
	Release()
}

// MemBuffer is the interface for transaction buffer of update in a transaction
type MemBuffer interface {
	// Get gets the value for key k from buffer. If not found, it returns ErrNotExist.
	Get(k Key) ([]byte, error)
	// Set associates key with value
	Set([]byte, []byte) error
	// NewIterator gets a new iterator on the buffer.
	NewIterator(param interface{}) Iterator
	// Release releases the buffer.
	Release()
}

// Driver is the interface that must be implemented by a KV storage.
type Driver interface {
	// Open returns a new Storage.
	// The schema is the string for storage specific format.
	Open(schema string) (Storage, error)
}

// Storage defines the interface for storage.
// Isolation should be at least SI(SNAPSHOT ISOLATION)
type Storage interface {
	// Begin transaction
	Begin() (Transaction, error)
	// GetSnapshot gets a snaphot that is able to read any data which data is <= ver.
	// if ver is MaxVersion or > current max committed version, we will use current version for this snapshot.
	GetSnapshot(ver Version) (MvccSnapshot, error)
	// Close store
	Close() error
	// Storage's unique ID
	UUID() string
	// CurrentVersion returns current max committed version.
	CurrentVersion() (Version, error)
}

// FnKeyCmp is the function for iterator the keys
type FnKeyCmp func(key Key) bool

// Iterator is the interface for a interator on KV store.
type Iterator interface {
	Next() error
	Value() []byte
	Key() string
	Valid() bool
	Close()
}

// IndexIterator is the interface for iterator of index data on KV store.
type IndexIterator interface {
	Next() (k []interface{}, h int64, err error)
	Close()
}

// Index is the interface for index data on KV store.
type Index interface {
	Create(txn Transaction, indexedValues []interface{}, h int64) error                          // supports insert into statement
	Delete(txn Transaction, indexedValues []interface{}, h int64) error                          // supports delete from statement
	Drop(txn Transaction) error                                                                  // supports drop table, drop index statements
	Exist(txn Transaction, indexedValues []interface{}, h int64) (bool, int64, error)            // supports check index exist
	GenIndexKey(indexedValues []interface{}, h int64) (key []byte, distinct bool, err error)     // supports index check
	Seek(txn Transaction, indexedValues []interface{}) (iter IndexIterator, hit bool, err error) // supports where clause
	SeekFirst(txn Transaction) (iter IndexIterator, err error)                                   // supports aggregate min / ascending order by
}
<commit_msg>*: address comments<commit_after>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package kv

import (
	"bytes"
	"math"

	"github.com/juju/errors"
)

// Key represents high-level Key type.
type Key []byte

// Next returns the next key in byte-order.
func (k Key) Next() Key {
	// add 0x0 to the end of key
	buf := make([]byte, len([]byte(k))+1)
	copy(buf, []byte(k))
	return buf
}

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k Key) Cmp(another Key) int {
	return bytes.Compare(k, another)
}

// EncodedKey represents encoded key in low-level storage engine.
type EncodedKey []byte

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k EncodedKey) Cmp(another EncodedKey) int {
	return bytes.Compare(k, another)
}

// Next returns the next key in byte-order.
func (k EncodedKey) Next() EncodedKey {
	return EncodedKey(bytes.Join([][]byte{k, Key{0}}, nil))
}

// VersionProvider provides increasing IDs.
type VersionProvider interface {
	CurrentVersion() (Version, error)
}

// Version is the wrapper of KV's version.
type Version struct {
	Ver uint64
}

var (
	// MaxVersion is the maximum version, notice that it's not a valid version.
	MaxVersion = Version{Ver: math.MaxUint64}
	// MinVersion is the minimum version, it's not a valid version, too.
	MinVersion = Version{Ver: 0}
)

// NewVersion creates a new Version struct.
func NewVersion(v uint64) Version {
	return Version{
		Ver: v,
	}
}

// Cmp returns the comparison result of two versions.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (v Version) Cmp(another Version) int {
	if v.Ver > another.Ver {
		return 1
	} else if v.Ver < another.Ver {
		return -1
	}
	return 0
}

// DecodeFn is a function that decodes data after fetching from store.
type DecodeFn func(raw interface{}) (interface{}, error)

// EncodeFn is a function that encodes data before putting into store.
type EncodeFn func(raw interface{}) (interface{}, error)

// ErrNotCommitted is the error returned by CommitVersion when this
// transaction is not committed.
var ErrNotCommitted = errors.New("this transaction is not committed")

// Option is used for customizing kv store's behaviors during a transaction.
type Option int

// Options is an interface of a set of options. Each option is associated with a value.
type Options interface {
	// Get gets an option value.
	Get(opt Option) (v interface{}, ok bool)
}

const (
	// RangePrefetchOnCacheMiss directives that when dealing with a Get operation but failing to read data from cache,
	// it will launch a RangePrefetch to underlying storage instead of Get. The range starts from requested key and
	// has a limit of the option value. The feature is disabled if option value <= 0 or value type is not int.
	// This option is particularly useful when we have to do sequential Gets, e.g. table scans.
	RangePrefetchOnCacheMiss Option = iota + 1

	// PresumeKeyNotExists directives that when dealing with a Get operation but failing to read data from cache,
	// we presume that the key does not exist in Store. The actual existence will be checked before the
	// transaction's commit.
	// This option is an optimization for frequent checks during a transaction, e.g. batch inserts.
	PresumeKeyNotExists
)

// Transaction defines the interface for operations inside a Transaction.
// This is not thread safe.
type Transaction interface {
	// Get gets the value for key k from KV store.
	Get(k Key) ([]byte, error)
	// BatchPrefetch fetches values from KV storage to cache for later use.
	BatchPrefetch(keys []Key) error
	// RangePrefetch fetches values in the range [start, end] from KV storage
	// to cache for later use. Maximum number of values is up to limit.
	RangePrefetch(start, end Key, limit int) error
	// Set sets the value for key k as v into KV store.
	Set(k Key, v []byte) error
	// Seek searches for the entry with key k in KV store.
	Seek(k Key) (Iterator, error)
	// Inc increases the value for key k in KV store by step.
	Inc(k Key, step int64) (int64, error)
	// GetInt64 get int64 which created by Inc method.
	GetInt64(k Key) (int64, error)
	// Delete removes the entry for key k from KV store.
	Delete(k Key) error
	// Commit commits the transaction operations to KV store.
	Commit() error
	// CommittedVersion returns the version of this committed transaction. If this
	// transaction has not been committed, returns ErrNotCommitted error.
	CommittedVersion() (Version, error)
	// Rollback undoes the transaction operations to KV store.
	Rollback() error
	// String implements fmt.Stringer interface.
	String() string
	// LockKeys tries to lock the entries with the keys in KV store.
	LockKeys(keys ...Key) error
	// SetOption sets an option with a value, when val is nil, uses the default
	// value of this option.
	SetOption(opt Option, val interface{})
	// DelOption deletes an option.
	DelOption(opt Option)
}

// MvccSnapshot is used to get/seek a specific version in a snapshot.
type MvccSnapshot interface {
	// MvccGet returns the specific version of given key, if the version doesn't
	// exist, returns the nearest(lower) version's data.
	MvccGet(k Key, ver Version) ([]byte, error)
	// MvccIterator seeks to the key in the specific version's snapshot, if the
	// version doesn't exist, returns the nearest(lower) version's snaphot.
	NewMvccIterator(k Key, ver Version) Iterator
	// Release releases this snapshot.
	MvccRelease()
}

// Snapshot defines the interface for the snapshot fetched from KV store.
type Snapshot interface {
	// Get gets the value for key k from snapshot.
	Get(k Key) ([]byte, error)
	// BatchGet gets a batch of values from snapshot.
	BatchGet(keys []Key) (map[string][]byte, error)
	// RangeGet gets values in the range [start, end] from snapshot. Maximum
	// number of values is up to limit.
	RangeGet(start, end Key, limit int) (map[string][]byte, error)
	// NewIterator gets a new iterator on the snapshot.
	NewIterator(param interface{}) Iterator
	// Release releases the snapshot to store.
	Release()
}

// MemBuffer is the interface for transaction buffer of update in a transaction
type MemBuffer interface {
	// Get gets the value for key k from buffer. If not found, it returns ErrNotExist.
	Get(k Key) ([]byte, error)
	// Set associates key with value
	Set([]byte, []byte) error
	// NewIterator gets a new iterator on the buffer.
	NewIterator(param interface{}) Iterator
	// Release releases the buffer.
	Release()
}

// Driver is the interface that must be implemented by a KV storage.
type Driver interface {
	// Open returns a new Storage.
	// The schema is the string for storage specific format.
	Open(schema string) (Storage, error)
}

// Storage defines the interface for storage.
// Isolation should be at least SI(SNAPSHOT ISOLATION)
type Storage interface {
	// Begin transaction
	Begin() (Transaction, error)
	// GetSnapshot gets a snaphot that is able to read any data which data is <= ver.
	// if ver is MaxVersion or > current max committed version, we will use current version for this snapshot.
	GetSnapshot(ver Version) (MvccSnapshot, error)
	// Close store
	Close() error
	// Storage's unique ID
	UUID() string
	// CurrentVersion returns current max committed version.
	CurrentVersion() (Version, error)
}

// FnKeyCmp is the function for iterator the keys
type FnKeyCmp func(key Key) bool

// Iterator is the interface for a interator on KV store.
type Iterator interface {
	Next() error
	Value() []byte
	Key() string
	Valid() bool
	Close()
}

// IndexIterator is the interface for iterator of index data on KV store.
type IndexIterator interface {
	Next() (k []interface{}, h int64, err error)
	Close()
}

// Index is the interface for index data on KV store.
type Index interface {
	Create(txn Transaction, indexedValues []interface{}, h int64) error                          // supports insert into statement
	Delete(txn Transaction, indexedValues []interface{}, h int64) error                          // supports delete from statement
	Drop(txn Transaction) error                                                                  // supports drop table, drop index statements
	Exist(txn Transaction, indexedValues []interface{}, h int64) (bool, int64, error)            // supports check index exist
	GenIndexKey(indexedValues []interface{}, h int64) (key []byte, distinct bool, err error)     // supports index check
	Seek(txn Transaction, indexedValues []interface{}) (iter IndexIterator, hit bool, err error) // supports where clause
	SeekFirst(txn Transaction) (iter IndexIterator, err error)                                   // supports aggregate min / ascending order by
}
<|endoftext|>


<commit_before>package kv

// KeyValueStore is universal interface for a key-value store with string keys and JSON serializable struct values
type KeyValueStore interface {
	Get(key string, value StoreValue) (bool, error)
	Put(key string, value StoreValue) error
	Delete(key string) error
}

// StoreValue is deserialized entry from store
// StoreValue must be a JSON serializable struct
type StoreValue interface{}

<commit_msg>Update doc<commit_after>/*

Kasper companion library for stateful stream processing.

 */

package kv

// KeyValueStore is universal interface for a key-value store with string keys and JSON serializable struct values
type KeyValueStore interface {
	Get(key string, value StoreValue) (bool, error)
	Put(key string, value StoreValue) error
	Delete(key string) error
}

// StoreValue is deserialized entry from store
// StoreValue must be a JSON serializable struct
type StoreValue interface{}

<|endoftext|>


<commit_before>package mutagen

// LegalNotice provides license notices for Mutagen itself and any third-party
// dependencies.
const LegalNotice = `Mutagen

Copyright (c) 2016 Jacob Howard. All rights reserved.

Released under the terms of the MIT License.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Mutagen makes use of the following third-party software:

errors (https://github.com/pkg/errors)

Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pflag (https://github.com/ogier/pflag)

Copyright (c) 2012 Alex Ogier. All rights reserved.
Copyright (c) 2012 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of Google Inc. nor the names of its contributors may be used
  to endorse or promote products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
`
<commit_msg>Small formatting fix for legal information.<commit_after>package mutagen

// LegalNotice provides license notices for Mutagen itself and any third-party
// dependencies.
const LegalNotice = `Mutagen

Copyright (c) 2016 Jacob Howard. All rights reserved.

Released under the terms of the MIT License.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Mutagen makes use of the following third-party software:

errors (https://github.com/pkg/errors)

Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pflag (https://github.com/ogier/pflag)

Copyright (c) 2012 Alex Ogier. All rights reserved.
Copyright (c) 2012 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of Google Inc. nor the names of its contributors may be used
  to endorse or promote products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
`
<|endoftext|>