<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package api

// facadeVersions lists the best version of facades that we know about. This
// will be used to pick out a default version for communication, given the list
// of known versions that the API server tells us it is capable of supporting.
// This map should be updated whenever the API server exposes a new version (so
// that the client will use it whenever it is available).
// New facades should start at 1.
// Facades that existed before versioning start at 0.
var facadeVersions = map[string]int{
	"Action":                       0,
	"Addresser":                    1,
	"Agent":                        1,
	"AllWatcher":                   0,
	"Annotations":                  1,
	"Backups":                      0,
	"Block":                        1,
	"Charms":                       1,
	"CharmRevisionUpdater":         0,
	"Client":                       0,
	"Cleaner":                      1,
	"Deployer":                     0,
	"DiskManager":                  1,
	"EntityWatcher":                1,
	"Environment":                  0,
	"EnvironmentManager":           1,
	"FilesystemAttachmentsWatcher": 1,
	"Firewaller":                   1,
	"HighAvailability":             1,
	"ImageManager":                 1,
	"InstancePoller":               1,
	"KeyManager":                   0,
	"KeyUpdater":                   0,
	"LeadershipService":            1,
	"Logger":                       0,
	"MachineManager":               1,
	"Machiner":                     0,
	"MetricsManager":               0,
	"Networker":                    0,
	"NotifyWatcher":                0,
	"Pinger":                       0,
	"Provisioner":                  1,
	"Reboot":                       1,
	"RelationUnitsWatcher":         0,
	"Resumer":                      1,
	"Rsyslog":                      0,
	"Service":                      1,
	"Storage":                      1,
	"StorageProvisioner":           1,
	"StringsWatcher":               0,
	"SystemManager":                1,
	"Upgrader":                     0,
	"Uniter":                       2,
	"UserManager":                  0,
	"VolumeAttachmentsWatcher":     1,
}

// bestVersion tries to find the newest version in the version list that we can
// use.
func bestVersion(desiredVersion int, versions []int) int {
	best := 0
	for _, version := range versions {
		if version <= desiredVersion && version > best {
			best = version
		}
	}
	return best
}
<commit_msg>api: add AllEnvWatcher to facadeVersions<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package api

// facadeVersions lists the best version of facades that we know about. This
// will be used to pick out a default version for communication, given the list
// of known versions that the API server tells us it is capable of supporting.
// This map should be updated whenever the API server exposes a new version (so
// that the client will use it whenever it is available).
// New facades should start at 1.
// Facades that existed before versioning start at 0.
var facadeVersions = map[string]int{
	"Action":                       0,
	"Addresser":                    1,
	"Agent":                        1,
	"AllWatcher":                   0,
	"AllEnvWatcher":                1,
	"Annotations":                  1,
	"Backups":                      0,
	"Block":                        1,
	"Charms":                       1,
	"CharmRevisionUpdater":         0,
	"Client":                       0,
	"Cleaner":                      1,
	"Deployer":                     0,
	"DiskManager":                  1,
	"EntityWatcher":                1,
	"Environment":                  0,
	"EnvironmentManager":           1,
	"FilesystemAttachmentsWatcher": 1,
	"Firewaller":                   1,
	"HighAvailability":             1,
	"ImageManager":                 1,
	"InstancePoller":               1,
	"KeyManager":                   0,
	"KeyUpdater":                   0,
	"LeadershipService":            1,
	"Logger":                       0,
	"MachineManager":               1,
	"Machiner":                     0,
	"MetricsManager":               0,
	"Networker":                    0,
	"NotifyWatcher":                0,
	"Pinger":                       0,
	"Provisioner":                  1,
	"Reboot":                       1,
	"RelationUnitsWatcher":         0,
	"Resumer":                      1,
	"Rsyslog":                      0,
	"Service":                      1,
	"Storage":                      1,
	"StorageProvisioner":           1,
	"StringsWatcher":               0,
	"SystemManager":                1,
	"Upgrader":                     0,
	"Uniter":                       2,
	"UserManager":                  0,
	"VolumeAttachmentsWatcher":     1,
}

// bestVersion tries to find the newest version in the version list that we can
// use.
func bestVersion(desiredVersion int, versions []int) int {
	best := 0
	for _, version := range versions {
		if version <= desiredVersion && version > best {
			best = version
		}
	}
	return best
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"strings"
	"time"

	"github.com/kelseyhightower/envconfig"

	"nimona.io/internal/version"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/hyperspace/resolver"
	"nimona.io/pkg/localpeer"
	"nimona.io/pkg/log"
	"nimona.io/pkg/network"
	"nimona.io/pkg/object"
	"nimona.io/pkg/objectmanager"
	"nimona.io/pkg/objectstore"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/sqlobjectstore"
	"nimona.io/pkg/stream"
)

func init() {
	go func() {
		http.ListenAndServe("localhost:6060", nil)
	}()
}

// nolint: lll
type config struct {
	Peer struct {
		PrivateKey  crypto.PrivateKey `envconfig:"PRIVATE_KEY"`
		BindAddress string            `envconfig:"BIND_ADDRESS" default:"0.0.0.0:0"`
		Bootstraps  []peer.Shorthand  `envconfig:"BOOTSTRAPS"`
	} `envconfig:"PEER"`
	Chat struct {
		Nonce string `envconfig:"NONCE"`
	} `envconfig:"CHAT"`
}

type chat struct {
	local         localpeer.LocalPeer
	objectmanager objectmanager.ObjectManager
	objectstore   objectstore.Store
	resolver      resolver.Resolver
	logger        log.Logger
}

func (c *chat) subscribe(
	conversationRootHash object.Hash,
) (chan interface{}, error) {
	objects := make(chan *object.Object)
	events := make(chan interface{})

	// handle objects from subscriptions or store
	go func() {
		typeConversationMessageAdded := new(ConversationMessageAdded).Type()
		for o := range objects {
			switch o.Type {
			case typeConversationMessageAdded:
				v := &ConversationMessageAdded{}
				v.FromObject(o)
				if v.Body == "" || v.Datetime == "" {
					fmt.Println("> Received message without date of body")
					continue
				}
				if v.Metadata.Owner.IsEmpty() {
					fmt.Println("> Received unsigned message")
					continue
				}
				events <- v
			}
		}
	}()

	// get objects from db first
	or, err := c.objectstore.GetByStream(conversationRootHash)
	if err != nil {
		return nil, err
	}

	go func() {
		for {
			o, err := or.Read()
			if err != nil {
				break
			}
			objects <- o
		}
		// subscribe to conversation updates
		sub := c.objectmanager.Subscribe(
			objectmanager.FilterByStreamHash(conversationRootHash),
		)
		for {
			o, err := sub.Next()
			if err != nil {
				break
			}
			objects <- o
		}
	}()

	// create subscription for stream
	go func() {
		// add a subscription to the stream if one doesn't already exist
		or, err := c.objectstore.GetByStream(conversationRootHash)
		if err != nil {
			c.logger.Fatal("error checking for subscription", log.Error(err))
		}
		alreadySubscribed := false
		for {
			o, err := or.Read()
			if err != nil {
				break
			}
			if o.Type == new(stream.Subscription).Type() {
				s := &stream.Subscription{}
				if err := s.FromObject(o); err != nil {
					continue
				}
				if s.Metadata.Owner == c.local.GetPrimaryPeerKey().PublicKey() {
					alreadySubscribed = true
					or.Close()
					break
				}
			}
		}
		if !alreadySubscribed {
			ctx := context.New(context.WithTimeout(time.Second * 5))
			if _, err := c.objectmanager.Put(ctx, stream.Subscription{
				Metadata: object.Metadata{
					Owner:  c.local.GetPrimaryPeerKey().PublicKey(),
					Stream: conversationRootHash,
				},
				RootHashes: []object.Hash{
					conversationRootHash,
				},
			}.ToObject()); err != nil {
				c.logger.Fatal("could not persist conversation sub", log.Error(err))
			}
		}

		// sync conversation
		queryCtx := context.New(context.WithTimeout(time.Second * 5))
		peers, err := c.resolver.Lookup(
			queryCtx,
			resolver.LookupByContentHash(conversationRootHash),
		)
		if err != nil {
			c.logger.Error("could not find any peers that have this hash")
			return
		}
		for _, p := range peers {
			reqCtx := context.New(context.WithTimeout(time.Second * 5))
			cr, err := c.objectmanager.RequestStream(
				reqCtx,
				conversationRootHash,
				p,
			)
			if err != nil {
				c.logger.Warn(
					"could not ask peer for stream",
					log.String("peer", p.PublicKey.String()),
				)
				continue
			}
			for {
				o, err := cr.Read()
				if err != nil {
					break
				}
				c.objectmanager.Put(
					context.New(),
					o,
				)
			}
			cr.Close()
		}
	}()
	return events, nil
}

func main() {
	ctx := context.New(
		context.WithCorrelationID("nimona"),
	)

	logger := log.FromContext(ctx).With(
		log.String("build.version", version.Version),
		log.String("build.commit", version.Commit),
		log.String("build.timestamp", version.Date),
	)

	cfg := &config{}
	if err := envconfig.Process("nimona", cfg); err != nil {
		logger.Fatal("error processing config", log.Error(err))
	}

	if cfg.Peer.PrivateKey.IsEmpty() {
		k, err := crypto.GenerateEd25519PrivateKey()
		if err != nil {
			logger.Fatal("missing peer key and unable to generate one")
		}
		cfg.Peer.PrivateKey = k
	}

	// construct local peer
	local := localpeer.New()
	// attach peer private key from config
	local.PutPrimaryPeerKey(cfg.Peer.PrivateKey)

	// construct new network
	net := network.New(
		ctx,
		network.WithLocalPeer(local),
	)

	if cfg.Peer.BindAddress != "" {
		// start listening
		lis, err := net.Listen(
			ctx,
			cfg.Peer.BindAddress,
			network.ListenOnLocalIPs,
			network.ListenOnExternalPort,
		)
		if err != nil {
			logger.Fatal("error while listening", log.Error(err))
		}
		defer lis.Close() // nolint: errcheck
	}

	// make sure we have some bootstrap peers to start with
	if len(cfg.Peer.Bootstraps) == 0 {
		cfg.Peer.Bootstraps = []peer.Shorthand{
			"ed25519.CJi6yjjXuNBFDoYYPrp697d6RmpXeW8ZUZPmEce9AgEc@tcps:asimov.bootstrap.nimona.io:22581",
			"ed25519.6fVWVAK2DVGxBhtVBvzNWNKBWk9S83aQrAqGJfrxr75o@tcps:egan.bootstrap.nimona.io:22581",
			"ed25519.7q7YpmPNQmvSCEBWW8ENw8XV8MHzETLostJTYKeaRTcL@tcps:sloan.bootstrap.nimona.io:22581",
		}
	}

	// convert shorthands into connection infos
	bootstrapPeers := []*peer.ConnectionInfo{}
	for _, s := range cfg.Peer.Bootstraps {
		bootstrapPeer, err := s.ConnectionInfo()
		if err != nil {
			logger.Fatal("error parsing bootstrap peer", log.Error(err))
		}
		bootstrapPeers = append(bootstrapPeers, bootstrapPeer)
	}

	// add bootstrap peers as relays
	local.PutRelays(bootstrapPeers...)

	// construct new resolver
	res := resolver.New(
		ctx,
		net,
		resolver.WithBoostrapPeers(bootstrapPeers...),
	)

	logger = logger.With(
		log.String("peer.publicKey", local.GetPrimaryPeerKey().PublicKey().String()),
		log.Strings("peer.addresses", local.GetAddresses()),
	)

	logger.Info("ready")

	// construct object store
	db, err := sql.Open("sqlite3", "chat.db")
	if err != nil {
		logger.Fatal("error opening sql file", log.Error(err))
	}

	str, err := sqlobjectstore.New(db)
	if err != nil {
		logger.Fatal("error starting sql store", log.Error(err))
	}

	// construct manager
	man := objectmanager.New(
		ctx,
		net,
		res,
		str,
	)

	// if no noce is specified use a default
	if cfg.Chat.Nonce == "" {
		cfg.Chat.Nonce = "hello-world!!1"
	}

	// construct hypothetical root in order to get a root hash
	conversationRoot := ConversationStreamRoot{
		Nonce: cfg.Chat.Nonce,
	}

	// register types so object manager persists them
	local.PutContentTypes(
		new(ConversationStreamRoot).Type(),
		new(ConversationMessageAdded).Type(),
		new(stream.Subscription).Type(),
	)

	conversationRootObject := conversationRoot.ToObject()
	conversationRootHash := conversationRootObject.Hash()

	// register conversation in object manager
	if _, err := man.Put(ctx, conversationRootObject); err != nil {
		logger.Fatal("could not persist conversation root", log.Error(err))
	}

	c := &chat{
		local:         local,
		objectmanager: man,
		objectstore:   str,
		resolver:      res,
		logger:        logger,
	}

	events, err := c.subscribe(conversationRootHash)
	if err != nil {
		logger.Fatal("error subscribing to conversation", log.Error(err))
	}

	app := NewApp(conversationRootHash.String())
	app.Chat = c
	go app.Show()

	go func() {
		for input := range app.Channels.InputLines {
			if _, err := man.Put(
				context.New(
					context.WithTimeout(time.Second*5),
				),
				ConversationMessageAdded{
					Metadata: object.Metadata{
						Owner:  local.GetPrimaryPeerKey().PublicKey(),
						Stream: conversationRootHash,
					},
					Body:     input,
					Datetime: time.Now().Format(time.RFC3339Nano),
				}.ToObject(),
			); err != nil {
				logger.Warn(
					"error putting message",
					log.Error(err),
				)
			}
		}
	}()

	for event := range events {
		switch v := event.(type) {
		case *ConversationMessageAdded:
			t, err := time.Parse(time.RFC3339Nano, v.Datetime)
			if err != nil {
				continue
			}
			usr := last(v.Metadata.Owner.String(), 8)
			app.Channels.MessageAdded <- &Message{
				Hash:             v.ToObject().Hash().String(),
				ConversationHash: v.Metadata.Stream.String(),
				SenderHash:       v.Metadata.Owner.String(),
				SenderNickname:   usr,
				Body:             strings.TrimSpace(v.Body),
				Created:          t,
			}
		}
	}
}

func last(t string, i int) string {
	if len(t) <= i {
		return t
	}
	return t[len(t)-i:]
}
<commit_msg>chore(examples/chat): put conversation hash to local peer<commit_after>package main

import (
	"database/sql"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"strings"
	"time"

	"github.com/kelseyhightower/envconfig"

	"nimona.io/internal/version"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/hyperspace/resolver"
	"nimona.io/pkg/localpeer"
	"nimona.io/pkg/log"
	"nimona.io/pkg/network"
	"nimona.io/pkg/object"
	"nimona.io/pkg/objectmanager"
	"nimona.io/pkg/objectstore"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/sqlobjectstore"
	"nimona.io/pkg/stream"
)

func init() {
	go func() {
		http.ListenAndServe("localhost:6060", nil)
	}()
}

var (
	typeConversationMessageAdded = new(ConversationMessageAdded).Type()
)

// nolint: lll
type config struct {
	Peer struct {
		PrivateKey  crypto.PrivateKey `envconfig:"PRIVATE_KEY"`
		BindAddress string            `envconfig:"BIND_ADDRESS" default:"0.0.0.0:0"`
		Bootstraps  []peer.Shorthand  `envconfig:"BOOTSTRAPS"`
	} `envconfig:"PEER"`
	Chat struct {
		Nonce string `envconfig:"NONCE"`
	} `envconfig:"CHAT"`
}

type chat struct {
	local         localpeer.LocalPeer
	objectmanager objectmanager.ObjectManager
	objectstore   objectstore.Store
	resolver      resolver.Resolver
	logger        log.Logger
}

func (c *chat) subscribe(
	conversationRootHash object.Hash,
) (chan interface{}, error) {
	objects := make(chan *object.Object)
	events := make(chan interface{})

	// handle objects from subscriptions or store
	go func() {
		for o := range objects {
			switch o.Type {
			case typeConversationMessageAdded:
				v := &ConversationMessageAdded{}
				v.FromObject(o)
				if v.Body == "" || v.Datetime == "" {
					fmt.Println("> Received message without date of body")
					continue
				}
				if v.Metadata.Owner.IsEmpty() {
					fmt.Println("> Received unsigned message")
					continue
				}
				events <- v
			}
		}
	}()

	// get objects from db first
	or, err := c.objectstore.GetByStream(conversationRootHash)
	if err != nil {
		return nil, err
	}

	go func() {
		for {
			o, err := or.Read()
			if err != nil {
				break
			}
			objects <- o
		}
		// subscribe to conversation updates
		sub := c.objectmanager.Subscribe(
			objectmanager.FilterByStreamHash(conversationRootHash),
		)
		for {
			o, err := sub.Next()
			if err != nil {
				break
			}
			objects <- o
		}
	}()

	// create subscription for stream
	go func() {
		// add a subscription to the stream if one doesn't already exist
		or, err := c.objectstore.GetByStream(conversationRootHash)
		if err != nil {
			c.logger.Fatal("error checking for subscription", log.Error(err))
		}
		alreadySubscribed := false
		for {
			o, err := or.Read()
			if err != nil {
				break
			}
			if o.Type == new(stream.Subscription).Type() {
				s := &stream.Subscription{}
				if err := s.FromObject(o); err != nil {
					continue
				}
				if s.Metadata.Owner == c.local.GetPrimaryPeerKey().PublicKey() {
					alreadySubscribed = true
					or.Close()
					break
				}
			}
		}
		if !alreadySubscribed {
			ctx := context.New(context.WithTimeout(time.Second * 5))
			if _, err := c.objectmanager.Put(ctx, stream.Subscription{
				Metadata: object.Metadata{
					Owner:  c.local.GetPrimaryPeerKey().PublicKey(),
					Stream: conversationRootHash,
				},
				RootHashes: []object.Hash{
					conversationRootHash,
				},
			}.ToObject()); err != nil {
				c.logger.Fatal("could not persist conversation sub", log.Error(err))
			}
		}

		// sync conversation
		queryCtx := context.New(context.WithTimeout(time.Second * 5))
		peers, err := c.resolver.Lookup(
			queryCtx,
			resolver.LookupByContentHash(conversationRootHash),
		)
		if err != nil {
			c.logger.Error("could not find any peers that have this hash")
			return
		}
		for _, p := range peers {
			reqCtx := context.New(context.WithTimeout(time.Second * 5))
			cr, err := c.objectmanager.RequestStream(
				reqCtx,
				conversationRootHash,
				p,
			)
			if err != nil {
				c.logger.Warn(
					"could not ask peer for stream",
					log.String("peer", p.PublicKey.String()),
				)
				continue
			}
			for {
				o, err := cr.Read()
				if err != nil {
					break
				}
				c.objectmanager.Put(
					context.New(),
					o,
				)
			}
			cr.Close()
		}
	}()
	return events, nil
}

func main() {
	ctx := context.New(
		context.WithCorrelationID("nimona"),
	)

	logger := log.FromContext(ctx).With(
		log.String("build.version", version.Version),
		log.String("build.commit", version.Commit),
		log.String("build.timestamp", version.Date),
	)

	cfg := &config{}
	if err := envconfig.Process("nimona", cfg); err != nil {
		logger.Fatal("error processing config", log.Error(err))
	}

	if cfg.Peer.PrivateKey.IsEmpty() {
		k, err := crypto.GenerateEd25519PrivateKey()
		if err != nil {
			logger.Fatal("missing peer key and unable to generate one")
		}
		cfg.Peer.PrivateKey = k
	}

	// construct local peer
	local := localpeer.New()
	// attach peer private key from config
	local.PutPrimaryPeerKey(cfg.Peer.PrivateKey)

	// construct new network
	net := network.New(
		ctx,
		network.WithLocalPeer(local),
	)

	if cfg.Peer.BindAddress != "" {
		// start listening
		lis, err := net.Listen(
			ctx,
			cfg.Peer.BindAddress,
			network.ListenOnLocalIPs,
			network.ListenOnExternalPort,
		)
		if err != nil {
			logger.Fatal("error while listening", log.Error(err))
		}
		defer lis.Close() // nolint: errcheck
	}

	// make sure we have some bootstrap peers to start with
	if len(cfg.Peer.Bootstraps) == 0 {
		cfg.Peer.Bootstraps = []peer.Shorthand{
			"ed25519.CJi6yjjXuNBFDoYYPrp697d6RmpXeW8ZUZPmEce9AgEc@tcps:asimov.bootstrap.nimona.io:22581",
			"ed25519.6fVWVAK2DVGxBhtVBvzNWNKBWk9S83aQrAqGJfrxr75o@tcps:egan.bootstrap.nimona.io:22581",
			"ed25519.7q7YpmPNQmvSCEBWW8ENw8XV8MHzETLostJTYKeaRTcL@tcps:sloan.bootstrap.nimona.io:22581",
		}
	}

	// convert shorthands into connection infos
	bootstrapPeers := []*peer.ConnectionInfo{}
	for _, s := range cfg.Peer.Bootstraps {
		bootstrapPeer, err := s.ConnectionInfo()
		if err != nil {
			logger.Fatal("error parsing bootstrap peer", log.Error(err))
		}
		bootstrapPeers = append(bootstrapPeers, bootstrapPeer)
	}

	// add bootstrap peers as relays
	local.PutRelays(bootstrapPeers...)

	// construct new resolver
	res := resolver.New(
		ctx,
		net,
		resolver.WithBoostrapPeers(bootstrapPeers...),
	)

	logger = logger.With(
		log.String("peer.publicKey", local.GetPrimaryPeerKey().PublicKey().String()),
		log.Strings("peer.addresses", local.GetAddresses()),
	)

	logger.Info("ready")

	// construct object store
	db, err := sql.Open("sqlite3", "chat.db")
	if err != nil {
		logger.Fatal("error opening sql file", log.Error(err))
	}

	str, err := sqlobjectstore.New(db)
	if err != nil {
		logger.Fatal("error starting sql store", log.Error(err))
	}

	// construct manager
	man := objectmanager.New(
		ctx,
		net,
		res,
		str,
	)

	// if no noce is specified use a default
	if cfg.Chat.Nonce == "" {
		cfg.Chat.Nonce = "hello-world!!1"
	}

	// construct hypothetical root in order to get a root hash
	conversationRoot := ConversationStreamRoot{
		Nonce: cfg.Chat.Nonce,
	}

	// register types so object manager persists them
	local.PutContentTypes(
		new(ConversationStreamRoot).Type(),
		new(ConversationMessageAdded).Type(),
		new(stream.Subscription).Type(),
	)

	conversationRootObject := conversationRoot.ToObject()
	conversationRootHash := conversationRootObject.Hash()

	// register conversation in object manager
	if _, err := man.Put(ctx, conversationRootObject); err != nil {
		logger.Fatal("could not persist conversation root", log.Error(err))
	}

	// add conversation to the list of content we provide
	local.PutContentHashes(conversationRootHash)

	c := &chat{
		local:         local,
		objectmanager: man,
		objectstore:   str,
		resolver:      res,
		logger:        logger,
	}

	events, err := c.subscribe(conversationRootHash)
	if err != nil {
		logger.Fatal("error subscribing to conversation", log.Error(err))
	}

	app := NewApp(conversationRootHash.String())
	app.Chat = c
	go app.Show()

	go func() {
		for input := range app.Channels.InputLines {
			if _, err := man.Put(
				context.New(
					context.WithTimeout(time.Second*5),
				),
				ConversationMessageAdded{
					Metadata: object.Metadata{
						Owner:  local.GetPrimaryPeerKey().PublicKey(),
						Stream: conversationRootHash,
					},
					Body:     input,
					Datetime: time.Now().Format(time.RFC3339Nano),
				}.ToObject(),
			); err != nil {
				logger.Warn(
					"error putting message",
					log.Error(err),
				)
			}
		}
	}()

	for event := range events {
		switch v := event.(type) {
		case *ConversationMessageAdded:
			t, err := time.Parse(time.RFC3339Nano, v.Datetime)
			if err != nil {
				continue
			}
			usr := last(v.Metadata.Owner.String(), 8)
			app.Channels.MessageAdded <- &Message{
				Hash:             v.ToObject().Hash().String(),
				ConversationHash: v.Metadata.Stream.String(),
				SenderHash:       v.Metadata.Owner.String(),
				SenderNickname:   usr,
				Body:             strings.TrimSpace(v.Body),
				Created:          t,
			}
		}
	}
}

func last(t string, i int) string {
	if len(t) <= i {
		return t
	}
	return t[len(t)-i:]
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"strings"

	golog "github.com/ipfs/go-log"
	host "github.com/libp2p/go-libp2p-host"
	inet "github.com/libp2p/go-libp2p-net"
	net "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	swarm "github.com/libp2p/go-libp2p-swarm"
	bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
	testutil "github.com/libp2p/go-testutil"
	ma "github.com/multiformats/go-multiaddr"
	gologging "github.com/whyrusleeping/go-logging"
)

// create a 'Host' with a random peer to listen on the given address
func makeBasicHost(listen string, secio bool) (host.Host, error) {
	addr, err := ma.NewMultiaddr(listen)
	if err != nil {
		return nil, err
	}

	ps := pstore.NewPeerstore()
	var pid peer.ID

	if secio {
		ident, err := testutil.RandIdentity()
		if err != nil {
			return nil, err
		}

		ident.PrivateKey()
		ps.AddPrivKey(ident.ID(), ident.PrivateKey())
		ps.AddPubKey(ident.ID(), ident.PublicKey())
		pid = ident.ID()
	} else {
		fakepid, err := testutil.RandPeerID()
		if err != nil {
			return nil, err
		}
		pid = fakepid
	}

	ctx := context.Background()

	// create a new swarm to be used by the service host
	netw, err := swarm.NewNetwork(ctx, []ma.Multiaddr{addr}, pid, ps, nil)
	if err != nil {
		return nil, err
	}

	log.Printf("I am %s/ipfs/%s\n", addr, pid.Pretty())
	return bhost.New(netw), nil
}

func main() {
	golog.SetAllLoggers(gologging.INFO) // Change to DEBUG for extra info
	listenF := flag.Int("l", 0, "wait for incoming connections")
	target := flag.String("d", "", "target peer to dial")
	secio := flag.Bool("secio", false, "enable secio")

	flag.Parse()

	if *listenF == 0 {
		log.Fatal("Please provide a port to bind on with -l")
	}

	listenaddr := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", *listenF)

	ha, err := makeBasicHost(listenaddr, *secio)
	if err != nil {
		log.Fatal(err)
	}

	// Set a stream handler on host A
	ha.SetStreamHandler("/echo/1.0.0", func(s net.Stream) {
		log.Println("Got a new stream!")
		defer s.Close()
		doEcho(s)
	})

	if *target == "" {
		log.Println("listening for connections")
		select {} // hang forever
	}
	// This is where the listener code ends

	ipfsaddr, err := ma.NewMultiaddr(*target)
	if err != nil {
		log.Fatalln(err)
	}

	pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS)
	if err != nil {
		log.Fatalln(err)
	}

	peerid, err := peer.IDB58Decode(pid)
	if err != nil {
		log.Fatalln(err)
	}

	tptaddr := strings.Split(ipfsaddr.String(), "/ipfs/")[0]
	// This creates a MA with the "/ip4/ipaddr/tcp/port" part of the target
	tptmaddr, err := ma.NewMultiaddr(tptaddr)
	if err != nil {
		log.Fatalln(err)
	}

	// We need to add the target to our peerstore, so we know how we can
	// contact it
	ha.Peerstore().AddAddr(peerid, tptmaddr, pstore.PermanentAddrTTL)

	log.Println("opening stream")
	// make a new stream from host B to host A
	// it should be handled on host A by the handler we set above
	s, err := ha.NewStream(context.Background(), peerid, "/echo/1.0.0")
	if err != nil {
		log.Fatalln(err)
	}

	_, err = s.Write([]byte("Hello, world!"))
	if err != nil {
		log.Fatalln(err)
	}

	out, err := ioutil.ReadAll(s)
	if err != nil {
		log.Fatalln(err)
	}

	log.Printf("read reply: %q\n", out)
}

// doEcho reads some data from a stream, writes it back and closes the
// stream.
func doEcho(s inet.Stream) {
	buf := make([]byte, 1024)
	n, err := s.Read(buf)
	if err != nil {
		log.Println(err)
		return
	}

	log.Printf("read request: %q\n", buf[:n])
	_, err = s.Write(buf[:n])
	if err != nil {
		log.Println(err)
		return
	}
}
<commit_msg>more imports cleanup, another dup.<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"strings"

	golog "github.com/ipfs/go-log"
	host "github.com/libp2p/go-libp2p-host"
	net "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	swarm "github.com/libp2p/go-libp2p-swarm"
	bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
	testutil "github.com/libp2p/go-testutil"
	ma "github.com/multiformats/go-multiaddr"
	gologging "github.com/whyrusleeping/go-logging"
)

// create a 'Host' with a random peer to listen on the given address
func makeBasicHost(listen string, secio bool) (host.Host, error) {
	addr, err := ma.NewMultiaddr(listen)
	if err != nil {
		return nil, err
	}

	ps := pstore.NewPeerstore()
	var pid peer.ID

	if secio {
		ident, err := testutil.RandIdentity()
		if err != nil {
			return nil, err
		}

		ident.PrivateKey()
		ps.AddPrivKey(ident.ID(), ident.PrivateKey())
		ps.AddPubKey(ident.ID(), ident.PublicKey())
		pid = ident.ID()
	} else {
		fakepid, err := testutil.RandPeerID()
		if err != nil {
			return nil, err
		}
		pid = fakepid
	}

	ctx := context.Background()

	// create a new swarm to be used by the service host
	netw, err := swarm.NewNetwork(ctx, []ma.Multiaddr{addr}, pid, ps, nil)
	if err != nil {
		return nil, err
	}

	log.Printf("I am %s/ipfs/%s\n", addr, pid.Pretty())
	return bhost.New(netw), nil
}

func main() {
	golog.SetAllLoggers(gologging.INFO) // Change to DEBUG for extra info
	listenF := flag.Int("l", 0, "wait for incoming connections")
	target := flag.String("d", "", "target peer to dial")
	secio := flag.Bool("secio", false, "enable secio")

	flag.Parse()

	if *listenF == 0 {
		log.Fatal("Please provide a port to bind on with -l")
	}

	listenaddr := fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", *listenF)

	ha, err := makeBasicHost(listenaddr, *secio)
	if err != nil {
		log.Fatal(err)
	}

	// Set a stream handler on host A
	ha.SetStreamHandler("/echo/1.0.0", func(s net.Stream) {
		log.Println("Got a new stream!")
		defer s.Close()
		doEcho(s)
	})

	if *target == "" {
		log.Println("listening for connections")
		select {} // hang forever
	}
	// This is where the listener code ends

	ipfsaddr, err := ma.NewMultiaddr(*target)
	if err != nil {
		log.Fatalln(err)
	}

	pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS)
	if err != nil {
		log.Fatalln(err)
	}

	peerid, err := peer.IDB58Decode(pid)
	if err != nil {
		log.Fatalln(err)
	}

	tptaddr := strings.Split(ipfsaddr.String(), "/ipfs/")[0]
	// This creates a MA with the "/ip4/ipaddr/tcp/port" part of the target
	tptmaddr, err := ma.NewMultiaddr(tptaddr)
	if err != nil {
		log.Fatalln(err)
	}

	// We need to add the target to our peerstore, so we know how we can
	// contact it
	ha.Peerstore().AddAddr(peerid, tptmaddr, pstore.PermanentAddrTTL)

	log.Println("opening stream")
	// make a new stream from host B to host A
	// it should be handled on host A by the handler we set above
	s, err := ha.NewStream(context.Background(), peerid, "/echo/1.0.0")
	if err != nil {
		log.Fatalln(err)
	}

	_, err = s.Write([]byte("Hello, world!"))
	if err != nil {
		log.Fatalln(err)
	}

	out, err := ioutil.ReadAll(s)
	if err != nil {
		log.Fatalln(err)
	}

	log.Printf("read reply: %q\n", out)
}

// doEcho reads some data from a stream, writes it back and closes the
// stream.
func doEcho(s net.Stream) {
	buf := make([]byte, 1024)
	n, err := s.Read(buf)
	if err != nil {
		log.Println(err)
		return
	}

	log.Printf("read request: %q\n", buf[:n])
	_, err = s.Write(buf[:n])
	if err != nil {
		log.Println(err)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/goplan9/plan9/acme"
	"fmt"
	"io"
	"os"
	"os/user"
	"strconv"
	"strings"
)

type acmeFile struct {
	name       string
	body       []byte
	offset     int
	runeOffset int
}

func acmeCurrentFile() (*acmeFile, error) {
	win, err := acmeCurrentWin()
	if err != nil {
		return nil, err
	}
	defer win.CloseFiles()
	_, _, err = win.ReadAddr() // make sure address file is already open.
	if err != nil {
		return nil, fmt.Errorf("cannot read address: %v", err)
	}
	err = win.Ctl("addr=dot")
	if err != nil {
		return nil, fmt.Errorf("cannot set addr=dot: %v", err)
	}
	q0, _, err := win.ReadAddr()
	if err != nil {
		return nil, fmt.Errorf("cannot read address: %v", err)
	}
	body, err := readBody(win)
	if err != nil {
		return nil, fmt.Errorf("cannot read body: %v", err)
	}
	tagb, err := win.ReadAll("tag")
	if err != nil {
		return nil, fmt.Errorf("cannot read tag: %v", err)
	}
	tag := string(tagb)
	i := strings.Index(tag, " ")
	if i == -1 {
		return nil, fmt.Errorf("strange tag with no spaces")
	}

	w := &acmeFile{
		name:       tag[0:i],
		body:       body,
		offset:     runeOffset2ByteOffset(body, q0),
		runeOffset: q0,
	}
	return w, nil
}

// We would use win.ReadAll except for a bug in acme
// where it crashes when reading trying to read more
// than the negotiated 9P message size.
func readBody(win *acme.Win) ([]byte, error) {
	var body []byte
	buf := make([]byte, 8000)
	for {
		n, err := win.Read("body", buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		body = append(body, buf[0:n]...)
	}
	return body, nil
}

func acmeCurrentWin() (*acme.Win, error) {
	winid := os.Getenv("winid")
	if winid == "" {
		return nil, fmt.Errorf("$winid not set - not running inside acme?")
	}
	id, err := strconv.Atoi(winid)
	if err != nil {
		return nil, fmt.Errorf("invalid $winid %q", winid)
	}
	if err := setNameSpace(); err != nil {
		return nil, err
	}
	win, err := acme.Open(id, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot open acme window: %v", err)
	}
	return win, nil
}

func runeOffset2ByteOffset(b []byte, off int) int {
	r := 0
	for i, _ := range string(b) {
		if r == off {
			return i
		}
		r++
	}
	return len(b)
}

func setNameSpace() error {
	if ns := os.Getenv("NAMESPACE"); ns != "" {
		return nil
	}
	ns, err := nsFromDisplay()
	if err != nil {
		return fmt.Errorf("cannot get name space: %v", err)
	}
	os.Setenv("NAMESPACE", ns)
	return nil
}

// taken from src/lib9/getns.c
// This should go into goplan9/plan9/client.
func nsFromDisplay() (string, error) {
	disp := os.Getenv("DISPLAY")
	if disp == "" {
		// original code had heuristic for OS X here;
		// we'll just assume that and fail anyway if it
		// doesn't work.
		disp = ":0.0"
	}
	// canonicalize: xxx:0.0 => xxx:0
	if i := strings.LastIndex(disp, ":"); i >= 0 {
		if strings.HasSuffix(disp, ".0") {
			disp = disp[:len(disp)-2]
		}
	}

	// turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5)
	disp = strings.Replace(disp, "/", "_", -1)

	u, err := user.Current()
	if err != nil {
		return "", fmt.Errorf("cannot get current user name: %v", err)
	}
	ns := fmt.Sprintf("/tmp/ns.%s.%s", u.Username, disp)
	_, err = os.Stat(ns)
	if os.IsNotExist(err) {
		return "", fmt.Errorf("no name space directory found")
	}
	if err != nil {
		return "", fmt.Errorf("cannot stat name space directory: %v", err)
	}
	// heuristics for checking permissions and owner of name space
	// directory omitted.
	return ns, nil
}
<commit_msg>exp/cmd/godef: change import: code.google.com/p/goplan9/plan9/acme -> 9fans.net/go/acme<commit_after>package main

import (
	"9fans.net/go/acme"
	"fmt"
	"io"
	"os"
	"os/user"
	"strconv"
	"strings"
)

type acmeFile struct {
	name       string
	body       []byte
	offset     int
	runeOffset int
}

func acmeCurrentFile() (*acmeFile, error) {
	win, err := acmeCurrentWin()
	if err != nil {
		return nil, err
	}
	defer win.CloseFiles()
	_, _, err = win.ReadAddr() // make sure address file is already open.
	if err != nil {
		return nil, fmt.Errorf("cannot read address: %v", err)
	}
	err = win.Ctl("addr=dot")
	if err != nil {
		return nil, fmt.Errorf("cannot set addr=dot: %v", err)
	}
	q0, _, err := win.ReadAddr()
	if err != nil {
		return nil, fmt.Errorf("cannot read address: %v", err)
	}
	body, err := readBody(win)
	if err != nil {
		return nil, fmt.Errorf("cannot read body: %v", err)
	}
	tagb, err := win.ReadAll("tag")
	if err != nil {
		return nil, fmt.Errorf("cannot read tag: %v", err)
	}
	tag := string(tagb)
	i := strings.Index(tag, " ")
	if i == -1 {
		return nil, fmt.Errorf("strange tag with no spaces")
	}

	w := &acmeFile{
		name:       tag[0:i],
		body:       body,
		offset:     runeOffset2ByteOffset(body, q0),
		runeOffset: q0,
	}
	return w, nil
}

// We would use win.ReadAll except for a bug in acme
// where it crashes when reading trying to read more
// than the negotiated 9P message size.
func readBody(win *acme.Win) ([]byte, error) {
	var body []byte
	buf := make([]byte, 8000)
	for {
		n, err := win.Read("body", buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		body = append(body, buf[0:n]...)
	}
	return body, nil
}

func acmeCurrentWin() (*acme.Win, error) {
	winid := os.Getenv("winid")
	if winid == "" {
		return nil, fmt.Errorf("$winid not set - not running inside acme?")
	}
	id, err := strconv.Atoi(winid)
	if err != nil {
		return nil, fmt.Errorf("invalid $winid %q", winid)
	}
	if err := setNameSpace(); err != nil {
		return nil, err
	}
	win, err := acme.Open(id, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot open acme window: %v", err)
	}
	return win, nil
}

func runeOffset2ByteOffset(b []byte, off int) int {
	r := 0
	for i, _ := range string(b) {
		if r == off {
			return i
		}
		r++
	}
	return len(b)
}

func setNameSpace() error {
	if ns := os.Getenv("NAMESPACE"); ns != "" {
		return nil
	}
	ns, err := nsFromDisplay()
	if err != nil {
		return fmt.Errorf("cannot get name space: %v", err)
	}
	os.Setenv("NAMESPACE", ns)
	return nil
}

// taken from src/lib9/getns.c
// This should go into goplan9/plan9/client.
func nsFromDisplay() (string, error) {
	disp := os.Getenv("DISPLAY")
	if disp == "" {
		// original code had heuristic for OS X here;
		// we'll just assume that and fail anyway if it
		// doesn't work.
		disp = ":0.0"
	}
	// canonicalize: xxx:0.0 => xxx:0
	if i := strings.LastIndex(disp, ":"); i >= 0 {
		if strings.HasSuffix(disp, ".0") {
			disp = disp[:len(disp)-2]
		}
	}

	// turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5)
	disp = strings.Replace(disp, "/", "_", -1)

	u, err := user.Current()
	if err != nil {
		return "", fmt.Errorf("cannot get current user name: %v", err)
	}
	ns := fmt.Sprintf("/tmp/ns.%s.%s", u.Username, disp)
	_, err = os.Stat(ns)
	if os.IsNotExist(err) {
		return "", fmt.Errorf("no name space directory found")
	}
	if err != nil {
		return "", fmt.Errorf("cannot stat name space directory: %v", err)
	}
	// heuristics for checking permissions and owner of name space
	// directory omitted.
	return ns, nil
}
<|endoftext|>


<commit_before>package yorm

import (
	"database/sql"
	"errors"
	"reflect"
)

type querySetter struct {
	table   string
	dests   []interface{}
	columns []column
}

type sqlScanner interface {
	Scan(dest ...interface{}) error
}

//Query do a query operation.
func Query(i interface{}, query string, args ...interface{}) error {
	typ := reflect.TypeOf(i)
	if typ.Kind() != reflect.Ptr {
		return ErrNonPtr
	}
	typ = typ.Elem()
	var err error
	var stmt *sql.Stmt
	stmt, err = getStmt(query)
	if stmt == nil {
		return err
	}
	if typ.Kind() == reflect.Slice {
		rows, err := stmt.Query(args...)
		if rows == nil {
			return err
		}
		return queryList(i, rows)
	}
	return queryOne(i, stmt.QueryRow(args...))

}

func queryOne(i interface{}, row *sql.Row) error {
	if row == nil {
		return ErrIllegalParams
	}
	return convertAssignRow(i, row)
}
func queryList(i interface{}, rows *sql.Rows) error {
	if rows == nil {
		return ErrIllegalParams
	}
	return convertAssignRows(i, rows)
}

func newQuery(ri reflect.Value) *querySetter {
	if q, ok := tableMap[ri.Kind()]; ok {
		return q
	}
	if ri.Kind() != reflect.Ptr || ri.IsNil() {
		return nil
	}
	q := new(querySetter)
	defer func() {
		tableMap[ri.Kind()] = q
	}()
	table, cs := structToTable(reflect.Indirect(ri).Interface())
	q.table = table
	q.columns = cs
	q.dests = make([]interface{}, len(cs))
	for k, v := range cs {
		q.dests[k] = newPtrInterface(v.typ.Kind())
	}
	return q
}

func newPtrInterface(k reflect.Kind) interface{} {
	var ti interface{}
	switch k {
	case reflect.Int:
		ti = new(int)
	case reflect.Int64:
		ti = new(int64)
	case reflect.String:
		ti = new(string)
	}
	return ti
}

func convertAssignRows(i interface{}, rows *sql.Rows) error {
	typ := reflect.TypeOf(i)
	if typ.Kind() != reflect.Ptr {
		return ErrNonPtr
	}
	typ = typ.Elem()
	if typ.Kind() != reflect.Slice {
		return ErrNonSlice
	}
	typ = typ.Elem()
	var q *querySetter
	if typ.Kind() == reflect.Struct {
		q = newQuery(reflect.New(typ))
		if q == nil {
			return errors.New("q is not support")
		}
	}
	size := 0
	v := reflect.Indirect(reflect.ValueOf(i))
	ti := newPtrInterface(typ.Kind())
	for rows.Next() {
		if size >= v.Cap() {
			newCap := v.Cap()
			if newCap == 0 {
				newCap = 1
			} else {
				if newCap < 1024 {
					newCap += newCap
				} else {
					newCap += newCap / 4
				}
			}
			nv := reflect.MakeSlice(v.Type(), v.Len(), newCap)
			reflect.Copy(nv, v)
			v.Set(nv)
		}
		if size >= v.Len() {
			v.SetLen(size + 1)
		}
		st := reflect.New(typ)
		st = st.Elem()
		if q != nil {
			err := scanValue(rows, q, st)
			if err != nil {
				return err
			}
		} else {
			rows.Scan(ti)
			st.Set(reflect.ValueOf(ti).Elem())
		}
		v.Index(size).Set(st)
		size++
	}
	return nil
}
func convertAssignRow(i interface{}, row *sql.Row) error {
	typ := reflect.TypeOf(i)

	if typ.Kind() == reflect.Ptr && typ.Elem().Kind() != reflect.Struct {
		return row.Scan(i)
	}

	q := newQuery(reflect.ValueOf(i))
	if q == nil {
		return errors.New("nil struct")
	}
	st := reflect.ValueOf(i).Elem()
	return scanValue(row, q, st)
}

func scanValue(sc sqlScanner, q *querySetter, st reflect.Value) error {
	err := sc.Scan(q.dests...)
	if err != nil {
		return err
	}
	for idx, c := range q.columns {
		// different assign func here
		switch c.typ.Kind() {
		case reflect.Int:
			st.Field(c.fieldNum).SetInt(int64(*(q.dests[idx].(*int))))
		case reflect.Int64:
			st.Field(c.fieldNum).SetInt(int64(*(q.dests[idx].(*int64))))
		case reflect.String:
			st.Field(c.fieldNum).SetString(string(*(q.dests[idx].(*string))))
		}
	}
	return nil
}
<commit_msg>params modify<commit_after>package yorm

import (
	"database/sql"
	"errors"
	"reflect"
)

type querySetter struct {
	table   string
	dests   []interface{}
	columns []column
}

type sqlScanner interface {
	Scan(dest ...interface{}) error
}

//Query do a query operation.
func Query(i interface{}, query string, args ...interface{}) error {
	typ := reflect.TypeOf(i)
	if typ.Kind() != reflect.Ptr {
		return ErrNonPtr
	}
	typ = typ.Elem()
	var err error
	var stmt *sql.Stmt
	stmt, err = getStmt(query)
	if stmt == nil {
		return err
	}
	if typ.Kind() == reflect.Slice {
		rows, err := stmt.Query(args...)
		if rows == nil {
			return err
		}
		return queryList(i, rows)
	}
	return queryOne(i, stmt.QueryRow(args...))

}

func queryOne(i interface{}, row *sql.Row) error {
	if row == nil {
		return ErrIllegalParams
	}
	return convertAssignRow(i, row)
}
func queryList(i interface{}, rows *sql.Rows) error {
	if rows == nil {
		return ErrIllegalParams
	}
	return convertAssignRows(i, rows)
}

func newQuery(ri reflect.Value) *querySetter {
	if q, ok := tableMap[ri.Kind()]; ok {
		return q
	}
	if ri.Kind() != reflect.Ptr || ri.IsNil() {
		return nil
	}
	q := new(querySetter)
	defer func() {
		tableMap[ri.Kind()] = q
	}()
	table, cs := structToTable(reflect.Indirect(ri).Interface())
	q.table = table
	q.columns = cs
	q.dests = make([]interface{}, len(cs))
	for k, v := range cs {
		q.dests[k] = newPtrInterface(v.typ)
	}
	return q
}

func newPtrInterface(t reflect.Type) interface{} {
	k := t.Kind()
	var ti interface{}
	switch k {
	case reflect.Int:
		ti = new(int)
	case reflect.Int64:
		ti = new(int64)
	case reflect.String:
		ti = new(string)
	}
	return ti
}

func convertAssignRows(i interface{}, rows *sql.Rows) error {
	typ := reflect.TypeOf(i)
	if typ.Kind() != reflect.Ptr {
		return ErrNonPtr
	}
	typ = typ.Elem()
	if typ.Kind() != reflect.Slice {
		return ErrNonSlice
	}
	typ = typ.Elem()
	var q *querySetter
	if typ.Kind() == reflect.Struct {
		q = newQuery(reflect.New(typ))
		if q == nil {
			return errors.New("q is not support")
		}
	}
	size := 0
	v := reflect.Indirect(reflect.ValueOf(i))
	ti := newPtrInterface(typ)
	for rows.Next() {
		if size >= v.Cap() {
			newCap := v.Cap()
			if newCap == 0 {
				newCap = 1
			} else {
				if newCap < 1024 {
					newCap += newCap
				} else {
					newCap += newCap / 4
				}
			}
			nv := reflect.MakeSlice(v.Type(), v.Len(), newCap)
			reflect.Copy(nv, v)
			v.Set(nv)
		}
		if size >= v.Len() {
			v.SetLen(size + 1)
		}
		st := reflect.New(typ)
		st = st.Elem()
		if q != nil {
			err := scanValue(rows, q, st)
			if err != nil {
				return err
			}
		} else {
			rows.Scan(ti)
			st.Set(reflect.ValueOf(ti).Elem())
		}
		v.Index(size).Set(st)
		size++
	}
	return nil
}
func convertAssignRow(i interface{}, row *sql.Row) error {
	typ := reflect.TypeOf(i)

	if typ.Kind() == reflect.Ptr && typ.Elem().Kind() != reflect.Struct {
		return row.Scan(i)
	}

	q := newQuery(reflect.ValueOf(i))
	if q == nil {
		return errors.New("nil struct")
	}
	st := reflect.ValueOf(i).Elem()
	return scanValue(row, q, st)
}

func scanValue(sc sqlScanner, q *querySetter, st reflect.Value) error {
	err := sc.Scan(q.dests...)
	if err != nil {
		return err
	}
	for idx, c := range q.columns {
		// different assign func here
		switch c.typ.Kind() {
		case reflect.Int:
			st.Field(c.fieldNum).SetInt(int64(*(q.dests[idx].(*int))))
		case reflect.Int64:
			st.Field(c.fieldNum).SetInt(int64(*(q.dests[idx].(*int64))))
		case reflect.String:
			st.Field(c.fieldNum).SetString(string(*(q.dests[idx].(*string))))
		}
	}
	return nil
}
<|endoftext|>


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

package apiserver

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"

	"github.com/fiorix/freegeoip"
)

func newTestHandler() (http.Handler, error) {
	c := NewConfig()
	c.APIPrefix = "/api"
	c.PublicDir = "."
	c.DB = freegeoip.MaxMindDB
	c.RateLimitLimit = 5
	c.RateLimitBackend = "map"
	c.Silent = true
	return NewHandler(c)
}

func TestHandler(t *testing.T) {
	f, err := newTestHandler()
	if err != nil {
		t.Fatal(err)
	}
	w := &httptest.ResponseRecorder{Body: &bytes.Buffer{}}
	r := &http.Request{
		Method:     "GET",
		URL:        &url.URL{Path: "/api/json/200.1.2.3"},
		RemoteAddr: "[::1]:1905",
	}
	f.ServeHTTP(w, r)
	if w.Code != http.StatusOK {
		t.Fatalf("Unexpected response: %d %s", w.Code, w.Body.String())
	}
	m := struct {
		Country string `json:"country_name"`
		City    string `json:"city"`
	}{}
	if err = json.NewDecoder(w.Body).Decode(&m); err != nil {
		t.Fatal(err)
	}
	if m.Country != "Venezuela" && m.City != "Caracas" {
		t.Fatalf("Query data does not match: want Caracas,Venezuela, have %q,%q",
			m.City, m.Country)
	}
}

func TestMetricsHandler(t *testing.T) {
	f, err := newTestHandler()
	if err != nil {
		t.Fatal(err)
	}
	tp := []http.Request{
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/200.1.2.3"},
			RemoteAddr: "[::1]:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/200.1.2.3"},
			RemoteAddr: "127.0.0.1:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/200.1.2.3"},
			RemoteAddr: "200.1.2.3:1905",
		},
	}
	for i, r := range tp {
		w := &httptest.ResponseRecorder{Body: &bytes.Buffer{}}
		f.ServeHTTP(w, &r)
		if w.Code != http.StatusOK {
			t.Fatalf("Test %d: Unexpected response: %d %s", i, w.Code, w.Body.String())
		}
	}
}

func TestWriters(t *testing.T) {
	f, err := newTestHandler()
	if err != nil {
		t.Fatal(err)
	}
	tp := []http.Request{
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/csv/"},
			RemoteAddr: "[::1]:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/xml/"},
			RemoteAddr: "[::1]:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/"},
			RemoteAddr: "[::1]:1905",
		},
	}
	for i, r := range tp {
		w := &httptest.ResponseRecorder{Body: &bytes.Buffer{}}
		f.ServeHTTP(w, &r)
		if w.Code != http.StatusOK {
			t.Fatalf("Test %d: Unexpected response: %d %s", i, w.Code, w.Body.String())
		}
	}
}
<commit_msg>Fix db path in test<commit_after>// Copyright 2009 The freegeoip authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package apiserver

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"path/filepath"
	"runtime"
	"testing"
)

func newTestHandler() (http.Handler, error) {
	_, f, _, _ := runtime.Caller(0)
	c := NewConfig()
	c.APIPrefix = "/api"
	c.PublicDir = "."
	c.DB = filepath.Join(filepath.Dir(f), "../testdata/db.gz")
	c.RateLimitLimit = 5
	c.RateLimitBackend = "map"
	c.Silent = true
	return NewHandler(c)
}

func TestHandler(t *testing.T) {
	f, err := newTestHandler()
	if err != nil {
		t.Fatal(err)
	}
	w := &httptest.ResponseRecorder{Body: &bytes.Buffer{}}
	r := &http.Request{
		Method:     "GET",
		URL:        &url.URL{Path: "/api/json/200.1.2.3"},
		RemoteAddr: "[::1]:1905",
	}
	f.ServeHTTP(w, r)
	if w.Code != http.StatusOK {
		t.Fatalf("Unexpected response: %d %s", w.Code, w.Body.String())
	}
	m := struct {
		Country string `json:"country_name"`
		City    string `json:"city"`
	}{}
	if err = json.NewDecoder(w.Body).Decode(&m); err != nil {
		t.Fatal(err)
	}
	if m.Country != "Venezuela" && m.City != "Caracas" {
		t.Fatalf("Query data does not match: want Caracas,Venezuela, have %q,%q",
			m.City, m.Country)
	}
}

func TestMetricsHandler(t *testing.T) {
	f, err := newTestHandler()
	if err != nil {
		t.Fatal(err)
	}
	tp := []http.Request{
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/200.1.2.3"},
			RemoteAddr: "[::1]:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/200.1.2.3"},
			RemoteAddr: "127.0.0.1:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/200.1.2.3"},
			RemoteAddr: "200.1.2.3:1905",
		},
	}
	for i, r := range tp {
		w := &httptest.ResponseRecorder{Body: &bytes.Buffer{}}
		f.ServeHTTP(w, &r)
		if w.Code != http.StatusOK {
			t.Fatalf("Test %d: Unexpected response: %d %s", i, w.Code, w.Body.String())
		}
	}
}

func TestWriters(t *testing.T) {
	f, err := newTestHandler()
	if err != nil {
		t.Fatal(err)
	}
	tp := []http.Request{
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/csv/"},
			RemoteAddr: "[::1]:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/xml/"},
			RemoteAddr: "[::1]:1905",
		},
		http.Request{
			Method:     "GET",
			URL:        &url.URL{Path: "/api/json/"},
			RemoteAddr: "[::1]:1905",
		},
	}
	for i, r := range tp {
		w := &httptest.ResponseRecorder{Body: &bytes.Buffer{}}
		f.ServeHTTP(w, &r)
		if w.Code != http.StatusOK {
			t.Fatalf("Test %d: Unexpected response: %d %s", i, w.Code, w.Body.String())
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
)

type LimitedWriter struct {
	N   int
	buf []byte
}

func (w *LimitedWriter) Write(data []byte) (int, error) {
	writable := len(data)
	if writable > w.N {
		writable = w.N
	}
	after := len(w.buf) + writable
	discard := 0
	if after > w.N {
		discard = after - w.N
	}
	w.buf = append(w.buf[discard:], data[len(data)-writable:]...)
	return len(data), nil
}

func (w *LimitedWriter) Bytes() []byte {
	return w.buf
}

func quiet(args []string) error {
	if len(args) < 1 {
		return fmt.Errorf("command argument was not supplied")
	}
	command := args[0]
	args = args[1:]
	if command == "-h" || command == "--help" {
		fmt.Printf(`quiet COMMAND [ARGS...]

quiet executes supplied command with its arguments, keeping the last QUIET_MAX
bytes of combined standard output and prints them only if the command fails.
QUIET_MAX defaults to 1024.

Originally used in crontab.
`)
		return nil
	}
	n := 1024
	nEnv := os.Getenv("QUIET_MAX")
	if nEnv != "" {
		nn, err := strconv.ParseInt(nEnv, 10, 32)
		if err != nil {
			return err
		}
		n = int(nn)
	}
	w := &LimitedWriter{
		N: n,
	}
	cmd := exec.Command(command, args...)
	cmd.Stdout = w
	cmd.Stderr = w
	err := cmd.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, string(w.Bytes()))
	}
	return err
}

func main() {
	err := quiet(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}
}
<commit_msg>quiet: replace buggy Fprintf with Write<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
)

type LimitedWriter struct {
	N   int
	buf []byte
}

func (w *LimitedWriter) Write(data []byte) (int, error) {
	writable := len(data)
	if writable > w.N {
		writable = w.N
	}
	after := len(w.buf) + writable
	discard := 0
	if after > w.N {
		discard = after - w.N
	}
	w.buf = append(w.buf[discard:], data[len(data)-writable:]...)
	return len(data), nil
}

func (w *LimitedWriter) Bytes() []byte {
	return w.buf
}

func quiet(args []string) error {
	if len(args) < 1 {
		return fmt.Errorf("command argument was not supplied")
	}
	command := args[0]
	args = args[1:]
	if command == "-h" || command == "--help" {
		fmt.Printf(`quiet COMMAND [ARGS...]

quiet executes supplied command with its arguments, keeping the last QUIET_MAX
bytes of combined standard output and prints them only if the command fails.
QUIET_MAX defaults to 1024.

Originally used in crontab.
`)
		return nil
	}
	n := 1024
	nEnv := os.Getenv("QUIET_MAX")
	if nEnv != "" {
		nn, err := strconv.ParseInt(nEnv, 10, 32)
		if err != nil {
			return err
		}
		n = int(nn)
	}
	w := &LimitedWriter{
		N: n,
	}
	cmd := exec.Command(command, args...)
	cmd.Stdout = w
	cmd.Stderr = w
	err := cmd.Run()
	if err != nil {
		_, err = os.Stderr.Write(w.Bytes())
	}
	return err
}

func main() {
	err := quiet(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

// index template
const index = `[[define "index"]]<!doctype html>

[[template "head" . ]]

    <ng-include src="'pages/global.html'"></ng-include>

[[template "header" . ]]

[[end]]`

// head items
const head = `[[define "head"]]
    <base href="/[[ .base ]]">
    <title data-ng-bind="page.title">[[ .title ]]</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="description" content="[[ .desc ]]" />[[if .nsfw]]
    <meta name="rating" content="adult" />
    <meta name="rating" content="RTA-5042-1996-1400-1577-RTA" />[[end]]

    <link rel="stylesheet" href="/assets/prim/[[ .primcss ]]" />
    <link rel="stylesheet" href="/assets/styles/[[ .style ]]" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    [[template "angular" . ]]
    [[template "headinclude" . ]][[end]]`

// angular config
const angular = `[[define "angular"]][[end]]`

// site header
const header = `[[define "header"]]

[[template "navmenuinclude" . ]]
[[template "navmenu" . ]]

                <ng-include src="'pages/menus/nav.html'"></ng-include>

                login

                            <ng-include src="'pages/menus/user.html'"></ng-include>

[[end]]`

const navmenu = `[[define "navmenu"]][[ range $ib := .imageboards ]]
[[ $ib.Title ]]

[[end]][[end]]`
<commit_msg>add subdirectory support<commit_after>package main

// index template
const index = `[[define "index"]]<!doctype html>

[[template "head" . ]]

    <ng-include src="'pages/global.html'"></ng-include>

[[template "header" . ]]

[[end]]`

// head items
const head = `[[define "head"]]
    <base href="/[[ .base ]]">
    <title data-ng-bind="page.title">[[ .title ]]</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="description" content="[[ .desc ]]" />[[if .nsfw]]
    <meta name="rating" content="adult" />
    <meta name="rating" content="RTA-5042-1996-1400-1577-RTA" />[[end]]

    <link rel="stylesheet" href="/assets/prim/[[ .primcss ]]" />
    <link rel="stylesheet" href="/assets/styles/[[ .style ]]" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    [[template "angular" . ]]
    [[template "headinclude" . ]][[end]]`

// angular config
const angular = `[[define "angular"]][[end]]`

// site header
const header = `[[define "header"]]

[[template "navmenuinclude" . ]]
[[template "navmenu" . ]]

                <ng-include src="'pages/menus/nav.html'"></ng-include>

                login

                            <ng-include src="'pages/menus/user.html'"></ng-include>

[[end]]`

const navmenu = `[[define "navmenu"]][[ range $ib := .imageboards ]]
[[ $ib.Title ]]

[[end]][[end]]`
<|endoftext|>


<commit_before>package cc1101

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"github.com/ecc1/radio"
)

const (
	readFifoUsingBurst = true
	fifoSize           = 64
	maxPacketSize      = 110

	// Approximate time for one byte to be transmitted, based on
	// the data rate.  It was determined empirically so that few
	// if any iterations are needed in drainTxFifo().
	byteDuration = time.Millisecond
)

func (r *Radio) Start() {
	if !r.radioStarted {
		r.radioStarted = true
		go r.radio()
	}
}

func (r *Radio) Stop() {
	// stop radio goroutines and enter IDLE state
	panic("not implemented")
}

func (r *Radio) Incoming() <-chan radio.Packet {
	return r.receivedPackets
}

func (r *Radio) Outgoing() chan<- radio.Packet {
	return r.transmittedPackets
}

func (r *Radio) radio() {
	var err error
	receiving := false
	go r.awaitInterrupts()
	for {
		select {
		case packet := <-r.transmittedPackets:
			if receiving {
				err = r.changeState(SIDLE, STATE_IDLE)
				if err != nil {
					log.Fatal(err)
				}
				receiving = false
			}
			err = r.transmit(packet.Data)
		case <-r.interrupt:
			err = r.receive()
		default:
			if !receiving {
				err = r.changeState(SRX, STATE_RX)
				if err != nil {
					log.Fatal(err)
				}
				receiving = true
			}
		}
		if err != nil {
			log.Fatal(err)
		}
	}
}

func (r *Radio) awaitInterrupts() {
	for {
		if verbose {
			log.Printf("waiting for interrupt in %s state\n", r.State())
		}
		r.interruptPin.Wait()
		r.interrupt <- struct{}{}
	}
}

func (r *Radio) transmit(data []byte) error {
	if len(data) > maxPacketSize {
		log.Panicf("attempting to send %d-byte packet\n", len(data))
	}
	// Terminate packet with zero byte,
	// and pad with another to ensure final bytes
	// are transmitted before leaving TX state.
	var buffer [maxPacketSize + 2]byte
	copy(buffer[0:], data)
	buffer[len(data)] = 0
	buffer[len(data)+1] = 0
	packet := buffer[:len(data)+2]
	var err error
	if len(packet) <= fifoSize {
		err = r.transmitSmall(packet)
	} else {
		err = r.transmitLarge(packet)
	}
	if err == nil {
		r.stats.Packets.Sent++
		r.stats.Bytes.Sent += len(data)
	}
	return err
}

func (r *Radio) transmitSmall(data []byte) error {
	err := r.WriteBurst(TXFIFO, data)
	if err != nil {
		return err
	}
	err = r.changeState(STX, STATE_TX)
	if err != nil {
		return err
	}
	return r.drainTxFifo(len(data))
}

// Transmit a packet that is larger than the TXFIFO size.
// See TI Design Note DN500 (swra109c).
func (r *Radio) transmitLarge(data []byte) error {
	avail := fifoSize
	for {
		err := r.WriteBurst(TXFIFO, data[:avail])
		if err != nil {
			return err
		}
		err = r.changeState(STX, STATE_TX)
		if err != nil {
			return err
		}
		data = data[avail:]
		if len(data) == 0 {
			break
		}
		// Err on the short side here to avoid TXFIFO underflow.
		time.Sleep(fifoSize / 4 * byteDuration)
		for {
			n, err := r.ReadNumTxBytes()
			if err != nil {
				return err
			}
			if n < fifoSize {
				avail = fifoSize - int(n)
				if avail > len(data) {
					avail = len(data)
				}
				break
			}
		}
	}
	return r.drainTxFifo(avail)
}

func (r *Radio) drainTxFifo(numBytes int) error {
	time.Sleep(time.Duration(numBytes) * byteDuration)
	for {
		n, err := r.ReadNumTxBytes()
		if err != nil && err != TxFifoUnderflow {
			return err
		}
		if n == 0 || err == TxFifoUnderflow {
			break
		}
		s, err := r.ReadState()
		if err != nil {
			return err
		}
		if s != STATE_TX && s != STATE_TXFIFO_UNDERFLOW {
			return fmt.Errorf("unexpected %s state during TXFIFO drain", StateName(s))
		}
		if verbose {
			log.Printf("waiting to transmit %d bytes in state %s\n", n, r.State())
		}
		time.Sleep(byteDuration)
	}
	if verbose {
		log.Printf("TX FIFO drained in state %s\n", r.State())
	}
	return r.changeState(SIDLE, STATE_IDLE)
}

func (r *Radio) receive() error {
	waiting := false
	for {
		numBytes, err := r.ReadNumRxBytes()
		if err == RxFifoOverflow {
			r.changeState(SRX, STATE_RX)
			continue
		} else if err != nil {
			return err
		}
		// Don't read last byte of FIFO if packet is still
		// being received. See Section 20 of data sheet.
		if numBytes < 2 {
			if waiting {
				return nil
			}
			waiting = true
			time.Sleep(byteDuration)
			continue
		}
		waiting = false
		if readFifoUsingBurst {
			data, err := r.ReadBurst(RXFIFO, int(numBytes))
			if err != nil {
				return err
			}
			i := bytes.IndexByte(data, 0)
			if i == -1 {
				// No zero byte found; packet is still incoming.
				// Append all the data and continue to receive.
				_, err = r.receiveBuffer.Write(data)
				if err != nil {
					return err
				}
				continue
			}
			// End of packet.
			_, err = r.receiveBuffer.Write(data[:i])
			if err != nil {
				return err
			}
		} else {
			c, err := r.ReadRegister(RXFIFO)
			if err != nil {
				return err
			}
			if c != 0 {
				err = r.receiveBuffer.WriteByte(c)
				if err != nil {
					return err
				}
				continue
			}
		}
		// End of packet.
		rssi, err := r.ReadRSSI()
		if err != nil {
			return err
		}
		size := r.receiveBuffer.Len()
		if size != 0 {
			r.stats.Packets.Received++
			r.stats.Bytes.Received += size
			p := make([]byte, size)
			_, err := r.receiveBuffer.Read(p)
			if err != nil {
				return err
			}
			r.receiveBuffer.Reset()
			r.receivedPackets <- radio.Packet{Rssi: rssi, Data: p}
		}
		if verbose {
			n, _ := r.ReadNumRxBytes()
			log.Printf("received %d-byte packet in state %s; %d bytes remaining\n", size, r.State(), n)
		}
		return nil
	}
}

func (r *Radio) drainRxFifo() error {
	n, err := r.ReadNumRxBytes()
	if err == RxFifoOverflow {
		// Flush RX FIFO and change back to RX.
		return r.changeState(SRX, STATE_RX)
	}
	if err != nil || n == 0 {
		return err
	}
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	switch s {
	case STATE_RX:
		log.Printf("draining %d bytes from RXFIFO\n", n)
		_, err = r.ReadBurst(RXFIFO, int(n))
		return err
	default:
		return fmt.Errorf("unexpected %s state during RXFIFO drain", StateName(s))
	}
}

func (r *Radio) changeState(strobe byte, desired byte) error {
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	if verbose && s != desired {
		log.Printf("change from %s to %s\n", StateName(s), StateName(desired))
	}
	for {
		switch s {
		case desired:
			return nil
		case STATE_RXFIFO_OVERFLOW:
			s, err = r.Strobe(SFRX)
		case STATE_TXFIFO_UNDERFLOW:
			s, err = r.Strobe(SFTX)
		default:
			s, err = r.Strobe(strobe)
		}
		if err != nil {
			return err
		}
		s = (s >> STATE_SHIFT) & STATE_MASK
		if verbose {
			log.Printf("  %s\n", StateName(s))
		}
	}
}
<commit_msg>Simplify transmit method<commit_after>package cc1101

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"github.com/ecc1/radio"
)

const (
	readFifoUsingBurst = true
	fifoSize           = 64
	maxPacketSize      = 110

	// Approximate time for one byte to be transmitted, based on
	// the data rate.  It was determined empirically so that few
	// if any iterations are needed in drainTxFifo().
	byteDuration = time.Millisecond
)

func (r *Radio) Start() {
	if !r.radioStarted {
		r.radioStarted = true
		go r.radio()
	}
}

func (r *Radio) Stop() {
	// stop radio goroutines and enter IDLE state
	panic("not implemented")
}

func (r *Radio) Incoming() <-chan radio.Packet {
	return r.receivedPackets
}

func (r *Radio) Outgoing() chan<- radio.Packet {
	return r.transmittedPackets
}

func (r *Radio) radio() {
	var err error
	receiving := false
	go r.awaitInterrupts()
	for {
		select {
		case packet := <-r.transmittedPackets:
			if receiving {
				err = r.changeState(SIDLE, STATE_IDLE)
				if err != nil {
					log.Fatal(err)
				}
				receiving = false
			}
			err = r.transmit(packet.Data)
		case <-r.interrupt:
			err = r.receive()
		default:
			if !receiving {
				err = r.changeState(SRX, STATE_RX)
				if err != nil {
					log.Fatal(err)
				}
				receiving = true
			}
		}
		if err != nil {
			log.Fatal(err)
		}
	}
}

func (r *Radio) awaitInterrupts() {
	for {
		if verbose {
			log.Printf("waiting for interrupt in %s state\n", r.State())
		}
		r.interruptPin.Wait()
		r.interrupt <- struct{}{}
	}
}

func (r *Radio) transmit(data []byte) error {
	if len(data) > maxPacketSize {
		log.Panicf("attempting to send %d-byte packet\n", len(data))
	}
	// Terminate packet with zero byte,
	// and pad with another to ensure final bytes
	// are transmitted before leaving TX state.
	var buffer [maxPacketSize + 2]byte
	copy(buffer[0:], data)
	buffer[len(data)] = 0
	buffer[len(data)+1] = 0
	packet := buffer[:len(data)+2]
	err := r.send(packet)
	if err == nil {
		r.stats.Packets.Sent++
		r.stats.Bytes.Sent += len(data)
	}
	return err
}

func (r *Radio) send(data []byte) error {
	avail := fifoSize
	for {
		if avail > len(data) {
			avail = len(data)
		}
		err := r.WriteBurst(TXFIFO, data[:avail])
		if err != nil {
			return err
		}
		err = r.changeState(STX, STATE_TX)
		if err != nil {
			return err
		}
		data = data[avail:]
		if len(data) == 0 {
			break
		}
		// Transmitting a packet that is larger than the TXFIFO size.
		// See TI Design Note DN500 (swra109c).
		// Err on the short side here to avoid TXFIFO underflow.
		time.Sleep(fifoSize / 4 * byteDuration)
		for {
			n, err := r.ReadNumTxBytes()
			if err != nil {
				return err
			}
			if n < fifoSize {
				avail = fifoSize - int(n)
				if avail > len(data) {
					avail = len(data)
				}
				break
			}
		}
	}
	return r.drainTxFifo(avail)
}

func (r *Radio) drainTxFifo(numBytes int) error {
	time.Sleep(time.Duration(numBytes) * byteDuration)
	for {
		n, err := r.ReadNumTxBytes()
		if err != nil && err != TxFifoUnderflow {
			return err
		}
		if n == 0 || err == TxFifoUnderflow {
			break
		}
		s, err := r.ReadState()
		if err != nil {
			return err
		}
		if s != STATE_TX && s != STATE_TXFIFO_UNDERFLOW {
			return fmt.Errorf("unexpected %s state during TXFIFO drain", StateName(s))
		}
		if verbose {
			log.Printf("waiting to transmit %d bytes in state %s\n", n, r.State())
		}
		time.Sleep(byteDuration)
	}
	if verbose {
		log.Printf("TX FIFO drained in state %s\n", r.State())
	}
	return r.changeState(SIDLE, STATE_IDLE)
}

func (r *Radio) receive() error {
	waiting := false
	for {
		numBytes, err := r.ReadNumRxBytes()
		if err == RxFifoOverflow {
			r.changeState(SRX, STATE_RX)
			continue
		} else if err != nil {
			return err
		}
		// Don't read last byte of FIFO if packet is still
		// being received. See Section 20 of data sheet.
		if numBytes < 2 {
			if waiting {
				return nil
			}
			waiting = true
			time.Sleep(byteDuration)
			continue
		}
		waiting = false
		if readFifoUsingBurst {
			data, err := r.ReadBurst(RXFIFO, int(numBytes))
			if err != nil {
				return err
			}
			i := bytes.IndexByte(data, 0)
			if i == -1 {
				// No zero byte found; packet is still incoming.
				// Append all the data and continue to receive.
				_, err = r.receiveBuffer.Write(data)
				if err != nil {
					return err
				}
				continue
			}
			// End of packet.
			_, err = r.receiveBuffer.Write(data[:i])
			if err != nil {
				return err
			}
		} else {
			c, err := r.ReadRegister(RXFIFO)
			if err != nil {
				return err
			}
			if c != 0 {
				err = r.receiveBuffer.WriteByte(c)
				if err != nil {
					return err
				}
				continue
			}
		}
		// End of packet.
		rssi, err := r.ReadRSSI()
		if err != nil {
			return err
		}
		size := r.receiveBuffer.Len()
		if size != 0 {
			r.stats.Packets.Received++
			r.stats.Bytes.Received += size
			p := make([]byte, size)
			_, err := r.receiveBuffer.Read(p)
			if err != nil {
				return err
			}
			r.receiveBuffer.Reset()
			r.receivedPackets <- radio.Packet{Rssi: rssi, Data: p}
		}
		if verbose {
			n, _ := r.ReadNumRxBytes()
			log.Printf("received %d-byte packet in state %s; %d bytes remaining\n", size, r.State(), n)
		}
		return nil
	}
}

func (r *Radio) drainRxFifo() error {
	n, err := r.ReadNumRxBytes()
	if err == RxFifoOverflow {
		// Flush RX FIFO and change back to RX.
		return r.changeState(SRX, STATE_RX)
	}
	if err != nil || n == 0 {
		return err
	}
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	switch s {
	case STATE_RX:
		log.Printf("draining %d bytes from RXFIFO\n", n)
		_, err = r.ReadBurst(RXFIFO, int(n))
		return err
	default:
		return fmt.Errorf("unexpected %s state during RXFIFO drain", StateName(s))
	}
}

func (r *Radio) changeState(strobe byte, desired byte) error {
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	if verbose && s != desired {
		log.Printf("change from %s to %s\n", StateName(s), StateName(desired))
	}
	for {
		switch s {
		case desired:
			return nil
		case STATE_RXFIFO_OVERFLOW:
			s, err = r.Strobe(SFRX)
		case STATE_TXFIFO_UNDERFLOW:
			s, err = r.Strobe(SFTX)
		default:
			s, err = r.Strobe(strobe)
		}
		if err != nil {
			return err
		}
		s = (s >> STATE_SHIFT) & STATE_MASK
		if verbose {
			log.Printf("  %s\n", StateName(s))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Openprovider Authors. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

/*
Package rates 0.0.4
This package helps to manage exchange rates from any provider

Example 1: Get all exchange rates for the ECB Provider

    package main

    import (
        "fmt"

        "github.com/openprovider/rates"
        "github.com/openprovider/rates/providers"
    )

    func main() {
        registry := rates.Registry{
            // any collection of providers which implement rates.Provider interface
            providers.NewECBProvider(new(rates.Options)),
        }
        service := rates.New(registry)
        rates, errors := service.FetchLast()
        if len(errors) != 0 {
            fmt.Println(errors)
        }
        fmt.Println("European Central Bank exchange rates for today")
        for index, rate := range rates {
            fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
        }
    }

Example 2: Get exchange rates for EUR, USD, CHF, HKD

	package main

	import (
		"fmt"

		"github.com/openprovider/rates"
		"github.com/openprovider/rates/providers"
	)

	func main() {
		registry := rates.Registry{
			// any collection of providers which implement rates.Provider interface
			providers.NewECBProvider(
				&rates.Options{
					Currencies: []string{
						providers.EUR,
						providers.USD,
						providers.CHF,
						providers.HKD,
					},
				},
			),
		}
		service := rates.New(registry)
		rates, errors := service.FetchLast()
		if len(errors) != 0 {
			fmt.Println(errors)
		}
		fmt.Println("European Central Bank exchange rates for today")
		for index, rate := range rates {
			fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
		}
	}

Exchange Rates Provider
*/
package rates

import (
	"time"

	"golang.org/x/text/currency"
)

// Rate represent date and currency exchange rates
type Rate struct {
	ID       uint64        `json:"id,omitempty"`
	Date     string        `json:"date"`
	Currency string        `json:"currency"`
	Time     time.Time     `json:"-"`
	Base     currency.Unit `json:"-"`
	Unit     currency.Unit `json:"-"`
	Value    interface{}   `json:"value"`
}

// Options is some specific things for the specific provider
// It should configure the provider to manage currencies
type Options struct {
	// API key/token
	Token string
	// List of the currencies which need to get from the provider
	// If it is empty, should get all of existing currencies from the provider
	Currencies []string
	// Flexible settings list
	Settings map[string]interface{}
}

// Provider holds methods for providers which implement this interface
type Provider interface {
	FetchLast() (rates []Rate, errors []error)
	FetchHistory() (rates []Rate, errors []error)
}

// Registry contains registered providers
type Registry []Provider

// New service which contains registered providers
func New(providers ...Provider) Provider {
	var registry Registry
	for _, provider := range providers {
		registry = append(registry, provider)
	}
	return registry
}

// FetchLast returns exchange rates from all registered providers on last day
func (registry Registry) FetchLast() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchLast()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}

// FetchHistory returns exchange rates from all registered providers from history
func (registry Registry) FetchHistory() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchHistory()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}
<commit_msg>Bumped version number to 0.1.0<commit_after>// Copyright 2016 Openprovider Authors. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

/*
Package rates 0.1.0
This package helps to manage exchange rates from any provider

Example 1: Get all exchange rates for the ECB Provider

    package main

    import (
        "fmt"

        "github.com/openprovider/rates"
        "github.com/openprovider/rates/providers"
    )

    func main() {
        registry := rates.Registry{
            // any collection of providers which implement rates.Provider interface
            providers.NewECBProvider(new(rates.Options)),
        }
        service := rates.New(registry)
        rates, errors := service.FetchLast()
        if len(errors) != 0 {
            fmt.Println(errors)
        }
        fmt.Println("European Central Bank exchange rates for today")
        for index, rate := range rates {
            fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
        }
    }

Example 2: Get exchange rates for EUR, USD, CHF, HKD

	package main

	import (
		"fmt"

		"github.com/openprovider/rates"
		"github.com/openprovider/rates/providers"
	)

	func main() {
		registry := rates.Registry{
			// any collection of providers which implement rates.Provider interface
			providers.NewECBProvider(
				&rates.Options{
					Currencies: []string{
						providers.EUR,
						providers.USD,
						providers.CHF,
						providers.HKD,
					},
				},
			),
		}
		service := rates.New(registry)
		rates, errors := service.FetchLast()
		if len(errors) != 0 {
			fmt.Println(errors)
		}
		fmt.Println("European Central Bank exchange rates for today")
		for index, rate := range rates {
			fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
		}
	}

Exchange Rates Provider
*/
package rates

import (
	"time"

	"golang.org/x/text/currency"
)

// Rate represent date and currency exchange rates
type Rate struct {
	ID       uint64        `json:"id,omitempty"`
	Date     string        `json:"date"`
	Currency string        `json:"currency"`
	Time     time.Time     `json:"-"`
	Base     currency.Unit `json:"-"`
	Unit     currency.Unit `json:"-"`
	Value    interface{}   `json:"value"`
}

// Options is some specific things for the specific provider
// It should configure the provider to manage currencies
type Options struct {
	// API key/token
	Token string
	// List of the currencies which need to get from the provider
	// If it is empty, should get all of existing currencies from the provider
	Currencies []string
	// Flexible settings list
	Settings map[string]interface{}
}

// Provider holds methods for providers which implement this interface
type Provider interface {
	FetchLast() (rates []Rate, errors []error)
	FetchHistory() (rates []Rate, errors []error)
}

// Registry contains registered providers
type Registry []Provider

// New service which contains registered providers
func New(providers ...Provider) Provider {
	var registry Registry
	for _, provider := range providers {
		registry = append(registry, provider)
	}
	return registry
}

// FetchLast returns exchange rates from all registered providers on last day
func (registry Registry) FetchLast() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchLast()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}

// FetchHistory returns exchange rates from all registered providers from history
func (registry Registry) FetchHistory() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchHistory()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}
<|endoftext|>


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

package cacher

import (
	"github.com/garyburd/redigo/redis"
	"github.com/jelmersnoeck/cacher/internal/numbers"
)

// RedisCache is a caching implementation that stores the data in memory. The
// cache will be emptied when the application has run.
type RedisCache struct {
	client redis.Conn
}

// NewRedisCache creates a new instance of RedisCache and initiates the
// storage map.
func NewRedisCache(client redis.Conn) *RedisCache {
	cache := new(RedisCache)
	cache.client = client

	return cache
}

// Add an item to the cache. If the item is already cached, the value won't be
// overwritten.
//
// ttl defines the number of seconds the value should be cached. If ttl is 0,
// the item will be cached infinitely.
func (c *RedisCache) Add(key string, value []byte, ttl int64) bool {
	if c.exists(key) {
		return false
	}

	return c.Set(key, value, ttl)
}

// Set sets the value of an item, regardless of wether or not the value is
// already cached.
//
// ttl defines the number of seconds the value should be cached. If ttl is 0,
// the item will be cached infinitely.
func (c *RedisCache) Set(key string, value []byte, ttl int64) bool {
	if ttl > 0 {
		c.client.Do("SETEX", key, ttl, value)
	} else {
		c.client.Do("SET", key, value)
	}

	return true
}

// SetMulti sets multiple values for their respective keys. This is a shorthand
// to use `Set` multiple times.
func (c *RedisCache) SetMulti(items map[string][]byte, ttl int64) map[string]bool {
	results := make(map[string]bool)

	for key, value := range items {
		results[key] = c.Set(key, value, ttl)
	}

	return results
}

// Replace will update and only update the value of a cache key. If the key is
// not previously used, we will return false.
func (c *RedisCache) Replace(key string, value []byte, ttl int64) bool {
	if !c.exists(key) {
		return false
	}

	return c.Set(key, value, ttl)
}

// Get gets the value out of the map associated with the provided key.
func (c *RedisCache) Get(key string) ([]byte, bool) {
	value, _ := c.client.Do("GET", key)
	val, ok := value.([]byte)

	if !ok {
		return nil, false
	}

	return val, true
}

// GetMulti gets multiple values from the cache and returns them as a map. It
// uses `Get` internally to retrieve the data.
func (c *RedisCache) GetMulti(keys []string) map[string][]byte {
	items := make(map[string][]byte)

	for _, key := range keys {
		items[key], _ = c.Get(key)
	}

	return items
}

// Increment adds a value of offset to the initial value. If the initial value
// is already set, it will be added to the value currently stored in the cache.
func (c *RedisCache) Increment(key string, initial, offset, ttl int64) bool {
	if initial < 0 || offset <= 0 {
		return false
	}

	return c.incrementOffset(key, initial, offset, ttl)
}

// Decrement subtracts a value of offset to the initial value. If the initial
// value is already set, it will be added to the value currently stored in the
// cache.
func (c *RedisCache) Decrement(key string, initial, offset, ttl int64) bool {
	if initial < 0 || offset <= 0 {
		return false
	}

	return c.incrementOffset(key, initial, offset*-1, ttl)
}

// Flush will remove all the items from the hash.
func (c *RedisCache) Flush() bool {
	c.client.Do("FLUSHDB")

	return true
}

// Delete will validate if the key actually is stored in the cache. If it is
// stored, it will remove the item from the cache. If it is not stored, it will
// return false.
func (c *RedisCache) Delete(key string) bool {
	_, err := c.client.Do("DEL", key)

	if err != nil {
		return false
	}

	return true
}

// DeleteMulti will delete multiple values at a time. It uses the `Delete`
// method internally to do so. It will return a map of results to see if the
// deletion is successful.
func (c *RedisCache) DeleteMulti(keys []string) map[string]bool {
	results := make(map[string]bool)

	for _, v := range keys {
		results[v] = c.Delete(v)
	}

	return results
}

// incrementOffset is a common incrementor method used between Increment and
// Decrement. If the key isn't set before, we will set the initial value. If
// there is a value present, we will add the given offset to that value and
// update the value with the new TTL.
func (c *RedisCache) incrementOffset(key string, initial, offset, ttl int64) bool {
	c.client.Do("WATCH", key)

	if !c.exists(key) {
		c.client.Do("MULTI")
		defer c.client.Do("EXEC")
		return c.Set(key, numbers.Int64Bytes(initial), ttl)
	}

	getValue, _ := c.Get(key)
	val, ok := numbers.BytesInt64(getValue)

	if !ok {
		return false
	}

	c.client.Do("MULTI")
	defer c.client.Do("EXEC")

	val += offset
	if val < 0 {
		return false
	}

	return c.Set(key, numbers.Int64Bytes(val), ttl)
}

func (c *RedisCache) exists(key string) bool {
	val, _ := c.client.Do("EXISTS", key)

	if val.(int64) == 1 {
		return true
	}

	return false
}
<commit_msg>Redis: use MGET to get multiple keys.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found
// in the LICENSE file.

package cacher

import (
	"github.com/garyburd/redigo/redis"
	"github.com/jelmersnoeck/cacher/internal/numbers"
)

// RedisCache is a caching implementation that stores the data in memory. The
// cache will be emptied when the application has run.
type RedisCache struct {
	client redis.Conn
}

// NewRedisCache creates a new instance of RedisCache and initiates the
// storage map.
func NewRedisCache(client redis.Conn) *RedisCache {
	cache := new(RedisCache)
	cache.client = client

	return cache
}

// Add an item to the cache. If the item is already cached, the value won't be
// overwritten.
//
// ttl defines the number of seconds the value should be cached. If ttl is 0,
// the item will be cached infinitely.
func (c *RedisCache) Add(key string, value []byte, ttl int64) bool {
	if c.exists(key) {
		return false
	}

	return c.Set(key, value, ttl)
}

// Set sets the value of an item, regardless of wether or not the value is
// already cached.
//
// ttl defines the number of seconds the value should be cached. If ttl is 0,
// the item will be cached infinitely.
func (c *RedisCache) Set(key string, value []byte, ttl int64) bool {
	if ttl > 0 {
		c.client.Do("SETEX", key, ttl, value)
	} else {
		c.client.Do("SET", key, value)
	}

	return true
}

// SetMulti sets multiple values for their respective keys. This is a shorthand
// to use `Set` multiple times.
func (c *RedisCache) SetMulti(items map[string][]byte, ttl int64) map[string]bool {
	results := make(map[string]bool)

	for key, value := range items {
		results[key] = c.Set(key, value, ttl)
	}

	return results
}

// Replace will update and only update the value of a cache key. If the key is
// not previously used, we will return false.
func (c *RedisCache) Replace(key string, value []byte, ttl int64) bool {
	if !c.exists(key) {
		return false
	}

	return c.Set(key, value, ttl)
}

// Get gets the value out of the map associated with the provided key.
func (c *RedisCache) Get(key string) ([]byte, bool) {
	value, _ := c.client.Do("GET", key)
	val, ok := value.([]byte)

	if !ok {
		return nil, false
	}

	return val, true
}

// GetMulti gets multiple values from the cache and returns them as a map. It
// uses `Get` internally to retrieve the data.
func (c *RedisCache) GetMulti(keys []string) map[string][]byte {
	var args []interface{}
	for _, key := range keys {
		args = append(args, key)
	}

	cValues, err := c.client.Do("MGET", args...)
	items := make(map[string][]byte)

	if err == nil {
		values := cValues.([]interface{})
		for i, val := range values {
			items[keys[i]] = val.([]byte)
		}
	}

	return items
}

// Increment adds a value of offset to the initial value. If the initial value
// is already set, it will be added to the value currently stored in the cache.
func (c *RedisCache) Increment(key string, initial, offset, ttl int64) bool {
	if initial < 0 || offset <= 0 {
		return false
	}

	return c.incrementOffset(key, initial, offset, ttl)
}

// Decrement subtracts a value of offset to the initial value. If the initial
// value is already set, it will be added to the value currently stored in the
// cache.
func (c *RedisCache) Decrement(key string, initial, offset, ttl int64) bool {
	if initial < 0 || offset <= 0 {
		return false
	}

	return c.incrementOffset(key, initial, offset*-1, ttl)
}

// Flush will remove all the items from the hash.
func (c *RedisCache) Flush() bool {
	c.client.Do("FLUSHDB")

	return true
}

// Delete will validate if the key actually is stored in the cache. If it is
// stored, it will remove the item from the cache. If it is not stored, it will
// return false.
func (c *RedisCache) Delete(key string) bool {
	_, err := c.client.Do("DEL", key)

	if err != nil {
		return false
	}

	return true
}

// DeleteMulti will delete multiple values at a time. It uses the `Delete`
// method internally to do so. It will return a map of results to see if the
// deletion is successful.
func (c *RedisCache) DeleteMulti(keys []string) map[string]bool {
	results := make(map[string]bool)

	for _, v := range keys {
		results[v] = c.Delete(v)
	}

	return results
}

// incrementOffset is a common incrementor method used between Increment and
// Decrement. If the key isn't set before, we will set the initial value. If
// there is a value present, we will add the given offset to that value and
// update the value with the new TTL.
func (c *RedisCache) incrementOffset(key string, initial, offset, ttl int64) bool {
	c.client.Do("WATCH", key)

	if !c.exists(key) {
		c.client.Do("MULTI")
		defer c.client.Do("EXEC")
		return c.Set(key, numbers.Int64Bytes(initial), ttl)
	}

	getValue, _ := c.Get(key)
	val, ok := numbers.BytesInt64(getValue)

	if !ok {
		return false
	}

	c.client.Do("MULTI")
	defer c.client.Do("EXEC")

	val += offset
	if val < 0 {
		return false
	}

	return c.Set(key, numbers.Int64Bytes(val), ttl)
}

func (c *RedisCache) exists(key string) bool {
	val, _ := c.client.Do("EXISTS", key)

	if val.(int64) == 1 {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package easyss

import (
	"io"
	"net"
	"time"

	"github.com/nange/easypool"
	"github.com/nange/easyss/cipherstream"
	"github.com/nange/easyss/util"
	log "github.com/sirupsen/logrus"
)

var connStateBytes = util.NewBytes(32)

// relay copies between cipher stream and plaintext stream.
// return the number of bytes copies
// from plaintext stream to cipher stream, from cipher stream to plaintext stream, and needClose on server conn
func relay(cipher, plaintxt io.ReadWriteCloser) (n1 int64, n2 int64, needClose bool) {
	type res struct {
		N   int64
		Err error
	}
	ch1 := make(chan res, 1)
	ch2 := make(chan res, 1)

	go func() {
		n, err := io.Copy(plaintxt, cipher)
		ch2 <- res{N: n, Err: err}
	}()
	go func() {
		n, err := io.Copy(cipher, plaintxt)
		ch1 <- res{N: n, Err: err}
	}()

	var state *ConnState
	for i := 0; i < 2; i++ {
		select {
		case res1 := <-ch1:
			expireConn(cipher)
			n1 = res1.N
			err := res1.Err
			if cipherstream.EncryptErr(err) || cipherstream.WriteCipherErr(err) {
				log.Debugf("io.Copy err:%+v, maybe underline connection has been closed", err)
				markCipherStreamUnusable(cipher)
				continue
			}

			if i == 0 {
				log.Debugf("read plaintxt stream error, set start state. details:%v", err)
				buf := connStateBytes.Get(32)
				defer connStateBytes.Put(buf)
				state = NewConnState(FIN_WAIT1, buf)
			} else if err != nil {
				if !cipherstream.TimeoutErr(err) {
					log.Errorf("execpt error is net: io timeout. but get:%v", err)
				}
			}

		case res2 := <-ch2:
			expireConn(plaintxt)
			n2 = res2.N
			err := res2.Err
			if cipherstream.DecryptErr(err) || cipherstream.ReadCipherErr(err) {
				log.Debugf("io.Copy err:%+v, maybe underline connection has been closed", err)
				markCipherStreamUnusable(cipher)
				continue
			}

			if i == 0 {
				if cipherstream.FINRSTStreamErr(err) {
					log.Debugf("read cipher stream ErrFINRSTStream, set start state")
					buf := connStateBytes.Get(32)
					defer connStateBytes.Put(buf)
					state = NewConnState(CLOSE_WAIT, buf)
				} else {
					log.Errorf("execpt error is ErrFINRSTStream, but get:%v", err)
					markCipherStreamUnusable(cipher)
				}
			} else if err != nil {
				if !cipherstream.TimeoutErr(err) {
					log.Errorf("execpt error is net: io timeout. but get:%v", err)
				}
			}

		}
	}

	if cipherStreamUnusable(cipher) {
		needClose = true
		return
	}

	setCipherDeadline(cipher)
	if state == nil {
		log.Warnf("unexcepted state, some unexcepted error occor, maybe client connection is closed")
		needClose = true
		return
	}
	for stateFn := state.fn; stateFn != nil; {
		stateFn = stateFn(cipher).fn
	}
	if state.err != nil {
		log.Warnf("state err:%+v, state:%v", state.err, state.state)
		markCipherStreamUnusable(cipher)
		needClose = true
	}

	return
}

// mark the cipher stream unusable, return mark result
func markCipherStreamUnusable(cipher io.ReadWriteCloser) bool {
	if cs, ok := cipher.(*cipherstream.CipherStream); ok {
		if pc, ok := cs.ReadWriteCloser.(*easypool.PoolConn); ok {
			log.Debugf("mark cipher stream unusable")
			pc.MarkUnusable()
			return true
		}
	}
	return false
}

// return true if the cipher stream is unusable
func cipherStreamUnusable(cipher io.ReadWriteCloser) bool {
	if cs, ok := cipher.(*cipherstream.CipherStream); ok {
		if pc, ok := cs.ReadWriteCloser.(*easypool.PoolConn); ok {
			return pc.IsUnusable()
		}
	}
	return false
}

func expireConn(conn io.ReadWriteCloser) {
	if conn, ok := conn.(net.Conn); ok {
		log.Debugf("expire the plaintxt tcp connection to make the reader to be failed immediately")
		conn.SetDeadline(time.Unix(0, 0))
		return
	}

	if cs, ok := conn.(*cipherstream.CipherStream); ok {
		if conn, ok := cs.ReadWriteCloser.(net.Conn); ok {
			log.Debugf("expire the cipher tcp connection to make the reader to be failed immediately")
			conn.SetDeadline(time.Unix(0, 0))
		}
	}
}

func setCipherDeadline(cipher io.ReadWriteCloser) {
	if cs, ok := cipher.(*cipherstream.CipherStream); ok {
		if conn, ok := cs.ReadWriteCloser.(net.Conn); ok {
			log.Debugf("set cipher tcp connection deadline to 30 second later")
			conn.SetDeadline(time.Now().Add(30 * time.Second))
		}
	}
}
<commit_msg>relay: update log-level print<commit_after>package easyss

import (
	"io"
	"net"
	"time"

	"github.com/nange/easypool"
	"github.com/nange/easyss/cipherstream"
	"github.com/nange/easyss/util"
	log "github.com/sirupsen/logrus"
)

var connStateBytes = util.NewBytes(32)

// relay copies between cipher stream and plaintext stream.
// return the number of bytes copies
// from plaintext stream to cipher stream, from cipher stream to plaintext stream, and needClose on server conn
func relay(cipher, plaintxt io.ReadWriteCloser) (n1 int64, n2 int64, needClose bool) {
	type res struct {
		N   int64
		Err error
	}
	ch1 := make(chan res, 1)
	ch2 := make(chan res, 1)

	go func() {
		n, err := io.Copy(plaintxt, cipher)
		ch2 <- res{N: n, Err: err}
	}()
	go func() {
		n, err := io.Copy(cipher, plaintxt)
		ch1 <- res{N: n, Err: err}
	}()

	var state *ConnState
	for i := 0; i < 2; i++ {
		select {
		case res1 := <-ch1:
			expireConn(cipher)
			n1 = res1.N
			err := res1.Err
			if cipherstream.EncryptErr(err) || cipherstream.WriteCipherErr(err) {
				log.Debugf("io.Copy err:%+v, maybe underline connection has been closed", err)
				markCipherStreamUnusable(cipher)
				continue
			}

			if i == 0 {
				log.Debugf("read plaintxt stream error, set start state. details:%v", err)
				buf := connStateBytes.Get(32)
				defer connStateBytes.Put(buf)
				state = NewConnState(FIN_WAIT1, buf)
			} else if err != nil {
				if !cipherstream.TimeoutErr(err) {
					log.Errorf("execpt error is net: io timeout. but get:%v", err)
				}
			}

		case res2 := <-ch2:
			expireConn(plaintxt)
			n2 = res2.N
			err := res2.Err
			if cipherstream.DecryptErr(err) || cipherstream.ReadCipherErr(err) {
				log.Debugf("io.Copy err:%+v, maybe underline connection has been closed", err)
				markCipherStreamUnusable(cipher)
				continue
			}

			if i == 0 {
				if cipherstream.FINRSTStreamErr(err) {
					log.Debugf("read cipher stream ErrFINRSTStream, set start state")
					buf := connStateBytes.Get(32)
					defer connStateBytes.Put(buf)
					state = NewConnState(CLOSE_WAIT, buf)
				} else {
					log.Errorf("execpt error is ErrFINRSTStream, but get:%v", err)
					markCipherStreamUnusable(cipher)
				}
			} else if err != nil {
				if !cipherstream.TimeoutErr(err) {
					log.Errorf("execpt error is net: io timeout. but get:%v", err)
				}
			}

		}
	}

	if cipherStreamUnusable(cipher) {
		needClose = true
		return
	}

	setCipherDeadline(cipher)
	if state == nil {
		log.Infof("unexcepted state, some unexcepted error occor, maybe client connection is closed")
		needClose = true
		return
	}
	for stateFn := state.fn; stateFn != nil; {
		stateFn = stateFn(cipher).fn
	}
	if state.err != nil {
		log.Infof("state err:%v, state:%v", state.err, state.state)
		markCipherStreamUnusable(cipher)
		needClose = true
	}

	return
}

// mark the cipher stream unusable, return mark result
func markCipherStreamUnusable(cipher io.ReadWriteCloser) bool {
	if cs, ok := cipher.(*cipherstream.CipherStream); ok {
		if pc, ok := cs.ReadWriteCloser.(*easypool.PoolConn); ok {
			log.Debugf("mark cipher stream unusable")
			pc.MarkUnusable()
			return true
		}
	}
	return false
}

// return true if the cipher stream is unusable
func cipherStreamUnusable(cipher io.ReadWriteCloser) bool {
	if cs, ok := cipher.(*cipherstream.CipherStream); ok {
		if pc, ok := cs.ReadWriteCloser.(*easypool.PoolConn); ok {
			return pc.IsUnusable()
		}
	}
	return false
}

func expireConn(conn io.ReadWriteCloser) {
	if conn, ok := conn.(net.Conn); ok {
		log.Debugf("expire the plaintxt tcp connection to make the reader to be failed immediately")
		conn.SetDeadline(time.Unix(0, 0))
		return
	}

	if cs, ok := conn.(*cipherstream.CipherStream); ok {
		if conn, ok := cs.ReadWriteCloser.(net.Conn); ok {
			log.Debugf("expire the cipher tcp connection to make the reader to be failed immediately")
			conn.SetDeadline(time.Unix(0, 0))
		}
	}
}

func setCipherDeadline(cipher io.ReadWriteCloser) {
	if cs, ok := cipher.(*cipherstream.CipherStream); ok {
		if conn, ok := cs.ReadWriteCloser.(net.Conn); ok {
			log.Debugf("set cipher tcp connection deadline to 30 second later")
			conn.SetDeadline(time.Now().Add(30 * time.Second))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Jacques Supcik, HEIA-FR
//
// 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.

// 2015-12-29 | JS | First version

//
// Telegram bot
//

package main

import (
	"fmt"
	"github.com/tucnak/telebot"
)

const (
	maxMsgLen = 42 // The tower can show up to 21 characters (using 6x8 font).
)

var colorKeyboard = telebot.SendOptions{
	ReplyMarkup: telebot.ReplyMarkup{
		CustomKeyboard: [][]string{
			[]string{"Red", "SkyBlue"},
			[]string{"Green", "Orange"},
		},
		OneTimeKeyboard: true,
	},
}

var msgKeyboard = telebot.SendOptions{
	ReplyMarkup: telebot.ReplyMarkup{
		CustomKeyboard: [][]string{
			[]string{"I ♥ Computer Science"},
			[]string{"I ♥ Telecommunications"},
			[]string{"I ♥ HEIA-FR"},
		},
		OneTimeKeyboard: true,
	},
}

var hideKeyboard = telebot.SendOptions{
	ReplyMarkup: telebot.ReplyMarkup{
		HideCustomKeyboard: true,
	},
}

func (s *session) sayHello() {
	bot.SendMessage(s.conversation,
		fmt.Sprintf(
			"Hello %s, nice to see you. Please, enter the color for your message.",
			s.sender.FirstName),
		&colorKeyboard)
}

func (s *session) sayCanceled() {
	bot.SendMessage(s.conversation, "OK", &hideKeyboard)
}

func (s *session) sayBadColor() {
	bot.SendMessage(s.conversation,
		"I don't know this color. Please try another one.",
		&colorKeyboard)
}

func (s *session) sayGoodColor() {
	bot.SendMessage(s.conversation,
		fmt.Sprintf("Good. Now please enter your message (max %d characters).", maxMsgLen),
		&msgKeyboard)
}

func (s *session) sayTooLongText() {
	bot.SendMessage(s.conversation,
		"Your message is too long. Please try a shorter one.",
		&msgKeyboard)
}

func (s *session) sayGoodText() {
	bot.SendMessage(s.conversation,
		"Thank you. I will display your message soon.",
		&hideKeyboard)
}
<commit_msg>Update max message size<commit_after>// Copyright 2015 Jacques Supcik, HEIA-FR
//
// 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.

// 2015-12-29 | JS | First version

//
// Telegram bot
//

package main

import (
	"fmt"
	"github.com/tucnak/telebot"
)

const (
	maxMsgLen = 64 // The tower can show up to 21 characters (using 6x8 font).
)

var colorKeyboard = telebot.SendOptions{
	ReplyMarkup: telebot.ReplyMarkup{
		CustomKeyboard: [][]string{
			[]string{"Red", "SkyBlue"},
			[]string{"Green", "Orange"},
		},
		OneTimeKeyboard: true,
	},
}

var msgKeyboard = telebot.SendOptions{
	ReplyMarkup: telebot.ReplyMarkup{
		CustomKeyboard: [][]string{
			[]string{"I ♥ Computer Science"},
			[]string{"I ♥ Telecommunications"},
			[]string{"I ♥ HEIA-FR"},
		},
		OneTimeKeyboard: true,
	},
}

var hideKeyboard = telebot.SendOptions{
	ReplyMarkup: telebot.ReplyMarkup{
		HideCustomKeyboard: true,
	},
}

func (s *session) sayHello() {
	bot.SendMessage(s.conversation,
		fmt.Sprintf(
			"Hello %s, nice to see you. Please, enter the color for your message.",
			s.sender.FirstName),
		&colorKeyboard)
}

func (s *session) sayCanceled() {
	bot.SendMessage(s.conversation, "OK", &hideKeyboard)
}

func (s *session) sayBadColor() {
	bot.SendMessage(s.conversation,
		"I don't know this color. Please try another one.",
		&colorKeyboard)
}

func (s *session) sayGoodColor() {
	bot.SendMessage(s.conversation,
		fmt.Sprintf("Good. Now please enter your message (max %d characters).", maxMsgLen),
		&msgKeyboard)
}

func (s *session) sayTooLongText() {
	bot.SendMessage(s.conversation,
		"Your message is too long. Please try a shorter one.",
		&msgKeyboard)
}

func (s *session) sayGoodText() {
	bot.SendMessage(s.conversation,
		"Thank you. I will display your message soon.",
		&hideKeyboard)
}
<|endoftext|>