<commit_before>package ppm

import (
	"bufio"
	"fmt"
	"image"
	"io"
)

func Decode(r io.Reader) (image.Image, error) {
	b := bufio.NewReader(r)
	return decode(b)
}

func decode(r *bufio.Reader) (image.Image, error) {

	// Check magic.
	if err := decodeMagic(r); err != nil {
		return nil, fmt.Errorf("Failed to decode magic: %v", err)
	}

	// Read comments and white space.
	if err := decodeComments(r); err != nil {
		return nil, fmt.Errorf("Failed to decode comments: %v", err)
	}

	// Get the image size.
	width, height, err := decodeWidthHeight(r)
	if err != nil {
		return nil, fmt.Errorf("Failed to decode width/height: %v", err)
	}

	// Get image color format.
	if _, err := decodeFormat(r); err != nil {
		return nil, fmt.Errorf("Failed to decode format; %v", err)
	}

	// Read the image data.
	i, err := decodeImage(r, width, height)

	return i, nil
}

func decodeMagic(r *bufio.Reader) error {

	s, err := r.ReadString('\n')
	if err != nil {
		return fmt.Errorf("Failed to read magic: %v", err.Error())
	}

	if s != "P6\n" {
		return fmt.Errorf("Invalid magic.")
	}

	return nil

}

func decodeComments(r *bufio.Reader) error {

	for {
		if b, err := r.Peek(1); err != nil {
			return err
		} else if b[0] == '#' {
			if _, err := r.ReadBytes('\n'); err != nil {
				return fmt.Errorf("Failed to read white space: %v", err.Error())
			}
		} else {
			break
		}
	}

	return nil
}

func decodeWidthHeight(r *bufio.Reader) (int, int, error) {

	var width, height int
	if n, err := fmt.Fscanf(r, "%d %d\n", &width, &height); err != nil {
		return width, height, fmt.Errorf("Failed to read width/height: %v", err.Error())
	} else if n != 2 {
		return width, height, fmt.Errorf("Failed to read image width/height.")
	}

	if width < 0 || height < 0 {
		return 0, 0, fmt.Errorf("out of range.")
	}

	return width, height, nil

}

func decodeFormat(r *bufio.Reader) (int, error) {

	var rgb_color int
	if n, err := fmt.Fscanf(r, "%d\n", &rgb_color); err != nil {
		return rgb_color, fmt.Errorf("Failed to read format: %v", err.Error())
	} else if n != 1 {
		return rgb_color, fmt.Errorf("Failed to read format.")
	}

	if rgb_color != 255 {
		return rgb_color, fmt.Errorf("Invalid or unsupported color format.")
	}

	return rgb_color, nil
}

func decodeImage(r *bufio.Reader, width, height int) (image.Image, error) {

	if width < 0 || height < 0 {
		return nil, fmt.Errorf("Invalid image size.")
	}

	b := make([]byte, 3)
	i := image.NewRGBA(image.Rect(0, 0, width, height))
	for x := 0; x < width*height; x++ {

		if _, err := io.ReadFull(r, b); err != nil {
			return nil, fmt.Errorf("Failed to read image data: %v", err.Error())
		}

		o := x * 4
		i.Pix[o+0] = b[0]
		i.Pix[o+1] = b[1]
		i.Pix[o+2] = b[2]
		i.Pix[o+3] = 0xFF

	}

	return i, nil

}
<commit_msg>Added format registration.<commit_after>package ppm

import (
	"bufio"
	"fmt"
	"image"
	"image/color"
	"io"
)

const pngHeader = "P6\n"

func Decode(r io.Reader) (image.Image, error) {
	b := bufio.NewReader(r)
	return decode(b)
}

func decode(r *bufio.Reader) (image.Image, error) {

	// Check magic.
	if err := decodeMagic(r); err != nil {
		return nil, fmt.Errorf("Failed to decode magic: %v", err)
	}

	// Read comments and white space.
	if err := decodeComments(r); err != nil {
		return nil, fmt.Errorf("Failed to decode comments: %v", err)
	}

	// Get the image size.
	width, height, err := decodeWidthHeight(r)
	if err != nil {
		return nil, fmt.Errorf("Failed to decode width/height: %v", err)
	}

	// Get image color format.
	if _, err := decodeFormat(r); err != nil {
		return nil, fmt.Errorf("Failed to decode format; %v", err)
	}

	// Read the image data.
	i, err := decodeImage(r, width, height)

	return i, nil
}

func decodeMagic(r *bufio.Reader) error {

	s, err := r.ReadString('\n')
	if err != nil {
		return fmt.Errorf("Failed to read magic: %v", err.Error())
	}

	if s != "P6\n" {
		return fmt.Errorf("Invalid magic.")
	}

	return nil

}

func decodeComments(r *bufio.Reader) error {

	for {
		if b, err := r.Peek(1); err != nil {
			return err
		} else if b[0] == '#' {
			if _, err := r.ReadBytes('\n'); err != nil {
				return fmt.Errorf("Failed to read white space: %v", err.Error())
			}
		} else {
			break
		}
	}

	return nil
}

func decodeWidthHeight(r *bufio.Reader) (int, int, error) {

	var width, height int
	if n, err := fmt.Fscanf(r, "%d %d\n", &width, &height); err != nil {
		return width, height, fmt.Errorf("Failed to read width/height: %v", err.Error())
	} else if n != 2 {
		return width, height, fmt.Errorf("Failed to read image width/height.")
	}

	if width < 0 || height < 0 {
		return 0, 0, fmt.Errorf("out of range.")
	}

	return width, height, nil

}

func decodeFormat(r *bufio.Reader) (int, error) {

	var rgb_color int
	if n, err := fmt.Fscanf(r, "%d\n", &rgb_color); err != nil {
		return rgb_color, fmt.Errorf("Failed to read format: %v", err.Error())
	} else if n != 1 {
		return rgb_color, fmt.Errorf("Failed to read format.")
	}

	if rgb_color != 255 {
		return rgb_color, fmt.Errorf("Invalid or unsupported color format.")
	}

	return rgb_color, nil
}

func decodeImage(r *bufio.Reader, width, height int) (image.Image, error) {

	if width < 0 || height < 0 {
		return nil, fmt.Errorf("Invalid image size.")
	}

	b := make([]byte, 3)
	i := image.NewRGBA(image.Rect(0, 0, width, height))
	for x := 0; x < width*height; x++ {

		if _, err := io.ReadFull(r, b); err != nil {
			return nil, fmt.Errorf("Failed to read image data: %v", err.Error())
		}

		o := x * 4
		i.Pix[o+0] = b[0]
		i.Pix[o+1] = b[1]
		i.Pix[o+2] = b[2]
		i.Pix[o+3] = 0xFF

	}

	return i, nil
}

func DecodeConfig(r io.Reader) (image.Config, error) {

	b := bufio.NewReader(r)

	// Read the header.
	if err := decodeMagic(b); err != nil {

		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}

		return image.Config{}, err
	}

	// Read comments and white space.
	if err := decodeComments(b); err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		return image.Config{}, err
	}

	// Get the image size.
	width, height, err := decodeWidthHeight(b)
	if err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		return image.Config{}, err
	}

	return image.Config{
		// This decoder only works with color.RGBAModel
		ColorModel: color.RGBAModel,
		Width:      width,
		Height:     height,
	}, nil
}

func init() {
	image.RegisterFormat("ppm", pngHeader, Decode, DecodeConfig)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Intel Corporation

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

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

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

package rdt

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/ghodss/yaml"

	pkgcfg "github.com/intel/cri-resource-manager/pkg/config"
	logger "github.com/intel/cri-resource-manager/pkg/log"
	"github.com/intel/cri-resource-manager/pkg/utils"
)

const resctrlGroupPrefix = "cri-resmgr."

// Control is the interface managing Intel RDT resources
type Control interface {
	// GetClasses returns the names of RDT classes (or resctrl control groups)
	// available
	GetClasses() []string

	// SetProcessClass assigns a set of processes to a RDT class
	SetProcessClass(string, ...string) error
}

var rdtInfo Info

type control struct {
	logger.Logger

	conf config
}

type config struct {
	Options       SchemaOptions                 `json:"options,omitempty"`
	ResctrlGroups map[string]ResctrlGroupConfig `json:"resctrlGroups"`
}

// NewControl returns new instance of the RDT Control interface
func NewControl(resctrlpath string) (Control, error) {
	var err error
	r := &control{Logger: logger.NewLogger("rdt")}

	// Get info from the resctrl filesystem
	rdtInfo, err = getRdtInfo(resctrlpath)
	if err != nil {
		return nil, err
	}

	// Configure resctrl
	r.conf = opt.Config
	if err := r.configureResctrl(r.conf); err != nil {
		return nil, rdtError("configuration failed: %v", err)
	}

	pkgcfg.GetModule("rdt").AddNotify(r.configNotify)

	return r, nil
}

func (r *control) GetClasses() []string {
	ret := make([]string, len(r.conf.ResctrlGroups))

	i := 0
	for k := range r.conf.ResctrlGroups {
		ret[i] = k
		i++
	}
	sort.Strings(ret)
	return ret
}

func (r *control) SetProcessClass(class string, pids ...string) error {
	if _, ok := r.conf.ResctrlGroups[class]; !ok {
		return rdtError("unknown RDT class %q", class)
	}

	path := filepath.Join(r.resctrlGroupPath(class), "tasks")
	f, err := os.OpenFile(path, os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	for _, pid := range pids {
		if _, err := f.WriteString(pid + "\n"); err != nil {
			unwrapped := err
			if pathError, ok := err.(*os.PathError); ok {
				unwrapped = pathError.Unwrap()
			}
			if unwrapped == syscall.ESRCH {
				r.Debug("no task %s", pid)
			} else {
				return rdtError("failed to assign processes %v to class %q: %v", pids, class, r.cmdError(err))
			}
		}
	}
	return nil
}

func (r *control) configNotify(event pkgcfg.Event, source pkgcfg.Source) error {
	r.Info("configuration %s", event)

	err := r.configureResctrl(opt.Config)
	if err != nil {
		return rdtError("resctrl configuration failed: %v", err)
	}

	r.conf = opt.Config

	return nil
}

func (r *control) configureResctrl(conf config) error {
	r.DebugBlock("  applying ", "%s", utils.DumpJSON(conf))

	// Remove stale resctrl groups
	existingGroups, err := r.getResctrlGroups()
	if err != nil {
		return err
	}

	for _, name := range existingGroups {
		if _, ok := conf.ResctrlGroups[name]; !ok {
			tasks, err := r.resctrlGroupTasks(name)
			if err != nil {
				return rdtError("failed to get resctrl group tasks: %v", err)
			}
			path := r.resctrlGroupPath(name)
			if len(tasks) > 0 {
				return rdtError("refusing to remove non-empty resctrl group %q", path)
			}
			err = os.Remove(path)
			if err != nil {
				return rdtError("failed to remove resctrl group %q: %v", path, err)
			}
		}
	}

	// Try to apply given configuration
	for name, grpConf := range conf.ResctrlGroups {
		err := r.configureResctrlGroup(name, grpConf, conf.Options)
		if err != nil {
			return err
		}
	}

	return nil
}

func parseConfData(raw []byte) (config, error) {
	conf := config{}

	err := yaml.Unmarshal(raw, &conf)
	if err != nil {
		return conf, rdtError("failed to parse configuration: %v", err)
	}
	return conf, nil
}

func (r *control) configureResctrlGroup(name string, config ResctrlGroupConfig, options SchemaOptions) error {
	if err := os.Mkdir(r.resctrlGroupPath(name), 0755); err != nil && !os.IsExist(err) {
		return err
	}

	schemata := ""
	// Handle L3 cache allocation
	switch {
	case rdtInfo.l3.Supported():
		schemata += config.L3Schema.ToStr(L3SchemaTypeUnified)
	case rdtInfo.l3data.Supported() || rdtInfo.l3code.Supported():
		schemata += config.L3Schema.ToStr(L3SchemaTypeCode)
		schemata += config.L3Schema.ToStr(L3SchemaTypeData)
	default:
		if !config.L3Schema.IsNil() && !options.L3.Optional {
			return rdtError("L3 cache allocation for %q specified in configuration but not supported by system", name)
		}
	}

	// Handle memory bandwidth allocation
	switch {
	case rdtInfo.mb.Supported():
		schemata += config.MBSchema.ToStr()
	default:
		if !config.MBSchema.IsNil() && !options.MB.Optional {
			return rdtError("memory bandwidth allocation specified in configuration but not supported by system")
		}
	}

	if len(schemata) > 0 {
		r.Debug("writing schemata %q", schemata)
		dirName := r.resctrlGroupDirName(name)
		if err := r.writeRdtFile(filepath.Join(dirName, "schemata"), []byte(schemata)); err != nil {
			return err
		}
	} else {
		r.Debug("empty schemata")
	}

	return nil
}

func (r *control) resctrlGroupDirName(name string) string {
	return resctrlGroupPrefix + name
}

func (r *control) resctrlGroupPath(name string) string {
	return filepath.Join(rdtInfo.resctrlPath, r.resctrlGroupDirName(name))
}

func (r *control) getResctrlGroups() ([]string, error) {

	files, err := ioutil.ReadDir(rdtInfo.resctrlPath)
	if err != nil {
		return nil, err
	}
	groups := make([]string, 0, len(files))
	for _, file := range files {
		fullName := file.Name()
		if strings.HasPrefix(fullName, resctrlGroupPrefix) {
			groups = append(groups, fullName[len(resctrlGroupPrefix):])
		}
	}
	return groups, nil
}

func (r *control) resctrlGroupTasks(name string) ([]string, error) {
	data, err := r.readRdtFile(filepath.Join(r.resctrlGroupDirName(name), "tasks"))
	if err != nil {
		return []string{}, err
	}
	split := strings.Split(strings.TrimSpace(string(data)), "\n")
	if len(split[0]) > 0 {
		return split, nil
	}
	return []string{}, nil
}

func (r *control) readRdtFile(rdtPath string) ([]byte, error) {
	return ioutil.ReadFile(filepath.Join(rdtInfo.resctrlPath, rdtPath))
}

func (r *control) writeRdtFile(rdtPath string, data []byte) error {
	if err := ioutil.WriteFile(filepath.Join(rdtInfo.resctrlPath, rdtPath), data, 0644); err != nil {
		return r.cmdError(err)
	}
	return nil
}

func (r *control) cmdError(origErr error) error {
	errData, readErr := r.readRdtFile(filepath.Join("info", "last_cmd_status"))
	if readErr != nil {
		return origErr
	}
	cmdStatus := strings.TrimSpace(string(errData))
	if len(cmdStatus) > 0 && cmdStatus != "ok" {
		return fmt.Errorf("%s", cmdStatus)
	}
	return origErr
}

func rdtError(format string, args ...interface{}) error {
	return fmt.Errorf("rdt: "+format, args...)
}
<commit_msg>(import)rdt: extra hack for getting rdt properly configured and started<commit_after>/*
Copyright 2019 Intel Corporation

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

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

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

package rdt

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/ghodss/yaml"

	pkgcfg "github.com/intel/cri-resource-manager/pkg/config"
	logger "github.com/intel/cri-resource-manager/pkg/log"
	"github.com/intel/cri-resource-manager/pkg/utils"
)

const resctrlGroupPrefix = "cri-resmgr."

// Control is the interface managing Intel RDT resources
type Control interface {
	// GetClasses returns the names of RDT classes (or resctrl control groups)
	// available
	GetClasses() []string

	// SetProcessClass assigns a set of processes to a RDT class
	SetProcessClass(string, ...string) error
}

var rdtInfo Info

type control struct {
	logger.Logger

	conf config
}

type config struct {
	Options       SchemaOptions                 `json:"options,omitempty"`
	ResctrlGroups map[string]ResctrlGroupConfig `json:"resctrlGroups"`
}

// NewControl returns new instance of the RDT Control interface
func NewControl(resctrlpath string) (Control, error) {
	var err error
	r := &control{Logger: logger.NewLogger("rdt")}

	// Get info from the resctrl filesystem
	rdtInfo, err = getRdtInfo(resctrlpath)
	if err != nil {
		return nil, err
	}

	// Configure resctrl
	r.conf = opt.Config
	if err := r.configureResctrl(r.conf); err != nil {
		// Temporary hack to get rdt properly configured.
		// Corresponging hack located in pkg/cri/resource-manager/resource-manager.go
		// TODO: switch back to returning an error after rdt config management is fixed
		r.Warn("configuration failed: %v", err)
	}

	pkgcfg.GetModule("rdt").AddNotify(r.configNotify)

	return r, nil
}

func (r *control) GetClasses() []string {
	ret := make([]string, len(r.conf.ResctrlGroups))

	i := 0
	for k := range r.conf.ResctrlGroups {
		ret[i] = k
		i++
	}
	sort.Strings(ret)
	return ret
}

func (r *control) SetProcessClass(class string, pids ...string) error {
	if _, ok := r.conf.ResctrlGroups[class]; !ok {
		return rdtError("unknown RDT class %q", class)
	}

	path := filepath.Join(r.resctrlGroupPath(class), "tasks")
	f, err := os.OpenFile(path, os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	for _, pid := range pids {
		if _, err := f.WriteString(pid + "\n"); err != nil {
			unwrapped := err
			if pathError, ok := err.(*os.PathError); ok {
				unwrapped = pathError.Unwrap()
			}
			if unwrapped == syscall.ESRCH {
				r.Debug("no task %s", pid)
			} else {
				return rdtError("failed to assign processes %v to class %q: %v", pids, class, r.cmdError(err))
			}
		}
	}
	return nil
}

func (r *control) configNotify(event pkgcfg.Event, source pkgcfg.Source) error {
	r.Info("configuration %s", event)

	err := r.configureResctrl(opt.Config)
	if err != nil {
		return rdtError("resctrl configuration failed: %v", err)
	}

	r.conf = opt.Config

	return nil
}

func (r *control) configureResctrl(conf config) error {
	r.DebugBlock("  applying ", "%s", utils.DumpJSON(conf))

	// Remove stale resctrl groups
	existingGroups, err := r.getResctrlGroups()
	if err != nil {
		return err
	}

	for _, name := range existingGroups {
		if _, ok := conf.ResctrlGroups[name]; !ok {
			tasks, err := r.resctrlGroupTasks(name)
			if err != nil {
				return rdtError("failed to get resctrl group tasks: %v", err)
			}
			path := r.resctrlGroupPath(name)
			if len(tasks) > 0 {
				return rdtError("refusing to remove non-empty resctrl group %q", path)
			}
			err = os.Remove(path)
			if err != nil {
				return rdtError("failed to remove resctrl group %q: %v", path, err)
			}
		}
	}

	// Try to apply given configuration
	for name, grpConf := range conf.ResctrlGroups {
		err := r.configureResctrlGroup(name, grpConf, conf.Options)
		if err != nil {
			return err
		}
	}

	return nil
}

func parseConfData(raw []byte) (config, error) {
	conf := config{}

	err := yaml.Unmarshal(raw, &conf)
	if err != nil {
		return conf, rdtError("failed to parse configuration: %v", err)
	}
	return conf, nil
}

func (r *control) configureResctrlGroup(name string, config ResctrlGroupConfig, options SchemaOptions) error {
	if err := os.Mkdir(r.resctrlGroupPath(name), 0755); err != nil && !os.IsExist(err) {
		return err
	}

	schemata := ""
	// Handle L3 cache allocation
	switch {
	case rdtInfo.l3.Supported():
		schemata += config.L3Schema.ToStr(L3SchemaTypeUnified)
	case rdtInfo.l3data.Supported() || rdtInfo.l3code.Supported():
		schemata += config.L3Schema.ToStr(L3SchemaTypeCode)
		schemata += config.L3Schema.ToStr(L3SchemaTypeData)
	default:
		if !config.L3Schema.IsNil() && !options.L3.Optional {
			return rdtError("L3 cache allocation for %q specified in configuration but not supported by system", name)
		}
	}

	// Handle memory bandwidth allocation
	switch {
	case rdtInfo.mb.Supported():
		schemata += config.MBSchema.ToStr()
	default:
		if !config.MBSchema.IsNil() && !options.MB.Optional {
			return rdtError("memory bandwidth allocation specified in configuration but not supported by system")
		}
	}

	if len(schemata) > 0 {
		r.Debug("writing schemata %q", schemata)
		dirName := r.resctrlGroupDirName(name)
		if err := r.writeRdtFile(filepath.Join(dirName, "schemata"), []byte(schemata)); err != nil {
			return err
		}
	} else {
		r.Debug("empty schemata")
	}

	return nil
}

func (r *control) resctrlGroupDirName(name string) string {
	return resctrlGroupPrefix + name
}

func (r *control) resctrlGroupPath(name string) string {
	return filepath.Join(rdtInfo.resctrlPath, r.resctrlGroupDirName(name))
}

func (r *control) getResctrlGroups() ([]string, error) {

	files, err := ioutil.ReadDir(rdtInfo.resctrlPath)
	if err != nil {
		return nil, err
	}
	groups := make([]string, 0, len(files))
	for _, file := range files {
		fullName := file.Name()
		if strings.HasPrefix(fullName, resctrlGroupPrefix) {
			groups = append(groups, fullName[len(resctrlGroupPrefix):])
		}
	}
	return groups, nil
}

func (r *control) resctrlGroupTasks(name string) ([]string, error) {
	data, err := r.readRdtFile(filepath.Join(r.resctrlGroupDirName(name), "tasks"))
	if err != nil {
		return []string{}, err
	}
	split := strings.Split(strings.TrimSpace(string(data)), "\n")
	if len(split[0]) > 0 {
		return split, nil
	}
	return []string{}, nil
}

func (r *control) readRdtFile(rdtPath string) ([]byte, error) {
	return ioutil.ReadFile(filepath.Join(rdtInfo.resctrlPath, rdtPath))
}

func (r *control) writeRdtFile(rdtPath string, data []byte) error {
	if err := ioutil.WriteFile(filepath.Join(rdtInfo.resctrlPath, rdtPath), data, 0644); err != nil {
		return r.cmdError(err)
	}
	return nil
}

func (r *control) cmdError(origErr error) error {
	errData, readErr := r.readRdtFile(filepath.Join("info", "last_cmd_status"))
	if readErr != nil {
		return origErr
	}
	cmdStatus := strings.TrimSpace(string(errData))
	if len(cmdStatus) > 0 && cmdStatus != "ok" {
		return fmt.Errorf("%s", cmdStatus)
	}
	return origErr
}

func rdtError(format string, args ...interface{}) error {
	return fmt.Errorf("rdt: "+format, args...)
}
<|endoftext|>


<commit_before>package gorums

import (
	"context"

	"github.com/relab/gorums/ordering"
	"google.golang.org/protobuf/reflect/protoreflect"
)

type CallData struct {
	Manager *Manager
	Node    *Node
	Message protoreflect.ProtoMessage
	Method  string
}

func RPCCall(ctx context.Context, d CallData) (resp protoreflect.ProtoMessage, err error) {
	msgID := d.Manager.nextMsgID()
	// set up channel to collect replies to this call.
	replyChan := make(chan *gorumsStreamResult, 1)
	d.Manager.putChan(msgID, replyChan)
	// and remove it when the call is complete
	defer d.Manager.deleteChan(msgID)

	md := &ordering.Metadata{
		MessageID: msgID,
		Method:    d.Method,
	}

	d.Node.sendQ <- gorumsStreamRequest{ctx: ctx, msg: &Message{Metadata: md, Message: d.Message}}

	select {
	case r := <-replyChan:
		if r.err != nil {
			return nil, err
		}
		return r.reply, nil
	case <-ctx.Done():
		return resp, ctx.Err()
	}
}
<commit_msg>Replaced receiveQueue methods w/newCall in RPCCall<commit_after>package gorums

import (
	"context"

	"google.golang.org/protobuf/reflect/protoreflect"
)

type CallData struct {
	Manager *Manager
	Node    *Node
	Message protoreflect.ProtoMessage
	Method  string
}

func RPCCall(ctx context.Context, d CallData) (resp protoreflect.ProtoMessage, err error) {
	replyChan := make(chan *gorumsStreamResult, 1)
	md, callDone := d.Manager.newCall(d.Method, replyChan)
	defer callDone()

	d.Node.sendQ <- gorumsStreamRequest{ctx: ctx, msg: &Message{Metadata: md, Message: d.Message}}

	select {
	case r := <-replyChan:
		if r.err != nil {
			return nil, err
		}
		return r.reply, nil
	case <-ctx.Done():
		return resp, ctx.Err()
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"log"
	"os"
	"path"
	"reflect"
	"sort"
	"strings"

	"go/ast"
	"go/build"
	"go/doc"
	"go/parser"
	"go/token"

	"github.com/ibelie/ruid"
	"github.com/ibelie/tygo"
)

var (
	SRC_PATH = path.Join(os.Getenv("GOPATH"), "src")
	PKG_PATH = reflect.TypeOf(Depend{}).PkgPath()
)

type Service interface {
	Procedure(ruid.RUID, uint64, []byte) ([]byte, error)
}

type IServer interface {
	Notify(ruid.RUID, ruid.RUID, []byte) error
	Distribute(ruid.RUID, ruid.RUID, uint64, uint64, []byte, chan<- []byte) error
	Procedure(ruid.RUID, ruid.RUID, uint64, uint64, []byte) ([]byte, error)
}

type Register func(IServer, map[string]uint64) (uint64, Service)

type Depend struct {
	Path     string
	Services []string
}

type Entity struct {
	Name       string
	Components []*tygo.Object
}

func SerializeSession(i ruid.RUID, symbols map[string]uint64, components ...[]byte) (data []byte) {
	size := tygo.SizeVarint(uint64(i))
	return nil
}

func Extract(dir string) (pkgname string, depends []*Depend) {
	buildPackage, err := build.Import(dir, "", build.ImportComment)
	if err != nil {
		log.Fatalf("[RPC][Entity] Cannot import package:\n>>>>%v", err)
		return
	}
	fs := token.NewFileSet()
	for _, filename := range buildPackage.GoFiles {
		file, err := parser.ParseFile(fs, path.Join(buildPackage.Dir, filename), nil, parser.ParseComments)
		if err != nil {
			log.Fatalf("[RPC][Entity] Cannot parse file:\n>>>>%v", err)
		}
		pkgname = file.Name.Name
		for _, d := range file.Decls {
			decl, ok := d.(*ast.GenDecl)
			if !ok || decl.Tok != token.IMPORT {
				continue
			}
			for _, s := range decl.Specs {
				spec, ok := s.(*ast.ImportSpec)
				if !ok || strings.Trim(spec.Path.Value, "\"") != PKG_PATH {
					continue
				}
				if strings.TrimSpace(decl.Doc.Text()) != "" {
					depends = merge(depends, parse(decl.Doc.Text())...)
				}
			}
		}
	}
	return
}

func parse(code string) (depends []*Depend) {
	code = strings.Split(code, "depends on:")[1]
	for _, line := range strings.Split(code, "\n") {
		tokens := strings.Split(line, "from")
		if len(tokens) != 2 {
			continue
		}
		depends = merge(depends, &Depend{
			Services: []string{strings.TrimSpace(tokens[0])},
			Path:     strings.TrimSpace(tokens[1]),
		})
	}
	return
}

func merge(a []*Depend, b ...*Depend) (c []*Depend) {
	var sorted []string
	m := make(map[string]map[string]bool)
	for _, ab := range [][]*Depend{a, b} {
		for _, x := range ab {
			if _, ok := m[x.Path]; !ok {
				m[x.Path] = make(map[string]bool)
				sorted = append(sorted, x.Path)
			}
			for _, y := range x.Services {
				m[x.Path][y] = true
			}
		}
	}
	sort.Strings(sorted)
	for _, p := range sorted {
		var s []string
		for x, _ := range m[p] {
			s = append(s, x)
		}
		sort.Strings(s)
		c = append(c, &Depend{Path: p, Services: s})
	}
	return
}

func update(a map[string]string, b map[string]string) map[string]string {
	if b == nil {
		return a
	} else if a == nil {
		return b
	}
	for k, v := range b {
		a[k] = v
	}
	return a
}

func isService(t tygo.Type) (*tygo.Object, bool) {
	object, ok := t.(*tygo.Object)
	return object, ok && object.Parent.Name == "Entity"
}

func hasMethod(object *doc.Type, method *tygo.Method) bool {
	for _, m := range object.Methods {
		if m.Name == method.Name {
			return true
		}
	}
	return false
}

func packageDoc(path string) *doc.Package {
	p, err := build.Import(path, "", build.ImportComment)
	if err != nil {
		return nil
	}
	fs := token.NewFileSet()
	include := func(info os.FileInfo) bool {
		for _, name := range p.GoFiles {
			if name == info.Name() {
				return true
			}
		}
		return false
	}

	if pkgs, err := parser.ParseDir(fs, p.Dir, include, parser.ParseComments); err != nil || len(pkgs) != 1 {
		return nil
	} else {
		return doc.New(pkgs[p.Name], p.ImportPath, doc.AllDecls)
	}
}

func resolveTypes(typesMap map[string]tygo.Type, typ tygo.Type) {
	switch t := typ.(type) {
	case *tygo.InstanceType:
		if _, exist := typesMap[t.Name]; !exist && (t.Name != "Entity" || t.PkgName != "" || t.PkgPath != "") {
			for _, typ := range tygo.Extract(t.PkgPath, ReplaceEntity) {
				switch t := typ.(type) {
				case *tygo.Object:
					typesMap[t.Name] = t
					resolveTypes(typesMap, t)
				case *tygo.Enum:
					typesMap[t.Name] = t
					resolveTypes(typesMap, t)
				}
			}
			if _, exist := typesMap[t.Name]; !exist {
				log.Fatalf("[RPC][Entity] Cannot resolve type: %v", t)
			}
		}
	case *tygo.Object:
		if t.HasParent() {
			resolveTypes(typesMap, t.Parent)
		}
		for _, f := range t.Fields {
			resolveTypes(typesMap, f)
		}
		for _, m := range t.Methods {
			for _, p := range m.Params {
				resolveTypes(typesMap, p)
			}
			for _, r := range m.Results {
				resolveTypes(typesMap, r)
			}
		}
	case *tygo.ListType:
		resolveTypes(typesMap, t.E)
	case *tygo.DictType:
		resolveTypes(typesMap, t.K)
		resolveTypes(typesMap, t.V)
	case *tygo.VariantType:
		for _, ts := range t.Ts {
			resolveTypes(typesMap, ts)
		}
	}
}

func resolveEntities(entityMap map[string]map[string][]string) (entities []*Entity, types []tygo.Type) {
	typesMap := make(map[string]tygo.Type)
	var entitySorted []string
	for n, _ := range entityMap {
		entitySorted = append(entitySorted, n)
	}
	sort.Strings(entitySorted)

	for _, n := range entitySorted {
		var componentSorted []string
		componentMap := make(map[string]*tygo.Object)
		for pkg, names := range entityMap[n] {
			if _, err := build.Import(pkg, "", build.ImportComment); err != nil {
				log.Printf("[RPC][Entity] Ignore component:\n>>>>%v", err)
				continue
			}
			for _, typ := range tygo.Extract(pkg, ReplaceEntity) {
				switch t := typ.(type) {
				case *tygo.Object:
					for _, s := range names {
						if t.Parent.Name == "Entity" && s == t.Name {
							componentSorted = append(componentSorted, s)
							componentMap[s] = t
						}
					}
					typesMap[t.Name] = t
				case *tygo.Enum:
					typesMap[t.Name] = t
				}
			}
		}
		sort.Strings(componentSorted)
		var components []*tygo.Object
		for _, c := range componentSorted {
			components = append(components, componentMap[c])
		}
		entities = append(entities, &Entity{Name: n, Components: components})
	}

	var typesSorted []string
	for n, _ := range typesMap {
		typesSorted = append(typesSorted, n)
	}
	for _, n := range typesSorted {
		resolveTypes(typesMap, typesMap[n])
	}
	typesSorted = nil
	for n, _ := range typesMap {
		typesSorted = append(typesSorted, n)
	}
	sort.Strings(typesSorted)
	for _, n := range typesSorted {
		types = append(types, typesMap[n])
	}

	return
}
<commit_msg>serialize session<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"log"
	"os"
	"path"
	"reflect"
	"sort"
	"strings"

	"go/ast"
	"go/build"
	"go/doc"
	"go/parser"
	"go/token"

	"github.com/ibelie/ruid"
	"github.com/ibelie/tygo"
)

var (
	SRC_PATH = path.Join(os.Getenv("GOPATH"), "src")
	PKG_PATH = reflect.TypeOf(Depend{}).PkgPath()
)

type Service interface {
	Procedure(ruid.RUID, uint64, []byte) ([]byte, error)
}

type IServer interface {
	Notify(ruid.RUID, ruid.RUID, []byte) error
	Distribute(ruid.RUID, ruid.RUID, uint64, uint64, []byte, chan<- []byte) error
	Procedure(ruid.RUID, ruid.RUID, uint64, uint64, []byte) ([]byte, error)
}

type Register func(IServer, map[string]uint64) (uint64, Service)

type Depend struct {
	Path     string
	Services []string
}

type Entity struct {
	Name       string
	Components []*tygo.Object
}

func SerializeSession(i ruid.RUID, symbols map[string]uint64, components ...[]byte) (data []byte) {
	symbolsSize := 0
	for name, value := range symbols {
		symbol := []byte(name)
		symbolsSize += tygo.SizeVarint(uint64(len(symbol))) + len(symbol) + tygo.SizeVarint(value)
	}
	size := symbolsSize + tygo.SizeVarint(symbolsSize) + tygo.SizeVarint(uint64(i))
	for _, component := range components {
		size += len(component)
	}

	data = make([]byte, size)
	protobuf := &tygo.ProtoBuf{Buffer: data}
	protobuf.WriteVarint(uint64(i))
	protobuf.WriteVarint(uint64(symbolsSize))
	for symbol, value := range symbols {
		protobuf.WriteBuf([]byte(symbol))
		protobuf.WriteVarint(value)
	}
	for _, component := range components {
		protobuf.Write(component)
	}
	return
}

func Extract(dir string) (pkgname string, depends []*Depend) {
	buildPackage, err := build.Import(dir, "", build.ImportComment)
	if err != nil {
		log.Fatalf("[RPC][Entity] Cannot import package:\n>>>>%v", err)
		return
	}
	fs := token.NewFileSet()
	for _, filename := range buildPackage.GoFiles {
		file, err := parser.ParseFile(fs, path.Join(buildPackage.Dir, filename), nil, parser.ParseComments)
		if err != nil {
			log.Fatalf("[RPC][Entity] Cannot parse file:\n>>>>%v", err)
		}
		pkgname = file.Name.Name
		for _, d := range file.Decls {
			decl, ok := d.(*ast.GenDecl)
			if !ok || decl.Tok != token.IMPORT {
				continue
			}
			for _, s := range decl.Specs {
				spec, ok := s.(*ast.ImportSpec)
				if !ok || strings.Trim(spec.Path.Value, "\"") != PKG_PATH {
					continue
				}
				if strings.TrimSpace(decl.Doc.Text()) != "" {
					depends = merge(depends, parse(decl.Doc.Text())...)
				}
			}
		}
	}
	return
}

func parse(code string) (depends []*Depend) {
	code = strings.Split(code, "depends on:")[1]
	for _, line := range strings.Split(code, "\n") {
		tokens := strings.Split(line, "from")
		if len(tokens) != 2 {
			continue
		}
		depends = merge(depends, &Depend{
			Services: []string{strings.TrimSpace(tokens[0])},
			Path:     strings.TrimSpace(tokens[1]),
		})
	}
	return
}

func merge(a []*Depend, b ...*Depend) (c []*Depend) {
	var sorted []string
	m := make(map[string]map[string]bool)
	for _, ab := range [][]*Depend{a, b} {
		for _, x := range ab {
			if _, ok := m[x.Path]; !ok {
				m[x.Path] = make(map[string]bool)
				sorted = append(sorted, x.Path)
			}
			for _, y := range x.Services {
				m[x.Path][y] = true
			}
		}
	}
	sort.Strings(sorted)
	for _, p := range sorted {
		var s []string
		for x, _ := range m[p] {
			s = append(s, x)
		}
		sort.Strings(s)
		c = append(c, &Depend{Path: p, Services: s})
	}
	return
}

func update(a map[string]string, b map[string]string) map[string]string {
	if b == nil {
		return a
	} else if a == nil {
		return b
	}
	for k, v := range b {
		a[k] = v
	}
	return a
}

func isService(t tygo.Type) (*tygo.Object, bool) {
	object, ok := t.(*tygo.Object)
	return object, ok && object.Parent.Name == "Entity"
}

func hasMethod(object *doc.Type, method *tygo.Method) bool {
	for _, m := range object.Methods {
		if m.Name == method.Name {
			return true
		}
	}
	return false
}

func packageDoc(path string) *doc.Package {
	p, err := build.Import(path, "", build.ImportComment)
	if err != nil {
		return nil
	}
	fs := token.NewFileSet()
	include := func(info os.FileInfo) bool {
		for _, name := range p.GoFiles {
			if name == info.Name() {
				return true
			}
		}
		return false
	}

	if pkgs, err := parser.ParseDir(fs, p.Dir, include, parser.ParseComments); err != nil || len(pkgs) != 1 {
		return nil
	} else {
		return doc.New(pkgs[p.Name], p.ImportPath, doc.AllDecls)
	}
}

func resolveTypes(typesMap map[string]tygo.Type, typ tygo.Type) {
	switch t := typ.(type) {
	case *tygo.InstanceType:
		if _, exist := typesMap[t.Name]; !exist && (t.Name != "Entity" || t.PkgName != "" || t.PkgPath != "") {
			for _, typ := range tygo.Extract(t.PkgPath, ReplaceEntity) {
				switch t := typ.(type) {
				case *tygo.Object:
					typesMap[t.Name] = t
					resolveTypes(typesMap, t)
				case *tygo.Enum:
					typesMap[t.Name] = t
					resolveTypes(typesMap, t)
				}
			}
			if _, exist := typesMap[t.Name]; !exist {
				log.Fatalf("[RPC][Entity] Cannot resolve type: %v", t)
			}
		}
	case *tygo.Object:
		if t.HasParent() {
			resolveTypes(typesMap, t.Parent)
		}
		for _, f := range t.Fields {
			resolveTypes(typesMap, f)
		}
		for _, m := range t.Methods {
			for _, p := range m.Params {
				resolveTypes(typesMap, p)
			}
			for _, r := range m.Results {
				resolveTypes(typesMap, r)
			}
		}
	case *tygo.ListType:
		resolveTypes(typesMap, t.E)
	case *tygo.DictType:
		resolveTypes(typesMap, t.K)
		resolveTypes(typesMap, t.V)
	case *tygo.VariantType:
		for _, ts := range t.Ts {
			resolveTypes(typesMap, ts)
		}
	}
}

func resolveEntities(entityMap map[string]map[string][]string) (entities []*Entity, types []tygo.Type) {
	typesMap := make(map[string]tygo.Type)
	var entitySorted []string
	for n, _ := range entityMap {
		entitySorted = append(entitySorted, n)
	}
	sort.Strings(entitySorted)

	for _, n := range entitySorted {
		var componentSorted []string
		componentMap := make(map[string]*tygo.Object)
		for pkg, names := range entityMap[n] {
			if _, err := build.Import(pkg, "", build.ImportComment); err != nil {
				log.Printf("[RPC][Entity] Ignore component:\n>>>>%v", err)
				continue
			}
			for _, typ := range tygo.Extract(pkg, ReplaceEntity) {
				switch t := typ.(type) {
				case *tygo.Object:
					for _, s := range names {
						if t.Parent.Name == "Entity" && s == t.Name {
							componentSorted = append(componentSorted, s)
							componentMap[s] = t
						}
					}
					typesMap[t.Name] = t
				case *tygo.Enum:
					typesMap[t.Name] = t
				}
			}
		}
		sort.Strings(componentSorted)
		var components []*tygo.Object
		for _, c := range componentSorted {
			components = append(components, componentMap[c])
		}
		entities = append(entities, &Entity{Name: n, Components: components})
	}

	var typesSorted []string
	for n, _ := range typesMap {
		typesSorted = append(typesSorted, n)
	}
	for _, n := range typesSorted {
		resolveTypes(typesMap, typesMap[n])
	}
	typesSorted = nil
	for n, _ := range typesMap {
		typesSorted = append(typesSorted, n)
	}
	sort.Strings(typesSorted)
	for _, n := range typesSorted {
		types = append(types, typesMap[n])
	}

	return
}
<|endoftext|>


<commit_before>package rqc

import (
	"fmt"
	"strings"

	"github.com/garyburd/redigo/redis"
)

type Builder struct {
	Conn redis.Conn
}

func (e *Builder) Select(key string) *Selection {
	return &Selection{
		Conn:             e.Conn,
		BaseKey:          key,
		ResultKey:        "result",
		IntersectionKeys: []string{key},
	}
}

type Selection struct {
	Conn             redis.Conn
	BaseKey          string
	ResultKey        string
	IntersectionKeys []string
}

// Intersect specifies another set key to intersect with.
func (s Selection) Intersect(key string) Selection {
	s.IntersectionKeys = append(s.IntersectionKeys, key)
	return s
}

func (s Selection) Generate() string {
	intersectionKeyArgs := strings.Join(s.IntersectionKeys, "', '")
	return fmt.Sprintf("redis.call('ZINTERSTORE', '%s', %d, '%s')\n",
		s.ResultKey, len(s.IntersectionKeys), intersectionKeyArgs)
}

func (s Selection) Script() *redis.Script {
	code := s.Generate()
	return redis.NewScript(0, code)
}

func (s Selection) Run() {
	script := s.Script()
	_, err := script.Do(s.Conn)
	if err != nil {
		panic(err)
	}
}
<commit_msg>e->b for Builder variable names<commit_after>package rqc

import (
	"fmt"
	"strings"

	"github.com/garyburd/redigo/redis"
)

type Builder struct {
	Conn redis.Conn
}

func (b *Builder) Select(key string) *Selection {
	return &Selection{
		Conn:             b.Conn,
		BaseKey:          key,
		ResultKey:        "result",
		IntersectionKeys: []string{key},
	}
}

type Selection struct {
	Conn             redis.Conn
	BaseKey          string
	ResultKey        string
	IntersectionKeys []string
}

// Intersect specifies another set key to intersect with.
func (s Selection) Intersect(key string) Selection {
	s.IntersectionKeys = append(s.IntersectionKeys, key)
	return s
}

func (s Selection) Generate() string {
	intersectionKeyArgs := strings.Join(s.IntersectionKeys, "', '")
	return fmt.Sprintf("redis.call('ZINTERSTORE', '%s', %d, '%s')\n",
		s.ResultKey, len(s.IntersectionKeys), intersectionKeyArgs)
}

func (s Selection) Script() *redis.Script {
	code := s.Generate()
	return redis.NewScript(0, code)
}

func (s Selection) Run() {
	script := s.Script()
	_, err := script.Do(s.Conn)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
  "encoding/json"
  "errors"
  "fmt"
  "io/ioutil"
  "log"
  "os"
  "os/exec"
  "path"
  "path/filepath"
  "runtime"
  "strings"
  "syscall"
)

// The current version number of Run. Run versions will be tagged in the git
// repo, so this is merely provided as a convenience.
const version = "0.0.1"

// callerDir returns the directory of this source code file in Run's
// implementation. Similar to __dir__ in Ruby.
func callerDir() string {
  _, callerFile, _, _ := runtime.Caller(1)
  return path.Dir(callerFile)
}

// getCommands gets the collection of supported commands. This is represented as
// a map of file extensions (strings) to commands (strings), loaded from the
// data file (commands.json).
func getCommands() (map[string]string, error) {
  // Load the commands from the data file to a slice of bytes.
  var commands map[string]string
  jsonStream, fileErr := ioutil.ReadFile(path.Join(callerDir(), "commands.json"))
  if fileErr != nil {
    return commands, fileErr
  }

  // Parse the byte slice to get a map of type commands.
  jsonErr := json.Unmarshal(jsonStream, &commands)
  return commands, jsonErr
}

// commandForFile returns the command that should be used to run the given file.
// The beginning of the command depends on the extension of the file, while the
// file path portion(s) of the command will automatically be substituted with
// the given file path.
func commandForFile(path string) (string, error) {
  commands, err := getCommands()
  if err != nil {
    return "", err
  }

  extension := strings.Replace(filepath.Ext(path), ".", "", -1)

  // Fill out the command template.
  if command, success := commands[extension]; success {
    return strings.Replace(command, "%", path, -1), nil
  }
  return "", errors.New("run could not determine how to run this file because it does not have a known extension")
}

// runCommand finds the appropriate command to run a file and executes it. For
// now, this waits until a command completes and then shows all of its stdout at
// once. If the command fails, a failure message will be displayed.
//
// TODO: Make this more efficient and don't hide the command's stderr.
func runCommand(command string) error {
  // Separate the command into arguments for syscall.Exec.
  args := strings.Split(command, " ")

  // Get the path to the binary.
  binary, err := exec.LookPath(args[0])
  if err != nil {
    return err
  }

  // Execute the command, replacing the current process with it.
  return syscall.Exec(binary, args, os.Environ())
}

// start takes the command line args given to Run. It a filename is given as the
// first argument, the command to run it is returned. Otherwise, it returns an
// error. This mostly exists for testing purposes so that the args for main
// won't need to be mocked.
func start(args ...string) (string, error) {
  if len(args) <= 1 {
    return "", errors.New("no files given")
  }
  return commandForFile(args[1])
}

// main runs start and executes the resulting command if it succeeds. Otherwise,
// it returns an error.
func main() {
  command, err := start(os.Args...)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println(command)
  runCommand(command)
}
<commit_msg>Update the comment for runCommand<commit_after>package main

import (
  "encoding/json"
  "errors"
  "fmt"
  "io/ioutil"
  "log"
  "os"
  "os/exec"
  "path"
  "path/filepath"
  "runtime"
  "strings"
  "syscall"
)

// The current version number of Run. Run versions will be tagged in the git
// repo, so this is merely provided as a convenience.
const version = "0.0.1"

// callerDir returns the directory of this source code file in Run's
// implementation. Similar to __dir__ in Ruby.
func callerDir() string {
  _, callerFile, _, _ := runtime.Caller(1)
  return path.Dir(callerFile)
}

// getCommands gets the collection of supported commands. This is represented as
// a map of file extensions (strings) to commands (strings), loaded from the
// data file (commands.json).
func getCommands() (map[string]string, error) {
  // Load the commands from the data file to a slice of bytes.
  var commands map[string]string
  jsonStream, fileErr := ioutil.ReadFile(path.Join(callerDir(), "commands.json"))
  if fileErr != nil {
    return commands, fileErr
  }

  // Parse the byte slice to get a map of type commands.
  jsonErr := json.Unmarshal(jsonStream, &commands)
  return commands, jsonErr
}

// commandForFile returns the command that should be used to run the given file.
// The beginning of the command depends on the extension of the file, while the
// file path portion(s) of the command will automatically be substituted with
// the given file path.
func commandForFile(path string) (string, error) {
  commands, err := getCommands()
  if err != nil {
    return "", err
  }

  extension := strings.Replace(filepath.Ext(path), ".", "", -1)

  // Fill out the command template.
  if command, success := commands[extension]; success {
    return strings.Replace(command, "%", path, -1), nil
  }
  return "", errors.New("run could not determine how to run this file because it does not have a known extension")
}

// runCommand finds the appropriate command to run a file and executes it,
// replacing the current process. If the command fails, an error will be
// returned.
func runCommand(command string) error {
  // Separate the command into arguments for syscall.Exec.
  args := strings.Split(command, " ")

  // Get the path to the binary.
  binary, err := exec.LookPath(args[0])
  if err != nil {
    return err
  }

  // Execute the command, replacing the current process with it.
  return syscall.Exec(binary, args, os.Environ())
}

// start takes the command line args given to Run. It a filename is given as the
// first argument, the command to run it is returned. Otherwise, it returns an
// error. This mostly exists for testing purposes so that the args for main
// won't need to be mocked.
func start(args ...string) (string, error) {
  if len(args) <= 1 {
    return "", errors.New("no files given")
  }
  return commandForFile(args[1])
}

// main runs start and executes the resulting command if it succeeds. Otherwise,
// it returns an error.
func main() {
  command, err := start(os.Args...)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println(command)
  runCommand(command)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/itchyny/zshhist-go"
	"github.com/mitchellh/go-homedir"
)

// Run fillin
func Run(configDir string, args []string, in *bufio.Reader, out *bufio.Writer) (string, error) {
	dir, err := homedir.Expand(normalizeFileSeparator(configDir))
	if err := os.MkdirAll(dir, 0700); err != nil {
		return "", err
	}
	if err := os.Chmod(dir, 0700); err != nil {
		return "", err
	}

	path := filepath.Join(dir, "fillin.json")
	rfile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0600)
	if err != nil {
		return "", err
	}
	w := new(bytes.Buffer)
	filled, err := Fillin(args, rfile, w, in, out)
	if err != nil {
		return "", err
	}
	cmd := escapeJoin(filled)
	rfile.Close() // not be defered due to rename

	tmp := filepath.Join(dir, fmt.Sprintf("fillin.%d-%d.json", os.Getpid(), rand.Int()))
	defer os.Remove(tmp)
	wfile, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		return "", err
	}
	if n, err := wfile.Write(w.Bytes()); n != w.Len() || err != nil {
		wfile.Close()
		return "", err
	}
	wfile.Close() // not be defered due to rename

	if err := os.Rename(tmp, path); err != nil {
		return "", err
	}

	if cmd != "" {
		histfile := filepath.Join(dir, ".fillin.histfile")
		hfile, err := os.OpenFile(histfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
		defer hfile.Close()
		if err != nil {
			return "", err
		}
		w := zshhist.NewWriter(hfile)
		w.Write(zshhist.History{Time: int(time.Now().Unix()), Elapsed: 0, Command: cmd})
		hfile.Chmod(0600)
	}

	return cmd, nil
}

func normalizeFileSeparator(path string) string {
	p := filepath.Join(strings.Split(path, "/")...)
	if path[0] == '/' {
		p = "/" + p
	}
	return p
}

func escapeJoin(args []string) string {
	if len(args) == 1 {
		return args[0]
	}
	for i, arg := range args {
		args[i] = escape(arg)
	}
	return strings.Join(args, " ")
}

func escape(arg string) string {
	switch arg {
	case "|", "||", "&&", ">", ">>", "<":
		return arg
	}
quote:
	for _, quote := range []bool{false, true} {
		s := arg
		isHead, afterFd, afterRedirect := true, false, false
		var buf bytes.Buffer
		if quote {
			buf.WriteByte('\'')
		}
		for len(s) > 0 {
			c, l := utf8.DecodeRuneInString(s)
			s = s[l:]
			if (isHead || afterFd) && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd, afterRedirect = false, false, true
				continue
			} else if afterRedirect && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
			} else if isHead && strings.ContainsRune("12", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd = false, true
				continue
			} else if afterRedirect && strings.ContainsRune("&", c) && !quote {
				buf.WriteRune(c)
			} else if strings.ContainsRune("\\'\"`${[|&;<>()*?!", c) && !quote {
				buf.WriteByte('\\')
				buf.WriteRune(c)
			} else if c == rune(' ') && !quote {
				continue quote
			} else if c == rune('\t') {
				if quote {
					buf.WriteByte('\\')
					buf.WriteByte('t')
				} else {
					continue quote
				}
			} else {
				buf.WriteRune(c)
			}
			isHead, afterFd, afterRedirect = false, false, false
		}
		if quote {
			buf.WriteByte('\'')
		}
		return buf.String()
	}
	return ""
}
<commit_msg>use O_EXCL to ensure the temporary file does not exist<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/itchyny/zshhist-go"
	"github.com/mitchellh/go-homedir"
)

// Run fillin
func Run(configDir string, args []string, in *bufio.Reader, out *bufio.Writer) (string, error) {
	dir, err := homedir.Expand(normalizeFileSeparator(configDir))
	if err := os.MkdirAll(dir, 0700); err != nil {
		return "", err
	}
	if err := os.Chmod(dir, 0700); err != nil {
		return "", err
	}

	path := filepath.Join(dir, "fillin.json")
	rfile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0600)
	if err != nil {
		return "", err
	}
	w := new(bytes.Buffer)
	filled, err := Fillin(args, rfile, w, in, out)
	if err != nil {
		return "", err
	}
	cmd := escapeJoin(filled)
	rfile.Close() // not be defered due to rename

	tmp := filepath.Join(dir, fmt.Sprintf("fillin.%d-%d.json", os.Getpid(), rand.Int()))
	defer os.Remove(tmp)
	wfile, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
	if err != nil {
		return "", err
	}
	if n, err := wfile.Write(w.Bytes()); n != w.Len() || err != nil {
		wfile.Close()
		return "", err
	}
	wfile.Close() // not be defered due to rename

	if err := os.Rename(tmp, path); err != nil {
		return "", err
	}

	if cmd != "" {
		histfile := filepath.Join(dir, ".fillin.histfile")
		hfile, err := os.OpenFile(histfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
		defer hfile.Close()
		if err != nil {
			return "", err
		}
		w := zshhist.NewWriter(hfile)
		w.Write(zshhist.History{Time: int(time.Now().Unix()), Elapsed: 0, Command: cmd})
		hfile.Chmod(0600)
	}

	return cmd, nil
}

func normalizeFileSeparator(path string) string {
	p := filepath.Join(strings.Split(path, "/")...)
	if path[0] == '/' {
		p = "/" + p
	}
	return p
}

func escapeJoin(args []string) string {
	if len(args) == 1 {
		return args[0]
	}
	for i, arg := range args {
		args[i] = escape(arg)
	}
	return strings.Join(args, " ")
}

func escape(arg string) string {
	switch arg {
	case "|", "||", "&&", ">", ">>", "<":
		return arg
	}
quote:
	for _, quote := range []bool{false, true} {
		s := arg
		isHead, afterFd, afterRedirect := true, false, false
		var buf bytes.Buffer
		if quote {
			buf.WriteByte('\'')
		}
		for len(s) > 0 {
			c, l := utf8.DecodeRuneInString(s)
			s = s[l:]
			if (isHead || afterFd) && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd, afterRedirect = false, false, true
				continue
			} else if afterRedirect && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
			} else if isHead && strings.ContainsRune("12", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd = false, true
				continue
			} else if afterRedirect && strings.ContainsRune("&", c) && !quote {
				buf.WriteRune(c)
			} else if strings.ContainsRune("\\'\"`${[|&;<>()*?!", c) && !quote {
				buf.WriteByte('\\')
				buf.WriteRune(c)
			} else if c == rune(' ') && !quote {
				continue quote
			} else if c == rune('\t') {
				if quote {
					buf.WriteByte('\\')
					buf.WriteByte('t')
				} else {
					continue quote
				}
			} else {
				buf.WriteRune(c)
			}
			isHead, afterFd, afterRedirect = false, false, false
		}
		if quote {
			buf.WriteByte('\'')
		}
		return buf.String()
	}
	return ""
}
<|endoftext|>


<commit_before>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	conn   *tls.Conn
	queue  chan PushNotification
	errors chan *BadPushNotification
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() *Response {
	return new(Response)
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	go func(pn *PushNotification) {
		conn.queue <- *pn
	}(pn)
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan *BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification)
	go conn.sender(conn.queue, sent)
	//Start reader goroutine
	responses := make(chan *Response, ResponseQueueSize)
	go conn.reader(responses)
	//Start limbo goroutine
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() {
	//We can't just close the main queue channel, because retries might still need to be sent there.
	//
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	defer conn.conn.Close()
	var backoff = time.Duration(100)
	for {
		pn, ok := <-conn.queue
		if !ok {
			//That means the Connection is stopped
			//close sent?
			return
		} else {
			//If not connected, connect
			if conn.conn == nil {
				for {
					err := conn.connect()
					if err != nil {
						//Exponential backoff up to a limit
						log.Println("APNS: Error connecting to server: ", err)
						backoff = backoff * 2
						if backoff > maxBackoff {
							backoff = maxBackoff
						}
						time.Sleep(backoff)
					} else {
						backoff = 100
						break
					}
				}
			}
			//Then send the push notification
			//TODO(draaglom): Do buffering as per the APNS docs
			payload, err := pn.ToBytes()
			if err != nil {
				//Should report this on the bad notifications channel probably
			} else {
				_, err = conn.conn.Write(payload)
				if err != nil {
					//Disconnect?
				} else {
					sent <- pn
				}
			}

		}
	}
}

func (conn *Connection) reader(responses chan<- *Response) {
	buffer := make([]byte, 6)
	for {
		_, err := conn.conn.Read(buffer)
		if err != nil {
			log.Println("APNS: Error reading from connection: ", err)
			conn.conn.Close()
			return
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	limbo := make(chan PushNotification, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	timeNextNotification := true
	for {
		select {
		case pn := <-sent:
			//Drop it into the array
			limbo <- pn
			if timeNextNotification {
				//Is there a cleaner way of doing this?
				go func(pn PushNotification) {
					<-time.After(TimeoutSeconds * time.Second)
					successResp := newResponse()
					successResp.Identifier = pn.Identifier
					responses <- *successResp
				}(pn)
				timeNextNotification = false
			}
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			switch {
			case resp.Status == 0:
				//Status 0 is a "success" response generated by a timeout in the library.
				for pn := range limbo {
					//Drop all the notifications until we get to the timed-out one.
					//(and leave the others in limbo)
					if pn.Identifier == resp.Identifier {
						break
					}
				}
			default:
				hit := false
				for pn := range limbo {
					switch {
					case pn.Identifier != resp.Identifier && !hit:
						//We haven't seen the identified notification yet
						//so these are all successful (drop silently)
					case pn.Identifier == resp.Identifier:
						hit = true
						if resp.Status != 10 {
							//It was an error, we should report this on the error channel
							bad := BadPushNotification{PushNotification: pn, Status: resp.Status}
							go func(bad BadPushNotification) {
								errors <- bad
							}(bad)
						}
					case pn.Identifier != resp.Identifier && hit:
						//We've already seen the identified notification,
						//so these should be requeued
						conn.Enqueue(&pn)
					}
				}
			}
		case <-ticker.C:
			timeNextNotification = true
		}
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	tlsConn, err := tls.Dial("tcp", conn.Gateway, conf)
	if err != nil {
		return err
	}
	err = tlsConn.Handshake()
	if err != nil {
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	return nil
}
<commit_msg>add a constructor for Connection<commit_after>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	conn   *tls.Conn
	queue  chan PushNotification
	errors chan *BadPushNotification
}

//NewConnection initializes an APNS connection. Use Connection.Start() to actually start sending notifications.
func NewConnection(client *Client) *Connection {
	c := new(Connection)
	c.Client = *client
	queue := make(chan PushNotification)
	errors := make(chan *BadPushNotification)
	c.queue = queue
	c.errors = errors
	return c
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() *Response {
	return new(Response)
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	go func(pn *PushNotification) {
		conn.queue <- *pn
	}(pn)
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan *BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification)
	go conn.sender(conn.queue, sent)
	//Start reader goroutine
	responses := make(chan *Response, ResponseQueueSize)
	go conn.reader(responses)
	//Start limbo goroutine
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() {
	//We can't just close the main queue channel, because retries might still need to be sent there.
	//
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	defer conn.conn.Close()
	var backoff = time.Duration(100)
	for {
		pn, ok := <-conn.queue
		if !ok {
			//That means the Connection is stopped
			//close sent?
			return
		} else {
			//If not connected, connect
			if conn.conn == nil {
				for {
					err := conn.connect()
					if err != nil {
						//Exponential backoff up to a limit
						log.Println("APNS: Error connecting to server: ", err)
						backoff = backoff * 2
						if backoff > maxBackoff {
							backoff = maxBackoff
						}
						time.Sleep(backoff)
					} else {
						backoff = 100
						break
					}
				}
			}
			//Then send the push notification
			//TODO(draaglom): Do buffering as per the APNS docs
			payload, err := pn.ToBytes()
			if err != nil {
				//Should report this on the bad notifications channel probably
			} else {
				_, err = conn.conn.Write(payload)
				if err != nil {
					//Disconnect?
				} else {
					sent <- pn
				}
			}

		}
	}
}

func (conn *Connection) reader(responses chan<- *Response) {
	buffer := make([]byte, 6)
	for {
		_, err := conn.conn.Read(buffer)
		if err != nil {
			log.Println("APNS: Error reading from connection: ", err)
			conn.conn.Close()
			return
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	limbo := make(chan PushNotification, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	timeNextNotification := true
	for {
		select {
		case pn := <-sent:
			//Drop it into the array
			limbo <- pn
			if timeNextNotification {
				//Is there a cleaner way of doing this?
				go func(pn PushNotification) {
					<-time.After(TimeoutSeconds * time.Second)
					successResp := newResponse()
					successResp.Identifier = pn.Identifier
					responses <- *successResp
				}(pn)
				timeNextNotification = false
			}
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			switch {
			case resp.Status == 0:
				//Status 0 is a "success" response generated by a timeout in the library.
				for pn := range limbo {
					//Drop all the notifications until we get to the timed-out one.
					//(and leave the others in limbo)
					if pn.Identifier == resp.Identifier {
						break
					}
				}
			default:
				hit := false
				for pn := range limbo {
					switch {
					case pn.Identifier != resp.Identifier && !hit:
						//We haven't seen the identified notification yet
						//so these are all successful (drop silently)
					case pn.Identifier == resp.Identifier:
						hit = true
						if resp.Status != 10 {
							//It was an error, we should report this on the error channel
							bad := BadPushNotification{PushNotification: pn, Status: resp.Status}
							go func(bad BadPushNotification) {
								errors <- bad
							}(bad)
						}
					case pn.Identifier != resp.Identifier && hit:
						//We've already seen the identified notification,
						//so these should be requeued
						conn.Enqueue(&pn)
					}
				}
			}
		case <-ticker.C:
			timeNextNotification = true
		}
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	tlsConn, err := tls.Dial("tcp", conn.Gateway, conf)
	if err != nil {
		return err
	}
	err = tlsConn.Handshake()
	if err != nil {
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	return nil
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you 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 avatica

import (
	"context"
	"database/sql/driver"

	"github.com/apache/calcite-avatica-go/v4/errors"
	"github.com/apache/calcite-avatica-go/v4/message"
)

type conn struct {
	connectionId string
	config       *Config
	httpClient   *httpClient
	adapter      Adapter
}

// Prepare returns a prepared statement, bound to this connection.
func (c *conn) Prepare(query string) (driver.Stmt, error) {
	return c.prepare(context.Background(), query)
}

func (c *conn) prepare(ctx context.Context, query string) (driver.Stmt, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	response, err := c.httpClient.post(ctx, &message.PrepareRequest{
		ConnectionId: c.connectionId,
		Sql:          query,
		MaxRowsTotal: c.config.maxRowsTotal,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	prepareResponse := response.(*message.PrepareResponse)

	return &stmt{
		statementID: prepareResponse.Statement.Id,
		conn:        c,
		parameters:  prepareResponse.Statement.Signature.Parameters,
		handle:      *prepareResponse.Statement,
	}, nil
}

// Close invalidates and potentially stops any current
// prepared statements and transactions, marking this
// connection as no longer in use.
//
// Because the sql package maintains a free pool of
// connections and only calls Close when there's a surplus of
// idle connections, it shouldn't be necessary for drivers to
// do their own connection caching.
func (c *conn) Close() error {

	if c.connectionId == "" {
		return driver.ErrBadConn
	}

	_, err := c.httpClient.post(context.Background(), &message.CloseConnectionRequest{
		ConnectionId: c.connectionId,
	})

	c.connectionId = ""

	if err != nil {
		return c.avaticaErrorToResponseErrorOrError(err)
	}

	return nil
}

// Begin starts and returns a new transaction.
func (c *conn) Begin() (driver.Tx, error) {
	return c.begin(context.Background(), isolationUseCurrent)
}

func (c *conn) begin(ctx context.Context, isolationLevel isoLevel) (driver.Tx, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	if isolationLevel == isolationUseCurrent {
		isolationLevel = isoLevel(c.config.transactionIsolation)
	}

	_, err := c.httpClient.post(ctx, &message.ConnectionSyncRequest{
		ConnectionId: c.connectionId,
		ConnProps: &message.ConnectionProperties{
			AutoCommit:           false,
			HasAutoCommit:        true,
			TransactionIsolation: uint32(isolationLevel),
		},
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	return &tx{
		conn: c,
	}, nil
}

// Exec prepares and executes a query and returns the result directly.
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	list := driverValueToNamedValue(args)
	return c.exec(context.Background(), query, list)
}

func (c *conn) exec(ctx context.Context, query string, args []namedValue) (driver.Result, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	if len(args) != 0 {
		return nil, driver.ErrSkip
	}

	st, err := c.httpClient.post(ctx, &message.CreateStatementRequest{
		ConnectionId: c.connectionId,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	res, err := c.httpClient.post(ctx, &message.PrepareAndExecuteRequest{
		ConnectionId:      c.connectionId,
		StatementId:       st.(*message.CreateStatementResponse).StatementId,
		Sql:               query,
		MaxRowsTotal:      c.config.maxRowsTotal,
		FirstFrameMaxSize: c.config.frameMaxSize,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	// Currently there is only 1 ResultSet per response for exec
	changed := int64(res.(*message.ExecuteResponse).Results[0].UpdateCount)

	return &result{
		affectedRows: changed,
	}, nil
}

// Query prepares and executes a query and returns the result directly.
func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	list := driverValueToNamedValue(args)
	return c.query(context.Background(), query, list)
}

func (c *conn) query(ctx context.Context, query string, args []namedValue) (driver.Rows, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	if len(args) != 0 {
		return nil, driver.ErrSkip
	}

	st, err := c.httpClient.post(ctx, &message.CreateStatementRequest{
		ConnectionId: c.connectionId,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	res, err := c.httpClient.post(ctx, &message.PrepareAndExecuteRequest{
		ConnectionId:      c.connectionId,
		StatementId:       st.(*message.CreateStatementResponse).StatementId,
		Sql:               query,
		MaxRowsTotal:      c.config.maxRowsTotal,
		FirstFrameMaxSize: c.config.frameMaxSize,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	resultSets := res.(*message.ExecuteResponse).Results

	return newRows(c, st.(*message.CreateStatementResponse).StatementId, resultSets), nil
}

func (c *conn) avaticaErrorToResponseErrorOrError(err error) error {

	avaticaErr, ok := err.(avaticaError)

	if !ok {
		return err
	}

	if c.adapter != nil {
		return c.adapter.ErrorResponseToResponseError(avaticaErr.message)
	}

	return errors.ResponseError{
		Exceptions:   avaticaErr.message.Exceptions,
		ErrorMessage: avaticaErr.message.ErrorMessage,
		Severity:     int8(avaticaErr.message.Severity),
		ErrorCode:    errors.ErrorCode(avaticaErr.message.ErrorCode),
		SqlState:     errors.SQLState(avaticaErr.message.SqlState),
		Metadata: &errors.RPCMetadata{
			ServerAddress: avaticaErr.message.GetMetadata().ServerAddress,
		},
	}
}
<commit_msg>[CALCITE-3253] Check server address exists before returning it in an avatica response error (Tino Rusch)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you 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 avatica

import (
	"context"
	"database/sql/driver"

	"github.com/apache/calcite-avatica-go/v4/errors"
	"github.com/apache/calcite-avatica-go/v4/message"
)

type conn struct {
	connectionId string
	config       *Config
	httpClient   *httpClient
	adapter      Adapter
}

// Prepare returns a prepared statement, bound to this connection.
func (c *conn) Prepare(query string) (driver.Stmt, error) {
	return c.prepare(context.Background(), query)
}

func (c *conn) prepare(ctx context.Context, query string) (driver.Stmt, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	response, err := c.httpClient.post(ctx, &message.PrepareRequest{
		ConnectionId: c.connectionId,
		Sql:          query,
		MaxRowsTotal: c.config.maxRowsTotal,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	prepareResponse := response.(*message.PrepareResponse)

	return &stmt{
		statementID: prepareResponse.Statement.Id,
		conn:        c,
		parameters:  prepareResponse.Statement.Signature.Parameters,
		handle:      *prepareResponse.Statement,
	}, nil
}

// Close invalidates and potentially stops any current
// prepared statements and transactions, marking this
// connection as no longer in use.
//
// Because the sql package maintains a free pool of
// connections and only calls Close when there's a surplus of
// idle connections, it shouldn't be necessary for drivers to
// do their own connection caching.
func (c *conn) Close() error {

	if c.connectionId == "" {
		return driver.ErrBadConn
	}

	_, err := c.httpClient.post(context.Background(), &message.CloseConnectionRequest{
		ConnectionId: c.connectionId,
	})

	c.connectionId = ""

	if err != nil {
		return c.avaticaErrorToResponseErrorOrError(err)
	}

	return nil
}

// Begin starts and returns a new transaction.
func (c *conn) Begin() (driver.Tx, error) {
	return c.begin(context.Background(), isolationUseCurrent)
}

func (c *conn) begin(ctx context.Context, isolationLevel isoLevel) (driver.Tx, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	if isolationLevel == isolationUseCurrent {
		isolationLevel = isoLevel(c.config.transactionIsolation)
	}

	_, err := c.httpClient.post(ctx, &message.ConnectionSyncRequest{
		ConnectionId: c.connectionId,
		ConnProps: &message.ConnectionProperties{
			AutoCommit:           false,
			HasAutoCommit:        true,
			TransactionIsolation: uint32(isolationLevel),
		},
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	return &tx{
		conn: c,
	}, nil
}

// Exec prepares and executes a query and returns the result directly.
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	list := driverValueToNamedValue(args)
	return c.exec(context.Background(), query, list)
}

func (c *conn) exec(ctx context.Context, query string, args []namedValue) (driver.Result, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	if len(args) != 0 {
		return nil, driver.ErrSkip
	}

	st, err := c.httpClient.post(ctx, &message.CreateStatementRequest{
		ConnectionId: c.connectionId,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	res, err := c.httpClient.post(ctx, &message.PrepareAndExecuteRequest{
		ConnectionId:      c.connectionId,
		StatementId:       st.(*message.CreateStatementResponse).StatementId,
		Sql:               query,
		MaxRowsTotal:      c.config.maxRowsTotal,
		FirstFrameMaxSize: c.config.frameMaxSize,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	// Currently there is only 1 ResultSet per response for exec
	changed := int64(res.(*message.ExecuteResponse).Results[0].UpdateCount)

	return &result{
		affectedRows: changed,
	}, nil
}

// Query prepares and executes a query and returns the result directly.
func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	list := driverValueToNamedValue(args)
	return c.query(context.Background(), query, list)
}

func (c *conn) query(ctx context.Context, query string, args []namedValue) (driver.Rows, error) {
	if c.connectionId == "" {
		return nil, driver.ErrBadConn
	}

	if len(args) != 0 {
		return nil, driver.ErrSkip
	}

	st, err := c.httpClient.post(ctx, &message.CreateStatementRequest{
		ConnectionId: c.connectionId,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	res, err := c.httpClient.post(ctx, &message.PrepareAndExecuteRequest{
		ConnectionId:      c.connectionId,
		StatementId:       st.(*message.CreateStatementResponse).StatementId,
		Sql:               query,
		MaxRowsTotal:      c.config.maxRowsTotal,
		FirstFrameMaxSize: c.config.frameMaxSize,
	})

	if err != nil {
		return nil, c.avaticaErrorToResponseErrorOrError(err)
	}

	resultSets := res.(*message.ExecuteResponse).Results

	return newRows(c, st.(*message.CreateStatementResponse).StatementId, resultSets), nil
}

func (c *conn) avaticaErrorToResponseErrorOrError(err error) error {

	avaticaErr, ok := err.(avaticaError)

	if !ok {
		return err
	}

	if c.adapter != nil {
		return c.adapter.ErrorResponseToResponseError(avaticaErr.message)
	}

	serverAddress := "unknown"
	md := avaticaErr.message.GetMetadata()
	if md != nil {
		serverAddress = md.ServerAddress
	}
	return errors.ResponseError{
		Exceptions:   avaticaErr.message.Exceptions,
		ErrorMessage: avaticaErr.message.ErrorMessage,
		Severity:     int8(avaticaErr.message.Severity),
		ErrorCode:    errors.ErrorCode(avaticaErr.message.ErrorCode),
		SqlState:     errors.SQLState(avaticaErr.message.SqlState),
		Metadata: &errors.RPCMetadata{
			ServerAddress: serverAddress,
		},
	}
}
<|endoftext|>


<commit_before>package torrent

import (
	"container/list"
	"encoding"
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"time"

	"bitbucket.org/anacrolix/go.torrent/peer_protocol"
)

// Maintains the state of a connection with a peer.
type connection struct {
	Socket   net.Conn
	Incoming bool
	closed   bool
	mu       sync.Mutex // Only for closing.
	post     chan peer_protocol.Message
	write    chan []byte

	// Stuff controlled by the local peer.
	Interested bool
	Choked     bool
	Requests   map[request]struct{}

	// Stuff controlled by the remote peer.
	PeerId           [20]byte
	PeerInterested   bool
	PeerChoked       bool
	PeerRequests     map[request]struct{}
	PeerExtensions   [8]byte
	PeerPieces       []bool
	PeerMaxRequests  int // Maximum pending requests the peer allows.
	PeerExtensionIDs map[string]int64
	PeerClientName   string
}

func (cn *connection) completedString() string {
	if cn.PeerPieces == nil {
		return "?"
	}
	f := float32(cn.piecesPeerHasCount()) / float32(cn.totalPiecesCount())
	return fmt.Sprintf("%d%%", int(f*100))
}

func (cn *connection) totalPiecesCount() int {
	return len(cn.PeerPieces)
}

func (cn *connection) piecesPeerHasCount() (count int) {
	for _, has := range cn.PeerPieces {
		if has {
			count++
		}
	}
	return
}

func (cn *connection) WriteStatus(w io.Writer) {
	fmt.Fprintf(w, "%q: %s-%s: %s completed: ", cn.PeerId, cn.Socket.LocalAddr(), cn.Socket.RemoteAddr(), cn.completedString())
	c := func(b byte) {
		fmt.Fprintf(w, "%c", b)
	}
	// https://trac.transmissionbt.com/wiki/PeerStatusText
	if len(cn.Requests) != 0 {
		c('D')
	} else if cn.Interested {
		c('d')
	}
	if !cn.PeerChoked && !cn.Interested {
		c('K')
	}
	if !cn.Choked && !cn.PeerInterested {
		c('?')
	}
	if cn.Incoming {
		c('I')
	}
	fmt.Fprintln(w)
}

func (c *connection) Close() {
	c.mu.Lock()
	if c.closed {
		return
	}
	c.Socket.Close()
	close(c.post)
	c.closed = true
	c.mu.Unlock()
}

func (c *connection) getClosed() bool {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.closed
}

func (c *connection) PeerHasPiece(index peer_protocol.Integer) bool {
	if c.PeerPieces == nil {
		return false
	}
	if int(index) >= len(c.PeerPieces) {
		return false
	}
	return c.PeerPieces[index]
}

func (c *connection) Post(msg peer_protocol.Message) {
	c.post <- msg
}

func (c *connection) RequestPending(r request) bool {
	_, ok := c.Requests[r]
	return ok
}

// Returns true if more requests can be sent.
func (c *connection) Request(chunk request) bool {
	if len(c.Requests) >= c.PeerMaxRequests {
		return false
	}
	if !c.PeerHasPiece(chunk.Index) {
		return true
	}
	if c.RequestPending(chunk) {
		return true
	}
	c.SetInterested(true)
	if c.PeerChoked {
		return false
	}
	if c.Requests == nil {
		c.Requests = make(map[request]struct{}, c.PeerMaxRequests)
	}
	c.Requests[chunk] = struct{}{}
	c.Post(peer_protocol.Message{
		Type:   peer_protocol.Request,
		Index:  chunk.Index,
		Begin:  chunk.Begin,
		Length: chunk.Length,
	})
	return true
}

// Returns true if an unsatisfied request was canceled.
func (c *connection) Cancel(r request) bool {
	if c.Requests == nil {
		return false
	}
	if _, ok := c.Requests[r]; !ok {
		return false
	}
	delete(c.Requests, r)
	c.Post(peer_protocol.Message{
		Type:   peer_protocol.Cancel,
		Index:  r.Index,
		Begin:  r.Begin,
		Length: r.Length,
	})
	return true
}

// Returns true if an unsatisfied request was canceled.
func (c *connection) PeerCancel(r request) bool {
	if c.PeerRequests == nil {
		return false
	}
	if _, ok := c.PeerRequests[r]; !ok {
		return false
	}
	delete(c.PeerRequests, r)
	return true
}

func (c *connection) Choke() {
	if c.Choked {
		return
	}
	c.Post(peer_protocol.Message{
		Type: peer_protocol.Choke,
	})
	c.Choked = true
}

func (c *connection) Unchoke() {
	if !c.Choked {
		return
	}
	c.Post(peer_protocol.Message{
		Type: peer_protocol.Unchoke,
	})
	c.Choked = false
}

func (c *connection) SetInterested(interested bool) {
	if c.Interested == interested {
		return
	}
	c.Post(peer_protocol.Message{
		Type: func() peer_protocol.MessageType {
			if interested {
				return peer_protocol.Interested
			} else {
				return peer_protocol.NotInterested
			}
		}(),
	})
	c.Interested = interested
}

var (
	// Four consecutive zero bytes that comprise a keep alive on the wire.
	keepAliveBytes [4]byte
)

// Writes buffers to the socket from the write channel.
func (conn *connection) writer() {
	for b := range conn.write {
		_, err := conn.Socket.Write(b)
		// log.Printf("wrote %q to %s", b, conn.Socket.RemoteAddr())
		if err != nil {
			if !conn.getClosed() {
				log.Print(err)
			}
			break
		}
	}
}

func (conn *connection) writeOptimizer(keepAliveDelay time.Duration) {
	defer close(conn.write) // Responsible for notifying downstream routines.
	pending := list.New()   // Message queue.
	var nextWrite []byte    // Set to nil if we need to need to marshal the next message.
	timer := time.NewTimer(keepAliveDelay)
	defer timer.Stop()
	lastWrite := time.Now()
	for {
		write := conn.write // Set to nil if there's nothing to write.
		if pending.Len() == 0 {
			write = nil
		} else if nextWrite == nil {
			var err error
			nextWrite, err = pending.Front().Value.(encoding.BinaryMarshaler).MarshalBinary()
			if err != nil {
				panic(err)
			}
		}
	event:
		select {
		case <-timer.C:
			if pending.Len() != 0 {
				break
			}
			keepAliveTime := lastWrite.Add(keepAliveDelay)
			if time.Now().Before(keepAliveTime) {
				timer.Reset(keepAliveTime.Sub(time.Now()))
				break
			}
			pending.PushBack(peer_protocol.Message{Keepalive: true})
		case msg, ok := <-conn.post:
			if !ok {
				return
			}
			if msg.Type == peer_protocol.Cancel {
				for e := pending.Back(); e != nil; e = e.Prev() {
					elemMsg := e.Value.(peer_protocol.Message)
					if elemMsg.Type == peer_protocol.Request && msg.Index == elemMsg.Index && msg.Begin == elemMsg.Begin && msg.Length == elemMsg.Length {
						pending.Remove(e)
						log.Printf("optimized cancel! %v", msg)
						break event
					}
				}
			}
			pending.PushBack(msg)
		case write <- nextWrite:
			pending.Remove(pending.Front())
			nextWrite = nil
			lastWrite = time.Now()
			if pending.Len() == 0 {
				timer.Reset(keepAliveDelay)
			}
		}
	}
}
<commit_msg>Add some extra char flags to connection status<commit_after>package torrent

import (
	"container/list"
	"encoding"
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"time"

	"bitbucket.org/anacrolix/go.torrent/peer_protocol"
)

// Maintains the state of a connection with a peer.
type connection struct {
	Socket   net.Conn
	Incoming bool
	closed   bool
	mu       sync.Mutex // Only for closing.
	post     chan peer_protocol.Message
	write    chan []byte

	// Stuff controlled by the local peer.
	Interested bool
	Choked     bool
	Requests   map[request]struct{}

	// Stuff controlled by the remote peer.
	PeerId           [20]byte
	PeerInterested   bool
	PeerChoked       bool
	PeerRequests     map[request]struct{}
	PeerExtensions   [8]byte
	PeerPieces       []bool
	PeerMaxRequests  int // Maximum pending requests the peer allows.
	PeerExtensionIDs map[string]int64
	PeerClientName   string
}

func (cn *connection) completedString() string {
	if cn.PeerPieces == nil {
		return "?"
	}
	f := float32(cn.piecesPeerHasCount()) / float32(cn.totalPiecesCount())
	return fmt.Sprintf("%d%%", int(f*100))
}

func (cn *connection) totalPiecesCount() int {
	return len(cn.PeerPieces)
}

func (cn *connection) piecesPeerHasCount() (count int) {
	for _, has := range cn.PeerPieces {
		if has {
			count++
		}
	}
	return
}

func (cn *connection) WriteStatus(w io.Writer) {
	fmt.Fprintf(w, "%q: %s-%s: %s completed: ", cn.PeerId, cn.Socket.LocalAddr(), cn.Socket.RemoteAddr(), cn.completedString())
	c := func(b byte) {
		fmt.Fprintf(w, "%c", b)
	}
	// https://trac.transmissionbt.com/wiki/PeerStatusText
	if cn.PeerInterested && !cn.Choked {
		c('O')
	}
	if len(cn.Requests) != 0 {
		c('D')
	}
	if cn.PeerChoked && cn.Interested {
		c('d')
	}
	if !cn.Choked && cn.PeerInterested {
		c('U')
	} else {
		c('u')
	}
	if !cn.PeerChoked && !cn.Interested {
		c('K')
	}
	if !cn.Choked && !cn.PeerInterested {
		c('?')
	}
	if cn.Incoming {
		c('I')
	}
	fmt.Fprintln(w)
}

func (c *connection) Close() {
	c.mu.Lock()
	if c.closed {
		return
	}
	c.Socket.Close()
	close(c.post)
	c.closed = true
	c.mu.Unlock()
}

func (c *connection) getClosed() bool {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.closed
}

func (c *connection) PeerHasPiece(index peer_protocol.Integer) bool {
	if c.PeerPieces == nil {
		return false
	}
	if int(index) >= len(c.PeerPieces) {
		return false
	}
	return c.PeerPieces[index]
}

func (c *connection) Post(msg peer_protocol.Message) {
	c.post <- msg
}

func (c *connection) RequestPending(r request) bool {
	_, ok := c.Requests[r]
	return ok
}

// Returns true if more requests can be sent.
func (c *connection) Request(chunk request) bool {
	if len(c.Requests) >= c.PeerMaxRequests {
		return false
	}
	if !c.PeerHasPiece(chunk.Index) {
		return true
	}
	if c.RequestPending(chunk) {
		return true
	}
	c.SetInterested(true)
	if c.PeerChoked {
		return false
	}
	if c.Requests == nil {
		c.Requests = make(map[request]struct{}, c.PeerMaxRequests)
	}
	c.Requests[chunk] = struct{}{}
	c.Post(peer_protocol.Message{
		Type:   peer_protocol.Request,
		Index:  chunk.Index,
		Begin:  chunk.Begin,
		Length: chunk.Length,
	})
	return true
}

// Returns true if an unsatisfied request was canceled.
func (c *connection) Cancel(r request) bool {
	if c.Requests == nil {
		return false
	}
	if _, ok := c.Requests[r]; !ok {
		return false
	}
	delete(c.Requests, r)
	c.Post(peer_protocol.Message{
		Type:   peer_protocol.Cancel,
		Index:  r.Index,
		Begin:  r.Begin,
		Length: r.Length,
	})
	return true
}

// Returns true if an unsatisfied request was canceled.
func (c *connection) PeerCancel(r request) bool {
	if c.PeerRequests == nil {
		return false
	}
	if _, ok := c.PeerRequests[r]; !ok {
		return false
	}
	delete(c.PeerRequests, r)
	return true
}

func (c *connection) Choke() {
	if c.Choked {
		return
	}
	c.Post(peer_protocol.Message{
		Type: peer_protocol.Choke,
	})
	c.Choked = true
}

func (c *connection) Unchoke() {
	if !c.Choked {
		return
	}
	c.Post(peer_protocol.Message{
		Type: peer_protocol.Unchoke,
	})
	c.Choked = false
}

func (c *connection) SetInterested(interested bool) {
	if c.Interested == interested {
		return
	}
	c.Post(peer_protocol.Message{
		Type: func() peer_protocol.MessageType {
			if interested {
				return peer_protocol.Interested
			} else {
				return peer_protocol.NotInterested
			}
		}(),
	})
	c.Interested = interested
}

var (
	// Four consecutive zero bytes that comprise a keep alive on the wire.
	keepAliveBytes [4]byte
)

// Writes buffers to the socket from the write channel.
func (conn *connection) writer() {
	for b := range conn.write {
		_, err := conn.Socket.Write(b)
		// log.Printf("wrote %q to %s", b, conn.Socket.RemoteAddr())
		if err != nil {
			if !conn.getClosed() {
				log.Print(err)
			}
			break
		}
	}
}

func (conn *connection) writeOptimizer(keepAliveDelay time.Duration) {
	defer close(conn.write) // Responsible for notifying downstream routines.
	pending := list.New()   // Message queue.
	var nextWrite []byte    // Set to nil if we need to need to marshal the next message.
	timer := time.NewTimer(keepAliveDelay)
	defer timer.Stop()
	lastWrite := time.Now()
	for {
		write := conn.write // Set to nil if there's nothing to write.
		if pending.Len() == 0 {
			write = nil
		} else if nextWrite == nil {
			var err error
			nextWrite, err = pending.Front().Value.(encoding.BinaryMarshaler).MarshalBinary()
			if err != nil {
				panic(err)
			}
		}
	event:
		select {
		case <-timer.C:
			if pending.Len() != 0 {
				break
			}
			keepAliveTime := lastWrite.Add(keepAliveDelay)
			if time.Now().Before(keepAliveTime) {
				timer.Reset(keepAliveTime.Sub(time.Now()))
				break
			}
			pending.PushBack(peer_protocol.Message{Keepalive: true})
		case msg, ok := <-conn.post:
			if !ok {
				return
			}
			if msg.Type == peer_protocol.Cancel {
				for e := pending.Back(); e != nil; e = e.Prev() {
					elemMsg := e.Value.(peer_protocol.Message)
					if elemMsg.Type == peer_protocol.Request && msg.Index == elemMsg.Index && msg.Begin == elemMsg.Begin && msg.Length == elemMsg.Length {
						pending.Remove(e)
						log.Printf("optimized cancel! %v", msg)
						break event
					}
				}
			}
			pending.PushBack(msg)
		case write <- nextWrite:
			pending.Remove(pending.Front())
			nextWrite = nil
			lastWrite = time.Now()
			if pending.Len() == 0 {
				timer.Reset(keepAliveDelay)
			}
		}
	}
}
<|endoftext|>