<commit_before>package broker

import (
	"github.com/travisjeffery/jocko"
	"github.com/travisjeffery/simplelog"
)

type BrokerFn func(b *Broker)

func LogDir(logDir string) BrokerFn {
	return func(b *Broker) {
		b.logDir = logDir
	}
}

func Addr(brokerAddr string) BrokerFn {
	return func(b *Broker) {
		b.brokerAddr = brokerAddr
	}
}

func Logger(logger *simplelog.Logger) BrokerFn {
	return func(b *Broker) {
		b.logger = logger
	}
}

func Serf(serf jocko.Serf) BrokerFn {
	return func(b *Broker) {
		b.serf = serf
	}
}

func Raft(raft jocko.Raft) BrokerFn {
	return func(b *Broker) {
		b.raft = raft
	}
}

type ReplicatorFn func(r *Replicator)

func ReplicatorReplicaID(id int32) ReplicatorFn {
	return func(r *Replicator) {
		r.replicaID = id
	}
}

func ReplicatorFetchSize(size int32) ReplicatorFn {
	return func(r *Replicator) {
		r.fetchSize = size
	}
}

func ReplicatorMinBytes(size int32) ReplicatorFn {
	return func(r *Replicator) {
		r.minBytes = size
	}
}

func ReplicatorMaxWaitTime(time int32) ReplicatorFn {
	return func(r *Replicator) {
		r.maxWaitTime = time
	}
}

func ReplicatorProxy(proxy jocko.Proxy) ReplicatorFn {
	return func(r *Replicator) {
		r.proxy = proxy
	}
}
<commit_msg>broker: add docs for opts<commit_after>package broker

import (
	"github.com/travisjeffery/jocko"
	"github.com/travisjeffery/simplelog"
)

// BrokerFn is used to configure brokers.
type BrokerFn func(b *Broker)

// LogDir is used to set the directory the broker stores its data logs.
func LogDir(logDir string) BrokerFn {
	return func(b *Broker) {
		b.logDir = logDir
	}
}

// Addr is used to set the broker's client addr.
func Addr(brokerAddr string) BrokerFn {
	return func(b *Broker) {
		b.brokerAddr = brokerAddr
	}
}

// Logger is used to set the broker's logger.
func Logger(logger *simplelog.Logger) BrokerFn {
	return func(b *Broker) {
		b.logger = logger
	}
}

// Serf is used to set the broker's serf instance.
func Serf(serf jocko.Serf) BrokerFn {
	return func(b *Broker) {
		b.serf = serf
	}
}

// Raft is used to set the broker's raft instance.
func Raft(raft jocko.Raft) BrokerFn {
	return func(b *Broker) {
		b.raft = raft
	}
}

// ReplicatorFn is used to configure replicators.
type ReplicatorFn func(r *Replicator)

// ReplicatorReplicaID is used to set the ID of the broker this replicator should replicate. Similar to the consumer config in Kafka.
func ReplicatorReplicaID(id int32) ReplicatorFn {
	return func(r *Replicator) {
		r.replicaID = id
	}
}

// ReplicatorFetchSize is used to set replicator's fetch request size.
func ReplicatorFetchSize(size int32) ReplicatorFn {
	return func(r *Replicator) {
		r.fetchSize = size
	}
}

// ReplicatorMinBytes is used to set the replicator's min byte request size. Similar to the consumer config in Kafka.
func ReplicatorMinBytes(size int32) ReplicatorFn {
	return func(r *Replicator) {
		r.minBytes = size
	}
}

// ReplicatorMaxWaitTime is used to set the replicator's request's max wait time. Similar to the consumer config in Kakfa.
func ReplicatorMaxWaitTime(time int32) ReplicatorFn {
	return func(r *Replicator) {
		r.maxWaitTime = time
	}
}

// ReplicatorProxy is used to set the replicator's proxy which is used to proxy requests from one broker to another.
func ReplicatorProxy(proxy jocko.Proxy) ReplicatorFn {
	return func(r *Replicator) {
		r.proxy = proxy
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 fatedier, fatedier@gmail.com
//
// 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 vhost

import (
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/fatedier/frp/utils/version"
)

const (
	NotFound = `<!DOCTYPE html>

<title>Not Found</title>

The page you visit not found.

Sorry, the page you are looking for is currently unavailable.

Please try again later.

The server is powered by frp.

Faithfully yours, frp.

`
)

func notFoundResponse() *http.Response {
	header := make(http.Header)
	header.Set("server", "frp/"+version.Full())
	res := &http.Response{
		Status:     "Not Found",
		StatusCode: 400,
		Proto:      "HTTP/1.0",
		ProtoMajor: 1,
		ProtoMinor: 0,
		Header:     header,
		Body:       ioutil.NopCloser(strings.NewReader(NotFound)),
	}
	return res
}
<commit_msg>vhost: fix 404 page<commit_after>// Copyright 2017 fatedier, fatedier@gmail.com
//
// 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 vhost

import (
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/fatedier/frp/utils/version"
)

const (
	NotFound = `<!DOCTYPE html>

<title>Not Found</title>

The page you visit not found.

Sorry, the page you are looking for is currently unavailable.

Please try again later.

The server is powered by frp.

Faithfully yours, frp.

`
)

func notFoundResponse() *http.Response {
	header := make(http.Header)
	header.Set("server", "frp/"+version.Full())
	header.Set("Content-Type", "text/html")
	res := &http.Response{
		Status:     "Not Found",
		StatusCode: 404,
		Proto:      "HTTP/1.0",
		ProtoMajor: 1,
		ProtoMinor: 0,
		Header:     header,
		Body:       ioutil.NopCloser(strings.NewReader(NotFound)),
	}
	return res
}
<|endoftext|>


<commit_before>package registry

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/docker/distribution/reference"
	"github.com/estesp/manifest-tool/v2/pkg/store"
	"github.com/estesp/manifest-tool/v2/pkg/types"
	"github.com/estesp/manifest-tool/v2/pkg/util"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/sirupsen/logrus"
)

func PushManifestList(username, password string, input types.YAMLInput, ignoreMissing, insecure, plainHttp bool, configDir string) (hash string, length int, err error) {
	// resolve the target image reference for the combined manifest list/index
	targetRef, err := reference.ParseNormalizedNamed(input.Image)
	if err != nil {
		return hash, length, fmt.Errorf("Error parsing name for manifest list (%s): %v", input.Image, err)
	}

	var configDirs []string
	if configDir != "" {
		configDirs = append(configDirs, configDir)
	}
	resolver := util.NewResolver(username, password, insecure,
		plainHttp, configDirs...)

	imageType := types.Docker
	manifestList := types.ManifestList{
		Name:      input.Image,
		Reference: targetRef,
		Resolver:  resolver,
		Type:      imageType,
	}
	// create an in-memory store for OCI descriptors and content used during the push operation
	memoryStore := store.NewMemoryStore()

	logrus.Info("Retrieving digests of member images")
	for _, img := range input.Manifests {
		ref, err := util.ParseName(img.Image)
		if err != nil {
			return hash, length, fmt.Errorf("Unable to parse image reference: %s: %v", img.Image, err)
		}
		if reference.Domain(targetRef) != reference.Domain(ref) {
			return hash, length, fmt.Errorf("Cannot use source images from a different registry than the target image: %s != %s", reference.Domain(ref), reference.Domain(targetRef))
		}
		descriptor, err := FetchDescriptor(resolver, memoryStore, ref)
		if err != nil {
			if ignoreMissing {
				logrus.Warnf("Couldn't access image '%q'. Skipping due to 'ignore missing' configuration.", img.Image)
				continue
			}
			return hash, length, fmt.Errorf("Inspect of image %q failed with error: %v", img.Image, err)
		}

		// Check that only member images of type OCI manifest or Docker v2.2 manifest are included
		switch descriptor.MediaType {
		case ocispec.MediaTypeImageIndex, types.MediaTypeDockerSchema2ManifestList:
			return hash, length, fmt.Errorf("Cannot include an image in a manifest list/index which is already a multi-platform image: %s", img.Image)
		case ocispec.MediaTypeImageManifest, types.MediaTypeDockerSchema2Manifest:
			// valid image type to include
		default:
			return hash, length, fmt.Errorf("Cannot include unknown media type '%s' in a manifest list/index push", descriptor.MediaType)
		}
		_, db, _ := memoryStore.Get(descriptor)
		var man ocispec.Manifest
		if err := json.Unmarshal(db, &man); err != nil {
			return hash, length, fmt.Errorf("Could not unmarshal manifest object from descriptor for image '%s': %v", img.Image, err)
		}
		_, cb, _ := memoryStore.Get(man.Config)
		var imgConfig types.Image
		if err := json.Unmarshal(cb, &imgConfig); err != nil {
			return hash, length, fmt.Errorf("Could not unmarshal config object from descriptor for image '%s': %v", img.Image, err)
		}
		// set labels for handling distribution source to get automatic cross-repo blob mounting for the layers
		info, _ := memoryStore.Info(context.TODO(), descriptor.Digest)
		for _, layer := range man.Layers {
			// only need to handle cross-repo blob mount for distributable layer types
			if skippable(layer.MediaType) {
				continue
			}
			info.Digest = layer.Digest
			if _, err := memoryStore.Update(context.TODO(), info, ""); err != nil {
				logrus.Warnf("couldn't update in-memory store labels for %v: %v", info.Digest, err)
			}
		}

		// finalize the platform object that will be used to push with this manifest
		descriptor.Platform, err = resolvePlatform(descriptor, img, imgConfig)
		if err != nil {
			return hash, length, fmt.Errorf("Unable to create platform object for manifest %s: %v", descriptor.Digest.String(), err)
		}
		manifest := types.Manifest{
			Descriptor: descriptor,
			PushRef:    false,
		}

		if reference.Path(ref) != reference.Path(targetRef) {
			// the target manifest list/index is located in a different repo; need to push
			// the manifest as a digest to the target repo before the list/index is pushed
			manifest.PushRef = true
		}
		manifestList.Manifests = append(manifestList.Manifests, manifest)
	}

	if ignoreMissing && len(manifestList.Manifests) == 0 {
		// we need to verify we at least have one valid entry in the list
		// otherwise our manifest list will be totally empty
		return hash, length, fmt.Errorf("all entries were skipped due to missing source image references; no manifest list to push")
	}

	return Push(manifestList, input.Tags, memoryStore)
}

func resolvePlatform(descriptor ocispec.Descriptor, img types.ManifestEntry, imgConfig types.Image) (*ocispec.Platform, error) {
	platform := &img.Platform
	if platform == nil {
		platform = &ocispec.Platform{}
	}
	// fill os/arch from inspected image if not specified in input YAML
	if platform.OS == "" && platform.Architecture == "" {
		// prefer a full platform object, if one is already available (and appears to have meaningful content)
		if descriptor.Platform != nil && (descriptor.Platform.OS != "" || descriptor.Platform.Architecture != "") {
			platform = descriptor.Platform
		} else if imgConfig.OS != "" || imgConfig.Architecture != "" {
			platform.OS = imgConfig.OS
			platform.Architecture = imgConfig.Architecture
		}
	}
	// if Variant is specified in the origin image but not the descriptor or YAML, bubble it up
	if imgConfig.Variant != "" && platform.Variant == "" {
		platform.Variant = imgConfig.Variant
	}
	// Windows: if the origin image has OSFeature and/or OSVersion information, and
	// these values were not specified in the creation YAML, then
	// retain the origin values in the Platform definition for the manifest list:
	if imgConfig.OSVersion != "" && platform.OSVersion == "" {
		platform.OSVersion = imgConfig.OSVersion
	}
	if len(imgConfig.OSFeatures) > 0 && len(platform.OSFeatures) == 0 {
		platform.OSFeatures = imgConfig.OSFeatures
	}

	// validate os/arch input
	if !util.IsValidOSArch(platform.OS, platform.Architecture, platform.Variant) {
		return nil, fmt.Errorf("Manifest entry for image %s has unsupported os/arch or os/arch/variant combination: %s/%s/%s", img.Image, platform.OS, platform.Architecture, platform.Variant)
	}
	return platform, nil
}

func skippable(mediaType string) bool {
	// skip foreign/non-distributable layers
	if strings.Index(mediaType, "foreign") > 0 || strings.Index(mediaType, "nondistributable") > 0 {
		return true
	}
	// skip manifests (OCI or Dockerv2) as they are already handled on push references code
	switch mediaType {
	case ocispec.MediaTypeImageManifest, types.MediaTypeDockerSchema2Manifest:
		return true
	}
	return false
}
<commit_msg>Reword registry mismatch message<commit_after>package registry

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/docker/distribution/reference"
	"github.com/estesp/manifest-tool/v2/pkg/store"
	"github.com/estesp/manifest-tool/v2/pkg/types"
	"github.com/estesp/manifest-tool/v2/pkg/util"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/sirupsen/logrus"
)

func PushManifestList(username, password string, input types.YAMLInput, ignoreMissing, insecure, plainHttp bool, configDir string) (hash string, length int, err error) {
	// resolve the target image reference for the combined manifest list/index
	targetRef, err := reference.ParseNormalizedNamed(input.Image)
	if err != nil {
		return hash, length, fmt.Errorf("Error parsing name for manifest list (%s): %v", input.Image, err)
	}

	var configDirs []string
	if configDir != "" {
		configDirs = append(configDirs, configDir)
	}
	resolver := util.NewResolver(username, password, insecure,
		plainHttp, configDirs...)

	imageType := types.Docker
	manifestList := types.ManifestList{
		Name:      input.Image,
		Reference: targetRef,
		Resolver:  resolver,
		Type:      imageType,
	}
	// create an in-memory store for OCI descriptors and content used during the push operation
	memoryStore := store.NewMemoryStore()

	logrus.Info("Retrieving digests of member images")
	for _, img := range input.Manifests {
		ref, err := util.ParseName(img.Image)
		if err != nil {
			return hash, length, fmt.Errorf("Unable to parse image reference: %s: %v", img.Image, err)
		}
		if reference.Domain(targetRef) != reference.Domain(ref) {
			return hash, length, fmt.Errorf("Source image (%s) registry does not match target image (%s) registry", ref, targetRef)
		}
		descriptor, err := FetchDescriptor(resolver, memoryStore, ref)
		if err != nil {
			if ignoreMissing {
				logrus.Warnf("Couldn't access image '%q'. Skipping due to 'ignore missing' configuration.", img.Image)
				continue
			}
			return hash, length, fmt.Errorf("Inspect of image %q failed with error: %v", img.Image, err)
		}

		// Check that only member images of type OCI manifest or Docker v2.2 manifest are included
		switch descriptor.MediaType {
		case ocispec.MediaTypeImageIndex, types.MediaTypeDockerSchema2ManifestList:
			return hash, length, fmt.Errorf("Cannot include an image in a manifest list/index which is already a multi-platform image: %s", img.Image)
		case ocispec.MediaTypeImageManifest, types.MediaTypeDockerSchema2Manifest:
			// valid image type to include
		default:
			return hash, length, fmt.Errorf("Cannot include unknown media type '%s' in a manifest list/index push", descriptor.MediaType)
		}
		_, db, _ := memoryStore.Get(descriptor)
		var man ocispec.Manifest
		if err := json.Unmarshal(db, &man); err != nil {
			return hash, length, fmt.Errorf("Could not unmarshal manifest object from descriptor for image '%s': %v", img.Image, err)
		}
		_, cb, _ := memoryStore.Get(man.Config)
		var imgConfig types.Image
		if err := json.Unmarshal(cb, &imgConfig); err != nil {
			return hash, length, fmt.Errorf("Could not unmarshal config object from descriptor for image '%s': %v", img.Image, err)
		}
		// set labels for handling distribution source to get automatic cross-repo blob mounting for the layers
		info, _ := memoryStore.Info(context.TODO(), descriptor.Digest)
		for _, layer := range man.Layers {
			// only need to handle cross-repo blob mount for distributable layer types
			if skippable(layer.MediaType) {
				continue
			}
			info.Digest = layer.Digest
			if _, err := memoryStore.Update(context.TODO(), info, ""); err != nil {
				logrus.Warnf("couldn't update in-memory store labels for %v: %v", info.Digest, err)
			}
		}

		// finalize the platform object that will be used to push with this manifest
		descriptor.Platform, err = resolvePlatform(descriptor, img, imgConfig)
		if err != nil {
			return hash, length, fmt.Errorf("Unable to create platform object for manifest %s: %v", descriptor.Digest.String(), err)
		}
		manifest := types.Manifest{
			Descriptor: descriptor,
			PushRef:    false,
		}

		if reference.Path(ref) != reference.Path(targetRef) {
			// the target manifest list/index is located in a different repo; need to push
			// the manifest as a digest to the target repo before the list/index is pushed
			manifest.PushRef = true
		}
		manifestList.Manifests = append(manifestList.Manifests, manifest)
	}

	if ignoreMissing && len(manifestList.Manifests) == 0 {
		// we need to verify we at least have one valid entry in the list
		// otherwise our manifest list will be totally empty
		return hash, length, fmt.Errorf("all entries were skipped due to missing source image references; no manifest list to push")
	}

	return Push(manifestList, input.Tags, memoryStore)
}

func resolvePlatform(descriptor ocispec.Descriptor, img types.ManifestEntry, imgConfig types.Image) (*ocispec.Platform, error) {
	platform := &img.Platform
	if platform == nil {
		platform = &ocispec.Platform{}
	}
	// fill os/arch from inspected image if not specified in input YAML
	if platform.OS == "" && platform.Architecture == "" {
		// prefer a full platform object, if one is already available (and appears to have meaningful content)
		if descriptor.Platform != nil && (descriptor.Platform.OS != "" || descriptor.Platform.Architecture != "") {
			platform = descriptor.Platform
		} else if imgConfig.OS != "" || imgConfig.Architecture != "" {
			platform.OS = imgConfig.OS
			platform.Architecture = imgConfig.Architecture
		}
	}
	// if Variant is specified in the origin image but not the descriptor or YAML, bubble it up
	if imgConfig.Variant != "" && platform.Variant == "" {
		platform.Variant = imgConfig.Variant
	}
	// Windows: if the origin image has OSFeature and/or OSVersion information, and
	// these values were not specified in the creation YAML, then
	// retain the origin values in the Platform definition for the manifest list:
	if imgConfig.OSVersion != "" && platform.OSVersion == "" {
		platform.OSVersion = imgConfig.OSVersion
	}
	if len(imgConfig.OSFeatures) > 0 && len(platform.OSFeatures) == 0 {
		platform.OSFeatures = imgConfig.OSFeatures
	}

	// validate os/arch input
	if !util.IsValidOSArch(platform.OS, platform.Architecture, platform.Variant) {
		return nil, fmt.Errorf("Manifest entry for image %s has unsupported os/arch or os/arch/variant combination: %s/%s/%s", img.Image, platform.OS, platform.Architecture, platform.Variant)
	}
	return platform, nil
}

func skippable(mediaType string) bool {
	// skip foreign/non-distributable layers
	if strings.Index(mediaType, "foreign") > 0 || strings.Index(mediaType, "nondistributable") > 0 {
		return true
	}
	// skip manifests (OCI or Dockerv2) as they are already handled on push references code
	switch mediaType {
	case ocispec.MediaTypeImageManifest, types.MediaTypeDockerSchema2Manifest:
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package ssdp

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"net/textproto"
	"strconv"
	"strings"
	"time"
)

const (
	AddrString            = "239.255.255.250:1900"
	rootDevice            = "upnp:rootdevice"
	DefaultNotifyInterval = 30
	aliveNTS              = "ssdp:alive"
)

var (
	NetAddr *net.UDPAddr
)

func init() {
	var err error
	NetAddr, err = net.ResolveUDPAddr("udp4", AddrString)
	if err != nil {
		panic(err)
	}
}

type badStringError struct {
	what string
	str  string
}

func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }

type Request struct {
	Method     string
	ProtoMajor int
	ProtoMinor int
	Header     http.Header
}

func ReadRequest(b *bufio.Reader) (req *Request, err error) {
	tp := textproto.NewReader(b)
	var s string
	if s, err = tp.ReadLine(); err != nil {
		return nil, err
	}
	defer func() {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
	}()

	var f []string
	// TODO a split that only allows N values?
	if f = strings.Split(s, " "); len(f) != 3 {
		return nil, &badStringError{"malformed request line", s}
	}
	if f[1] != "*" {
		return nil, &badStringError{"bad URL request", f[1]}
	}
	req = &Request{
		Method: f[0],
	}
	var ok bool
	if req.ProtoMajor, req.ProtoMinor, ok = http.ParseHTTPVersion(f[2]); !ok {
		return nil, &badStringError{"malformed HTTP version", f[2]}
	}

	mimeHeader, err := tp.ReadMIMEHeader()
	if err != nil {
		return nil, err
	}
	req.Header = http.Header(mimeHeader)
	return
}

type Server struct {
	conn      *net.UDPConn
	Interface net.Interface
	Server    string
	Services  []string
	Devices   []string
	Location  func(net.IP) string
	UUID      string
}

func makeConn(ifi net.Interface) (ret *net.UDPConn, err error) {
	ret, err = net.ListenMulticastUDP("udp", &ifi, NetAddr)
	if err != nil {
		return
	}
	if err := setTTL(ret, 2); err != nil {
		log.Println(err)
	}
	return
}

func (me *Server) serve() {
	for {
		b := make([]byte, me.Interface.MTU)
		n, addr, err := me.conn.ReadFromUDP(b)
		if err != nil {
			panic(err)
		}
		go me.handle(b[:n], addr)
	}
}

func (me *Server) Serve() (err error) {
	me.conn, err = makeConn(me.Interface)
	if err != nil {
		return
	}
	defer me.conn.Close()
	go me.serve()
	for {
		addrs, err := me.Interface.Addrs()
		if err != nil {
			return err
		}
		for _, addr := range addrs {
			ip := func() net.IP {
				switch val := addr.(type) {
				case *net.IPNet:
					return val.IP
				case *net.IPAddr:
					return val.IP
				}
				panic(fmt.Sprint("unexpected addr type:", addr))
			}()
			me.notifyAll(ip, aliveNTS)
		}
		time.Sleep(60 * time.Second)
	}
	panic(nil)
}

func (me *Server) usnFromTarget(target string) string {
	if target == me.UUID {
		return target
	}
	return me.UUID + "::" + target
}

func (me *Server) makeNotifyMessage(location, target, nts string) []byte {
	lines := [...][2]string{
		{"HOST", AddrString},
		{"CACHE-CONTROL", "max-age=120"},
		{"LOCATION", location},
		{"NT", target},
		{"NTS", nts},
		{"SERVER", me.Server},
		{"USN", me.usnFromTarget(target)},
	}
	buf := &bytes.Buffer{}
	fmt.Fprint(buf, "NOTIFY * HTTP/1.1\r\n")
	for _, pair := range lines {
		fmt.Fprintf(buf, "%s: %s\r\n", pair[0], pair[1])
	}
	fmt.Fprint(buf, "\r\n")
	return buf.Bytes()
}

func (me *Server) delayedSend(delay time.Duration, buf []byte, addr *net.UDPAddr) {
	time.Sleep(delay)
	n, err := me.conn.WriteToUDP(buf, addr)
	if err != nil {
		panic(err)
	}
	if n != len(buf) {
		panic(err)
	}
}

func (me *Server) notifyAll(ip net.IP, nts string) {
	loc := me.Location(ip)
	for _, type_ := range me.allTypes() {
		buf := me.makeNotifyMessage(loc, type_, nts)
		delay := time.Duration(rand.Int63n(int64(100 * time.Millisecond)))
		go me.delayedSend(delay, buf, NetAddr)
	}
}

func (me *Server) allTypes() (ret []string) {
	for _, a := range [][]string{
		{rootDevice, me.UUID},
		me.Devices,
		me.Services,
	} {
		ret = append(ret, a...)
	}
	return
}

func (me *Server) handle(buf []byte, sender *net.UDPAddr) {
	req, err := ReadRequest(bufio.NewReader(bytes.NewReader(buf)))
	if err != nil {
		log.Println(err)
		return
	}
	if req.Method != "M-SEARCH" || req.Header.Get("man") != `"ssdp:discover"` {
		return
	}
	var mx uint
	if req.Header.Get("Host") == AddrString {
		i, err := strconv.ParseUint(req.Header.Get("mx"), 0, 0)
		if err != nil {
			log.Println(err)
			return
		}
		mx = uint(i)
	} else {
		mx = 1
	}
	types := func(st string) []string {
		if st == "ssdp:all" {
			return me.allTypes()
		}
		for _, t := range me.allTypes() {
			if t == st {
				return []string{t}
			}
		}
		return nil
	}(req.Header.Get("st"))
	for _, ip := range func() (ret []net.IP) {
		addrs, err := me.Interface.Addrs()
		if err != nil {
			panic(err)
		}
		for _, addr := range addrs {
			if ip, ok := func() (net.IP, bool) {
				switch data := addr.(type) {
				case *net.IPNet:
					if data.Contains(sender.IP) {
						return data.IP, true
					}
					return nil, false
				case *net.IPAddr:
					return data.IP, true
				}
				panic(addr)
			}(); ok {
				ret = append(ret, ip)
			}
		}
		return
	}() {
		for _, type_ := range types {
			resp := me.makeResponse(ip, type_)
			delay := time.Duration(rand.Int63n(int64(time.Second) * int64(mx)))
			go me.delayedSend(delay, resp, sender)
		}
	}
}

func (me *Server) makeResponse(ip net.IP, targ string) (ret []byte) {
	resp := &http.Response{
		StatusCode: 200,
		ProtoMajor: 1,
		ProtoMinor: 1,
		Header:     make(http.Header),
	}
	for _, pair := range [...][2]string{
		{"CACHE-CONTROL", fmt.Sprintf("max-age=%d", (5*DefaultNotifyInterval)/2)},
		{"EXT", ""},
		{"LOCATION", me.Location(ip)},
		{"SERVER", me.Server},
		{"ST", targ},
		{"USN", me.usnFromTarget(targ)},
	} {
		resp.Header.Set(pair[0], pair[1])
	}
	buf := &bytes.Buffer{}
	if err := resp.Write(buf); err != nil {
		panic(err)
	}
	return buf.Bytes()
}
<commit_msg>Work around a bug in Go<=1.0.2 when http.Response.Request==nil<commit_after>package ssdp

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"net/textproto"
	"strconv"
	"strings"
	"time"
)

const (
	AddrString            = "239.255.255.250:1900"
	rootDevice            = "upnp:rootdevice"
	DefaultNotifyInterval = 30
	aliveNTS              = "ssdp:alive"
)

var (
	NetAddr *net.UDPAddr
)

func init() {
	var err error
	NetAddr, err = net.ResolveUDPAddr("udp4", AddrString)
	if err != nil {
		panic(err)
	}
}

type badStringError struct {
	what string
	str  string
}

func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }

func ReadRequest(b *bufio.Reader) (req *http.Request, err error) {
	tp := textproto.NewReader(b)
	var s string
	if s, err = tp.ReadLine(); err != nil {
		return nil, err
	}
	defer func() {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
	}()

	var f []string
	// TODO a split that only allows N values?
	if f = strings.Split(s, " "); len(f) != 3 {
		return nil, &badStringError{"malformed request line", s}
	}
	if f[1] != "*" {
		return nil, &badStringError{"bad URL request", f[1]}
	}
	req = &http.Request{
		Method: f[0],
	}
	var ok bool
	if req.ProtoMajor, req.ProtoMinor, ok = http.ParseHTTPVersion(f[2]); !ok {
		return nil, &badStringError{"malformed HTTP version", f[2]}
	}

	mimeHeader, err := tp.ReadMIMEHeader()
	if err != nil {
		return nil, err
	}
	req.Header = http.Header(mimeHeader)
	return
}

type Server struct {
	conn      *net.UDPConn
	Interface net.Interface
	Server    string
	Services  []string
	Devices   []string
	Location  func(net.IP) string
	UUID      string
}

func makeConn(ifi net.Interface) (ret *net.UDPConn, err error) {
	ret, err = net.ListenMulticastUDP("udp", &ifi, NetAddr)
	if err != nil {
		return
	}
	if err := setTTL(ret, 2); err != nil {
		log.Println(err)
	}
	return
}

func (me *Server) serve() {
	for {
		b := make([]byte, me.Interface.MTU)
		n, addr, err := me.conn.ReadFromUDP(b)
		if err != nil {
			panic(err)
		}
		go me.handle(b[:n], addr)
	}
}

func (me *Server) Serve() (err error) {
	me.conn, err = makeConn(me.Interface)
	if err != nil {
		return
	}
	defer me.conn.Close()
	go me.serve()
	for {
		addrs, err := me.Interface.Addrs()
		if err != nil {
			return err
		}
		for _, addr := range addrs {
			ip := func() net.IP {
				switch val := addr.(type) {
				case *net.IPNet:
					return val.IP
				case *net.IPAddr:
					return val.IP
				}
				panic(fmt.Sprint("unexpected addr type:", addr))
			}()
			me.notifyAll(ip, aliveNTS)
		}
		time.Sleep(60 * time.Second)
	}
	panic(nil)
}

func (me *Server) usnFromTarget(target string) string {
	if target == me.UUID {
		return target
	}
	return me.UUID + "::" + target
}

func (me *Server) makeNotifyMessage(location, target, nts string) []byte {
	lines := [...][2]string{
		{"HOST", AddrString},
		{"CACHE-CONTROL", "max-age=120"},
		{"LOCATION", location},
		{"NT", target},
		{"NTS", nts},
		{"SERVER", me.Server},
		{"USN", me.usnFromTarget(target)},
	}
	buf := &bytes.Buffer{}
	fmt.Fprint(buf, "NOTIFY * HTTP/1.1\r\n")
	for _, pair := range lines {
		fmt.Fprintf(buf, "%s: %s\r\n", pair[0], pair[1])
	}
	fmt.Fprint(buf, "\r\n")
	return buf.Bytes()
}

func (me *Server) delayedSend(delay time.Duration, buf []byte, addr *net.UDPAddr) {
	time.Sleep(delay)
	n, err := me.conn.WriteToUDP(buf, addr)
	if err != nil {
		panic(err)
	}
	if n != len(buf) {
		panic(err)
	}
}

func (me *Server) notifyAll(ip net.IP, nts string) {
	loc := me.Location(ip)
	for _, type_ := range me.allTypes() {
		buf := me.makeNotifyMessage(loc, type_, nts)
		delay := time.Duration(rand.Int63n(int64(100 * time.Millisecond)))
		go me.delayedSend(delay, buf, NetAddr)
	}
}

func (me *Server) allTypes() (ret []string) {
	for _, a := range [][]string{
		{rootDevice, me.UUID},
		me.Devices,
		me.Services,
	} {
		ret = append(ret, a...)
	}
	return
}

func (me *Server) handle(buf []byte, sender *net.UDPAddr) {
	req, err := ReadRequest(bufio.NewReader(bytes.NewReader(buf)))
	if err != nil {
		log.Println(err)
		return
	}
	if req.Method != "M-SEARCH" || req.Header.Get("man") != `"ssdp:discover"` {
		return
	}
	var mx uint
	if req.Header.Get("Host") == AddrString {
		i, err := strconv.ParseUint(req.Header.Get("mx"), 0, 0)
		if err != nil {
			log.Println(err)
			return
		}
		mx = uint(i)
	} else {
		mx = 1
	}
	types := func(st string) []string {
		if st == "ssdp:all" {
			return me.allTypes()
		}
		for _, t := range me.allTypes() {
			if t == st {
				return []string{t}
			}
		}
		return nil
	}(req.Header.Get("st"))
	for _, ip := range func() (ret []net.IP) {
		addrs, err := me.Interface.Addrs()
		if err != nil {
			panic(err)
		}
		for _, addr := range addrs {
			if ip, ok := func() (net.IP, bool) {
				switch data := addr.(type) {
				case *net.IPNet:
					if data.Contains(sender.IP) {
						return data.IP, true
					}
					return nil, false
				case *net.IPAddr:
					return data.IP, true
				}
				panic(addr)
			}(); ok {
				ret = append(ret, ip)
			}
		}
		return
	}() {
		for _, type_ := range types {
			resp := me.makeResponse(ip, type_, req)
			delay := time.Duration(rand.Int63n(int64(time.Second) * int64(mx)))
			go me.delayedSend(delay, resp, sender)
		}
	}
}

func (me *Server) makeResponse(ip net.IP, targ string, req *http.Request) (ret []byte) {
	resp := &http.Response{
		StatusCode: 200,
		ProtoMajor: 1,
		ProtoMinor: 1,
		Header:     make(http.Header),
		Request:	req,
	}
	for _, pair := range [...][2]string{
		{"CACHE-CONTROL", fmt.Sprintf("max-age=%d", (5*DefaultNotifyInterval)/2)},
		{"EXT", ""},
		{"LOCATION", me.Location(ip)},
		{"SERVER", me.Server},
		{"ST", targ},
		{"USN", me.usnFromTarget(targ)},
	} {
		resp.Header.Set(pair[0], pair[1])
	}
	buf := &bytes.Buffer{}
	if err := resp.Write(buf); err != nil {
		panic(err)
	}
	return buf.Bytes()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"cloud.google.com/go/spanner"
	"google.golang.org/api/iterator"
	adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
	spannerpb "google.golang.org/genproto/googleapis/spanner/v1"
)

type Statement interface {
	Execute(session *Session) (*Result, error)
}

type Result struct {
	ColumnNames []string
	Rows        []Row
	QueryStats  QueryStats
	IsMutation  bool
}

type Row struct {
	Columns []string
}

type QueryStats struct {
	Rows        int
	ElapsedTime string
}

var (
	exitRe            = regexp.MustCompile(`(?i)^EXIT$`)
	selectRe          = regexp.MustCompile(`(?i)^SELECT\s.+$`)
	createTableRe     = regexp.MustCompile(`(?i)^CREATE\s+TABLE\s.+$`)
	showDatabasesRe   = regexp.MustCompile(`(?i)^SHOW\s+DATABASES$`)
	showCreateTableRe = regexp.MustCompile(`(?i)^SHOW\s+CREATE\s+TABLE\s+(.*)$`)
	showTablesRe      = regexp.MustCompile(`(?i)^SHOW\s+TABLES$`)
	insertRe          = regexp.MustCompile(`(?i)^INSERT\s+INTO.+$`)
	updateRe          = regexp.MustCompile(`(?i)^UPDATE\s+.+$`)
	deleteRe          = regexp.MustCompile(`(?i)^DELETE\s+.+$`)
)

var (
	statementExitError = errors.New("exit")
)

func buildStatement(input string) (Statement, error) {
	var stmt Statement

	if exitRe.MatchString(input) {
		return nil, statementExitError
	} else if selectRe.MatchString(input) {
		stmt = &QueryStatement{
			text: input,
		}
	} else if createTableRe.MatchString(input) {
		stmt = &CreateTableStatement{
			text: input,
		}
	} else if showDatabasesRe.MatchString(input) {
		stmt = &ShowDatabasesStatement{}
	} else if showCreateTableRe.MatchString(input) {
		matched := showCreateTableRe.FindStringSubmatch(input)
		stmt = &ShowCreateTableStatement{
			table: matched[1],
		}
	} else if showTablesRe.MatchString(input) {
		stmt = &ShowTablesStatement{}
	} else if insertRe.MatchString(input) || updateRe.MatchString(input) || deleteRe.MatchString(input) {
		stmt = &DmlStatement{
			text: input,
		}
	}

	if stmt == nil {
		return nil, errors.New("invalid statement")
	}

	return stmt, nil
}

type QueryStatement struct {
	text string
}

func (s *QueryStatement) Execute(session *Session) (*Result, error) {
	stmt := spanner.NewStatement(s.text)
	iter := session.client.Single().QueryWithStats(session.ctx, stmt)

	result := &Result{
		ColumnNames: make([]string, 0),
		Rows:        make([]Row, 0),
		IsMutation:  false,
	}

	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}

		resultRow := Row{
			Columns: make([]string, row.Size()),
		}

		result.ColumnNames = row.ColumnNames() // TODO

		for i := 0; i < row.Size(); i++ {
			var column spanner.GenericColumnValue
			err := row.Column(i, &column)
			if err != nil {
				return nil, err
			}
			// fmt.Println(column.Type.Code)
			switch column.Type.Code {
			case spannerpb.TypeCode_INT64:
				var v int64
				if err := column.Decode(&v); err != nil {
					return nil, err
				}
				resultRow.Columns[i] = fmt.Sprintf("%d", v)
			case spannerpb.TypeCode_STRING:
				var v string
				if err := column.Decode(&v); err != nil {
					return nil, err
				}
				resultRow.Columns[i] = v
			default:
				resultRow.Columns[i] = fmt.Sprintf("%s", column.Value)
			}
		}

		result.Rows = append(result.Rows, resultRow)
	}

	rowsReturned, _ := strconv.Atoi(iter.QueryStats["rows_returned"].(string))
	elapsedTime := iter.QueryStats["elapsed_time"].(string)
	result.QueryStats = QueryStats{
		Rows:        rowsReturned,
		ElapsedTime: elapsedTime,
	}

	return result, nil
}

type CreateTableStatement struct {
	text string
}

func (s *CreateTableStatement) Execute(session *Session) (*Result, error) {
	result := &Result{
		ColumnNames: make([]string, 0),
		Rows:        make([]Row, 0),
		IsMutation:  true,
	}

	t1 := time.Now()
	op, err := session.adminClient.UpdateDatabaseDdl(session.ctx, &adminpb.UpdateDatabaseDdlRequest{
		Database:   session.GetDatabasePath(),
		Statements: []string{s.text},
	})
	if err != nil {
		return nil, err
	}
	if err := op.Wait(session.ctx); err != nil {
		return nil, err
	}
	elapsed := time.Since(t1).String()

	result.QueryStats = QueryStats{
		Rows:        0,
		ElapsedTime: elapsed,
	}

	return result, nil
}

type ShowDatabasesStatement struct {
}

func (s *ShowDatabasesStatement) Execute(session *Session) (*Result, error) {
	result := &Result{
		ColumnNames: []string{"Database"},
		Rows:        make([]Row, 0),
		IsMutation:  false,
	}

	t1 := time.Now()

	dbIter := session.adminClient.ListDatabases(session.ctx, &adminpb.ListDatabasesRequest{
		Parent: session.GetInstancePath(),
	})

	for {
		database, err := dbIter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}

		re := regexp.MustCompile(`projects/[^/]+/instances/[^/]+/databases/(.+)`)
		matched := re.FindStringSubmatch(database.GetName())
		dbname := matched[1]
		resultRow := Row{
			Columns: []string{dbname},
		}
		result.Rows = append(result.Rows, resultRow)
	}

	elapsed := time.Since(t1).String()

	result.QueryStats = QueryStats{
		Rows:        len(result.Rows),
		ElapsedTime: elapsed,
	}

	return result, nil
}

type ShowCreateTableStatement struct {
	table string
}

func (s *ShowCreateTableStatement) Execute(session *Session) (*Result, error) {
	result := &Result{
		ColumnNames: []string{"Table", "Create Table"},
		Rows:        make([]Row, 0),
		IsMutation:  false,
	}

	t1 := time.Now()

	ddlResponse, err := session.adminClient.GetDatabaseDdl(session.ctx, &adminpb.GetDatabaseDdlRequest{
		Database: session.GetDatabasePath(),
	})
	if err != nil {
		return nil, err
	}
	for _, statement := range ddlResponse.Statements {
		if strings.HasPrefix(statement, fmt.Sprintf("CREATE TABLE %s", s.table)) {
			resultRow := Row{
				Columns: []string{s.table, statement},
			}
			result.Rows = append(result.Rows, resultRow)
			break
		}
	}

	elapsed := time.Since(t1).String()

	result.QueryStats = QueryStats{
		Rows:        len(result.Rows),
		ElapsedTime: elapsed,
	}

	return result, nil
}

type ShowTablesStatement struct{}

func (s *ShowTablesStatement) Execute(session *Session) (*Result, error) {
	query := QueryStatement{
		text: `SELECT t.table_name FROM information_schema.tables AS t WHERE t.table_catalog = '' and t.table_schema = ''`,
	}

	result, err := query.Execute(session)
	if err != nil {
		return nil, err
	}

	// rename column name
	if len(result.ColumnNames) == 1 {
		result.ColumnNames[0] = fmt.Sprintf("Tables_in_%s", session.databaseId)
	}

	return result, nil
}

type DmlStatement struct {
	text string
}

func (s *DmlStatement) Execute(session *Session) (*Result, error) {
	stmt := spanner.NewStatement(s.text)

	result := &Result{
		ColumnNames: make([]string, 0),
		Rows:        make([]Row, 0),
		IsMutation:  true,
	}

	t1 := time.Now()
	_, err := session.client.ReadWriteTransaction(session.ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		numRows, err := txn.Update(ctx, stmt)
		if err != nil {
			return err
		}
		result.QueryStats.Rows = int(numRows) // TODO: int64
		return nil
	})
	if err != nil {
		return nil, err
	}

	elapsed := time.Since(t1).String()
	result.QueryStats.ElapsedTime = elapsed

	return result, nil
}
<commit_msg>add ALTER TABLE and DROP TABLE<commit_after>package main

import (
	"context"
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"cloud.google.com/go/spanner"
	"google.golang.org/api/iterator"
	adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
	spannerpb "google.golang.org/genproto/googleapis/spanner/v1"
)

type Statement interface {
	Execute(session *Session) (*Result, error)
}

type Result struct {
	ColumnNames []string
	Rows        []Row
	QueryStats  QueryStats
	IsMutation  bool
}

type Row struct {
	Columns []string
}

type QueryStats struct {
	Rows        int
	ElapsedTime string
}

var (
	// SQL
	selectRe = regexp.MustCompile(`(?i)^SELECT\s.+$`)

	// DDL
	createTableRe = regexp.MustCompile(`(?i)^CREATE\s+TABLE\s.+$`)
	alterTableRe  = regexp.MustCompile(`(?i)^ALTER\s+TABLE\s.+$`)
	dropTableRe   = regexp.MustCompile(`(?i)^DROP\s+TABLE\s.+$`)

	// DML
	insertRe = regexp.MustCompile(`(?i)^INSERT\s+.+$`)
	updateRe = regexp.MustCompile(`(?i)^UPDATE\s+.+$`)
	deleteRe = regexp.MustCompile(`(?i)^DELETE\s+.+$`)

	// Other
	exitRe            = regexp.MustCompile(`(?i)^EXIT$`)
	showDatabasesRe   = regexp.MustCompile(`(?i)^SHOW\s+DATABASES$`)
	showCreateTableRe = regexp.MustCompile(`(?i)^SHOW\s+CREATE\s+TABLE\s+(.*)$`)
	showTablesRe      = regexp.MustCompile(`(?i)^SHOW\s+TABLES$`)
)

var (
	statementExitError = errors.New("exit")
)

func buildStatement(input string) (Statement, error) {
	var stmt Statement

	if exitRe.MatchString(input) {
		return nil, statementExitError
	} else if selectRe.MatchString(input) {
		stmt = &QueryStatement{
			text: input,
		}
	} else if createTableRe.MatchString(input) || alterTableRe.MatchString(input) || dropTableRe.MatchString(input) {
		stmt = &DdlStatement{
			text: input,
		}
	} else if showDatabasesRe.MatchString(input) {
		stmt = &ShowDatabasesStatement{}
	} else if showCreateTableRe.MatchString(input) {
		matched := showCreateTableRe.FindStringSubmatch(input)
		stmt = &ShowCreateTableStatement{
			table: matched[1],
		}
	} else if showTablesRe.MatchString(input) {
		stmt = &ShowTablesStatement{}
	} else if insertRe.MatchString(input) || updateRe.MatchString(input) || deleteRe.MatchString(input) {
		stmt = &DmlStatement{
			text: input,
		}
	}

	if stmt == nil {
		return nil, errors.New("invalid statement")
	}

	return stmt, nil
}

type QueryStatement struct {
	text string
}

func (s *QueryStatement) Execute(session *Session) (*Result, error) {
	stmt := spanner.NewStatement(s.text)
	iter := session.client.Single().QueryWithStats(session.ctx, stmt)

	result := &Result{
		ColumnNames: make([]string, 0),
		Rows:        make([]Row, 0),
		IsMutation:  false,
	}

	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}

		resultRow := Row{
			Columns: make([]string, row.Size()),
		}

		result.ColumnNames = row.ColumnNames() // TODO

		for i := 0; i < row.Size(); i++ {
			var column spanner.GenericColumnValue
			err := row.Column(i, &column)
			if err != nil {
				return nil, err
			}
			// fmt.Println(column.Type.Code)
			switch column.Type.Code {
			case spannerpb.TypeCode_INT64:
				var v int64
				if err := column.Decode(&v); err != nil {
					return nil, err
				}
				resultRow.Columns[i] = fmt.Sprintf("%d", v)
			case spannerpb.TypeCode_STRING:
				var v string
				if err := column.Decode(&v); err != nil {
					return nil, err
				}
				resultRow.Columns[i] = v
			default:
				resultRow.Columns[i] = fmt.Sprintf("%s", column.Value)
			}
		}

		result.Rows = append(result.Rows, resultRow)
	}

	rowsReturned, _ := strconv.Atoi(iter.QueryStats["rows_returned"].(string))
	elapsedTime := iter.QueryStats["elapsed_time"].(string)
	result.QueryStats = QueryStats{
		Rows:        rowsReturned,
		ElapsedTime: elapsedTime,
	}

	return result, nil
}

type DdlStatement struct {
	text string
}

func (s *DdlStatement) Execute(session *Session) (*Result, error) {
	result := &Result{
		ColumnNames: make([]string, 0),
		Rows:        make([]Row, 0),
		IsMutation:  true,
	}

	t1 := time.Now()
	op, err := session.adminClient.UpdateDatabaseDdl(session.ctx, &adminpb.UpdateDatabaseDdlRequest{
		Database:   session.GetDatabasePath(),
		Statements: []string{s.text},
	})
	if err != nil {
		return nil, err
	}
	if err := op.Wait(session.ctx); err != nil {
		return nil, err
	}
	elapsed := time.Since(t1).String()

	result.QueryStats = QueryStats{
		Rows:        0,
		ElapsedTime: elapsed,
	}

	return result, nil
}

type ShowDatabasesStatement struct {
}

func (s *ShowDatabasesStatement) Execute(session *Session) (*Result, error) {
	result := &Result{
		ColumnNames: []string{"Database"},
		Rows:        make([]Row, 0),
		IsMutation:  false,
	}

	t1 := time.Now()

	dbIter := session.adminClient.ListDatabases(session.ctx, &adminpb.ListDatabasesRequest{
		Parent: session.GetInstancePath(),
	})

	for {
		database, err := dbIter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}

		re := regexp.MustCompile(`projects/[^/]+/instances/[^/]+/databases/(.+)`)
		matched := re.FindStringSubmatch(database.GetName())
		dbname := matched[1]
		resultRow := Row{
			Columns: []string{dbname},
		}
		result.Rows = append(result.Rows, resultRow)
	}

	elapsed := time.Since(t1).String()

	result.QueryStats = QueryStats{
		Rows:        len(result.Rows),
		ElapsedTime: elapsed,
	}

	return result, nil
}

type ShowCreateTableStatement struct {
	table string
}

func (s *ShowCreateTableStatement) Execute(session *Session) (*Result, error) {
	result := &Result{
		ColumnNames: []string{"Table", "Create Table"},
		Rows:        make([]Row, 0),
		IsMutation:  false,
	}

	t1 := time.Now()

	ddlResponse, err := session.adminClient.GetDatabaseDdl(session.ctx, &adminpb.GetDatabaseDdlRequest{
		Database: session.GetDatabasePath(),
	})
	if err != nil {
		return nil, err
	}
	for _, statement := range ddlResponse.Statements {
		if strings.HasPrefix(statement, fmt.Sprintf("CREATE TABLE %s", s.table)) {
			resultRow := Row{
				Columns: []string{s.table, statement},
			}
			result.Rows = append(result.Rows, resultRow)
			break
		}
	}

	elapsed := time.Since(t1).String()

	result.QueryStats = QueryStats{
		Rows:        len(result.Rows),
		ElapsedTime: elapsed,
	}

	return result, nil
}

type ShowTablesStatement struct{}

func (s *ShowTablesStatement) Execute(session *Session) (*Result, error) {
	query := QueryStatement{
		text: `SELECT t.table_name FROM information_schema.tables AS t WHERE t.table_catalog = '' and t.table_schema = ''`,
	}

	result, err := query.Execute(session)
	if err != nil {
		return nil, err
	}

	// rename column name
	if len(result.ColumnNames) == 1 {
		result.ColumnNames[0] = fmt.Sprintf("Tables_in_%s", session.databaseId)
	}

	return result, nil
}

type DmlStatement struct {
	text string
}

func (s *DmlStatement) Execute(session *Session) (*Result, error) {
	stmt := spanner.NewStatement(s.text)

	result := &Result{
		ColumnNames: make([]string, 0),
		Rows:        make([]Row, 0),
		IsMutation:  true,
	}

	t1 := time.Now()
	_, err := session.client.ReadWriteTransaction(session.ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		numRows, err := txn.Update(ctx, stmt)
		if err != nil {
			return err
		}
		result.QueryStats.Rows = int(numRows) // TODO: int64
		return nil
	})
	if err != nil {
		return nil, err
	}

	elapsed := time.Since(t1).String()
	result.QueryStats.ElapsedTime = elapsed

	return result, nil
}
<|endoftext|>


<commit_before>// statspipe is a metrics pipeline
package main

import (
	"bufio"
	"bytes"
	"flag"
	"io"
	"sync"
	"sync/atomic"
	//"io"
	"fmt"
	"log"
	"math"
	"net"
	"regexp"
	"sort"
	"strconv"
	"time"

	//"github.com/davecgh/go-spew/spew"
	"github.com/davecheney/profile"
)

const FlushInterval = time.Duration(10 * time.Second)
const BufSize = 8192

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

// Command line flags
var (
	listen     = flag.String("listen", ":1514", "UDP listener address")
	graphite   = flag.String("graphite", "localhost:2003", "Graphite server address")
	cpuprofile = flag.Bool("cpuprofile", false, "Enable CPU profiling")
)

// Metric Types
var In = make(chan *Metric)

var counters = struct {
	sync.RWMutex
	m map[string]int64
}{m: make(map[string]int64)}

var gauges = struct {
	sync.RWMutex
	m map[string]uint64
}{m: make(map[string]uint64)}

type Timers []uint64

func (t Timers) Len() int           { return len(t) }
func (t Timers) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t Timers) Less(i, j int) bool { return t[i] < t[j] }

var timers = struct {
	sync.RWMutex
	m map[string]Timers
}{m: make(map[string]Timers)}

var Percentiles = []int{5, 95}

// Internal metrics
type Stats struct {
	Metrics  int64
	Counters int64
	Gauges   int64
	Timers   int64
}

var stats = &Stats{}

//-----------------------------------------------------------------------------
// Read syslog stream

func ListenUDP(addr string) error {
	var buf = make([]byte, 1024)
	ln, err := net.ResolveUDPAddr("udp", addr)

	if err != nil {
		return err
	}

	sock, err := net.ListenUDP("udp", ln)

	if err != nil {
		return err
	}

	log.Printf("Listening on UDP %s\n", ln)

	for {
		n, raddr, err := sock.ReadFromUDP(buf[:])

		if err != nil {
			// TODO: handle error
			continue
		}

		log.Printf("Read %d bytes from %s\n", n, raddr)
		go handleMessage(buf)
	}
}

func ListenTCP(addr string) error {
	l, err := net.Listen("tcp", addr)

	if err != nil {
		return err
	}

	defer l.Close()
	log.Printf("Listening on TCP %s\n", l.Addr())

	for {
		conn, err := l.Accept()

		if err != nil {
			// TODO: handle error
			continue
		}

		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)

	for {
		line, err := r.ReadBytes('\n')

		if err != nil {
			if err == io.EOF {
				break
			} else {
				// TODO: handle error
			}
		}

		go handleMessage(line)
	}
}

// Metrics should be in statsd format
// <metric_name>:<metric_value>|<metric_type>
var statsPattern = regexp.MustCompile(`[\w\.]+:-?\d+\|(?:c|ms|g)(?:\|\@[\d\.]+)?`)

// Handle an event message
func handleMessage(buf []byte) {
	//log.Printf("DEBUG: buf is %d bytes\n", len(buf))
	// Parse metrics from the message
	m := statsPattern.FindAll(buf, -1)
	//spew.Dump(m)

	if m != nil {
		for _, metric := range m {
			err := handleMetric(metric)

			if err != nil {
				log.Printf("ERROR: Unable to process metric %s: %s",
					metric, err)
			}
		}
	} else {
		log.Println("No metrics found in message")
	}
}

type Metric struct {
	Name  string
	Value interface{}
	Type  string
}

// handle a single metric
func handleMetric(b []byte) error {
	i := bytes.Index(b, []byte(":"))
	j := bytes.Index(b, []byte("|"))
	k := bytes.Index(b, []byte("@"))
	v := b[i+1 : j]

	// End position of the metric type is the end of the byte slice
	// if no sample was sent.
	tEnd := len(b)
	var sampleRate float64 = 1

	if k > -1 {
		tEnd = k - 1 // Use -1 because of the | before the @
		sr := b[(k + 1):len(b)]
		var err error
		sampleRate, err = strconv.ParseFloat(string(sr), 64)

		if err != nil {
			return err
		}
	}

	m := &Metric{
		Name: string(b[0:i]),
		Type: string(b[j+1 : tEnd]),
	}

	switch m.Type {
	case "c":
		val, err := strconv.ParseInt(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = int64(float64(val) / sampleRate)
	default:
		val, err := strconv.ParseUint(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = val
	}

	In <- m
	return nil
}

func processMetrics() {
	ticker := time.NewTicker(FlushInterval)

	for {
		select {
		case <-ticker.C:
			flushMetrics()
		case m := <-In:
			atomic.AddInt64(&stats.Metrics, 1)

			switch m.Type {
			case "c":
				counters.Lock()
				counters.m[m.Name] += m.Value.(int64)
				counters.Unlock()
				atomic.AddInt64(&stats.Counters, 1)
			case "g":
				gauges.Lock()
				gauges.m[m.Name] = m.Value.(uint64)
				gauges.Unlock()
				atomic.AddInt64(&stats.Gauges, 1)
			case "ms":
				timers.Lock()
				_, ok := timers.m[m.Name]

				if !ok {
					var t Timers
					timers.m[m.Name] = t
				}

				timers.m[m.Name] = append(timers.m[m.Name], m.Value.(uint64))
				timers.Unlock()
				atomic.AddInt64(&stats.Timers, 1)
			}
		}
	}
}

func flushMetrics() {
	var buf bytes.Buffer
	now := time.Now().Unix()

	log.Printf("%+v", stats)

	flushCounters(&buf, now)
	flushGauges(&buf, now)
	flushTimers(&buf, now)

	// Send metrics to Graphite
	sendGraphite(&buf)
}

func flushCounters(buf *bytes.Buffer, now int64) {
	counters.Lock()
	defer counters.Unlock()
	var n int64

	for k, v := range counters.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(counters.m, k)
		n += v
	}

	log.Printf("counters=%d n=%d", atomic.LoadInt64(&stats.Counters), n)
	atomic.StoreInt64(&stats.Counters, atomic.LoadInt64(&stats.Counters)-n)
	atomic.StoreInt64(&stats.Metrics, atomic.LoadInt64(&stats.Metrics)-n)
}

func flushGauges(buf *bytes.Buffer, now int64) {
	gauges.Lock()
	defer gauges.Unlock()
	var n int64

	for k, v := range gauges.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(gauges.m, k)
		n++
	}

	// TODO : These counters aren't right...
	atomic.StoreInt64(&stats.Gauges, atomic.LoadInt64(&stats.Gauges)-n)
	atomic.StoreInt64(&stats.Metrics, atomic.LoadInt64(&stats.Metrics)-n)
}

func flushTimers(buf *bytes.Buffer, now int64) {
	timers.RLock()
	defer timers.RUnlock()
	var n int64

	for k, t := range timers.m {
		count := len(t)

		// Skip processing if there are no timer values
		if count < 1 {
			break
		}

		var sum uint64

		for _, v := range t {
			sum += v
			n++
		}

		// Linear average (mean)
		mean := float64(sum) / float64(count)

		// Min and Max
		sort.Sort(t)
		min := t[0]
		max := t[len(t)-1]

		// Write out all derived stats
		fmt.Fprintf(buf, "%s.count %d %d\n", k, count, now)
		fmt.Fprintf(buf, "%s.mean %f %d\n", k, mean, now)
		fmt.Fprintf(buf, "%s.lower %d %d\n", k, min, now)
		fmt.Fprintf(buf, "%s.upper %d %d\n", k, max, now)

		// Calculate and write out percentiles
		for _, pct := range Percentiles {
			p := perc(t, pct)
			fmt.Fprintf(buf, "%s.perc%d %f %d\n", k, pct, p, now)
		}

		delete(timers.m, k)
	}

	log.Printf("timers=%d n=%d", atomic.LoadInt64(&stats.Timers), n)

	atomic.StoreInt64(&stats.Timers, atomic.LoadInt64(&stats.Timers)-n)
	atomic.StoreInt64(&stats.Metrics, atomic.LoadInt64(&stats.Metrics)-n)
}

// percentile calculates Nth percentile of a list of values
func perc(values []uint64, pct int) float64 {
	p := float64(pct) / float64(100)
	n := float64(len(values))
	i := math.Ceil(p*n) - 1

	return float64(values[int(i)])
}

// sendGraphite sends metrics to graphite
func sendGraphite(buf *bytes.Buffer) {
	conn, err := net.Dial("tcp", *graphite)

	if err != nil {
		log.Fatal("ERROR: Unable to connect to graphite")
	}

	w := bufio.NewWriter(conn)
	n, err := buf.WriteTo(w)

	if err != nil {
		log.Fatal("ERROR: Unable to write to graphite")
	}

	w.Flush()
	conn.Close()

	log.Printf("Wrote %d bytes to Graphite", n)
}

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

func main() {
	flag.Parse()

	// Profiling
	cfg := profile.Config{
		CPUProfile:   *cpuprofile,
		MemProfile:   false,
		BlockProfile: false,
		ProfilePath:  ".",
	}

	p := profile.Start(&cfg)
	defer p.Stop()

	// Process metrics as they arrive
	go processMetrics()

	// Setup listeners
	go log.Fatal(ListenTCP(*listen))

}
<commit_msg>Cleaned up counters<commit_after>// statspipe is a metrics pipeline
package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"net"
	"regexp"
	"sort"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	//"github.com/davecgh/go-spew/spew"
	"github.com/davecheney/profile"
)

const FlushInterval = time.Duration(10 * time.Second)
const BufSize = 8192

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

// Command line flags
var (
	listen     = flag.String("listen", ":1514", "UDP listener address")
	graphite   = flag.String("graphite", "localhost:2003", "Graphite server address")
	cpuprofile = flag.Bool("cpuprofile", false, "Enable CPU profiling")
)

// Metric Types
var In = make(chan *Metric)

var counters = struct {
	sync.RWMutex
	m map[string]int64
}{m: make(map[string]int64)}

var gauges = struct {
	sync.RWMutex
	m map[string]uint64
}{m: make(map[string]uint64)}

type Timers []uint64

func (t Timers) Len() int           { return len(t) }
func (t Timers) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t Timers) Less(i, j int) bool { return t[i] < t[j] }

var timers = struct {
	sync.RWMutex
	m map[string]Timers
}{m: make(map[string]Timers)}

var Percentiles = []int{5, 95}

// Internal metrics
type Stats struct {
	IngressRate     int64
	IngressMetrics  int64
	IngressCounters int64
	IngressGauges   int64
	IngressTimers   int64
}

var stats = &Stats{}

//-----------------------------------------------------------------------------
// Read syslog stream

func ListenUDP(addr string) error {
	var buf = make([]byte, 1024)
	ln, err := net.ResolveUDPAddr("udp", addr)

	if err != nil {
		return err
	}

	sock, err := net.ListenUDP("udp", ln)

	if err != nil {
		return err
	}

	log.Printf("Listening on UDP %s\n", ln)

	for {
		n, raddr, err := sock.ReadFromUDP(buf[:])

		if err != nil {
			// TODO: handle error
			continue
		}

		log.Printf("Read %d bytes from %s\n", n, raddr)
		go handleMessage(buf)
	}
}

func ListenTCP(addr string) error {
	l, err := net.Listen("tcp", addr)

	if err != nil {
		return err
	}

	defer l.Close()
	log.Printf("Listening on TCP %s\n", l.Addr())

	for {
		conn, err := l.Accept()

		if err != nil {
			// TODO: handle error
			continue
		}

		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)

	for {
		line, err := r.ReadBytes('\n')

		if err != nil {
			if err == io.EOF {
				break
			} else {
				// TODO: handle error
			}
		}

		go handleMessage(line)
	}
}

// Metrics should be in statsd format
// <metric_name>:<metric_value>|<metric_type>
var statsPattern = regexp.MustCompile(`[\w\.]+:-?\d+\|(?:c|ms|g)(?:\|\@[\d\.]+)?`)

// Handle an event message
func handleMessage(buf []byte) {
	//log.Printf("DEBUG: buf is %d bytes\n", len(buf))
	// Parse metrics from the message
	m := statsPattern.FindAll(buf, -1)
	//spew.Dump(m)

	if m != nil {
		for _, metric := range m {
			err := handleMetric(metric)

			if err != nil {
				log.Printf("ERROR: Unable to process metric %s: %s",
					metric, err)
			}
		}
	} else {
		log.Println("No metrics found in message")
	}
}

type Metric struct {
	Name  string
	Value interface{}
	Type  string
}

// handle a single metric
func handleMetric(b []byte) error {
	i := bytes.Index(b, []byte(":"))
	j := bytes.Index(b, []byte("|"))
	k := bytes.Index(b, []byte("@"))
	v := b[i+1 : j]

	// End position of the metric type is the end of the byte slice
	// if no sample was sent.
	tEnd := len(b)
	var sampleRate float64 = 1

	if k > -1 {
		tEnd = k - 1 // Use -1 because of the | before the @
		sr := b[(k + 1):len(b)]
		var err error
		sampleRate, err = strconv.ParseFloat(string(sr), 64)

		if err != nil {
			return err
		}
	}

	m := &Metric{
		Name: string(b[0:i]),
		Type: string(b[j+1 : tEnd]),
	}

	switch m.Type {
	case "c":
		val, err := strconv.ParseInt(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = int64(float64(val) / sampleRate)
	default:
		val, err := strconv.ParseUint(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = val
	}

	In <- m
	return nil
}

func processMetrics() {
	ticker := time.NewTicker(FlushInterval)

	for {
		select {
		case <-ticker.C:
			flushMetrics()
		case m := <-In:
			atomic.AddInt64(&stats.IngressMetrics, 1)

			switch m.Type {
			case "c":
				counters.Lock()
				counters.m[m.Name] += m.Value.(int64)
				counters.Unlock()
				atomic.AddInt64(&stats.IngressCounters, 1)

			case "g":
				gauges.Lock()
				gauges.m[m.Name] = m.Value.(uint64)
				gauges.Unlock()
				atomic.AddInt64(&stats.IngressGauges, 1)

			case "ms":
				timers.Lock()
				_, ok := timers.m[m.Name]

				if !ok {
					var t Timers
					timers.m[m.Name] = t
				}

				timers.m[m.Name] = append(timers.m[m.Name], m.Value.(uint64))
				timers.Unlock()
				atomic.AddInt64(&stats.IngressTimers, 1)

			}
		}
	}
}

func flushMetrics() {
	var buf bytes.Buffer
	now := time.Now().Unix()

	log.Printf("%+v", stats)

	// Build buffer of stats
	flushCounters(&buf, now)
	flushGauges(&buf, now)
	flushTimers(&buf, now)
	flushInternalStats(&buf, now)

	// Send metrics to Graphite
	sendGraphite(&buf)
}

func flushInternalStats(buf *bytes.Buffer, now int64) {
	//fmt.Fprintf(buf, "statsd.metrics.per_second %d %d\n", v, now)
	fmt.Fprintf(buf, "statsd.metrics.count %d %d\n",
		atomic.LoadInt64(&stats.IngressMetrics), now)
	fmt.Fprintf(buf, "statsd.counters.count %d %d\n",
		atomic.LoadInt64(&stats.IngressCounters), now)
	fmt.Fprintf(buf, "statsd.gauges.count %d %d\n",
		atomic.LoadInt64(&stats.IngressGauges), now)
	fmt.Fprintf(buf, "statsd.timers.count %d %d\n",
		atomic.LoadInt64(&stats.IngressTimers), now)

	// Clear internal metrics
	atomic.StoreInt64(&stats.IngressMetrics, 0)
	atomic.StoreInt64(&stats.IngressCounters, 0)
	atomic.StoreInt64(&stats.IngressGauges, 0)
	atomic.StoreInt64(&stats.IngressTimers, 0)

}

func flushCounters(buf *bytes.Buffer, now int64) {
	counters.Lock()
	defer counters.Unlock()

	for k, v := range counters.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(counters.m, k)
	}
}

func flushGauges(buf *bytes.Buffer, now int64) {
	gauges.Lock()
	defer gauges.Unlock()

	for k, v := range gauges.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(gauges.m, k)
	}
}

func flushTimers(buf *bytes.Buffer, now int64) {
	timers.RLock()
	defer timers.RUnlock()
	var n int64

	for k, t := range timers.m {
		count := len(t)

		// Skip processing if there are no timer values
		if count < 1 {
			break
		}

		var sum uint64

		for _, v := range t {
			sum += v
			n++
		}

		// Linear average (mean)
		mean := float64(sum) / float64(count)

		// Min and Max
		sort.Sort(t)
		min := t[0]
		max := t[len(t)-1]

		// Write out all derived stats
		fmt.Fprintf(buf, "%s.count %d %d\n", k, count, now)
		fmt.Fprintf(buf, "%s.mean %f %d\n", k, mean, now)
		fmt.Fprintf(buf, "%s.lower %d %d\n", k, min, now)
		fmt.Fprintf(buf, "%s.upper %d %d\n", k, max, now)

		// Calculate and write out percentiles
		for _, pct := range Percentiles {
			p := perc(t, pct)
			fmt.Fprintf(buf, "%s.perc%d %f %d\n", k, pct, p, now)
		}

		delete(timers.m, k)
	}
}

// percentile calculates Nth percentile of a list of values
func perc(values []uint64, pct int) float64 {
	p := float64(pct) / float64(100)
	n := float64(len(values))
	i := math.Ceil(p*n) - 1

	return float64(values[int(i)])
}

// sendGraphite sends metrics to graphite
func sendGraphite(buf *bytes.Buffer) {
	conn, err := net.Dial("tcp", *graphite)

	if err != nil {
		log.Fatal("ERROR: Unable to connect to graphite")
	}

	w := bufio.NewWriter(conn)
	n, err := buf.WriteTo(w)

	if err != nil {
		log.Fatal("ERROR: Unable to write to graphite")
	}

	w.Flush()
	conn.Close()

	log.Printf("Wrote %d bytes to Graphite", n)
}

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

func main() {
	flag.Parse()

	// Profiling
	cfg := profile.Config{
		CPUProfile:   *cpuprofile,
		MemProfile:   false,
		BlockProfile: false,
		ProfilePath:  ".",
	}

	p := profile.Start(&cfg)
	defer p.Stop()

	// Process metrics as they arrive
	go processMetrics()

	// Setup listeners
	go log.Fatal(ListenTCP(*listen))

}
<|endoftext|>


<commit_before>package options

// AddDefaultOptions adds internal options that can be set by the user through
// the command-line interface.
func (o *Options) AddDefaultOptions() {
	o.Add(NewBoolOption("center"))
	o.Add(NewStringOption("columns"))
	o.Add(NewStringOption("sort"))
	o.Add(NewStringOption("topbar"))
}

// Defaults is the default, internal configuration file.
const Defaults string = `
# Global options
set nocenter
set columns=artist,track,title,album,year,time
set sort=file,track,disc,album,year,albumartistsort
set topbar="|$shortname $version||;${tag|artist} - ${tag|title}||${tag|album}, ${tag|year};$volume $mode $elapsed ${state} $time;|[${list|index}/${list|total}] ${list|title}||;;"

# Song tag styles
style album teal
style artist yellow
style date green
style time darkmagenta
style title white bold
style track green
style year green

# Tracklist styles
style allTagsMissing red
style currentSong black yellow
style cursor black white
style header green bold
style mostTagsMissing red
style selection white blue

# Topbar styles
style elapsed green
style listIndex darkblue
style listTitle blue bold
style listTotal darkblue
style mute red
style shortName bold
style state default
style switches teal
style tagMissing red
style topbar darkgray
style version gray
style volume green

# Other styles
style commandText default
style errorText white red bold
style readout default
style searchText white bold
style sequenceText teal
style statusbar default
style visualText teal

# Keyboard bindings: cursor movement
bind <Up> cursor up
bind k cursor up
bind <Down> cursor down
bind j cursor down
bind <PgUp> cursor pgup
bind <PgDn> cursor pgdn
bind <Home> cursor home
bind gg cursor home
bind <End> cursor end
bind G cursor end
bind gc cursor current
bind R cursor random
bind b cursor prevOf album
bind e cursor nextOf album

# Keyboard bindings: input mode
bind : inputmode input
bind / inputmode search
bind <F3> inputmode search
bind v select visual
bind V select visual

# Keyboard bindings: player and mixer
bind <Enter> play selection
bind <Space> pause
bind s stop
bind h previous
bind l next
bind + volume +2
bind - volume -2
bind <left> seek -5
bind <right> seek +5
bind M volume mute
bind S single

# Keyboard bindings: other
bind <C-c> quit
bind <C-l> redraw
bind <C-s> sort
bind i print file
bind t list next
bind T list previous
bind <C-w>d list duplicate
bind <C-g> list remove
bind <C-j> isolate artist
bind <C-t> isolate albumartist album
bind & select nearby albumartist album
bind m select toggle
bind a add
bind <Delete> cut
bind x cut
bind y yank
bind p paste after
bind P paste before
`
<commit_msg>Add default bindings control-{U,D,F,B}<commit_after>package options

// AddDefaultOptions adds internal options that can be set by the user through
// the command-line interface.
func (o *Options) AddDefaultOptions() {
	o.Add(NewBoolOption("center"))
	o.Add(NewStringOption("columns"))
	o.Add(NewStringOption("sort"))
	o.Add(NewStringOption("topbar"))
}

// Defaults is the default, internal configuration file.
const Defaults string = `
# Global options
set nocenter
set columns=artist,track,title,album,year,time
set sort=file,track,disc,album,year,albumartistsort
set topbar="|$shortname $version||;${tag|artist} - ${tag|title}||${tag|album}, ${tag|year};$volume $mode $elapsed ${state} $time;|[${list|index}/${list|total}] ${list|title}||;;"

# Song tag styles
style album teal
style artist yellow
style date green
style time darkmagenta
style title white bold
style track green
style year green

# Tracklist styles
style allTagsMissing red
style currentSong black yellow
style cursor black white
style header green bold
style mostTagsMissing red
style selection white blue

# Topbar styles
style elapsed green
style listIndex darkblue
style listTitle blue bold
style listTotal darkblue
style mute red
style shortName bold
style state default
style switches teal
style tagMissing red
style topbar darkgray
style version gray
style volume green

# Other styles
style commandText default
style errorText white red bold
style readout default
style searchText white bold
style sequenceText teal
style statusbar default
style visualText teal

# Keyboard bindings: cursor movement
bind <Up> cursor up
bind k cursor up
bind <Down> cursor down
bind j cursor down
bind <PgUp> cursor pgup
bind <PgDn> cursor pgdn
bind <C-b> cursor pgup
bind <C-f> cursor pgdn
bind <C-u> cursor halfpgup
bind <C-d> cursor halfpgdn
bind <Home> cursor home
bind gg cursor home
bind <End> cursor end
bind G cursor end
bind gc cursor current
bind R cursor random
bind b cursor prevOf album
bind e cursor nextOf album

# Keyboard bindings: input mode
bind : inputmode input
bind / inputmode search
bind <F3> inputmode search
bind v select visual
bind V select visual

# Keyboard bindings: player and mixer
bind <Enter> play selection
bind <Space> pause
bind s stop
bind h previous
bind l next
bind + volume +2
bind - volume -2
bind <left> seek -5
bind <right> seek +5
bind M volume mute
bind S single

# Keyboard bindings: other
bind <C-c> quit
bind <C-l> redraw
bind <C-s> sort
bind i print file
bind t list next
bind T list previous
bind <C-w>d list duplicate
bind <C-g> list remove
bind <C-j> isolate artist
bind <C-t> isolate albumartist album
bind & select nearby albumartist album
bind m select toggle
bind a add
bind <Delete> cut
bind x cut
bind y yank
bind p paste after
bind P paste before
`
<|endoftext|>


<commit_before>package m3u8

/*
 Part of M3U8 parser & generator library.
 This file defines data structures related to package.

 Copyleft 2013  Alexander I.Grafov aka Axel <grafov@gmail.com>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
)

const (
	/*
		Compatibility rules described in section 7:
		Clients and servers MUST implement protocol version 2 or higher to use:
		   o  The IV attribute of the EXT-X-KEY tag.
		   Clients and servers MUST implement protocol version 3 or higher to use:
		   o  Floating-point EXTINF duration values.
		   Clients and servers MUST implement protocol version 4 or higher to use:
		   o  The EXT-X-BYTERANGE tag.
		   o  The EXT-X-I-FRAME-STREAM-INF tag.
		   o  The EXT-X-I-FRAMES-ONLY tag.
		   o  The EXT-X-MEDIA tag.
		   o  The AUDIO and VIDEO attributes of the EXT-X-STREAM-INF tag.
	*/
	minver = uint8(3)
)

type ListType uint

const (
	UNKNOWN ListType = iota
	MASTER
	MEDIA
)

/*
 This structure represents a single bitrate playlist aka media playlist.
 It related to both a simple media playlists and a sliding window media playlists.
 URI lines in the Playlist point to media segments.

 Simple Media Playlist file sample:

   #EXTM3U
   #EXT-X-VERSION:3
   #EXT-X-TARGETDURATION:5220
   #EXTINF:5219.2,
   http://media.example.com/entire.ts
   #EXT-X-ENDLIST

 Sample of Sliding Window Media Playlist, using HTTPS:

   #EXTM3U
   #EXT-X-VERSION:3
   #EXT-X-TARGETDURATION:8
   #EXT-X-MEDIA-SEQUENCE:2680

   #EXTINF:7.975,
   https://priv.example.com/fileSequence2680.ts
   #EXTINF:7.941,
   https://priv.example.com/fileSequence2681.ts
   #EXTINF:7.975,
   https://priv.example.com/fileSequence2682.ts
*/
type MediaPlaylist struct {
	TargetDuration float64
	SeqNo          uint64 // EXT-X-MEDIA-SEQUENCE
	Segments       []*MediaSegment
	SID            string
	Iframe         bool // EXT-X-I-FRAMES-ONLY
	Closed         bool // is this VOD (closed) or Live (sliding) playlist?
	durationAsInt  bool // output durations as integers of floats?
	keyformat      int
	winsize        uint // max number of segments removed from queue on playlist generation
	capacity       uint // total capacity of slice used for the playlist
	head           uint // head of FIFO, we add segments to head
	tail           uint // tail of FIFO, we remove segments from tail
	count          uint // number of segments in the playlist
	buf            bytes.Buffer
	ver            uint8
	WV             *WV // Widevine related tags
}

/*
 This structure represents a master playlist which combines media playlists for multiple bitrates.
 URI lines in the playlist identify media playlists.
 Sample of Master Playlist file:

   #EXTM3U
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000
   http://example.com/low.m3u8
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000
   http://example.com/mid.m3u8
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000
   http://example.com/hi.m3u8
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS="mp4a.40.5"
   http://example.com/audio-only.m3u8
*/
type MasterPlaylist struct {
	SID      string
	Variants []*Variant
	buf      bytes.Buffer
	ver      uint8
}

// This structure represents variants for master playlist.
// Variants included in a master playlist and point to media playlists.
type Variant struct {
	URI       string
	Chunklist *MediaPlaylist
	VariantParams
}

// This stucture represents additional parameters for a variant
type VariantParams struct {
	ProgramId  uint8
	Bandwidth  uint32
	Codecs     string
	Resolution string
	Audio      string
	Video      string
	Subtitles  string
	Iframe     bool // EXT-X-I-FRAME-STREAM-INF
	AltMedia   []*AltMedia
}

// This structure represents EXT-X-MEDIA tag in variants.
type AltMedia struct {
	GroupId         string
	URI             string
	Type            string
	Language        string
	Name            string
	Default         string
	Autoselect      string
	Forced          string
	Characteristics string
	Subtitles       string
}

// This structure represents a media segment included in a media playlist.
// Media segment may be encrypted.
// Widevine supports own tags for encryption metadata.
type MediaSegment struct {
	SeqId uint64
	Title string // optional second parameter for EXTINF tag
	URI   string
	// duration must be integers if protocol version is less than 3 but we are always keep them float
	Duration float64 // first parameter for EXTINF tag
	Key      *Key
}

// This structure represents information about stream encryption.
// Realizes EXT-X-KEY tag.
type Key struct {
	Method            string
	URI               string
	IV                string
	Keyformat         string
	Keyformatversions string
}

// This structure represents metadata  for Google Widevine playlists.
// This format not described in IETF draft but provied by Widevine packager as
// additional tags in the playlist.
type WV struct {
	AudioChannels          uint
	AudioFormat            uint
	AudioProfileIDC        uint
	AudioSampleSize        uint
	AudioSamplingFrequency uint
	CypherVersion          string
	ECM                    string
	VideoFormat            uint
	VideoFrameRate         uint
	VideoLevelIDC          uint
	VideoProfileIDC        uint
	VideoResolution        string
	VideoSAR               string
}

// Interface applied to various playlist types.
type Playlist interface {
	Encode() *bytes.Buffer
	Decode(bytes.Buffer, bool) error
}
<commit_msg>Comment added.<commit_after>package m3u8

/*
 Part of M3U8 parser & generator library.
 This file defines data structures related to package.

 Copyleft 2013  Alexander I.Grafov aka Axel <grafov@gmail.com>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
)

const (
	/*
		Compatibility rules described in section 7:
		Clients and servers MUST implement protocol version 2 or higher to use:
		   o  The IV attribute of the EXT-X-KEY tag.
		   Clients and servers MUST implement protocol version 3 or higher to use:
		   o  Floating-point EXTINF duration values.
		   Clients and servers MUST implement protocol version 4 or higher to use:
		   o  The EXT-X-BYTERANGE tag.
		   o  The EXT-X-I-FRAME-STREAM-INF tag.
		   o  The EXT-X-I-FRAMES-ONLY tag.
		   o  The EXT-X-MEDIA tag.
		   o  The AUDIO and VIDEO attributes of the EXT-X-STREAM-INF tag.
	*/
	minver = uint8(3)
)

type ListType uint

const (
	UNKNOWN ListType = iota
	MASTER
	MEDIA
)

/*
 This structure represents a single bitrate playlist aka media playlist.
 It related to both a simple media playlists and a sliding window media playlists.
 URI lines in the Playlist point to media segments.

 Simple Media Playlist file sample:

   #EXTM3U
   #EXT-X-VERSION:3
   #EXT-X-TARGETDURATION:5220
   #EXTINF:5219.2,
   http://media.example.com/entire.ts
   #EXT-X-ENDLIST

 Sample of Sliding Window Media Playlist, using HTTPS:

   #EXTM3U
   #EXT-X-VERSION:3
   #EXT-X-TARGETDURATION:8
   #EXT-X-MEDIA-SEQUENCE:2680

   #EXTINF:7.975,
   https://priv.example.com/fileSequence2680.ts
   #EXTINF:7.941,
   https://priv.example.com/fileSequence2681.ts
   #EXTINF:7.975,
   https://priv.example.com/fileSequence2682.ts
*/
type MediaPlaylist struct {
	TargetDuration float64
	SeqNo          uint64 // EXT-X-MEDIA-SEQUENCE
	Segments       []*MediaSegment
	SID            string // optional session identifier (out of scope of HLS specs but useful in some cases)
	Iframe         bool   // EXT-X-I-FRAMES-ONLY
	Closed         bool   // is this VOD (closed) or Live (sliding) playlist?
	durationAsInt  bool   // output durations as integers of floats?
	keyformat      int
	winsize        uint // max number of segments removed from queue on playlist generation
	capacity       uint // total capacity of slice used for the playlist
	head           uint // head of FIFO, we add segments to head
	tail           uint // tail of FIFO, we remove segments from tail
	count          uint // number of segments in the playlist
	buf            bytes.Buffer
	ver            uint8
	WV             *WV // Widevine related tags
}

/*
 This structure represents a master playlist which combines media playlists for multiple bitrates.
 URI lines in the playlist identify media playlists.
 Sample of Master Playlist file:

   #EXTM3U
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000
   http://example.com/low.m3u8
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000
   http://example.com/mid.m3u8
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000
   http://example.com/hi.m3u8
   #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS="mp4a.40.5"
   http://example.com/audio-only.m3u8
*/
type MasterPlaylist struct {
	SID      string
	Variants []*Variant
	buf      bytes.Buffer
	ver      uint8
}

// This structure represents variants for master playlist.
// Variants included in a master playlist and point to media playlists.
type Variant struct {
	URI       string
	Chunklist *MediaPlaylist
	VariantParams
}

// This stucture represents additional parameters for a variant
type VariantParams struct {
	ProgramId  uint8
	Bandwidth  uint32
	Codecs     string
	Resolution string
	Audio      string
	Video      string
	Subtitles  string
	Iframe     bool // EXT-X-I-FRAME-STREAM-INF
	AltMedia   []*AltMedia
}

// This structure represents EXT-X-MEDIA tag in variants.
type AltMedia struct {
	GroupId         string
	URI             string
	Type            string
	Language        string
	Name            string
	Default         string
	Autoselect      string
	Forced          string
	Characteristics string
	Subtitles       string
}

// This structure represents a media segment included in a media playlist.
// Media segment may be encrypted.
// Widevine supports own tags for encryption metadata.
type MediaSegment struct {
	SeqId uint64
	Title string // optional second parameter for EXTINF tag
	URI   string
	// duration must be integers if protocol version is less than 3 but we are always keep them float
	Duration float64 // first parameter for EXTINF tag
	Key      *Key
}

// This structure represents information about stream encryption.
// Realizes EXT-X-KEY tag.
type Key struct {
	Method            string
	URI               string
	IV                string
	Keyformat         string
	Keyformatversions string
}

// This structure represents metadata  for Google Widevine playlists.
// This format not described in IETF draft but provied by Widevine packager as
// additional tags in the playlist.
type WV struct {
	AudioChannels          uint
	AudioFormat            uint
	AudioProfileIDC        uint
	AudioSampleSize        uint
	AudioSamplingFrequency uint
	CypherVersion          string
	ECM                    string
	VideoFormat            uint
	VideoFrameRate         uint
	VideoLevelIDC          uint
	VideoProfileIDC        uint
	VideoResolution        string
	VideoSAR               string
}

// Interface applied to various playlist types.
type Playlist interface {
	Encode() *bytes.Buffer
	Decode(bytes.Buffer, bool) error
}
<|endoftext|>


<commit_before>package turn

import (
	"encoding/binary"
	"errors"
	"net"
	"time"

	"github.com/pion/stun"
	"github.com/pion/turn/v2/internal/proto"
)

var (
	errInvalidTURNFrame    = errors.New("data is not a valid TURN frame, no STUN or ChannelData found")
	errIncompleteTURNFrame = errors.New("data contains incomplete STUN or TURN frame")
)

// STUNConn wraps a net.Conn and implements
// net.PacketConn by being STUN aware and
// packetizing the stream
type STUNConn struct {
	nextConn net.Conn
	buff     []byte
}

const (
	stunHeaderSize = 20

	channelDataLengthSize = 2
	channelDataNumberSize = channelDataLengthSize
	channelDataHeaderSize = channelDataLengthSize + channelDataNumberSize
	channelDataPadding    = 4
)

// Given a buffer give the last offset of the TURN frame
// If the buffer isn't a valid STUN or ChannelData packet
// or the length doesn't match return false
func consumeSingleTURNFrame(p []byte) (int, error) {
	// Too short to determine if ChannelData or STUN
	if len(p) < 9 {
		return 0, errIncompleteTURNFrame
	}

	var datagramSize uint16
	if stun.IsMessage(p) {
		datagramSize = binary.BigEndian.Uint16(p[2:4]) + stunHeaderSize
	} else if num := binary.BigEndian.Uint16(p[0:2]); proto.ChannelNumber(num).Valid() {
		datagramSize = binary.BigEndian.Uint16(p[channelDataNumberSize:channelDataHeaderSize])
		if paddingOverflow := (datagramSize + channelDataPadding) % channelDataPadding; paddingOverflow != 0 {
			datagramSize = (datagramSize + channelDataPadding) - paddingOverflow
		}

		datagramSize += channelDataHeaderSize
	} else if len(p) < stunHeaderSize {
		return 0, errIncompleteTURNFrame
	} else {
		return 0, errInvalidTURNFrame
	}

	if len(p) < int(datagramSize) {
		return 0, errIncompleteTURNFrame
	}

	return int(datagramSize), nil
}

// ReadFrom implements ReadFrom from net.PacketConn
func (s *STUNConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
	// First pass any buffered data from previous reads
	n, err = consumeSingleTURNFrame(s.buff)
	if errors.Is(err, errInvalidTURNFrame) {
		return 0, nil, err
	} else if err == nil {
		copy(p, s.buff[:n])
		s.buff = s.buff[n:]

		return n, s.nextConn.RemoteAddr(), nil
	}

	// Then read from the nextConn, appending to our buff
	n, err = s.nextConn.Read(p)
	if err != nil {
		return 0, nil, err
	}

	s.buff = append(s.buff, append([]byte{}, p[:n]...)...)
	return s.ReadFrom(p)
}

// WriteTo implements WriteTo from net.PacketConn
func (s *STUNConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
	return s.nextConn.Write(p)
}

// Close implements Close from net.PacketConn
func (s *STUNConn) Close() error {
	return s.nextConn.Close()
}

// LocalAddr implements LocalAddr from net.PacketConn
func (s *STUNConn) LocalAddr() net.Addr {
	return s.nextConn.LocalAddr()
}

// SetDeadline implements SetDeadline from net.PacketConn
func (s *STUNConn) SetDeadline(t time.Time) error {
	return s.nextConn.SetDeadline(t)
}

// SetReadDeadline implements SetReadDeadline from net.PacketConn
func (s *STUNConn) SetReadDeadline(t time.Time) error {
	return s.nextConn.SetReadDeadline(t)
}

// SetWriteDeadline implements SetWriteDeadline from net.PacketConn
func (s *STUNConn) SetWriteDeadline(t time.Time) error {
	return s.nextConn.SetWriteDeadline(t)
}

// NewSTUNConn creates a STUNConn
func NewSTUNConn(nextConn net.Conn) *STUNConn {
	return &STUNConn{nextConn: nextConn}
}
<commit_msg>Fix lint<commit_after>package turn

import (
	"encoding/binary"
	"errors"
	"net"
	"time"

	"github.com/pion/stun"
	"github.com/pion/turn/v2/internal/proto"
)

var (
	errInvalidTURNFrame    = errors.New("data is not a valid TURN frame, no STUN or ChannelData found")
	errIncompleteTURNFrame = errors.New("data contains incomplete STUN or TURN frame")
)

// STUNConn wraps a net.Conn and implements
// net.PacketConn by being STUN aware and
// packetizing the stream
type STUNConn struct {
	nextConn net.Conn
	buff     []byte
}

const (
	stunHeaderSize = 20

	channelDataLengthSize = 2
	channelDataNumberSize = channelDataLengthSize
	channelDataHeaderSize = channelDataLengthSize + channelDataNumberSize
	channelDataPadding    = 4
)

// Given a buffer give the last offset of the TURN frame
// If the buffer isn't a valid STUN or ChannelData packet
// or the length doesn't match return false
func consumeSingleTURNFrame(p []byte) (int, error) {
	// Too short to determine if ChannelData or STUN
	if len(p) < 9 {
		return 0, errIncompleteTURNFrame
	}

	var datagramSize uint16
	switch {
	case stun.IsMessage(p):
		datagramSize = binary.BigEndian.Uint16(p[2:4]) + stunHeaderSize
	case proto.ChannelNumber(binary.BigEndian.Uint16(p[0:2])).Valid():
		datagramSize = binary.BigEndian.Uint16(p[channelDataNumberSize:channelDataHeaderSize])
		if paddingOverflow := (datagramSize + channelDataPadding) % channelDataPadding; paddingOverflow != 0 {
			datagramSize = (datagramSize + channelDataPadding) - paddingOverflow
		}

		datagramSize += channelDataHeaderSize
	case len(p) < stunHeaderSize:
		return 0, errIncompleteTURNFrame
	default:
		return 0, errInvalidTURNFrame
	}

	if len(p) < int(datagramSize) {
		return 0, errIncompleteTURNFrame
	}

	return int(datagramSize), nil
}

// ReadFrom implements ReadFrom from net.PacketConn
func (s *STUNConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
	// First pass any buffered data from previous reads
	n, err = consumeSingleTURNFrame(s.buff)
	if errors.Is(err, errInvalidTURNFrame) {
		return 0, nil, err
	} else if err == nil {
		copy(p, s.buff[:n])
		s.buff = s.buff[n:]

		return n, s.nextConn.RemoteAddr(), nil
	}

	// Then read from the nextConn, appending to our buff
	n, err = s.nextConn.Read(p)
	if err != nil {
		return 0, nil, err
	}

	s.buff = append(s.buff, append([]byte{}, p[:n]...)...)
	return s.ReadFrom(p)
}

// WriteTo implements WriteTo from net.PacketConn
func (s *STUNConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
	return s.nextConn.Write(p)
}

// Close implements Close from net.PacketConn
func (s *STUNConn) Close() error {
	return s.nextConn.Close()
}

// LocalAddr implements LocalAddr from net.PacketConn
func (s *STUNConn) LocalAddr() net.Addr {
	return s.nextConn.LocalAddr()
}

// SetDeadline implements SetDeadline from net.PacketConn
func (s *STUNConn) SetDeadline(t time.Time) error {
	return s.nextConn.SetDeadline(t)
}

// SetReadDeadline implements SetReadDeadline from net.PacketConn
func (s *STUNConn) SetReadDeadline(t time.Time) error {
	return s.nextConn.SetReadDeadline(t)
}

// SetWriteDeadline implements SetWriteDeadline from net.PacketConn
func (s *STUNConn) SetWriteDeadline(t time.Time) error {
	return s.nextConn.SetWriteDeadline(t)
}

// NewSTUNConn creates a STUNConn
func NewSTUNConn(nextConn net.Conn) *STUNConn {
	return &STUNConn{nextConn: nextConn}
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
	"errors"

	"github.com/ava-labs/avalanchego/codec"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow"
	"github.com/ava-labs/avalanchego/vms/components/avax"
	"github.com/ava-labs/avalanchego/vms/components/verify"
)

var (
	errOperationsNotSortedUnique = errors.New("operations not sorted and unique")
	errNoOperations              = errors.New("an operationTx must have at least one operation")
	errDoubleSpend               = errors.New("inputs attempt to double spend an input")
)

// OperationTx is a transaction with no credentials.
type OperationTx struct {
	BaseTx `serialize:"true"`
	Ops    []*Operation `serialize:"true" json:"operations"`
}

func (t *OperationTx) Init(vm *VM) error {
	for i, n := 0, len(t.Ops); i < n; i++ {
		op := t.Ops[i]
		fx, err := vm.getParsedFx(op.Op)
		if err != nil {
			return err
		}
		op.FxID = fx.ID
		op.Op.InitCtx(vm.ctx)
	}

	return t.BaseTx.Init(vm)
}

// Operations track which ops this transaction is performing. The returned array
// should not be modified.
func (t *OperationTx) Operations() []*Operation { return t.Ops }

// InputUTXOs track which UTXOs this transaction is consuming.
func (t *OperationTx) InputUTXOs() []*avax.UTXOID {
	utxos := t.BaseTx.InputUTXOs()
	for _, op := range t.Ops {
		utxos = append(utxos, op.UTXOIDs...)
	}
	return utxos
}

// ConsumedAssetIDs returns the IDs of the assets this transaction consumes
func (t *OperationTx) ConsumedAssetIDs() ids.Set {
	assets := t.BaseTx.AssetIDs()
	for _, op := range t.Ops {
		if len(op.UTXOIDs) > 0 {
			assets.Add(op.AssetID())
		}
	}
	return assets
}

// AssetIDs returns the IDs of the assets this transaction depends on
func (t *OperationTx) AssetIDs() ids.Set {
	assets := t.BaseTx.AssetIDs()
	for _, op := range t.Ops {
		assets.Add(op.AssetID())
	}
	return assets
}

// NumCredentials returns the number of expected credentials
func (t *OperationTx) NumCredentials() int { return t.BaseTx.NumCredentials() + len(t.Ops) }

// UTXOs returns the UTXOs transaction is producing.
func (t *OperationTx) UTXOs() []*avax.UTXO {
	txID := t.ID()
	utxos := t.BaseTx.UTXOs()

	for _, op := range t.Ops {
		asset := op.AssetID()
		for _, out := range op.Op.Outs() {
			utxos = append(utxos, &avax.UTXO{
				UTXOID: avax.UTXOID{
					TxID:        txID,
					OutputIndex: uint32(len(utxos)),
				},
				Asset: avax.Asset{ID: asset},
				Out:   out,
			})
		}
	}

	return utxos
}

// SyntacticVerify that this transaction is well-formed.
func (t *OperationTx) SyntacticVerify(
	ctx *snow.Context,
	c codec.Manager,
	txFeeAssetID ids.ID,
	txFee uint64,
	_ uint64,
	numFxs int,
) error {
	switch {
	case t == nil:
		return errNilTx
	case len(t.Ops) == 0:
		return errNoOperations
	}

	if err := t.BaseTx.SyntacticVerify(ctx, c, txFeeAssetID, txFee, txFee, numFxs); err != nil {
		return err
	}

	inputs := ids.NewSet(len(t.Ins))
	for _, in := range t.Ins {
		inputs.Add(in.InputID())
	}

	for _, op := range t.Ops {
		if err := op.Verify(c); err != nil {
			return err
		}
		for _, utxoID := range op.UTXOIDs {
			inputID := utxoID.InputID()
			if inputs.Contains(inputID) {
				return errDoubleSpend
			}
			inputs.Add(inputID)
		}
	}
	if !isSortedAndUniqueOperations(t.Ops, c) {
		return errOperationsNotSortedUnique
	}
	return nil
}

// SemanticVerify that this transaction is well-formed.
func (t *OperationTx) SemanticVerify(vm *VM, tx UnsignedTx, creds []verify.Verifiable) error {
	if err := t.BaseTx.SemanticVerify(vm, tx, creds); err != nil {
		return err
	}

	offset := t.BaseTx.NumCredentials()
	for i, op := range t.Ops {
		cred := creds[offset+i]
		if err := vm.verifyOperation(tx, op, cred); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>use range<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
	"errors"

	"github.com/ava-labs/avalanchego/codec"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow"
	"github.com/ava-labs/avalanchego/vms/components/avax"
	"github.com/ava-labs/avalanchego/vms/components/verify"
)

var (
	errOperationsNotSortedUnique = errors.New("operations not sorted and unique")
	errNoOperations              = errors.New("an operationTx must have at least one operation")
	errDoubleSpend               = errors.New("inputs attempt to double spend an input")
)

// OperationTx is a transaction with no credentials.
type OperationTx struct {
	BaseTx `serialize:"true"`
	Ops    []*Operation `serialize:"true" json:"operations"`
}

func (t *OperationTx) Init(vm *VM) error {
	for _, op := range t.Ops {
		fx, err := vm.getParsedFx(op.Op)
		if err != nil {
			return err
		}
		op.FxID = fx.ID
		op.Op.InitCtx(vm.ctx)
	}

	return t.BaseTx.Init(vm)
}

// Operations track which ops this transaction is performing. The returned array
// should not be modified.
func (t *OperationTx) Operations() []*Operation { return t.Ops }

// InputUTXOs track which UTXOs this transaction is consuming.
func (t *OperationTx) InputUTXOs() []*avax.UTXOID {
	utxos := t.BaseTx.InputUTXOs()
	for _, op := range t.Ops {
		utxos = append(utxos, op.UTXOIDs...)
	}
	return utxos
}

// ConsumedAssetIDs returns the IDs of the assets this transaction consumes
func (t *OperationTx) ConsumedAssetIDs() ids.Set {
	assets := t.BaseTx.AssetIDs()
	for _, op := range t.Ops {
		if len(op.UTXOIDs) > 0 {
			assets.Add(op.AssetID())
		}
	}
	return assets
}

// AssetIDs returns the IDs of the assets this transaction depends on
func (t *OperationTx) AssetIDs() ids.Set {
	assets := t.BaseTx.AssetIDs()
	for _, op := range t.Ops {
		assets.Add(op.AssetID())
	}
	return assets
}

// NumCredentials returns the number of expected credentials
func (t *OperationTx) NumCredentials() int { return t.BaseTx.NumCredentials() + len(t.Ops) }

// UTXOs returns the UTXOs transaction is producing.
func (t *OperationTx) UTXOs() []*avax.UTXO {
	txID := t.ID()
	utxos := t.BaseTx.UTXOs()

	for _, op := range t.Ops {
		asset := op.AssetID()
		for _, out := range op.Op.Outs() {
			utxos = append(utxos, &avax.UTXO{
				UTXOID: avax.UTXOID{
					TxID:        txID,
					OutputIndex: uint32(len(utxos)),
				},
				Asset: avax.Asset{ID: asset},
				Out:   out,
			})
		}
	}

	return utxos
}

// SyntacticVerify that this transaction is well-formed.
func (t *OperationTx) SyntacticVerify(
	ctx *snow.Context,
	c codec.Manager,
	txFeeAssetID ids.ID,
	txFee uint64,
	_ uint64,
	numFxs int,
) error {
	switch {
	case t == nil:
		return errNilTx
	case len(t.Ops) == 0:
		return errNoOperations
	}

	if err := t.BaseTx.SyntacticVerify(ctx, c, txFeeAssetID, txFee, txFee, numFxs); err != nil {
		return err
	}

	inputs := ids.NewSet(len(t.Ins))
	for _, in := range t.Ins {
		inputs.Add(in.InputID())
	}

	for _, op := range t.Ops {
		if err := op.Verify(c); err != nil {
			return err
		}
		for _, utxoID := range op.UTXOIDs {
			inputID := utxoID.InputID()
			if inputs.Contains(inputID) {
				return errDoubleSpend
			}
			inputs.Add(inputID)
		}
	}
	if !isSortedAndUniqueOperations(t.Ops, c) {
		return errOperationsNotSortedUnique
	}
	return nil
}

// SemanticVerify that this transaction is well-formed.
func (t *OperationTx) SemanticVerify(vm *VM, tx UnsignedTx, creds []verify.Verifiable) error {
	if err := t.BaseTx.SemanticVerify(vm, tx, creds); err != nil {
		return err
	}

	offset := t.BaseTx.NumCredentials()
	for i, op := range t.Ops {
		cred := creds[offset+i]
		if err := vm.verifyOperation(tx, op, cred); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>