<commit_before>package copper

import (
	"bufio"
	"errors"
	"io"
	"net"
	"sync"
	"time"
)

const (
	inactivityTimeout = 60 * time.Second
	generatePingAfter = 2 * inactivityTimeout / 3
)

// Returned when stream handler is nil
var ErrInvalidStreamHandler = errors.New("stream handler cannot be nil")

// Returned when target id is not valid or not previously registered
var ErrInvalidTarget = errors.New("target must be greater than 0 and registered")

// Returned when connection is closed with a Close() call
var ErrConnClosed = errors.New("connection closed")

// StreamHandler is used to handle incoming streams
type StreamHandler interface {
	HandleStream(target int64, r io.Reader, w io.Writer)
}

// StreamHandlerFunc wraps a function to conform with StreamHandler interface
type StreamHandlerFunc func(target int64, r io.Reader, w io.Writer)

var _ StreamHandler = StreamHandlerFunc(nil)

// HandleStream calls the underlying function
func (f StreamHandlerFunc) HandleStream(target int64, r io.Reader, w io.Writer) {
	f(target, r, w)
}

// Conn is a multiplexed connection implementing the copper protocol
type Conn interface {
	Close() error
	OpenStream(target int64) (r io.Reader, w io.Writer, err error)
	AddHandler(handler StreamHandler) (target int64, err error)
	RemoveHandler(target int64) error
}

type rawConn struct {
	lock        sync.Mutex
	conn        net.Conn
	closed      bool
	failure     error
	signal      chan struct{}
	pingAcks    []uint64
	pingQueue   []uint64
	pingResults map[uint64][]chan error
	handlers    map[int64]StreamHandler
	nexthandler int64
}

var _ Conn = &rawConn{}

// NewConn wraps the underlying network connection with the copper protocol
func NewConn(conn net.Conn, handler StreamHandler) Conn {
	handlers := map[int64]StreamHandler{
		0: handler,
	}
	c := &rawConn{
		conn:        conn,
		closed:      false,
		signal:      make(chan struct{}, 1),
		pingResults: make(map[uint64][]chan error),
		handlers:    handlers,
		nexthandler: 1,
	}
	go c.readloop()
	go c.writeloop()
	return c
}

func (c *rawConn) wakeupLocked() {
	if !c.closed {
		select {
		case c.signal <- struct{}{}:
		default:
		}
	}
}

func (c *rawConn) closeWithErrorLocked(err error) error {
	if !c.closed {
		c.closed = true
		c.failure = err
		close(c.signal)
		return nil
	}
	return c.failure
}

func (c *rawConn) closeWithError(err error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.closeWithErrorLocked(err)
}

func (c *rawConn) Close() error {
	return c.closeWithError(ErrConnClosed)
}

func (c *rawConn) OpenStream(target int64) (io.Reader, io.Writer, error) {
	// TODO
	return nil, nil, nil
}

func (c *rawConn) AddHandler(handler StreamHandler) (int64, error) {
	if handler == nil {
		return 0, ErrInvalidStreamHandler
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	target := c.nexthandler
	c.nexthandler++
	c.handlers[target] = handler
	return target, nil
}

func (c *rawConn) RemoveHandler(target int64) error {
	if target <= 0 {
		return ErrInvalidTarget
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	if _, ok := c.handlers[target]; !ok {
		return ErrInvalidTarget
	}
	delete(c.handlers, target)
	return nil
}

func (c *rawConn) addPingAck(value uint64) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.pingAcks = append(c.pingAcks, value)
	c.wakeupLocked()
}

func (c *rawConn) takePingResult(value uint64) (result chan error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	results, ok := c.pingResults[value]
	if ok {
		result = results[0]
		if len(results) > 1 {
			resultscopy := make([]chan error, len(results)-1)
			copy(resultscopy, results[1:])
			c.pingResults[value] = resultscopy
		} else {
			delete(c.pingResults, value)
		}
	}
	return
}

func (c *rawConn) addPingRequest(value uint64, result chan error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return c.failure
	}
	c.pingResults[value] = append(c.pingResults[value], result)
	c.pingQueue = append(c.pingQueue, value)
	return nil
}

func (c *rawConn) failAllPings() {
	c.lock.Lock()
	defer c.lock.Unlock()
	pingResults := c.pingResults
	c.pingQueue = nil
	c.pingResults = nil
	for _, results := range pingResults {
		for _, result := range results {
			select {
			case result <- c.failure:
			default:
			}
			close(result)
		}
	}
}

func (c *rawConn) readloop() {
	r := bufio.NewReader(c.conn)
	for {
		rawFrame, err := readFrame(r)
		if err != nil {
			c.closeWithError(err)
			break
		}
		switch frame := rawFrame.(type) {
		case pingFrame:
			if (frame.flags & flagAck) != 0 {
				result := c.takePingResult(frame.value)
				if result != nil {
					select {
					case result <- nil:
					default:
					}
					close(result)
				}
			} else {
				c.addPingAck(frame.value)
			}
		default:
			panic("unhandled frame type")
		}
	}
	c.failAllPings()
}

func (c *rawConn) prepareWriteBatch(datarequired bool) (frames []frame, err error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return nil, c.failure
	}
	if len(c.pingQueue) > 0 {
		for _, value := range c.pingQueue {
			frames = append(frames, pingFrame{
				value: value,
			})
		}
		c.pingQueue = c.pingQueue[:0]
		return
	}
	if datarequired {
		frames = append(frames, dataFrame{
			streamID: 0,
			data:     nil,
		})
	}
	return
}

func (c *rawConn) writeloop() {
	datarequired := false
	w := bufio.NewWriter(c.conn)
	t := time.NewTimer(generatePingAfter)
	for {
		select {
		case <-c.signal:
		case <-t.C:
			datarequired = true
		}
		for {
			frames, err := c.prepareWriteBatch(datarequired)
			if err != nil {
				// Attempt to notify the other side that we have an error
				// It's ok if any of this fails, the read side will stop
				// when we close the connection.
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				frame := fatalFrame{
					reason:  255, // TODO: implement reason codes
					message: []byte(err.Error()),
				}
				frame.writeFrameTo(w)
				w.Flush()
				c.conn.Close()
				return
			}
			datarequired = false
			if len(frames) == 0 {
				break
			}
			for _, frame := range frames {
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				err = frame.writeFrameTo(w)
				if err != nil {
					c.closeWithError(err)
					c.conn.Close()
					return
				}
			}
		}
		if w.Buffered() > 0 {
			c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
			err := w.Flush()
			if err != nil {
				c.closeWithError(err)
				c.conn.Close()
				return
			}
		}
		t.Reset(generatePingAfter)
	}
}
<commit_msg>Set read deadline in the readloop<commit_after>package copper

import (
	"bufio"
	"errors"
	"io"
	"net"
	"sync"
	"time"
)

const (
	inactivityTimeout = 60 * time.Second
	generatePingAfter = 2 * inactivityTimeout / 3
)

// Returned when stream handler is nil
var ErrInvalidStreamHandler = errors.New("stream handler cannot be nil")

// Returned when target id is not valid or not previously registered
var ErrInvalidTarget = errors.New("target must be greater than 0 and registered")

// Returned when connection is closed with a Close() call
var ErrConnClosed = errors.New("connection closed")

// StreamHandler is used to handle incoming streams
type StreamHandler interface {
	HandleStream(target int64, r io.Reader, w io.Writer)
}

// StreamHandlerFunc wraps a function to conform with StreamHandler interface
type StreamHandlerFunc func(target int64, r io.Reader, w io.Writer)

var _ StreamHandler = StreamHandlerFunc(nil)

// HandleStream calls the underlying function
func (f StreamHandlerFunc) HandleStream(target int64, r io.Reader, w io.Writer) {
	f(target, r, w)
}

// Conn is a multiplexed connection implementing the copper protocol
type Conn interface {
	Close() error
	OpenStream(target int64) (r io.Reader, w io.Writer, err error)
	AddHandler(handler StreamHandler) (target int64, err error)
	RemoveHandler(target int64) error
}

type rawConn struct {
	lock        sync.Mutex
	conn        net.Conn
	closed      bool
	failure     error
	signal      chan struct{}
	pingAcks    []uint64
	pingQueue   []uint64
	pingResults map[uint64][]chan error
	handlers    map[int64]StreamHandler
	nexthandler int64
}

var _ Conn = &rawConn{}

// NewConn wraps the underlying network connection with the copper protocol
func NewConn(conn net.Conn, handler StreamHandler) Conn {
	handlers := map[int64]StreamHandler{
		0: handler,
	}
	c := &rawConn{
		conn:        conn,
		closed:      false,
		signal:      make(chan struct{}, 1),
		pingResults: make(map[uint64][]chan error),
		handlers:    handlers,
		nexthandler: 1,
	}
	go c.readloop()
	go c.writeloop()
	return c
}

func (c *rawConn) wakeupLocked() {
	if !c.closed {
		select {
		case c.signal <- struct{}{}:
		default:
		}
	}
}

func (c *rawConn) closeWithErrorLocked(err error) error {
	if !c.closed {
		c.closed = true
		c.failure = err
		close(c.signal)
		return nil
	}
	return c.failure
}

func (c *rawConn) closeWithError(err error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.closeWithErrorLocked(err)
}

func (c *rawConn) Close() error {
	return c.closeWithError(ErrConnClosed)
}

func (c *rawConn) OpenStream(target int64) (io.Reader, io.Writer, error) {
	// TODO
	return nil, nil, nil
}

func (c *rawConn) AddHandler(handler StreamHandler) (int64, error) {
	if handler == nil {
		return 0, ErrInvalidStreamHandler
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	target := c.nexthandler
	c.nexthandler++
	c.handlers[target] = handler
	return target, nil
}

func (c *rawConn) RemoveHandler(target int64) error {
	if target <= 0 {
		return ErrInvalidTarget
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	if _, ok := c.handlers[target]; !ok {
		return ErrInvalidTarget
	}
	delete(c.handlers, target)
	return nil
}

func (c *rawConn) addPingAck(value uint64) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.pingAcks = append(c.pingAcks, value)
	c.wakeupLocked()
}

func (c *rawConn) takePingResult(value uint64) (result chan error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	results, ok := c.pingResults[value]
	if ok {
		result = results[0]
		if len(results) > 1 {
			resultscopy := make([]chan error, len(results)-1)
			copy(resultscopy, results[1:])
			c.pingResults[value] = resultscopy
		} else {
			delete(c.pingResults, value)
		}
	}
	return
}

func (c *rawConn) addPingRequest(value uint64, result chan error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return c.failure
	}
	c.pingResults[value] = append(c.pingResults[value], result)
	c.pingQueue = append(c.pingQueue, value)
	return nil
}

func (c *rawConn) failAllPings() {
	c.lock.Lock()
	defer c.lock.Unlock()
	pingResults := c.pingResults
	c.pingQueue = nil
	c.pingResults = nil
	for _, results := range pingResults {
		for _, result := range results {
			select {
			case result <- c.failure:
			default:
			}
			close(result)
		}
	}
}

func (c *rawConn) readloop() {
	r := bufio.NewReader(c.conn)
	for {
		c.conn.SetReadDeadline(time.Now().Add(inactivityTimeout))
		rawFrame, err := readFrame(r)
		if err != nil {
			c.closeWithError(err)
			break
		}
		switch frame := rawFrame.(type) {
		case pingFrame:
			if (frame.flags & flagAck) != 0 {
				result := c.takePingResult(frame.value)
				if result != nil {
					select {
					case result <- nil:
					default:
					}
					close(result)
				}
			} else {
				c.addPingAck(frame.value)
			}
		default:
			panic("unhandled frame type")
		}
	}
	c.failAllPings()
}

func (c *rawConn) prepareWriteBatch(datarequired bool) (frames []frame, err error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return nil, c.failure
	}
	if len(c.pingQueue) > 0 {
		for _, value := range c.pingQueue {
			frames = append(frames, pingFrame{
				value: value,
			})
		}
		c.pingQueue = c.pingQueue[:0]
		return
	}
	if datarequired {
		frames = append(frames, dataFrame{
			streamID: 0,
			data:     nil,
		})
	}
	return
}

func (c *rawConn) writeloop() {
	datarequired := false
	w := bufio.NewWriter(c.conn)
	t := time.NewTimer(generatePingAfter)
	for {
		select {
		case <-c.signal:
		case <-t.C:
			datarequired = true
		}
		for {
			frames, err := c.prepareWriteBatch(datarequired)
			if err != nil {
				// Attempt to notify the other side that we have an error
				// It's ok if any of this fails, the read side will stop
				// when we close the connection.
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				frame := fatalFrame{
					reason:  255, // TODO: implement reason codes
					message: []byte(err.Error()),
				}
				frame.writeFrameTo(w)
				w.Flush()
				c.conn.Close()
				return
			}
			datarequired = false
			if len(frames) == 0 {
				break
			}
			for _, frame := range frames {
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				err = frame.writeFrameTo(w)
				if err != nil {
					c.closeWithError(err)
					c.conn.Close()
					return
				}
			}
		}
		if w.Buffered() > 0 {
			c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
			err := w.Flush()
			if err != nil {
				c.closeWithError(err)
				c.conn.Close()
				return
			}
		}
		t.Reset(generatePingAfter)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"fmt"
	"strconv"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"golang.org/x/net/context"
)

type CmdPassphraseRemember struct {
	libkb.Contextified
	newValue *bool
	json     bool
}

func NewCmdPassphraseRemember(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "remember",
		ArgumentHelp: "[bool]",
		Usage:        "Remember your keybase account passphrase.",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(NewCmdPassphraseRememberRunner(g), "change", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "j, json",
				Usage: "If no new value is provided, output the current status as a JSON boolean",
			},
		},
	}
}

func NewCmdPassphraseRememberRunner(g *libkb.GlobalContext) *CmdPassphraseRemember {
	return &CmdPassphraseRemember{
		Contextified: libkb.NewContextified(g),
	}
}

func (c *CmdPassphraseRemember) Run() error {
	ctx := context.Background()
	ui := c.G().UI.GetTerminalUI()
	protocols := []rpc.Protocol{
		NewSecretUIProtocol(c.G()),
	}
	if err := RegisterProtocolsWithContext(protocols, c.G()); err != nil {
		return err
	}

	cfg, err := GetConfigClient(c.G())
	if err != nil {
		return err
	}

	if c.newValue == nil {
		currentVal, err := cfg.GetRememberPassphrase(ctx, 0)
		if err != nil {
			return err
		}

		if c.json {
			dui := c.G().UI.GetDumbOutputUI()
			_, err = dui.Printf(strconv.FormatBool(currentVal) + "\n")
			return err
		}

		if currentVal {
			ui.Printf(`Your current account will always stay logged in.
You won't be asked for your password when restarting the app or your device.
`)
			return nil
		}

		ui.Printf(`Your current account will be logged out when you restart the app or your device.`)
		return nil
	}

	newValue := *c.newValue
	if err := cfg.SetRememberPassphrase(ctx, keybase1.SetRememberPassphraseArg{
		Remember: newValue,
	}); err != nil {
		return err
	}

	if newValue {
		ui.Printf("This account will now stay logged in across restarts.\n")
	} else {
		ui.Printf("You will now be asked for your password when restarting the app.\n")
	}
	return nil
}

func (c *CmdPassphraseRemember) ParseArgv(ctx *cli.Context) error {
	c.json = ctx.Bool("json")

	newValStr := ctx.Args().First()
	if newValStr == "" {
		return nil
	}
	newVal, err := strconv.ParseBool(newValStr)
	if err != nil {
		return fmt.Errorf("Invalid argument syntax: %v", err)
	}
	c.newValue = &newVal
	return nil
}

func (c *CmdPassphraseRemember) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<commit_msg>tweak remember passphrase help copy (#20516)<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"fmt"
	"strconv"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"golang.org/x/net/context"
)

type CmdPassphraseRemember struct {
	libkb.Contextified
	newValue *bool
	json     bool
}

func NewCmdPassphraseRemember(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "remember",
		ArgumentHelp: "[<true|false>]",
		Usage:        "Set whether your account passphrase should be remembered across restarts. Run with no arguments to check status.",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(NewCmdPassphraseRememberRunner(g), "change", c)
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "j, json",
				Usage: "If no new value is provided, output the current status as a JSON boolean",
			},
		},
	}
}

func NewCmdPassphraseRememberRunner(g *libkb.GlobalContext) *CmdPassphraseRemember {
	return &CmdPassphraseRemember{
		Contextified: libkb.NewContextified(g),
	}
}

func (c *CmdPassphraseRemember) Run() error {
	ctx := context.Background()
	ui := c.G().UI.GetTerminalUI()
	protocols := []rpc.Protocol{
		NewSecretUIProtocol(c.G()),
	}
	if err := RegisterProtocolsWithContext(protocols, c.G()); err != nil {
		return err
	}

	cfg, err := GetConfigClient(c.G())
	if err != nil {
		return err
	}

	if c.newValue == nil {
		currentVal, err := cfg.GetRememberPassphrase(ctx, 0)
		if err != nil {
			return err
		}

		if c.json {
			dui := c.G().UI.GetDumbOutputUI()
			_, err = dui.Printf(strconv.FormatBool(currentVal) + "\n")
			return err
		}

		if currentVal {
			ui.Printf(`Your current account will always stay logged in.
You won't be asked for your password when restarting the app or your device.
`)
			return nil
		}

		ui.Printf(`Your current account will be logged out when you restart the app or your device.`)
		return nil
	}

	newValue := *c.newValue
	if err := cfg.SetRememberPassphrase(ctx, keybase1.SetRememberPassphraseArg{
		Remember: newValue,
	}); err != nil {
		return err
	}

	if newValue {
		ui.Printf("This account will now stay logged in across restarts.\n")
	} else {
		ui.Printf("You will now be asked for your password when restarting the app.\n")
	}
	return nil
}

func (c *CmdPassphraseRemember) ParseArgv(ctx *cli.Context) error {
	c.json = ctx.Bool("json")

	newValStr := ctx.Args().First()
	if newValStr == "" {
		return nil
	}
	newVal, err := strconv.ParseBool(newValStr)
	if err != nil {
		return fmt.Errorf("Invalid argument syntax: %v", err)
	}
	c.newValue = &newVal
	return nil
}

func (c *CmdPassphraseRemember) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<|endoftext|>


<commit_before>package action

import (
	boshappl "bosh/agent/applier"
	boshas "bosh/agent/applier/applyspec"
	bosherr "bosh/errors"
	boshplatform "bosh/platform"
	boshsettings "bosh/settings"
	boshsys "bosh/system"
	"encoding/json"
	"path/filepath"
)

type applyAction struct {
	applier  boshappl.Applier
	fs       boshsys.FileSystem
	platform boshplatform.Platform
}

func newApply(applier boshappl.Applier, fs boshsys.FileSystem, platform boshplatform.Platform) (action applyAction) {
	action.applier = applier
	action.fs = fs
	action.platform = platform
	return
}

func (a applyAction) IsAsynchronous() bool {
	return true
}

func (a applyAction) Run(applySpec boshas.V1ApplySpec) (value interface{}, err error) {
	err = a.applier.Apply(applySpec)
	if err != nil {
		err = bosherr.WrapError(err, "Applying")
		return
	}

	spec, err := json.Marshal(applySpec)
	if err != nil {
		err = bosherr.WrapError(err, "Marshalling apply spec")
		return
	}

	specFilePath := filepath.Join(boshsettings.VCAP_BASE_DIR, "/bosh/spec.json")
	_, err = a.fs.WriteToFile(specFilePath, string(spec))
	if err != nil {
		err = bosherr.WrapError(err, "Writing spec to disk")
	}
	return
}
<commit_msg>extract method persistApplySpec<commit_after>package action

import (
	boshappl "bosh/agent/applier"
	boshas "bosh/agent/applier/applyspec"
	bosherr "bosh/errors"
	boshplatform "bosh/platform"
	boshsettings "bosh/settings"
	boshsys "bosh/system"
	"encoding/json"
	"path/filepath"
)

type applyAction struct {
	applier  boshappl.Applier
	fs       boshsys.FileSystem
	platform boshplatform.Platform
}

func newApply(applier boshappl.Applier, fs boshsys.FileSystem, platform boshplatform.Platform) (action applyAction) {
	action.applier = applier
	action.fs = fs
	action.platform = platform
	return
}

func (a applyAction) IsAsynchronous() bool {
	return true
}

func (a applyAction) Run(applySpec boshas.V1ApplySpec) (value interface{}, err error) {
	err = a.applier.Apply(applySpec)
	if err != nil {
		err = bosherr.WrapError(err, "Applying")
		return
	}

	err = a.persistApplySpec(applySpec)
	if err != nil {
		err = bosherr.WrapError(err, "Persisting apply spec")
	}
	return
}

func (a applyAction) persistApplySpec(applySpec boshas.V1ApplySpec) (err error) {
	spec, err := json.Marshal(applySpec)
	if err != nil {
		err = bosherr.WrapError(err, "Marshalling apply spec")
		return
	}

	specFilePath := filepath.Join(boshsettings.VCAP_BASE_DIR, "/bosh/spec.json")
	_, err = a.fs.WriteToFile(specFilePath, string(spec))
	if err != nil {
		err = bosherr.WrapError(err, "Writing spec to disk")
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"github.com/Sirupsen/logrus"
)

func daemonize(ctx context.Context) bool {
	logrus.Error("Windows doesn't support daemon mode")
	return false
}
<commit_msg>fix daemonize stub for windows<commit_after>package main

import (
	"github.com/Sirupsen/logrus"
)

func daemonize() bool {
	logrus.Error("Windows doesn't support daemon mode")
	return false
}
<|endoftext|>


<commit_before>package mount

// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeShared(mountPoint string) error {
	return ensureMountedAs(mountPoint, "shared")
}

// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRShared(mountPoint string) error {
	return ensureMountedAs(mountPoint, "rshared")
}

// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
// See the supported options in flags.go for further reference.
func MakePrivate(mountPoint string) error {
	return ensureMountedAs(mountPoint, "private")
}

// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeRPrivate(mountPoint string) error {
	return ensureMountedAs(mountPoint, "rprivate")
}

// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeSlave(mountPoint string) error {
	return ensureMountedAs(mountPoint, "slave")
}

// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRSlave(mountPoint string) error {
	return ensureMountedAs(mountPoint, "rslave")
}

// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeUnbindable(mountPoint string) error {
	return ensureMountedAs(mountPoint, "unbindable")
}

// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
// option enabled. See the supported options in flags.go for further reference.
func MakeRUnbindable(mountPoint string) error {
	return ensureMountedAs(mountPoint, "runbindable")
}

func ensureMountedAs(mountPoint, options string) error {
	mounted, err := Mounted(mountPoint)
	if err != nil {
		return err
	}

	if !mounted {
		if err := ForceMount(mountPoint, mountPoint, "none", "bind"); err != nil {
			return err
		}
	}

	return ForceMount("", mountPoint, "none", options)
}
<commit_msg>pkg/mount/Make*: optimize<commit_after>package mount

// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeShared(mountPoint string) error {
	return ensureMountedAs(mountPoint, SHARED)
}

// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRShared(mountPoint string) error {
	return ensureMountedAs(mountPoint, RSHARED)
}

// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
// See the supported options in flags.go for further reference.
func MakePrivate(mountPoint string) error {
	return ensureMountedAs(mountPoint, PRIVATE)
}

// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeRPrivate(mountPoint string) error {
	return ensureMountedAs(mountPoint, RPRIVATE)
}

// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeSlave(mountPoint string) error {
	return ensureMountedAs(mountPoint, SLAVE)
}

// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRSlave(mountPoint string) error {
	return ensureMountedAs(mountPoint, RSLAVE)
}

// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeUnbindable(mountPoint string) error {
	return ensureMountedAs(mountPoint, UNBINDABLE)
}

// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
// option enabled. See the supported options in flags.go for further reference.
func MakeRUnbindable(mountPoint string) error {
	return ensureMountedAs(mountPoint, RUNBINDABLE)
}

func ensureMountedAs(mnt string, flags int) error {
	mounted, err := Mounted(mnt)
	if err != nil {
		return err
	}

	if !mounted {
		if err := mount(mnt, mnt, "none", uintptr(BIND), ""); err != nil {
			return err
		}
	}

	return mount("", mnt, "none", uintptr(flags), "")
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Romain LÉTENDART
//
// See LICENSE file.

// Contains the bot's core functionalities
package core

import (
	"github.com/thoj/go-ircevent"
)

// Bot structure that contains connection informations, IRC connection, command handlers and message handlers
type Bot struct {
	Nick              string
	Server            string
	Channel           string
	ChannelKey        string
	ircConn           *irc.Connection
	MsgHandlers       []func(*irc.Event, func(*ReplyCallbackData))
	CmdHandlers       []func(*irc.Event, func(*ReplyCallbackData)) bool
	MsgReplyCallbacks []func(*ReplyCallbackData)
	CmdReplyCallbacks []func(*ReplyCallbackData)
}

// Structure used by the handlers to send data in a standardized format
type ReplyCallbackData struct {
	Message string
	Nick    string
}

// Bot constructor.
// Set the required parameters and open the connection to the server.
func NewBot(nick, server, channel, channelKey string) *Bot {
	bot := Bot{Nick: nick, Server: server, Channel: channel, ChannelKey: channelKey}
	bot.ircConn = irc.IRC(nick, nick)
	bot.ircConn.UseTLS = true
	bot.ircConn.Connect(server)
	bot.ircConn.Join(channel + " " + channelKey)
	bot.ircConn.AddCallback("PRIVMSG", bot.mainHandler)
	return &bot
}

// msgProcessCallback will be called on every user message the bot reads (if a command was not found previously in the message).
// replyCallback is to be called by msgProcessCallback (or not) to yield and process its result as a string message.
func (bot *Bot) AddMsgHandler(msgProcessCallback func(*irc.Event, func(*ReplyCallbackData)), replyCallback func(*ReplyCallbackData)) {
	if msgProcessCallback != nil && replyCallback != nil {
		bot.MsgHandlers = append(bot.MsgHandlers, msgProcessCallback)
		bot.MsgReplyCallbacks = append(bot.MsgReplyCallbacks, replyCallback)
	}
}

// cmdProcessCallback will be called on every user message the bot reads (if a command was not found previously in the message).
// replyCallback is to be called by cmdProcessCallback (or not) to yield and process its result as a string message.
// cmdProcessCallback must check if their replyCallback is nil before using it
// Command handlers must return true if they found a command to process, false otherwise
func (bot *Bot) AddCmdHandler(cmdProcessCallback func(*irc.Event, func(*ReplyCallbackData)) bool, replyCallback func(*ReplyCallbackData)) {
	if cmdProcessCallback != nil {
		bot.CmdHandlers = append(bot.CmdHandlers, cmdProcessCallback)
		bot.CmdReplyCallbacks = append(bot.CmdReplyCallbacks, replyCallback)
	}
}

// Start the event loop
func (bot *Bot) Run() {
	bot.ircConn.Loop()
}

// Send a message to the channel where the bot is connected
func (bot *Bot) ReplyToAll(data *ReplyCallbackData) {
	bot.ircConn.Privmsg(bot.Channel, data.Message)
}

// Send a private message to the user "data.Nick".
// If data.Nick is an empty string, do nothing
func (bot *Bot) ReplyToNick(data *ReplyCallbackData) {
	if data.Nick != "" {
		bot.ircConn.Privmsg(data.Nick, data.Message)
	}
}

// Send a private message to the user "data.Nick" if "data.Nick" isn't an empty string.
// If "data.Nick" is an empty string then send the message to the channel where the bot is connected.
func (bot *Bot) Reply(data *ReplyCallbackData) {
	if data.Nick == "" {
		bot.ircConn.Privmsg(bot.Channel, data.Message)
	} else {
		bot.ircConn.Privmsg(data.Nick, data.Message)
	}
}

// Handler called on every message posted in the channel where the bot is connected or directly sent to the bot
func (bot *Bot) mainHandler(event *irc.Event) {
	for i, handler := range bot.CmdHandlers {
		if handler(event, bot.CmdReplyCallbacks[i]) {
			return
		}
	}
	for i, handler := range bot.MsgHandlers {
		handler(event, bot.MsgReplyCallbacks[i])
	}
}
<commit_msg>Core: Added a Quit function to the bot struct<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Romain LÉTENDART
//
// See LICENSE file.

// Contains the bot's core functionalities
package core

import (
	"github.com/thoj/go-ircevent"
)

// Bot structure that contains connection informations, IRC connection, command handlers and message handlers
type Bot struct {
	Nick              string
	Server            string
	Channel           string
	ChannelKey        string
	ircConn           *irc.Connection
	MsgHandlers       []func(*irc.Event, func(*ReplyCallbackData))
	CmdHandlers       []func(*irc.Event, func(*ReplyCallbackData)) bool
	MsgReplyCallbacks []func(*ReplyCallbackData)
	CmdReplyCallbacks []func(*ReplyCallbackData)
}

// Structure used by the handlers to send data in a standardized format
type ReplyCallbackData struct {
	Message string
	Nick    string
}

// Bot constructor.
// Set the required parameters and open the connection to the server.
func NewBot(nick, server, channel, channelKey string) *Bot {
	bot := Bot{Nick: nick, Server: server, Channel: channel, ChannelKey: channelKey}
	bot.ircConn = irc.IRC(nick, nick)
	bot.ircConn.UseTLS = true
	bot.ircConn.Connect(server)
	bot.ircConn.Join(channel + " " + channelKey)
	bot.ircConn.AddCallback("PRIVMSG", bot.mainHandler)
	return &bot
}

// msgProcessCallback will be called on every user message the bot reads (if a command was not found previously in the message).
// replyCallback is to be called by msgProcessCallback (or not) to yield and process its result as a string message.
func (bot *Bot) AddMsgHandler(msgProcessCallback func(*irc.Event, func(*ReplyCallbackData)), replyCallback func(*ReplyCallbackData)) {
	if msgProcessCallback != nil && replyCallback != nil {
		bot.MsgHandlers = append(bot.MsgHandlers, msgProcessCallback)
		bot.MsgReplyCallbacks = append(bot.MsgReplyCallbacks, replyCallback)
	}
}

// cmdProcessCallback will be called on every user message the bot reads (if a command was not found previously in the message).
// replyCallback is to be called by cmdProcessCallback (or not) to yield and process its result as a string message.
// cmdProcessCallback must check if their replyCallback is nil before using it
// Command handlers must return true if they found a command to process, false otherwise
func (bot *Bot) AddCmdHandler(cmdProcessCallback func(*irc.Event, func(*ReplyCallbackData)) bool, replyCallback func(*ReplyCallbackData)) {
	if cmdProcessCallback != nil {
		bot.CmdHandlers = append(bot.CmdHandlers, cmdProcessCallback)
		bot.CmdReplyCallbacks = append(bot.CmdReplyCallbacks, replyCallback)
	}
}

// Start the event loop
func (bot *Bot) Run() {
	bot.ircConn.Loop()
}

// Exit the event loop
func (bot *Bot) Stop() {
	// Quit the current connection and disconnect from the server (details: https://tools.ietf.org/html/rfc1459#section-4.1.6)
	bot.ircConn.Quit()
}

// Send a message to the channel where the bot is connected
func (bot *Bot) ReplyToAll(data *ReplyCallbackData) {
	bot.ircConn.Privmsg(bot.Channel, data.Message)
}

// Send a private message to the user "data.Nick".
// If data.Nick is an empty string, do nothing
func (bot *Bot) ReplyToNick(data *ReplyCallbackData) {
	if data.Nick != "" {
		bot.ircConn.Privmsg(data.Nick, data.Message)
	}
}

// Send a private message to the user "data.Nick" if "data.Nick" isn't an empty string.
// If "data.Nick" is an empty string then send the message to the channel where the bot is connected.
func (bot *Bot) Reply(data *ReplyCallbackData) {
	if data.Nick == "" {
		bot.ircConn.Privmsg(bot.Channel, data.Message)
	} else {
		bot.ircConn.Privmsg(data.Nick, data.Message)
	}
}

// Handler called on every message posted in the channel where the bot is connected or directly sent to the bot
func (bot *Bot) mainHandler(event *irc.Event) {
	for i, handler := range bot.CmdHandlers {
		if handler(event, bot.CmdReplyCallbacks[i]) {
			return
		}
	}
	for i, handler := range bot.MsgHandlers {
		handler(event, bot.MsgReplyCallbacks[i])
	}
}
<|endoftext|>


<commit_before>// Copyright 2016, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// +build cgo

// Package bzip2 implements the BZip2 compressed data format using C wrappers.
package bzip2

/*
#cgo LDFLAGS: -lbz2

#include <stdlib.h>
#include "bzlib.h"

bz_stream* bzDecCreate() {
	bz_stream* state = calloc(1, sizeof(bz_stream));
	BZ2_bzDecompressInit(state, 0, 0);
	return state;
}

int bzDecStream(
	bz_stream* state,
	unsigned int* avail_in, char* next_in,
	unsigned int* avail_out, char* next_out
) {
	state->avail_in = *avail_in;
	state->avail_out = *avail_out;
	state->next_in = next_in;
	state->next_out = next_out;
	int ret = BZ2_bzDecompress(state);
	*avail_in = state->avail_in;
	*avail_out = state->avail_out;
	state->next_in = NULL;
	state->next_out = NULL;
	return ret;
}

void bzDecDestroy(bz_stream* state) {
	BZ2_bzDecompressEnd(state);
	free(state);
}

bz_stream* bzEncCreate(int level) {
	bz_stream* state = calloc(1, sizeof(bz_stream));
	BZ2_bzCompressInit(state, level, 0, 0);
	return state;
}

int bzEncStream(
	bz_stream* state, int mode,
	unsigned int* avail_in, char* next_in,
	unsigned int* avail_out, char* next_out
) {
	state->avail_in = *avail_in;
	state->avail_out = *avail_out;
	state->next_in = next_in;
	state->next_out = next_out;
	int ret = BZ2_bzCompress(state, mode);
	*avail_in = state->avail_in;
	*avail_out = state->avail_out;
	state->next_in = NULL;
	state->next_out = NULL;
	return ret;
}

void bzEncDestroy(bz_stream* state) {
	BZ2_bzCompressEnd(state);
	free(state);
}
*/
import "C"

import (
	"errors"
	"io"
	"unsafe"
)

type Reader struct {
	r     io.Reader
	err   error
	state *C.bz_stream
	buf   []byte
	arr   [1 << 14]byte
}

func NewReader(r io.Reader) io.ReadCloser {
	zr := &Reader{r: r, state: C.bzDecCreate()}
	if zr.state == nil {
		panic("bzip2: could not allocate decoder state")
	}
	return zr
}

func (zr *Reader) Read(buf []byte) (int, error) {
	if zr.state == nil {
		return 0, io.ErrClosedPipe
	}

	var n int
	for zr.err == nil && (len(buf) > 0 && n == 0) {
		availIn, availOut, ptrIn, ptrOut := sizePtrs(zr.buf, buf)
		ret := C.bzDecStream(zr.state, &availIn, ptrIn, &availOut, ptrOut)
		n += len(buf) - int(availOut)
		buf = buf[len(buf)-int(availOut):]
		zr.buf = zr.buf[len(zr.buf)-int(availIn):]

		switch ret {
		case C.BZ_OK:
			if len(zr.buf) == 0 && n == 0 {
				n1, err := zr.r.Read(zr.arr[:])
				if n1 > 0 {
					zr.buf = zr.arr[:n1]
				} else if err != nil {
					if err == io.EOF {
						err = io.ErrUnexpectedEOF
					}
					zr.err = err
				}
			}
		case C.BZ_STREAM_END:
			return n, io.EOF
		default:
			zr.err = errors.New("bzip2: corrupted input")
		}
	}
	return n, zr.err
}

func (zr *Reader) Close() error {
	if zr.state != nil {
		defer func() {
			C.bzDecDestroy(zr.state)
			zr.state = nil
		}()
	}
	return zr.err
}

type Writer struct {
	w     io.Writer
	err   error
	state *C.bz_stream
	buf   []byte
	arr   [1 << 14]byte
}

func NewWriter(w io.Writer, level int) io.WriteCloser {
	if level < 1 || level > 9 {
		panic("bzip2: invalid compression level")
	}

	zw := &Writer{w: w, state: C.bzEncCreate(C.int(level))}
	if zw.state == nil {
		panic("bzip2: could not allocate encoder state")
	}
	return zw
}

func (zw *Writer) Write(buf []byte) (int, error) {
	return zw.write(buf, C.BZ_RUN)
}

func (zw *Writer) write(buf []byte, op C.int) (int, error) {
	if zw.state == nil {
		return 0, io.ErrClosedPipe
	}

	var n int
	flush := op != C.BZ_RUN
	for zw.err == nil && (len(buf) > 0 || flush) {
		availIn, availOut, ptrIn, ptrOut := sizePtrs(buf, zw.arr[:])
		ret := C.bzEncStream(zw.state, op, &availIn, ptrIn, &availOut, ptrOut)
		n += len(buf) - int(availIn)
		buf = buf[len(buf)-int(availIn):]
		zw.buf = zw.arr[:len(zw.arr)-int(availOut)]

		if len(zw.buf) > 0 {
			if _, err := zw.w.Write(zw.buf); err != nil {
				zw.err = err
			}
		}
		switch ret {
		case C.BZ_OK, C.BZ_RUN_OK, C.BZ_FLUSH_OK, C.BZ_FINISH_OK:
			continue // Do nothing
		case C.BZ_STREAM_END:
			return n, zw.err
		default:
			zw.err = errors.New("bzip2: compression error")
		}
	}
	return n, zw.err
}

func (zw *Writer) Close() error {
	if zw.state != nil {
		defer func() {
			C.bzEncDestroy(zw.state)
			zw.state = nil
		}()
		zw.write(nil, C.BZ_FINISH)
	}
	return zw.err
}

func sizePtrs(in, out []byte) (sizeIn, sizeOut C.uint, ptrIn, ptrOut *C.char) {
	sizeIn = C.uint(len(in))
	sizeOut = C.uint(len(out))
	if len(in) > 0 {
		ptrIn = (*C.char)(unsafe.Pointer(&in[0]))
	}
	if len(out) > 0 {
		ptrOut = (*C.char)(unsafe.Pointer(&out[0]))
	}
	return
}
<commit_msg>internal/cgo/bzip2: add support for reading multistream files<commit_after>// Copyright 2016, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// +build cgo

// Package bzip2 implements the BZip2 compressed data format using C wrappers.
package bzip2

/*
#cgo LDFLAGS: -lbz2

#include <stdlib.h>
#include "bzlib.h"

bz_stream* bzDecCreate() {
	bz_stream* state = calloc(1, sizeof(bz_stream));
	BZ2_bzDecompressInit(state, 0, 0);
	return state;
}

int bzDecStream(
	bz_stream* state,
	unsigned int* avail_in, char* next_in,
	unsigned int* avail_out, char* next_out
) {
	state->avail_in = *avail_in;
	state->avail_out = *avail_out;
	state->next_in = next_in;
	state->next_out = next_out;
	int ret = BZ2_bzDecompress(state);
	*avail_in = state->avail_in;
	*avail_out = state->avail_out;
	state->next_in = NULL;
	state->next_out = NULL;
	return ret;
}

void bzDecDestroy(bz_stream* state) {
	BZ2_bzDecompressEnd(state);
	free(state);
}

bz_stream* bzEncCreate(int level) {
	bz_stream* state = calloc(1, sizeof(bz_stream));
	BZ2_bzCompressInit(state, level, 0, 0);
	return state;
}

int bzEncStream(
	bz_stream* state, int mode,
	unsigned int* avail_in, char* next_in,
	unsigned int* avail_out, char* next_out
) {
	state->avail_in = *avail_in;
	state->avail_out = *avail_out;
	state->next_in = next_in;
	state->next_out = next_out;
	int ret = BZ2_bzCompress(state, mode);
	*avail_in = state->avail_in;
	*avail_out = state->avail_out;
	state->next_in = NULL;
	state->next_out = NULL;
	return ret;
}

void bzEncDestroy(bz_stream* state) {
	BZ2_bzCompressEnd(state);
	free(state);
}
*/
import "C"

import (
	"errors"
	"io"
	"unsafe"
)

type Reader struct {
	r     io.Reader
	err   error
	state *C.bz_stream
	buf   []byte
	arr   [1 << 14]byte
}

func NewReader(r io.Reader) io.ReadCloser {
	zr := &Reader{r: r, state: C.bzDecCreate()}
	if zr.state == nil {
		panic("bzip2: could not allocate decoder state")
	}
	return zr
}

func (zr *Reader) Read(buf []byte) (int, error) {
	if zr.state == nil {
		return 0, io.ErrClosedPipe
	}

	var n int
	for zr.err == nil && (len(buf) > 0 && n == 0) {
		availIn, availOut, ptrIn, ptrOut := sizePtrs(zr.buf, buf)
		ret := C.bzDecStream(zr.state, &availIn, ptrIn, &availOut, ptrOut)
		n += len(buf) - int(availOut)
		buf = buf[len(buf)-int(availOut):]
		zr.buf = zr.buf[len(zr.buf)-int(availIn):]

		switch ret {
		case C.BZ_OK:
			if len(zr.buf) == 0 && n == 0 {
				n1, err := zr.r.Read(zr.arr[:])
				if n1 > 0 {
					zr.buf = zr.arr[:n1]
				} else if err != nil {
					if err == io.EOF {
						err = io.ErrUnexpectedEOF
					}
					zr.err = err
				}
			}
		case C.BZ_STREAM_END:
			// Handle multi-stream files by re-setting the state.
			if len(zr.buf) == 0 {
				if _, err := io.ReadFull(zr.r, zr.arr[:1]); err != nil {
					if err == io.EOF {
						return n, io.EOF
					}
					zr.err = io.ErrUnexpectedEOF
					return n, zr.err
				}
				zr.buf = zr.arr[:1]
			}
			C.bzDecDestroy(zr.state)
			zr.state = C.bzDecCreate()
		default:
			zr.err = errors.New("bzip2: corrupted input")
		}
	}
	return n, zr.err
}

func (zr *Reader) Close() error {
	if zr.state != nil {
		defer func() {
			C.bzDecDestroy(zr.state)
			zr.state = nil
		}()
	}
	return zr.err
}

type Writer struct {
	w     io.Writer
	err   error
	state *C.bz_stream
	buf   []byte
	arr   [1 << 14]byte
}

func NewWriter(w io.Writer, level int) io.WriteCloser {
	if level < 1 || level > 9 {
		panic("bzip2: invalid compression level")
	}

	zw := &Writer{w: w, state: C.bzEncCreate(C.int(level))}
	if zw.state == nil {
		panic("bzip2: could not allocate encoder state")
	}
	return zw
}

func (zw *Writer) Write(buf []byte) (int, error) {
	return zw.write(buf, C.BZ_RUN)
}

func (zw *Writer) write(buf []byte, op C.int) (int, error) {
	if zw.state == nil {
		return 0, io.ErrClosedPipe
	}

	var n int
	flush := op != C.BZ_RUN
	for zw.err == nil && (len(buf) > 0 || flush) {
		availIn, availOut, ptrIn, ptrOut := sizePtrs(buf, zw.arr[:])
		ret := C.bzEncStream(zw.state, op, &availIn, ptrIn, &availOut, ptrOut)
		n += len(buf) - int(availIn)
		buf = buf[len(buf)-int(availIn):]
		zw.buf = zw.arr[:len(zw.arr)-int(availOut)]

		if len(zw.buf) > 0 {
			if _, err := zw.w.Write(zw.buf); err != nil {
				zw.err = err
			}
		}
		switch ret {
		case C.BZ_OK, C.BZ_RUN_OK, C.BZ_FLUSH_OK, C.BZ_FINISH_OK:
			continue // Do nothing
		case C.BZ_STREAM_END:
			return n, zw.err
		default:
			zw.err = errors.New("bzip2: compression error")
		}
	}
	return n, zw.err
}

func (zw *Writer) Close() error {
	if zw.state != nil {
		defer func() {
			C.bzEncDestroy(zw.state)
			zw.state = nil
		}()
		zw.write(nil, C.BZ_FINISH)
	}
	return zw.err
}

func sizePtrs(in, out []byte) (sizeIn, sizeOut C.uint, ptrIn, ptrOut *C.char) {
	sizeIn = C.uint(len(in))
	sizeOut = C.uint(len(out))
	if len(in) > 0 {
		ptrIn = (*C.char)(unsafe.Pointer(&in[0]))
	}
	if len(out) > 0 {
		ptrOut = (*C.char)(unsafe.Pointer(&out[0]))
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/serbe/adb"
	"github.com/serbe/pool"
)

func findProxy() {
	var (
		addedProxy int64
		newList    []adb.Proxy
	)
	debugmsg("Start find proxy")
	p := pool.New(cfg.FindWorkers)
	p.SetTimeout(cfg.Timeout)
	ml := getMapLink()
	mp := newMapProxy()
	list := getProxyListFromDB()
	mp.fillMapProxy(list)
	mp.loadProxyFromFile()

	debugmsg("load links", len(ml.values))
	debugmsg("load proxies", len(mp.values))
	debugmsg("start add to pool")
	p.SetQuitTimeout(2000)
	for _, link := range ml.values {
		if useAddLink || useTestLink || link.Iterate && time.Since(link.UpdateAt) > time.Duration(1)*time.Hour {
			err := p.Add(link.Hostname, nil)
			if err == nil {
				addedProxy++
			}
			chkErr("findProxy p.Add", err)
		}
	}
	if addedProxy == 0 {
		debugmsg("not added tasks to pool")
		return
	}
	debugmsg("end add to pool, added", p.GetAddedTasks(), "links")
	debugmsg("start get from chan")
	for result := range p.ResultChan {
		if result.Error != nil {
			errmsg("result", result.Error)
			continue
		}
		ml.update(result.Hostname)
		links := ml.getNewLinksFromTask(result)
		newProxy := mp.newProxyInTask(result)
		num := int64(len(newProxy))
		if num > 0 {
			debugmsg("find", num, "proxy in", result.Hostname)
			if link, ok := ml.get(result.Hostname); ok {
				link.Num = link.Num + num
				ml.set(link)
			}
			newList = append(newList, newProxy...)
		}
		if !useNoAddLinks {
			for _, l := range links {
				chkErr("findProxy add to pool", p.Add(l.Hostname, nil))
				debugmsg("add to pool", l.Hostname)
			}
		} else {
			debugmsg("find", len(links), "links in", result.Hostname)
		}
		addedProxy = addedProxy + num
	}
	if !useTestLink {
		debugmsg("save proxy")
		ml.saveAll()
	}
	p.Quit()
	debugmsg(addedProxy, "new proxy found")
	debugmsg("end findProxy")
	checkProxy(newList)
}

func checkProxy(list []adb.Proxy) {
	debugmsg("start checkProxy")
	var (
		checked    int64
		totalProxy int64
		anonProxy  int64
	)

	myIP, err := getMyIP()
	if err != nil {
		errmsg("checkProxy getMyIP", err)
		return
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	listLen := len(list)
	debugmsg("load proxies", listLen)

breakCheckProxyLoop:
	for j := 0; j < listLen; {
		mp := newMapProxy()
		var r = 10000
		if j+10000 > listLen {
			r = listLen % 10000
		}
		for i := 0; i < r; i++ {
			mp.set(list[j])
			j++
		}
		p := pool.New(cfg.CheckWorkers)
		defer p.Quit()
		p.SetTimeout(cfg.Timeout)
		debugmsg("start add to pool")
		for _, proxy := range mp.values {
			proxyURL, err := url.Parse(proxy.Hostname)
			chkErr("parse url", err)
			chkErr("add to pool", p.Add(cfg.Target, proxyURL))
		}
		debugmsg("end add to pool")
		// p.EndWaitingTasks()
		p.SetQuitTimeout(cfg.Timeout + 1000)
		if p.GetAddedTasks() == 0 {
			debugmsg("no task added to pool")
			return
		}
	checkProxyLoop:
		for {
			select {
			case task, ok := <-p.ResultChan:
				if !ok {
					debugmsg("break loop by close chan ResultChan")
					break checkProxyLoop
				}
				checked++
				isNew := false
				if useFUP || useCheckScheme {
					isNew = true
				}
				proxy, isOk := mp.taskToProxy(task, isNew, myIP)
				if !isOk {
					continue
				}
				mp.set(proxy)
				if !(useFUP || useCheckScheme) {
					saveProxy(proxy)
				}
				if proxy.IsWork {
					if useFUP || useCheckScheme {
						saveProxy(proxy)
					}
					totalProxy++
					debugmsg(fmt.Sprintf("%d/%d/%d %-15v %-5v %-6v %v",
						totalProxy,
						checked,
						listLen,
						task.Proxy.Hostname(),
						task.Proxy.Port(),
						task.Proxy.Scheme,
						proxy.IsAnon,
					))
					if proxy.IsAnon {
						anonProxy++
					}
				}
			case <-c:
				debugmsg("break loop by pressing ctrl+c")
				break breakCheckProxyLoop
			}
		}
		if listLen > 0 {
			debugmsg(fmt.Sprintf("checked %d from %d", checked, listLen))
		}
	}
	debugmsg(fmt.Sprintf("%d is good", totalProxy))
	debugmsg(fmt.Sprintf("%d is anon", anonProxy))
	debugmsg("end checkProxy")
}
<commit_msg>less lehgth<commit_after>package main

import (
	"fmt"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/serbe/adb"
	"github.com/serbe/pool"
)

func findProxy() {
	var (
		addedProxy int64
		newList    []adb.Proxy
	)
	debugmsg("Start find proxy")
	p := pool.New(cfg.FindWorkers)
	p.SetTimeout(cfg.Timeout)
	ml := getMapLink()
	mp := newMapProxy()
	list := getProxyListFromDB()
	mp.fillMapProxy(list)
	mp.loadProxyFromFile()

	debugmsg("load links", len(ml.values))
	debugmsg("load proxies", len(mp.values))
	debugmsg("start add to pool")
	p.SetQuitTimeout(2000)
	for _, link := range ml.values {
		if useAddLink || useTestLink || link.Iterate && time.Since(link.UpdateAt) > time.Duration(1)*time.Hour {
			err := p.Add(link.Hostname, nil)
			if err == nil {
				addedProxy++
			}
			chkErr("findProxy p.Add", err)
		}
	}
	if addedProxy == 0 {
		debugmsg("not added tasks to pool")
		return
	}
	debugmsg("end add to pool, added", p.GetAddedTasks(), "links")
	debugmsg("start get from chan")
	for result := range p.ResultChan {
		if result.Error != nil {
			errmsg("result", result.Error)
			continue
		}
		ml.update(result.Hostname)
		links := ml.getNewLinksFromTask(result)
		newProxy := mp.newProxyInTask(result)
		num := int64(len(newProxy))
		if num > 0 {
			debugmsg("find", num, "proxy in", result.Hostname)
			if link, ok := ml.get(result.Hostname); ok {
				link.Num = link.Num + num
				ml.set(link)
			}
			newList = append(newList, newProxy...)
		}
		if !useNoAddLinks {
			for _, l := range links {
				chkErr("findProxy add to pool", p.Add(l.Hostname, nil))
				debugmsg("add to pool", l.Hostname)
			}
		} else {
			debugmsg("find", len(links), "links in", result.Hostname)
		}
		addedProxy = addedProxy + num
	}
	if !useTestLink {
		debugmsg("save proxy")
		ml.saveAll()
	}
	p.Quit()
	debugmsg(addedProxy, "new proxy found")
	debugmsg("end findProxy")
	checkProxy(newList)
}

func checkProxy(list []adb.Proxy) {
	debugmsg("start checkProxy")
	var (
		checked    int64
		totalProxy int64
		anonProxy  int64
	)

	myIP, err := getMyIP()
	if err != nil {
		errmsg("checkProxy getMyIP", err)
		return
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	listLen := len(list)
	debugmsg("load proxies", listLen)

breakCheckProxyLoop:
	for j := 0; j < listLen; {
		mp := newMapProxy()
		var r = 2000
		if j+2000 > listLen {
			r = listLen % 2000
		}
		for i := 0; i < r; i++ {
			mp.set(list[j])
			j++
		}
		p := pool.New(cfg.CheckWorkers)
		defer p.Quit()
		p.SetTimeout(cfg.Timeout)
		debugmsg("start add to pool")
		for _, proxy := range mp.values {
			proxyURL, err := url.Parse(proxy.Hostname)
			chkErr("parse url", err)
			chkErr("add to pool", p.Add(cfg.Target, proxyURL))
		}
		debugmsg("end add to pool")
		// p.EndWaitingTasks()
		p.SetQuitTimeout(cfg.Timeout + 1000)
		// if p.GetAddedTasks() == 0 {
		// 	debugmsg("no task added to pool")
		// 	return
		// }
	checkProxyLoop:
		for {
			select {
			case task, ok := <-p.ResultChan:
				if !ok {
					debugmsg("break loop by close chan ResultChan")
					break checkProxyLoop
				}
				checked++
				isNew := false
				if useFUP || useCheckScheme {
					isNew = true
				}
				proxy, isOk := mp.taskToProxy(task, isNew, myIP)
				if !isOk {
					continue
				}
				mp.set(proxy)
				if !(useFUP || useCheckScheme) {
					saveProxy(proxy)
				}
				if proxy.IsWork {
					if useFUP || useCheckScheme {
						saveProxy(proxy)
					}
					totalProxy++
					debugmsg(fmt.Sprintf("%d/%d/%d %-15v %-5v %-6v %v",
						totalProxy,
						checked,
						listLen,
						task.Proxy.Hostname(),
						task.Proxy.Port(),
						task.Proxy.Scheme,
						proxy.IsAnon,
					))
					if proxy.IsAnon {
						anonProxy++
					}
				}
			case <-c:
				debugmsg("break loop by pressing ctrl+c")
				break breakCheckProxyLoop
			}
		}
		if listLen > 0 {
			debugmsg(fmt.Sprintf("checked %d from %d", checked, listLen))
		}
	}
	debugmsg(fmt.Sprintf("%d is good", totalProxy))
	debugmsg(fmt.Sprintf("%d is anon", anonProxy))
	debugmsg("end checkProxy")
}
<|endoftext|>


<commit_before>package copper

import (
	"bufio"
	"errors"
	"io"
	"net"
	"sync"
	"time"
)

const (
	inactivityTimeout = 60 * time.Second
	generatePingAfter = 2 * inactivityTimeout / 3
)

// Returned when stream handler is nil
var ErrInvalidStreamHandler = errors.New("stream handler cannot be nil")

// Returned when target id is not valid or not previously registered
var ErrInvalidTarget = errors.New("target must be greater than 0 and registered")

// Returned when connection is closed with a Close() call
var ErrConnClosed = errors.New("connection closed")

// StreamHandler is used to handle incoming streams
type StreamHandler interface {
	HandleStream(target int64, r io.Reader, w io.Writer)
}

// StreamHandlerFunc wraps a function to conform with StreamHandler interface
type StreamHandlerFunc func(target int64, r io.Reader, w io.Writer)

var _ StreamHandler = StreamHandlerFunc(nil)

// HandleStream calls the underlying function
func (f StreamHandlerFunc) HandleStream(target int64, r io.Reader, w io.Writer) {
	f(target, r, w)
}

// Conn is a multiplexed connection implementing the copper protocol
type Conn interface {
	Close() error
	OpenStream(target int64) (r io.Reader, w io.Writer, err error)
	AddHandler(handler StreamHandler) (target int64, err error)
	RemoveHandler(target int64) error
}

type rawConn struct {
	lock        sync.Mutex
	conn        net.Conn
	closed      bool
	failure     error
	signal      chan struct{}
	pingAcks    []uint64
	pingQueue   []uint64
	pingResults map[uint64][]chan error
	handlers    map[int64]StreamHandler
	nexthandler int64
}

var _ Conn = &rawConn{}

// NewConn wraps the underlying network connection with the copper protocol
func NewConn(conn net.Conn, handler StreamHandler) Conn {
	handlers := map[int64]StreamHandler{
		0: handler,
	}
	c := &rawConn{
		conn:        conn,
		closed:      false,
		signal:      make(chan struct{}, 1),
		pingResults: make(map[uint64][]chan error),
		handlers:    handlers,
		nexthandler: 1,
	}
	go c.readloop()
	go c.writeloop()
	return c
}

func (c *rawConn) wakeupLocked() {
	if !c.closed {
		select {
		case c.signal <- struct{}{}:
		default:
		}
	}
}

func (c *rawConn) closeWithErrorLocked(err error) error {
	if !c.closed {
		c.closed = true
		c.failure = err
		close(c.signal)
		return nil
	}
	return c.failure
}

func (c *rawConn) closeWithError(err error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.closeWithErrorLocked(err)
}

func (c *rawConn) Close() error {
	return c.closeWithError(ErrConnClosed)
}

func (c *rawConn) OpenStream(target int64) (io.Reader, io.Writer, error) {
	// TODO
	return nil, nil, nil
}

func (c *rawConn) AddHandler(handler StreamHandler) (int64, error) {
	if handler == nil {
		return 0, ErrInvalidStreamHandler
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	target := c.nexthandler
	c.nexthandler++
	c.handlers[target] = handler
	return target, nil
}

func (c *rawConn) RemoveHandler(target int64) error {
	if target <= 0 {
		return ErrInvalidTarget
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	if _, ok := c.handlers[target]; !ok {
		return ErrInvalidTarget
	}
	delete(c.handlers, target)
	return nil
}

func (c *rawConn) addPingAck(value uint64) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.pingAcks = append(c.pingAcks, value)
	c.wakeupLocked()
}

func (c *rawConn) takePingResult(value uint64) (result chan error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	results, ok := c.pingResults[value]
	if ok {
		result = results[0]
		if len(results) > 1 {
			resultscopy := make([]chan error, len(results)-1)
			copy(resultscopy, results[1:])
			c.pingResults[value] = resultscopy
		} else {
			delete(c.pingResults, value)
		}
	}
	return
}

func (c *rawConn) addPingRequest(value uint64, result chan error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return c.failure
	}
	c.pingResults[value] = append(c.pingResults[value], result)
	c.pingQueue = append(c.pingQueue, value)
	return nil
}

func (c *rawConn) failAllPings() {
	c.lock.Lock()
	defer c.lock.Unlock()
	pingResults := c.pingResults
	c.pingQueue = nil
	c.pingResults = nil
	for _, results := range pingResults {
		for _, result := range results {
			select {
			case result <- c.failure:
			default:
			}
			close(result)
		}
	}
}

func (c *rawConn) readloop() {
	r := bufio.NewReader(c.conn)
	for {
		rawFrame, err := readFrame(r)
		if err != nil {
			c.closeWithError(err)
			break
		}
		switch frame := rawFrame.(type) {
		case pingFrame:
			if (frame.flags & flagAck) != 0 {
				result := c.takePingResult(frame.value)
				if result != nil {
					select {
					case result <- nil:
					default:
					}
					close(result)
				}
			} else {
				c.addPingAck(frame.value)
			}
		default:
			panic("unhandled frame type")
		}
	}
	c.failAllPings()
}

func (c *rawConn) prepareWriteBatch(timeout bool) (frames []frame, err error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return nil, c.failure
	}
	if timeout && len(c.pingQueue) == 0 {
		// add a syntetic ping request
		value := uint64(time.Now().UnixNano())
		c.pingResults[value] = append([]chan error{nil}, c.pingResults[value]...)
		c.pingQueue = append(c.pingQueue, value)
	}
	if len(c.pingQueue) > 0 {
		for _, value := range c.pingQueue {
			frames = append(frames, pingFrame{
				value: value,
			})
		}
		c.pingQueue = c.pingQueue[:0]
		return
	}
	panic("TODO")
}

func (c *rawConn) writeloop() {
	w := bufio.NewWriter(c.conn)
	t := time.NewTimer(generatePingAfter)
	for {
		timeout := false
		select {
		case <-c.signal:
		case <-t.C:
			timeout = true
		}
		for {
			frames, err := c.prepareWriteBatch(timeout)
			if err != nil {
				// Attempt to notify the other side that we have an error
				// It's ok if any of this fails, the read side will stop
				// when we close the connection.
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				frame := fatalFrame{
					reason:  255, // TODO: implement reason codes
					message: []byte(err.Error()),
				}
				frame.writeFrameTo(w)
				w.Flush()
				c.conn.Close()
				return
			}
			if len(frames) == 0 {
				break
			}
			for _, frame := range frames {
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				err = frame.writeFrameTo(w)
				if err != nil {
					c.closeWithError(err)
					c.conn.Close()
					return
				}
			}
			timeout = false
		}
		if w.Buffered() > 0 {
			c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
			err := w.Flush()
			if err != nil {
				c.closeWithError(err)
				c.conn.Close()
				return
			}
		}
		t.Reset(generatePingAfter)
	}
}
<commit_msg>For activity use empty data frames instead of pings<commit_after>package copper

import (
	"bufio"
	"errors"
	"io"
	"net"
	"sync"
	"time"
)

const (
	inactivityTimeout = 60 * time.Second
	generatePingAfter = 2 * inactivityTimeout / 3
)

// Returned when stream handler is nil
var ErrInvalidStreamHandler = errors.New("stream handler cannot be nil")

// Returned when target id is not valid or not previously registered
var ErrInvalidTarget = errors.New("target must be greater than 0 and registered")

// Returned when connection is closed with a Close() call
var ErrConnClosed = errors.New("connection closed")

// StreamHandler is used to handle incoming streams
type StreamHandler interface {
	HandleStream(target int64, r io.Reader, w io.Writer)
}

// StreamHandlerFunc wraps a function to conform with StreamHandler interface
type StreamHandlerFunc func(target int64, r io.Reader, w io.Writer)

var _ StreamHandler = StreamHandlerFunc(nil)

// HandleStream calls the underlying function
func (f StreamHandlerFunc) HandleStream(target int64, r io.Reader, w io.Writer) {
	f(target, r, w)
}

// Conn is a multiplexed connection implementing the copper protocol
type Conn interface {
	Close() error
	OpenStream(target int64) (r io.Reader, w io.Writer, err error)
	AddHandler(handler StreamHandler) (target int64, err error)
	RemoveHandler(target int64) error
}

type rawConn struct {
	lock        sync.Mutex
	conn        net.Conn
	closed      bool
	failure     error
	signal      chan struct{}
	pingAcks    []uint64
	pingQueue   []uint64
	pingResults map[uint64][]chan error
	handlers    map[int64]StreamHandler
	nexthandler int64
}

var _ Conn = &rawConn{}

// NewConn wraps the underlying network connection with the copper protocol
func NewConn(conn net.Conn, handler StreamHandler) Conn {
	handlers := map[int64]StreamHandler{
		0: handler,
	}
	c := &rawConn{
		conn:        conn,
		closed:      false,
		signal:      make(chan struct{}, 1),
		pingResults: make(map[uint64][]chan error),
		handlers:    handlers,
		nexthandler: 1,
	}
	go c.readloop()
	go c.writeloop()
	return c
}

func (c *rawConn) wakeupLocked() {
	if !c.closed {
		select {
		case c.signal <- struct{}{}:
		default:
		}
	}
}

func (c *rawConn) closeWithErrorLocked(err error) error {
	if !c.closed {
		c.closed = true
		c.failure = err
		close(c.signal)
		return nil
	}
	return c.failure
}

func (c *rawConn) closeWithError(err error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.closeWithErrorLocked(err)
}

func (c *rawConn) Close() error {
	return c.closeWithError(ErrConnClosed)
}

func (c *rawConn) OpenStream(target int64) (io.Reader, io.Writer, error) {
	// TODO
	return nil, nil, nil
}

func (c *rawConn) AddHandler(handler StreamHandler) (int64, error) {
	if handler == nil {
		return 0, ErrInvalidStreamHandler
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	target := c.nexthandler
	c.nexthandler++
	c.handlers[target] = handler
	return target, nil
}

func (c *rawConn) RemoveHandler(target int64) error {
	if target <= 0 {
		return ErrInvalidTarget
	}
	c.lock.Lock()
	defer c.lock.Unlock()
	if _, ok := c.handlers[target]; !ok {
		return ErrInvalidTarget
	}
	delete(c.handlers, target)
	return nil
}

func (c *rawConn) addPingAck(value uint64) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.pingAcks = append(c.pingAcks, value)
	c.wakeupLocked()
}

func (c *rawConn) takePingResult(value uint64) (result chan error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	results, ok := c.pingResults[value]
	if ok {
		result = results[0]
		if len(results) > 1 {
			resultscopy := make([]chan error, len(results)-1)
			copy(resultscopy, results[1:])
			c.pingResults[value] = resultscopy
		} else {
			delete(c.pingResults, value)
		}
	}
	return
}

func (c *rawConn) addPingRequest(value uint64, result chan error) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return c.failure
	}
	c.pingResults[value] = append(c.pingResults[value], result)
	c.pingQueue = append(c.pingQueue, value)
	return nil
}

func (c *rawConn) failAllPings() {
	c.lock.Lock()
	defer c.lock.Unlock()
	pingResults := c.pingResults
	c.pingQueue = nil
	c.pingResults = nil
	for _, results := range pingResults {
		for _, result := range results {
			select {
			case result <- c.failure:
			default:
			}
			close(result)
		}
	}
}

func (c *rawConn) readloop() {
	r := bufio.NewReader(c.conn)
	for {
		rawFrame, err := readFrame(r)
		if err != nil {
			c.closeWithError(err)
			break
		}
		switch frame := rawFrame.(type) {
		case pingFrame:
			if (frame.flags & flagAck) != 0 {
				result := c.takePingResult(frame.value)
				if result != nil {
					select {
					case result <- nil:
					default:
					}
					close(result)
				}
			} else {
				c.addPingAck(frame.value)
			}
		default:
			panic("unhandled frame type")
		}
	}
	c.failAllPings()
}

func (c *rawConn) prepareWriteBatch(datarequired bool) (frames []frame, err error) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.closed {
		return nil, c.failure
	}
	if len(c.pingQueue) > 0 {
		for _, value := range c.pingQueue {
			frames = append(frames, pingFrame{
				value: value,
			})
		}
		c.pingQueue = c.pingQueue[:0]
		return
	}
	if datarequired {
		frames = append(frames, dataFrame{
			streamID: 0,
			data:     nil,
		})
	}
	return
}

func (c *rawConn) writeloop() {
	datarequired := false
	w := bufio.NewWriter(c.conn)
	t := time.NewTimer(generatePingAfter)
	for {
		select {
		case <-c.signal:
		case <-t.C:
			datarequired = true
		}
		for {
			frames, err := c.prepareWriteBatch(datarequired)
			if err != nil {
				// Attempt to notify the other side that we have an error
				// It's ok if any of this fails, the read side will stop
				// when we close the connection.
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				frame := fatalFrame{
					reason:  255, // TODO: implement reason codes
					message: []byte(err.Error()),
				}
				frame.writeFrameTo(w)
				w.Flush()
				c.conn.Close()
				return
			}
			datarequired = false
			if len(frames) == 0 {
				break
			}
			for _, frame := range frames {
				c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
				err = frame.writeFrameTo(w)
				if err != nil {
					c.closeWithError(err)
					c.conn.Close()
					return
				}
			}
		}
		if w.Buffered() > 0 {
			c.conn.SetWriteDeadline(time.Now().Add(inactivityTimeout))
			err := w.Flush()
			if err != nil {
				c.closeWithError(err)
				c.conn.Close()
				return
			}
		}
		t.Reset(generatePingAfter)
	}
}
<|endoftext|>


<commit_before>// Package dnode implements a message processor for communication
// via dnode protocol. See the following URL for details:
// https://github.com/substack/dnode-protocol/blob/master/doc/protocol.markdown
package dnode

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"reflect"
	"strconv"
	"sync/atomic"
)

var l *log.Logger = log.New(ioutil.Discard, "", log.Lshortfile)

// Uncomment following to see log messages.
// var l *log.Logger = log.New(os.Stderr, "", log.Lshortfile)

type Dnode struct {
	// Registered methods are saved in this map.
	handlers map[string]Handler

	// Reference to sent callbacks are saved in this map.
	callbacks map[uint64]SimpleFunc

	// Next callback number.
	// Incremented atomically by registerCallback().
	seq uint64

	// For sending and receiving messages
	transport Transport
}

// Transport is an interface for sending and receiving data on network.
// Each Transport must be unique for each Client.
type Transport interface {
	// Address of the connected client
	RemoteAddr() string

	// Send single message
	Send(msg []byte) error

	// Receive single message
	Receive() ([]byte, error)

	// A place to save/read extra information about the client
	Properties() map[string]interface{}
}

// Objects implementing the Handler interface can be
// registered to serve a particular method in the dnode processor.
type Handler interface {
	ProcessMessage(*Message, Transport)
}

// Message is the JSON object to call a method at the other side.
type Message struct {
	// Method can be an integer or string.
	Method interface{} `json:"method"`

	// Array of arguments
	Arguments *Partial `json:"arguments"`

	// Integer map of callback paths in arguments
	Callbacks map[string]Path `json:"callbacks"`

	// Links are not used for now.
	Links []interface{} `json:"links"`
}

// New returns a pointer to a new Dnode.
func New(transport Transport) *Dnode {
	return &Dnode{
		handlers:  make(map[string]Handler),
		callbacks: make(map[uint64]SimpleFunc),
		transport: transport,
	}
}

// Copy returns a pointer to a new Dnode with the same handlers as d but empty callbacks.
func (d *Dnode) Copy(transport Transport) *Dnode {
	return &Dnode{
		handlers:  d.handlers,
		callbacks: make(map[uint64]SimpleFunc),
		transport: transport,
	}
}

// Handle registers the handler for the given method.
// If a handler already exists for method, Handle panics.
func (d *Dnode) Handle(method string, handler Handler) {
	if method == "" {
		panic("dnode: invalid method " + method)
	}
	if handler == nil {
		panic("dnode: nil handler")
	}
	if _, ok := d.handlers[method]; ok {
		panic("dnode: handler already exists for method")
	}

	d.handlers[method] = handler
}

// HandleFunc registers the handler function for the given method.
func (d *Dnode) HandleFunc(method string, handler func(*Message, Transport)) {
	d.Handle(method, HandlerFunc(handler))
}

type HandlerFunc func(*Message, Transport)

func (f HandlerFunc) ProcessMessage(m *Message, tr Transport) {
	f(m, tr)
}

// HandleSimple registers the handler function for given method.
// The difference from HandleFunc() all dnode message arguments are passed
// directly to the handler.
func (d *Dnode) HandleSimple(method string, handler interface{}) {
	v := reflect.ValueOf(handler)
	if v.Kind() != reflect.Func {
		panic(errors.New("dnode: handler is not a func"))
	}

	d.Handle(method, SimpleFunc(v))
}

type SimpleFunc reflect.Value

func (f SimpleFunc) ProcessMessage(m *Message, tr Transport) {
	// Call the handler with arguments.
	args := []reflect.Value{reflect.ValueOf(m.Arguments)}
	reflect.Value(f).Call(args)
}

// Run processes incoming messages. Blocking.
func (d *Dnode) Run() error {
	for {
		msg, err := d.transport.Receive()
		if err != nil {
			return err
		}

		go d.processMessage(msg)
	}
}

// Call sends the method and arguments to remote.
func (d *Dnode) Call(method string, arguments ...interface{}) (map[string]Path, error) {
	if method == "" {
		panic("Empty method name")
	}

	return d.call(method, arguments...)
}

func (d *Dnode) call(method interface{}, arguments ...interface{}) (map[string]Path, error) {
	l.Printf("Call method: %s arguments: %+v\n", method, arguments)

	var err error
	callbacks := make(map[string]Path)
	defer func() {
		if err != nil {
			d.removeCallbacks(callbacks)
		}
	}()

	d.collectCallbacks(arguments, make(Path, 0), callbacks)

	// Do not encode empty arguments as "null", make it "[]".
	if arguments == nil {
		arguments = make([]interface{}, 0)
	}

	rawArgs, err := json.Marshal(arguments)
	if err != nil {
		l.Printf("Cannot marshal arguments: %s: %#v", err, arguments)
		return nil, err
	}

	msg := Message{
		Method:    method,
		Arguments: &Partial{Raw: rawArgs},
		Callbacks: callbacks,
		Links:     []interface{}{},
	}

	data, err := json.Marshal(msg)
	if err != nil {
		l.Printf("Cannot marshal message: %s: %#v", err, msg)
		return nil, err
	}

	err = d.transport.Send(data)
	if err != nil {
		l.Printf("Cannot send message over transport: %s", err)
		return nil, err
	}

	// We are returning callbacks here so the caller can Cull() after it gets the response.
	return callbacks, nil
}

// Used to remove callbacks after error occurs in call().
func (d *Dnode) removeCallbacks(callbacks map[string]Path) {
	for id, _ := range callbacks {
		delete(d.handlers, id)
	}
}

// RemoveCallback removes the callback with id from handlers.
// Can be used to remove unused callbacks to free memory.
func (d *Dnode) RemoveCallback(id uint64) {
	delete(d.handlers, strconv.FormatUint(id, 10))
}

// collectCallbacks walks over the rawObj and populates callbackMap
// with callbacks. This is a recursive function. The top level call must
// sends arguments as rawObj, an empty path and empty callbackMap parameter.
func (d *Dnode) collectCallbacks(rawObj interface{}, path Path, callbackMap map[string]Path) {
	switch obj := rawObj.(type) {
	// skip nil values
	case nil:
	case []interface{}:
		for i, item := range obj {
			d.collectCallbacks(item, append(path, strconv.Itoa(i)), callbackMap)
		}
	case map[string]interface{}:
		for key, item := range obj {
			d.collectCallbacks(item, append(path, key), callbackMap)
		}
	// Dereference and continue.
	case *[]interface{}:
		if obj != nil {
			d.collectCallbacks(*obj, path, callbackMap)
		}
	// Dereference and continue.
	case *map[string]interface{}:
		if obj != nil {
			d.collectCallbacks(*obj, path, callbackMap)
		}
	default:
		v := reflect.ValueOf(obj)

		switch v.Kind() {
		case reflect.Func:
			d.registerCallback(v, path, callbackMap)
		case reflect.Ptr:
			e := v.Elem()
			if e == reflect.ValueOf(nil) {
				return
			}

			v = reflect.ValueOf(e.Interface())
			d.collectFields(v, path, callbackMap)
		case reflect.Struct:
			d.collectFields(v, path, callbackMap)
		}
	}
}

// collectFields collects callbacks from the exported fields of a struct.
func (d *Dnode) collectFields(v reflect.Value, path Path, callbackMap map[string]Path) {
	for i := 0; i < v.NumField(); i++ {
		f := v.Type().Field(i)
		if f.PkgPath == "" { // exported
			d.collectCallbacks(v.Field(i).Interface(), append(path, f.Name), callbackMap)
		}
	}
}

// registerCallback is called when a function/method is found in arguments array.
func (d *Dnode) registerCallback(callback reflect.Value, path Path, callbackMap map[string]Path) {
	// Make a copy of path because it is reused in caller.
	pathCopy := make(Path, len(path))
	copy(pathCopy, path)

	// Subtract one to start counting from zero.
	// This is not absolutely necessary, just cosmetics.
	next := atomic.AddUint64(&d.seq, 1) - 1

	seq := strconv.FormatUint(next, 10)

	// Add to callback map to be sent to remote.
	callbackMap[seq] = pathCopy

	// Save in client callbacks so we can call it when we receive a call.
	d.callbacks[next] = SimpleFunc(callback)
}

// processMessage processes a single message and call the previously
// added callbacks.
func (d *Dnode) processMessage(data []byte) error {
	l.Printf("processMessage: %s", string(data))

	var (
		err     error
		msg     Message
		handler Handler
	)

	defer func() {
		if err != nil {
			l.Printf("Cannot process message: %s", err)
		}
	}()

	if err = json.Unmarshal(data, &msg); err != nil {
		return err
	}

	if err = d.ParseCallbacks(&msg); err != nil {
		return err
	}

	// Get the handler function. Method may be string or integer.
	l.Printf("Received method: %s", msg.Method)
	switch method := msg.Method.(type) {
	case float64:
		handler = d.callbacks[uint64(method)]
	case string:
		handler = d.handlers[method]
	default:
		return fmt.Errorf("Invalid method: %s", msg.Method)
	}

	// Method is not found.
	if handler == nil {
		return fmt.Errorf("Unknown method: %v", msg.Method)
	}

	handler.ProcessMessage(&msg, d.transport)

	return nil
}

// ParseCallbacks parses the message's "callbacks" field and prepares
// callback functions in "arguments" field.
func (d *Dnode) ParseCallbacks(msg *Message) error {
	// Parse callbacks field and create callback functions.
	l.Printf("Received message callbacks: %#v", msg.Callbacks)

	for methodID, path := range msg.Callbacks {
		l.Printf("MehodID: %s", methodID)

		id, err := strconv.ParseUint(methodID, 10, 64)
		if err != nil {
			return err
		}

		// When the callback is called, we must send the method to the remote.
		f := Function(func(args ...interface{}) error {
			_, err := d.call(id, args...)
			return err
		})

		spec := CallbackSpec{path, f}
		msg.Arguments.CallbackSpecs = append(msg.Arguments.CallbackSpecs, spec)
	}

	return nil
}
<commit_msg>kite: set error to print log message<commit_after>// Package dnode implements a message processor for communication
// via dnode protocol. See the following URL for details:
// https://github.com/substack/dnode-protocol/blob/master/doc/protocol.markdown
package dnode

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"reflect"
	"strconv"
	"sync/atomic"
)

var l *log.Logger = log.New(ioutil.Discard, "", log.Lshortfile)

// Uncomment following to see log messages.
// var l *log.Logger = log.New(os.Stderr, "", log.Lshortfile)

type Dnode struct {
	// Registered methods are saved in this map.
	handlers map[string]Handler

	// Reference to sent callbacks are saved in this map.
	callbacks map[uint64]SimpleFunc

	// Next callback number.
	// Incremented atomically by registerCallback().
	seq uint64

	// For sending and receiving messages
	transport Transport
}

// Transport is an interface for sending and receiving data on network.
// Each Transport must be unique for each Client.
type Transport interface {
	// Address of the connected client
	RemoteAddr() string

	// Send single message
	Send(msg []byte) error

	// Receive single message
	Receive() ([]byte, error)

	// A place to save/read extra information about the client
	Properties() map[string]interface{}
}

// Objects implementing the Handler interface can be
// registered to serve a particular method in the dnode processor.
type Handler interface {
	ProcessMessage(*Message, Transport)
}

// Message is the JSON object to call a method at the other side.
type Message struct {
	// Method can be an integer or string.
	Method interface{} `json:"method"`

	// Array of arguments
	Arguments *Partial `json:"arguments"`

	// Integer map of callback paths in arguments
	Callbacks map[string]Path `json:"callbacks"`

	// Links are not used for now.
	Links []interface{} `json:"links"`
}

// New returns a pointer to a new Dnode.
func New(transport Transport) *Dnode {
	return &Dnode{
		handlers:  make(map[string]Handler),
		callbacks: make(map[uint64]SimpleFunc),
		transport: transport,
	}
}

// Copy returns a pointer to a new Dnode with the same handlers as d but empty callbacks.
func (d *Dnode) Copy(transport Transport) *Dnode {
	return &Dnode{
		handlers:  d.handlers,
		callbacks: make(map[uint64]SimpleFunc),
		transport: transport,
	}
}

// Handle registers the handler for the given method.
// If a handler already exists for method, Handle panics.
func (d *Dnode) Handle(method string, handler Handler) {
	if method == "" {
		panic("dnode: invalid method " + method)
	}
	if handler == nil {
		panic("dnode: nil handler")
	}
	if _, ok := d.handlers[method]; ok {
		panic("dnode: handler already exists for method")
	}

	d.handlers[method] = handler
}

// HandleFunc registers the handler function for the given method.
func (d *Dnode) HandleFunc(method string, handler func(*Message, Transport)) {
	d.Handle(method, HandlerFunc(handler))
}

type HandlerFunc func(*Message, Transport)

func (f HandlerFunc) ProcessMessage(m *Message, tr Transport) {
	f(m, tr)
}

// HandleSimple registers the handler function for given method.
// The difference from HandleFunc() all dnode message arguments are passed
// directly to the handler.
func (d *Dnode) HandleSimple(method string, handler interface{}) {
	v := reflect.ValueOf(handler)
	if v.Kind() != reflect.Func {
		panic(errors.New("dnode: handler is not a func"))
	}

	d.Handle(method, SimpleFunc(v))
}

type SimpleFunc reflect.Value

func (f SimpleFunc) ProcessMessage(m *Message, tr Transport) {
	// Call the handler with arguments.
	args := []reflect.Value{reflect.ValueOf(m.Arguments)}
	reflect.Value(f).Call(args)
}

// Run processes incoming messages. Blocking.
func (d *Dnode) Run() error {
	for {
		msg, err := d.transport.Receive()
		if err != nil {
			return err
		}

		go d.processMessage(msg)
	}
}

// Call sends the method and arguments to remote.
func (d *Dnode) Call(method string, arguments ...interface{}) (map[string]Path, error) {
	if method == "" {
		panic("Empty method name")
	}

	return d.call(method, arguments...)
}

func (d *Dnode) call(method interface{}, arguments ...interface{}) (map[string]Path, error) {
	l.Printf("Call method: %s arguments: %+v\n", method, arguments)

	var err error
	callbacks := make(map[string]Path)
	defer func() {
		if err != nil {
			d.removeCallbacks(callbacks)
		}
	}()

	d.collectCallbacks(arguments, make(Path, 0), callbacks)

	// Do not encode empty arguments as "null", make it "[]".
	if arguments == nil {
		arguments = make([]interface{}, 0)
	}

	rawArgs, err := json.Marshal(arguments)
	if err != nil {
		l.Printf("Cannot marshal arguments: %s: %#v", err, arguments)
		return nil, err
	}

	msg := Message{
		Method:    method,
		Arguments: &Partial{Raw: rawArgs},
		Callbacks: callbacks,
		Links:     []interface{}{},
	}

	data, err := json.Marshal(msg)
	if err != nil {
		l.Printf("Cannot marshal message: %s: %#v", err, msg)
		return nil, err
	}

	err = d.transport.Send(data)
	if err != nil {
		l.Printf("Cannot send message over transport: %s", err)
		return nil, err
	}

	// We are returning callbacks here so the caller can Cull() after it gets the response.
	return callbacks, nil
}

// Used to remove callbacks after error occurs in call().
func (d *Dnode) removeCallbacks(callbacks map[string]Path) {
	for id, _ := range callbacks {
		delete(d.handlers, id)
	}
}

// RemoveCallback removes the callback with id from handlers.
// Can be used to remove unused callbacks to free memory.
func (d *Dnode) RemoveCallback(id uint64) {
	delete(d.handlers, strconv.FormatUint(id, 10))
}

// collectCallbacks walks over the rawObj and populates callbackMap
// with callbacks. This is a recursive function. The top level call must
// sends arguments as rawObj, an empty path and empty callbackMap parameter.
func (d *Dnode) collectCallbacks(rawObj interface{}, path Path, callbackMap map[string]Path) {
	switch obj := rawObj.(type) {
	// skip nil values
	case nil:
	case []interface{}:
		for i, item := range obj {
			d.collectCallbacks(item, append(path, strconv.Itoa(i)), callbackMap)
		}
	case map[string]interface{}:
		for key, item := range obj {
			d.collectCallbacks(item, append(path, key), callbackMap)
		}
	// Dereference and continue.
	case *[]interface{}:
		if obj != nil {
			d.collectCallbacks(*obj, path, callbackMap)
		}
	// Dereference and continue.
	case *map[string]interface{}:
		if obj != nil {
			d.collectCallbacks(*obj, path, callbackMap)
		}
	default:
		v := reflect.ValueOf(obj)

		switch v.Kind() {
		case reflect.Func:
			d.registerCallback(v, path, callbackMap)
		case reflect.Ptr:
			e := v.Elem()
			if e == reflect.ValueOf(nil) {
				return
			}

			v = reflect.ValueOf(e.Interface())
			d.collectFields(v, path, callbackMap)
		case reflect.Struct:
			d.collectFields(v, path, callbackMap)
		}
	}
}

// collectFields collects callbacks from the exported fields of a struct.
func (d *Dnode) collectFields(v reflect.Value, path Path, callbackMap map[string]Path) {
	for i := 0; i < v.NumField(); i++ {
		f := v.Type().Field(i)
		if f.PkgPath == "" { // exported
			d.collectCallbacks(v.Field(i).Interface(), append(path, f.Name), callbackMap)
		}
	}
}

// registerCallback is called when a function/method is found in arguments array.
func (d *Dnode) registerCallback(callback reflect.Value, path Path, callbackMap map[string]Path) {
	// Make a copy of path because it is reused in caller.
	pathCopy := make(Path, len(path))
	copy(pathCopy, path)

	// Subtract one to start counting from zero.
	// This is not absolutely necessary, just cosmetics.
	next := atomic.AddUint64(&d.seq, 1) - 1

	seq := strconv.FormatUint(next, 10)

	// Add to callback map to be sent to remote.
	callbackMap[seq] = pathCopy

	// Save in client callbacks so we can call it when we receive a call.
	d.callbacks[next] = SimpleFunc(callback)
}

// processMessage processes a single message and call the previously
// added callbacks.
func (d *Dnode) processMessage(data []byte) error {
	l.Printf("processMessage: %s", string(data))

	var (
		err     error
		msg     Message
		handler Handler
	)

	defer func() {
		if err != nil {
			l.Printf("Cannot process message: %s", err)
		}
	}()

	if err = json.Unmarshal(data, &msg); err != nil {
		return err
	}

	if err = d.ParseCallbacks(&msg); err != nil {
		return err
	}

	// Get the handler function. Method may be string or integer.
	l.Printf("Received method: %s", msg.Method)
	switch method := msg.Method.(type) {
	case float64:
		handler = d.callbacks[uint64(method)]
	case string:
		handler = d.handlers[method]
	default:
		err = fmt.Errorf("Invalid method: %s", msg.Method)
		return
	}

	// Method is not found.
	if handler == nil {
		err = fmt.Errorf("Unknown method: %v", msg.Method)
		return
	}

	handler.ProcessMessage(&msg, d.transport)

	return nil
}

// ParseCallbacks parses the message's "callbacks" field and prepares
// callback functions in "arguments" field.
func (d *Dnode) ParseCallbacks(msg *Message) error {
	// Parse callbacks field and create callback functions.
	l.Printf("Received message callbacks: %#v", msg.Callbacks)

	for methodID, path := range msg.Callbacks {
		l.Printf("MehodID: %s", methodID)

		id, err := strconv.ParseUint(methodID, 10, 64)
		if err != nil {
			return err
		}

		// When the callback is called, we must send the method to the remote.
		f := Function(func(args ...interface{}) error {
			_, err := d.call(id, args...)
			return err
		})

		spec := CallbackSpec{path, f}
		msg.Arguments.CallbackSpecs = append(msg.Arguments.CallbackSpecs, spec)
	}

	return nil
}
<|endoftext|>