<commit_before>// +build !plan9

package sftp

import (
	"io"
	"os"
	"syscall"
	"time"

	"github.com/pkg/sftp"
	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/vfs"
)

// vfsHandler converts the VFS to be served by SFTP
type vfsHandler struct {
	*vfs.VFS
}

// vfsHandler returns a Handlers object with the test handlers.
func newVFSHandler(vfs *vfs.VFS) sftp.Handlers {
	v := vfsHandler{VFS: vfs}
	return sftp.Handlers{
		FileGet:  v,
		FilePut:  v,
		FileCmd:  v,
		FileList: v,
	}
}

func (v vfsHandler) Fileread(r *sftp.Request) (io.ReaderAt, error) {
	file, err := v.OpenFile(r.Filepath, os.O_RDONLY, 0777)
	if err != nil {
		return nil, err
	}
	return file, nil
}

func (v vfsHandler) Filewrite(r *sftp.Request) (io.WriterAt, error) {
	file, err := v.OpenFile(r.Filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
	if err != nil {
		return nil, err
	}
	return file, nil
}

func (v vfsHandler) Filecmd(r *sftp.Request) error {
	switch r.Method {
	case "Setstat":
		node, err := v.Stat(r.Filepath)
		if err != nil {
			return err
		}
		attr := r.Attributes()
		if attr.Mtime != 0 {
			modTime := time.Unix(int64(attr.Mtime), 0)
			err := node.SetModTime(modTime)
			if err != nil {
				return err
			}
		}
		return nil
	case "Rename":
		err := v.Rename(r.Filepath, r.Target)
		if err != nil {
			return err
		}
	case "Rmdir", "Remove":
		node, err := v.Stat(r.Filepath)
		if err != nil {
			return err
		}
		err = node.Remove()
		if err != nil {
			return err
		}
	case "Mkdir":
		dir, leaf, err := v.StatParent(r.Filepath)
		if err != nil {
			return err
		}
		_, err = dir.Mkdir(leaf)
		if err != nil {
			return err
		}
	case "Symlink":
		// FIXME
		// _, err := v.fetch(r.Filepath)
		// if err != nil {
		// 	return err
		// }
		// link := newMemFile(r.Target, false)
		// link.symlink = r.Filepath
		// v.files[r.Target] = link
	}
	return sftp.ErrSshFxOpUnsupported
}

type listerat []os.FileInfo

// Modeled after strings.Reader's ReadAt() implementation
func (f listerat) ListAt(ls []os.FileInfo, offset int64) (int, error) {
	var n int
	if offset >= int64(len(f)) {
		return 0, io.EOF
	}
	n = copy(ls, f[offset:])
	if n < len(ls) {
		return n, io.EOF
	}
	return n, nil
}

func (v vfsHandler) Filelist(r *sftp.Request) (l sftp.ListerAt, err error) {
	var node vfs.Node
	var handle vfs.Handle
	switch r.Method {
	case "List":
		node, err = v.Stat(r.Filepath)
		if err != nil {
			return nil, err
		}
		if !node.IsDir() {
			return nil, syscall.ENOTDIR
		}
		handle, err = node.Open(os.O_RDONLY)
		if err != nil {
			return nil, err
		}
		defer fs.CheckClose(handle, &err)
		fis, err := handle.Readdir(-1)
		if err != nil {
			return nil, err
		}
		return listerat(fis), nil
	case "Stat":
		node, err = v.Stat(r.Filepath)
		if err != nil {
			return nil, err
		}
		return listerat([]os.FileInfo{node}), nil
	case "Readlink":
		// FIXME
		// if file.symlink != "" {
		// 	file, err = v.fetch(file.symlink)
		// 	if err != nil {
		// 		return nil, err
		// 	}
		// }
		// return listerat([]os.FileInfo{file}), nil
	}
	return nil, sftp.ErrSshFxOpUnsupported
}
<commit_msg>sftp: fix test failures<commit_after>// +build !plan9

package sftp

import (
	"io"
	"os"
	"syscall"
	"time"

	"github.com/pkg/sftp"
	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/vfs"
)

// vfsHandler converts the VFS to be served by SFTP
type vfsHandler struct {
	*vfs.VFS
}

// vfsHandler returns a Handlers object with the test handlers.
func newVFSHandler(vfs *vfs.VFS) sftp.Handlers {
	v := vfsHandler{VFS: vfs}
	return sftp.Handlers{
		FileGet:  v,
		FilePut:  v,
		FileCmd:  v,
		FileList: v,
	}
}

func (v vfsHandler) Fileread(r *sftp.Request) (io.ReaderAt, error) {
	file, err := v.OpenFile(r.Filepath, os.O_RDONLY, 0777)
	if err != nil {
		return nil, err
	}
	return file, nil
}

func (v vfsHandler) Filewrite(r *sftp.Request) (io.WriterAt, error) {
	file, err := v.OpenFile(r.Filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
	if err != nil {
		return nil, err
	}
	return file, nil
}

func (v vfsHandler) Filecmd(r *sftp.Request) error {
	switch r.Method {
	case "Setstat":
		node, err := v.Stat(r.Filepath)
		if err != nil {
			return err
		}
		attr := r.Attributes()
		if attr.Mtime != 0 {
			modTime := time.Unix(int64(attr.Mtime), 0)
			err := node.SetModTime(modTime)
			if err != nil {
				return err
			}
		}
		return nil
	case "Rename":
		err := v.Rename(r.Filepath, r.Target)
		if err != nil {
			return err
		}
	case "Rmdir", "Remove":
		node, err := v.Stat(r.Filepath)
		if err != nil {
			return err
		}
		err = node.Remove()
		if err != nil {
			return err
		}
	case "Mkdir":
		dir, leaf, err := v.StatParent(r.Filepath)
		if err != nil {
			return err
		}
		_, err = dir.Mkdir(leaf)
		if err != nil {
			return err
		}
	case "Symlink":
		// FIXME
		// _, err := v.fetch(r.Filepath)
		// if err != nil {
		// 	return err
		// }
		// link := newMemFile(r.Target, false)
		// link.symlink = r.Filepath
		// v.files[r.Target] = link
		return sftp.ErrSshFxOpUnsupported
	}
	return nil
}

type listerat []os.FileInfo

// Modeled after strings.Reader's ReadAt() implementation
func (f listerat) ListAt(ls []os.FileInfo, offset int64) (int, error) {
	var n int
	if offset >= int64(len(f)) {
		return 0, io.EOF
	}
	n = copy(ls, f[offset:])
	if n < len(ls) {
		return n, io.EOF
	}
	return n, nil
}

func (v vfsHandler) Filelist(r *sftp.Request) (l sftp.ListerAt, err error) {
	var node vfs.Node
	var handle vfs.Handle
	switch r.Method {
	case "List":
		node, err = v.Stat(r.Filepath)
		if err != nil {
			return nil, err
		}
		if !node.IsDir() {
			return nil, syscall.ENOTDIR
		}
		handle, err = node.Open(os.O_RDONLY)
		if err != nil {
			return nil, err
		}
		defer fs.CheckClose(handle, &err)
		fis, err := handle.Readdir(-1)
		if err != nil {
			return nil, err
		}
		return listerat(fis), nil
	case "Stat":
		node, err = v.Stat(r.Filepath)
		if err != nil {
			return nil, err
		}
		return listerat([]os.FileInfo{node}), nil
	case "Readlink":
		// FIXME
		// if file.symlink != "" {
		// 	file, err = v.fetch(file.symlink)
		// 	if err != nil {
		// 		return nil, err
		// 	}
		// }
		// return listerat([]os.FileInfo{file}), nil
	}
	return nil, sftp.ErrSshFxOpUnsupported
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"context"
	"errors"
	"github.com/kobtea/go-todoist/cmd/util"
	"github.com/kobtea/go-todoist/todoist"
	"github.com/spf13/cobra"
	"strconv"
	"strings"
)

// filterCmd represents the filter command
var filterCmd = &cobra.Command{
	Use:   "filter",
	Short: "subcommand for filter",
}

var filterListCmd = &cobra.Command{
	Use:   "list",
	Short: "list filters",
	RunE: func(cmd *cobra.Command, args []string) error {
		client, err := util.NewClient()
		if err != nil {
			return err
		}
		filters := client.Filter.GetAll()
		fmt.Println(util.FilterTableString(filters))
		return nil
	},
}

var filterAddCmd = &cobra.Command{
	Use:   "add",
	Short: "add filter",
	RunE: func(cmd *cobra.Command, args []string) error {
		client, err := util.NewClient()
		if err != nil {
			return err
		}
		name := strings.Join(args, " ")
		query, err := cmd.Flags().GetString("query")
		if err != nil {
			return err
		}
		filter := todoist.Filter{
			Name:  name,
			Query: query,
		}
		colorStr, err := cmd.Flags().GetString("color")
		if err != nil {
			return errors.New("Invalid filter color")
		}
		if len(colorStr) > 0 {
			color, err := strconv.Atoi(colorStr)
			if err != nil {
				return fmt.Errorf("Invalid filter color: %s", colorStr)
			}
			filter.Color = color
		}
		if _, err = client.Filter.Add(filter); err != nil {
			return err
		}
		ctx := context.Background()
		if err = client.Commit(ctx); err != nil {
			return err
		}
		if err = client.FullSync(ctx, []todoist.Command{}); err != nil {
			return err
		}
		filters := client.Filter.FindByName(name)
		if len(filters) == 0 {
			return errors.New("Failed to add this filter. It may be failed to sync.")
		}
		syncedFilter := filters[len(filters)-1]
		fmt.Println("Successful addition of a filter.")
		fmt.Println(util.FilterTableString([]todoist.Filter{syncedFilter}))
		return nil
	},
}

var filterUpdateCmd = &cobra.Command{
	Use:   "update id [new_name]",
	Short: "update filter",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return errors.New("Require filter ID to update")
		}
		id, err := todoist.NewID(args[0])
		if err != nil {
			return fmt.Errorf("Invalid ID: %s", args[0])
		}
		client, err := util.NewClient()
		if err != nil {
			return err
		}
		filter := client.Filter.Resolve(id)
		if filter == nil {
			return fmt.Errorf("No such filter id: %s", id)
		}
		if len(args) > 1 {
			filter.Name = strings.Join(args[1:], " ")
		}
		query, err := cmd.Flags().GetString("query")
		if err != nil {
			return err
		}
		if len(query) > 0 {
			filter.Query = query
		}
		colorStr, err := cmd.Flags().GetString("color")
		if err != nil {
			return errors.New("Invalid filter color")
		}
		if len(colorStr) > 0 {
			color, err := strconv.Atoi(colorStr)
			if err != nil {
				return fmt.Errorf("Invalid filter color: %s", colorStr)
			}
			filter.Color = color
		}
		if _, err = client.Filter.Update(*filter); err != nil {
			return err
		}
		ctx := context.Background()
		if err = client.Commit(ctx); err != nil {
			return err
		}
		if err = client.FullSync(ctx, []todoist.Command{}); err != nil {
			return err
		}
		syncedFilter := client.Filter.Resolve(id)
		if syncedFilter == nil {
			return errors.New("Failed to add this filter. It may be failed to sync.")
		}
		fmt.Println("Successful updating filter.")
		fmt.Println(util.FilterTableString([]todoist.Filter{*syncedFilter}))
		return nil
	},
}

var filterDeleteCmd = &cobra.Command{
	Use:   "delete id [...]",
	Short: "delete filters",
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := util.AutoCommit(func(client todoist.Client, ctx context.Context) error {
			return util.ProcessIDs(
				args,
				func(ids []todoist.ID) error {
					for _, id := range ids {
						if err := client.Filter.Delete(id); err != nil {
							return err
						}
					}
					return nil
				})
		}); err != nil {
			return err
		}
		fmt.Println("Successful deleting of filter(s).")
		return nil
	},
}

func init() {
	RootCmd.AddCommand(filterCmd)
	filterCmd.AddCommand(filterListCmd)
	filterAddCmd.Flags().StringP("query", "q", "", "query")
	filterAddCmd.Flags().StringP("color", "c", "12", "color")
	filterCmd.AddCommand(filterAddCmd)
	filterUpdateCmd.Flags().StringP("query", "q", "", "query")
	filterUpdateCmd.Flags().StringP("color", "c", "", "color")
	filterCmd.AddCommand(filterUpdateCmd)
	filterCmd.AddCommand(filterDeleteCmd)
}
<commit_msg>confirm when deleting filters<commit_after>package cmd

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"github.com/kobtea/go-todoist/cmd/util"
	"github.com/kobtea/go-todoist/todoist"
	"github.com/spf13/cobra"
	"os"
	"strconv"
	"strings"
)

// filterCmd represents the filter command
var filterCmd = &cobra.Command{
	Use:   "filter",
	Short: "subcommand for filter",
}

var filterListCmd = &cobra.Command{
	Use:   "list",
	Short: "list filters",
	RunE: func(cmd *cobra.Command, args []string) error {
		client, err := util.NewClient()
		if err != nil {
			return err
		}
		filters := client.Filter.GetAll()
		fmt.Println(util.FilterTableString(filters))
		return nil
	},
}

var filterAddCmd = &cobra.Command{
	Use:   "add",
	Short: "add filter",
	RunE: func(cmd *cobra.Command, args []string) error {
		client, err := util.NewClient()
		if err != nil {
			return err
		}
		name := strings.Join(args, " ")
		query, err := cmd.Flags().GetString("query")
		if err != nil {
			return err
		}
		filter := todoist.Filter{
			Name:  name,
			Query: query,
		}
		colorStr, err := cmd.Flags().GetString("color")
		if err != nil {
			return errors.New("Invalid filter color")
		}
		if len(colorStr) > 0 {
			color, err := strconv.Atoi(colorStr)
			if err != nil {
				return fmt.Errorf("Invalid filter color: %s", colorStr)
			}
			filter.Color = color
		}
		if _, err = client.Filter.Add(filter); err != nil {
			return err
		}
		ctx := context.Background()
		if err = client.Commit(ctx); err != nil {
			return err
		}
		if err = client.FullSync(ctx, []todoist.Command{}); err != nil {
			return err
		}
		filters := client.Filter.FindByName(name)
		if len(filters) == 0 {
			return errors.New("Failed to add this filter. It may be failed to sync.")
		}
		syncedFilter := filters[len(filters)-1]
		fmt.Println("Successful addition of a filter.")
		fmt.Println(util.FilterTableString([]todoist.Filter{syncedFilter}))
		return nil
	},
}

var filterUpdateCmd = &cobra.Command{
	Use:   "update id [new_name]",
	Short: "update filter",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return errors.New("Require filter ID to update")
		}
		id, err := todoist.NewID(args[0])
		if err != nil {
			return fmt.Errorf("Invalid ID: %s", args[0])
		}
		client, err := util.NewClient()
		if err != nil {
			return err
		}
		filter := client.Filter.Resolve(id)
		if filter == nil {
			return fmt.Errorf("No such filter id: %s", id)
		}
		if len(args) > 1 {
			filter.Name = strings.Join(args[1:], " ")
		}
		query, err := cmd.Flags().GetString("query")
		if err != nil {
			return err
		}
		if len(query) > 0 {
			filter.Query = query
		}
		colorStr, err := cmd.Flags().GetString("color")
		if err != nil {
			return errors.New("Invalid filter color")
		}
		if len(colorStr) > 0 {
			color, err := strconv.Atoi(colorStr)
			if err != nil {
				return fmt.Errorf("Invalid filter color: %s", colorStr)
			}
			filter.Color = color
		}
		if _, err = client.Filter.Update(*filter); err != nil {
			return err
		}
		ctx := context.Background()
		if err = client.Commit(ctx); err != nil {
			return err
		}
		if err = client.FullSync(ctx, []todoist.Command{}); err != nil {
			return err
		}
		syncedFilter := client.Filter.Resolve(id)
		if syncedFilter == nil {
			return errors.New("Failed to add this filter. It may be failed to sync.")
		}
		fmt.Println("Successful updating filter.")
		fmt.Println(util.FilterTableString([]todoist.Filter{*syncedFilter}))
		return nil
	},
}

var filterDeleteCmd = &cobra.Command{
	Use:   "delete id [...]",
	Short: "delete filters",
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := util.AutoCommit(func(client todoist.Client, ctx context.Context) error {
			return util.ProcessIDs(
				args,
				func(ids []todoist.ID) error {
					var filters []todoist.Filter
					for _, id := range ids {
						filter := client.Filter.Resolve(id)
						if filter == nil {
							return fmt.Errorf("invalid id: %s", id)
						}
						filters = append(filters, *filter)
					}
					fmt.Println(util.FilterTableString(filters))

					reader := bufio.NewReader(os.Stdin)
					fmt.Print("are you sure to delete above filter(s)? (y/[n]): ")
					ans, err := reader.ReadString('\n')
					if ans != "y\n" || err != nil {
						fmt.Println("abort")
						return errors.New("abort")
					}
					for _, id := range ids {
						if err := client.Filter.Delete(id); err != nil {
							return err
						}
					}
					return nil
				})
		}); err != nil {
			if err.Error() == "abort" {
				return nil
			}
			return err
		}
		fmt.Println("Successful deleting of filter(s).")
		return nil
	},
}

func init() {
	RootCmd.AddCommand(filterCmd)
	filterCmd.AddCommand(filterListCmd)
	filterAddCmd.Flags().StringP("query", "q", "", "query")
	filterAddCmd.Flags().StringP("color", "c", "12", "color")
	filterCmd.AddCommand(filterAddCmd)
	filterUpdateCmd.Flags().StringP("query", "q", "", "query")
	filterUpdateCmd.Flags().StringP("color", "c", "", "color")
	filterCmd.AddCommand(filterUpdateCmd)
	filterCmd.AddCommand(filterDeleteCmd)
}
<|endoftext|>


<commit_before>package scaling_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"lib/models"
	"lib/policy_client"
	"lib/testsupport"
	"math/rand"
	"net"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"code.cloudfoundry.org/lager/lagertest"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/pivotal-cf-experimental/rainmaker"
)

const Timeout_Check = 20 * time.Minute

// 3 * observed agent total poll time with 200 containers per cell
const Policy_Update_Wait = 180 * time.Second

var ports []int

var _ = Describe("connectivity between containers on the overlay network", func() {
	Describe("networking policy", func() {
		var (
			appProxy       string
			appRegistry    string
			appsTest       []string
			appInstances   int
			applications   int
			proxyInstances int
			sampleSize     int
		)

		BeforeEach(func() {
			appInstances = pushConfig.AppInstances
			applications = pushConfig.Applications
			proxyInstances = pushConfig.ProxyInstances
			sampleSize = pushConfig.SampleSize
			appProxy = pushConfig.Prefix + "proxy"
			appRegistry = pushConfig.Prefix + "registry"
			for i := 0; i < applications; i++ {
				appsTest = append(appsTest, fmt.Sprintf(pushConfig.Prefix+"tick-%d", i))
			}

			ports = []int{8080}
			for i := 0; i < pushConfig.ExtraListenPorts; i++ {
				ports = append(ports, 7000+i)
			}
		})

		It("allows the user to configure policies", func(done Done) {
			By("checking that all test app instances have registered themselves")
			checkRegistry(appRegistry, 10*time.Second, 500*time.Millisecond, len(appsTest)*appInstances)

			appIPs := getAppIPs(appRegistry)
			sample := sampleIPs(appIPs, sampleSize)

			By(fmt.Sprintf("checking that the connection fails sampling %d out of %d IPs", len(sample), len(appIPs)))
			runWithTimeout("check connection failures", Timeout_Check, func() {
				assertConnectionFails(appProxy, sample, ports, proxyInstances)
			})

			By("creating policies")
			doAllPolicies("create", appProxy, appsTest, ports)

			By(fmt.Sprintf("waiting %s for policies to be updated on cells", Policy_Update_Wait))
			time.Sleep(Policy_Update_Wait)

			sample = sampleIPs(appIPs, sampleSize)
			By(fmt.Sprintf("checking that the connection succeeds sampling %d out of %d IPs", len(sample), len(appIPs)))
			runWithTimeout("check connection success", Timeout_Check, func() {
				assertConnectionSucceeds(appProxy, sample, ports, proxyInstances)
			})

			dumpStats(appProxy, config.AppsDomain)

			By("deleting policies")
			doAllPolicies("delete", appProxy, appsTest, ports)

			By(fmt.Sprintf("waiting %s for policies to be updated on cells", Policy_Update_Wait))
			time.Sleep(Policy_Update_Wait)

			sample = sampleIPs(appIPs, sampleSize)
			By(fmt.Sprintf("checking that the connection succeeds sampling %d out of %d IPs", len(sample), len(appIPs)))
			runWithTimeout("check connection failures, again", Timeout_Check, func() {
				assertConnectionFails(appProxy, sample, ports, proxyInstances)
			})

			close(done)
		}, 30*60 /* <-- overall spec timeout in seconds */)
	})
	Describe("sampleIPs", func() {
		var population []string
		BeforeEach(func() {
			population = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
		})

		It("returns a sample of unique choices from the population", func() {
			sample := sampleIPs(population, 9)
			Expect(len(sample)).To(Equal(9))
			for i := 0; i < len(sample); i++ {
				for j := i + 1; j < len(sample); j++ {
					Expect(sample[i]).NotTo(Equal(sample[j]))
				}
			}
		})
		Context("when the sample size is larger than the population", func() {
			It("returns the whole population", func() {
				sample := sampleIPs(population, 999)
				Expect(sample).To(Equal(population))
			})
		})
		Context("when the sample size is zero", func() {
			It("returns the whole population", func() {
				sample := sampleIPs(population, 0)
				Expect(sample).To(Equal(population))
			})
		})
		Context("when the sample size is negative", func() {
			It("returns the whole population", func() {
				sample := sampleIPs(population, -1)
				Expect(sample).To(Equal(population))
			})
		})
	})
})

func getToken() string {
	By("getting token")
	cmd := exec.Command("cf", "oauth-token")
	session, err := gexec.Start(cmd, nil, nil)
	Expect(err).NotTo(HaveOccurred())
	Eventually(session.Wait(Timeout_Short)).Should(gexec.Exit(0))
	rawOutput := string(session.Out.Contents())
	return strings.TrimSpace(strings.TrimPrefix(rawOutput, "bearer "))
}

func getGuids(sourceAppName string, dstAppNames []string) (string, []string) {
	dstGuids := []string{}
	sourceGuid := ""
	token := getToken()
	appsClient := rainmaker.NewApplicationsService(rainmaker.Config{Host: "http://" + config.ApiEndpoint})

	appsList, err := appsClient.List(token)
	Expect(err).NotTo(HaveOccurred())

	for {
		for _, app := range appsList.Applications {
			if app.Name == sourceAppName {
				sourceGuid = app.GUID
				continue
			}
			for _, tickAppName := range dstAppNames {
				if app.Name == tickAppName {
					dstGuids = append(dstGuids, app.GUID)
					break
				}
			}
		}
		if appsList.HasNextPage() {
			appsList, err = appsList.Next(token)
			Expect(err).NotTo(HaveOccurred())
		} else {
			break
		}
	}

	Expect(sourceGuid).NotTo(BeEmpty())
	Expect(dstGuids).To(HaveLen(len(dstAppNames)))

	return sourceGuid, dstGuids
}

func doAllPolicies(action string, source string, dstList []string, dstPorts []int) {
	policyClient := policy_client.NewExternal(lagertest.NewTestLogger("test"), &http.Client{}, "http://"+config.ApiEndpoint)
	sourceGuid, dstGuids := getGuids(source, dstList)
	policies := []models.Policy{}
	for _, dstGuid := range dstGuids {
		for _, port := range dstPorts {
			policies = append(policies, models.Policy{
				Source: models.Source{
					ID: sourceGuid,
				},
				Destination: models.Destination{
					ID:       dstGuid,
					Port:     port,
					Protocol: "tcp",
				},
			})
		}
	}
	token := getToken()
	if action == "create" {
		Expect(policyClient.AddPolicies(token, policies)).To(Succeed())
	} else if action == "delete" {
		Expect(policyClient.DeletePolicies(token, policies)).To(Succeed())
	}
}

func runWithTimeout(operation string, timeout time.Duration, work func()) {
	done := make(chan bool)
	go func() {
		fmt.Printf("starting %s\n", operation)
		work()
		done <- true
	}()

	select {
	case <-done:
		fmt.Printf("completed %s\n", operation)
		return
	case <-time.After(timeout):
		Fail("timeout on " + operation)
	}
}

func dumpStats(host, domain string) {
	resp, err := httpGetBytes(fmt.Sprintf("http://%s.%s/stats", host, domain))
	Expect(err).NotTo(HaveOccurred())

	fmt.Printf("STATS: %s\n", string(resp.Body))
	netStatsFile := os.Getenv("NETWORK_STATS_FILE")
	if netStatsFile != "" {
		Expect(ioutil.WriteFile(netStatsFile, resp.Body, 0600)).To(Succeed())
	}
}

type RegistryInstancesResponse struct {
	Instances []struct {
		ServiceName string `json:"service_name"`
		Endpoint    struct {
			Value string `json:"value"`
		} `json:"endpoint"`
	} `json:"instances"`
}

func getInstancesFromA8(registry string) (*RegistryInstancesResponse, error) {
	resp, err := httpGetBytes(fmt.Sprintf("http://%s.%s/api/v1/instances", registry, config.AppsDomain))
	if err != nil {
		return nil, err
	}

	Expect(resp.StatusCode).To(Equal(http.StatusOK))

	var instancesResponse RegistryInstancesResponse
	err = json.Unmarshal(resp.Body, &instancesResponse)
	if err != nil {
		return nil, err
	}
	return &instancesResponse, nil
}

func checkRegistry(registry string, timeout, pollingInterval time.Duration, totalInstances int) {
	registeredApps := func() (int, error) {
		instancesResponse, err := getInstancesFromA8(registry)
		if err != nil {
			return 0, err
		}
		return len(instancesResponse.Instances), nil
	}

	Eventually(registeredApps, timeout, pollingInterval).Should(Equal(totalInstances))
}

func getAppIPs(registry string) []string {
	instancesResponse, err := getInstancesFromA8(registry)
	Expect(err).NotTo(HaveOccurred())

	ips := []string{}
	for _, instance := range instancesResponse.Instances {
		ip, _, err := net.SplitHostPort(instance.Endpoint.Value)
		Expect(err).NotTo(HaveOccurred())
		ips = append(ips, ip)
	}
	return ips
}

func sampleIPs(population []string, sampleSize int) []string {
	populationSize := len(population)
	if len(population) < sampleSize || sampleSize < 1 {
		return population
	}
	var sample = []string{}
	for i := 0; i < sampleSize; i++ {
		j := rand.Intn(populationSize)
		sample = append(sample, population[j])
		population = append(population[:j], population[j+1:]...)
		populationSize--
	}
	return sample
}

func assertConnectionSucceeds(sourceApp string, destApps []string, ports []int, nProxies int) {
	parallelRunner := &testsupport.ParallelRunner{
		NumWorkers: 50 * nProxies,
	}
	parallelRunner.RunOnSliceStrings(destApps, func(appIP string) {
		for _, port := range ports {
			assertSingleConnection(appIP, port, sourceApp, true)
		}
	})
}

func assertConnectionFails(sourceApp string, destApps []string, ports []int, nProxies int) {
	parallelRunner := &testsupport.ParallelRunner{
		NumWorkers: 50 * nProxies,
	}
	parallelRunner.RunOnSliceStrings(destApps, func(appIP string) {
		for _, port := range ports {
			assertSingleConnection(appIP, port, sourceApp, false)
		}
	})
}

func assertSingleConnection(destIP string, port int, sourceAppName string, shouldSucceed bool) {
	if shouldSucceed {
		By(fmt.Sprintf("eventually proxy should reach %s at port %d", destIP, port))
		assertResponseContains(destIP, port, sourceAppName, "application_name")
	} else {
		By(fmt.Sprintf("eventually proxy should NOT reach %s at port %d", destIP, port))
		assertResponseContains(destIP, port, sourceAppName, "request failed")
	}
}

func assertResponseContains(destIP string, port int, sourceAppName string, desiredResponse string) {
	proxyTest := func() (string, error) {
		resp, err := httpGetBytes(fmt.Sprintf("http://%s.%s/proxy/%s:%d", sourceAppName, config.AppsDomain, destIP, port))
		if err != nil {
			return "", err
		}
		return string(resp.Body), nil
	}
	Eventually(proxyTest, 10*time.Second, 500*time.Millisecond).Should(ContainSubstring(desiredResponse))
}

var httpClient = &http.Client{
	Transport: &http.Transport{
		DisableKeepAlives: true,
		Dial: (&net.Dialer{
			Timeout:   4 * time.Second,
			KeepAlive: 0,
		}).Dial,
	},
}

type httpResp struct {
	StatusCode int
	Body       []byte
}

func httpGetBytes(url string) (httpResp, error) {
	resp, err := httpClient.Get(url)
	if err != nil {
		return httpResp{}, err
	}
	defer resp.Body.Close()

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return httpResp{}, err
	}

	return httpResp{resp.StatusCode, respBytes}, nil
}
<commit_msg>Sleep for five minutes while policies exist<commit_after>package scaling_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"lib/models"
	"lib/policy_client"
	"lib/testsupport"
	"math/rand"
	"net"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"code.cloudfoundry.org/lager/lagertest"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/pivotal-cf-experimental/rainmaker"
)

const Timeout_Check = 20 * time.Minute

// 3 * observed agent total poll time with 200 containers per cell
const Policy_Update_Wait = 180 * time.Second

var ports []int

var _ = Describe("connectivity between containers on the overlay network", func() {
	Describe("networking policy", func() {
		var (
			appProxy       string
			appRegistry    string
			appsTest       []string
			appInstances   int
			applications   int
			proxyInstances int
			sampleSize     int
		)

		BeforeEach(func() {
			appInstances = pushConfig.AppInstances
			applications = pushConfig.Applications
			proxyInstances = pushConfig.ProxyInstances
			sampleSize = pushConfig.SampleSize
			appProxy = pushConfig.Prefix + "proxy"
			appRegistry = pushConfig.Prefix + "registry"
			for i := 0; i < applications; i++ {
				appsTest = append(appsTest, fmt.Sprintf(pushConfig.Prefix+"tick-%d", i))
			}

			ports = []int{8080}
			for i := 0; i < pushConfig.ExtraListenPorts; i++ {
				ports = append(ports, 7000+i)
			}
		})

		It("allows the user to configure policies", func(done Done) {
			By("checking that all test app instances have registered themselves")
			checkRegistry(appRegistry, 10*time.Second, 500*time.Millisecond, len(appsTest)*appInstances)

			appIPs := getAppIPs(appRegistry)
			sample := sampleIPs(appIPs, sampleSize)

			By(fmt.Sprintf("checking that the connection fails sampling %d out of %d IPs", len(sample), len(appIPs)))
			runWithTimeout("check connection failures", Timeout_Check, func() {
				assertConnectionFails(appProxy, sample, ports, proxyInstances)
			})

			By("creating policies")
			doAllPolicies("create", appProxy, appsTest, ports)

			By(fmt.Sprintf("waiting %s for policies to be updated on cells", Policy_Update_Wait))
			time.Sleep(Policy_Update_Wait)

			sample = sampleIPs(appIPs, sampleSize)
			By(fmt.Sprintf("checking that the connection succeeds sampling %d out of %d IPs", len(sample), len(appIPs)))
			runWithTimeout("check connection success", Timeout_Check, func() {
				assertConnectionSucceeds(appProxy, sample, ports, proxyInstances)
			})

			dumpStats(appProxy, config.AppsDomain)

			By("sleeping for 5 minutes while policies exist")
			time.Sleep(5 * time.Minute)

			By("deleting policies")
			doAllPolicies("delete", appProxy, appsTest, ports)

			By(fmt.Sprintf("waiting %s for policies to be updated on cells", Policy_Update_Wait))
			time.Sleep(Policy_Update_Wait)

			sample = sampleIPs(appIPs, sampleSize)
			By(fmt.Sprintf("checking that the connection succeeds sampling %d out of %d IPs", len(sample), len(appIPs)))
			runWithTimeout("check connection failures, again", Timeout_Check, func() {
				assertConnectionFails(appProxy, sample, ports, proxyInstances)
			})

			close(done)
		}, 30*60 /* <-- overall spec timeout in seconds */)
	})
	Describe("sampleIPs", func() {
		var population []string
		BeforeEach(func() {
			population = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
		})

		It("returns a sample of unique choices from the population", func() {
			sample := sampleIPs(population, 9)
			Expect(len(sample)).To(Equal(9))
			for i := 0; i < len(sample); i++ {
				for j := i + 1; j < len(sample); j++ {
					Expect(sample[i]).NotTo(Equal(sample[j]))
				}
			}
		})
		Context("when the sample size is larger than the population", func() {
			It("returns the whole population", func() {
				sample := sampleIPs(population, 999)
				Expect(sample).To(Equal(population))
			})
		})
		Context("when the sample size is zero", func() {
			It("returns the whole population", func() {
				sample := sampleIPs(population, 0)
				Expect(sample).To(Equal(population))
			})
		})
		Context("when the sample size is negative", func() {
			It("returns the whole population", func() {
				sample := sampleIPs(population, -1)
				Expect(sample).To(Equal(population))
			})
		})
	})
})

func getToken() string {
	By("getting token")
	cmd := exec.Command("cf", "oauth-token")
	session, err := gexec.Start(cmd, nil, nil)
	Expect(err).NotTo(HaveOccurred())
	Eventually(session.Wait(Timeout_Short)).Should(gexec.Exit(0))
	rawOutput := string(session.Out.Contents())
	return strings.TrimSpace(strings.TrimPrefix(rawOutput, "bearer "))
}

func getGuids(sourceAppName string, dstAppNames []string) (string, []string) {
	dstGuids := []string{}
	sourceGuid := ""
	token := getToken()
	appsClient := rainmaker.NewApplicationsService(rainmaker.Config{Host: "http://" + config.ApiEndpoint})

	appsList, err := appsClient.List(token)
	Expect(err).NotTo(HaveOccurred())

	for {
		for _, app := range appsList.Applications {
			if app.Name == sourceAppName {
				sourceGuid = app.GUID
				continue
			}
			for _, tickAppName := range dstAppNames {
				if app.Name == tickAppName {
					dstGuids = append(dstGuids, app.GUID)
					break
				}
			}
		}
		if appsList.HasNextPage() {
			appsList, err = appsList.Next(token)
			Expect(err).NotTo(HaveOccurred())
		} else {
			break
		}
	}

	Expect(sourceGuid).NotTo(BeEmpty())
	Expect(dstGuids).To(HaveLen(len(dstAppNames)))

	return sourceGuid, dstGuids
}

func doAllPolicies(action string, source string, dstList []string, dstPorts []int) {
	policyClient := policy_client.NewExternal(lagertest.NewTestLogger("test"), &http.Client{}, "http://"+config.ApiEndpoint)
	sourceGuid, dstGuids := getGuids(source, dstList)
	policies := []models.Policy{}
	for _, dstGuid := range dstGuids {
		for _, port := range dstPorts {
			policies = append(policies, models.Policy{
				Source: models.Source{
					ID: sourceGuid,
				},
				Destination: models.Destination{
					ID:       dstGuid,
					Port:     port,
					Protocol: "tcp",
				},
			})
		}
	}
	token := getToken()
	if action == "create" {
		Expect(policyClient.AddPolicies(token, policies)).To(Succeed())
	} else if action == "delete" {
		Expect(policyClient.DeletePolicies(token, policies)).To(Succeed())
	}
}

func runWithTimeout(operation string, timeout time.Duration, work func()) {
	done := make(chan bool)
	go func() {
		fmt.Printf("starting %s\n", operation)
		work()
		done <- true
	}()

	select {
	case <-done:
		fmt.Printf("completed %s\n", operation)
		return
	case <-time.After(timeout):
		Fail("timeout on " + operation)
	}
}

func dumpStats(host, domain string) {
	resp, err := httpGetBytes(fmt.Sprintf("http://%s.%s/stats", host, domain))
	Expect(err).NotTo(HaveOccurred())

	fmt.Printf("STATS: %s\n", string(resp.Body))
	netStatsFile := os.Getenv("NETWORK_STATS_FILE")
	if netStatsFile != "" {
		Expect(ioutil.WriteFile(netStatsFile, resp.Body, 0600)).To(Succeed())
	}
}

type RegistryInstancesResponse struct {
	Instances []struct {
		ServiceName string `json:"service_name"`
		Endpoint    struct {
			Value string `json:"value"`
		} `json:"endpoint"`
	} `json:"instances"`
}

func getInstancesFromA8(registry string) (*RegistryInstancesResponse, error) {
	resp, err := httpGetBytes(fmt.Sprintf("http://%s.%s/api/v1/instances", registry, config.AppsDomain))
	if err != nil {
		return nil, err
	}

	Expect(resp.StatusCode).To(Equal(http.StatusOK))

	var instancesResponse RegistryInstancesResponse
	err = json.Unmarshal(resp.Body, &instancesResponse)
	if err != nil {
		return nil, err
	}
	return &instancesResponse, nil
}

func checkRegistry(registry string, timeout, pollingInterval time.Duration, totalInstances int) {
	registeredApps := func() (int, error) {
		instancesResponse, err := getInstancesFromA8(registry)
		if err != nil {
			return 0, err
		}
		return len(instancesResponse.Instances), nil
	}

	Eventually(registeredApps, timeout, pollingInterval).Should(Equal(totalInstances))
}

func getAppIPs(registry string) []string {
	instancesResponse, err := getInstancesFromA8(registry)
	Expect(err).NotTo(HaveOccurred())

	ips := []string{}
	for _, instance := range instancesResponse.Instances {
		ip, _, err := net.SplitHostPort(instance.Endpoint.Value)
		Expect(err).NotTo(HaveOccurred())
		ips = append(ips, ip)
	}
	return ips
}

func sampleIPs(population []string, sampleSize int) []string {
	populationSize := len(population)
	if len(population) < sampleSize || sampleSize < 1 {
		return population
	}
	var sample = []string{}
	for i := 0; i < sampleSize; i++ {
		j := rand.Intn(populationSize)
		sample = append(sample, population[j])
		population = append(population[:j], population[j+1:]...)
		populationSize--
	}
	return sample
}

func assertConnectionSucceeds(sourceApp string, destApps []string, ports []int, nProxies int) {
	parallelRunner := &testsupport.ParallelRunner{
		NumWorkers: 50 * nProxies,
	}
	parallelRunner.RunOnSliceStrings(destApps, func(appIP string) {
		for _, port := range ports {
			assertSingleConnection(appIP, port, sourceApp, true)
		}
	})
}

func assertConnectionFails(sourceApp string, destApps []string, ports []int, nProxies int) {
	parallelRunner := &testsupport.ParallelRunner{
		NumWorkers: 50 * nProxies,
	}
	parallelRunner.RunOnSliceStrings(destApps, func(appIP string) {
		for _, port := range ports {
			assertSingleConnection(appIP, port, sourceApp, false)
		}
	})
}

func assertSingleConnection(destIP string, port int, sourceAppName string, shouldSucceed bool) {
	if shouldSucceed {
		By(fmt.Sprintf("eventually proxy should reach %s at port %d", destIP, port))
		assertResponseContains(destIP, port, sourceAppName, "application_name")
	} else {
		By(fmt.Sprintf("eventually proxy should NOT reach %s at port %d", destIP, port))
		assertResponseContains(destIP, port, sourceAppName, "request failed")
	}
}

func assertResponseContains(destIP string, port int, sourceAppName string, desiredResponse string) {
	proxyTest := func() (string, error) {
		resp, err := httpGetBytes(fmt.Sprintf("http://%s.%s/proxy/%s:%d", sourceAppName, config.AppsDomain, destIP, port))
		if err != nil {
			return "", err
		}
		return string(resp.Body), nil
	}
	Eventually(proxyTest, 10*time.Second, 500*time.Millisecond).Should(ContainSubstring(desiredResponse))
}

var httpClient = &http.Client{
	Transport: &http.Transport{
		DisableKeepAlives: true,
		Dial: (&net.Dialer{
			Timeout:   4 * time.Second,
			KeepAlive: 0,
		}).Dial,
	},
}

type httpResp struct {
	StatusCode int
	Body       []byte
}

func httpGetBytes(url string) (httpResp, error) {
	resp, err := httpClient.Get(url)
	if err != nil {
		return httpResp{}, err
	}
	defer resp.Body.Close()

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return httpResp{}, err
	}

	return httpResp{resp.StatusCode, respBytes}, nil
}
<|endoftext|>


<commit_before>package search_test

import (
	"testing"

	"github.com/wasanx25/sreq/search"
)

func TestExec(t *testing.T) {
	s := search.New("testK", "testS")
	t.Run("return content", func(t *testing.T) {
		actualC, actualE := s.Exec()
		expectedContents := []*search.Content{}
		var expectedError *error

		if actualC != expectedContents {
			t.Errorf("expected=%q, got=%q", expectedContents, actualC)
		}

		if actualE != expectedError {
			t.Errorf("expected=%q, got=%q", expectedError, actualE)
		}
	})
}
<commit_msg>Add search new test<commit_after>package search_test

import (
	"testing"

	"github.com/wasanx25/sreq/search"
)

func TestNew(t *testing.T) {
	actual := search.New("testK", "testS")
	if actual.Keyword != "testK" {
		t.Errorf("expected=%q, got=%q", "testK", actual.Keyword)
	}

	if actual.Sort != "testS" {
		t.Errorf("expected=%q, got=%q", "testS", actual.Sort)
	}
}

func TestExec(t *testing.T) {
	s := search.New("testK", "testS")
	t.Run("return content", func(t *testing.T) {
		actualC, actualE := s.Exec()
		expectedContents := []*search.Content{}
		var expectedError *error

		if actualC != expectedContents {
			t.Errorf("expected=%q, got=%q", expectedContents, actualC)
		}

		if actualE != expectedError {
			t.Errorf("expected=%q, got=%q", expectedError, actualE)
		}
	})
}
<|endoftext|>


<commit_before>package dockerclient

import (
	"fmt"
	"time"

	"github.com/docker/docker/pkg/units"
)

type ContainerConfig struct {
	Hostname        string
	Domainname      string
	User            string
	Memory          int64
	MemorySwap      int64
	CpuShares       int64
	Cpuset          string
	AttachStdin     bool
	AttachStdout    bool
	AttachStderr    bool
	PortSpecs       []string
	ExposedPorts    map[string]struct{}
	Tty             bool
	OpenStdin       bool
	StdinOnce       bool
	Env             []string
	Cmd             []string
	Image           string
	Labels          map[string]string
	Volumes         map[string]struct{}
	WorkingDir      string
	Entrypoint      []string
	NetworkDisabled bool
	OnBuild         []string

	// This is used only by the create command
	HostConfig HostConfig
}

type HostConfig struct {
	Binds           []string
	ContainerIDFile string
	LxcConf         []map[string]string
	Privileged      bool
	PortBindings    map[string][]PortBinding
	Links           []string
	PublishAllPorts bool
	Dns             []string
	DnsSearch       []string
	VolumesFrom     []string
	SecurityOpt     []string
	NetworkMode     string
	RestartPolicy   RestartPolicy
	Ulimits         []Ulimit
	LogConfig       LogConfig
}

type ExecConfig struct {
	AttachStdin  bool
	AttachStdout bool
	AttachStderr bool
	Tty          bool
	Cmd          []string
	Container    string
	Detach       bool
}

type LogOptions struct {
	Follow     bool
	Stdout     bool
	Stderr     bool
	Timestamps bool
	Tail       int64
}

type RestartPolicy struct {
	Name              string
	MaximumRetryCount int64
}

type PortBinding struct {
	HostIp   string
	HostPort string
}

type State struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string // contains last known error when starting the container
	StartedAt  time.Time
	FinishedAt time.Time
	Ghost      bool
}

// String returns a human-readable description of the state
// Stoken from docker/docker/daemon/state.go
func (s *State) String() string {
	if s.Running {
		if s.Paused {
			return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
		}
		if s.Restarting {
			return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
		}

		return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
	}

	if s.Dead {
		return "Dead"
	}

	if s.FinishedAt.IsZero() {
		return ""
	}

	return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
}

// StateString returns a single string to describe state
// Stoken from docker/docker/daemon/state.go
func (s *State) StateString() string {
	if s.Running {
		if s.Paused {
			return "paused"
		}
		if s.Restarting {
			return "restarting"
		}
		return "running"
	}

	if s.Dead {
		return "dead"
	}

	return "exited"
}

type ContainerInfo struct {
	Id              string
	Created         string
	Path            string
	Name            string
	Args            []string
	ExecIDs         []string
	Config          *ContainerConfig
	State           *State
	Image           string
	NetworkSettings struct {
		IPAddress   string `json:"IpAddress"`
		IPPrefixLen int    `json:"IpPrefixLen"`
		Gateway     string
		Bridge      string
		Ports       map[string][]PortBinding
	}
	SysInitPath    string
	ResolvConfPath string
	Volumes        map[string]string
	HostConfig     *HostConfig
}

type ContainerChanges struct {
	Path string
	Kind int
}

type Port struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type Container struct {
	Id         string
	Names      []string
	Image      string
	Command    string
	Created    int64
	Status     string
	Ports      []Port
	SizeRw     int64
	SizeRootFs int64
	Labels     map[string]string
}

type Event struct {
	Id     string
	Status string
	From   string
	Time   int64
}

type Version struct {
	Version   string
	GitCommit string
	GoVersion string
}

type RespContainersCreate struct {
	Id       string
	Warnings []string
}

type Image struct {
	Created     int64
	Id          string
	ParentId    string
	RepoTags    []string
	Size        int64
	VirtualSize int64
}

type Info struct {
	ID              string
	Containers      int64
	Driver          string
	DriverStatus    [][]string
	ExecutionDriver string
	Images          int64
	KernelVersion   string
	OperatingSystem string
	NCPU            int64
	MemTotal        int64
	Name            string
	Labels          []string
}

type ImageDelete struct {
	Deleted  string
	Untagged string
}

// The following are types for the API stats endpoint
type ThrottlingData struct {
	// Number of periods with throttling active
	Periods uint64 `json:"periods"`
	// Number of periods when the container hit its throttling limit.
	ThrottledPeriods uint64 `json:"throttled_periods"`
	// Aggregate time the container was throttled for in nanoseconds.
	ThrottledTime uint64 `json:"throttled_time"`
}

type CpuUsage struct {
	// Total CPU time consumed.
	// Units: nanoseconds.
	TotalUsage uint64 `json:"total_usage"`
	// Total CPU time consumed per core.
	// Units: nanoseconds.
	PercpuUsage []uint64 `json:"percpu_usage"`
	// Time spent by tasks of the cgroup in kernel mode.
	// Units: nanoseconds.
	UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
	// Time spent by tasks of the cgroup in user mode.
	// Units: nanoseconds.
	UsageInUsermode uint64 `json:"usage_in_usermode"`
}

type CpuStats struct {
	CpuUsage       CpuUsage       `json:"cpu_usage"`
	SystemUsage    uint64         `json:"system_cpu_usage"`
	ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
}

type NetworkStats struct {
	RxBytes   uint64 `json:"rx_bytes"`
	RxPackets uint64 `json:"rx_packets"`
	RxErrors  uint64 `json:"rx_errors"`
	RxDropped uint64 `json:"rx_dropped"`
	TxBytes   uint64 `json:"tx_bytes"`
	TxPackets uint64 `json:"tx_packets"`
	TxErrors  uint64 `json:"tx_errors"`
	TxDropped uint64 `json:"tx_dropped"`
}

type MemoryStats struct {
	Usage    uint64            `json:"usage"`
	MaxUsage uint64            `json:"max_usage"`
	Stats    map[string]uint64 `json:"stats"`
	Failcnt  uint64            `json:"failcnt"`
	Limit    uint64            `json:"limit"`
}

type BlkioStatEntry struct {
	Major uint64 `json:"major"`
	Minor uint64 `json:"minor"`
	Op    string `json:"op"`
	Value uint64 `json:"value"`
}

type BlkioStats struct {
	// number of bytes tranferred to and from the block device
	IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"`
	IoServicedRecursive     []BlkioStatEntry `json:"io_serviced_recursive"`
	IoQueuedRecursive       []BlkioStatEntry `json:"io_queue_recursive"`
	IoServiceTimeRecursive  []BlkioStatEntry `json:"io_service_time_recursive"`
	IoWaitTimeRecursive     []BlkioStatEntry `json:"io_wait_time_recursive"`
	IoMergedRecursive       []BlkioStatEntry `json:"io_merged_recursive"`
	IoTimeRecursive         []BlkioStatEntry `json:"io_time_recursive"`
	SectorsRecursive        []BlkioStatEntry `json:"sectors_recursive"`
}

type Stats struct {
	Read         time.Time    `json:"read"`
	NetworkStats NetworkStats `json:"network,omitempty"`
	CpuStats     CpuStats     `json:"cpu_stats,omitempty"`
	MemoryStats  MemoryStats  `json:"memory_stats,omitempty"`
	BlkioStats   BlkioStats   `json:"blkio_stats,omitempty"`
}

type Ulimit struct {
	Name string `json:"name"`
	Soft uint64 `json:"soft"`
	Hard uint64 `json:"hard"`
}

type LogConfig struct {
	Type   string            `json:"type"`
	Config map[string]string `json:"config"`
}
<commit_msg>add more version fields<commit_after>package dockerclient

import (
	"fmt"
	"time"

	"github.com/docker/docker/pkg/units"
)

type ContainerConfig struct {
	Hostname        string
	Domainname      string
	User            string
	Memory          int64
	MemorySwap      int64
	CpuShares       int64
	Cpuset          string
	AttachStdin     bool
	AttachStdout    bool
	AttachStderr    bool
	PortSpecs       []string
	ExposedPorts    map[string]struct{}
	Tty             bool
	OpenStdin       bool
	StdinOnce       bool
	Env             []string
	Cmd             []string
	Image           string
	Labels          map[string]string
	Volumes         map[string]struct{}
	WorkingDir      string
	Entrypoint      []string
	NetworkDisabled bool
	OnBuild         []string

	// This is used only by the create command
	HostConfig HostConfig
}

type HostConfig struct {
	Binds           []string
	ContainerIDFile string
	LxcConf         []map[string]string
	Privileged      bool
	PortBindings    map[string][]PortBinding
	Links           []string
	PublishAllPorts bool
	Dns             []string
	DnsSearch       []string
	VolumesFrom     []string
	SecurityOpt     []string
	NetworkMode     string
	RestartPolicy   RestartPolicy
	Ulimits         []Ulimit
	LogConfig       LogConfig
}

type ExecConfig struct {
	AttachStdin  bool
	AttachStdout bool
	AttachStderr bool
	Tty          bool
	Cmd          []string
	Container    string
	Detach       bool
}

type LogOptions struct {
	Follow     bool
	Stdout     bool
	Stderr     bool
	Timestamps bool
	Tail       int64
}

type RestartPolicy struct {
	Name              string
	MaximumRetryCount int64
}

type PortBinding struct {
	HostIp   string
	HostPort string
}

type State struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string // contains last known error when starting the container
	StartedAt  time.Time
	FinishedAt time.Time
	Ghost      bool
}

// String returns a human-readable description of the state
// Stoken from docker/docker/daemon/state.go
func (s *State) String() string {
	if s.Running {
		if s.Paused {
			return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
		}
		if s.Restarting {
			return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
		}

		return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
	}

	if s.Dead {
		return "Dead"
	}

	if s.FinishedAt.IsZero() {
		return ""
	}

	return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
}

// StateString returns a single string to describe state
// Stoken from docker/docker/daemon/state.go
func (s *State) StateString() string {
	if s.Running {
		if s.Paused {
			return "paused"
		}
		if s.Restarting {
			return "restarting"
		}
		return "running"
	}

	if s.Dead {
		return "dead"
	}

	return "exited"
}

type ContainerInfo struct {
	Id              string
	Created         string
	Path            string
	Name            string
	Args            []string
	ExecIDs         []string
	Config          *ContainerConfig
	State           *State
	Image           string
	NetworkSettings struct {
		IPAddress   string `json:"IpAddress"`
		IPPrefixLen int    `json:"IpPrefixLen"`
		Gateway     string
		Bridge      string
		Ports       map[string][]PortBinding
	}
	SysInitPath    string
	ResolvConfPath string
	Volumes        map[string]string
	HostConfig     *HostConfig
}

type ContainerChanges struct {
	Path string
	Kind int
}

type Port struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type Container struct {
	Id         string
	Names      []string
	Image      string
	Command    string
	Created    int64
	Status     string
	Ports      []Port
	SizeRw     int64
	SizeRootFs int64
	Labels     map[string]string
}

type Event struct {
	Id     string
	Status string
	From   string
	Time   int64
}

type Version struct {
	ApiVersion    string
	Arch          string
	GitCommit     string
	GoVersion     string
	KernelVersion string
	Os            string
	Version       string
}

type RespContainersCreate struct {
	Id       string
	Warnings []string
}

type Image struct {
	Created     int64
	Id          string
	ParentId    string
	RepoTags    []string
	Size        int64
	VirtualSize int64
}

type Info struct {
	ID              string
	Containers      int64
	Driver          string
	DriverStatus    [][]string
	ExecutionDriver string
	Images          int64
	KernelVersion   string
	OperatingSystem string
	NCPU            int64
	MemTotal        int64
	Name            string
	Labels          []string
}

type ImageDelete struct {
	Deleted  string
	Untagged string
}

// The following are types for the API stats endpoint
type ThrottlingData struct {
	// Number of periods with throttling active
	Periods uint64 `json:"periods"`
	// Number of periods when the container hit its throttling limit.
	ThrottledPeriods uint64 `json:"throttled_periods"`
	// Aggregate time the container was throttled for in nanoseconds.
	ThrottledTime uint64 `json:"throttled_time"`
}

type CpuUsage struct {
	// Total CPU time consumed.
	// Units: nanoseconds.
	TotalUsage uint64 `json:"total_usage"`
	// Total CPU time consumed per core.
	// Units: nanoseconds.
	PercpuUsage []uint64 `json:"percpu_usage"`
	// Time spent by tasks of the cgroup in kernel mode.
	// Units: nanoseconds.
	UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
	// Time spent by tasks of the cgroup in user mode.
	// Units: nanoseconds.
	UsageInUsermode uint64 `json:"usage_in_usermode"`
}

type CpuStats struct {
	CpuUsage       CpuUsage       `json:"cpu_usage"`
	SystemUsage    uint64         `json:"system_cpu_usage"`
	ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
}

type NetworkStats struct {
	RxBytes   uint64 `json:"rx_bytes"`
	RxPackets uint64 `json:"rx_packets"`
	RxErrors  uint64 `json:"rx_errors"`
	RxDropped uint64 `json:"rx_dropped"`
	TxBytes   uint64 `json:"tx_bytes"`
	TxPackets uint64 `json:"tx_packets"`
	TxErrors  uint64 `json:"tx_errors"`
	TxDropped uint64 `json:"tx_dropped"`
}

type MemoryStats struct {
	Usage    uint64            `json:"usage"`
	MaxUsage uint64            `json:"max_usage"`
	Stats    map[string]uint64 `json:"stats"`
	Failcnt  uint64            `json:"failcnt"`
	Limit    uint64            `json:"limit"`
}

type BlkioStatEntry struct {
	Major uint64 `json:"major"`
	Minor uint64 `json:"minor"`
	Op    string `json:"op"`
	Value uint64 `json:"value"`
}

type BlkioStats struct {
	// number of bytes tranferred to and from the block device
	IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"`
	IoServicedRecursive     []BlkioStatEntry `json:"io_serviced_recursive"`
	IoQueuedRecursive       []BlkioStatEntry `json:"io_queue_recursive"`
	IoServiceTimeRecursive  []BlkioStatEntry `json:"io_service_time_recursive"`
	IoWaitTimeRecursive     []BlkioStatEntry `json:"io_wait_time_recursive"`
	IoMergedRecursive       []BlkioStatEntry `json:"io_merged_recursive"`
	IoTimeRecursive         []BlkioStatEntry `json:"io_time_recursive"`
	SectorsRecursive        []BlkioStatEntry `json:"sectors_recursive"`
}

type Stats struct {
	Read         time.Time    `json:"read"`
	NetworkStats NetworkStats `json:"network,omitempty"`
	CpuStats     CpuStats     `json:"cpu_stats,omitempty"`
	MemoryStats  MemoryStats  `json:"memory_stats,omitempty"`
	BlkioStats   BlkioStats   `json:"blkio_stats,omitempty"`
}

type Ulimit struct {
	Name string `json:"name"`
	Soft uint64 `json:"soft"`
	Hard uint64 `json:"hard"`
}

type LogConfig struct {
	Type   string            `json:"type"`
	Config map[string]string `json:"config"`
}
<|endoftext|>


<commit_before>package litrpc

import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/mit-dci/lit/btcutil/hdkeychain"
	"github.com/mit-dci/lit/coinparam"
	"github.com/mit-dci/lit/crypto/koblitz"
	"github.com/mit-dci/lit/lndc"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/logging"
	"github.com/mit-dci/lit/portxo"
)

// LndcRpcClient can be used to remotely talk to a lit node over LNDC, making
// remote control instructions over the remote control interface. It uses a
// regular lndc.Conn to connect to lit over port 2448, and sends
// RemoteControlRpcRequestMsg to it, and receives RemoteControlRpcResponseMsg
type LndcRpcClient struct {
	lnconn           *lndc.Conn
	requestNonce     uint64
	requestNonceMtx  sync.Mutex
	responseChannels map[uint64]chan lnutil.RemoteControlRpcResponseMsg
	key              *koblitz.PrivateKey
	conMtx           sync.Mutex
}

// LndcRpcCanConnectLocally checks if we can connect to lit using the normal
// home directory. In that case, we read from the privkey.hex and use a different
// derivation than the nodeID to determine the private key. This key is authorized
// by default for remote control.
func LndcRpcCanConnectLocally() bool {
	litHomeDir := os.Getenv("HOME") + "/.lit"
	return LndcRpcCanConnectLocallyWithHomeDir(litHomeDir)
}

// LndcRpcCanConnectLocallyWithHomeDir checks if we can connect to lit given the
// home directory. In that case, we read from the privkey.hex and use a different
// derivation than the nodeID to determine the private key. This key is authorized
// by default for remote control.
func LndcRpcCanConnectLocallyWithHomeDir(litHomeDir string) bool {
	keyFilePath := filepath.Join(litHomeDir, "privkey.hex")

	_, err := os.Stat(keyFilePath)
	return (err == nil)
}

// NewLocalLndcRpcClient is an overload for NewLocalLndcRpcClientWithHomeDirAndPort
// using the default home dir and port
func NewLocalLndcRpcClient() (*LndcRpcClient, error) {
	litHomeDir := os.Getenv("HOME") + "/.lit"
	return NewLocalLndcRpcClientWithHomeDirAndPort(litHomeDir, 2448)
}

// NewLocalLndcRpcClientWithPort is an overload for
// NewLocalLndcRpcClientWithHomeDirAndPort using the default home dir
func NewLocalLndcRpcClientWithPort(port uint32) (*LndcRpcClient, error) {
	litHomeDir := os.Getenv("HOME") + "/.lit"
	return NewLocalLndcRpcClientWithHomeDirAndPort(litHomeDir, port)
}

// NewLocalLndcRpcClientWithHomeDirAndPort loads up privkey.hex, and derives
// the local lit node's address from it, as well as derives the default remote
// control private key from it. Then it will connect to the local lit instance.
func NewLocalLndcRpcClientWithHomeDirAndPort(litHomeDir string, port uint32) (*LndcRpcClient, error) {
	keyFilePath := filepath.Join(litHomeDir, "privkey.hex")
	privKey, err := lnutil.ReadKeyFile(keyFilePath)
	if err != nil {
		return nil, err
	}
	rootPrivKey, err := hdkeychain.NewMaster(privKey[:], &coinparam.TestNet3Params)
	if err != nil {
		return nil, err
	}

	var kg portxo.KeyGen
	kg.Depth = 5
	kg.Step[0] = 44 | 1<<31
	kg.Step[1] = 513 | 1<<31
	kg.Step[2] = 9 | 1<<31
	kg.Step[3] = 1 | 1<<31
	kg.Step[4] = 0 | 1<<31
	key, err := kg.DerivePrivateKey(rootPrivKey)
	if err != nil {
		return nil, err
	}

	kg.Step[3] = 0 | 1<<31
	localIDPriv, err := kg.DerivePrivateKey(rootPrivKey)
	if err != nil {
		logging.Errorf(err.Error())
	}
	var localIDPub [33]byte
	copy(localIDPub[:], localIDPriv.PubKey().SerializeCompressed())

	adr := fmt.Sprintf("%s@127.0.0.1:%d", lnutil.LitAdrFromPubkey(localIDPub), port)
	localIDPriv = nil

	return NewLndcRpcClient(adr, key)
}

// NewLndcRpcClient creates a new LNDC client using the given private key, which
// is arbitrary. It will then connect to the lit node specified in address, and
// can then exchange remote control calls with it. In order to succesfully
// execute command, the given key must be authorized in the lit instance we're
// connecting to.
func NewLndcRpcClient(address string, key *koblitz.PrivateKey) (*LndcRpcClient, error) {
	var err error

	cli := new(LndcRpcClient)
	// Create a map of chan objects to receive returned responses on. These channels
	// are sent to from the ReceiveLoop, and awaited in the Call method.
	cli.responseChannels = make(map[uint64]chan lnutil.RemoteControlRpcResponseMsg)

	//Parse the address we're connecting to
	who, where := lnutil.ParseAdrString(address)

	// If we couldn't deduce a URL, look it up on the tracker
	if where == "" {
		// TODO: Implement address lookups
		err = fmt.Errorf("Tracker lookups not supported yet from LNDC proxy")
		if err != nil {
			return nil, err
		}
	}

	// Dial a connection to the lit node
	cli.lnconn, err = lndc.Dial(key, where, who, net.Dial)
	if err != nil {
		return nil, err
	}

	// Start the receive loop for reply messages
	go cli.ReceiveLoop()
	return cli, nil
}

func (cli *LndcRpcClient) Close() error {
	return cli.lnconn.Close()
}

func (cli *LndcRpcClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
	var err error

	// Generate a local unique nonce using the mutex
	cli.requestNonceMtx.Lock()
	cli.requestNonce++
	nonce := cli.requestNonce
	cli.requestNonceMtx.Unlock()

	// Create the channel to receive the reply on
	cli.responseChannels[nonce] = make(chan lnutil.RemoteControlRpcResponseMsg)

	// Send the message in a goroutine
	go func() {
		msg := new(lnutil.RemoteControlRpcRequestMsg)
		msg.Args, err = json.Marshal(args)
		msg.Idx = nonce
		msg.Method = serviceMethod

		if err != nil {
			logging.Fatal(err)
		}

		rawMsg := msg.Bytes()
		cli.conMtx.Lock()
		n, err := cli.lnconn.Write(rawMsg)
		cli.conMtx.Unlock()
		if err != nil {
			logging.Fatal(err)
		}

		if n < len(rawMsg) {
			logging.Fatal(fmt.Errorf("Did not write entire message to peer"))
		}
	}()

	// If reply is nil the caller apparently doesn't care about the results. So we shouldn't wait for it
	if reply != nil {
		// If not nil, await the reply from the responseChannel for the nonce we sent out.
		// the server will include the same nonce in its reply.
		select {
		case receivedReply := <-cli.responseChannels[nonce]:
			{
				if receivedReply.Error {
					return errors.New(string(receivedReply.Result))
				}

				err = json.Unmarshal(receivedReply.Result, &reply)
				return err
			}
		case <-time.After(time.Second * 10):
			// If no reply is received within 10 seconds, we time out the request.
			// TODO: We could make this configurable in the call
			return errors.New("RPC call timed out")
		}
	}
	return nil
}

// ReceiveLoop reads messages from the LNDC connection and check if they are
// RPC responses
func (cli *LndcRpcClient) ReceiveLoop() {
	for {
		msg := make([]byte, 1<<24)
		//	log.Printf("read message from %x\n", l.RemoteLNId)
		n, err := cli.lnconn.Read(msg)
		if err != nil {
			logging.Warnf("Error reading message from LNDC: %s\n", err.Error())
			cli.lnconn.Close()
			return
		}
		msg = msg[:n]
		// We only care about RPC responses (for now)
		if msg[0] == lnutil.MSGID_REMOTE_RPCRESPONSE {
			// Parse the received message
			response, err := lnutil.NewRemoteControlRpcResponseMsgFromBytes(msg, 0)
			if err != nil {
				logging.Warnf("Error while receiving RPC response: %s\n", err.Error())
				cli.lnconn.Close()
				return
			}

			// Find the response channel to send the reply to
			responseChan, ok := cli.responseChannels[response.Idx]
			if ok {
				// Send the response, but don't depend on someone
				// listening. The caller decides if he's interested in the
				// reply and therefore, it could have not blocked and just
				// ignore the return value.
				select {
				case responseChan <- response:
				default:
				}

				// Clean up the channel to preserve memory. It's only used once.
				delete(cli.responseChannels, response.Idx)
			} else {
				logging.Errorf("Could not find response channel for index %d\n", response.Idx)
			}
		}
	}

}
<commit_msg>Add mutex for modification of the map tracking request/reply (#401)<commit_after>package litrpc

import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/mit-dci/lit/btcutil/hdkeychain"
	"github.com/mit-dci/lit/coinparam"
	"github.com/mit-dci/lit/crypto/koblitz"
	"github.com/mit-dci/lit/lndc"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/logging"
	"github.com/mit-dci/lit/portxo"
)

// LndcRpcClient can be used to remotely talk to a lit node over LNDC, making
// remote control instructions over the remote control interface. It uses a
// regular lndc.Conn to connect to lit over port 2448, and sends
// RemoteControlRpcRequestMsg to it, and receives RemoteControlRpcResponseMsg
type LndcRpcClient struct {
	lnconn             *lndc.Conn
	requestNonce       uint64
	requestNonceMtx    sync.Mutex
	responseChannelMtx sync.Mutex
	responseChannels   map[uint64]chan lnutil.RemoteControlRpcResponseMsg
	key                *koblitz.PrivateKey
	conMtx             sync.Mutex
}

// LndcRpcCanConnectLocally checks if we can connect to lit using the normal
// home directory. In that case, we read from the privkey.hex and use a different
// derivation than the nodeID to determine the private key. This key is authorized
// by default for remote control.
func LndcRpcCanConnectLocally() bool {
	litHomeDir := os.Getenv("HOME") + "/.lit"
	return LndcRpcCanConnectLocallyWithHomeDir(litHomeDir)
}

// LndcRpcCanConnectLocallyWithHomeDir checks if we can connect to lit given the
// home directory. In that case, we read from the privkey.hex and use a different
// derivation than the nodeID to determine the private key. This key is authorized
// by default for remote control.
func LndcRpcCanConnectLocallyWithHomeDir(litHomeDir string) bool {
	keyFilePath := filepath.Join(litHomeDir, "privkey.hex")

	_, err := os.Stat(keyFilePath)
	return (err == nil)
}

// NewLocalLndcRpcClient is an overload for NewLocalLndcRpcClientWithHomeDirAndPort
// using the default home dir and port
func NewLocalLndcRpcClient() (*LndcRpcClient, error) {
	litHomeDir := os.Getenv("HOME") + "/.lit"
	return NewLocalLndcRpcClientWithHomeDirAndPort(litHomeDir, 2448)
}

// NewLocalLndcRpcClientWithPort is an overload for
// NewLocalLndcRpcClientWithHomeDirAndPort using the default home dir
func NewLocalLndcRpcClientWithPort(port uint32) (*LndcRpcClient, error) {
	litHomeDir := os.Getenv("HOME") + "/.lit"
	return NewLocalLndcRpcClientWithHomeDirAndPort(litHomeDir, port)
}

// NewLocalLndcRpcClientWithHomeDirAndPort loads up privkey.hex, and derives
// the local lit node's address from it, as well as derives the default remote
// control private key from it. Then it will connect to the local lit instance.
func NewLocalLndcRpcClientWithHomeDirAndPort(litHomeDir string, port uint32) (*LndcRpcClient, error) {
	keyFilePath := filepath.Join(litHomeDir, "privkey.hex")
	privKey, err := lnutil.ReadKeyFile(keyFilePath)
	if err != nil {
		return nil, err
	}
	rootPrivKey, err := hdkeychain.NewMaster(privKey[:], &coinparam.TestNet3Params)
	if err != nil {
		return nil, err
	}

	var kg portxo.KeyGen
	kg.Depth = 5
	kg.Step[0] = 44 | 1<<31
	kg.Step[1] = 513 | 1<<31
	kg.Step[2] = 9 | 1<<31
	kg.Step[3] = 1 | 1<<31
	kg.Step[4] = 0 | 1<<31
	key, err := kg.DerivePrivateKey(rootPrivKey)
	if err != nil {
		return nil, err
	}

	kg.Step[3] = 0 | 1<<31
	localIDPriv, err := kg.DerivePrivateKey(rootPrivKey)
	if err != nil {
		logging.Errorf(err.Error())
	}
	var localIDPub [33]byte
	copy(localIDPub[:], localIDPriv.PubKey().SerializeCompressed())

	adr := fmt.Sprintf("%s@127.0.0.1:%d", lnutil.LitAdrFromPubkey(localIDPub), port)
	localIDPriv = nil

	return NewLndcRpcClient(adr, key)
}

// NewLndcRpcClient creates a new LNDC client using the given private key, which
// is arbitrary. It will then connect to the lit node specified in address, and
// can then exchange remote control calls with it. In order to succesfully
// execute command, the given key must be authorized in the lit instance we're
// connecting to.
func NewLndcRpcClient(address string, key *koblitz.PrivateKey) (*LndcRpcClient, error) {
	var err error

	cli := new(LndcRpcClient)
	// Create a map of chan objects to receive returned responses on. These channels
	// are sent to from the ReceiveLoop, and awaited in the Call method.
	cli.responseChannels = make(map[uint64]chan lnutil.RemoteControlRpcResponseMsg)

	//Parse the address we're connecting to
	who, where := lnutil.ParseAdrString(address)

	// If we couldn't deduce a URL, look it up on the tracker
	if where == "" {
		// TODO: Implement address lookups
		err = fmt.Errorf("Tracker lookups not supported yet from LNDC proxy")
		if err != nil {
			return nil, err
		}
	}

	// Dial a connection to the lit node
	cli.lnconn, err = lndc.Dial(key, where, who, net.Dial)
	if err != nil {
		return nil, err
	}

	// Start the receive loop for reply messages
	go cli.ReceiveLoop()
	return cli, nil
}

func (cli *LndcRpcClient) Close() error {
	return cli.lnconn.Close()
}

func (cli *LndcRpcClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
	var err error

	// Generate a local unique nonce using the mutex
	cli.requestNonceMtx.Lock()
	cli.requestNonce++
	nonce := cli.requestNonce
	cli.requestNonceMtx.Unlock()

	// Create the channel to receive the reply on
	cli.responseChannelMtx.Lock()
	cli.responseChannels[nonce] = make(chan lnutil.RemoteControlRpcResponseMsg)
	cli.responseChannelMtx.Unlock()

	// Send the message in a goroutine
	go func() {
		msg := new(lnutil.RemoteControlRpcRequestMsg)
		msg.Args, err = json.Marshal(args)
		msg.Idx = nonce
		msg.Method = serviceMethod

		if err != nil {
			logging.Fatal(err)
		}

		rawMsg := msg.Bytes()
		cli.conMtx.Lock()
		n, err := cli.lnconn.Write(rawMsg)
		cli.conMtx.Unlock()
		if err != nil {
			logging.Fatal(err)
		}

		if n < len(rawMsg) {
			logging.Fatal(fmt.Errorf("Did not write entire message to peer"))
		}
	}()

	// If reply is nil the caller apparently doesn't care about the results. So we shouldn't wait for it
	if reply != nil {
		// If not nil, await the reply from the responseChannel for the nonce we sent out.
		// the server will include the same nonce in its reply.
		select {
		case receivedReply := <-cli.responseChannels[nonce]:
			{
				if receivedReply.Error {
					return errors.New(string(receivedReply.Result))
				}

				err = json.Unmarshal(receivedReply.Result, &reply)
				return err
			}
		case <-time.After(time.Second * 10):
			// If no reply is received within 10 seconds, we time out the request.
			// TODO: We could make this configurable in the call
			return errors.New("RPC call timed out")
		}
	}
	return nil
}

// ReceiveLoop reads messages from the LNDC connection and check if they are
// RPC responses
func (cli *LndcRpcClient) ReceiveLoop() {
	for {
		msg := make([]byte, 1<<24)
		//	log.Printf("read message from %x\n", l.RemoteLNId)
		n, err := cli.lnconn.Read(msg)
		if err != nil {
			logging.Warnf("Error reading message from LNDC: %s\n", err.Error())
			cli.lnconn.Close()
			return
		}
		msg = msg[:n]
		// We only care about RPC responses (for now)
		if msg[0] == lnutil.MSGID_REMOTE_RPCRESPONSE {
			// Parse the received message
			response, err := lnutil.NewRemoteControlRpcResponseMsgFromBytes(msg, 0)
			if err != nil {
				logging.Warnf("Error while receiving RPC response: %s\n", err.Error())
				cli.lnconn.Close()
				return
			}

			// Find the response channel to send the reply to
			responseChan, ok := cli.responseChannels[response.Idx]
			if ok {
				// Send the response, but don't depend on someone
				// listening. The caller decides if he's interested in the
				// reply and therefore, it could have not blocked and just
				// ignore the return value.
				select {
				case responseChan <- response:
				default:
				}

				// Clean up the channel to preserve memory. It's only used once.
				cli.responseChannelMtx.Lock()
				delete(cli.responseChannels, response.Idx)
				cli.responseChannelMtx.Unlock()

			} else {
				logging.Errorf("Could not find response channel for index %d\n", response.Idx)
			}
		}
	}

}
<|endoftext|>


<commit_before>package gocsv

import (
	"encoding"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

// --------------------------------------------------------------------------
// Conversion interfaces

// TypeMarshaller is implemented by any value that has a MarshalCSV method
// This converter is used to convert the value to it string representation
type TypeMarshaller interface {
	MarshalCSV() (string, error)
}

// Stringer is implemented by any value that has a String method
// This converter is used to convert the value to it string representation
// This converter will be used if your value does not implement TypeMarshaller
type Stringer interface {
	String() string
}

// TypeUnmarshaller is implemented by any value that has an UnmarshalCSV method
// This converter is used to convert a string to your value representation of that string
type TypeUnmarshaller interface {
	UnmarshalCSV(string) error
}

var (
	stringerType        = reflect.TypeOf((*Stringer)(nil)).Elem()
	marshallerType      = reflect.TypeOf((*TypeMarshaller)(nil)).Elem()
	unMarshallerType    = reflect.TypeOf((*TypeUnmarshaller)(nil)).Elem()
	textMarshalerType   = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
	textUnMarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)

// --------------------------------------------------------------------------
// Conversion helpers

func toString(in interface{}) (string, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		return inValue.String(), nil
	case reflect.Bool:
		b := inValue.Bool()
		if b {
			return "true", nil
		}
		return "false", nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return fmt.Sprintf("%v", inValue.Int()), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return fmt.Sprintf("%v", inValue.Uint()), nil
	case reflect.Float32:
		return strconv.FormatFloat(inValue.Float(), byte('f'), -1, 32), nil
	case reflect.Float64:
		return strconv.FormatFloat(inValue.Float(), byte('f'), -1, 64), nil
	}
	return "", fmt.Errorf("No known conversion from " + inValue.Type().String() + " to string")
}

func toBool(in interface{}) (bool, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := inValue.String()
		if s == "true" || s == "yes" || s == "1" {
			return true, nil
		} else if s == "false" || s == "no" || s == "0" {
			return false, nil
		}
	case reflect.Bool:
		return inValue.Bool(), nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		i := inValue.Int()
		if i != 0 {
			return true, nil
		}
		return false, nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		i := inValue.Uint()
		if i != 0 {
			return true, nil
		}
		return false, nil
	case reflect.Float32, reflect.Float64:
		f := inValue.Float()
		if f != 0 {
			return true, nil
		}
		return false, nil
	}
	return false, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to bool")
}

func toInt(in interface{}) (int64, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		return strconv.ParseInt(inValue.String(), 0, 64)
	case reflect.Bool:
		if inValue.Bool() {
			return 1, nil
		}
		return 0, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return inValue.Int(), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return int64(inValue.Uint()), nil
	case reflect.Float32, reflect.Float64:
		return int64(inValue.Float()), nil
	}
	return 0, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to int")
}

func toUint(in interface{}) (uint64, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := strings.TrimSpace(inValue.String())
		if s == "" {
			return 0, nil
		}

		// support the float input
		if strings.Contains(s, ".") {
			f, err := strconv.ParseFloat(s, 64)
			if err != nil {
				return 0, err
			}
			return uint64(f), nil
		}
		return strconv.ParseUint(s, 0, 64)
	case reflect.Bool:
		if inValue.Bool() {
			return 1, nil
		}
		return 0, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return uint64(inValue.Int()), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return inValue.Uint(), nil
	case reflect.Float32, reflect.Float64:
		return uint64(inValue.Float()), nil
	}
	return 0, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to uint")
}

func toFloat(in interface{}) (float64, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := strings.TrimSpace(inValue.String())
		if s == "" {
			return 0, nil
		}
		return strconv.ParseFloat(s, 64)
	case reflect.Bool:
		if inValue.Bool() {
			return 1, nil
		}
		return 0, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(inValue.Int()), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return float64(inValue.Uint()), nil
	case reflect.Float32, reflect.Float64:
		return inValue.Float(), nil
	}
	return 0, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to float")
}

func setField(field reflect.Value, value string) error {
	switch field.Kind() {
	case reflect.String:
		s, err := toString(value)
		if err != nil {
			return err
		}
		field.SetString(s)
	case reflect.Bool:
		b, err := toBool(value)
		if err != nil {
			return err
		}
		field.SetBool(b)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		i, err := toInt(value)
		if err != nil {
			return err
		}
		field.SetInt(i)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		ui, err := toUint(value)
		if err != nil {
			return err
		}
		field.SetUint(ui)
	case reflect.Float32, reflect.Float64:
		f, err := toFloat(value)
		if err != nil {
			return err
		}
		field.SetFloat(f)
	default:
		return unmarshall(field, value)
	}
	return nil
}

func getFieldAsString(field reflect.Value) (str string, err error) {
	switch field.Kind() {
	case reflect.String:
		return field.String(), nil
	case reflect.Bool:
		str, err = toString(field.Bool())
		if err != nil {
			return str, err
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		str, err = toString(field.Int())
		if err != nil {
			return str, err
		}
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		str, err = toString(field.Uint())
		if err != nil {
			return str, err
		}
	case reflect.Float32:
		str, err = toString(float32(field.Float()))
		if err != nil {
			return str, err
		}
	case reflect.Float64:
		str, err = toString(field.Float())
		if err != nil {
			return str, err
		}
	default:
		return marshall(field)
	}
	return str, nil
}

// --------------------------------------------------------------------------
// Un/serializations helpers

func unmarshall(field reflect.Value, value string) error {
	dupField := field
	unMarshallIt := func(finalField reflect.Value) error {
		if finalField.CanInterface() && finalField.Type().Implements(unMarshallerType) {
			if err := finalField.Interface().(TypeUnmarshaller).UnmarshalCSV(value); err != nil {
				return err
			}
			return nil
		} else if finalField.CanInterface() && finalField.Type().Implements(textUnMarshalerType) { // Otherwise try to use TextMarshaller
			if err := finalField.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
				return err
			}
		}

		return fmt.Errorf("No known conversion from string to " + field.Type().String() + ", " + field.Type().String() + " does not implements TypeUnmarshaller")
	}
	for dupField.Kind() == reflect.Interface || dupField.Kind() == reflect.Ptr {
		if dupField.IsNil() {
			dupField = reflect.New(field.Type().Elem())
			field.Set(dupField)
			return unMarshallIt(dupField)
			break
		}
		dupField = dupField.Elem()
	}
	if dupField.CanAddr() {
		return unMarshallIt(dupField.Addr())
	}
	return fmt.Errorf("No known conversion from string to " + field.Type().String() + ", " + field.Type().String() + " does not implements TypeUnmarshaller")
}

func marshall(field reflect.Value) (value string, err error) {
	dupField := field
	marshallIt := func(finalField reflect.Value) (string, error) {
		if finalField.CanInterface() && finalField.Type().Implements(marshallerType) { // Use TypeMarshaller when possible
			return finalField.Interface().(TypeMarshaller).MarshalCSV()
		} else if finalField.CanInterface() && finalField.Type().Implements(stringerType) { // Otherwise try to use Stringer
			return finalField.Interface().(Stringer).String(), nil
		} else if finalField.CanInterface() && finalField.Type().Implements(textMarshalerType) { // Otherwise try to use TextMarshaller
			text, err := finalField.Interface().(encoding.TextMarshaler).MarshalText()
			return string(text), err
		}

		return value, fmt.Errorf("No known conversion from " + field.Type().String() + " to string, " + field.Type().String() + " does not implements TypeMarshaller nor Stringer")
	}
	for dupField.Kind() == reflect.Interface || dupField.Kind() == reflect.Ptr {
		if dupField.IsNil() {
			return value, nil
		}
		dupField = dupField.Elem()
	}
	if dupField.CanAddr() {
		return marshallIt(dupField.Addr())
	}
	return value, fmt.Errorf("No known conversion from " + field.Type().String() + " to string, " + field.Type().String() + " does not implements TypeMarshaller nor Stringer")
}
<commit_msg>add default int value(0) for blank string<commit_after>package gocsv

import (
	"encoding"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

// --------------------------------------------------------------------------
// Conversion interfaces

// TypeMarshaller is implemented by any value that has a MarshalCSV method
// This converter is used to convert the value to it string representation
type TypeMarshaller interface {
	MarshalCSV() (string, error)
}

// Stringer is implemented by any value that has a String method
// This converter is used to convert the value to it string representation
// This converter will be used if your value does not implement TypeMarshaller
type Stringer interface {
	String() string
}

// TypeUnmarshaller is implemented by any value that has an UnmarshalCSV method
// This converter is used to convert a string to your value representation of that string
type TypeUnmarshaller interface {
	UnmarshalCSV(string) error
}

var (
	stringerType        = reflect.TypeOf((*Stringer)(nil)).Elem()
	marshallerType      = reflect.TypeOf((*TypeMarshaller)(nil)).Elem()
	unMarshallerType    = reflect.TypeOf((*TypeUnmarshaller)(nil)).Elem()
	textMarshalerType   = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
	textUnMarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)

// --------------------------------------------------------------------------
// Conversion helpers

func toString(in interface{}) (string, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		return inValue.String(), nil
	case reflect.Bool:
		b := inValue.Bool()
		if b {
			return "true", nil
		}
		return "false", nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return fmt.Sprintf("%v", inValue.Int()), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return fmt.Sprintf("%v", inValue.Uint()), nil
	case reflect.Float32:
		return strconv.FormatFloat(inValue.Float(), byte('f'), -1, 32), nil
	case reflect.Float64:
		return strconv.FormatFloat(inValue.Float(), byte('f'), -1, 64), nil
	}
	return "", fmt.Errorf("No known conversion from " + inValue.Type().String() + " to string")
}

func toBool(in interface{}) (bool, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := inValue.String()
		if s == "true" || s == "yes" || s == "1" {
			return true, nil
		} else if s == "false" || s == "no" || s == "0" {
			return false, nil
		}
	case reflect.Bool:
		return inValue.Bool(), nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		i := inValue.Int()
		if i != 0 {
			return true, nil
		}
		return false, nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		i := inValue.Uint()
		if i != 0 {
			return true, nil
		}
		return false, nil
	case reflect.Float32, reflect.Float64:
		f := inValue.Float()
		if f != 0 {
			return true, nil
		}
		return false, nil
	}
	return false, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to bool")
}

func toInt(in interface{}) (int64, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := strings.TrimSpace(inValue.String())
		if s == "" {
			return 0, nil
		}
		return strconv.ParseInt(s, 0, 64)
	case reflect.Bool:
		if inValue.Bool() {
			return 1, nil
		}
		return 0, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return inValue.Int(), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return int64(inValue.Uint()), nil
	case reflect.Float32, reflect.Float64:
		return int64(inValue.Float()), nil
	}
	return 0, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to int")
}

func toUint(in interface{}) (uint64, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := strings.TrimSpace(inValue.String())
		if s == "" {
			return 0, nil
		}

		// support the float input
		if strings.Contains(s, ".") {
			f, err := strconv.ParseFloat(s, 64)
			if err != nil {
				return 0, err
			}
			return uint64(f), nil
		}
		return strconv.ParseUint(s, 0, 64)
	case reflect.Bool:
		if inValue.Bool() {
			return 1, nil
		}
		return 0, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return uint64(inValue.Int()), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return inValue.Uint(), nil
	case reflect.Float32, reflect.Float64:
		return uint64(inValue.Float()), nil
	}
	return 0, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to uint")
}

func toFloat(in interface{}) (float64, error) {
	inValue := reflect.ValueOf(in)

	switch inValue.Kind() {
	case reflect.String:
		s := strings.TrimSpace(inValue.String())
		if s == "" {
			return 0, nil
		}
		return strconv.ParseFloat(s, 64)
	case reflect.Bool:
		if inValue.Bool() {
			return 1, nil
		}
		return 0, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(inValue.Int()), nil
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return float64(inValue.Uint()), nil
	case reflect.Float32, reflect.Float64:
		return inValue.Float(), nil
	}
	return 0, fmt.Errorf("No known conversion from " + inValue.Type().String() + " to float")
}

func setField(field reflect.Value, value string) error {
	switch field.Kind() {
	case reflect.String:
		s, err := toString(value)
		if err != nil {
			return err
		}
		field.SetString(s)
	case reflect.Bool:
		b, err := toBool(value)
		if err != nil {
			return err
		}
		field.SetBool(b)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		i, err := toInt(value)
		if err != nil {
			return err
		}
		field.SetInt(i)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		ui, err := toUint(value)
		if err != nil {
			return err
		}
		field.SetUint(ui)
	case reflect.Float32, reflect.Float64:
		f, err := toFloat(value)
		if err != nil {
			return err
		}
		field.SetFloat(f)
	default:
		return unmarshall(field, value)
	}
	return nil
}

func getFieldAsString(field reflect.Value) (str string, err error) {
	switch field.Kind() {
	case reflect.String:
		return field.String(), nil
	case reflect.Bool:
		str, err = toString(field.Bool())
		if err != nil {
			return str, err
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		str, err = toString(field.Int())
		if err != nil {
			return str, err
		}
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		str, err = toString(field.Uint())
		if err != nil {
			return str, err
		}
	case reflect.Float32:
		str, err = toString(float32(field.Float()))
		if err != nil {
			return str, err
		}
	case reflect.Float64:
		str, err = toString(field.Float())
		if err != nil {
			return str, err
		}
	default:
		return marshall(field)
	}
	return str, nil
}

// --------------------------------------------------------------------------
// Un/serializations helpers

func unmarshall(field reflect.Value, value string) error {
	dupField := field
	unMarshallIt := func(finalField reflect.Value) error {
		if finalField.CanInterface() && finalField.Type().Implements(unMarshallerType) {
			if err := finalField.Interface().(TypeUnmarshaller).UnmarshalCSV(value); err != nil {
				return err
			}
			return nil
		} else if finalField.CanInterface() && finalField.Type().Implements(textUnMarshalerType) { // Otherwise try to use TextMarshaller
			if err := finalField.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
				return err
			}
		}

		return fmt.Errorf("No known conversion from string to " + field.Type().String() + ", " + field.Type().String() + " does not implements TypeUnmarshaller")
	}
	for dupField.Kind() == reflect.Interface || dupField.Kind() == reflect.Ptr {
		if dupField.IsNil() {
			dupField = reflect.New(field.Type().Elem())
			field.Set(dupField)
			return unMarshallIt(dupField)
			break
		}
		dupField = dupField.Elem()
	}
	if dupField.CanAddr() {
		return unMarshallIt(dupField.Addr())
	}
	return fmt.Errorf("No known conversion from string to " + field.Type().String() + ", " + field.Type().String() + " does not implements TypeUnmarshaller")
}

func marshall(field reflect.Value) (value string, err error) {
	dupField := field
	marshallIt := func(finalField reflect.Value) (string, error) {
		if finalField.CanInterface() && finalField.Type().Implements(marshallerType) { // Use TypeMarshaller when possible
			return finalField.Interface().(TypeMarshaller).MarshalCSV()
		} else if finalField.CanInterface() && finalField.Type().Implements(stringerType) { // Otherwise try to use Stringer
			return finalField.Interface().(Stringer).String(), nil
		} else if finalField.CanInterface() && finalField.Type().Implements(textMarshalerType) { // Otherwise try to use TextMarshaller
			text, err := finalField.Interface().(encoding.TextMarshaler).MarshalText()
			return string(text), err
		}

		return value, fmt.Errorf("No known conversion from " + field.Type().String() + " to string, " + field.Type().String() + " does not implements TypeMarshaller nor Stringer")
	}
	for dupField.Kind() == reflect.Interface || dupField.Kind() == reflect.Ptr {
		if dupField.IsNil() {
			return value, nil
		}
		dupField = dupField.Elem()
	}
	if dupField.CanAddr() {
		return marshallIt(dupField.Addr())
	}
	return value, fmt.Errorf("No known conversion from " + field.Type().String() + " to string, " + field.Type().String() + " does not implements TypeMarshaller nor Stringer")
}
<|endoftext|>


<commit_before>package dbus

import (
	"container/list"
	"sync"
)

// NewSequentialSignalHandler returns an instance of a new
// signal handler that guarantees sequential processing of signals. It is a
// guarantee of this signal handler that signals will be written to
// channels in the order they are received on the DBus connection.
func NewSequentialSignalHandler() SignalHandler {
	return &sequentialSignalHandler{}
}

type sequentialSignalHandler struct {
	mu      sync.RWMutex
	closed  bool
	signals []*sequentialSignalChannelData
}

func (sh *sequentialSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
	sh.mu.RLock()
	defer sh.mu.RUnlock()
	if sh.closed {
		return
	}
	for _, scd := range sh.signals {
		scd.deliver(signal)
	}
}

func (sh *sequentialSignalHandler) Terminate() {
	sh.mu.Lock()
	defer sh.mu.Unlock()
	if sh.closed {
		return
	}

	for _, scd := range sh.signals {
		scd.close()
		close(scd.ch)
	}
	sh.closed = true
	sh.signals = nil
}

func (sh *sequentialSignalHandler) AddSignal(ch chan<- *Signal) {
	sh.mu.Lock()
	defer sh.mu.Unlock()
	if sh.closed {
		return
	}
	sh.signals = append(sh.signals, &sequentialSignalChannelData{
		queue: list.New(),
		ch:    ch,
		done:  make(chan struct{}),
	})
}

func (sh *sequentialSignalHandler) RemoveSignal(ch chan<- *Signal) {
	sh.mu.Lock()
	defer sh.mu.Unlock()
	if sh.closed {
		return
	}
	for i := len(sh.signals) - 1; i >= 0; i-- {
		if ch == sh.signals[i].ch {
			sh.signals[i].close()
			copy(sh.signals[i:], sh.signals[i+1:])
			sh.signals[len(sh.signals)-1] = nil
			sh.signals = sh.signals[:len(sh.signals)-1]
		}
	}
}

type sequentialSignalChannelData struct {
	stateLock sync.Mutex
	writeLock sync.Mutex
	queue     *list.List
	wg        sync.WaitGroup
	ch        chan<- *Signal
	done      chan struct{}
}

func (scd *sequentialSignalChannelData) deliver(signal *Signal) {
	// Avoid blocking the main DBus message processing routine;
	// queue signal to be dispatched later.
	scd.stateLock.Lock()
	scd.queue.PushBack(signal)
	scd.stateLock.Unlock()

	scd.wg.Add(1)
	go scd.deferredDeliver()
}

func (scd *sequentialSignalChannelData) deferredDeliver() {
	defer scd.wg.Done()

	// Ensure only one goroutine is in this section at once, to
	// make sure signals are sent over ch in the order they
	// are in the queue.
	scd.writeLock.Lock()
	defer scd.writeLock.Unlock()

	scd.stateLock.Lock()
	elem := scd.queue.Front()
	scd.queue.Remove(elem)
	scd.stateLock.Unlock()

	select {
	case scd.ch <- elem.Value.(*Signal):
	case <-scd.done:
	}
}

func (scd *sequentialSignalChannelData) close() {
	close(scd.done)
	scd.wg.Wait() // wait until all spawned goroutines return
}
<commit_msg>sequential_handler: simplify to use less goroutines<commit_after>package dbus

import (
	"container/list"
	"sync"
)

// NewSequentialSignalHandler returns an instance of a new
// signal handler that guarantees sequential processing of signals. It is a
// guarantee of this signal handler that signals will be written to
// channels in the order they are received on the DBus connection.
func NewSequentialSignalHandler() SignalHandler {
	return &sequentialSignalHandler{}
}

type sequentialSignalHandler struct {
	mu      sync.RWMutex
	closed  bool
	signals []*sequentialSignalChannelData
}

func (sh *sequentialSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
	sh.mu.RLock()
	defer sh.mu.RUnlock()
	if sh.closed {
		return
	}
	for _, scd := range sh.signals {
		scd.deliver(signal)
	}
}

func (sh *sequentialSignalHandler) Terminate() {
	sh.mu.Lock()
	defer sh.mu.Unlock()
	if sh.closed {
		return
	}

	for _, scd := range sh.signals {
		scd.close()
		close(scd.ch)
	}
	sh.closed = true
	sh.signals = nil
}

func (sh *sequentialSignalHandler) AddSignal(ch chan<- *Signal) {
	sh.mu.Lock()
	defer sh.mu.Unlock()
	if sh.closed {
		return
	}
	sh.signals = append(sh.signals, newSequentialSignalChannelData(ch))
}

func (sh *sequentialSignalHandler) RemoveSignal(ch chan<- *Signal) {
	sh.mu.Lock()
	defer sh.mu.Unlock()
	if sh.closed {
		return
	}
	for i := len(sh.signals) - 1; i >= 0; i-- {
		if ch == sh.signals[i].ch {
			sh.signals[i].close()
			copy(sh.signals[i:], sh.signals[i+1:])
			sh.signals[len(sh.signals)-1] = nil
			sh.signals = sh.signals[:len(sh.signals)-1]
		}
	}
}

type sequentialSignalChannelData struct {
	ch   chan<- *Signal
	in   chan *Signal
	done chan struct{}
}

func newSequentialSignalChannelData(ch chan<- *Signal) *sequentialSignalChannelData {
	scd := &sequentialSignalChannelData{
		ch:   ch,
		in:   make(chan *Signal),
		done: make(chan struct{}),
	}
	go scd.bufferSignals()
	return scd
}

func (scd *sequentialSignalChannelData) bufferSignals() {
	var (
		queue list.List
		next  *Signal
	)
	defer close(scd.done)

	for {
		if next == nil {
			if queue.Len() != 0 {
				elem := queue.Front()
				queue.Remove(elem)
				next = elem.Value.(*Signal)
			} else {
				var ok bool
				next, ok = <-scd.in
				if !ok {
					return
				}
			}
		}
		select {
		case scd.ch <- next:
			// Signal delivered: the next signal will be
			// picked next iteration.
			next = nil
		case signal, ok := <-scd.in:
			if ok {
				queue.PushBack(signal)
			} else {
				return
			}
		}
	}
}

func (scd *sequentialSignalChannelData) deliver(signal *Signal) {
	scd.in <- signal
}

func (scd *sequentialSignalChannelData) close() {
	close(scd.in)
	// Ensure that bufferSignals() has exited and won't attempt
	// any future sends on scd.ch
	<-scd.done
}
<|endoftext|>