<commit_before>package integrations

// This was intentionally added under the integrations package and not the integrations test package
// so that changes in other parts of the code base that may have an effect on these test will not
// compile until they are fixed.

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/bolt"
	"github.com/influxdata/chronograf/oauth2"
	"github.com/influxdata/chronograf/server"
)

func TestServer(t *testing.T) {
	type fields struct {
		Organizations []chronograf.Organization
		Users         []chronograf.User
		Sources       []chronograf.Source
		Servers       []chronograf.Server
		Layouts       []chronograf.Layout
		Dashboards    []chronograf.Dashboard
	}
	type args struct {
		server    *server.Server
		method    string
		path      string
		payload   interface{} // Expects this to be a json serializable struct
		principal oauth2.Principal
	}
	type wants struct {
		statusCode  int
		contentType string
		body        string
	}

	tests := []struct {
		name    string
		subName string
		fields  fields
		args    args
		wants   wants
	}{
		{
			name:    "GET /users",
			subName: "User Not Found in the Default Organization",
			fields:  fields{},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 401,
				body:       `{"code":401,"message":"User is not authorized"}`,
			},
		},
		{
			name:    "GET /users",
			subName: "Single User in the Default Organization as SuperAdmin",
			fields: fields{
				Users: []chronograf.User{
					{
						ID:         1, // This is artificial, but should be reflective of the users actual ID
						Name:       "billibob",
						Provider:   "github",
						Scheme:     "oauth2",
						SuperAdmin: true,
						Roles: []chronograf.Role{
							{
								Name:         "admin",
								Organization: "0",
							},
						},
					},
				},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 200,
				body: `
					{
					  "links": {
					    "self": "/chronograf/v1/users"
					  },
					  "users": [
					    {
					      "links": {
					        "self": "/chronograf/v1/users/1"
					      },
					      "id": "1",
					      "name": "billibob",
					      "provider": "github",
					      "scheme": "oauth2",
					      "superAdmin": true,
					      "roles": [
					        {
					          "name": "admin",
					          "organization": "0"
					        }
					      ]
					    }
					  ]
					}`,
			},
		},
		{
			name:    "GET /users",
			subName: "Single User in the Default Organization as Admin",
			fields: fields{
				Users: []chronograf.User{
					{
						ID:       1, // This is artificial, but should be reflective of the users actual ID
						Name:     "billibob",
						Provider: "github",
						Scheme:   "oauth2",
						Roles: []chronograf.Role{
							{
								Name:         "admin",
								Organization: "0",
							},
						},
					},
				},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 200,
				body: `
					{
					  "links": {
					    "self": "/chronograf/v1/users"
					  },
					  "users": [
					    {
					      "links": {
					        "self": "/chronograf/v1/users/1"
					      },
					      "id": "1",
					      "name": "billibob",
					      "provider": "github",
					      "scheme": "oauth2",
					      "superAdmin": false,
					      "roles": [
					        {
					          "name": "admin",
					          "organization": "0"
					        }
					      ]
					    }
					  ]
					}`,
			},
		},
		{
			name:    "GET /users",
			subName: "Single User in the Default Organization as Editor",
			fields: fields{
				Users: []chronograf.User{
					{
						ID:       1, // This is artificial, but should be reflective of the users actual ID
						Name:     "billibob",
						Provider: "github",
						Scheme:   "oauth2",
						Roles: []chronograf.Role{
							{
								Name:         "editor",
								Organization: "0",
							},
						},
					},
				},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 401,
				body:       `{"code":401,"message":"User is not authorized"}`,
			},
		},
		{
			name:    "GET /users",
			subName: "Single User in the Default Organization as Viewer",
			fields: fields{
				Users: []chronograf.User{
					{
						ID:       1, // This is artificial, but should be reflective of the users actual ID
						Name:     "billibob",
						Provider: "github",
						Scheme:   "oauth2",
						Roles: []chronograf.Role{
							{
								Name:         "viewer",
								Organization: "0",
							},
						},
					},
				},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 401,
				body:       `{"code":401,"message":"User is not authorized"}`,
			},
		},
		{
			name:    "GET /users",
			subName: "Single User in the Default Organization as Member",
			fields: fields{
				Users: []chronograf.User{
					{
						ID:       1, // This is artificial, but should be reflective of the users actual ID
						Name:     "billibob",
						Provider: "github",
						Scheme:   "oauth2",
						Roles: []chronograf.Role{
							{
								Name:         "viewer",
								Organization: "0",
							},
						},
					},
				},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 401,
				body:       `{"code":401,"message":"User is not authorized"}`,
			},
		},
	}

	for _, tt := range tests {
		testName := fmt.Sprintf("%s: %s", tt.name, tt.subName)
		t.Run(testName, func(t *testing.T) {
			ctx := context.TODO()
			// Create Test Server
			host, port := hostAndPort()
			tt.args.server.Host = host
			tt.args.server.Port = port

			// This is so that we can use staticly generate jwts
			tt.args.server.TokenSecret = "secret"

			boltFile := newBoltFile()
			tt.args.server.BoltPath = boltFile

			// Prepopulate BoltDB Database for Server
			boltdb := bolt.NewClient()
			boltdb.Path = boltFile
			_ = boltdb.Open(ctx)

			// Populate Organizations
			for i, organization := range tt.fields.Organizations {
				o, err := boltdb.OrganizationsStore.Add(ctx, &organization)
				if err != nil {
					t.Fatalf("failed to add organization: %v", err)
					return
				}
				tt.fields.Organizations[i] = *o
			}

			// Populate Users
			for i, user := range tt.fields.Users {
				u, err := boltdb.UsersStore.Add(ctx, &user)
				if err != nil {
					t.Fatalf("failed to add user: %v", err)
					return
				}
				tt.fields.Users[i] = *u
			}

			// Populate Sources
			for i, source := range tt.fields.Sources {
				s, err := boltdb.SourcesStore.Add(ctx, source)
				if err != nil {
					t.Fatalf("failed to add source: %v", err)
					return
				}
				tt.fields.Sources[i] = s
			}

			// Populate Servers
			for i, server := range tt.fields.Servers {
				s, err := boltdb.ServersStore.Add(ctx, server)
				if err != nil {
					t.Fatalf("failed to add server: %v", err)
					return
				}
				tt.fields.Servers[i] = s
			}

			// Populate Layouts
			for i, layout := range tt.fields.Layouts {
				l, err := boltdb.LayoutsStore.Add(ctx, layout)
				if err != nil {
					t.Fatalf("failed to add layout: %v", err)
					return
				}
				tt.fields.Layouts[i] = l
			}

			// Populate Dashboards
			for i, dashboard := range tt.fields.Dashboards {
				d, err := boltdb.DashboardsStore.Add(ctx, dashboard)
				if err != nil {
					t.Fatalf("failed to add dashboard: %v", err)
					return
				}
				tt.fields.Dashboards[i] = d
			}

			_ = boltdb.Close()

			go tt.args.server.Serve(ctx)
			serverURL := fmt.Sprintf("http://%v:%v%v", host, port, tt.args.path)

			timeout := time.Now().Add(100 * time.Millisecond)
			for {
				_, err := http.Get(serverURL + "/swagger.json")
				if err == nil {
					break
				}
				if time.Now().After(timeout) {
					t.Fatalf("failed to start server")
					return
				}
			}

			// Construct HTTP Request
			buf, _ := json.Marshal(tt.args.payload)
			reqBody := ioutil.NopCloser(bytes.NewReader(buf))
			req, _ := http.NewRequest(tt.args.method, serverURL, reqBody)
			token, _ := oauth2.NewJWT(tt.args.server.TokenSecret).Create(ctx, tt.args.principal)
			req.AddCookie(&http.Cookie{
				Name:     "session",
				Value:    string(token),
				HttpOnly: true,
				Path:     "/",
			})

			// Make actual http request
			resp, err := http.DefaultClient.Do(req)
			if err != nil {
				t.Fatalf("failed to make httprequest: %v", err)
				return
			}

			content := resp.Header.Get("Content-Type")
			body, _ := ioutil.ReadAll(resp.Body)

			if resp.StatusCode != tt.wants.statusCode {
				t.Errorf(
					"%s %s Status Code = %v, want %v",
					tt.args.method,
					tt.args.path,
					resp.StatusCode,
					tt.wants.statusCode,
				)
			}

			if tt.wants.contentType != "" && content != tt.wants.contentType {
				t.Errorf(
					"%s %s Content Type = %v, want %v",
					tt.args.method,
					tt.args.path,
					content,
					tt.wants.contentType,
				)
			}

			if eq, err := jsonEqual(tt.wants.body, string(body)); err != nil || !eq {
				t.Errorf(
					"%s %s Body = %v, want %v",
					tt.args.method,
					tt.args.path,
					string(body),
					tt.wants.body,
				)
			}

			tt.args.server.Listener.Close()
		})
	}
}
<commit_msg>Remove "impossible" state from tests<commit_after>package integrations

// This was intentionally added under the integrations package and not the integrations test package
// so that changes in other parts of the code base that may have an effect on these test will not
// compile until they are fixed.

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/bolt"
	"github.com/influxdata/chronograf/oauth2"
	"github.com/influxdata/chronograf/server"
)

func TestServer(t *testing.T) {
	type fields struct {
		Organizations []chronograf.Organization
		Users         []chronograf.User
		Sources       []chronograf.Source
		Servers       []chronograf.Server
		Layouts       []chronograf.Layout
		Dashboards    []chronograf.Dashboard
	}
	type args struct {
		server    *server.Server
		method    string
		path      string
		payload   interface{} // Expects this to be a json serializable struct
		principal oauth2.Principal
	}
	type wants struct {
		statusCode  int
		contentType string
		body        string
	}

	tests := []struct {
		name    string
		subName string
		fields  fields
		args    args
		wants   wants
	}{
		{
			name:    "GET /users",
			subName: "User Not Found in the Default Organization",
			fields: fields{
				Users: []chronograf.User{},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 401,
				body:       `{"code":401,"message":"User is not authorized"}`,
			},
		},
		{
			name:    "GET /users",
			subName: "Single User in the Default Organization as SuperAdmin",
			fields: fields{
				Users: []chronograf.User{
					{
						ID:         1, // This is artificial, but should be reflective of the users actual ID
						Name:       "billibob",
						Provider:   "github",
						Scheme:     "oauth2",
						SuperAdmin: true,
						Roles: []chronograf.Role{
							{
								Name:         "admin",
								Organization: "0",
							},
						},
					},
				},
			},
			args: args{
				server: &server.Server{
					GithubClientID:     "not empty",
					GithubClientSecret: "not empty",
				},
				method: "GET",
				path:   "/chronograf/v1/users",
				principal: oauth2.Principal{
					Organization: "0",
					Subject:      "billibob",
					Issuer:       "github",
					ExpiresAt:    time.Now().Add(10 * time.Second),
					IssuedAt:     time.Now(),
				},
			},
			wants: wants{
				statusCode: 200,
				body: `
					{
					  "links": {
					    "self": "/chronograf/v1/users"
					  },
					  "users": [
					    {
					      "links": {
					        "self": "/chronograf/v1/users/1"
					      },
					      "id": "1",
					      "name": "billibob",
					      "provider": "github",
					      "scheme": "oauth2",
					      "superAdmin": true,
					      "roles": [
					        {
					          "name": "admin",
					          "organization": "0"
					        }
					      ]
					    }
					  ]
					}`,
			},
		},
	}

	for _, tt := range tests {
		testName := fmt.Sprintf("%s: %s", tt.name, tt.subName)
		t.Run(testName, func(t *testing.T) {
			ctx := context.TODO()
			// Create Test Server
			host, port := hostAndPort()
			tt.args.server.Host = host
			tt.args.server.Port = port

			// This is so that we can use staticly generate jwts
			tt.args.server.TokenSecret = "secret"

			boltFile := newBoltFile()
			tt.args.server.BoltPath = boltFile

			// Prepopulate BoltDB Database for Server
			boltdb := bolt.NewClient()
			boltdb.Path = boltFile
			_ = boltdb.Open(ctx)

			// Populate Organizations
			for i, organization := range tt.fields.Organizations {
				o, err := boltdb.OrganizationsStore.Add(ctx, &organization)
				if err != nil {
					t.Fatalf("failed to add organization: %v", err)
					return
				}
				tt.fields.Organizations[i] = *o
			}

			// Populate Users
			for i, user := range tt.fields.Users {
				u, err := boltdb.UsersStore.Add(ctx, &user)
				if err != nil {
					t.Fatalf("failed to add user: %v", err)
					return
				}
				tt.fields.Users[i] = *u
			}

			// Populate Sources
			for i, source := range tt.fields.Sources {
				s, err := boltdb.SourcesStore.Add(ctx, source)
				if err != nil {
					t.Fatalf("failed to add source: %v", err)
					return
				}
				tt.fields.Sources[i] = s
			}

			// Populate Servers
			for i, server := range tt.fields.Servers {
				s, err := boltdb.ServersStore.Add(ctx, server)
				if err != nil {
					t.Fatalf("failed to add server: %v", err)
					return
				}
				tt.fields.Servers[i] = s
			}

			// Populate Layouts
			for i, layout := range tt.fields.Layouts {
				l, err := boltdb.LayoutsStore.Add(ctx, layout)
				if err != nil {
					t.Fatalf("failed to add layout: %v", err)
					return
				}
				tt.fields.Layouts[i] = l
			}

			// Populate Dashboards
			for i, dashboard := range tt.fields.Dashboards {
				d, err := boltdb.DashboardsStore.Add(ctx, dashboard)
				if err != nil {
					t.Fatalf("failed to add dashboard: %v", err)
					return
				}
				tt.fields.Dashboards[i] = d
			}

			_ = boltdb.Close()

			go tt.args.server.Serve(ctx)
			serverURL := fmt.Sprintf("http://%v:%v%v", host, port, tt.args.path)

			// Wait for the server to come online
			timeout := time.Now().Add(100 * time.Millisecond)
			for {
				_, err := http.Get(serverURL + "/swagger.json")
				if err == nil {
					break
				}
				if time.Now().After(timeout) {
					t.Fatalf("failed to start server")
					return
				}
			}

			// Construct HTTP Request
			buf, _ := json.Marshal(tt.args.payload)
			reqBody := ioutil.NopCloser(bytes.NewReader(buf))
			req, _ := http.NewRequest(tt.args.method, serverURL, reqBody)
			token, _ := oauth2.NewJWT(tt.args.server.TokenSecret).Create(ctx, tt.args.principal)
			req.AddCookie(&http.Cookie{
				Name:     "session",
				Value:    string(token),
				HttpOnly: true,
				Path:     "/",
			})

			// Make actual http request
			resp, err := http.DefaultClient.Do(req)
			if err != nil {
				t.Fatalf("failed to make httprequest: %v", err)
				return
			}

			content := resp.Header.Get("Content-Type")
			body, _ := ioutil.ReadAll(resp.Body)

			if resp.StatusCode != tt.wants.statusCode {
				t.Errorf(
					"%s %s Status Code = %v, want %v",
					tt.args.method,
					tt.args.path,
					resp.StatusCode,
					tt.wants.statusCode,
				)
			}

			if tt.wants.contentType != "" && content != tt.wants.contentType {
				t.Errorf(
					"%s %s Content Type = %v, want %v",
					tt.args.method,
					tt.args.path,
					content,
					tt.wants.contentType,
				)
			}

			if eq, err := jsonEqual(tt.wants.body, string(body)); err != nil || !eq {
				t.Errorf(
					"%s %s Body = %v, want %v",
					tt.args.method,
					tt.args.path,
					string(body),
					tt.wants.body,
				)
			}

			tt.args.server.Listener.Close()
		})
	}
}
<|endoftext|>


<commit_before>package ssh

import (
	"log"
	"os"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
)

func KeyboardInteractive() ssh.KeyboardInteractiveChallenge {
	return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
		if len(questions) == 0 {
			return []string{}, nil
		}

		log.Printf("-- User: %s", user)
		log.Printf("-- Instructions: %s", instruction)
		for i, question := range questions {
			log.Printf("-- Question %d: %s", i+1, question)
		}
		answers := make([]string, len(questions))
		for i := range questions {
			s, err := terminal.ReadPassword(int(os.Stdin.Fd()))
			if err != nil {
				return nil, err
			}
			answers[i] = string(s)
		}
		return answers, nil
	}
}
<commit_msg>use tty when IsTerminal is false<commit_after>package ssh

import (
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
	"log"
	"os"
)

func KeyboardInteractive() ssh.KeyboardInteractiveChallenge {
	return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
		if len(questions) == 0 {
			return []string{}, nil
		}

		log.Printf("-- User: %s", user)
		log.Printf("-- Instructions: %s", instruction)
		for i, question := range questions {
			log.Printf("-- Question %d: %s", i+1, question)
		}
		answers := make([]string, len(questions))
		for i := range questions {
			var fd int
			if terminal.IsTerminal(int(os.Stdin.Fd())) {
				fd = int(os.Stdin.Fd())
			} else {
				tty, err := os.Open("/dev/tty")
				if err != nil {
					return nil, err
				}
				defer tty.Close()
				fd = int(tty.Fd())
			}
			s, err := terminal.ReadPassword(fd)
			if err != nil {
				return nil, err
			}
			answers[i] = string(s)
		}
		return answers, nil
	}
}
<|endoftext|>


<commit_before>//+build go1.12,linux

package netlink_test

import (
	"net"
	"os"
	"runtime"
	"sync"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/jsimonetti/rtnetlink/rtnl"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

func TestIntegrationConnTimeout(t *testing.T) {
	t.Parallel()

	conn, err := netlink.Dial(unix.NETLINK_GENERIC, nil)
	if err != nil {
		t.Fatalf("failed to dial: %v", err)
	}
	defer conn.Close()

	timeout := 1 * time.Millisecond
	if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
		t.Fatalf("failed to set deadline: %v", err)
	}

	errC := make(chan error)
	go func() {
		_, err := conn.Receive()
		errC <- err
	}()

	select {
	case err := <-errC:
		mustBeTimeoutNetError(t, err)
	case <-time.After(timeout + 1*time.Millisecond):
		t.Fatalf("timeout did not fire")
	}
}

func TestIntegrationConnExecuteAfterReadDeadline(t *testing.T) {
	t.Parallel()

	conn, err := netlink.Dial(unix.NETLINK_GENERIC, nil)
	if err != nil {
		t.Fatalf("failed to dial: %v", err)
	}
	defer conn.Close()

	timeout := 1 * time.Millisecond
	if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
		t.Fatalf("failed to set deadline: %v", err)
	}
	time.Sleep(2 * timeout)

	req := netlink.Message{
		Header: netlink.Header{
			Flags:    netlink.Request | netlink.Acknowledge,
			Sequence: 1,
		},
	}
	got, err := conn.Execute(req)
	if err == nil {
		t.Fatalf("Execute succeeded: got %v", got)
	}
	mustBeTimeoutNetError(t, err)
}

func TestIntegrationConnNetNSExplicit(t *testing.T) {
	t.Parallel()

	skipUnprivileged(t)

	// Create a network namespace for use within this test.
	const ns = "nltest0"
	shell(t, "ip", "netns", "add", ns)
	defer shell(t, "ip", "netns", "del", ns)

	f, err := os.Open("/var/run/netns/" + ns)
	if err != nil {
		t.Fatalf("failed to open namespace file: %v", err)
	}
	defer f.Close()

	// Create a connection in each the host namespace and the new network
	// namespace. We will use these to validate that a namespace was entered
	// and that an interface creation notification was only visible to the
	// connection within the namespace.
	hostC, hostDone := rtnlDial(t, 0)
	defer hostDone()

	nsC, nsDone := rtnlDial(t, int(f.Fd()))
	defer nsDone()

	var wg sync.WaitGroup
	wg.Add(1)
	defer wg.Wait()

	go func() {
		defer wg.Done()

		_, err := hostC.Receive()
		if err == nil {
			panic("received netlink message in host namespace")
		}

		// Timeout means we were interrupted, so return.
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			return
		}

		panicf("failed to receive in host namespace: %v", err)
	}()

	// Create a temporary interface within the new network namespace.
	const ifName = "nltestns0"
	defer shell(t, "ip", "netns", "exec", ns, "ip", "link", "del", ifName)

	ifi := rtnlReceive(t, nsC, func() {
		// Trigger a notification in the new namespace.
		shell(t, "ip", "netns", "exec", ns, "ip", "tuntap", "add", ifName, "mode", "tun")
	})

	// And finally interrupt the host connection so it can exit its
	// receive goroutine.
	if err := hostC.SetDeadline(time.Unix(1, 0)); err != nil {
		t.Fatalf("failed to interrupt host connection: %v", err)
	}

	if diff := cmp.Diff(ifName, ifi); diff != "" {
		t.Fatalf("unexpected interface name (-want +got):\n%s", diff)
	}
}

func TestIntegrationConnNetNSImplicit(t *testing.T) {
	t.Parallel()

	skipUnprivileged(t)

	// Create a network namespace for use within this test.
	const ns = "nltest0"
	shell(t, "ip", "netns", "add", ns)
	defer shell(t, "ip", "netns", "del", ns)

	f, err := os.Open("/var/run/netns/" + ns)
	if err != nil {
		t.Fatalf("failed to open namespace file: %v", err)
	}
	defer f.Close()

	// Create an interface in the new namespace. We will attempt to find it later.
	const ifName = "nltestns0"
	shell(t, "ip", "netns", "exec", ns, "ip", "tuntap", "add", ifName, "mode", "tun")
	defer shell(t, "ip", "netns", "exec", ns, "ip", "link", "del", ifName)

	// We're going to manipulate the network namespace of this thread, so we
	// must lock OS thread and keep track of the original namespace for later.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	threadNS, err := netlink.ThreadNetNS()
	if err != nil {
		t.Fatalf("failed to get current network namespace: %v", err)
	}
	defer threadNS.Close()

	if err := threadNS.Set(int(f.Fd())); err != nil {
		t.Fatalf("failed to enter new network namespace: %v", err)
	}

	// A newly created netlink connection should enter the new network namespace
	// associated with this thread automatically.
	if !findLink(t, ifName) {
		t.Fatalf("did not find interface %q in namespace %q", ifName, ns)
	}

	// Return to the default namespace.
	//
	// A newly created netlink connection should NOT find the link because it
	// is now in the default namespace.
	if err := threadNS.Restore(); err != nil {
		t.Fatalf("failed to restore original network namespace: %v", err)
	}

	if findLink(t, ifName) {
		t.Fatalf("found interface %q in default namespace", ifName)
	}
}

func findLink(t *testing.T, name string) bool {
	t.Helper()

	c, err := rtnl.Dial(nil)
	if err != nil {
		t.Fatalf("failed to dial rtnetlink: %v", err)
	}
	defer c.Close()

	ifis, err := c.Links()
	if err != nil {
		t.Fatalf("failed to list links: %v", err)
	}

	var found bool
	for _, ifi := range ifis {
		if ifi.Name == name {
			found = true
			break
		}
	}

	return found
}

func mustBeTimeoutNetError(t *testing.T, err error) {
	t.Helper()
	ne, ok := err.(net.Error)
	if !ok {
		t.Fatalf("didn't get a net.Error: got a %T instead", err)
	}
	if !ne.Timeout() {
		t.Fatalf("didn't get a timeout")
	}
}
<commit_msg>netlink: bump integration test timeout<commit_after>//+build go1.12,linux

package netlink_test

import (
	"net"
	"os"
	"runtime"
	"sync"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/jsimonetti/rtnetlink/rtnl"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

func TestIntegrationConnTimeout(t *testing.T) {
	t.Parallel()

	conn, err := netlink.Dial(unix.NETLINK_GENERIC, nil)
	if err != nil {
		t.Fatalf("failed to dial: %v", err)
	}
	defer conn.Close()

	timeout := 1 * time.Millisecond
	if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
		t.Fatalf("failed to set deadline: %v", err)
	}

	errC := make(chan error)
	go func() {
		_, err := conn.Receive()
		errC <- err
	}()

	select {
	case err := <-errC:
		mustBeTimeoutNetError(t, err)
	case <-time.After(timeout + 100*time.Millisecond):
		t.Fatalf("timeout did not fire")
	}
}

func TestIntegrationConnExecuteAfterReadDeadline(t *testing.T) {
	t.Parallel()

	conn, err := netlink.Dial(unix.NETLINK_GENERIC, nil)
	if err != nil {
		t.Fatalf("failed to dial: %v", err)
	}
	defer conn.Close()

	timeout := 1 * time.Millisecond
	if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
		t.Fatalf("failed to set deadline: %v", err)
	}
	time.Sleep(2 * timeout)

	req := netlink.Message{
		Header: netlink.Header{
			Flags:    netlink.Request | netlink.Acknowledge,
			Sequence: 1,
		},
	}
	got, err := conn.Execute(req)
	if err == nil {
		t.Fatalf("Execute succeeded: got %v", got)
	}
	mustBeTimeoutNetError(t, err)
}

func TestIntegrationConnNetNSExplicit(t *testing.T) {
	t.Parallel()

	skipUnprivileged(t)

	// Create a network namespace for use within this test.
	const ns = "nltest0"
	shell(t, "ip", "netns", "add", ns)
	defer shell(t, "ip", "netns", "del", ns)

	f, err := os.Open("/var/run/netns/" + ns)
	if err != nil {
		t.Fatalf("failed to open namespace file: %v", err)
	}
	defer f.Close()

	// Create a connection in each the host namespace and the new network
	// namespace. We will use these to validate that a namespace was entered
	// and that an interface creation notification was only visible to the
	// connection within the namespace.
	hostC, hostDone := rtnlDial(t, 0)
	defer hostDone()

	nsC, nsDone := rtnlDial(t, int(f.Fd()))
	defer nsDone()

	var wg sync.WaitGroup
	wg.Add(1)
	defer wg.Wait()

	go func() {
		defer wg.Done()

		_, err := hostC.Receive()
		if err == nil {
			panic("received netlink message in host namespace")
		}

		// Timeout means we were interrupted, so return.
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			return
		}

		panicf("failed to receive in host namespace: %v", err)
	}()

	// Create a temporary interface within the new network namespace.
	const ifName = "nltestns0"
	defer shell(t, "ip", "netns", "exec", ns, "ip", "link", "del", ifName)

	ifi := rtnlReceive(t, nsC, func() {
		// Trigger a notification in the new namespace.
		shell(t, "ip", "netns", "exec", ns, "ip", "tuntap", "add", ifName, "mode", "tun")
	})

	// And finally interrupt the host connection so it can exit its
	// receive goroutine.
	if err := hostC.SetDeadline(time.Unix(1, 0)); err != nil {
		t.Fatalf("failed to interrupt host connection: %v", err)
	}

	if diff := cmp.Diff(ifName, ifi); diff != "" {
		t.Fatalf("unexpected interface name (-want +got):\n%s", diff)
	}
}

func TestIntegrationConnNetNSImplicit(t *testing.T) {
	t.Parallel()

	skipUnprivileged(t)

	// Create a network namespace for use within this test.
	const ns = "nltest0"
	shell(t, "ip", "netns", "add", ns)
	defer shell(t, "ip", "netns", "del", ns)

	f, err := os.Open("/var/run/netns/" + ns)
	if err != nil {
		t.Fatalf("failed to open namespace file: %v", err)
	}
	defer f.Close()

	// Create an interface in the new namespace. We will attempt to find it later.
	const ifName = "nltestns0"
	shell(t, "ip", "netns", "exec", ns, "ip", "tuntap", "add", ifName, "mode", "tun")
	defer shell(t, "ip", "netns", "exec", ns, "ip", "link", "del", ifName)

	// We're going to manipulate the network namespace of this thread, so we
	// must lock OS thread and keep track of the original namespace for later.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	threadNS, err := netlink.ThreadNetNS()
	if err != nil {
		t.Fatalf("failed to get current network namespace: %v", err)
	}
	defer threadNS.Close()

	if err := threadNS.Set(int(f.Fd())); err != nil {
		t.Fatalf("failed to enter new network namespace: %v", err)
	}

	// A newly created netlink connection should enter the new network namespace
	// associated with this thread automatically.
	if !findLink(t, ifName) {
		t.Fatalf("did not find interface %q in namespace %q", ifName, ns)
	}

	// Return to the default namespace.
	//
	// A newly created netlink connection should NOT find the link because it
	// is now in the default namespace.
	if err := threadNS.Restore(); err != nil {
		t.Fatalf("failed to restore original network namespace: %v", err)
	}

	if findLink(t, ifName) {
		t.Fatalf("found interface %q in default namespace", ifName)
	}
}

func findLink(t *testing.T, name string) bool {
	t.Helper()

	c, err := rtnl.Dial(nil)
	if err != nil {
		t.Fatalf("failed to dial rtnetlink: %v", err)
	}
	defer c.Close()

	ifis, err := c.Links()
	if err != nil {
		t.Fatalf("failed to list links: %v", err)
	}

	var found bool
	for _, ifi := range ifis {
		if ifi.Name == name {
			found = true
			break
		}
	}

	return found
}

func mustBeTimeoutNetError(t *testing.T, err error) {
	t.Helper()
	ne, ok := err.(net.Error)
	if !ok {
		t.Fatalf("didn't get a net.Error: got a %T instead", err)
	}
	if !ne.Timeout() {
		t.Fatalf("didn't get a timeout")
	}
}
<|endoftext|>


<commit_before>package swarm

import (
	"bytes"
	"net"
	"sync"
	"time"
	"xd/lib/bittorrent"
	"xd/lib/bittorrent/extensions"
	"xd/lib/common"
	"xd/lib/log"
	"xd/lib/metainfo"
	"xd/lib/network"
	"xd/lib/storage"
	"xd/lib/tracker"
)

// single torrent tracked in a swarm
type Torrent struct {
	Net         network.Network
	Trackers    []tracker.Announcer
	announcer   *time.Ticker
	id          common.PeerID
	st          storage.Torrent
	piece       chan pieceEvent
	obconns     map[string]*PeerConn
	ibconns     map[string]*PeerConn
	mtx         sync.Mutex
	pt          *pieceTracker
	defaultOpts *extensions.ExtendedOptions
}

func newTorrent(st storage.Torrent) *Torrent {
	t := &Torrent{
		st:          st,
		piece:       make(chan pieceEvent),
		ibconns:     make(map[string]*PeerConn),
		obconns:     make(map[string]*PeerConn),
		defaultOpts: extensions.New(),
	}
	t.pt = createPieceTracker(st, t.getRarestPiece)
	t.pt.have = t.broadcastHave
	return t
}

func (t *Torrent) getRarestPiece(remote *bittorrent.Bitfield) (idx uint32) {
	var swarm []*bittorrent.Bitfield
	t.VisitPeers(func(c *PeerConn) {
		if c.bf != nil {
			swarm = append(swarm, c.bf)
		}
	})
	idx = remote.FindRarest(swarm)
	return
}

// call a visitor on each open peer connection
func (t *Torrent) VisitPeers(v func(*PeerConn)) {
	var conns []*PeerConn
	t.mtx.Lock()
	for _, conn := range t.obconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	for _, conn := range t.ibconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		v(conn)
	}
}

func (t *Torrent) GetStatus() TorrentStatus {
	name := t.Name()
	var peers []*PeerConnStats
	t.VisitPeers(func(c *PeerConn) {
		peers = append(peers, c.Stats())
	})
	log.Debugf("unlocked torrent mutex for %s", name)
	state := Downloading
	if t.Done() {
		state = Seeding
	}
	return TorrentStatus{
		Peers:    peers,
		Name:     name,
		State:    state,
		Infohash: t.MetaInfo().Infohash().Hex(),
	}

}

func (t *Torrent) Bitfield() *bittorrent.Bitfield {
	return t.st.Bitfield()
}

// start annoucing on all trackers
func (t *Torrent) StartAnnouncing() {
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Started)
	}
	if t.announcer == nil {
		t.announcer = time.NewTicker(time.Second)
	}
	go t.pollAnnounce()
}

// stop annoucing on all trackers
func (t *Torrent) StopAnnouncing() {
	if t.announcer != nil {
		t.announcer.Stop()
	}
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Stopped)
	}
}

// poll announce ticker channel and issue announces
func (t *Torrent) pollAnnounce() {
	for {
		_, ok := <-t.announcer.C
		if !ok {
			// done
			return
		}
		for _, tr := range t.Trackers {
			if tr.ShouldAnnounce() {
				go t.Announce(tr, tracker.Nop)
			}
		}
	}
}

// do an announce
func (t *Torrent) Announce(tr tracker.Announcer, event tracker.Event) {
	req := &tracker.Request{
		Infohash: t.st.Infohash(),
		PeerID:   t.id,
		IP:       t.Net.Addr(),
		Port:     6881,
		Event:    event,
		NumWant:  10, // TODO: don't hardcode
		Left:     t.st.DownloadRemaining(),
	}
	resp, err := tr.Announce(req)
	if err == nil {
		for _, p := range resp.Peers {
			a, e := p.Resolve(t.Net)
			if e == nil {
				if a.String() == t.Net.Addr().String() {
					// don't connect to self or a duplicate
					continue
				}
				// no error resolving
				go t.PersistPeer(a, p.ID)
			} else {
				log.Warnf("failed to resolve peer %s", e.Error())
			}
		}
	} else {
		log.Warnf("failed to announce to %s", tr.Name())
	}
}

// persit a connection to a peer
func (t *Torrent) PersistPeer(a net.Addr, id common.PeerID) {

	triesLeft := 10
	for !t.Done() {
		if t.HasIBConn(a) {
			return
		}
		if !t.HasOBConn(a) {
			err := t.AddPeer(a, id)
			if err == nil {
				triesLeft = 10
			} else {
				triesLeft--
			}
			if triesLeft == 0 {
				return
			}
		} else {
			time.Sleep(time.Second)
		}
	}
}

func (t *Torrent) HasIBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.ibconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) HasOBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.obconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) addOBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.obconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
}

func (t *Torrent) removeOBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.obconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

func (t *Torrent) addIBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.ibconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
	c.inbound = true
}

func (t *Torrent) removeIBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.ibconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

// connect to a new peer for this swarm, blocks
func (t *Torrent) AddPeer(a net.Addr, id common.PeerID) error {
	c, err := t.Net.Dial(a.Network(), a.String())
	if err == nil {
		// connected
		ih := t.st.Infohash()
		// build handshake
		h := new(bittorrent.Handshake)
		// enable bittorrent extensions
		h.Reserved.Set(bittorrent.Extension)
		copy(h.Infohash[:], ih[:])
		copy(h.PeerID[:], t.id[:])
		// send handshake
		err = h.Send(c)
		if err == nil {
			// get response to handshake
			err = h.Recv(c)
			if err == nil {
				if bytes.Equal(ih[:], h.Infohash[:]) {
					// infohashes match
					var opts *extensions.ExtendedOptions
					if h.Reserved.Has(bittorrent.Extension) {
						opts = t.defaultOpts.Copy()
					}
					pc := makePeerConn(c, t, h.PeerID, opts)
					pc.start()
					t.addOBPeer(pc)
					pc.Send(t.Bitfield().ToWireMessage())
					return nil
				} else {
					log.Warn("Infohash missmatch")
				}
			}
		}
		log.Debugf("didn't complete handshake with peer: %s", err)
		// bad thing happened
		c.Close()
	}
	log.Debugf("didn't connect to %s: %s", a, err)
	return err
}

func (t *Torrent) broadcastHave(idx uint32) {
	msg := common.NewHave(idx)
	conns := make(map[string]*PeerConn)
	t.mtx.Lock()
	for k, conn := range t.ibconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	for k, conn := range t.obconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		go conn.Send(msg)
	}
}

// get metainfo for this torrent
func (t *Torrent) MetaInfo() *metainfo.TorrentFile {
	return t.st.MetaInfo()
}

func (t *Torrent) Name() string {
	return t.MetaInfo().TorrentName()
}

// gracefully close torrent and flush to disk
func (t *Torrent) Close() {
	chnl := t.piece
	t.piece = nil
	close(chnl)
	t.st.Flush()
}

// callback called when we get a new inbound peer
func (t *Torrent) onNewPeer(c *PeerConn) {
	a := c.c.RemoteAddr()
	if t.HasIBConn(a) {
		log.Infof("duplicate peer from %s", a)
		c.Close()
		return
	}
	log.Infof("New peer (%s) for %s", c.id.String(), t.st.Infohash().Hex())
	t.addIBPeer(c)
}

// handle a piece request
func (t *Torrent) onPieceRequest(c *PeerConn, req *common.PieceRequest) {
	if t.piece != nil {
		t.piece <- pieceEvent{c, req}
	}
}

func (t *Torrent) Run() {
	go t.handlePieces()
	for !t.Done() {
		time.Sleep(time.Minute)
	}
	// do final piece check
	log.Infof("%s checking all pieces before seeding", t.Name())
	err := t.st.VerifyAll(false)
	if err == nil {
		log.Infof("%s is seeding", t.Name())
		for _, tr := range t.Trackers {
			go t.Announce(tr, "completed")
		}
	} else {
		log.Errorf("%s verify pieces fail: %s", t.Name(), err)
	}
}

func (t *Torrent) handlePieces() {
	log.Infof("%s running", t.Name())
	for {
		ev, ok := <-t.piece
		if !ok {
			log.Infof("%s torrent run exit", t.Name())
			// channel closed
			return
		}
		r := ev.r
		if r.Length > 0 {
			log.Debugf("%s asked for piece %d %d-%d", ev.c.id.String(), r.Index, r.Begin, r.Begin+r.Length)
			// TODO: cache common pieces (?)
			p, err := t.st.GetPiece(r)
			if p == nil {
				// we don't have the piece
				log.Infof("%s asked for a piece we don't have for %s: %s", ev.c.id.String(), t.Name(), err)
				// TODO: should we close here?
				ev.c.Close()
			} else {
				// have the piece, send it
				ev.c.Send(p.ToWireMessage())
				log.Debugf("%s queued piece %d %d-%d", ev.c.id.String(), r.Index, r.Begin, r.Begin+r.Length)
			}
		} else {
			log.Infof("%s asked for a zero length piece", ev.c.id.String())
			// TODO: should we close here?
			ev.c.Close()
		}

	}
}

func (t *Torrent) Done() bool {
	return t.Bitfield().Completed()
}
<commit_msg>run inbound peer<commit_after>package swarm

import (
	"bytes"
	"net"
	"sync"
	"time"
	"xd/lib/bittorrent"
	"xd/lib/bittorrent/extensions"
	"xd/lib/common"
	"xd/lib/log"
	"xd/lib/metainfo"
	"xd/lib/network"
	"xd/lib/storage"
	"xd/lib/tracker"
)

// single torrent tracked in a swarm
type Torrent struct {
	Net         network.Network
	Trackers    []tracker.Announcer
	announcer   *time.Ticker
	id          common.PeerID
	st          storage.Torrent
	piece       chan pieceEvent
	obconns     map[string]*PeerConn
	ibconns     map[string]*PeerConn
	mtx         sync.Mutex
	pt          *pieceTracker
	defaultOpts *extensions.ExtendedOptions
}

func newTorrent(st storage.Torrent) *Torrent {
	t := &Torrent{
		st:          st,
		piece:       make(chan pieceEvent),
		ibconns:     make(map[string]*PeerConn),
		obconns:     make(map[string]*PeerConn),
		defaultOpts: extensions.New(),
	}
	t.pt = createPieceTracker(st, t.getRarestPiece)
	t.pt.have = t.broadcastHave
	return t
}

func (t *Torrent) getRarestPiece(remote *bittorrent.Bitfield) (idx uint32) {
	var swarm []*bittorrent.Bitfield
	t.VisitPeers(func(c *PeerConn) {
		if c.bf != nil {
			swarm = append(swarm, c.bf)
		}
	})
	idx = remote.FindRarest(swarm)
	return
}

// call a visitor on each open peer connection
func (t *Torrent) VisitPeers(v func(*PeerConn)) {
	var conns []*PeerConn
	t.mtx.Lock()
	for _, conn := range t.obconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	for _, conn := range t.ibconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		v(conn)
	}
}

func (t *Torrent) GetStatus() TorrentStatus {
	name := t.Name()
	var peers []*PeerConnStats
	t.VisitPeers(func(c *PeerConn) {
		peers = append(peers, c.Stats())
	})
	log.Debugf("unlocked torrent mutex for %s", name)
	state := Downloading
	if t.Done() {
		state = Seeding
	}
	return TorrentStatus{
		Peers:    peers,
		Name:     name,
		State:    state,
		Infohash: t.MetaInfo().Infohash().Hex(),
	}

}

func (t *Torrent) Bitfield() *bittorrent.Bitfield {
	return t.st.Bitfield()
}

// start annoucing on all trackers
func (t *Torrent) StartAnnouncing() {
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Started)
	}
	if t.announcer == nil {
		t.announcer = time.NewTicker(time.Second)
	}
	go t.pollAnnounce()
}

// stop annoucing on all trackers
func (t *Torrent) StopAnnouncing() {
	if t.announcer != nil {
		t.announcer.Stop()
	}
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Stopped)
	}
}

// poll announce ticker channel and issue announces
func (t *Torrent) pollAnnounce() {
	for {
		_, ok := <-t.announcer.C
		if !ok {
			// done
			return
		}
		for _, tr := range t.Trackers {
			if tr.ShouldAnnounce() {
				go t.Announce(tr, tracker.Nop)
			}
		}
	}
}

// do an announce
func (t *Torrent) Announce(tr tracker.Announcer, event tracker.Event) {
	req := &tracker.Request{
		Infohash: t.st.Infohash(),
		PeerID:   t.id,
		IP:       t.Net.Addr(),
		Port:     6881,
		Event:    event,
		NumWant:  10, // TODO: don't hardcode
		Left:     t.st.DownloadRemaining(),
	}
	resp, err := tr.Announce(req)
	if err == nil {
		for _, p := range resp.Peers {
			a, e := p.Resolve(t.Net)
			if e == nil {
				if a.String() == t.Net.Addr().String() {
					// don't connect to self or a duplicate
					continue
				}
				// no error resolving
				go t.PersistPeer(a, p.ID)
			} else {
				log.Warnf("failed to resolve peer %s", e.Error())
			}
		}
	} else {
		log.Warnf("failed to announce to %s", tr.Name())
	}
}

// persit a connection to a peer
func (t *Torrent) PersistPeer(a net.Addr, id common.PeerID) {

	triesLeft := 10
	for !t.Done() {
		if t.HasIBConn(a) {
			return
		}
		if !t.HasOBConn(a) {
			err := t.AddPeer(a, id)
			if err == nil {
				triesLeft = 10
			} else {
				triesLeft--
			}
			if triesLeft == 0 {
				return
			}
		} else {
			time.Sleep(time.Second)
		}
	}
}

func (t *Torrent) HasIBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.ibconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) HasOBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.obconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) addOBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.obconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
}

func (t *Torrent) removeOBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.obconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

func (t *Torrent) addIBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.ibconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
	c.inbound = true
}

func (t *Torrent) removeIBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.ibconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

// connect to a new peer for this swarm, blocks
func (t *Torrent) AddPeer(a net.Addr, id common.PeerID) error {
	c, err := t.Net.Dial(a.Network(), a.String())
	if err == nil {
		// connected
		ih := t.st.Infohash()
		// build handshake
		h := new(bittorrent.Handshake)
		// enable bittorrent extensions
		h.Reserved.Set(bittorrent.Extension)
		copy(h.Infohash[:], ih[:])
		copy(h.PeerID[:], t.id[:])
		// send handshake
		err = h.Send(c)
		if err == nil {
			// get response to handshake
			err = h.Recv(c)
			if err == nil {
				if bytes.Equal(ih[:], h.Infohash[:]) {
					// infohashes match
					var opts *extensions.ExtendedOptions
					if h.Reserved.Has(bittorrent.Extension) {
						opts = t.defaultOpts.Copy()
					}
					pc := makePeerConn(c, t, h.PeerID, opts)
					pc.start()
					t.addOBPeer(pc)
					pc.Send(t.Bitfield().ToWireMessage())
					return nil
				} else {
					log.Warn("Infohash missmatch")
				}
			}
		}
		log.Debugf("didn't complete handshake with peer: %s", err)
		// bad thing happened
		c.Close()
	}
	log.Debugf("didn't connect to %s: %s", a, err)
	return err
}

func (t *Torrent) broadcastHave(idx uint32) {
	msg := common.NewHave(idx)
	conns := make(map[string]*PeerConn)
	t.mtx.Lock()
	for k, conn := range t.ibconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	for k, conn := range t.obconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		go conn.Send(msg)
	}
}

// get metainfo for this torrent
func (t *Torrent) MetaInfo() *metainfo.TorrentFile {
	return t.st.MetaInfo()
}

func (t *Torrent) Name() string {
	return t.MetaInfo().TorrentName()
}

// gracefully close torrent and flush to disk
func (t *Torrent) Close() {
	chnl := t.piece
	t.piece = nil
	close(chnl)
	t.st.Flush()
}

// callback called when we get a new inbound peer
func (t *Torrent) onNewPeer(c *PeerConn) {
	a := c.c.RemoteAddr()
	if t.HasIBConn(a) {
		log.Infof("duplicate peer from %s", a)
		c.Close()
		return
	}
	log.Infof("New peer (%s) for %s", c.id.String(), t.st.Infohash().Hex())
	t.addIBPeer(c)
	c.start()
}

// handle a piece request
func (t *Torrent) onPieceRequest(c *PeerConn, req *common.PieceRequest) {
	if t.piece != nil {
		t.piece <- pieceEvent{c, req}
	}
}

func (t *Torrent) Run() {
	go t.handlePieces()
	for !t.Done() {
		time.Sleep(time.Minute)
	}
	// do final piece check
	log.Infof("%s checking all pieces before seeding", t.Name())
	err := t.st.VerifyAll(false)
	if err == nil {
		log.Infof("%s is seeding", t.Name())
		for _, tr := range t.Trackers {
			go t.Announce(tr, "completed")
		}
	} else {
		log.Errorf("%s verify pieces fail: %s", t.Name(), err)
	}
}

func (t *Torrent) handlePieces() {
	log.Infof("%s running", t.Name())
	for {
		ev, ok := <-t.piece
		if !ok {
			log.Infof("%s torrent run exit", t.Name())
			// channel closed
			return
		}
		r := ev.r
		if r.Length > 0 {
			log.Debugf("%s asked for piece %d %d-%d", ev.c.id.String(), r.Index, r.Begin, r.Begin+r.Length)
			// TODO: cache common pieces (?)
			p, err := t.st.GetPiece(r)
			if p == nil {
				// we don't have the piece
				log.Infof("%s asked for a piece we don't have for %s: %s", ev.c.id.String(), t.Name(), err)
				// TODO: should we close here?
				ev.c.Close()
			} else {
				// have the piece, send it
				ev.c.Send(p.ToWireMessage())
				log.Debugf("%s queued piece %d %d-%d", ev.c.id.String(), r.Index, r.Begin, r.Begin+r.Length)
			}
		} else {
			log.Infof("%s asked for a zero length piece", ev.c.id.String())
			// TODO: should we close here?
			ev.c.Close()
		}

	}
}

func (t *Torrent) Done() bool {
	return t.Bitfield().Completed()
}
<|endoftext|>


<commit_before>package main

// A comment

/* Multi
  line
  comment
*/

// To run type at terminal: go run language.go

import "fmt" // Input and output

// Another way of importing
import ("log"
"strings"
"sort"
"os"
"io/ioutil"
"strconv")

// Program entry point
func main() {
	fmt.Println("Hello, World!"); // At terminal you can godoc fmt Println for more info

	// Data Types:
	// Integers: uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64
	// String: string
	// Booelan: bool

	// Variables (statically typed: defined and cannot be changed)

	// uint8 is 2^8 possible values, so 0 to 255

	// Declare, then initialize
	var aUint8 uint8
	aUint8 = 0

	// Declare and initialize
	var anInt int = 1

	// Type defined implicitly
	someNumber := 33
	someFloat := 100.01

	// String
	var someString string = "My String"  // We can use

	// Constant
	const HOURS_PER_DAY int = 24

	// Multiple variable declaration
	var (
		fingers = 5
		hands = 2
		lengthOfSomeString = len(someString)
	)

	// Math: +, -, *, /, %
	// Also: +=, -= for  a = a + x
	fingers = fingers + 5 - 5 / 1
	hands = (4 % hands) + 2

	// Printing to console
	fmt.Println(aUint8, " ", anInt, " ", someNumber, " ", someFloat, " ", someString, " ", lengthOfSomeString)
	// Output: 0 1 33 100.01 My String 9

	fmt.Println("Concatenating this string " + "and this other string.")

	// Using fmt.Printf
	fmt.Printf("Humans have %d fingers, %d hands, and %.2f average IQ\n", fingers, hands, someFloat)
	// Output: Humans have 5 fingers, 2 hands, and 100.01 average IQ

	fmt.Printf("aUint8 is of type %T\n", aUint8) // Output the data type
	fmt.Printf("someNumber in binary is %b \n", someNumber) // Output as binary, 100001
	fmt.Printf("The code 64 code is character %c \n", 64) // Output a character, @

	{
		// Arrays
		var cards[2] int
		cards[0] = 1
		cards[1] = 2

		cards2 := [2]int {1, 2} // Same as above

		// Going through the array, considering index
		for index, value := range cards {
			assert( value-1 == index, "value-1 == index")
		}

		for _, value := range cards2 {
			assert( value == value, "value == value")
		}
	}

	// Logical operators:
	// - And: &&
	// - Or: ||
	// - Not: !

	// Relational operators:
	// - Equality: ==
	// - Not Equal: !=
	// - Less Than: <
	// ... : >, <=, >=

	// For loops
	i:=0
	for i < 10 { i++ }

	for j:=0; j<10; j++ {
		// Stuff to do
	}

	// If else
	if 5 >= 2 {
		// This line runs
	} else {
		// Does not run
	}

	// if else if
	if 4 > 4 {
		// This line doesn't run
	} else if ( 2 < 4) {
		// This line runs
	} else {
		// This line doesn't run
	}

	// switch
	switch(5) {
		case 1: // does not run
		case 5: // this line runs
		default: // does not run
	}

	{
	// Slices: like an array, but no size specified

		slice := []int {0, 1, 2, 3, 4, 5}
		firstSlice := slice[0:3] // 0 up to but not including 3rd index, so length is 3 and has {0, 1, 2}
		assert( firstSlice[0] == 0 && firstSlice[2] == 2, "0 2")
		fmt.Println(slice[:3]) // From 0 to but not including 3rd index.  Output: [0, 1, 2]
		fmt.Println(slice[2:]) // From 2 index to end. Output: [2, 3, 4, 5]

		zeroForFirst := 3
		size := 9
		notDefinedValuesSlice := make([]int, zeroForFirst, size)
		fmt.Println(notDefinedValuesSlice[0:]) // [0 0 0]

		copy(notDefinedValuesSlice, slice) // Copy values from slice to notDefinedValuesSlice
		fmt.Println(notDefinedValuesSlice[0:]) // [0 1 2]

		notDefinedValuesSlice = append(notDefinedValuesSlice, 4, 5, 6)
		fmt.Println(notDefinedValuesSlice[0:]) // [0 1 2 4 5 6]
	}

	{
		// Maps
		kidAges := make(map[string] int) // map[keyType] valueType
		kidAges["Tom"] = 12
		kidAges["Tim"] = 13
		assert( len(kidAges) == 2, "len(kidAges) == 2" )
		delete(kidAges, "Tom")
		assert( len(kidAges) == 1, "len(kidAges) == 1" )
	}

	{
		// string operations
		helloWorld := "Hello, World"
		assert(strings.Contains(helloWorld, "ld") == true, "Check for ld")
		assert(strings.Index(helloWorld, "llo") == 2, "Index of llo")
		assert(strings.Count(helloWorld, "l") == 3, "Count of ls")
		assert(strings.Replace(helloWorld, "o", "0", 1) == "Hell0, World", "Replacing one o in Hello, World")

		// Split, sort
		names := "Tim,Tom,Bob"
		arrayOfNames := strings.Split(names, ",")
		sort.Strings(arrayOfNames)

		// Join
		otherNames := strings.Join( []string{"Tara", "Thor"}, "," )
		fmt.Println(otherNames) // Tara,Thor
	}

	{
		// Conversion
		someUint := 0
		someInt := 1
		someFloat := 2.34
		someString1 := "56"
		someString2 := "78.9"

		assert( int(someUint) == 0, "Uint to int" )
		assert( float64(someInt) == 1.0, "Int to float" )
		assert( int(someFloat) == 2, "Float to int" )

		intFromString, _ := strconv.ParseInt(someString1, 0, 64)
		assert( intFromString == 56, "int from string")

		floatFromString, _ := strconv.ParseFloat(someString2, 64)
		assert( floatFromString == 78.9, "float from string")
	}

	// Function calls

	// Simple function call
	assert( sum(2,3) == 5, "sum(2,3) == 5" )

	// Call a function when main finishes, useful for cleanup operations
	defer assert( sum(1,2) == 3, "sum(1,2) == 3")

	// n arguments in function
	assert( sumTheArguments(1, 2, 3, 4, 5, 6) == 21, "sumTheArguments(1, 2, 3, 4, 5, 6) == 21")

	{
		// Multiple return from function
		num1, num2 := returnTwoValues()
		assert( num1 == 2, "num1 == 2")
		assert( num2 == 3, "num3 == 3")
	}

	{
		// Function with closure
		num:= 2
		checkForDivisible := func(n int) bool {
			return n % num == 0 // Note that num doesn't exist in this scope, but it's one level outside
		}
		assert( checkForDivisible(5) == false, "checkForDivisible(5) == false")
	}

	{
		// Calling Recursive function
		assert( fib(8) == 21, "fib(8) == 21" )
	}

	{
		produceDivByZero(); // runtime error: integer divide by zero
		doPanic() // Hello, this calls recover()
	}

	{
		// Pass by value
		n := 0
		passByValue(&n)	// &n gets the address of n
		assert( n == 1, "n == 1")

		// Pointer
		nPtr := new(int) // A pointer
		passByValue(nPtr)
		assert( *nPtr == 1, "*nPtr == 1") // The * is used to dereference
	}

	{
		// Object
		point := Point{ 0, 1 }
		assert( point.x == 0, "point.x == 0")
		assert( point.y == 1, "point.y == 1")
		assert( point.isXPositive() == true, "point.isXPositive() == true")
	}

	{
		// Using a function that uses an interface
		truck := Truck { }
		doDrive(&truck) // Since Truck is a Vehicle then this is ok
	}

	// FILE IO
	{
		fileName := "temp.txt"
		defer os.Remove(fileName) // Cleanup

		// Writing
		fileOut, err := os.Create(fileName)
		if (err != nil) { log.Fatal(err) }
		fileOut.WriteString("Some text")
		fileOut.Close()

		fileIn, err := ioutil.ReadFile(fileName)
		if (err != nil) { log.Fatal(err) }
		text1 := string(fileIn)
		assert(text1 == "Some text", "Verifying data from file.")
	}

}

// For my debug testing
func assert(evaluateTo bool, description string) {
	if (!evaluateTo) { log.Fatal("Failed assert,", description) }
}

// Declare a function
// func nameOfFunction(variableName variableType) returnType
func sum(a int, b int) int {
	return a + b
}

// Function with multiple return
// func nameOfFunction(arguments) (returnType1, returnType2, returnType...)
func returnTwoValues() (int, int) {
	return 2, 3
}
// Function with n arguments
func sumTheArguments(arguments ... int) int {
	theSum := 0
	for _, value := range arguments  {
		theSum += value
	}
	return theSum
}

// Recursive function
func fib(n int) int {
	if (n == 0 || n == 1) { return n }
	return fib(n-1) + fib(n-2)
}

// Function with defer and recover
func produceDivByZero() {
	defer func() { fmt.Println(recover()) }()
	n := 0
	divByZero := func() int { return 5 / n }
	divByZero() // Will yield: runtime error: integer divide by zero
}

// Function with panic
func doPanic() {
	defer func() { fmt.Println(recover()) }()
	panic("Hello, this calls recover()")
}

// Passing by reference
func passByValue(nPtr *int) {
	*nPtr = 1
}

// Structs
type Point struct {
	x int
	y int
}

// Method for Point called isXPositive
func (point *Point) isXPositive() bool {
	if ( point.x < 0) { return false }
	return true
}

// Interfaces
// - If you want to be a Vehicle then you must implement drive() method
type Vehicle interface {
	drive()
}

type Truck struct { }

// Implementation of drive()
func (truck *Truck) drive() { }

// Function that accepts objects that employ the Vehicle interface
func doDrive(vehicle Vehicle)  {
	vehicle.drive()
}<commit_msg>Example of time.Sleep and go routine<commit_after>package main

// A comment

/* Multi
  line
  comment
*/

// To run type at terminal: go run language.go

import "fmt" // Input and output

// Another way of importing
import (
"log"
"strings"
"sort"
"os"
"io/ioutil"
"strconv"
"time"
)

// Program entry point
func main() {
	fmt.Println("Hello, World!"); // At terminal you can godoc fmt Println for more info

	// Data Types:
	// Integers: uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64
	// String: string
	// Booelan: bool

	// Variables (statically typed: defined and cannot be changed)

	// uint8 is 2^8 possible values, so 0 to 255

	// Declare, then initialize
	var aUint8 uint8
	aUint8 = 0

	// Declare and initialize
	var anInt int = 1

	// Type defined implicitly
	someNumber := 33
	someFloat := 100.01

	// String
	var someString string = "My String"  // We can use

	// Constant
	const HOURS_PER_DAY int = 24

	// Multiple variable declaration
	var (
		fingers = 5
		hands = 2
		lengthOfSomeString = len(someString)
	)

	// Math: +, -, *, /, %
	// Also: +=, -= for  a = a + x
	fingers = fingers + 5 - 5 / 1
	hands = (4 % hands) + 2

	// Printing to console
	fmt.Println(aUint8, " ", anInt, " ", someNumber, " ", someFloat, " ", someString, " ", lengthOfSomeString)
	// Output: 0 1 33 100.01 My String 9

	fmt.Println("Concatenating this string " + "and this other string.")

	// Using fmt.Printf
	fmt.Printf("Humans have %d fingers, %d hands, and %.2f average IQ\n", fingers, hands, someFloat)
	// Output: Humans have 5 fingers, 2 hands, and 100.01 average IQ

	fmt.Printf("aUint8 is of type %T\n", aUint8) // Output the data type
	fmt.Printf("someNumber in binary is %b \n", someNumber) // Output as binary, 100001
	fmt.Printf("The code 64 code is character %c \n", 64) // Output a character, @

	{
		// Arrays
		var cards[2] int
		cards[0] = 1
		cards[1] = 2

		cards2 := [2]int {1, 2} // Same as above

		// Going through the array, considering index
		for index, value := range cards {
			assert( value-1 == index, "value-1 == index")
		}

		for _, value := range cards2 {
			assert( value == value, "value == value")
		}
	}

	// Logical operators:
	// - And: &&
	// - Or: ||
	// - Not: !

	// Relational operators:
	// - Equality: ==
	// - Not Equal: !=
	// - Less Than: <
	// ... : >, <=, >=

	// For loops
	i:=0
	for i < 10 { i++ }

	for j:=0; j<10; j++ {
		// Stuff to do
	}

	// If else
	if 5 >= 2 {
		// This line runs
	} else {
		// Does not run
	}

	// if else if
	if 4 > 4 {
		// This line doesn't run
	} else if ( 2 < 4) {
		// This line runs
	} else {
		// This line doesn't run
	}

	// switch
	switch(5) {
		case 1: // does not run
		case 5: // this line runs
		default: // does not run
	}

	{
	// Slices: like an array, but no size specified

		slice := []int {0, 1, 2, 3, 4, 5}
		firstSlice := slice[0:3] // 0 up to but not including 3rd index, so length is 3 and has {0, 1, 2}
		assert( firstSlice[0] == 0 && firstSlice[2] == 2, "0 2")
		fmt.Println(slice[:3]) // From 0 to but not including 3rd index.  Output: [0, 1, 2]
		fmt.Println(slice[2:]) // From 2 index to end. Output: [2, 3, 4, 5]

		zeroForFirst := 3
		size := 9
		notDefinedValuesSlice := make([]int, zeroForFirst, size)
		fmt.Println(notDefinedValuesSlice[0:]) // [0 0 0]

		copy(notDefinedValuesSlice, slice) // Copy values from slice to notDefinedValuesSlice
		fmt.Println(notDefinedValuesSlice[0:]) // [0 1 2]

		notDefinedValuesSlice = append(notDefinedValuesSlice, 4, 5, 6)
		fmt.Println(notDefinedValuesSlice[0:]) // [0 1 2 4 5 6]
	}

	{
		// Maps
		kidAges := make(map[string] int) // map[keyType] valueType
		kidAges["Tom"] = 12
		kidAges["Tim"] = 13
		assert( len(kidAges) == 2, "len(kidAges) == 2" )
		delete(kidAges, "Tom")
		assert( len(kidAges) == 1, "len(kidAges) == 1" )
	}

	{
		// string operations
		helloWorld := "Hello, World"
		assert(strings.Contains(helloWorld, "ld") == true, "Check for ld")
		assert(strings.Index(helloWorld, "llo") == 2, "Index of llo")
		assert(strings.Count(helloWorld, "l") == 3, "Count of ls")
		assert(strings.Replace(helloWorld, "o", "0", 1) == "Hell0, World", "Replacing one o in Hello, World")

		// Split, sort
		names := "Tim,Tom,Bob"
		arrayOfNames := strings.Split(names, ",")
		sort.Strings(arrayOfNames)

		// Join
		otherNames := strings.Join( []string{"Tara", "Thor"}, "," )
		fmt.Println(otherNames) // Tara,Thor
	}

	{
		// Conversion
		someUint := 0
		someInt := 1
		someFloat := 2.34
		someString1 := "56"
		someString2 := "78.9"

		assert( int(someUint) == 0, "uint to int" )
		assert( float64(someInt) == 1.0, "unt to float" )
		assert( int(someFloat) == 2, "float to int" )
		assert( strconv.Itoa(someInt) == "1", "int to string")

		intFromString, _ := strconv.ParseInt(someString1, 0, 64)
		assert( intFromString == 56, "int from string")

		floatFromString, _ := strconv.ParseFloat(someString2, 64)
		assert( floatFromString == 78.9, "float from string")

	}

	// Function calls

	// Simple function call
	assert( sum(2,3) == 5, "sum(2,3) == 5" )

	// Call a function when main finishes, useful for cleanup operations
	defer assert( sum(1,2) == 3, "sum(1,2) == 3")

	// n arguments in function
	assert( sumTheArguments(1, 2, 3, 4, 5, 6) == 21, "sumTheArguments(1, 2, 3, 4, 5, 6) == 21")

	{
		// Multiple return from function
		num1, num2 := returnTwoValues()
		assert( num1 == 2, "num1 == 2")
		assert( num2 == 3, "num3 == 3")
	}

	{
		// Function with closure
		num:= 2
		checkForDivisible := func(n int) bool {
			return n % num == 0 // Note that num doesn't exist in this scope, but it's one level outside
		}
		assert( checkForDivisible(5) == false, "checkForDivisible(5) == false")
	}

	{
		// Calling Recursive function
		assert( fib(8) == 21, "fib(8) == 21" )
	}

	{
		produceDivByZero(); // runtime error: integer divide by zero
		doPanic() // Hello, this calls recover()
	}

	{
		// Pass by value
		n := 0
		passByValue(&n)	// &n gets the address of n
		assert( n == 1, "n == 1")

		// Pointer
		nPtr := new(int) // A pointer
		passByValue(nPtr)
		assert( *nPtr == 1, "*nPtr == 1") // The * is used to dereference
	}

	{
		// Object
		point := Point{ 0, 1 }
		assert( point.x == 0, "point.x == 0")
		assert( point.y == 1, "point.y == 1")
		assert( point.isXPositive() == true, "point.isXPositive() == true")
	}

	{
		// Using a function that uses an interface
		truck := Truck { }
		doDrive(&truck) // Since Truck is a Vehicle then this is ok
	}

	// FILE IO
	{
		fileName := "temp.txt"
		defer os.Remove(fileName) // Cleanup

		// Writing
		fileOut, err := os.Create(fileName)
		if (err != nil) { log.Fatal(err) }
		fileOut.WriteString("Some text")
		fileOut.Close()

		fileIn, err := ioutil.ReadFile(fileName)
		if (err != nil) { log.Fatal(err) }
		text1 := string(fileIn)
		assert(text1 == "Some text", "Verifying data from file.")
	}

	// Using time
	{
		for i:=0; i<3; i++ {
			fmt.Println("i is ", i)
			time.Sleep(time.Second) // Sleep for one second
		}

		myFunc := func (id int) {
			fmt.Print("{id:", id, "}\t")
		}
		// Calling a function
		for i:=0; i<50; i++ {
			go myFunc(i) // go routine: a lightweight thread
		}
		// The above will probably not yield in order output.
	}

}

// For my debug testing
func assert(evaluateTo bool, description string) {
	if (!evaluateTo) { log.Fatal("Failed assert,", description) }
}

// Declare a function
// func nameOfFunction(variableName variableType) returnType
func sum(a int, b int) int {
	return a + b
}

// Function with multiple return
// func nameOfFunction(arguments) (returnType1, returnType2, returnType...)
func returnTwoValues() (int, int) {
	return 2, 3
}
// Function with n arguments
func sumTheArguments(arguments ... int) int {
	theSum := 0
	for _, value := range arguments  {
		theSum += value
	}
	return theSum
}

// Recursive function
func fib(n int) int {
	if (n == 0 || n == 1) { return n }
	return fib(n-1) + fib(n-2)
}

// Function with defer and recover
func produceDivByZero() {
	defer func() { fmt.Println(recover()) }()
	n := 0
	divByZero := func() int { return 5 / n }
	divByZero() // Will yield: runtime error: integer divide by zero
}

// Function with panic
func doPanic() {
	defer func() { fmt.Println(recover()) }()
	panic("Hello, this calls recover()")
}

// Passing by reference
func passByValue(nPtr *int) {
	*nPtr = 1
}

// Structs
type Point struct {
	x int
	y int
}

// Method for Point called isXPositive
func (point *Point) isXPositive() bool {
	if ( point.x < 0) { return false }
	return true
}

// Interfaces
// - If you want to be a Vehicle then you must implement drive() method
type Vehicle interface {
	drive()
}

type Truck struct { }

// Implementation of drive()
func (truck *Truck) drive() { }

// Function that accepts objects that employ the Vehicle interface
func doDrive(vehicle Vehicle)  {
	vehicle.drive()
}<|endoftext|>


<commit_before>package jd

import "testing"

func TestReadPatch(t *testing.T) {
	cases := []struct {
		patch   string
		diff    string
		wantErr bool
	}{{
		patch: s(`[{"op":"add","path":"/foo","value":1}]`),
		diff: s(
			`@ ["foo"]`,
			`+ 1`,
		),
	}, {
		patch: s(
			`[{"op":"test","path":"/foo","value":1},`,
			`{"op":"remove","path":"/foo","value":1}]`,
		),
		diff: s(
			`@ ["foo"]`,
			`- 1`,
		),
	}, {
		patch: s(
			`[{"op":"add","path":"/foo","value":1},`,
			`{"op":"test","path":"/foo","value":1},`,
			`{"op":"remove","path":"/foo","value":1}]`,
		),
		diff: s(
			`@ ["foo"]`,
			`+ 1`,
			`@ ["foo"]`,
			`- 1`,
		),
	}, {
		patch: s(`[{"op":"add","path":"/foo/-","value":2}]`),
		diff: s(
			`@ ["foo",-1]`,
			`+ 2`,
		),
	}, {
		patch:   s(`[{"op":"test","path":"/foo","value":1}]`),
		wantErr: true,
	}, {
		patch:   s(`[{"op":"remove","path":"/foo","value":1}]`),
		wantErr: true,
	}}

	for _, tc := range cases {
		diff, err := ReadPatchString(tc.patch)
		if err != nil && !tc.wantErr {
			t.Errorf("Wanted no error. Got %v", err)
		}
		if err == nil && tc.wantErr {
			t.Errorf("Wanted an error. Got nil")
		}
		if err != nil && tc.wantErr {
			// Everything is okay
			continue
		}
		got := diff.Render()
		if got != tc.diff {
			t.Errorf("Wanted \n%q. Got \n%q", tc.diff, got)
		}
	}
}

func TestReadMerge(t *testing.T) {
	cases := []struct {
		patch string
		diff  string
	}{{
		patch: `{"a":1}`,
		diff: s(
			`@ [["MERGE"],"a"]`,
			`+ 1`,
		),
	}, {
		patch: ``,
		diff: s(
			`@ [["MERGE"]]`,
			`+`,
		),
	}, {
		patch: `null`,
		diff: s(
			`@ [["MERGE"]]`,
			`+ null`,
		),
	}, {
		patch: `[1,2,3]`,
		diff: s(
			`@ [["MERGE"]]`,
			`+ [1,2,3]`,
		),
	}}

	for _, c := range cases {
		diff, err := ReadMergeString(c.patch)
		if err != nil {
			t.Errorf("Wanted no error. Got %v", err)
		}
		if got := diff.Render(); got != c.diff {
			t.Errorf("Wanted %s. Got %s", c.diff, got)
		}
	}
}
<commit_msg>Expect void when reading null merge patch.<commit_after>package jd

import "testing"

func TestReadPatch(t *testing.T) {
	cases := []struct {
		patch   string
		diff    string
		wantErr bool
	}{{
		patch: s(`[{"op":"add","path":"/foo","value":1}]`),
		diff: s(
			`@ ["foo"]`,
			`+ 1`,
		),
	}, {
		patch: s(
			`[{"op":"test","path":"/foo","value":1},`,
			`{"op":"remove","path":"/foo","value":1}]`,
		),
		diff: s(
			`@ ["foo"]`,
			`- 1`,
		),
	}, {
		patch: s(
			`[{"op":"add","path":"/foo","value":1},`,
			`{"op":"test","path":"/foo","value":1},`,
			`{"op":"remove","path":"/foo","value":1}]`,
		),
		diff: s(
			`@ ["foo"]`,
			`+ 1`,
			`@ ["foo"]`,
			`- 1`,
		),
	}, {
		patch: s(`[{"op":"add","path":"/foo/-","value":2}]`),
		diff: s(
			`@ ["foo",-1]`,
			`+ 2`,
		),
	}, {
		patch:   s(`[{"op":"test","path":"/foo","value":1}]`),
		wantErr: true,
	}, {
		patch:   s(`[{"op":"remove","path":"/foo","value":1}]`),
		wantErr: true,
	}}

	for _, tc := range cases {
		diff, err := ReadPatchString(tc.patch)
		if err != nil && !tc.wantErr {
			t.Errorf("Wanted no error. Got %v", err)
		}
		if err == nil && tc.wantErr {
			t.Errorf("Wanted an error. Got nil")
		}
		if err != nil && tc.wantErr {
			// Everything is okay
			continue
		}
		got := diff.Render()
		if got != tc.diff {
			t.Errorf("Wanted \n%q. Got \n%q", tc.diff, got)
		}
	}
}

func TestReadMerge(t *testing.T) {
	cases := []struct {
		patch string
		diff  string
	}{{
		patch: `{"a":1}`,
		diff: s(
			`@ [["MERGE"],"a"]`,
			`+ 1`,
		),
	}, {
		patch: ``,
		diff: s(
			`@ [["MERGE"]]`,
			`+`,
		),
	}, {
		patch: `null`,
		diff: s(
			`@ [["MERGE"]]`,
			`+`,
		),
	}, {
		patch: `[1,2,3]`,
		diff: s(
			`@ [["MERGE"]]`,
			`+ [1,2,3]`,
		),
	}}

	for _, c := range cases {
		diff, err := ReadMergeString(c.patch)
		if err != nil {
			t.Errorf("Wanted no error. Got %v", err)
		}
		if got := diff.Render(); got != c.diff {
			t.Errorf("Wanted %s. Got %s", c.diff, got)
		}
	}
}
<|endoftext|>


<commit_before>package libgodelbrot

import (
    "math/big"
    "github.com/johnny-morrice/godelbrot/internal/bigbase"
)

// There are three different kinds of magic number in this program:
// 1. Mathematical constants.  For example, the location of the Mandelbrot set
//    is unlikely to change any time soon.  These are the most truly magical
//    numbers in this program.
// 2. Defaults.  It is convenient for this library to provide some sensible
//    defaults for its parameters.  As these are "guaranteed to work", these
//    represent mathematical truths in their own way.
// 3. Operational constants.  This program uses various integers in control
//    flow, in arithmetic, and when requesting memory from the operating system.
//    These are the least "magical" numbers present in this program.  Each of
//    these should be reviewed, since it may be desirable to replace these with
//    an item that can be configured at runtime.

// MATHEMATICAL CONSTANTS

// Minimum bounds of Mandelbrot set
const MandelbrotMin complex128 = -2.01 - 1.11i

// Maximum bounds of Mandelbrot set
const MandelbrotMax complex128 = 0.59 + 1.13i

// Named bignums
var bigZero big.Float = bigbase.MakeBigFloat(0, DefaultHighPrec)
var bigOne big.Float = bigbase.MakeBigFloat(1, DefaultHighPrec)
var bigTwo big.Float = bigbase.MakeBigFloat(2, DefaultHighPrec)

// DEFAULTS

// Default high precision for newly created big floats
const DefaultHighPrec uint = 500
// Default precision is for native arithmetic
const DefaultPrecision uint = 53

const DefaultIterations uint8 = 255
const DefaultDivergeLimit float64 = 4.0
const DefaultImageWidth uint = 800
const DefaultImageHeight uint = 600
const DefaultCollapse uint = 4
const DefaultBufferSize uint = 256

// Default base for newly parsed numbers
const DefaultBase int = 10

// What we consider to be a tiny image area, by default
const DefaultTinyImageArea uint = 40000

// Default sample size for region glitch-correction
const DefaultRegionSamples uint = 7<commit_msg>Increase default samples to prevent render glitch<commit_after>package libgodelbrot

import (
    "math/big"
    "github.com/johnny-morrice/godelbrot/internal/bigbase"
)

// There are three different kinds of magic number in this program:
// 1. Mathematical constants.  For example, the location of the Mandelbrot set
//    is unlikely to change any time soon.  These are the most truly magical
//    numbers in this program.
// 2. Defaults.  It is convenient for this library to provide some sensible
//    defaults for its parameters.  As these are "guaranteed to work", these
//    represent mathematical truths in their own way.
// 3. Operational constants.  This program uses various integers in control
//    flow, in arithmetic, and when requesting memory from the operating system.
//    These are the least "magical" numbers present in this program.  Each of
//    these should be reviewed, since it may be desirable to replace these with
//    an item that can be configured at runtime.

// MATHEMATICAL CONSTANTS

// Minimum bounds of Mandelbrot set
const MandelbrotMin complex128 = -2.01 - 1.11i

// Maximum bounds of Mandelbrot set
const MandelbrotMax complex128 = 0.59 + 1.13i

// Named bignums
var bigZero big.Float = bigbase.MakeBigFloat(0, DefaultHighPrec)
var bigOne big.Float = bigbase.MakeBigFloat(1, DefaultHighPrec)
var bigTwo big.Float = bigbase.MakeBigFloat(2, DefaultHighPrec)

// DEFAULTS

// Default high precision for newly created big floats
const DefaultHighPrec uint = 500
// Default precision is for native arithmetic
const DefaultPrecision uint = 53

const DefaultIterations uint8 = 255
const DefaultDivergeLimit float64 = 4.0
const DefaultImageWidth uint = 800
const DefaultImageHeight uint = 600
const DefaultCollapse uint = 4
const DefaultBufferSize uint = 256

// Default base for newly parsed numbers
const DefaultBase int = 10

// What we consider to be a tiny image area, by default
const DefaultTinyImageArea uint = 40000

// Default sample size for region glitch-correction
const DefaultRegionSamples uint = 12<|endoftext|>


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

package libkbfs

import (
	"sync"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/tlf"
	"golang.org/x/net/context"
)

func isRecoverableBlockError(err error) bool {
	_, isArchiveError := err.(BServerErrorBlockArchived)
	_, isDeleteError := err.(BServerErrorBlockDeleted)
	_, isRefError := err.(BServerErrorBlockNonExistent)
	_, isMaxExceededError := err.(BServerErrorMaxRefExceeded)
	return isArchiveError || isDeleteError || isRefError || isMaxExceededError
}

// putBlockToServer either puts the full block to the block server, or
// just adds a reference, depending on the refnonce in blockPtr.
func putBlockToServer(ctx context.Context, bserv BlockServer, tlfID tlf.ID,
	blockPtr BlockPointer, readyBlockData ReadyBlockData) error {
	var err error
	if blockPtr.RefNonce == ZeroBlockRefNonce {
		err = bserv.Put(ctx, tlfID, blockPtr.ID, blockPtr.BlockContext,
			readyBlockData.buf, readyBlockData.serverHalf)
	} else {
		// non-zero block refnonce means this is a new reference to an
		// existing block.
		err = bserv.AddBlockReference(ctx, tlfID, blockPtr.ID,
			blockPtr.BlockContext)
	}
	return err
}

// PutBlockCheckQuota is a thin wrapper around putBlockToServer (which
// calls either bserver.Put or bserver.AddBlockReference) that reports
// quota errors.
func PutBlockCheckQuota(ctx context.Context, bserv BlockServer,
	reporter Reporter, tlfID tlf.ID, blockPtr BlockPointer,
	readyBlockData ReadyBlockData, tlfName CanonicalTlfName) error {
	err := putBlockToServer(ctx, bserv, tlfID, blockPtr, readyBlockData)
	if qe, ok := err.(BServerErrorOverQuota); ok && !qe.Throttled {
		reporter.ReportErr(ctx, tlfName, tlfID.IsPublic(),
			WriteMode, OverQuotaWarning{qe.Usage, qe.Limit})
		return nil
	}
	return err
}

func doOneBlockPut(ctx context.Context, bserv BlockServer, reporter Reporter,
	tlfID tlf.ID, tlfName CanonicalTlfName, blockState blockState,
	errChan chan error, blocksToRemoveChan chan *FileBlock) {
	err := PutBlockCheckQuota(ctx, bserv, reporter, tlfID, blockState.blockPtr,
		blockState.readyBlockData, tlfName)
	if err == nil && blockState.syncedCb != nil {
		err = blockState.syncedCb()
	}
	if err != nil {
		if isRecoverableBlockError(err) {
			fblock, ok := blockState.block.(*FileBlock)
			if ok && !fblock.IsInd {
				blocksToRemoveChan <- fblock
			}
		}

		// one error causes everything else to cancel
		select {
		case errChan <- err:
		default:
			return
		}
	}
}

// doBlockPuts writes all the pending block puts to the cache and
// server. If the err returned by this function satisfies
// isRecoverableBlockError(err), the caller should retry its entire
// operation, starting from when the MD successor was created.
//
// Returns a slice of block pointers that resulted in recoverable
// errors and should be removed by the caller from any saved state.
func doBlockPuts(ctx context.Context, bserv BlockServer, bcache BlockCache,
	reporter Reporter, log logger.Logger, tlfID tlf.ID, tlfName CanonicalTlfName,
	bps blockPutState) ([]BlockPointer, error) {
	errChan := make(chan error, 1)
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	blocks := make(chan blockState, len(bps.blockStates))
	var wg sync.WaitGroup

	numWorkers := len(bps.blockStates)
	if numWorkers > maxParallelBlockPuts {
		numWorkers = maxParallelBlockPuts
	}
	wg.Add(numWorkers)
	// A channel to list any blocks that have been archived or
	// deleted.  Any of these will result in an error, so the maximum
	// we'll get is the same as the number of workers.
	blocksToRemoveChan := make(chan *FileBlock, numWorkers)

	worker := func() {
		defer wg.Done()
		for blockState := range blocks {
			doOneBlockPut(ctx, bserv, reporter, tlfID, tlfName,
				blockState, errChan, blocksToRemoveChan)
			select {
			// return early if the context has been canceled
			case <-ctx.Done():
				return
			default:
			}
		}
	}
	for i := 0; i < numWorkers; i++ {
		go worker()
	}

	for _, blockState := range bps.blockStates {
		blocks <- blockState
	}
	close(blocks)

	go func() {
		wg.Wait()
		close(errChan)
		close(blocksToRemoveChan)
	}()
	err := <-errChan
	var blocksToRemove []BlockPointer
	if isRecoverableBlockError(err) {
		// Wait for all the outstanding puts to finish, to amortize
		// the work of re-doing the put.
		for fblock := range blocksToRemoveChan {
			for i, bs := range bps.blockStates {
				if bs.block == fblock {
					// Let the caller know which blocks shouldn't be
					// retried.
					blocksToRemove = append(blocksToRemove,
						bps.blockStates[i].blockPtr)
				}
			}

			// Remove each problematic block from the cache so the
			// redo can just make a new block instead.
			if err := bcache.DeleteKnownPtr(tlfID, fblock); err != nil {
				log.CWarningf(ctx, "Couldn't delete ptr for a block: %v", err)
			}
		}
	}
	return blocksToRemove, err
}
<commit_msg>Make block_util.go use errgroup (#611)<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/tlf"
	"golang.org/x/net/context"
	"golang.org/x/sync/errgroup"
)

func isRecoverableBlockError(err error) bool {
	_, isArchiveError := err.(BServerErrorBlockArchived)
	_, isDeleteError := err.(BServerErrorBlockDeleted)
	_, isRefError := err.(BServerErrorBlockNonExistent)
	_, isMaxExceededError := err.(BServerErrorMaxRefExceeded)
	return isArchiveError || isDeleteError || isRefError || isMaxExceededError
}

// putBlockToServer either puts the full block to the block server, or
// just adds a reference, depending on the refnonce in blockPtr.
func putBlockToServer(ctx context.Context, bserv BlockServer, tlfID tlf.ID,
	blockPtr BlockPointer, readyBlockData ReadyBlockData) error {
	var err error
	if blockPtr.RefNonce == ZeroBlockRefNonce {
		err = bserv.Put(ctx, tlfID, blockPtr.ID, blockPtr.BlockContext,
			readyBlockData.buf, readyBlockData.serverHalf)
	} else {
		// non-zero block refnonce means this is a new reference to an
		// existing block.
		err = bserv.AddBlockReference(ctx, tlfID, blockPtr.ID,
			blockPtr.BlockContext)
	}
	return err
}

// PutBlockCheckQuota is a thin wrapper around putBlockToServer (which
// calls either bserver.Put or bserver.AddBlockReference) that reports
// quota errors.
func PutBlockCheckQuota(ctx context.Context, bserv BlockServer,
	reporter Reporter, tlfID tlf.ID, blockPtr BlockPointer,
	readyBlockData ReadyBlockData, tlfName CanonicalTlfName) error {
	err := putBlockToServer(ctx, bserv, tlfID, blockPtr, readyBlockData)
	if qe, ok := err.(BServerErrorOverQuota); ok && !qe.Throttled {
		reporter.ReportErr(ctx, tlfName, tlfID.IsPublic(),
			WriteMode, OverQuotaWarning{qe.Usage, qe.Limit})
		return nil
	}
	return err
}

func doOneBlockPut(ctx context.Context, bserv BlockServer, reporter Reporter,
	tlfID tlf.ID, tlfName CanonicalTlfName, blockState blockState,
	blocksToRemoveChan chan *FileBlock) error {
	err := PutBlockCheckQuota(ctx, bserv, reporter, tlfID, blockState.blockPtr,
		blockState.readyBlockData, tlfName)
	if err == nil && blockState.syncedCb != nil {
		err = blockState.syncedCb()
	}
	if err != nil && isRecoverableBlockError(err) {
		fblock, ok := blockState.block.(*FileBlock)
		if ok && !fblock.IsInd {
			blocksToRemoveChan <- fblock
		}
	}

	return err
}

// doBlockPuts writes all the pending block puts to the cache and
// server. If the err returned by this function satisfies
// isRecoverableBlockError(err), the caller should retry its entire
// operation, starting from when the MD successor was created.
//
// Returns a slice of block pointers that resulted in recoverable
// errors and should be removed by the caller from any saved state.
func doBlockPuts(ctx context.Context, bserv BlockServer, bcache BlockCache,
	reporter Reporter, log logger.Logger, tlfID tlf.ID, tlfName CanonicalTlfName,
	bps blockPutState) ([]BlockPointer, error) {
	eg, groupCtx := errgroup.WithContext(ctx)

	blocks := make(chan blockState, len(bps.blockStates))

	numWorkers := len(bps.blockStates)
	if numWorkers > maxParallelBlockPuts {
		numWorkers = maxParallelBlockPuts
	}
	// A channel to list any blocks that have been archived or
	// deleted.  Any of these will result in an error, so the maximum
	// we'll get is the same as the number of workers.
	blocksToRemoveChan := make(chan *FileBlock, numWorkers)

	worker := func() error {
		for blockState := range blocks {
			err := doOneBlockPut(groupCtx, bserv, reporter, tlfID,
				tlfName, blockState, blocksToRemoveChan)
			if err != nil {
				return err
			}
		}
		return nil
	}
	for i := 0; i < numWorkers; i++ {
		eg.Go(worker)
	}

	for _, blockState := range bps.blockStates {
		blocks <- blockState
	}
	close(blocks)

	err := eg.Wait()
	close(blocksToRemoveChan)
	var blocksToRemove []BlockPointer
	if isRecoverableBlockError(err) {
		// Wait for all the outstanding puts to finish, to amortize
		// the work of re-doing the put.
		for fblock := range blocksToRemoveChan {
			for i, bs := range bps.blockStates {
				if bs.block == fblock {
					// Let the caller know which blocks shouldn't be
					// retried.
					blocksToRemove = append(blocksToRemove,
						bps.blockStates[i].blockPtr)
				}
			}

			// Remove each problematic block from the cache so the
			// redo can just make a new block instead.
			if err := bcache.DeleteKnownPtr(tlfID, fblock); err != nil {
				log.CWarningf(ctx, "Couldn't delete ptr for a block: %v", err)
			}
		}
	}
	return blocksToRemove, err
}
<|endoftext|>


<commit_before>package gostore

import (
	"encoding/json"
	"github.com/mgutz/logxi/v1"
	"github.com/nanobox-io/golang-scribble"
)

type ScribbleStore struct {
	db   *scribble.Driver
	path string
}

func NewScribbleStore(path string) *ScribbleStore {
	if db, err := scribble.New(path, nil); err == nil {
		return &ScribbleStore{db, path}
	} else {
		log.Warn("cannot create scribble database", "err", err)
	}
	return nil
}

type ScribbleRows struct {
	rows []string
	i    int
	len  int
}

func (s ScribbleRows) Next(dst interface{}) (bool, error) {
	if s.i >= s.len {
		return false, nil
	}
	if err := json.Unmarshal([]byte(s.rows[s.i]), dst); err != nil {
		return false, err
	}
	s.i++
	return true, nil
}

func (s ScribbleRows) Close() {
	s.rows = nil
	s.i = -1
	s.len = -1
}

//Management Api
func (s ScribbleStore) CreateDatabase() error {
	return nil
}
func (s ScribbleStore) CreateTable(table string, sample interface{}) error {
	return nil
}

//Misc api
func (s ScribbleStore) GetStore() interface{} {
	return s.db
}
func (s ScribbleStore) Stats(store string) (map[string]interface{}, error) {
	return nil, nil
}

//New Api
func (s ScribbleStore) All(count int, skip int, store string) (ObjectRows, error) {
	_rows, err := s.db.ReadAll(store)
	if err != nil {
		return nil, err
	}
	return ScribbleRows{_rows, 0, len(_rows)}, nil
}
func (s ScribbleStore) AllCursor(store string) (ObjectRows, error) {
	return nil, ErrNotImplemented
}

func (s ScribbleStore) Since(id string, count int, skip int, store string) (ObjectRows, error) {
	return nil, ErrNotImplemented
}
func (s ScribbleStore) Before(id string, count int, skip int, store string) (ObjectRows, error) {
	return nil, ErrNotImplemented
}

func (s ScribbleStore) FilterSince(id string, filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (ObjectRows, error) {
	return nil, ErrNotImplemented
}
func (s ScribbleStore) FilterBefore(id string, filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (ObjectRows, error) {

	return nil, ErrNotImplemented
}
func (s ScribbleStore) FilterBeforeCount(id string, filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (int64, error) {

	return 0, ErrNotImplemented
}

func (s ScribbleStore) Get(key string, store string, dst interface{}) error {
	return s.db.Read(store, key, &dst)
}

func (s ScribbleStore) Save(store string, src interface{}) (string, error) {
	var key string
	if _v, ok := src.(map[string]interface{}); ok {
		if k, ok := _v["id"].(string); ok {
			key = k
		}
	} else {
		key = NewObjectId().String()
	}
	if err := s.db.Write(store, key, src); err != nil {
		return "", err
	}
	return key, nil
}
func (s ScribbleStore) Update(key string, store string, src interface{}) error {
	return ErrNotImplemented
}
func (s ScribbleStore) Replace(key string, store string, src interface{}) error {
	return ErrNotImplemented
}
func (s ScribbleStore) Delete(key string, store string) error {
	return s.db.Delete(store, key)
}

//Filter
func (s ScribbleStore) FilterUpdate(filter map[string]interface{}, src interface{}, store string, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterReplace(filter map[string]interface{}, src interface{}, store string, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterGet(filter map[string]interface{}, store string, dst interface{}, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterGetAll(filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (ObjectRows, error) {
	return nil, ErrNotImplemented
}
func (s ScribbleStore) FilterDelete(filter map[string]interface{}, store string, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterCount(filter map[string]interface{}, store string, opts ObjectStoreOptions) (int64, error) {
	return 0, ErrNotImplemented
}

//Misc gets
func (s ScribbleStore) GetByField(name, val, store string, dst interface{}) error {
	return ErrNotImplemented
}
func (s ScribbleStore) GetByFieldsByField(name, val, store string, fields []string, dst interface{}) (err error) {
	return ErrNotImplemented
}

func (s ScribbleStore) Close() {
}
<commit_msg>add some debug symbols<commit_after>package gostore

import (
	"encoding/json"
	"github.com/mgutz/logxi/v1"
	"github.com/nanobox-io/golang-scribble"
)

type ScribbleStore struct {
	db   *scribble.Driver
	path string
}

func NewScribbleStore(path string) *ScribbleStore {
	if db, err := scribble.New(path, nil); err == nil {
		return &ScribbleStore{db, path}
	} else {
		log.Warn("cannot create scribble database", "err", err)
	}
	return nil
}

type ScribbleRows struct {
	rows []string
	i    int
	len  int
}

func (s ScribbleRows) Next(dst interface{}) (bool, error) {
	if s.i >= s.len {
		return false, nil
	}
	if err := json.Unmarshal([]byte(s.rows[s.i]), dst); err != nil {
		return false, err
	}
	s.i++
	return true, nil
}

func (s ScribbleRows) Close() {
	s.rows = nil
	s.i = -1
	s.len = -1
}

//Management Api
func (s ScribbleStore) CreateDatabase() error {
	return nil
}
func (s ScribbleStore) CreateTable(table string, sample interface{}) error {
	return nil
}

//Misc api
func (s ScribbleStore) GetStore() interface{} {
	return s.db
}
func (s ScribbleStore) Stats(store string) (map[string]interface{}, error) {
	return nil, nil
}

//New Api
func (s ScribbleStore) All(count int, skip int, store string) (ObjectRows, error) {
	_rows, err := s.db.ReadAll(store)
	if err != nil {
		return nil, err
	}
	return ScribbleRows{_rows, 0, len(_rows)}, nil
}
func (s ScribbleStore) AllCursor(store string) (ObjectRows, error) {
	return nil, ErrNotImplemented
}

func (s ScribbleStore) Since(id string, count int, skip int, store string) (ObjectRows, error) {
	return nil, ErrNotImplemented
}
func (s ScribbleStore) Before(id string, count int, skip int, store string) (ObjectRows, error) {
	return nil, ErrNotImplemented
}

func (s ScribbleStore) FilterSince(id string, filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (ObjectRows, error) {
	return nil, ErrNotImplemented
}
func (s ScribbleStore) FilterBefore(id string, filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (ObjectRows, error) {

	return nil, ErrNotImplemented
}
func (s ScribbleStore) FilterBeforeCount(id string, filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (int64, error) {

	return 0, ErrNotImplemented
}

func (s ScribbleStore) Get(key string, store string, dst interface{}) error {
	return s.db.Read(store, key, &dst)
}

func (s ScribbleStore) Save(store string, src interface{}) (string, error) {
	var key string
	if _v, ok := src.(map[string]interface{}); ok {
		if k, ok := _v["id"].(string); ok {
			key = k
		}
	} else {
		key = NewObjectId().String()
	}
	log.Debug("saving " + key + " to " + store)
	if err := s.db.Write(store, key, src); err != nil {
		return "", err
	}
	return key, nil
}
func (s ScribbleStore) Update(key string, store string, src interface{}) error {
	return ErrNotImplemented
}
func (s ScribbleStore) Replace(key string, store string, src interface{}) error {
	return ErrNotImplemented
}
func (s ScribbleStore) Delete(key string, store string) error {
	return s.db.Delete(store, key)
}

//Filter
func (s ScribbleStore) FilterUpdate(filter map[string]interface{}, src interface{}, store string, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterReplace(filter map[string]interface{}, src interface{}, store string, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterGet(filter map[string]interface{}, store string, dst interface{}, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterGetAll(filter map[string]interface{}, count int, skip int, store string, opts ObjectStoreOptions) (ObjectRows, error) {
	return nil, ErrNotImplemented
}
func (s ScribbleStore) FilterDelete(filter map[string]interface{}, store string, opts ObjectStoreOptions) error {
	return ErrNotImplemented
}
func (s ScribbleStore) FilterCount(filter map[string]interface{}, store string, opts ObjectStoreOptions) (int64, error) {
	return 0, ErrNotImplemented
}

//Misc gets
func (s ScribbleStore) GetByField(name, val, store string, dst interface{}) error {
	return ErrNotImplemented
}
func (s ScribbleStore) GetByFieldsByField(name, val, store string, fields []string, dst interface{}) (err error) {
	return ErrNotImplemented
}

func (s ScribbleStore) Close() {
}
<|endoftext|>