<commit_before>package command

import (
	"fmt"
	"strings"
	"strconv"
	"time"
	"os"
)

func init() {
	cmdFuse.Run = runFuse // break init cycle
}

type parameter struct {
	name string
	value string
}

func runFuse(cmd *Command, args []string) bool {
	rawArgs := strings.Join(args, " ")
	rawArgsLen := len(rawArgs)
	option := strings.Builder{}
	options := []parameter{}
	masterProcess := true

	// first parameter
	i := 0
	for i = 0; i < rawArgsLen && rawArgs[i] != ' '; i++ {
		option.WriteByte(rawArgs[i])
	}
	options = append(options, parameter{"arg0", option.String()})
	option.Reset()

	for i++; i < rawArgsLen; i++ {

		// space separator check for filled option
		if rawArgs[i] == ' ' {
			if option.Len() > 0 {
				options = append(options, parameter{option.String(), "true"})
				option.Reset()
			}

		// dash separator read option until next space
		} else if rawArgs[i] == '-' {
			for i++; i < rawArgsLen && rawArgs[i] != ' '; i++ {
				option.WriteByte(rawArgs[i])
			}
			options = append(options, parameter{option.String(), "true"})
			option.Reset()

		// equal separator start option with pending value
		} else if rawArgs[i] == '=' {
			name := option.String()
			option.Reset()

			for i++; i < rawArgsLen && rawArgs[i] != ','; i++ {
				// double quote separator read option until next double quote
				if rawArgs[i] == '"' {
					for i++; i < rawArgsLen && rawArgs[i] != '"'; i++ {
						option.WriteByte(rawArgs[i])
					}

				// single quote separator read option until next single quote
				} else if rawArgs[i] == '\'' {
					for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
						option.WriteByte(rawArgs[i])
					}

				// add chars before comma
				} else if rawArgs[i] != ' ' {
					option.WriteByte(rawArgs[i])
				}
			}

			options = append(options, parameter{name, option.String()})
			option.Reset()

		// comma separator just read current option
		} else if rawArgs[i] == ',' {
			options = append(options, parameter{option.String(), "true"})
			option.Reset()

		// what is not a separator fill option buffer
		} else {
			option.WriteByte(rawArgs[i])
		}
	}

	// get residual option data
	if option.Len() > 0 {
		// add value to pending option
		options = append(options, parameter{option.String(), "true"})
		option.Reset()
	}

	// scan each parameter
	for i := 0; i < len(options); i++ {
		parameter := options[i]

		switch parameter.name  {
		case "child":
			masterProcess = false
		case "arg0":
			mountOptions.dir = &parameter.value
		case "filer":
			mountOptions.filer = &parameter.value
		case "filer.path":
			mountOptions.filerMountRootPath = &parameter.value
		case "dirAutoCreate":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.dirAutoCreate = &parsed
			} else {
				panic(fmt.Errorf("dirAutoCreate: %s", err))
			}
		case "collection":
			mountOptions.collection = &parameter.value
		case "replication":
			mountOptions.replication = &parameter.value
		case "disk":
			mountOptions.diskType = &parameter.value
		case "ttl":
			if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
				intValue := int(parsed)
				mountOptions.ttlSec = &intValue
			} else {
				panic(fmt.Errorf("ttl: %s", err))
			}
		case "chunkSizeLimitMB":
			if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
				intValue := int(parsed)
				mountOptions.chunkSizeLimitMB = &intValue
			} else {
				panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
			}
		case "concurrentWriters":
			i++
			if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
				intValue := int(parsed)
				mountOptions.concurrentWriters = &intValue
			} else {
				panic(fmt.Errorf("concurrentWriters: %s", err))
			}
		case "cacheDir":
			mountOptions.cacheDir = &parameter.value
		case "cacheCapacityMB":
			if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err != nil {
				mountOptions.cacheSizeMB = &parsed
			} else {
				panic(fmt.Errorf("cacheCapacityMB: %s", err))
			}
		case "dataCenter":
			mountOptions.dataCenter = &parameter.value
		case "allowOthers":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.allowOthers = &parsed
			} else {
				panic(fmt.Errorf("allowOthers: %s", err))
			}
		case "umask":
			mountOptions.umaskString = &parameter.value
		case "nonempty":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.nonempty = &parsed
			} else {
				panic(fmt.Errorf("nonempty: %s", err))
			}
		case "volumeServerAccess":
			mountOptions.volumeServerAccess = &parameter.value
		case "map.uid":
			mountOptions.uidMap = &parameter.value
		case "map.gid":
			mountOptions.gidMap = &parameter.value
		case "readOnly":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.readOnly = &parsed
			} else {
				panic(fmt.Errorf("readOnly: %s", err))
			}
		case "cpuprofile":
			mountCpuProfile = &parameter.value
		case "memprofile":
			mountMemProfile = &parameter.value
		case "readRetryTime":
			if parsed, err := time.ParseDuration(parameter.value); err != nil {
				mountReadRetryTime = &parsed
			} else {
				panic(fmt.Errorf("readRetryTime: %s", err))
			}
		}
	}

	// the master start the child, release it then finish himself
	if masterProcess {
		arg0 := os.Args[0]
		argv := append(os.Args, "-o", "child")

		attr := os.ProcAttr{}
		child, err := os.StartProcess(arg0, argv, &attr)

		if err != nil {
			panic(fmt.Errorf("master process can not start child process: %s", err))
		}

		err = child.Release()

		if err != nil {
			panic(fmt.Errorf("master process can not release child process: %s", err))
		}

		return true
	}

	// I don't know why PATH environment variable is lost
	if err := os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"); err != nil {
		panic(fmt.Errorf("setenv: %s", err))
	}

	// just call "weed mount" command
	return runMount(cmdMount, []string{})
}

var cmdFuse = &Command{
	UsageLine: "fuse /mnt/mount/point -o \"filer=localhost:8888,filer.path=/\"",
	Short: "Allow use weed with linux's mount command",
	Long: `Allow use weed with linux's mount command

  You can use -t weed on mount command:
  mv weed /sbin/mount.weed
  mount -t weed fuse /mnt -o "filer=localhost:8888,filer.path=/"

  Or you can use -t fuse on mount command:
  mv weed /sbin/weed
  mount -t fuse.weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  mount -t fuse "weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"

  To use without mess with your /sbin:
  mount -t fuse./home/user/bin/weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  mount -t fuse "/home/user/bin/weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"

  To pass more than one parameter use quotes, example:
  mount -t weed fuse /mnt -o "filer='192.168.0.1:8888,192.168.0.2:8888',filer.path=/"

  To check valid options look "weed mount --help"
  `,
}
<commit_msg>Fix: Loosing environment variables at StartProcess<commit_after>package command

import (
	"fmt"
	"strings"
	"strconv"
	"time"
	"os"
)

func init() {
	cmdFuse.Run = runFuse // break init cycle
}

type parameter struct {
	name string
	value string
}

func runFuse(cmd *Command, args []string) bool {
	rawArgs := strings.Join(args, " ")
	rawArgsLen := len(rawArgs)
	option := strings.Builder{}
	options := []parameter{}
	masterProcess := true

	// first parameter
	i := 0
	for i = 0; i < rawArgsLen && rawArgs[i] != ' '; i++ {
		option.WriteByte(rawArgs[i])
	}
	options = append(options, parameter{"arg0", option.String()})
	option.Reset()

	for i++; i < rawArgsLen; i++ {

		// space separator check for filled option
		if rawArgs[i] == ' ' {
			if option.Len() > 0 {
				options = append(options, parameter{option.String(), "true"})
				option.Reset()
			}

		// dash separator read option until next space
		} else if rawArgs[i] == '-' {
			for i++; i < rawArgsLen && rawArgs[i] != ' '; i++ {
				option.WriteByte(rawArgs[i])
			}
			options = append(options, parameter{option.String(), "true"})
			option.Reset()

		// equal separator start option with pending value
		} else if rawArgs[i] == '=' {
			name := option.String()
			option.Reset()

			for i++; i < rawArgsLen && rawArgs[i] != ','; i++ {
				// double quote separator read option until next double quote
				if rawArgs[i] == '"' {
					for i++; i < rawArgsLen && rawArgs[i] != '"'; i++ {
						option.WriteByte(rawArgs[i])
					}

				// single quote separator read option until next single quote
				} else if rawArgs[i] == '\'' {
					for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
						option.WriteByte(rawArgs[i])
					}

				// add chars before comma
				} else if rawArgs[i] != ' ' {
					option.WriteByte(rawArgs[i])
				}
			}

			options = append(options, parameter{name, option.String()})
			option.Reset()

		// comma separator just read current option
		} else if rawArgs[i] == ',' {
			options = append(options, parameter{option.String(), "true"})
			option.Reset()

		// what is not a separator fill option buffer
		} else {
			option.WriteByte(rawArgs[i])
		}
	}

	// get residual option data
	if option.Len() > 0 {
		// add value to pending option
		options = append(options, parameter{option.String(), "true"})
		option.Reset()
	}

	// scan each parameter
	for i := 0; i < len(options); i++ {
		parameter := options[i]

		switch parameter.name  {
		case "child":
			masterProcess = false
		case "arg0":
			mountOptions.dir = &parameter.value
		case "filer":
			mountOptions.filer = &parameter.value
		case "filer.path":
			mountOptions.filerMountRootPath = &parameter.value
		case "dirAutoCreate":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.dirAutoCreate = &parsed
			} else {
				panic(fmt.Errorf("dirAutoCreate: %s", err))
			}
		case "collection":
			mountOptions.collection = &parameter.value
		case "replication":
			mountOptions.replication = &parameter.value
		case "disk":
			mountOptions.diskType = &parameter.value
		case "ttl":
			if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
				intValue := int(parsed)
				mountOptions.ttlSec = &intValue
			} else {
				panic(fmt.Errorf("ttl: %s", err))
			}
		case "chunkSizeLimitMB":
			if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
				intValue := int(parsed)
				mountOptions.chunkSizeLimitMB = &intValue
			} else {
				panic(fmt.Errorf("chunkSizeLimitMB: %s", err))
			}
		case "concurrentWriters":
			i++
			if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
				intValue := int(parsed)
				mountOptions.concurrentWriters = &intValue
			} else {
				panic(fmt.Errorf("concurrentWriters: %s", err))
			}
		case "cacheDir":
			mountOptions.cacheDir = &parameter.value
		case "cacheCapacityMB":
			if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err != nil {
				mountOptions.cacheSizeMB = &parsed
			} else {
				panic(fmt.Errorf("cacheCapacityMB: %s", err))
			}
		case "dataCenter":
			mountOptions.dataCenter = &parameter.value
		case "allowOthers":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.allowOthers = &parsed
			} else {
				panic(fmt.Errorf("allowOthers: %s", err))
			}
		case "umask":
			mountOptions.umaskString = &parameter.value
		case "nonempty":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.nonempty = &parsed
			} else {
				panic(fmt.Errorf("nonempty: %s", err))
			}
		case "volumeServerAccess":
			mountOptions.volumeServerAccess = &parameter.value
		case "map.uid":
			mountOptions.uidMap = &parameter.value
		case "map.gid":
			mountOptions.gidMap = &parameter.value
		case "readOnly":
			if parsed, err := strconv.ParseBool(parameter.value); err != nil {
				mountOptions.readOnly = &parsed
			} else {
				panic(fmt.Errorf("readOnly: %s", err))
			}
		case "cpuprofile":
			mountCpuProfile = &parameter.value
		case "memprofile":
			mountMemProfile = &parameter.value
		case "readRetryTime":
			if parsed, err := time.ParseDuration(parameter.value); err != nil {
				mountReadRetryTime = &parsed
			} else {
				panic(fmt.Errorf("readRetryTime: %s", err))
			}
		}
	}

	// the master start the child, release it then finish himself
	if masterProcess {
		arg0 := os.Args[0]
		argv := append(os.Args, "-o", "child")

		attr := os.ProcAttr{}
		attr.Env = os.Environ()

		child, err := os.StartProcess(arg0, argv, &attr)

		if err != nil {
			panic(fmt.Errorf("master process can not start child process: %s", err))
		}

		err = child.Release()

		if err != nil {
			panic(fmt.Errorf("master process can not release child process: %s", err))
		}

		return true
	}

	// just call "weed mount" command
	return runMount(cmdMount, []string{})
}

var cmdFuse = &Command{
	UsageLine: "fuse /mnt/mount/point -o \"filer=localhost:8888,filer.path=/\"",
	Short: "Allow use weed with linux's mount command",
	Long: `Allow use weed with linux's mount command

  You can use -t weed on mount command:
  mv weed /sbin/mount.weed
  mount -t weed fuse /mnt -o "filer=localhost:8888,filer.path=/"

  Or you can use -t fuse on mount command:
  mv weed /sbin/weed
  mount -t fuse.weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  mount -t fuse "weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"

  To use without mess with your /sbin:
  mount -t fuse./home/user/bin/weed fuse /mnt -o "filer=localhost:8888,filer.path=/"
  mount -t fuse "/home/user/bin/weed#fuse" /mnt -o "filer=localhost:8888,filer.path=/"

  To pass more than one parameter use quotes, example:
  mount -t weed fuse /mnt -o "filer='192.168.0.1:8888,192.168.0.2:8888',filer.path=/"

  To check valid options look "weed mount --help"
  `,
}
<|endoftext|>


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

package github

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"testing"

	"github.com/google/go-cmp/cmp"
)

func TestAdminOrgs_Create(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &Organization{
		Login: String("github"),
	}

	mux.HandleFunc("/admin/organizations", func(w http.ResponseWriter, r *http.Request) {
		v := new(createOrgRequest)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "POST")
		want := &createOrgRequest{Login: String("github"), Admin: String("ghAdmin")}
		if !cmp.Equal(v, want) {
			t.Errorf("Request body = %+v, want %+v", v, want)
		}

		fmt.Fprint(w, `{"login":"github","id":1}`)
	})

	ctx := context.Background()
	org, _, err := client.Admin.CreateOrg(ctx, input, "ghAdmin")
	if err != nil {
		t.Errorf("Admin.CreateOrg returned error: %v", err)
	}

	want := &Organization{ID: Int64(1), Login: String("github")}
	if !cmp.Equal(org, want) {
		t.Errorf("Admin.CreateOrg returned %+v, want %+v", org, want)
	}

	const methodName = "CreateOrg"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Admin.CreateOrg(ctx, input, "ghAdmin")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestAdminOrgs_Rename(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &Organization{
		Login: String("o"),
	}

	mux.HandleFunc("/admin/organizations/o", func(w http.ResponseWriter, r *http.Request) {
		v := new(renameOrgRequest)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PATCH")
		want := &renameOrgRequest{Login: String("the-new-octocats")}
		if !cmp.Equal(v, want) {
			t.Errorf("Request body = %+v, want %+v", v, want)
		}

		fmt.Fprint(w, `{"message":"Job queued to rename organization. It may take a few minutes to complete.","url":"https://<hostname>/api/v3/organizations/1"}`)
	})

	ctx := context.Background()
	resp, _, err := client.Admin.RenameOrg(ctx, input, "the-new-octocats")
	if err != nil {
		t.Errorf("Admin.RenameOrg returned error: %v", err)
	}

	want := &RenameOrgResponse{Message: String("Job queued to rename organization. It may take a few minutes to complete."), URL: String("https://<hostname>/api/v3/organizations/1")}
	if !cmp.Equal(resp, want) {
		t.Errorf("Admin.RenameOrg returned %+v, want %+v", resp, want)
	}

	const methodName = "RenameOrg"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Admin.RenameOrg(ctx, input, "the-new-octocats")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestAdminOrgs_RenameByName(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/admin/organizations/o", func(w http.ResponseWriter, r *http.Request) {
		v := new(renameOrgRequest)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PATCH")
		want := &renameOrgRequest{Login: String("the-new-octocats")}
		if !cmp.Equal(v, want) {
			t.Errorf("Request body = %+v, want %+v", v, want)
		}

		fmt.Fprint(w, `{"message":"Job queued to rename organization. It may take a few minutes to complete.","url":"https://<hostname>/api/v3/organizations/1"}`)
	})

	ctx := context.Background()
	resp, _, err := client.Admin.RenameOrgByName(ctx, "o", "the-new-octocats")
	if err != nil {
		t.Errorf("Admin.RenameOrg returned error: %v", err)
	}

	want := &RenameOrgResponse{Message: String("Job queued to rename organization. It may take a few minutes to complete."), URL: String("https://<hostname>/api/v3/organizations/1")}
	if !cmp.Equal(resp, want) {
		t.Errorf("Admin.RenameOrg returned %+v, want %+v", resp, want)
	}

	const methodName = "RenameOrgByName"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Admin.RenameOrgByName(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Admin.RenameOrgByName(ctx, "o", "the-new-octocats")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}
<commit_msg>Add test cases for JSON resource marshaling (#1918)<commit_after>// Copyright 2019 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"testing"

	"github.com/google/go-cmp/cmp"
)

func TestAdminOrgs_Create(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &Organization{
		Login: String("github"),
	}

	mux.HandleFunc("/admin/organizations", func(w http.ResponseWriter, r *http.Request) {
		v := new(createOrgRequest)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "POST")
		want := &createOrgRequest{Login: String("github"), Admin: String("ghAdmin")}
		if !cmp.Equal(v, want) {
			t.Errorf("Request body = %+v, want %+v", v, want)
		}

		fmt.Fprint(w, `{"login":"github","id":1}`)
	})

	ctx := context.Background()
	org, _, err := client.Admin.CreateOrg(ctx, input, "ghAdmin")
	if err != nil {
		t.Errorf("Admin.CreateOrg returned error: %v", err)
	}

	want := &Organization{ID: Int64(1), Login: String("github")}
	if !cmp.Equal(org, want) {
		t.Errorf("Admin.CreateOrg returned %+v, want %+v", org, want)
	}

	const methodName = "CreateOrg"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Admin.CreateOrg(ctx, input, "ghAdmin")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestAdminOrgs_Rename(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &Organization{
		Login: String("o"),
	}

	mux.HandleFunc("/admin/organizations/o", func(w http.ResponseWriter, r *http.Request) {
		v := new(renameOrgRequest)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PATCH")
		want := &renameOrgRequest{Login: String("the-new-octocats")}
		if !cmp.Equal(v, want) {
			t.Errorf("Request body = %+v, want %+v", v, want)
		}

		fmt.Fprint(w, `{"message":"Job queued to rename organization. It may take a few minutes to complete.","url":"https://<hostname>/api/v3/organizations/1"}`)
	})

	ctx := context.Background()
	resp, _, err := client.Admin.RenameOrg(ctx, input, "the-new-octocats")
	if err != nil {
		t.Errorf("Admin.RenameOrg returned error: %v", err)
	}

	want := &RenameOrgResponse{Message: String("Job queued to rename organization. It may take a few minutes to complete."), URL: String("https://<hostname>/api/v3/organizations/1")}
	if !cmp.Equal(resp, want) {
		t.Errorf("Admin.RenameOrg returned %+v, want %+v", resp, want)
	}

	const methodName = "RenameOrg"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Admin.RenameOrg(ctx, input, "the-new-octocats")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestAdminOrgs_RenameByName(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/admin/organizations/o", func(w http.ResponseWriter, r *http.Request) {
		v := new(renameOrgRequest)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PATCH")
		want := &renameOrgRequest{Login: String("the-new-octocats")}
		if !cmp.Equal(v, want) {
			t.Errorf("Request body = %+v, want %+v", v, want)
		}

		fmt.Fprint(w, `{"message":"Job queued to rename organization. It may take a few minutes to complete.","url":"https://<hostname>/api/v3/organizations/1"}`)
	})

	ctx := context.Background()
	resp, _, err := client.Admin.RenameOrgByName(ctx, "o", "the-new-octocats")
	if err != nil {
		t.Errorf("Admin.RenameOrg returned error: %v", err)
	}

	want := &RenameOrgResponse{Message: String("Job queued to rename organization. It may take a few minutes to complete."), URL: String("https://<hostname>/api/v3/organizations/1")}
	if !cmp.Equal(resp, want) {
		t.Errorf("Admin.RenameOrg returned %+v, want %+v", resp, want)
	}

	const methodName = "RenameOrgByName"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Admin.RenameOrgByName(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Admin.RenameOrgByName(ctx, "o", "the-new-octocats")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestCreateOrgRequest_Marshal(t *testing.T) {
	testJSONMarshal(t, &createOrgRequest{}, "{}")

	u := &createOrgRequest{
		Login: String("l"),
		Admin: String("a"),
	}

	want := `{
		"login": "l",
		"admin": "a"
	}`

	testJSONMarshal(t, u, want)
}

func TestRenameOrgRequest_Marshal(t *testing.T) {
	testJSONMarshal(t, &renameOrgRequest{}, "{}")

	u := &renameOrgRequest{
		Login: String("l"),
	}

	want := `{
		"login": "l"
	}`

	testJSONMarshal(t, u, want)
}

func TestRenameOrgResponse_Marshal(t *testing.T) {
	testJSONMarshal(t, &renameOrgRequest{}, "{}")

	u := &RenameOrgResponse{
		Message: String("m"),
		URL:     String("u"),
	}

	want := `{
		"message": "m",
		"url": "u"
	}`

	testJSONMarshal(t, u, want)
}
<|endoftext|>


<commit_before>package ip4defrag

import (
	"container/list"
	"fmt"
	"log"
	"sync"
	"time"

	"code.google.com/p/gopacket"
	"code.google.com/p/gopacket/layers"
)

// Quick and Easy to use debug code to trace
// how defrag works.
var debug debugging = false // or flip to false
type debugging bool

func (d debugging) Printf(format string, args ...interface{}) {
	if d {
		log.Printf(format, args...)
	}
}

const (
	IPv4MinimumFragmentSize    = 576
	IPv4MaximumSize            = 65535
	IPv4MaximumFragmentOffset  = 8189
	IPv4MaximumFragmentListLen = 8
)

// DefragIPv4 takes in an IPv4 packet with a fragment payload.
//
// It do not modify the IPv4 layer in place, 'in' remains untouched
// It returns a ready-to be used IPv4 layer.
//
// If the passed-in IPv4 layer is NOT fragmented, it will
// immediately return it without modifying the layer.
//
// If the IPv4 layer is a fragment and we don't have all
// fragments, it will return nil and store whatever internal
// information it needs to eventually defrag the packet.
//
// If the IPv4 layer is the last fragment needed to reconstruct
// the packet, a new IPv4 layer will be returned, and will be set to
// the entire defragmented packet,
//
// It use a map of all the running flows
//
// Usage example:
//
// func HandlePacket(in *layers.IPv4) err {
//     defragger := ip4defrag.NewIPv4Defrag()
//     in, err := defragger.DefragIPv4(in)
//     if err != nil {
//         return err
//     } else if in == nil {
//         return nil  // packet fragment, we don't have whole packet yet.
//     }
//     // At this point, we know that 'in' is defragmented.
//     //It may be the same 'in' passed to
//	   // HandlePacket, or it may not, but we don't really care :)
//	   ... do stuff to 'in' ...
//}
//
func (d *IPv4Defragmenter) DefragIPv4(in *layers.IPv4) (*layers.IPv4, error) {
	// check if we need to defrag
	if st := d.dontDefrag(in); st == true {
		return in, nil
	}
	// perfom security checks
	st, err := d.securityChecks(in)
	if err != nil || st == false {
		return nil, err
	}

	// ok, got a fragment
	debug.Printf("defrag: got in.Id=%d in.FragOffset=%d in.Flags=%d\n",
		in.Id, in.FragOffset*8, in.Flags)

	// do we already has seen a flow between src/dst with that Id
	ipf := newIPv4Flow(in)
	var fl *fragmentList
	var exist bool
	d.Lock()
	fl, exist = d.ipFlows[ipf]
	if !exist {
		debug.Printf("defrag: creating a new flow\n")
		fl = new(fragmentList)
		d.ipFlows[ipf] = fl
	}
	d.Unlock()
	// insert, and if final build it
	out, err2 := fl.insert(in)

	// at last, if we hit the maximum frag list len
	// without any defrag success, we just drop everything and
	// raise an error
	if out == nil && fl.List.Len()+1 > IPv4MaximumFragmentListLen {
		d.Lock()
		fl = new(fragmentList)
		d.ipFlows[ipf] = fl
		d.Unlock()
		return nil, fmt.Errorf("defrag: Fragment List hits its maximum"+
			"size(%d), without sucess. Flushing the list",
			IPv4MaximumFragmentListLen)
	}

	// if we got a packet, it's a new one, and he is defragmented
	if out != nil {
		return out, nil
	}
	return nil, err2
}

// DiscardOlderThan forgets all packets without any activity since
// time t. It returns the number of FragmentList aka number of
// fragment packets it has discarded.
func (d *IPv4Defragmenter) DiscardOlderThan(t time.Time) int {
	var nb int
	d.Lock()
	for k, v := range d.ipFlows {
		if v.LastSeen.Before(t) {
			nb = nb + 1
			delete(d.ipFlows, k)
		}
	}
	d.Unlock()
	return nb
}

// dontDefrag returns true if the IPv4 packet do not need
// any defragmentation
func (d *IPv4Defragmenter) dontDefrag(ip *layers.IPv4) bool {
	// don't defrag packet with DF flag
	if ip.Flags&layers.IPv4DontFragment != 0 {
		return true
	}
	// don't defrag not fragmented ones
	if ip.Flags == 0 && ip.Id == 0 {
		return true
	}
	return false
}

// securityChecks performs the needed security checks
func (d *IPv4Defragmenter) securityChecks(ip *layers.IPv4) (bool, error) {
	fragOffset := ip.FragOffset * 8
	// don't allow too big fragment offset
	if fragOffset > IPv4MaximumFragmentOffset {
		return false, fmt.Errorf("defrag: fragment offset too big "+
			"(handcrafted? %d > %d)", ip.FragOffset*8, IPv4MaximumFragmentOffset)
	}

	// don't allow fragment that would oversize an IP packet
	if fragOffset+ip.Length > IPv4MaximumSize {
		return false, fmt.Errorf("defrag: fragment will overrun "+
			"(handcrafted? %d > %d)", ip.FragOffset*8+ip.Length, IPv4MaximumSize)
	}

	return true, nil
}

// fragmentList holds a container/list used to contains IP
// packets/fragments.  It stores internal counters to track the
// maximum total of byte, and the current length it has received.
// It also stores a flag to know if he has seen the last packet.
type fragmentList struct {
	List          list.List
	Highest       uint16
	Current       uint16
	FinalReceived bool
	LastSeen      time.Time
}

// insert insert an IPv4 fragment/packet into the Fragment List
// It use the following strategy : we are inserting fragment based
// on their offset, latest first. This is sometimes called BSD-Right.
// See: http://www.sans.org/reading-room/whitepapers/detection/ip-fragment-reassembly-scapy-33969
func (f *fragmentList) insert(in *layers.IPv4) (*layers.IPv4, error) {
	// TODO: should keep a copy of *in in the list
	// or not (ie the packet source is reliable) ?
	fragOffset := in.FragOffset * 8
	if fragOffset >= f.Highest {
		f.List.PushBack(in)
	} else {
		for e := f.List.Front(); e != nil; e = e.Next() {
			frag, _ := e.Value.(*layers.IPv4)
			if in.FragOffset <= frag.FragOffset {
				debug.Printf("defrag: inserting frag %d before existing frag %d \n",
					fragOffset, frag.FragOffset*8)
				f.List.InsertBefore(in, e)
				break
			}
		}
	}
	// packet.Metadata().Timestamp should have been better, but
	// we don't have this info there...
	f.LastSeen = time.Now()

	fragLength := in.Length - 20
	// After inserting the Fragment, we update the counters
	if f.Highest < fragOffset+fragLength {
		f.Highest = fragOffset + fragLength
	}
	f.Current = f.Current + fragLength

	debug.Printf("defrag: insert ListLen: %d Highest:%d Current:%d\n",
		f.List.Len(),
		f.Highest, f.Current)

	// Final Fragment ?
	if in.Flags&layers.IPv4MoreFragments == 0 {
		f.FinalReceived = true
	}
	// Ready to try defrag ?
	if f.FinalReceived && f.Highest == f.Current {
		return f.build(in)
	}
	return nil, nil
}

// Build builds the final datagram, modifying ip in place.
// It puts priority to packet in the early position of the list.
// See Insert for more details.
func (f *fragmentList) build(in *layers.IPv4) (*layers.IPv4, error) {
	var final []byte
	var currentOffset uint16 = 0

	debug.Printf("defrag: building the datagram \n")
	for e := f.List.Front(); e != nil; e = e.Next() {
		frag, _ := e.Value.(*layers.IPv4)
		if frag.FragOffset*8 == currentOffset {
			debug.Printf("defrag: building - adding %d\n", frag.FragOffset*8)
			final = append(final, frag.Payload...)
			currentOffset = currentOffset + frag.Length - 20
		} else if frag.FragOffset*8 < currentOffset {
			// overlapping fragment - let's take only what we need
			startAt := currentOffset - frag.FragOffset*8
			debug.Printf("defrag: building - overlapping, starting at %d\n",
				startAt)
			if startAt > frag.Length-20 {
				return nil, fmt.Errorf("defrag: building - invalid fragment")
			}
			final = append(final, frag.Payload[startAt:]...)
			currentOffset = currentOffset + frag.FragOffset*8
		} else {
			// Houston - we have an hole !
			debug.Printf("defrag: hole found while building, " +
				"stopping the defrag process\n")
			return nil, fmt.Errorf("defrag: building - hole found")
		}
		debug.Printf("defrag: building - next is %d\n", currentOffset)
	}

	// TODO recompute IP Checksum
	out := in
	out.Payload = final
	out.Length = f.Highest
	out.FragOffset = 0
	out.Flags = 0

	return out, nil
}

// ipv4Flow is a struct to be used as a key.
type ipv4Flow struct {
	ip4 gopacket.Flow
	id  uint16
}

// newIPv4Flow returns a new initialized IPv4Flow
func newIPv4Flow(ip *layers.IPv4) ipv4Flow {
	return ipv4Flow{
		ip4: ip.NetworkFlow(),
		id:  ip.Id,
	}
}

// IPv4Defragmenter is a struct which embedded a map of
// all fragment/packet.
type IPv4Defragmenter struct {
	sync.RWMutex
	ipFlows map[ipv4Flow]*fragmentList
}

// NewIPv4Defragmenter returns a new IPv4Defragmenter
// with an initialized map.
func NewIPv4Defragmenter() *IPv4Defragmenter {
	return &IPv4Defragmenter{
		ipFlows: make(map[ipv4Flow]*fragmentList),
	}
}
<commit_msg>Rename IPv4Flow to ipv4 as its an internal struct<commit_after>package ip4defrag

import (
	"container/list"
	"fmt"
	"log"
	"sync"
	"time"

	"code.google.com/p/gopacket"
	"code.google.com/p/gopacket/layers"
)

// Quick and Easy to use debug code to trace
// how defrag works.
var debug debugging = false // or flip to false
type debugging bool

func (d debugging) Printf(format string, args ...interface{}) {
	if d {
		log.Printf(format, args...)
	}
}

const (
	IPv4MinimumFragmentSize    = 576
	IPv4MaximumSize            = 65535
	IPv4MaximumFragmentOffset  = 8189
	IPv4MaximumFragmentListLen = 8
)

// DefragIPv4 takes in an IPv4 packet with a fragment payload.
//
// It do not modify the IPv4 layer in place, 'in' remains untouched
// It returns a ready-to be used IPv4 layer.
//
// If the passed-in IPv4 layer is NOT fragmented, it will
// immediately return it without modifying the layer.
//
// If the IPv4 layer is a fragment and we don't have all
// fragments, it will return nil and store whatever internal
// information it needs to eventually defrag the packet.
//
// If the IPv4 layer is the last fragment needed to reconstruct
// the packet, a new IPv4 layer will be returned, and will be set to
// the entire defragmented packet,
//
// It use a map of all the running flows
//
// Usage example:
//
// func HandlePacket(in *layers.IPv4) err {
//     defragger := ip4defrag.NewIPv4Defrag()
//     in, err := defragger.DefragIPv4(in)
//     if err != nil {
//         return err
//     } else if in == nil {
//         return nil  // packet fragment, we don't have whole packet yet.
//     }
//     // At this point, we know that 'in' is defragmented.
//     //It may be the same 'in' passed to
//	   // HandlePacket, or it may not, but we don't really care :)
//	   ... do stuff to 'in' ...
//}
//
func (d *IPv4Defragmenter) DefragIPv4(in *layers.IPv4) (*layers.IPv4, error) {
	// check if we need to defrag
	if st := d.dontDefrag(in); st == true {
		return in, nil
	}
	// perfom security checks
	st, err := d.securityChecks(in)
	if err != nil || st == false {
		return nil, err
	}

	// ok, got a fragment
	debug.Printf("defrag: got in.Id=%d in.FragOffset=%d in.Flags=%d\n",
		in.Id, in.FragOffset*8, in.Flags)

	// do we already has seen a flow between src/dst with that Id
	ipf := newIPv4(in)
	var fl *fragmentList
	var exist bool
	d.Lock()
	fl, exist = d.ipFlows[ipf]
	if !exist {
		debug.Printf("defrag: creating a new flow\n")
		fl = new(fragmentList)
		d.ipFlows[ipf] = fl
	}
	d.Unlock()
	// insert, and if final build it
	out, err2 := fl.insert(in)

	// at last, if we hit the maximum frag list len
	// without any defrag success, we just drop everything and
	// raise an error
	if out == nil && fl.List.Len()+1 > IPv4MaximumFragmentListLen {
		d.Lock()
		fl = new(fragmentList)
		d.ipFlows[ipf] = fl
		d.Unlock()
		return nil, fmt.Errorf("defrag: Fragment List hits its maximum"+
			"size(%d), without sucess. Flushing the list",
			IPv4MaximumFragmentListLen)
	}

	// if we got a packet, it's a new one, and he is defragmented
	if out != nil {
		return out, nil
	}
	return nil, err2
}

// DiscardOlderThan forgets all packets without any activity since
// time t. It returns the number of FragmentList aka number of
// fragment packets it has discarded.
func (d *IPv4Defragmenter) DiscardOlderThan(t time.Time) int {
	var nb int
	d.Lock()
	for k, v := range d.ipFlows {
		if v.LastSeen.Before(t) {
			nb = nb + 1
			delete(d.ipFlows, k)
		}
	}
	d.Unlock()
	return nb
}

// dontDefrag returns true if the IPv4 packet do not need
// any defragmentation
func (d *IPv4Defragmenter) dontDefrag(ip *layers.IPv4) bool {
	// don't defrag packet with DF flag
	if ip.Flags&layers.IPv4DontFragment != 0 {
		return true
	}
	// don't defrag not fragmented ones
	if ip.Flags == 0 && ip.Id == 0 {
		return true
	}
	return false
}

// securityChecks performs the needed security checks
func (d *IPv4Defragmenter) securityChecks(ip *layers.IPv4) (bool, error) {
	fragOffset := ip.FragOffset * 8
	// don't allow too big fragment offset
	if fragOffset > IPv4MaximumFragmentOffset {
		return false, fmt.Errorf("defrag: fragment offset too big "+
			"(handcrafted? %d > %d)", ip.FragOffset*8, IPv4MaximumFragmentOffset)
	}

	// don't allow fragment that would oversize an IP packet
	if fragOffset+ip.Length > IPv4MaximumSize {
		return false, fmt.Errorf("defrag: fragment will overrun "+
			"(handcrafted? %d > %d)", ip.FragOffset*8+ip.Length, IPv4MaximumSize)
	}

	return true, nil
}

// fragmentList holds a container/list used to contains IP
// packets/fragments.  It stores internal counters to track the
// maximum total of byte, and the current length it has received.
// It also stores a flag to know if he has seen the last packet.
type fragmentList struct {
	List          list.List
	Highest       uint16
	Current       uint16
	FinalReceived bool
	LastSeen      time.Time
}

// insert insert an IPv4 fragment/packet into the Fragment List
// It use the following strategy : we are inserting fragment based
// on their offset, latest first. This is sometimes called BSD-Right.
// See: http://www.sans.org/reading-room/whitepapers/detection/ip-fragment-reassembly-scapy-33969
func (f *fragmentList) insert(in *layers.IPv4) (*layers.IPv4, error) {
	// TODO: should keep a copy of *in in the list
	// or not (ie the packet source is reliable) ?
	fragOffset := in.FragOffset * 8
	if fragOffset >= f.Highest {
		f.List.PushBack(in)
	} else {
		for e := f.List.Front(); e != nil; e = e.Next() {
			frag, _ := e.Value.(*layers.IPv4)
			if in.FragOffset <= frag.FragOffset {
				debug.Printf("defrag: inserting frag %d before existing frag %d \n",
					fragOffset, frag.FragOffset*8)
				f.List.InsertBefore(in, e)
				break
			}
		}
	}
	// packet.Metadata().Timestamp should have been better, but
	// we don't have this info there...
	f.LastSeen = time.Now()

	fragLength := in.Length - 20
	// After inserting the Fragment, we update the counters
	if f.Highest < fragOffset+fragLength {
		f.Highest = fragOffset + fragLength
	}
	f.Current = f.Current + fragLength

	debug.Printf("defrag: insert ListLen: %d Highest:%d Current:%d\n",
		f.List.Len(),
		f.Highest, f.Current)

	// Final Fragment ?
	if in.Flags&layers.IPv4MoreFragments == 0 {
		f.FinalReceived = true
	}
	// Ready to try defrag ?
	if f.FinalReceived && f.Highest == f.Current {
		return f.build(in)
	}
	return nil, nil
}

// Build builds the final datagram, modifying ip in place.
// It puts priority to packet in the early position of the list.
// See Insert for more details.
func (f *fragmentList) build(in *layers.IPv4) (*layers.IPv4, error) {
	var final []byte
	var currentOffset uint16 = 0

	debug.Printf("defrag: building the datagram \n")
	for e := f.List.Front(); e != nil; e = e.Next() {
		frag, _ := e.Value.(*layers.IPv4)
		if frag.FragOffset*8 == currentOffset {
			debug.Printf("defrag: building - adding %d\n", frag.FragOffset*8)
			final = append(final, frag.Payload...)
			currentOffset = currentOffset + frag.Length - 20
		} else if frag.FragOffset*8 < currentOffset {
			// overlapping fragment - let's take only what we need
			startAt := currentOffset - frag.FragOffset*8
			debug.Printf("defrag: building - overlapping, starting at %d\n",
				startAt)
			if startAt > frag.Length-20 {
				return nil, fmt.Errorf("defrag: building - invalid fragment")
			}
			final = append(final, frag.Payload[startAt:]...)
			currentOffset = currentOffset + frag.FragOffset*8
		} else {
			// Houston - we have an hole !
			debug.Printf("defrag: hole found while building, " +
				"stopping the defrag process\n")
			return nil, fmt.Errorf("defrag: building - hole found")
		}
		debug.Printf("defrag: building - next is %d\n", currentOffset)
	}

	// TODO recompute IP Checksum
	out := in
	out.Payload = final
	out.Length = f.Highest
	out.FragOffset = 0
	out.Flags = 0

	return out, nil
}

// ipv4 is a struct to be used as a key.
type ipv4 struct {
	ip4 gopacket.Flow
	id  uint16
}

// newIPv4 returns a new initialized IPv4 Flow
func newIPv4(ip *layers.IPv4) ipv4 {
	return ipv4{
		ip4: ip.NetworkFlow(),
		id:  ip.Id,
	}
}

// IPv4Defragmenter is a struct which embedded a map of
// all fragment/packet.
type IPv4Defragmenter struct {
	sync.RWMutex
	ipFlows map[ipv4]*fragmentList
}

// NewIPv4Defragmenter returns a new IPv4Defragmenter
// with an initialized map.
func NewIPv4Defragmenter() *IPv4Defragmenter {
	return &IPv4Defragmenter{
		ipFlows: make(map[ipv4]*fragmentList),
	}
}
<|endoftext|>


<commit_before>package libkbfs

import (
	"crypto/tls"
	"crypto/x509"
	_ "encoding/base64"
	"encoding/hex"
	"errors"
	"io/ioutil"
	"net"
	"sync"
	"time"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
)

var (
	// ErrNoActiveConn is an error returned when this component
	// is not yet connected to the block server.
	ErrNoActiveConn = errors.New("Not connected to block server")
	// ErrConnTimeout is an error returned timed out (repeatedly)
	// while trying to connect to the block server.
	ErrConnTimeout = errors.New("Repeatedly failed to connect to block server")
	// BServerTimeout is the timeout for communications with block server.
	BServerTimeout = 60 * time.Second
)

// BlockServerRemote implements the BlockServer interface and
// represents a remote KBFS block server.
type BlockServerRemote struct {
	config Config

	srvAddr  string
	certFile string

	conn      net.Conn
	clt       keybase1.BlockClient
	connected bool

	lastTried time.Time
	retryMu   sync.Mutex
}

// NewBlockServerRemote constructs a new BlockServerRemote for the
// given address.
func NewBlockServerRemote(config Config, blkSrvAddr string) *BlockServerRemote {
	b := &BlockServerRemote{
		config:   config,
		srvAddr:  blkSrvAddr,
		certFile: "./cert.pem",
	}

	if err := b.ConnectOnce(); err != nil {
		go b.Reconnect()
	}

	return b
}

// TLSConnect connects over TLS to the given server, expecting the
// connection to be authenticated with the given certificate.
func TLSConnect(cFile string, Addr string) (conn net.Conn, err error) {
	CAPool := x509.NewCertPool()
	var cacert []byte
	cacert, err = ioutil.ReadFile(cFile)
	if err != nil {
		return
	}
	CAPool.AppendCertsFromPEM(cacert)

	config := tls.Config{RootCAs: CAPool}
	conn, err = tls.Dial("tcp", Addr, &config)
	if err != nil {
		return
	}
	return
}

func (b *BlockServerRemote) Config() Config {
	return b.config
}

// ConnectOnce tries once to connect to the remote block server.
func (b *BlockServerRemote) ConnectOnce() error {
	var err error
	if b.conn, err = TLSConnect(b.certFile, b.srvAddr); err != nil {
		return err
	}

	b.clt = keybase1.BlockClient{Cli: rpc2.NewClient(
		rpc2.NewTransport(b.conn, libkb.NewRpcLogFactory(), libkb.WrapError), libkb.UnwrapError)}

	var session *libkb.Session
	if session, err = b.config.KBPKI().GetSession(); err != nil {
		libkb.G.Log.Warning("error getting session, disconnect from backend: %q", err)
		b.conn.Close()
		return err
	}
	/*
		var token []byte
		if token, err = base64.StdEncoding.DecodeString(session.GetToken()); err != nil {
			b.conn.Close()
			return err
		}
	*/
	if err = b.clt.EstablishSession(session.GetToken()); err != nil {
		b.conn.Close()
		return err
	}

	b.connected = true
	return nil
}

// WaitForReconnect waits for the timeout period to reconnect to the
// server.
func (b *BlockServerRemote) WaitForReconnect() error {
	timeout := time.Now().Add(BServerTimeout)

	b.retryMu.Lock()
	defer b.retryMu.Unlock()

	for !b.connected {
		b.retryMu.Unlock()
		if time.Now().After(timeout) {
			return ErrConnTimeout
		}
		time.Sleep(1 * time.Second)
		b.retryMu.Lock()
	}
	return nil
}

// Reconnect reconnects to block server.
func (b *BlockServerRemote) Reconnect() {
	b.retryMu.Lock()
	defer b.retryMu.Unlock()

	for b.ConnectOnce() != nil {
		b.retryMu.Unlock()
		time.Sleep(1 * time.Second)
		b.retryMu.Lock()
	}
	return
}

// Shutdown closes the connection to this remote block server.
func (b *BlockServerRemote) Shutdown() {
	b.conn.Close()
}

// Get implements the BlockServer interface for BlockServerRemote.
func (b *BlockServerRemote) Get(id BlockID, context BlockContext) (
	[]byte, BlockCryptKeyServerHalf, error) {
	if !b.connected {
		if err := b.WaitForReconnect(); err != nil {
			return nil, BlockCryptKeyServerHalf{}, err
		}
	}
	bid := keybase1.BlockIdCombo{
		BlockHash: hex.EncodeToString(id[:]),
		Size:      int(context.GetQuotaSize()),
		ChargedTo: context.GetWriter(),
	}
	//XXX: if fails due to connection problem, should reconnect
	res, err := b.clt.GetBlock(bid)
	if err != nil {
		return nil, BlockCryptKeyServerHalf{}, err
	}

	// TODO: return the server-half of the block key
	if kbuf, err := hex.DecodeString(res.BlockKey); err != nil {
		return nil, BlockCryptKeyServerHalf{}, err
	} else {
		bk := BlockCryptKeyServerHalf{}
		copy(bk.ServerHalf[:], kbuf)
		return res.Buf, bk, err
	}
}

// Put implements the BlockServer interface for BlockServerRemote.
// TODO: store the server-half of the block key
func (b *BlockServerRemote) Put(id BlockID, context BlockContext,
	buf []byte, serverHalf BlockCryptKeyServerHalf) error {
	if !b.connected {
		if err := b.WaitForReconnect(); err != nil {
			return err
		}
	}
	arg := keybase1.PutBlockArg{
		Bid: keybase1.BlockIdCombo{
			ChargedTo: context.GetWriter(),
			BlockHash: hex.EncodeToString(id[:]),
			Size:      int(context.GetQuotaSize()),
		},
		BlockKey: hex.EncodeToString(serverHalf.ServerHalf[:]),
		Folder:   "", //XXX: strib needs to tell me what folder this block belongs
		Buf:      buf,
	}
	err := b.clt.PutBlock(arg)
	if err != nil {
		libkb.G.Log.Warning("PUT to backend err : %q", err)
	}
	return err
}

// Delete implements the BlockServer interface for BlockServerRemote.
func (b *BlockServerRemote) Delete(id BlockID, context BlockContext) error {
	arg := keybase1.DecBlockReferenceArg{
		Bid: keybase1.BlockIdCombo{
			ChargedTo: context.GetWriter(), //should be the original chargedto
			BlockHash: hex.EncodeToString(id[:]),
			Size:      int(context.GetQuotaSize()),
		},
		Nonce:     "0000",
		Folder:    "",
		ChargedTo: context.GetWriter(), //the actual writer to decrement quota from
	}
	err := b.clt.DecBlockReference(arg)
	if err != nil {
		libkb.G.Log.Warning("PUT to backend err : %q", err)
	}
	return err
}
<commit_msg>lint free<commit_after>package libkbfs

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/hex"
	"errors"
	"io/ioutil"
	"net"
	"sync"
	"time"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
)

var (
	// ErrNoActiveConn is an error returned when this component
	// is not yet connected to the block server.
	ErrNoActiveConn = errors.New("Not connected to block server")
	// ErrConnTimeout is an error returned timed out (repeatedly)
	// while trying to connect to the block server.
	ErrConnTimeout = errors.New("Repeatedly failed to connect to block server")
	// BServerTimeout is the timeout for communications with block server.
	BServerTimeout = 60 * time.Second
)

// BlockServerRemote implements the BlockServer interface and
// represents a remote KBFS block server.
type BlockServerRemote struct {
	config Config

	srvAddr  string
	certFile string

	conn      net.Conn
	clt       keybase1.BlockClient
	connected bool

	lastTried time.Time
	retryMu   sync.Mutex
}

// NewBlockServerRemote constructs a new BlockServerRemote for the
// given address.
func NewBlockServerRemote(config Config, blkSrvAddr string) *BlockServerRemote {
	b := &BlockServerRemote{
		config:   config,
		srvAddr:  blkSrvAddr,
		certFile: "./cert.pem",
	}

	if err := b.ConnectOnce(); err != nil {
		go b.Reconnect()
	}

	return b
}

// TLSConnect connects over TLS to the given server, expecting the
// connection to be authenticated with the given certificate.
func TLSConnect(cFile string, Addr string) (conn net.Conn, err error) {
	CAPool := x509.NewCertPool()
	var cacert []byte
	cacert, err = ioutil.ReadFile(cFile)
	if err != nil {
		return
	}
	CAPool.AppendCertsFromPEM(cacert)

	config := tls.Config{RootCAs: CAPool}
	conn, err = tls.Dial("tcp", Addr, &config)
	if err != nil {
		return
	}
	return
}

// Config returns the configuration object
func (b *BlockServerRemote) Config() Config {
	return b.config
}

// ConnectOnce tries once to connect to the remote block server.
func (b *BlockServerRemote) ConnectOnce() error {
	var err error
	if b.conn, err = TLSConnect(b.certFile, b.srvAddr); err != nil {
		return err
	}

	b.clt = keybase1.BlockClient{Cli: rpc2.NewClient(
		rpc2.NewTransport(b.conn, libkb.NewRpcLogFactory(), libkb.WrapError), libkb.UnwrapError)}

	var session *libkb.Session
	if session, err = b.config.KBPKI().GetSession(); err != nil {
		libkb.G.Log.Warning("error getting session, disconnect from backend: %q", err)
		b.conn.Close()
		return err
	}
	/*
		var token []byte
		if token, err = base64.StdEncoding.DecodeString(session.GetToken()); err != nil {
			b.conn.Close()
			return err
		}
	*/
	if err = b.clt.EstablishSession(session.GetToken()); err != nil {
		b.conn.Close()
		return err
	}

	b.connected = true
	return nil
}

// WaitForReconnect waits for the timeout period to reconnect to the
// server.
func (b *BlockServerRemote) WaitForReconnect() error {
	timeout := time.Now().Add(BServerTimeout)

	b.retryMu.Lock()
	defer b.retryMu.Unlock()

	for !b.connected {
		b.retryMu.Unlock()
		if time.Now().After(timeout) {
			return ErrConnTimeout
		}
		time.Sleep(1 * time.Second)
		b.retryMu.Lock()
	}
	return nil
}

// Reconnect reconnects to block server.
func (b *BlockServerRemote) Reconnect() {
	b.retryMu.Lock()
	defer b.retryMu.Unlock()

	for b.ConnectOnce() != nil {
		b.retryMu.Unlock()
		time.Sleep(1 * time.Second)
		b.retryMu.Lock()
	}
	return
}

// Shutdown closes the connection to this remote block server.
func (b *BlockServerRemote) Shutdown() {
	b.conn.Close()
}

// Get implements the BlockServer interface for BlockServerRemote.
func (b *BlockServerRemote) Get(id BlockID, context BlockContext) (
	[]byte, BlockCryptKeyServerHalf, error) {
	if !b.connected {
		if err := b.WaitForReconnect(); err != nil {
			return nil, BlockCryptKeyServerHalf{}, err
		}
	}
	bid := keybase1.BlockIdCombo{
		BlockHash: hex.EncodeToString(id[:]),
		Size:      int(context.GetQuotaSize()),
		ChargedTo: context.GetWriter(),
	}
	//XXX: if fails due to connection problem, should reconnect
	res, err := b.clt.GetBlock(bid)
	if err != nil {
		return nil, BlockCryptKeyServerHalf{}, err
	}

	// TODO: return the server-half of the block key
	bk := BlockCryptKeyServerHalf{}
	if kbuf, err := hex.DecodeString(res.BlockKey); err == nil {
		copy(bk.ServerHalf[:], kbuf)
	}
	return res.Buf, bk, err
}

// Put implements the BlockServer interface for BlockServerRemote.
// TODO: store the server-half of the block key
func (b *BlockServerRemote) Put(id BlockID, context BlockContext,
	buf []byte, serverHalf BlockCryptKeyServerHalf) error {
	if !b.connected {
		if err := b.WaitForReconnect(); err != nil {
			return err
		}
	}
	arg := keybase1.PutBlockArg{
		Bid: keybase1.BlockIdCombo{
			ChargedTo: context.GetWriter(),
			BlockHash: hex.EncodeToString(id[:]),
			Size:      int(context.GetQuotaSize()),
		},
		BlockKey: hex.EncodeToString(serverHalf.ServerHalf[:]),
		Folder:   "", //XXX: strib needs to tell me what folder this block belongs
		Buf:      buf,
	}
	err := b.clt.PutBlock(arg)
	if err != nil {
		libkb.G.Log.Warning("PUT to backend err : %q", err)
	}
	return err
}

// Delete implements the BlockServer interface for BlockServerRemote.
func (b *BlockServerRemote) Delete(id BlockID, context BlockContext) error {
	arg := keybase1.DecBlockReferenceArg{
		Bid: keybase1.BlockIdCombo{
			ChargedTo: context.GetWriter(), //should be the original chargedto
			BlockHash: hex.EncodeToString(id[:]),
			Size:      int(context.GetQuotaSize()),
		},
		Nonce:     "0000",
		Folder:    "",
		ChargedTo: context.GetWriter(), //the actual writer to decrement quota from
	}
	err := b.clt.DecBlockReference(arg)
	if err != nil {
		libkb.G.Log.Warning("PUT to backend err : %q", err)
	}
	return err
}
<|endoftext|>


<commit_before>package device

import (
	"fmt"
	"path/filepath"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/xshellinc/esp-flasher/serialport"
	"github.com/xshellinc/go-serial"
	"github.com/xshellinc/iotit/device/config"
	"github.com/xshellinc/iotit/workstation"
	"github.com/xshellinc/tools/dialogs"
	"github.com/xshellinc/tools/lib/help"
)

const (
	COLIBRI = "colibri"
)

var serialPort serial.Serial

const portSelectionTries = 3

// toradex colibri imx6 device
type colibri struct {
	*flasher
	Port string
	Disk string
}

// Prepare overrides flasher Prepare method with port initialization
func (d *colibri) Prepare() error {
	// start VM, upload image and extract it
	d.flasher.Prepare()
	log.WithField("device", COLIBRI).Debug("Prepare")
	// install toradex flasher dependencies
	d.installTools()
	return nil
}

func (d *colibri) getPort() error {
	if d.Port != "" {
		return nil
	}
	var perr error
	for attempt := 0; attempt < portSelectionTries; attempt++ {
		if attempt > 0 && !dialogs.YesNoDialog("No ports found. Reconnect your device and try again. Ready?") {
			return perr
		}
		fmt.Println("[+] Enumerating serial ports...")
		port, err := serialport.GetPort("auto")
		if err != nil {
			perr = err
			continue
		}
		d.Port = port
		break
	}
	if d.Port == "" {
		return perr
	}
	fmt.Println("[+] Using ", dialogs.PrintColored(d.Port))
	return nil
}

// Configure overrides flasher Configure() method with custom image configuration
func (d *colibri) Configure() error {
	log.WithField("device", COLIBRI).Debug("Configure")
	fmt.Println("[+] Configuring...")

	job := help.NewBackgroundJob()

	go func() {
		defer job.Close()

		if err := d.configureImage(); err != nil {
			job.Error(err)
			return
		}
	}()

	if err := help.WaitJobAndSpin("Preparing", job); err != nil {
		return err
	}

	fmt.Println("[+] Image ready")
	return nil
}

// Flash configures and flashes image
func (d *colibri) Flash() error {
	if err := d.Prepare(); err != nil {
		return err
	}

	if err := d.Configure(); err != nil {
		return err
	}

	if err := d.Write(); err != nil {
		return err
	}

	return d.Done()
}

func (d *colibri) installTools() error {
	if err := d.exec("apk add dosfstools parted sudo e2fsprogs-extra coreutils libattr zip"); err != nil {
		return err
	}
	return nil
}

func (d *colibri) configureImage() error {
	d.img = "colibri_image.zip"

	log.Debug("Creating tmp folder")
	command := fmt.Sprintf("mkdir -p %s", config.MountDir)
	if err := d.exec(command); err != nil {
		return err
	}
	log.Debug("Running update.sh")
	command = fmt.Sprintf("cd %s && ./update.sh -o %s", help.AddPathSuffix("unix", config.TmpDir, d.folder), config.MountDir)
	if err := d.exec(command); err != nil {
		return err
	}
	command = fmt.Sprintf("cd %s && zip -0 -r ../%s *", config.MountDir, d.img)
	if err := d.exec(command); err != nil {
		return err
	}
	return nil
}

// Write - writes image to SD card
func (d *colibri) Write() error {
	if d.img != "" {
		log.WithField("img", d.img).Debug("Downloading image from vbox")

		job := help.NewBackgroundJob()
		go func() {
			defer job.Close()
			if err := d.conf.SSH.ScpFrom(help.AddPathSuffix("unix", config.TmpDir, d.img), filepath.Join(help.GetTempDir(), d.img)); err != nil {
				job.Error(err)
			}
		}()

		if err := help.WaitJobAndSpin("Copying files", job); err != nil {
			log.Error(err)
			return err
		}
	} else {
		d.img = "colibri_image.zip"
	}

	flash_only := d.flasher.CLI.Bool("flash")
	if !flash_only {
		w := workstation.NewWorkStation(d.Disk)
		img := filepath.Join(help.GetTempDir(), d.img)

		log.WithField("img", img).Debug("Writing image to disk")

		if job, err := w.CopyToDisk(img); err != nil {
			return err
		} else if job != nil {
			if err := help.WaitJobAndSpin("Writing image files to SD card", job); err != nil {
				return err
			}
		}
		time.Sleep(time.Second * 2)
		w.Unmount()
		fmt.Println("[+] SD card prepared")
	}
	if d.Port == "" {
		if err := d.getPort(); err != nil {
			log.Error(err)
			return err
		}
	}
	commonOpts := serial.OpenOptions{
		BaudRate:              115200,
		DataBits:              8,
		ParityMode:            serial.PARITY_NONE,
		StopBits:              1,
		InterCharacterTimeout: 200.0,
		PortName:              d.Port,
	}
	var err error
	serialPort, err = serial.Open(commonOpts)
	if err != nil {
		return err
	}

	defer serialPort.Close()

	if err := d.runUpdate(); err != nil {
		return err
	}

	return nil
}

func readResponse() string {
	data := make([]byte, 10000)
	if _, err := serialPort.Read(data); err != nil {
		log.Error(err)
	}
	line := strings.TrimSpace(string(data))
	log.WithField("data", line).Debug("Response")
	return line
}

func rebootBoard() error {
	serialPort.SetReadTimeout(time.Second * 5)
	if _, err := serialPort.Write([]byte("\r\n")); err != nil {
		log.Error(err)
		serialPort.Write([]byte("\r\n"))
	}
	for {
		line := readResponse()
		if line != "" {
			if strings.Contains(line, "imx6 login:") {
				if _, err := serialPort.Write([]byte("root\r\n")); err != nil {
					log.Error(err)
				}
				readResponse() //command echo
				readResponse() //response
				time.Sleep(time.Second * 2)
				if _, err := serialPort.Write([]byte("reboot\r\n")); err != nil {
					log.Error(err)
				}
				readResponse() //command echo
				readResponse() //response
				time.Sleep(time.Second * 2)
				return nil
			}
		}
	}
	return nil
}

func bootInRecovery() *help.BackgroundJob {
	job := help.NewBackgroundJob()
	go func() {
		defer job.Close()
		for {
			if _, err := serialPort.Write([]byte(" ")); err != nil {
				job.Error(err)
			}
			data := make([]byte, 10000)
			if _, err := serialPort.Read(data); err == nil {
				log.WithField("data", string(data)).Debug("Response")
				if strings.Contains(string(data), "Colibri iMX6 #") || strings.Contains(string(data), "iMX6 #") {
					break
				}
			}
		}
	}()
	return job
}

func (d *colibri) runUpdate() error {
	for !dialogs.YesNoDialog("Please insert prepared SD card into your Colibri iMX6 board. Type yes once ready.") {
	}
	message := "Now reset or power up the board"
	if !dialogs.YesNoDialog("Do you have a reset button on your carrier board?") {
		fmt.Println("[+] Trying to reboot the board")
		rebootBoard()
		message = "Booting in recovery"
	}
	job := bootInRecovery()
	if err := help.WaitJobAndSpin(message, job); err != nil {
		log.Error(err)
		return err
	}
	fmt.Println("[+] Flashing to eMMC")
	if _, err := serialPort.Write([]byte("run setupdate\r\n")); err != nil {
		log.Error(err)
	}

	readResponse()
	time.Sleep(time.Second * 1)
	readResponse()
	time.Sleep(time.Second * 2)
	if n, err := serialPort.Write([]byte("run update\r\n")); err != nil {
		log.Error(err)
	} else {
		log.Debug("Written:", n)
	}
	readResponse()
	for {
		serialPort.SetReadTimeout(time.Second * 5)
		line := readResponse()
		fmt.Print(line)
		if strings.Contains(line, "resetting") {
			fmt.Println("[+] Done! Rebooting the board.")
			return nil
		}
	}

	return nil
}

func (d *colibri) exec(command string) error {
	log.Debug(command)
	if out, eut, err := d.conf.SSH.Run(command); err != nil {
		log.Error("[-] Error executing: ", command, eut)
		return err
	} else if strings.TrimSpace(out) != "" {
		log.Debug(strings.TrimSpace(out))
	}
	return nil
}
<commit_msg>Make linter happier<commit_after>package device

import (
	"fmt"
	"path/filepath"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/xshellinc/esp-flasher/serialport"
	"github.com/xshellinc/go-serial"
	"github.com/xshellinc/iotit/device/config"
	"github.com/xshellinc/iotit/workstation"
	"github.com/xshellinc/tools/dialogs"
	"github.com/xshellinc/tools/lib/help"
)

var serialPort serial.Serial

const portSelectionTries = 3

// toradex colibri imx6 device
type colibri struct {
	*flasher
	Port string
	Disk string
}

// Prepare overrides flasher Prepare method with port initialization
func (d *colibri) Prepare() error {
	// start VM, upload image and extract it
	d.flasher.Prepare()
	log.WithField("device", "colibri").Debug("Prepare")
	// install toradex flasher dependencies
	d.installTools()
	return nil
}

func (d *colibri) getPort() error {
	if d.Port != "" {
		return nil
	}
	var perr error
	for attempt := 0; attempt < portSelectionTries; attempt++ {
		if attempt > 0 && !dialogs.YesNoDialog("No ports found. Reconnect your device and try again. Ready?") {
			return perr
		}
		fmt.Println("[+] Enumerating serial ports...")
		port, err := serialport.GetPort("auto")
		if err != nil {
			perr = err
			continue
		}
		d.Port = port
		break
	}
	if d.Port == "" {
		return perr
	}
	fmt.Println("[+] Using ", dialogs.PrintColored(d.Port))
	return nil
}

// Configure overrides flasher Configure() method with custom image configuration
func (d *colibri) Configure() error {
	log.WithField("device", "colibri").Debug("Configure")
	fmt.Println("[+] Configuring...")

	job := help.NewBackgroundJob()

	go func() {
		defer job.Close()

		if err := d.configureImage(); err != nil {
			job.Error(err)
			return
		}
	}()

	if err := help.WaitJobAndSpin("Preparing", job); err != nil {
		return err
	}

	fmt.Println("[+] Image ready")
	return nil
}

// Flash configures and flashes image
func (d *colibri) Flash() error {
	if err := d.Prepare(); err != nil {
		return err
	}

	if err := d.Configure(); err != nil {
		return err
	}

	if err := d.Write(); err != nil {
		return err
	}

	return d.Done()
}

func (d *colibri) installTools() error {
	if err := d.exec("apk add dosfstools parted sudo e2fsprogs-extra coreutils libattr zip"); err != nil {
		return err
	}
	return nil
}

func (d *colibri) configureImage() error {
	d.img = "colibri_image.zip"

	log.Debug("Creating tmp folder")
	command := fmt.Sprintf("mkdir -p %s", config.MountDir)
	if err := d.exec(command); err != nil {
		return err
	}
	log.Debug("Running update.sh")
	command = fmt.Sprintf("cd %s && ./update.sh -o %s", help.AddPathSuffix("unix", config.TmpDir, d.folder), config.MountDir)
	if err := d.exec(command); err != nil {
		return err
	}
	command = fmt.Sprintf("cd %s && zip -0 -r ../%s *", config.MountDir, d.img)
	if err := d.exec(command); err != nil {
		return err
	}
	return nil
}

// Write - writes image to SD card
func (d *colibri) Write() error {
	if d.img != "" {
		log.WithField("img", d.img).Debug("Downloading image from vbox")

		job := help.NewBackgroundJob()
		go func() {
			defer job.Close()
			if err := d.conf.SSH.ScpFrom(help.AddPathSuffix("unix", config.TmpDir, d.img), filepath.Join(help.GetTempDir(), d.img)); err != nil {
				job.Error(err)
			}
		}()

		if err := help.WaitJobAndSpin("Copying files", job); err != nil {
			log.Error(err)
			return err
		}
	} else {
		d.img = "colibri_image.zip"
	}

	flashOnly := d.flasher.CLI.Bool("flash")
	if !flashOnly {
		w := workstation.NewWorkStation(d.Disk)
		img := filepath.Join(help.GetTempDir(), d.img)

		log.WithField("img", img).Debug("Writing image to disk")

		if job, err := w.CopyToDisk(img); err != nil {
			return err
		} else if job != nil {
			if err := help.WaitJobAndSpin("Writing image files to SD card", job); err != nil {
				return err
			}
		}
		time.Sleep(time.Second * 2)
		w.Unmount()
		fmt.Println("[+] SD card prepared")
	}
	if d.Port == "" {
		if err := d.getPort(); err != nil {
			log.Error(err)
			return err
		}
	}
	commonOpts := serial.OpenOptions{
		BaudRate:              115200,
		DataBits:              8,
		ParityMode:            serial.PARITY_NONE,
		StopBits:              1,
		InterCharacterTimeout: 200.0,
		PortName:              d.Port,
	}
	var err error
	serialPort, err = serial.Open(commonOpts)
	if err != nil {
		return err
	}

	defer serialPort.Close()

	if err := d.runUpdate(); err != nil {
		return err
	}

	return nil
}

func readResponse() string {
	data := make([]byte, 10000)
	if _, err := serialPort.Read(data); err != nil {
		log.Error(err)
	}
	line := strings.TrimSpace(string(data))
	log.WithField("data", line).Debug("Response")
	return line
}

func rebootBoard() error {
	serialPort.SetReadTimeout(time.Second * 5)
	if _, err := serialPort.Write([]byte("\r\n")); err != nil {
		log.Error(err)
		serialPort.Write([]byte("\r\n"))
	}
	for {
		line := readResponse()
		if line != "" {
			if strings.Contains(line, "imx6 login:") {
				if _, err := serialPort.Write([]byte("root\r\n")); err != nil {
					log.Error(err)
				}
				readResponse() //command echo
				readResponse() //response
				time.Sleep(time.Second * 2)
				if _, err := serialPort.Write([]byte("reboot\r\n")); err != nil {
					log.Error(err)
				}
				readResponse() //command echo
				readResponse() //response
				time.Sleep(time.Second * 2)
				return nil
			}
		}
	}
}

func bootInRecovery() *help.BackgroundJob {
	job := help.NewBackgroundJob()
	go func() {
		defer job.Close()
		for {
			if _, err := serialPort.Write([]byte(" ")); err != nil {
				job.Error(err)
			}
			data := make([]byte, 10000)
			if _, err := serialPort.Read(data); err == nil {
				log.WithField("data", string(data)).Debug("Response")
				if strings.Contains(string(data), "Colibri iMX6 #") || strings.Contains(string(data), "iMX6 #") {
					break
				}
			}
		}
	}()
	return job
}

func (d *colibri) runUpdate() error {
	for !dialogs.YesNoDialog("Please insert prepared SD card into your Colibri iMX6 board. Type yes once ready.") {
	}
	message := "Now reset or power up the board"
	if !dialogs.YesNoDialog("Do you have a reset button on your carrier board?") {
		fmt.Println("[+] Trying to reboot the board")
		rebootBoard()
		message = "Booting in recovery"
	}
	job := bootInRecovery()
	if err := help.WaitJobAndSpin(message, job); err != nil {
		log.Error(err)
		return err
	}
	fmt.Println("[+] Flashing to eMMC")
	if _, err := serialPort.Write([]byte("run setupdate\r\n")); err != nil {
		log.Error(err)
	}

	readResponse()
	time.Sleep(time.Second * 1)
	readResponse()
	time.Sleep(time.Second * 2)
	if n, err := serialPort.Write([]byte("run update\r\n")); err != nil {
		log.Error(err)
	} else {
		log.Debug("Written:", n)
	}
	readResponse()
	for {
		serialPort.SetReadTimeout(time.Second * 5)
		line := readResponse()
		fmt.Print(line)
		if strings.Contains(line, "resetting") {
			fmt.Println("[+] Done! Rebooting the board.")
			return nil
		}
	}
}

func (d *colibri) exec(command string) error {
	log.Debug(command)
	if out, eut, err := d.conf.SSH.Run(command); err != nil {
		log.Error("[-] Error executing: ", command, eut)
		return err
	} else if strings.TrimSpace(out) != "" {
		log.Debug(strings.TrimSpace(out))
	}
	return nil
}
<|endoftext|>


<commit_before>package persist

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/maliceio/malice/utils/clitable"
	"github.com/rakyll/magicmime"
	// "github.com/dutchcoders/gossdeep"
)

// File is a file object
type File struct {
	Name   string
	Path   string
	Valid  bool
	Size   int64
	CRC32  string
	MD5    string
	SHA1   string
	SHA256 string
	SHA512 string
	Ssdeep string
	Mime   string
	Arch   string
	Data   []byte
}

// Init initializes the File object
func (file *File) Init() {
	if file.Path != "" {
		file.GetSize()
		file.getData()
		file.GetCRC32()
		file.GetMD5()
		file.GetSHA1()
		file.GetSHA256()
		file.GetSHA512()
		file.GetFileMimeType()
		file.Data = nil
	} else {
		log.Fatalf("error occured during file.Init() because file.Path was not set.")
	}
}

// GetSize calculates file Size
func (file *File) GetSize() (bytes int64, err error) {
	fileHandle, err := os.Open(file.Path)
	if err != nil {
		return
	}
	defer fileHandle.Close()

	stat, err := fileHandle.Stat()
	if err != nil {
		return
	}

	bytes = stat.Size()

	file.Size = bytes

	return
}

// getData loads file into []bytes
// TODO: This is probably pretty dumb to keep this data in memory
func (file *File) getData() {
	dat, err := ioutil.ReadFile(file.Path)
	assert(err)
	file.Data = dat
}

// GetCRC32 calculates the Files CRC32
func (file *File) GetCRC32() (hCRC32Sum string, err error) {

	var castagnoliTable = crc32.MakeTable(crc32.Castagnoli)

	crc := crc32.New(castagnoliTable)
	_, err = crc.Write(file.Data)
	assert(err)
	hCRC32Sum = fmt.Sprintf("%x", crc.Sum32())

	file.CRC32 = hCRC32Sum

	return
}

// GetMD5 calculates the Files md5sum
func (file *File) GetMD5() (hMd5Sum string, err error) {

	hmd5 := md5.New()
	_, err = hmd5.Write(file.Data)
	assert(err)
	hMd5Sum = fmt.Sprintf("%x", hmd5.Sum(nil))

	file.MD5 = hMd5Sum

	return
}

// GetSHA1 calculates the Files sha256sum
func (file *File) GetSHA1() (h1Sum string, err error) {

	h1 := sha1.New()
	_, err = h1.Write(file.Data)
	assert(err)
	h1Sum = fmt.Sprintf("%x", h1.Sum(nil))

	file.SHA1 = h1Sum

	return
}

// GetSHA256 calculates the Files sha256sum
func (file *File) GetSHA256() (h256Sum string, err error) {

	h256 := sha256.New()
	_, err = h256.Write(file.Data)
	assert(err)
	h256Sum = fmt.Sprintf("%x", h256.Sum(nil))

	file.SHA256 = h256Sum

	return
}

// GetSHA512 calculates the Files sha256sum
func (file *File) GetSHA512() (h512Sum string, err error) {

	h256 := sha256.New()
	_, err = h256.Write(file.Data)
	assert(err)
	h512Sum = fmt.Sprintf("%x", h256.Sum(nil))

	file.SHA512 = h512Sum

	return
}

// GetFileMimeType returns the mime-type of a file path
func (file *File) GetFileMimeType() (mimetype string, err error) {

	if err := magicmime.Open(magicmime.MAGIC_MIME_TYPE | magicmime.MAGIC_SYMLINK | magicmime.MAGIC_ERROR); err != nil {
		log.Fatal(err)
	}
	defer magicmime.Close()

	mimetype, err = magicmime.TypeByFile(file.Path)
	if err != nil {
		log.Fatalf("error occured during type lookup: %v", err)
	}

	file.Mime = mimetype
	// log.Printf("mime-type: %v", mimetype)
	return
}

// PrintFileDetails prints file details
func (file *File) PrintFileDetails() {
	table := clitable.New([]string{"Field", "Value"})
	table.AddRow(map[string]interface{}{"Field": "Name", "Value": file.Name})
	table.AddRow(map[string]interface{}{"Field": "Path", "Value": file.Path})
	table.AddRow(map[string]interface{}{"Field": "Valid", "Value": file.Valid})
	table.AddRow(map[string]interface{}{"Field": "Size", "Value": file.Size})
	table.AddRow(map[string]interface{}{"Field": "CRC32", "Value": file.CRC32})
	table.AddRow(map[string]interface{}{"Field": "MD5", "Value": file.MD5})
	table.AddRow(map[string]interface{}{"Field": "SHA1", "Value": file.SHA1})
	table.AddRow(map[string]interface{}{"Field": "SHA256", "Value": file.SHA256})
	table.AddRow(map[string]interface{}{"Field": "SHA512", "Value": file.SHA512})
	table.AddRow(map[string]interface{}{"Field": "Ssdeep", "Value": file.Ssdeep})
	table.AddRow(map[string]interface{}{"Field": "Mime", "Value": file.Mime})
	table.Markdown = true
	table.Print()
	// fmt.Println("Name: ", file.Name)
	// fmt.Println("Path: ", file.Path)
	// fmt.Println("Valid: ", file.Valid)
	// fmt.Println("Size: ", file.Size)
	// fmt.Println("CRC32: ", file.CRC32)
	// fmt.Println("MD5: ", file.MD5)
	// fmt.Println("SHA1: ", file.SHA1)
	// fmt.Println("SHA256: ", file.SHA256)
	// fmt.Println("SHA512: ", file.SHA512)
	// fmt.Println("Ssdeep: ", file.Ssdeep)
	// fmt.Println("Mime: ", file.Mime)
}

// // GetSsdeep calculates the Files ssdeep
// func (file File) GetSsdeep(data []byte) (hssdeep string, err error) {
//
// 	hssdeep, err = ssdeep.HashFilename(file)
// 	if err != nil {
// 		return "", err
// 	}
//
// 	return
// }
//
// // CompareSsdeep returns the percent that two hashes are similar
// func CompareSsdeep(firstHash, secondHash string) (percent int, err error) {
//
// 	percent, err = ssdeep.Compare(firstHash, secondHash)
// 	if err != nil {
// 		return 0, err
// 	}
//
// 	return
// }

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>add file.Name<commit_after>package persist

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/maliceio/malice/utils/clitable"
	"github.com/rakyll/magicmime"
	// "github.com/dutchcoders/gossdeep"
)

// File is a file object
type File struct {
	Name   string
	Path   string
	Valid  bool
	Size   int64
	CRC32  string
	MD5    string
	SHA1   string
	SHA256 string
	SHA512 string
	Ssdeep string
	Mime   string
	Arch   string
	Data   []byte
}

// Init initializes the File object
func (file *File) Init() {
	if file.Path != "" {
		file.GetName()
		file.GetSize()
		file.getData()
		file.GetCRC32()
		file.GetMD5()
		file.GetSHA1()
		file.GetSHA256()
		file.GetSHA512()
		file.GetFileMimeType()
		file.Data = nil
	} else {
		log.Fatalf("error occured during file.Init() because file.Path was not set.")
	}
}

// GetName returns file name
func (file *File) GetName() (name string, err error) {
	fileHandle, err := os.Open(file.Path)
	if err != nil {
		return
	}
	defer fileHandle.Close()

	stat, err := fileHandle.Stat()
	if err != nil {
		return
	}

	name = stat.Name()

	file.Name = name

	return
}

// GetSize calculates file Size
func (file *File) GetSize() (bytes int64, err error) {
	fileHandle, err := os.Open(file.Path)
	if err != nil {
		return
	}
	defer fileHandle.Close()

	stat, err := fileHandle.Stat()
	if err != nil {
		return
	}
	stat.Name()
	bytes = stat.Size()

	file.Size = bytes

	return
}

// getData loads file into []bytes
// TODO: This is probably pretty dumb to keep this data in memory
func (file *File) getData() {
	dat, err := ioutil.ReadFile(file.Path)
	assert(err)
	file.Data = dat
}

// GetCRC32 calculates the Files CRC32
func (file *File) GetCRC32() (hCRC32Sum string, err error) {

	var castagnoliTable = crc32.MakeTable(crc32.Castagnoli)

	crc := crc32.New(castagnoliTable)
	_, err = crc.Write(file.Data)
	assert(err)
	hCRC32Sum = fmt.Sprintf("%x", crc.Sum32())

	file.CRC32 = hCRC32Sum

	return
}

// GetMD5 calculates the Files md5sum
func (file *File) GetMD5() (hMd5Sum string, err error) {

	hmd5 := md5.New()
	_, err = hmd5.Write(file.Data)
	assert(err)
	hMd5Sum = fmt.Sprintf("%x", hmd5.Sum(nil))

	file.MD5 = hMd5Sum

	return
}

// GetSHA1 calculates the Files sha256sum
func (file *File) GetSHA1() (h1Sum string, err error) {

	h1 := sha1.New()
	_, err = h1.Write(file.Data)
	assert(err)
	h1Sum = fmt.Sprintf("%x", h1.Sum(nil))

	file.SHA1 = h1Sum

	return
}

// GetSHA256 calculates the Files sha256sum
func (file *File) GetSHA256() (h256Sum string, err error) {

	h256 := sha256.New()
	_, err = h256.Write(file.Data)
	assert(err)
	h256Sum = fmt.Sprintf("%x", h256.Sum(nil))

	file.SHA256 = h256Sum

	return
}

// GetSHA512 calculates the Files sha256sum
func (file *File) GetSHA512() (h512Sum string, err error) {

	h512 := sha512.New()
	_, err = h512.Write(file.Data)
	assert(err)
	h512Sum = fmt.Sprintf("%x", h512.Sum(nil))

	file.SHA512 = h512Sum

	return
}

// GetFileMimeType returns the mime-type of a file path
func (file *File) GetFileMimeType() (mimetype string, err error) {

	if err := magicmime.Open(magicmime.MAGIC_MIME_TYPE | magicmime.MAGIC_SYMLINK | magicmime.MAGIC_ERROR); err != nil {
		log.Fatal(err)
	}
	defer magicmime.Close()

	mimetype, err = magicmime.TypeByFile(file.Path)
	if err != nil {
		log.Fatalf("error occured during type lookup: %v", err)
	}

	file.Mime = mimetype
	// log.Printf("mime-type: %v", mimetype)
	return
}

// PrintFileDetails prints file details
func (file *File) PrintFileDetails() {
	table := clitable.New([]string{"Field", "Value"})
	table.AddRow(map[string]interface{}{"Field": "Name", "Value": file.Name})
	table.AddRow(map[string]interface{}{"Field": "Path", "Value": file.Path})
	table.AddRow(map[string]interface{}{"Field": "Valid", "Value": file.Valid})
	table.AddRow(map[string]interface{}{"Field": "Size", "Value": file.Size})
	table.AddRow(map[string]interface{}{"Field": "CRC32", "Value": file.CRC32})
	table.AddRow(map[string]interface{}{"Field": "MD5", "Value": file.MD5})
	table.AddRow(map[string]interface{}{"Field": "SHA1", "Value": file.SHA1})
	table.AddRow(map[string]interface{}{"Field": "SHA256", "Value": file.SHA256})
	table.AddRow(map[string]interface{}{"Field": "SHA512", "Value": file.SHA512})
	table.AddRow(map[string]interface{}{"Field": "Ssdeep", "Value": file.Ssdeep})
	table.AddRow(map[string]interface{}{"Field": "Mime", "Value": file.Mime})
	table.Markdown = true
	table.Print()
	// fmt.Println("Name: ", file.Name)
	// fmt.Println("Path: ", file.Path)
	// fmt.Println("Valid: ", file.Valid)
	// fmt.Println("Size: ", file.Size)
	// fmt.Println("CRC32: ", file.CRC32)
	// fmt.Println("MD5: ", file.MD5)
	// fmt.Println("SHA1: ", file.SHA1)
	// fmt.Println("SHA256: ", file.SHA256)
	// fmt.Println("SHA512: ", file.SHA512)
	// fmt.Println("Ssdeep: ", file.Ssdeep)
	// fmt.Println("Mime: ", file.Mime)
}

// // GetSsdeep calculates the Files ssdeep
// func (file File) GetSsdeep(data []byte) (hssdeep string, err error) {
//
// 	hssdeep, err = ssdeep.HashFilename(file)
// 	if err != nil {
// 		return "", err
// 	}
//
// 	return
// }
//
// // CompareSsdeep returns the percent that two hashes are similar
// func CompareSsdeep(firstHash, secondHash string) (percent int, err error) {
//
// 	percent, err = ssdeep.Compare(firstHash, secondHash)
// 	if err != nil {
// 		return 0, err
// 	}
//
// 	return
// }

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Package Bitcoind is client librarie for bitcoind JSON RPC API

package bitcoind

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
)

const (
	// VERSION represents bicoind package version
	VERSION = 0.1
	// DEFAULT_RPCCLIENT_TIMEOUT represent http timeout for rcp client
	RPCCLIENT_TIMEOUT = 30
)

// A Bitcoind represents a Bitcoind client
type Bitcoind struct {
	client *rpcClient
}

// New return a new bitcoind
func New(host string, port int, user, passwd string, useSSL bool) (*Bitcoind, error) {
	rpcClient, err := newClient(host, port, user, passwd, useSSL)
	if err != nil {
		return nil, err
	}
	return &Bitcoind{rpcClient}, nil
}

// BackupWallet Safely copies wallet.dat to destination,
// which can be a directory or a path with filename on the remote server
func (b *Bitcoind) BackupWallet(destination string) error {
	r, err := b.client.call("backupwallet", []string{destination})
	return handleError(err, &r)
}

// DumpPrivKey return private key as string associated to public <address>
func (b *Bitcoind) DumpPrivKey(address string) (privKey string, err error) {
	r, err := b.client.call("dumpprivkey", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &privKey)
	return
}

// EncryptWallet encrypts the wallet with <passphrase>.
func (b *Bitcoind) EncryptWallet(passphrase string) error {
	r, err := b.client.call("encryptwallet", []string{passphrase})
	return handleError(err, &r)
}

// GetAccount returns the account associated with the given address.
func (b *Bitcoind) GetAccount(address string) (account string, err error) {
	r, err := b.client.call("getaccount", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &account)
	return
}

// GetAccountAddress Returns the current bitcoin address for receiving
// payments to this account.
// If account does not exist, it will be created along with an
// associated new address that will be returned.
func (b *Bitcoind) GetAccountAddress(account string) (address string, err error) {
	r, err := b.client.call("getaccountaddress", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &address)
	return
}

// GetAddressesByAccount return addresses associated with account <account>
func (b *Bitcoind) GetAddressesByAccount(account string) (addresses []string, err error) {
	r, err := b.client.call("getaddressesbyaccount", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &addresses)
	return
}

// GetBalance return the balance of the server or of a specific account
//If [account] is "", returns the server's total available balance.
//If [account] is specified, returns the balance in the account
func (b *Bitcoind) GetBalance(account string, minconf uint64) (balance float64, err error) {
	r, err := b.client.call("getbalance", []interface{}{account, minconf})
	if err = handleError(err, &r); err != nil {
		return
	}
	balance, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetBestBlockhash returns the hash of the best (tip) block in the longest block chain.
func (b *Bitcoind) GetBestBlockhash() (bestBlockHash string, err error) {
	r, err := b.client.call("getbestblockhash", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &bestBlockHash)
	return
}

// GetBlock returns information about the block with the given hash.
func (b *Bitcoind) GetBlock(blockHash string) (block Block, err error) {
	r, err := b.client.call("getblock", []string{blockHash})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &block)
	return
}

// GetBlockCount returns the number of blocks in the longest block chain.
func (b *Bitcoind) GetBlockCount() (count uint64, err error) {
	r, err := b.client.call("getblockcount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetBlockHash returns hash of block in best-block-chain at <index>
func (b *Bitcoind) GetBlockHash(index uint64) (hash string, err error) {
	r, err := b.client.call("getblockhash", []uint64{index})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &hash)
	return
}

// getBlockTemplateParams reperesent parameters for GetBlockTemplate
type getBlockTemplateParams struct {
	Mode         string   `json:"mode,omitempty"`
	Capabilities []string `json:"capabilities,omitempty"`
}

// TODO a finir
// GetBlockTemplate Returns data needed to construct a block to work on.
// See BIP_0022 for more info on params.
func (b *Bitcoind) GetBlockTemplate(capabilities []string, mode string) (template string, err error) {
	params := getBlockTemplateParams{
		Mode:         mode,
		Capabilities: capabilities,
	}
	// TODO []interface{}{mode, capa}
	r, err := b.client.call("getblocktemplate", []getBlockTemplateParams{params})
	if err = handleError(err, &r); err != nil {
		return
	}
	fmt.Println(json.Unmarshal(r.Result, &template))
	return
}

// GetConnectionCount returns the number of connections to other nodes.
func (b *Bitcoind) GetConnectionCount() (count uint64, err error) {
	r, err := b.client.call("getconnectioncount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetDifficulty returns the proof-of-work difficulty as a multiple of
// the minimum difficulty.
func (b *Bitcoind) GetDifficulty() (difficulty float64, err error) {
	r, err := b.client.call("getdifficulty", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	difficulty, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetGenerate returns true or false whether bitcoind is currently generating hashes
func (b *Bitcoind) GetGenerate() (generate bool, err error) {
	r, err := b.client.call("getgenerate", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &generate)
	return
}

// GetHashesPerSec returns a recent hashes per second performance measurement while generating.
func (b *Bitcoind) GetHashesPerSec() (hashpersec float64, err error) {
	r, err := b.client.call("gethashespersec", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &hashpersec)
	return
}

// GetInfo return result of "getinfo" command (Amazing !)
func (b *Bitcoind) GetInfo() (i Info, err error) {
	r, err := b.client.call("getinfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &i)
	return
}

// GetMiningInfo returns an object containing mining-related information
func (b *Bitcoind) GetMiningInfo() (miningInfo MiningInfo, err error) {
	r, err := b.client.call("getmininginfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &miningInfo)
	return
}

// GetNewAddress return a new address for account [account].
func (b *Bitcoind) GetNewAddress(account ...string) (addr string, err error) {
	// 0 or 1 account
	if len(account) > 1 {
		err = errors.New("Bad parameters for GetNewAddress: you can set 0 or 1 account")
		return
	}
	r, err := b.client.call("getnewaddress", account)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &addr)
	return
}

// GetPeerInfo returns data about each connected node
func (b *Bitcoind) GetPeerInfo() (peerInfo []Peer, err error) {
	r, err := b.client.call("getpeerinfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &peerInfo)
	return
}

// GetRawChangeAddress Returns a new Bitcoin address, for receiving change.
// This is for use with raw transactions, NOT normal use.
func (b *Bitcoind) GetRawChangeAddress(account ...string) (rawAddress string, err error) {
	// 0 or 1 account
	if len(account) > 1 {
		err = errors.New("Bad parameters for GetRawChangeAddress: you can set 0 or 1 account")
		return
	}
	r, err := b.client.call("getrawchangeaddress", account)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &rawAddress)
	return
}

// GetRawMempool returns all transaction ids in memory pool
func (b *Bitcoind) GetRawMempool() (txId []string, err error) {
	r, err := b.client.call("getrawmempool", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &txId)
	return
}

// GetRawTransaction returns raw transaction representation for given transaction id.
func (b *Bitcoind) GetRawTransaction(txId string, verbose bool) (rawTx interface{}, err error) {
	r, err := b.client.call("getrawtransaction", []interface{}{txId, verbose})
	if err = handleError(err, &r); err != nil {
		return
	}
	if !verbose {
		err = json.Unmarshal(r.Result, &rawTx)
	} else {
		var t RawTx
		err = json.Unmarshal(r.Result, &t)
		rawTx = t
	}
	return
}

// GetReceivedByAccount Returns the total amount received by addresses with [account] in
// transactions with at least [minconf] confirmations. If [account] is set to all return
// will include all transactions to all accounts
func (b *Bitcoind) GetReceivedByAccount(account string, minconf uint32) (amount float64, err error) {
	if account == "all" {
		account = ""
	}
	r, err := b.client.call("getreceivedbyaccount", []interface{}{account, minconf})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &amount)
	return
}

// walletPassphrase stores the wallet decryption key in memory for <timeout> seconds.
func (b *Bitcoind) WalletPassphrase(passPhrase string, timeout uint64) error {
	r, err := b.client.call("walletpassphrase", []interface{}{passPhrase, timeout})
	return handleError(err, &r)
}
<commit_msg>typo<commit_after>// Package Bitcoind is client librari for bitcoind JSON RPC API
package bitcoind

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
)

const (
	// VERSION represents bicoind package version
	VERSION = 0.1
	// DEFAULT_RPCCLIENT_TIMEOUT represent http timeout for rcp client
	RPCCLIENT_TIMEOUT = 30
)

// A Bitcoind represents a Bitcoind client
type Bitcoind struct {
	client *rpcClient
}

// New return a new bitcoind
func New(host string, port int, user, passwd string, useSSL bool) (*Bitcoind, error) {
	rpcClient, err := newClient(host, port, user, passwd, useSSL)
	if err != nil {
		return nil, err
	}
	return &Bitcoind{rpcClient}, nil
}

// BackupWallet Safely copies wallet.dat to destination,
// which can be a directory or a path with filename on the remote server
func (b *Bitcoind) BackupWallet(destination string) error {
	r, err := b.client.call("backupwallet", []string{destination})
	return handleError(err, &r)
}

// DumpPrivKey return private key as string associated to public <address>
func (b *Bitcoind) DumpPrivKey(address string) (privKey string, err error) {
	r, err := b.client.call("dumpprivkey", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &privKey)
	return
}

// EncryptWallet encrypts the wallet with <passphrase>.
func (b *Bitcoind) EncryptWallet(passphrase string) error {
	r, err := b.client.call("encryptwallet", []string{passphrase})
	return handleError(err, &r)
}

// GetAccount returns the account associated with the given address.
func (b *Bitcoind) GetAccount(address string) (account string, err error) {
	r, err := b.client.call("getaccount", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &account)
	return
}

// GetAccountAddress Returns the current bitcoin address for receiving
// payments to this account.
// If account does not exist, it will be created along with an
// associated new address that will be returned.
func (b *Bitcoind) GetAccountAddress(account string) (address string, err error) {
	r, err := b.client.call("getaccountaddress", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &address)
	return
}

// GetAddressesByAccount return addresses associated with account <account>
func (b *Bitcoind) GetAddressesByAccount(account string) (addresses []string, err error) {
	r, err := b.client.call("getaddressesbyaccount", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &addresses)
	return
}

// GetBalance return the balance of the server or of a specific account
//If [account] is "", returns the server's total available balance.
//If [account] is specified, returns the balance in the account
func (b *Bitcoind) GetBalance(account string, minconf uint64) (balance float64, err error) {
	r, err := b.client.call("getbalance", []interface{}{account, minconf})
	if err = handleError(err, &r); err != nil {
		return
	}
	balance, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetBestBlockhash returns the hash of the best (tip) block in the longest block chain.
func (b *Bitcoind) GetBestBlockhash() (bestBlockHash string, err error) {
	r, err := b.client.call("getbestblockhash", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &bestBlockHash)
	return
}

// GetBlock returns information about the block with the given hash.
func (b *Bitcoind) GetBlock(blockHash string) (block Block, err error) {
	r, err := b.client.call("getblock", []string{blockHash})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &block)
	return
}

// GetBlockCount returns the number of blocks in the longest block chain.
func (b *Bitcoind) GetBlockCount() (count uint64, err error) {
	r, err := b.client.call("getblockcount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetBlockHash returns hash of block in best-block-chain at <index>
func (b *Bitcoind) GetBlockHash(index uint64) (hash string, err error) {
	r, err := b.client.call("getblockhash", []uint64{index})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &hash)
	return
}

// getBlockTemplateParams reperesent parameters for GetBlockTemplate
type getBlockTemplateParams struct {
	Mode         string   `json:"mode,omitempty"`
	Capabilities []string `json:"capabilities,omitempty"`
}

// TODO a finir
// GetBlockTemplate Returns data needed to construct a block to work on.
// See BIP_0022 for more info on params.
func (b *Bitcoind) GetBlockTemplate(capabilities []string, mode string) (template string, err error) {
	params := getBlockTemplateParams{
		Mode:         mode,
		Capabilities: capabilities,
	}
	// TODO []interface{}{mode, capa}
	r, err := b.client.call("getblocktemplate", []getBlockTemplateParams{params})
	if err = handleError(err, &r); err != nil {
		return
	}
	fmt.Println(json.Unmarshal(r.Result, &template))
	return
}

// GetConnectionCount returns the number of connections to other nodes.
func (b *Bitcoind) GetConnectionCount() (count uint64, err error) {
	r, err := b.client.call("getconnectioncount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetDifficulty returns the proof-of-work difficulty as a multiple of
// the minimum difficulty.
func (b *Bitcoind) GetDifficulty() (difficulty float64, err error) {
	r, err := b.client.call("getdifficulty", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	difficulty, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetGenerate returns true or false whether bitcoind is currently generating hashes
func (b *Bitcoind) GetGenerate() (generate bool, err error) {
	r, err := b.client.call("getgenerate", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &generate)
	return
}

// GetHashesPerSec returns a recent hashes per second performance measurement while generating.
func (b *Bitcoind) GetHashesPerSec() (hashpersec float64, err error) {
	r, err := b.client.call("gethashespersec", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &hashpersec)
	return
}

// GetInfo return result of "getinfo" command (Amazing !)
func (b *Bitcoind) GetInfo() (i Info, err error) {
	r, err := b.client.call("getinfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &i)
	return
}

// GetMiningInfo returns an object containing mining-related information
func (b *Bitcoind) GetMiningInfo() (miningInfo MiningInfo, err error) {
	r, err := b.client.call("getmininginfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &miningInfo)
	return
}

// GetNewAddress return a new address for account [account].
func (b *Bitcoind) GetNewAddress(account ...string) (addr string, err error) {
	// 0 or 1 account
	if len(account) > 1 {
		err = errors.New("Bad parameters for GetNewAddress: you can set 0 or 1 account")
		return
	}
	r, err := b.client.call("getnewaddress", account)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &addr)
	return
}

// GetPeerInfo returns data about each connected node
func (b *Bitcoind) GetPeerInfo() (peerInfo []Peer, err error) {
	r, err := b.client.call("getpeerinfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &peerInfo)
	return
}

// GetRawChangeAddress Returns a new Bitcoin address, for receiving change.
// This is for use with raw transactions, NOT normal use.
func (b *Bitcoind) GetRawChangeAddress(account ...string) (rawAddress string, err error) {
	// 0 or 1 account
	if len(account) > 1 {
		err = errors.New("Bad parameters for GetRawChangeAddress: you can set 0 or 1 account")
		return
	}
	r, err := b.client.call("getrawchangeaddress", account)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &rawAddress)
	return
}

// GetRawMempool returns all transaction ids in memory pool
func (b *Bitcoind) GetRawMempool() (txId []string, err error) {
	r, err := b.client.call("getrawmempool", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &txId)
	return
}

// GetRawTransaction returns raw transaction representation for given transaction id.
func (b *Bitcoind) GetRawTransaction(txId string, verbose bool) (rawTx interface{}, err error) {
	r, err := b.client.call("getrawtransaction", []interface{}{txId, verbose})
	if err = handleError(err, &r); err != nil {
		return
	}
	if !verbose {
		err = json.Unmarshal(r.Result, &rawTx)
	} else {
		var t RawTx
		err = json.Unmarshal(r.Result, &t)
		rawTx = t
	}
	return
}

// GetReceivedByAccount Returns the total amount received by addresses with [account] in
// transactions with at least [minconf] confirmations. If [account] is set to all return
// will include all transactions to all accounts
func (b *Bitcoind) GetReceivedByAccount(account string, minconf uint32) (amount float64, err error) {
	if account == "all" {
		account = ""
	}
	r, err := b.client.call("getreceivedbyaccount", []interface{}{account, minconf})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &amount)
	return
}

// walletPassphrase stores the wallet decryption key in memory for <timeout> seconds.
func (b *Bitcoind) WalletPassphrase(passPhrase string, timeout uint64) error {
	r, err := b.client.call("walletpassphrase", []interface{}{passPhrase, timeout})
	return handleError(err, &r)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/wmartins/playground/go/csv-read-write/csv"
	"fmt"
	"sync"
	"time"
	"runtime"
	"log"
	"os"
	"strconv"
)

func generate(n int) {
	csv.Generate(n)
}

func read(path string) {
	workers, err := strconv.Atoi(os.Getenv("NUM_WORKERS"))

	if err != nil {
		workers = 1
	}

	log.Printf("Using %d workers", workers)

	var wg sync.WaitGroup
	var mem runtime.MemStats

	printMemStats(&mem)

	t := time.Now()

	c := make(chan []string)

	go func() {
		csv.Read(path, c)
	}()

	wg.Add(workers)
	for i := 0 ; i < workers; i++ {
		go func() {
			for record := range c {
				fmt.Println(record)
			}

			defer wg.Done()
		}()
	}
	wg.Wait()

	printMemStats(&mem)
	log.Println(time.Since(t))
}

func printMemStats(mem *runtime.MemStats) {
	runtime.ReadMemStats(mem)
	log.Println(mem.Alloc, mem.TotalAlloc, mem.HeapAlloc, mem.HeapSys)
}

func main() {
	var cmd string = "read"
	var argsLen = len(os.Args)

	if argsLen >= 2 {
		cmd = os.Args[1]
	}

	if cmd == "generate" {
		var num = 1

		if argsLen >= 3 {
			num, _ = strconv.Atoi(os.Args[2])
		}

		generate(num)
    } else {
		if argsLen < 2 {
			log.Fatal("You must provide a file to read")
		}

		read(os.Args[1])
    }
}
<commit_msg>Improve code<commit_after>package main

import (
	"fmt"
	"github.com/wmartins/playground/go/csv-read-write/csv"
	"log"
	"os"
	"runtime"
	"strconv"
	"sync"
	"time"
)

func generate(n int) {
	csv.Generate(n)
}

func read(path string) {
	workers, err := strconv.Atoi(os.Getenv("NUM_WORKERS"))

	if err != nil {
		workers = 1
	}

	log.Printf("Using %d workers", workers)

	var wg sync.WaitGroup
	var mem runtime.MemStats

	printMemStats(&mem)

	t := time.Now()

	c := make(chan []string)

	go func() {
		csv.Read(path, c)
	}()

	wg.Add(workers)
	for i := 0; i < workers; i++ {
		go func() {
			for record := range c {
				fmt.Println(record)
			}

			defer wg.Done()
		}()
	}
	wg.Wait()

	printMemStats(&mem)
	log.Println(time.Since(t))
}

func printMemStats(mem *runtime.MemStats) {
	runtime.ReadMemStats(mem)
	log.Println(mem.Alloc, mem.TotalAlloc, mem.HeapAlloc, mem.HeapSys)
}

func main() {
	var cmd string = "read"
	var argsLen = len(os.Args)

	if argsLen >= 2 {
		cmd = os.Args[1]
	}

	if cmd == "generate" {
		var num = 1

		if argsLen >= 3 {
			num, _ = strconv.Atoi(os.Args[2])
		}

		generate(num)
	} else {
		if argsLen < 2 {
			log.Fatal("You must provide a file to read")
		}

		read(os.Args[1])
	}
}
<|endoftext|>