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

// +build java android

package rt

import (
	"runtime"
	"unsafe"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/x/ref/lib/xrpc"
	_ "v.io/x/ref/runtime/factories/roaming"

	jns "v.io/x/jni/impl/google/namespace"
	jrpc "v.io/x/jni/impl/google/rpc"
	jutil "v.io/x/jni/util"
	jcontext "v.io/x/jni/v23/context"
	jsecurity "v.io/x/jni/v23/security"
)

// #include "jni.h"
import "C"

// Init initializes the JNI code with the given Java environment.  This method
// must be invoked before any other method in this package and must be called
// from the main Java thread (e.g., On_Load()).
// interface and then cast into the package-local environment type.
func Init(env jutil.Env) error {
	return nil
}

type shutdownKey struct{}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeInit
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeInit(jenv *C.JNIEnv, jRuntime C.jclass, jNumCpus C.jint) C.jobject {
	env := jutil.WrapEnv(jenv)
	runtime.GOMAXPROCS(int(jNumCpus))
	ctx, shutdownFunc := v23.Init()
	ctx = context.WithValue(ctx, shutdownKey{}, shutdownFunc)
	jCtx, err := jcontext.JavaContext(env, ctx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeShutdown
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeShutdown(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) {
	env := jutil.WrapEnv(jenv)
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
	}
	value := ctx.Value(shutdownKey{})
	if shutdownFunc, ok := value.(v23.Shutdown); ok {
		shutdownFunc()
	}
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNewClient
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNewClient(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jOptions C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	// No options supported yet.
	newCtx, _, err := v23.WithNewClient(ctx)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetClient
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetClient(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	client := v23.GetClient(ctx)
	jClient, err := jrpc.JavaClient(env, client)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jClient))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeNewServer
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeNewServer(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jName C.jstring, jDispatcher C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	name := jutil.GoString(env, jutil.WrapObject(jName))
	d, err := jrpc.GoDispatcher(env, jutil.WrapObject(jDispatcher))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	server, err := xrpc.NewDispatchingServer(ctx, name, d)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jServer, err := jrpc.JavaServer(env, server)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jServer))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetPrincipal
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetPrincipal(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jPrincipal C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	principal, err := jsecurity.GoPrincipal(env, jutil.WrapObject(jPrincipal))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	newCtx, err := v23.WithPrincipal(ctx, principal)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetPrincipal
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetPrincipal(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	principal := v23.GetPrincipal(ctx)
	jPrincipal, err := jsecurity.JavaPrincipal(env, principal)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jPrincipal))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNamespace
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNamespace(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jRoots C.jobjectArray) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	roots, err := jutil.GoStringArray(env, jutil.WrapObject(jRoots))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}

	newCtx, _, err := v23.WithNewNamespace(ctx, roots...)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetNamespace
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetNamespace(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	namespace := v23.GetNamespace(ctx)
	jNamespace, err := jns.JavaNamespace(env, namespace)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNamespace))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetListenSpec
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetListenSpec(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	spec := v23.GetListenSpec(ctx)
	jSpec, err := jrpc.JavaListenSpec(env, spec)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jSpec))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetListenSpec
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetListenSpec(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jSpec C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	spec, err := jrpc.GoListenSpec(env, jutil.WrapObject(jSpec))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	newCtx := v23.WithListenSpec(ctx, spec)
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}
<commit_msg>jni: Update uses of the xprc library to the new v23.WithNew*Server API.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build java android

package rt

import (
	"runtime"
	"unsafe"

	"v.io/v23"
	"v.io/v23/context"
	_ "v.io/x/ref/runtime/factories/roaming"

	jns "v.io/x/jni/impl/google/namespace"
	jrpc "v.io/x/jni/impl/google/rpc"
	jutil "v.io/x/jni/util"
	jcontext "v.io/x/jni/v23/context"
	jsecurity "v.io/x/jni/v23/security"
)

// #include "jni.h"
import "C"

// Init initializes the JNI code with the given Java environment.  This method
// must be invoked before any other method in this package and must be called
// from the main Java thread (e.g., On_Load()).
// interface and then cast into the package-local environment type.
func Init(env jutil.Env) error {
	return nil
}

type shutdownKey struct{}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeInit
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeInit(jenv *C.JNIEnv, jRuntime C.jclass, jNumCpus C.jint) C.jobject {
	env := jutil.WrapEnv(jenv)
	runtime.GOMAXPROCS(int(jNumCpus))
	ctx, shutdownFunc := v23.Init()
	ctx = context.WithValue(ctx, shutdownKey{}, shutdownFunc)
	jCtx, err := jcontext.JavaContext(env, ctx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeShutdown
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeShutdown(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) {
	env := jutil.WrapEnv(jenv)
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
	}
	value := ctx.Value(shutdownKey{})
	if shutdownFunc, ok := value.(v23.Shutdown); ok {
		shutdownFunc()
	}
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNewClient
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNewClient(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jOptions C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	// No options supported yet.
	newCtx, _, err := v23.WithNewClient(ctx)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetClient
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetClient(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	client := v23.GetClient(ctx)
	jClient, err := jrpc.JavaClient(env, client)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jClient))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeNewServer
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeNewServer(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jName C.jstring, jDispatcher C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	name := jutil.GoString(env, jutil.WrapObject(jName))
	d, err := jrpc.GoDispatcher(env, jutil.WrapObject(jDispatcher))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	// TODO(mattr): This should be returning the new context returned here.
	_, server, err := v23.WithNewDispatchingServer(ctx, name, d)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jServer, err := jrpc.JavaServer(env, server)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jServer))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetPrincipal
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetPrincipal(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jPrincipal C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	principal, err := jsecurity.GoPrincipal(env, jutil.WrapObject(jPrincipal))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	newCtx, err := v23.WithPrincipal(ctx, principal)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetPrincipal
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetPrincipal(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	principal := v23.GetPrincipal(ctx)
	jPrincipal, err := jsecurity.JavaPrincipal(env, principal)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jPrincipal))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNamespace
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetNamespace(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jRoots C.jobjectArray) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	roots, err := jutil.GoStringArray(env, jutil.WrapObject(jRoots))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}

	newCtx, _, err := v23.WithNewNamespace(ctx, roots...)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetNamespace
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetNamespace(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	// TODO(spetrovic): Have Java context support nativePtr()?
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	namespace := v23.GetNamespace(ctx)
	jNamespace, err := jns.JavaNamespace(env, namespace)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNamespace))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetListenSpec
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeGetListenSpec(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	spec := v23.GetListenSpec(ctx)
	jSpec, err := jrpc.JavaListenSpec(env, spec)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jSpec))
}

//export Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetListenSpec
func Java_io_v_impl_google_rt_VRuntimeImpl_nativeSetListenSpec(jenv *C.JNIEnv, jRuntime C.jclass, jContext C.jobject, jSpec C.jobject) C.jobject {
	env := jutil.WrapEnv(jenv)
	ctx, err := jcontext.GoContext(env, jutil.WrapObject(jContext))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	spec, err := jrpc.GoListenSpec(env, jutil.WrapObject(jSpec))
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	newCtx := v23.WithListenSpec(ctx, spec)
	jNewCtx, err := jcontext.JavaContext(env, newCtx, nil)
	if err != nil {
		jutil.JThrowV(env, err)
		return nil
	}
	return C.jobject(unsafe.Pointer(jNewCtx))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"os"
	"path"
	"path/filepath"
)

var _ = Describe("Storage", func() {

	root := path.Join(os.TempDir(), "StorageTest")
	separateGitDir := path.Join(os.TempDir(), "StorageTestGitDir")
	folders := []string{
		path.Join(root, "folder1"),
		path.Join(root, "folder2"),
		path.Join(root, "folder3"),
		path.Join(root, "folder1/sub1"),
		path.Join(root, "folder1/sub2"),
		path.Join(root, "folder1/sub1/subsub1"),
		path.Join(root, "folder1/a/b/c/d/e/f/g/h/i/j/k/l")}

	Describe("Identifying git repo root", func() {
		Context("Valid git repo", func() {

			BeforeEach(func() {
				// Set up git repo with some subfolders
				CreateGitRepoForTest(root)

				for _, f := range folders {
					err := os.MkdirAll(f, 0777)
					if err != nil {
						fmt.Printf("Can't MkdirAll %v: %v", f, err)
					}
				}

			})

			AfterEach(func() {
				// Delete repo
				os.RemoveAll(root)
			})

			It("finds root git folder", func() {

				// Need to expand root for symlinks here in order to guarantee string comparison works
				// /var turns into /private/var on OS X for example
				// Can't use this for creating repos etc though, OS X doesn't like direct access
				expandedroot, _ := filepath.EvalSymlinks(root)

				for _, f := range folders {
					err := os.Chdir(f)
					if err != nil {
						Fail(fmt.Sprintf("Can't chdir to %v: %v", f, err))
					}
					testroot, sep := GetRepoRoot()
					Expect(testroot).To(Equal(expandedroot))
					Expect(sep).To(Equal(false))
				}
			})
		})
		Context("Invalid git repo", func() {
			It("Fails safely outside a git repo", func() {
				// Relies on temp dir not being a git repo, which should be valid assumption
				os.Chdir(os.TempDir())
				testroot, _ := GetRepoRoot()
				Expect(testroot).To(Equal(""))
			})

		})

	})

	Describe("Finding git dir", func() {
		Context("Git repo with standard git dir", func() {
			BeforeEach(func() {
				// Set up git repo with some subfolders
				CreateGitRepoForTest(root)

				for _, f := range folders {
					err := os.MkdirAll(f, 0777)
					if err != nil {
						fmt.Printf("Can't MkdirAll %v: %v", f, err)
					}
				}

			})

			AfterEach(func() {
				// Delete repo
				os.RemoveAll(root)
			})

			It("finds git dir", func() {

				// Need to expand root for symlinks here in order to guarantee string comparison works
				// /var turns into /private/var on OS X for example
				// Can't use this for creating repos etc though, OS X doesn't like direct access
				gitdir, _ := filepath.EvalSymlinks(path.Join(root, ".git"))

				for _, f := range folders {
					err := os.Chdir(f)
					if err != nil {
						Fail(fmt.Sprintf("Can't chdir to %v: %v", f, err))
					}
					testgitdir := GetGitDir()
					Expect(testgitdir).To(Equal(gitdir))
				}
			})

		})

		Context("Git repo with separate git dir", func() {
			BeforeEach(func() {
				// Set up git repo with some subfolders
				CreateGitRepoWithSeparateGitDirForTest(root, separateGitDir)

				for _, f := range folders {
					err := os.MkdirAll(f, 0777)
					if err != nil {
						fmt.Printf("Can't MkdirAll %v: %v", f, err)
					}
				}

			})

			AfterEach(func() {
				// Delete repo
				os.RemoveAll(root)
			})

			It("finds git dir", func() {

				// Need to expand root for symlinks here in order to guarantee string comparison works
				// /var turns into /private/var on OS X for example
				// Can't use this for creating repos etc though, OS X doesn't like direct access
				gitdir, _ := filepath.EvalSymlinks(separateGitDir)

				for _, f := range folders {
					err := os.Chdir(f)
					if err != nil {
						Fail(fmt.Sprintf("Can't chdir to %v: %v", f, err))
					}
					testgitdir := GetGitDir()
					Expect(testgitdir).To(Equal(gitdir))
				}
			})

		})
	})

})
<commit_msg>StoreLOB test<commit_after>package main

import (
	"bytes"
	"fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"os"
	"path"
	"path/filepath"
)

var _ = Describe("Storage", func() {

	root := path.Join(os.TempDir(), "StorageTest")
	separateGitDir := path.Join(os.TempDir(), "StorageTestGitDir")
	folders := []string{
		path.Join(root, "folder1"),
		path.Join(root, "folder2"),
		path.Join(root, "folder3"),
		path.Join(root, "folder1/sub1"),
		path.Join(root, "folder1/sub2"),
		path.Join(root, "folder1/sub1/subsub1"),
		path.Join(root, "folder1/a/b/c/d/e/f/g/h/i/j/k/l")}

	Describe("Identifying git repo root", func() {
		Context("Valid git repo", func() {

			BeforeEach(func() {
				// Set up git repo with some subfolders
				CreateGitRepoForTest(root)

				for _, f := range folders {
					err := os.MkdirAll(f, 0777)
					if err != nil {
						fmt.Printf("Can't MkdirAll %v: %v", f, err)
					}
				}

			})

			AfterEach(func() {
				// Delete repo
				os.RemoveAll(root)
			})

			It("finds root git folder", func() {

				// Need to expand root for symlinks here in order to guarantee string comparison works
				// /var turns into /private/var on OS X for example
				// Can't use this for creating repos etc though, OS X doesn't like direct access
				expandedroot, _ := filepath.EvalSymlinks(root)

				for _, f := range folders {
					err := os.Chdir(f)
					if err != nil {
						Fail(fmt.Sprintf("Can't chdir to %v: %v", f, err))
					}
					testroot, sep := GetRepoRoot()
					Expect(testroot).To(Equal(expandedroot))
					Expect(sep).To(Equal(false))
				}
			})
		})
		Context("Invalid git repo", func() {
			It("Fails safely outside a git repo", func() {
				// Relies on temp dir not being a git repo, which should be valid assumption
				os.Chdir(os.TempDir())
				testroot, _ := GetRepoRoot()
				Expect(testroot).To(Equal(""))
			})

		})

	})

	Describe("Finding git dir", func() {
		Context("Git repo with standard git dir", func() {
			BeforeEach(func() {
				// Set up git repo with some subfolders
				CreateGitRepoForTest(root)

				for _, f := range folders {
					err := os.MkdirAll(f, 0777)
					if err != nil {
						fmt.Printf("Can't MkdirAll %v: %v", f, err)
					}
				}

			})

			AfterEach(func() {
				// Delete repo
				os.RemoveAll(root)
			})

			It("finds git dir", func() {

				// Need to expand root for symlinks here in order to guarantee string comparison works
				// /var turns into /private/var on OS X for example
				// Can't use this for creating repos etc though, OS X doesn't like direct access
				gitdir, _ := filepath.EvalSymlinks(path.Join(root, ".git"))

				for _, f := range folders {
					err := os.Chdir(f)
					if err != nil {
						Fail(fmt.Sprintf("Can't chdir to %v: %v", f, err))
					}
					testgitdir := GetGitDir()
					Expect(testgitdir).To(Equal(gitdir))
				}
			})

		})

		Context("Git repo with separate git dir", func() {
			BeforeEach(func() {
				// Set up git repo with some subfolders
				CreateGitRepoWithSeparateGitDirForTest(root, separateGitDir)

				for _, f := range folders {
					err := os.MkdirAll(f, 0777)
					if err != nil {
						fmt.Printf("Can't MkdirAll %v: %v", f, err)
					}
				}

			})

			AfterEach(func() {
				// Delete repo
				os.RemoveAll(root)
			})

			It("finds git dir", func() {

				// Need to expand root for symlinks here in order to guarantee string comparison works
				// /var turns into /private/var on OS X for example
				// Can't use this for creating repos etc though, OS X doesn't like direct access
				gitdir, _ := filepath.EvalSymlinks(separateGitDir)

				for _, f := range folders {
					err := os.Chdir(f)
					if err != nil {
						Fail(fmt.Sprintf("Can't chdir to %v: %v", f, err))
					}
					testgitdir := GetGitDir()
					Expect(testgitdir).To(Equal(gitdir))
				}
			})

		})
	})

	Describe("Storing a LOB", func() {
		// Common git repo
		BeforeEach(func() {
			// Set up git repo with some subfolders
			CreateGitRepoForTest(root)

			for _, f := range folders {
				err := os.MkdirAll(f, 0777)
				if err != nil {
					fmt.Printf("Can't MkdirAll %v: %v", f, err)
				}
			}

		})

		AfterEach(func() {
			// Delete repo
			os.RemoveAll(root)
		})

		Context("Small single chunk LOB", func() {
			testFileName := path.Join(folders[2], "small.dat")
			// This was calculated with 'shasum' on Mac OS X with this file content
			correctLOBInfo := LOBInfo{SHA: "772157c6ef480852edf921f5924b1ca582b0d78f", NumChunks: 1, Size: 128 * 255 * 16}

			BeforeEach(func() {
				// Create binary file
				f, err := os.OpenFile(testFileName, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0777)
				if err != nil {
					Fail(fmt.Sprintf("Can't create test file %v: %v", testFileName, err))
				}
				for i := 0; i < 128; i++ {
					var j byte
					for j = 0; j < 255; j++ {
						f.Write(bytes.Repeat([]byte{j}, 16))
					}
				}
				f.Close()
			})
			AfterEach(func() {
				os.Remove(testFileName)
			})

			It("correctly stores a small file", func() {
				f, err := os.Open(testFileName)
				if err != nil {
					Fail(fmt.Sprintf("Can't reopen test file %v: %v", testFileName, err))
				}
				// Need to read leader for consistency with real usage
				leader := make([]byte, SHALineLen)
				c, err := f.Read(leader)
				if err != nil {
					Fail(fmt.Sprintf("Can't read leader of test file %v: %v", testFileName, err))
				}
				lobinfo, err := StoreLOB(f, leader[:c])
				Expect(err).To(BeNil())
				Expect(lobinfo).To(Equal(correctLOBInfo))

			})

		})

	})

})
<|endoftext|>


<commit_before>package spvwallet

import (
	"errors"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/peer"
	"github.com/btcsuite/btcd/txscript"
	btc "github.com/btcsuite/btcutil"
	hd "github.com/btcsuite/btcutil/hdkeychain"
	"github.com/btcsuite/btcwallet/wallet/txrules"
	"github.com/op/go-logging"
	b39 "github.com/tyler-smith/go-bip39"
	"io"
	"os"
	"path"
	"sync"
	"time"
)

type SPVWallet struct {
	params *chaincfg.Params

	masterPrivateKey *hd.ExtendedKey
	masterPublicKey  *hd.ExtendedKey

	mnemonic string

	feeProvider *FeeProvider

	repoPath string

	blockchain  *Blockchain
	txstore     *TxStore
	peerManager *PeerManager
	keyManager  *KeyManager

	fPositives    chan *peer.Peer
	stopChan      chan int
	fpAccumulator map[int32]int32
	blockQueue    chan chainhash.Hash
	mutex         *sync.RWMutex

	creationDate time.Time

	running bool

	config *PeerManagerConfig
}

var log = logging.MustGetLogger("bitcoin")

const WALLET_VERSION = "0.2.0"

func NewSPVWallet(config *Config) (*SPVWallet, error) {

	log.SetBackend(logging.AddModuleLevel(config.Logger))

	if config.Mnemonic == "" {
		ent, err := b39.NewEntropy(128)
		if err != nil {
			return nil, err
		}
		mnemonic, err := b39.NewMnemonic(ent)
		if err != nil {
			return nil, err
		}
		config.Mnemonic = mnemonic
		config.CreationDate = time.Now()
	}
	seed := b39.NewSeed(config.Mnemonic, "")

	mPrivKey, err := hd.NewMaster(seed, config.Params)
	if err != nil {
		return nil, err
	}
	mPubKey, err := mPrivKey.Neuter()
	if err != nil {
		return nil, err
	}
	w := &SPVWallet{
		repoPath:         config.RepoPath,
		masterPrivateKey: mPrivKey,
		masterPublicKey:  mPubKey,
		mnemonic:         config.Mnemonic,
		params:           config.Params,
		creationDate:     config.CreationDate,
		feeProvider: NewFeeProvider(
			config.MaxFee,
			config.HighFee,
			config.MediumFee,
			config.LowFee,
			config.FeeAPI.String(),
			config.Proxy,
		),
		fPositives:    make(chan *peer.Peer),
		stopChan:      make(chan int),
		fpAccumulator: make(map[int32]int32),
		blockQueue:    make(chan chainhash.Hash, 32),
		mutex:         new(sync.RWMutex),
	}

	w.keyManager, err = NewKeyManager(config.DB.Keys(), w.params, w.masterPrivateKey)

	w.txstore, err = NewTxStore(w.params, config.DB, w.keyManager)
	if err != nil {
		return nil, err
	}

	w.blockchain, err = NewBlockchain(w.repoPath, w.creationDate, w.params)
	if err != nil {
		return nil, err
	}

	listeners := &peer.MessageListeners{
		OnMerkleBlock: w.onMerkleBlock,
		OnInv:         w.onInv,
		OnTx:          w.onTx,
		OnGetData:     w.onGetData,
	}

	getNewestBlock := func() (*chainhash.Hash, int32, error) {
		storedHeader, err := w.blockchain.db.GetBestHeader()
		if err != nil {
			return nil, 0, err
		}
		height, err := w.blockchain.db.Height()
		if err != nil {
			return nil, 0, err
		}
		hash := storedHeader.header.BlockHash()
		return &hash, int32(height), nil
	}

	w.config = &PeerManagerConfig{
		UserAgentName:      config.UserAgent,
		UserAgentVersion:   WALLET_VERSION,
		Params:             w.params,
		AddressCacheDir:    config.RepoPath,
		GetFilter:          w.txstore.GimmeFilter,
		StartChainDownload: w.startChainDownload,
		GetNewestBlock:     getNewestBlock,
		Listeners:          listeners,
		Proxy:              config.Proxy,
	}

	if config.TrustedPeer != nil {
		w.config.TrustedPeer = config.TrustedPeer
	}

	w.peerManager, err = NewPeerManager(w.config)
	if err != nil {
		return nil, err
	}

	return w, nil
}

func (w *SPVWallet) Start() {
	w.running = true
	go w.peerManager.Start()
	w.fPositiveHandler(w.stopChan)
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// API
//
//////////////

func (w *SPVWallet) CurrencyCode() string {
	if w.params.Name == chaincfg.MainNetParams.Name {
		return "btc"
	} else {
		return "tbtc"
	}
}

func (w *SPVWallet) IsDust(amount int64) bool {
	return txrules.IsDustAmount(btc.Amount(amount), 25, txrules.DefaultRelayFeePerKb)
}

func (w *SPVWallet) MasterPrivateKey() *hd.ExtendedKey {
	return w.masterPrivateKey
}

func (w *SPVWallet) MasterPublicKey() *hd.ExtendedKey {
	return w.masterPublicKey
}

func (w *SPVWallet) Mnemonic() string {
	return w.mnemonic
}

func (w *SPVWallet) CreationDate() time.Time {
	return w.creationDate
}

func (w *SPVWallet) ConnectedPeers() []*peer.Peer {
	return w.peerManager.ConnectedPeers()
}

func (w *SPVWallet) CurrentAddress(purpose KeyPurpose) btc.Address {
	key, _ := w.keyManager.GetCurrentKey(purpose)
	addr, _ := key.Address(w.params)
	return btc.Address(addr)
}

func (w *SPVWallet) NewAddress(purpose KeyPurpose) btc.Address {
	i, _ := w.txstore.Keys().GetUnused(purpose)
	key, _ := w.keyManager.generateChildKey(purpose, uint32(i[1]))
	addr, _ := key.Address(w.params)
	w.txstore.Keys().MarkKeyAsUsed(addr.ScriptAddress())
	w.txstore.PopulateAdrs()
	return btc.Address(addr)
}

func (w *SPVWallet) DecodeAddress(addr string) (btc.Address, error) {
	return btc.DecodeAddress(addr, w.params)
}

func (w *SPVWallet) ScriptToAddress(script []byte) (btc.Address, error) {
	_, addrs, _, err := txscript.ExtractPkScriptAddrs(script, w.params)
	if err != nil {
		return nil, err
	}
	if len(addrs) == 0 {
		return nil, errors.New("unknown script")
	}
	return addrs[0], nil
}

func (w *SPVWallet) AddressToScript(addr btc.Address) ([]byte, error) {
	return txscript.PayToAddrScript(addr)
}

func (w *SPVWallet) HasKey(addr btc.Address) bool {
	_, err := w.keyManager.GetKeyForScript(addr.ScriptAddress())
	if err != nil {
		return false
	}
	return true
}

func (w *SPVWallet) ImportKey(privKey *btcec.PrivateKey, compress bool) error {
	pub := privKey.PubKey()
	var pubKeyBytes []byte
	if compress {
		pubKeyBytes = pub.SerializeCompressed()
	} else {
		pubKeyBytes = pub.SerializeUncompressed()
	}
	pkHash := btc.Hash160(pubKeyBytes)
	addr, err := btc.NewAddressPubKeyHash(pkHash, w.params)
	if err != nil {
		return err
	}
	return w.keyManager.datastore.ImportKey(addr.ScriptAddress(), privKey)
}

func (w *SPVWallet) GetKey(addr btc.Address) (*btcec.PrivateKey, error) {
	key, err := w.keyManager.GetKeyForScript(addr.ScriptAddress())
	if err != nil {
		return nil, err
	}
	return key.ECPrivKey()
}

func (w *SPVWallet) ListAddresses() []btc.Address {
	keys := w.keyManager.GetKeys()
	addrs := []btc.Address{}
	for _, k := range keys {
		addr, err := k.Address(w.params)
		if err != nil {
			continue
		}
		addrs = append(addrs, addr)
	}
	return addrs
}

func (w *SPVWallet) ListKeys() []btcec.PrivateKey {
	keys := w.keyManager.GetKeys()
	list := []btcec.PrivateKey{}
	for _, k := range keys {
		priv, err := k.ECPrivKey()
		if err != nil {
			continue
		}
		list = append(list, *priv)
	}
	return list
}

func (w *SPVWallet) Balance() (confirmed, unconfirmed int64) {
	utxos, _ := w.txstore.Utxos().GetAll()
	stxos, _ := w.txstore.Stxos().GetAll()
	for _, utxo := range utxos {
		if !utxo.WatchOnly {
			if utxo.AtHeight > 0 {
				confirmed += utxo.Value
			} else {
				if w.checkIfStxoIsConfirmed(utxo, stxos) {
					confirmed += utxo.Value
				} else {
					unconfirmed += utxo.Value
				}
			}
		}
	}
	return confirmed, unconfirmed
}

func (w *SPVWallet) Transactions() ([]Txn, error) {
	return w.txstore.Txns().GetAll(false)
}

func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (Txn, error) {
	_, txn, err := w.txstore.Txns().Get(txid)
	return txn, err
}

func (w *SPVWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) {
	_, txn, err := w.txstore.Txns().Get(txid)
	if err != nil {
		return 0, 0, err
	}
	if txn.Height == 0 {
		return 0, 0, nil
	}
	chainTip, _ := w.ChainTip()
	return chainTip - uint32(txn.Height) + 1, uint32(txn.Height), nil
}

func (w *SPVWallet) checkIfStxoIsConfirmed(utxo Utxo, stxos []Stxo) bool {
	for _, stxo := range stxos {
		if stxo.SpendTxid.IsEqual(&utxo.Op.Hash) {
			if stxo.SpendHeight > 0 {
				return true
			} else {
				return w.checkIfStxoIsConfirmed(stxo.Utxo, stxos)
			}
		} else if stxo.Utxo.IsEqual(&utxo) {
			if stxo.Utxo.AtHeight > 0 {
				return true
			} else {
				return false
			}
		}
	}
	return false
}

func (w *SPVWallet) Params() *chaincfg.Params {
	return w.params
}

func (w *SPVWallet) AddTransactionListener(callback func(TransactionCallback)) {
	w.txstore.listeners = append(w.txstore.listeners, callback)
}

func (w *SPVWallet) ChainTip() (uint32, chainhash.Hash) {
	var ch chainhash.Hash
	sh, err := w.blockchain.db.GetBestHeader()
	if err != nil {
		return 0, ch
	}
	return sh.height, sh.header.BlockHash()
}

func (w *SPVWallet) AddWatchedScript(script []byte) error {
	err := w.txstore.WatchedScripts().Put(script)
	w.txstore.PopulateAdrs()

	for _, peer := range w.peerManager.ConnectedPeers() {
		w.updateFilterAndSend(peer)
	}
	return err
}

func (w *SPVWallet) DumpHeaders(writer io.Writer) {
	w.blockchain.db.Print(writer)
}

func (w *SPVWallet) Close() {
	if w.running {
		log.Info("Disconnecting from peers and shutting down")
		w.peerManager.Stop()
		w.blockchain.Close()
		w.stopChan <- 1
		w.running = false
	}
}

func (w *SPVWallet) ReSyncBlockchain(fromDate time.Time) {
	w.Close()
	os.Remove(path.Join(w.repoPath, "headers.bin"))
	blockchain, err := NewBlockchain(w.repoPath, fromDate, w.params)
	if err != nil {
		return
	}
	w.blockchain = blockchain
	w.txstore.PopulateAdrs()
	w.peerManager, err = NewPeerManager(w.config)
	if err != nil {
		return
	}
	w.blockQueue = make(chan chainhash.Hash, 32)
	go w.Start()
}
<commit_msg>Fix bug calculating balance<commit_after>package spvwallet

import (
	"errors"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/peer"
	"github.com/btcsuite/btcd/txscript"
	btc "github.com/btcsuite/btcutil"
	hd "github.com/btcsuite/btcutil/hdkeychain"
	"github.com/btcsuite/btcwallet/wallet/txrules"
	"github.com/op/go-logging"
	b39 "github.com/tyler-smith/go-bip39"
	"io"
	"os"
	"path"
	"sync"
	"time"
)

type SPVWallet struct {
	params *chaincfg.Params

	masterPrivateKey *hd.ExtendedKey
	masterPublicKey  *hd.ExtendedKey

	mnemonic string

	feeProvider *FeeProvider

	repoPath string

	blockchain  *Blockchain
	txstore     *TxStore
	peerManager *PeerManager
	keyManager  *KeyManager

	fPositives    chan *peer.Peer
	stopChan      chan int
	fpAccumulator map[int32]int32
	blockQueue    chan chainhash.Hash
	mutex         *sync.RWMutex

	creationDate time.Time

	running bool

	config *PeerManagerConfig
}

var log = logging.MustGetLogger("bitcoin")

const WALLET_VERSION = "0.2.0"

func NewSPVWallet(config *Config) (*SPVWallet, error) {

	log.SetBackend(logging.AddModuleLevel(config.Logger))

	if config.Mnemonic == "" {
		ent, err := b39.NewEntropy(128)
		if err != nil {
			return nil, err
		}
		mnemonic, err := b39.NewMnemonic(ent)
		if err != nil {
			return nil, err
		}
		config.Mnemonic = mnemonic
		config.CreationDate = time.Now()
	}
	seed := b39.NewSeed(config.Mnemonic, "")

	mPrivKey, err := hd.NewMaster(seed, config.Params)
	if err != nil {
		return nil, err
	}
	mPubKey, err := mPrivKey.Neuter()
	if err != nil {
		return nil, err
	}
	w := &SPVWallet{
		repoPath:         config.RepoPath,
		masterPrivateKey: mPrivKey,
		masterPublicKey:  mPubKey,
		mnemonic:         config.Mnemonic,
		params:           config.Params,
		creationDate:     config.CreationDate,
		feeProvider: NewFeeProvider(
			config.MaxFee,
			config.HighFee,
			config.MediumFee,
			config.LowFee,
			config.FeeAPI.String(),
			config.Proxy,
		),
		fPositives:    make(chan *peer.Peer),
		stopChan:      make(chan int),
		fpAccumulator: make(map[int32]int32),
		blockQueue:    make(chan chainhash.Hash, 32),
		mutex:         new(sync.RWMutex),
	}

	w.keyManager, err = NewKeyManager(config.DB.Keys(), w.params, w.masterPrivateKey)

	w.txstore, err = NewTxStore(w.params, config.DB, w.keyManager)
	if err != nil {
		return nil, err
	}

	w.blockchain, err = NewBlockchain(w.repoPath, w.creationDate, w.params)
	if err != nil {
		return nil, err
	}

	listeners := &peer.MessageListeners{
		OnMerkleBlock: w.onMerkleBlock,
		OnInv:         w.onInv,
		OnTx:          w.onTx,
		OnGetData:     w.onGetData,
	}

	getNewestBlock := func() (*chainhash.Hash, int32, error) {
		storedHeader, err := w.blockchain.db.GetBestHeader()
		if err != nil {
			return nil, 0, err
		}
		height, err := w.blockchain.db.Height()
		if err != nil {
			return nil, 0, err
		}
		hash := storedHeader.header.BlockHash()
		return &hash, int32(height), nil
	}

	w.config = &PeerManagerConfig{
		UserAgentName:      config.UserAgent,
		UserAgentVersion:   WALLET_VERSION,
		Params:             w.params,
		AddressCacheDir:    config.RepoPath,
		GetFilter:          w.txstore.GimmeFilter,
		StartChainDownload: w.startChainDownload,
		GetNewestBlock:     getNewestBlock,
		Listeners:          listeners,
		Proxy:              config.Proxy,
	}

	if config.TrustedPeer != nil {
		w.config.TrustedPeer = config.TrustedPeer
	}

	w.peerManager, err = NewPeerManager(w.config)
	if err != nil {
		return nil, err
	}

	return w, nil
}

func (w *SPVWallet) Start() {
	w.running = true
	go w.peerManager.Start()
	w.fPositiveHandler(w.stopChan)
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// API
//
//////////////

func (w *SPVWallet) CurrencyCode() string {
	if w.params.Name == chaincfg.MainNetParams.Name {
		return "btc"
	} else {
		return "tbtc"
	}
}

func (w *SPVWallet) IsDust(amount int64) bool {
	return txrules.IsDustAmount(btc.Amount(amount), 25, txrules.DefaultRelayFeePerKb)
}

func (w *SPVWallet) MasterPrivateKey() *hd.ExtendedKey {
	return w.masterPrivateKey
}

func (w *SPVWallet) MasterPublicKey() *hd.ExtendedKey {
	return w.masterPublicKey
}

func (w *SPVWallet) Mnemonic() string {
	return w.mnemonic
}

func (w *SPVWallet) CreationDate() time.Time {
	return w.creationDate
}

func (w *SPVWallet) ConnectedPeers() []*peer.Peer {
	return w.peerManager.ConnectedPeers()
}

func (w *SPVWallet) CurrentAddress(purpose KeyPurpose) btc.Address {
	key, _ := w.keyManager.GetCurrentKey(purpose)
	addr, _ := key.Address(w.params)
	return btc.Address(addr)
}

func (w *SPVWallet) NewAddress(purpose KeyPurpose) btc.Address {
	i, _ := w.txstore.Keys().GetUnused(purpose)
	key, _ := w.keyManager.generateChildKey(purpose, uint32(i[1]))
	addr, _ := key.Address(w.params)
	w.txstore.Keys().MarkKeyAsUsed(addr.ScriptAddress())
	w.txstore.PopulateAdrs()
	return btc.Address(addr)
}

func (w *SPVWallet) DecodeAddress(addr string) (btc.Address, error) {
	return btc.DecodeAddress(addr, w.params)
}

func (w *SPVWallet) ScriptToAddress(script []byte) (btc.Address, error) {
	_, addrs, _, err := txscript.ExtractPkScriptAddrs(script, w.params)
	if err != nil {
		return nil, err
	}
	if len(addrs) == 0 {
		return nil, errors.New("unknown script")
	}
	return addrs[0], nil
}

func (w *SPVWallet) AddressToScript(addr btc.Address) ([]byte, error) {
	return txscript.PayToAddrScript(addr)
}

func (w *SPVWallet) HasKey(addr btc.Address) bool {
	_, err := w.keyManager.GetKeyForScript(addr.ScriptAddress())
	if err != nil {
		return false
	}
	return true
}

func (w *SPVWallet) ImportKey(privKey *btcec.PrivateKey, compress bool) error {
	pub := privKey.PubKey()
	var pubKeyBytes []byte
	if compress {
		pubKeyBytes = pub.SerializeCompressed()
	} else {
		pubKeyBytes = pub.SerializeUncompressed()
	}
	pkHash := btc.Hash160(pubKeyBytes)
	addr, err := btc.NewAddressPubKeyHash(pkHash, w.params)
	if err != nil {
		return err
	}
	return w.keyManager.datastore.ImportKey(addr.ScriptAddress(), privKey)
}

func (w *SPVWallet) GetKey(addr btc.Address) (*btcec.PrivateKey, error) {
	key, err := w.keyManager.GetKeyForScript(addr.ScriptAddress())
	if err != nil {
		return nil, err
	}
	return key.ECPrivKey()
}

func (w *SPVWallet) ListAddresses() []btc.Address {
	keys := w.keyManager.GetKeys()
	addrs := []btc.Address{}
	for _, k := range keys {
		addr, err := k.Address(w.params)
		if err != nil {
			continue
		}
		addrs = append(addrs, addr)
	}
	return addrs
}

func (w *SPVWallet) ListKeys() []btcec.PrivateKey {
	keys := w.keyManager.GetKeys()
	list := []btcec.PrivateKey{}
	for _, k := range keys {
		priv, err := k.ECPrivKey()
		if err != nil {
			continue
		}
		list = append(list, *priv)
	}
	return list
}

func (w *SPVWallet) Balance() (confirmed, unconfirmed int64) {
	utxos, _ := w.txstore.Utxos().GetAll()
	stxos, _ := w.txstore.Stxos().GetAll()
	for _, utxo := range utxos {
		if !utxo.WatchOnly {
			if utxo.AtHeight > 0 {
				confirmed += utxo.Value
			} else {
				if w.checkIfStxoIsConfirmed(utxo, stxos) {
					confirmed += utxo.Value
				} else {
					unconfirmed += utxo.Value
				}
			}
		}
	}
	return confirmed, unconfirmed
}

func (w *SPVWallet) Transactions() ([]Txn, error) {
	return w.txstore.Txns().GetAll(false)
}

func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (Txn, error) {
	_, txn, err := w.txstore.Txns().Get(txid)
	return txn, err
}

func (w *SPVWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) {
	_, txn, err := w.txstore.Txns().Get(txid)
	if err != nil {
		return 0, 0, err
	}
	if txn.Height == 0 {
		return 0, 0, nil
	}
	chainTip, _ := w.ChainTip()
	return chainTip - uint32(txn.Height) + 1, uint32(txn.Height), nil
}

func (w *SPVWallet) checkIfStxoIsConfirmed(utxo Utxo, stxos []Stxo) bool {
	for _, stxo := range stxos {
		if !stxo.Utxo.WatchOnly {
			if stxo.SpendTxid.IsEqual(&utxo.Op.Hash) {
				if stxo.SpendHeight > 0 {
					return true
				} else {
					return w.checkIfStxoIsConfirmed(stxo.Utxo, stxos)
				}
			} else if stxo.Utxo.IsEqual(&utxo) {
				if stxo.Utxo.AtHeight > 0 {
					return true
				} else {
					return false
				}
			}
		}
	}
	return false
}

func (w *SPVWallet) Params() *chaincfg.Params {
	return w.params
}

func (w *SPVWallet) AddTransactionListener(callback func(TransactionCallback)) {
	w.txstore.listeners = append(w.txstore.listeners, callback)
}

func (w *SPVWallet) ChainTip() (uint32, chainhash.Hash) {
	var ch chainhash.Hash
	sh, err := w.blockchain.db.GetBestHeader()
	if err != nil {
		return 0, ch
	}
	return sh.height, sh.header.BlockHash()
}

func (w *SPVWallet) AddWatchedScript(script []byte) error {
	err := w.txstore.WatchedScripts().Put(script)
	w.txstore.PopulateAdrs()

	for _, peer := range w.peerManager.ConnectedPeers() {
		w.updateFilterAndSend(peer)
	}
	return err
}

func (w *SPVWallet) DumpHeaders(writer io.Writer) {
	w.blockchain.db.Print(writer)
}

func (w *SPVWallet) Close() {
	if w.running {
		log.Info("Disconnecting from peers and shutting down")
		w.peerManager.Stop()
		w.blockchain.Close()
		w.stopChan <- 1
		w.running = false
	}
}

func (w *SPVWallet) ReSyncBlockchain(fromDate time.Time) {
	w.Close()
	os.Remove(path.Join(w.repoPath, "headers.bin"))
	blockchain, err := NewBlockchain(w.repoPath, fromDate, w.params)
	if err != nil {
		return
	}
	w.blockchain = blockchain
	w.txstore.PopulateAdrs()
	w.peerManager, err = NewPeerManager(w.config)
	if err != nil {
		return
	}
	w.blockQueue = make(chan chainhash.Hash, 32)
	go w.Start()
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package k6

import (
	"context"
	"sync/atomic"
	"time"

	"github.com/dop251/goja"
	"github.com/loadimpact/k6/js/common"
	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/stats"
	"github.com/pkg/errors"
)

type K6 struct{}

func (*K6) Fail(msg string) (goja.Value, error) {
	return goja.Undefined(), errors.New(msg)
}

func (*K6) Sleep(ctx context.Context, secs float64) {
	timer := time.NewTimer(time.Duration(secs * float64(time.Second)))
	select {
	case <-timer.C:
	case <-ctx.Done():
		timer.Stop()
	}
}

func (*K6) Group(ctx context.Context, name string, fn goja.Callable) (goja.Value, error) {
	state := common.GetState(ctx)

	g, err := state.Group.Group(name)
	if err != nil {
		return goja.Undefined(), err
	}

	old := state.Group
	state.Group = g
	defer func() { state.Group = old }()

	return fn(goja.Undefined())
}

func (*K6) Check(ctx context.Context, arg0, checks goja.Value, extras ...goja.Value) (bool, error) {
	state := common.GetState(ctx)
	rt := common.GetRuntime(ctx)
	t := time.Now()

	// Prepare tags, make sure the `group` tag can't be overwritten.
	tags := make(map[string]string)
	if len(extras) > 0 {
		obj := extras[0].ToObject(rt)
		for _, k := range obj.Keys() {
			tags[k] = obj.Get(k).String()
		}
	}
	tags["group"] = state.Group.Path

	succ := true
	obj := checks.ToObject(rt)
	for _, name := range obj.Keys() {
		val := obj.Get(name)

		// Resolve the check record.
		check, err := state.Group.Check(name)
		if err != nil {
			return false, err
		}
		tags["check"] = check.Name

		// Resolve callables into values.
		fn, ok := goja.AssertFunction(val)
		if ok {
			val_, err := fn(goja.Undefined(), arg0)
			if err != nil {
				return false, err
			}
			val = val_
		}

		// Emit!
		if val.ToBoolean() {
			atomic.AddInt64(&check.Passes, 1)
			state.Samples = append(state.Samples,
				stats.Sample{Time: t, Metric: metrics.Checks, Tags: tags, Value: 1},
			)
		} else {
			atomic.AddInt64(&check.Fails, 1)
			state.Samples = append(state.Samples,
				stats.Sample{Time: t, Metric: metrics.Checks, Tags: tags, Value: 0},
			)

			// A single failure makes the return value false.
			succ = false
		}
	}

	return succ, nil
}
<commit_msg>Don't touch check counters past the end of a test<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package k6

import (
	"context"
	"sync/atomic"
	"time"

	"github.com/dop251/goja"
	"github.com/loadimpact/k6/js/common"
	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/stats"
	"github.com/pkg/errors"
)

type K6 struct{}

func (*K6) Fail(msg string) (goja.Value, error) {
	return goja.Undefined(), errors.New(msg)
}

func (*K6) Sleep(ctx context.Context, secs float64) {
	timer := time.NewTimer(time.Duration(secs * float64(time.Second)))
	select {
	case <-timer.C:
	case <-ctx.Done():
		timer.Stop()
	}
}

func (*K6) Group(ctx context.Context, name string, fn goja.Callable) (goja.Value, error) {
	state := common.GetState(ctx)

	g, err := state.Group.Group(name)
	if err != nil {
		return goja.Undefined(), err
	}

	old := state.Group
	state.Group = g
	defer func() { state.Group = old }()

	return fn(goja.Undefined())
}

func (*K6) Check(ctx context.Context, arg0, checks goja.Value, extras ...goja.Value) (bool, error) {
	state := common.GetState(ctx)
	rt := common.GetRuntime(ctx)
	t := time.Now()

	// Prepare tags, make sure the `group` tag can't be overwritten.
	tags := make(map[string]string)
	if len(extras) > 0 {
		obj := extras[0].ToObject(rt)
		for _, k := range obj.Keys() {
			tags[k] = obj.Get(k).String()
		}
	}
	tags["group"] = state.Group.Path

	succ := true
	obj := checks.ToObject(rt)
	for _, name := range obj.Keys() {
		val := obj.Get(name)

		// Resolve the check record.
		check, err := state.Group.Check(name)
		if err != nil {
			return false, err
		}
		tags["check"] = check.Name

		// Resolve callables into values.
		fn, ok := goja.AssertFunction(val)
		if ok {
			val_, err := fn(goja.Undefined(), arg0)
			if err != nil {
				return false, err
			}
			val = val_
		}

		// Emit! (But only if we have a valid context.)
		select {
		case <-ctx.Done():
		default:
			if val.ToBoolean() {
				atomic.AddInt64(&check.Passes, 1)
				state.Samples = append(state.Samples,
					stats.Sample{Time: t, Metric: metrics.Checks, Tags: tags, Value: 1},
				)
			} else {
				atomic.AddInt64(&check.Fails, 1)
				state.Samples = append(state.Samples,
					stats.Sample{Time: t, Metric: metrics.Checks, Tags: tags, Value: 0},
				)

				// A single failure makes the return value false.
				succ = false
			}
		}
	}

	return succ, nil
}
<|endoftext|>


<commit_before>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2015 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/

package toybroker

import (
	"net"
	"sync"
)

type MemoryClient struct {
	clientID         string
	loginName        string
	conn             net.Conn
	currentMessageID uint16
	messageBuffer    MessageBuffer
	sync.RWMutex
}

func NewMemoryClient(id string, name string, c net.Conn, messages MessageBuffer) MemoryClient {
	return MemoryClient{
		clientID:      id,
		loginName:     name,
		messageBuffer: messages,
		conn:          c,
	}
}

func (c MemoryClient) GetClientID() string {
	return c.clientID
}

func (c MemoryClient) GetLoginName() string {
	return c.loginName
}

func (c MemoryClient) GetConn() net.Conn {
	return c.conn
}

func (c MemoryClient) getNextMessageID() uint16 {
	c.Lock()
	defer c.Unlock()
	c.currentMessageID++
	if c.currentMessageID == 0 {
		c.currentMessageID++
	}
	return c.currentMessageID
}

func (c MemoryClient) Publish(dup bool, qos int, retain bool, topic string, payload []byte) {
	messageID := c.getNextMessageID()
	if c.conn != nil {
		c.conn.Write(packPUBLISH(dup, qos, retain, topic, messageID, payload))
	}
	if qos == 1 {
		c.messageBuffer.Set(messageID, payload)
	}
}

func (c MemoryClient) Send(data []byte) {
	c.conn.Write(data)
}

func (c MemoryClient) Disconnect() {
	c.Lock()
	defer c.Unlock()
	c.conn = nil
}
<commit_msg>Close() on Disconnect()<commit_after>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2015 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/

package toybroker

import (
	"net"
	"sync"
)

type MemoryClient struct {
	clientID         string
	loginName        string
	conn             net.Conn
	currentMessageID uint16
	messageBuffer    MessageBuffer
	sync.RWMutex
}

func NewMemoryClient(id string, name string, c net.Conn, messages MessageBuffer) MemoryClient {
	return MemoryClient{
		clientID:      id,
		loginName:     name,
		messageBuffer: messages,
		conn:          c,
	}
}

func (c MemoryClient) GetClientID() string {
	return c.clientID
}

func (c MemoryClient) GetLoginName() string {
	return c.loginName
}

func (c MemoryClient) GetConn() net.Conn {
	return c.conn
}

func (c MemoryClient) getNextMessageID() uint16 {
	c.Lock()
	defer c.Unlock()
	c.currentMessageID++
	if c.currentMessageID == 0 {
		c.currentMessageID++
	}
	return c.currentMessageID
}

func (c MemoryClient) Publish(dup bool, qos int, retain bool, topic string, payload []byte) {
	messageID := c.getNextMessageID()
	if c.conn != nil {
		c.conn.Write(packPUBLISH(dup, qos, retain, topic, messageID, payload))
	}
	if qos == 1 {
		c.messageBuffer.Set(messageID, payload)
	}
}

func (c MemoryClient) Send(data []byte) {
	c.conn.Write(data)
}

func (c MemoryClient) Disconnect() {
	c.Lock()
	defer c.Unlock()
	c.conn.Close()
	c.conn = nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"crypto/tls"
	"net/smtp"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/go-errors/errors"
	"github.com/mitchellh/mapstructure"
	irma "github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/keyshare"
	"github.com/spf13/cast"
	"github.com/spf13/pflag"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func configureEmail() keyshare.EmailConfiguration {
	// If username/password are specified for the email server, build an authentication object.
	var emailAuth smtp.Auth
	if viper.GetString("email_username") != "" {
		emailAuth = smtp.PlainAuth(
			"",
			viper.GetString("email_username"),
			viper.GetString("email_password"),
			viper.GetString("email_hostname"),
		)
	}

	return keyshare.EmailConfiguration{
		EmailServer:     viper.GetString("email_server"),
		EmailAuth:       emailAuth,
		EmailFrom:       viper.GetString("email_from"),
		DefaultLanguage: viper.GetString("default_language"),
	}
}

func configureIRMAServer() *server.Configuration {
	return &server.Configuration{
		SchemesPath:            viper.GetString("schemes_path"),
		SchemesAssetsPath:      viper.GetString("schemes_assets_path"),
		SchemesUpdateInterval:  viper.GetInt("schemes_update"),
		DisableSchemesUpdate:   viper.GetInt("schemes_update") == 0,
		IssuerPrivateKeysPath:  viper.GetString("privkeys"),
		RevocationDBType:       viper.GetString("revocation_db_type"),
		RevocationDBConnStr:    viper.GetString("revocation_db_str"),
		RevocationSettings:     irma.RevocationSettings{},
		URL:                    viper.GetString("url"),
		DisableTLS:             viper.GetBool("no_tls"),
		Email:                  viper.GetString("email"),
		EnableSSE:              viper.GetBool("sse"),
		Verbose:                viper.GetInt("verbose"),
		Quiet:                  viper.GetBool("quiet"),
		LogJSON:                viper.GetBool("log_json"),
		Logger:                 logger,
		Production:             viper.GetBool("production"),
		MaxSessionLifetime:     viper.GetInt("max_session_lifetime"),
		JwtIssuer:              viper.GetString("jwt_issuer"),
		JwtPrivateKey:          viper.GetString("jwt_privkey"),
		JwtPrivateKeyFile:      viper.GetString("jwt_privkey_file"),
		AllowUnsignedCallbacks: viper.GetBool("allow_unsigned_callbacks"),
		AugmentClientReturnURL: viper.GetBool("augment_client_return_url"),
	}
}

func configureTLS() *tls.Config {
	conf, err := server.TLSConf(
		viper.GetString("tls_cert"),
		viper.GetString("tls_cert_file"),
		viper.GetString("tls_privkey"),
		viper.GetString("tls_privkey_file"))
	if err != nil {
		die("", err)
	}
	return conf
}

func readConfig(cmd *cobra.Command, name, logname string, configpaths []string, productionDefaults map[string]interface{}) {
	dashReplacer := strings.NewReplacer("-", "_")
	viper.SetEnvKeyReplacer(dashReplacer)
	viper.SetEnvPrefix(strings.ToUpper(name))
	viper.AutomaticEnv()

	// Bind cmd flags to viper, such that configuration files use underscores instead of dashes
	f := cmd.Flags()
	normalizeFunc := f.GetNormalizeFunc()
	f.SetNormalizeFunc(func(fs *pflag.FlagSet, name string) pflag.NormalizedName {
		return pflag.NormalizedName(dashReplacer.Replace(string(normalizeFunc(fs, name))))
	})
	if err := viper.BindPFlags(f); err != nil {
		die("", err)
	}

	// Locate and read configuration file
	confpath := viper.GetString("config")
	if confpath != "" {
		info, err := os.Stat(confpath)
		if err != nil {
			if os.IsNotExist(err) {
				die("specified configuration file does not exist", nil)
			} else {
				die("failed to stat configuration file", err)
			}
		}
		if info.IsDir() {
			die("specified configuration file is a directory", nil)
		}
		dir, file := filepath.Dir(confpath), filepath.Base(confpath)
		viper.SetConfigName(strings.TrimSuffix(file, filepath.Ext(file)))
		viper.AddConfigPath(dir)
	} else {
		viper.SetConfigName(name)
		for _, path := range configpaths {
			viper.AddConfigPath(path)
		}
	}

	err := viper.ReadInConfig() // Hold error checking until we know how much of it to log

	// Create our logger instance
	logger = server.NewLogger(viper.GetInt("verbose"), viper.GetBool("quiet"), viper.GetBool("log_json"))

	// First log output: hello, development or production mode, log level
	mode := "development"
	if viper.GetBool("production") {
		mode = "production"
		for key, val := range productionDefaults {
			viper.SetDefault(key, val)
		}
	}
	logger.WithFields(logrus.Fields{
		"version":   irma.Version,
		"mode":      mode,
		"verbosity": server.Verbosity(viper.GetInt("verbose")),
	}).Info(logname + " running")

	// Now we finally examine and log any error from viper.ReadInConfig()
	if err != nil {
		if _, notfound := err.(viper.ConfigFileNotFoundError); notfound {
			logger.Info("No configuration file found")
		} else {
			die("", errors.WrapPrefix(err, "Failed to unmarshal configuration file at "+viper.ConfigFileUsed(), 0))
		}
	} else {
		logger.Info("Config file: ", viper.ConfigFileUsed())
	}
}

func handleMapOrString(key string, dest interface{}) error {
	var m map[string]interface{}
	var err error
	if val, flagOrEnv := viper.Get(key).(string); !flagOrEnv || val != "" {
		if m, err = cast.ToStringMapE(viper.Get(key)); err != nil {
			return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from flag or env var", 0)
		}
	}
	if len(m) == 0 {
		return nil
	}
	if err := mapstructure.Decode(m, dest); err != nil {
		return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from config file", 0)
	}
	return nil
}

func handlePermission(typ string) []string {
	if !viper.IsSet(typ) {
		if typ == "revoke_perms" || (viper.GetBool("production") && typ == "issue_perms") {
			return []string{}
		} else {
			return []string{"*"}
		}
	}
	perms := viper.GetStringSlice(typ)
	if perms == nil {
		return []string{}
	}
	return perms
}

// productionMode examines the arguments passed to the executable to see if --production is enabled.
// (This should really be done using viper, but when the help message is printed, viper is not yet
// initialized.)
func productionMode() bool {
	r := regexp.MustCompile("^--production(=(.*))?$")
	for _, arg := range os.Args {
		matches := r.FindStringSubmatch(arg)
		if len(matches) != 3 {
			continue
		}
		if matches[1] == "" {
			return true
		}
		return checkConfVal(matches[2])
	}

	return checkConfVal(os.Getenv("IRMASERVER_PRODUCTION"))
}

func checkConfVal(val string) bool {
	lc := strings.ToLower(val)
	return lc == "1" || lc == "true" || lc == "yes" || lc == "t"
}
<commit_msg>refactor: move imports order<commit_after>package cmd

import (
	"crypto/tls"
	"net/smtp"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	irma "github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/keyshare"

	"github.com/go-errors/errors"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cast"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

func configureEmail() keyshare.EmailConfiguration {
	// If username/password are specified for the email server, build an authentication object.
	var emailAuth smtp.Auth
	if viper.GetString("email_username") != "" {
		emailAuth = smtp.PlainAuth(
			"",
			viper.GetString("email_username"),
			viper.GetString("email_password"),
			viper.GetString("email_hostname"),
		)
	}

	return keyshare.EmailConfiguration{
		EmailServer:     viper.GetString("email_server"),
		EmailAuth:       emailAuth,
		EmailFrom:       viper.GetString("email_from"),
		DefaultLanguage: viper.GetString("default_language"),
	}
}

func configureIRMAServer() *server.Configuration {
	return &server.Configuration{
		SchemesPath:            viper.GetString("schemes_path"),
		SchemesAssetsPath:      viper.GetString("schemes_assets_path"),
		SchemesUpdateInterval:  viper.GetInt("schemes_update"),
		DisableSchemesUpdate:   viper.GetInt("schemes_update") == 0,
		IssuerPrivateKeysPath:  viper.GetString("privkeys"),
		RevocationDBType:       viper.GetString("revocation_db_type"),
		RevocationDBConnStr:    viper.GetString("revocation_db_str"),
		RevocationSettings:     irma.RevocationSettings{},
		URL:                    viper.GetString("url"),
		DisableTLS:             viper.GetBool("no_tls"),
		Email:                  viper.GetString("email"),
		EnableSSE:              viper.GetBool("sse"),
		Verbose:                viper.GetInt("verbose"),
		Quiet:                  viper.GetBool("quiet"),
		LogJSON:                viper.GetBool("log_json"),
		Logger:                 logger,
		Production:             viper.GetBool("production"),
		MaxSessionLifetime:     viper.GetInt("max_session_lifetime"),
		JwtIssuer:              viper.GetString("jwt_issuer"),
		JwtPrivateKey:          viper.GetString("jwt_privkey"),
		JwtPrivateKeyFile:      viper.GetString("jwt_privkey_file"),
		AllowUnsignedCallbacks: viper.GetBool("allow_unsigned_callbacks"),
		AugmentClientReturnURL: viper.GetBool("augment_client_return_url"),
	}
}

func configureTLS() *tls.Config {
	conf, err := server.TLSConf(
		viper.GetString("tls_cert"),
		viper.GetString("tls_cert_file"),
		viper.GetString("tls_privkey"),
		viper.GetString("tls_privkey_file"))
	if err != nil {
		die("", err)
	}
	return conf
}

func readConfig(cmd *cobra.Command, name, logname string, configpaths []string, productionDefaults map[string]interface{}) {
	dashReplacer := strings.NewReplacer("-", "_")
	viper.SetEnvKeyReplacer(dashReplacer)
	viper.SetEnvPrefix(strings.ToUpper(name))
	viper.AutomaticEnv()

	// Bind cmd flags to viper, such that configuration files use underscores instead of dashes
	f := cmd.Flags()
	normalizeFunc := f.GetNormalizeFunc()
	f.SetNormalizeFunc(func(fs *pflag.FlagSet, name string) pflag.NormalizedName {
		return pflag.NormalizedName(dashReplacer.Replace(string(normalizeFunc(fs, name))))
	})
	if err := viper.BindPFlags(f); err != nil {
		die("", err)
	}

	// Locate and read configuration file
	confpath := viper.GetString("config")
	if confpath != "" {
		info, err := os.Stat(confpath)
		if err != nil {
			if os.IsNotExist(err) {
				die("specified configuration file does not exist", nil)
			} else {
				die("failed to stat configuration file", err)
			}
		}
		if info.IsDir() {
			die("specified configuration file is a directory", nil)
		}
		dir, file := filepath.Dir(confpath), filepath.Base(confpath)
		viper.SetConfigName(strings.TrimSuffix(file, filepath.Ext(file)))
		viper.AddConfigPath(dir)
	} else {
		viper.SetConfigName(name)
		for _, path := range configpaths {
			viper.AddConfigPath(path)
		}
	}

	err := viper.ReadInConfig() // Hold error checking until we know how much of it to log

	// Create our logger instance
	logger = server.NewLogger(viper.GetInt("verbose"), viper.GetBool("quiet"), viper.GetBool("log_json"))

	// First log output: hello, development or production mode, log level
	mode := "development"
	if viper.GetBool("production") {
		mode = "production"
		for key, val := range productionDefaults {
			viper.SetDefault(key, val)
		}
	}
	logger.WithFields(logrus.Fields{
		"version":   irma.Version,
		"mode":      mode,
		"verbosity": server.Verbosity(viper.GetInt("verbose")),
	}).Info(logname + " running")

	// Now we finally examine and log any error from viper.ReadInConfig()
	if err != nil {
		if _, notfound := err.(viper.ConfigFileNotFoundError); notfound {
			logger.Info("No configuration file found")
		} else {
			die("", errors.WrapPrefix(err, "Failed to unmarshal configuration file at "+viper.ConfigFileUsed(), 0))
		}
	} else {
		logger.Info("Config file: ", viper.ConfigFileUsed())
	}
}

func handleMapOrString(key string, dest interface{}) error {
	var m map[string]interface{}
	var err error
	if val, flagOrEnv := viper.Get(key).(string); !flagOrEnv || val != "" {
		if m, err = cast.ToStringMapE(viper.Get(key)); err != nil {
			return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from flag or env var", 0)
		}
	}
	if len(m) == 0 {
		return nil
	}
	if err := mapstructure.Decode(m, dest); err != nil {
		return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from config file", 0)
	}
	return nil
}

func handlePermission(typ string) []string {
	if !viper.IsSet(typ) {
		if typ == "revoke_perms" || (viper.GetBool("production") && typ == "issue_perms") {
			return []string{}
		} else {
			return []string{"*"}
		}
	}
	perms := viper.GetStringSlice(typ)
	if perms == nil {
		return []string{}
	}
	return perms
}

// productionMode examines the arguments passed to the executable to see if --production is enabled.
// (This should really be done using viper, but when the help message is printed, viper is not yet
// initialized.)
func productionMode() bool {
	r := regexp.MustCompile("^--production(=(.*))?$")
	for _, arg := range os.Args {
		matches := r.FindStringSubmatch(arg)
		if len(matches) != 3 {
			continue
		}
		if matches[1] == "" {
			return true
		}
		return checkConfVal(matches[2])
	}

	return checkConfVal(os.Getenv("IRMASERVER_PRODUCTION"))
}

func checkConfVal(val string) bool {
	lc := strings.ToLower(val)
	return lc == "1" || lc == "true" || lc == "yes" || lc == "t"
}
<|endoftext|>


<commit_before>package dirwatch

import (
	"bitbucket.org/anacrolix/go.torrent"
	"github.com/anacrolix/libtorgo/metainfo"
	"github.com/go-fsnotify/fsnotify"
	"log"
	"os"
	"path/filepath"
)

type Change uint

const (
	Added Change = iota
	Removed
)

type Event struct {
	Magnet string
	Change
	TorrentFilePath string
	InfoHash        torrent.InfoHash
}

type Instance struct {
	w                     *fsnotify.Watcher
	dirName               string
	Events                chan Event
	torrentFileInfoHashes map[string]torrent.InfoHash
}

func (me *Instance) handleEvents() {
	for e := range me.w.Events {
		log.Printf("event: %s", e)
		me.processFile(e.Name)
	}
}

func (me *Instance) handleErrors() {
	for err := range me.w.Errors {
		log.Printf("error in torrent directory watcher: %s", err)
	}
}

func torrentFileInfoHash(fileName string) (ih torrent.InfoHash, ok bool) {
	mi, _ := metainfo.LoadFromFile(fileName)
	if mi == nil {
		return
	}
	if 20 != copy(ih[:], mi.Info.Hash) {
		panic(mi.Info.Hash)
	}
	ok = true
	return
}

func (me *Instance) processFile(name string) {
	name = filepath.Clean(name)
	log.Print(name)
	if filepath.Ext(name) != ".torrent" {
		return
	}
	ih, ok := me.torrentFileInfoHashes[name]
	if ok {
		me.Events <- Event{
			TorrentFilePath: name,
			Change:          Removed,
			InfoHash:        ih,
		}
	}
	delete(me.torrentFileInfoHashes, name)
	ih, ok = torrentFileInfoHash(name)
	if ok {
		me.torrentFileInfoHashes[name] = ih
		me.Events <- Event{
			TorrentFilePath: name,
			Change:          Added,
			InfoHash:        ih,
		}
	}
}

func (me *Instance) addDir() (err error) {
	f, err := os.Open(me.dirName)
	if err != nil {
		return
	}
	defer f.Close()
	names, err := f.Readdirnames(-1)
	if err != nil {
		return
	}
	for _, n := range names {
		me.processFile(filepath.Join(me.dirName, n))
	}
	return
}

func New(dirName string) (i *Instance, err error) {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return
	}
	err = w.Add(dirName)
	if err != nil {
		w.Close()
		return
	}
	i = &Instance{
		w:                     w,
		dirName:               dirName,
		Events:                make(chan Event),
		torrentFileInfoHashes: make(map[string]torrent.InfoHash, 20),
	}
	go func() {
		i.addDir()
		go i.handleEvents()
		go i.handleErrors()
	}()
	return
}
<commit_msg>Support watching for ".magnet" files in torrent directory<commit_after>package dirwatch

import (
	"bitbucket.org/anacrolix/go.torrent"
	"bufio"
	"github.com/anacrolix/libtorgo/metainfo"
	"github.com/go-fsnotify/fsnotify"
	"log"
	"os"
	"path/filepath"
)

type Change uint

const (
	Added Change = iota
	Removed
)

type Event struct {
	Magnet string
	Change
	TorrentFilePath string
	InfoHash        torrent.InfoHash
}

type Instance struct {
	w                     *fsnotify.Watcher
	dirName               string
	Events                chan Event
	torrentFileInfoHashes map[string]torrent.InfoHash
	magnetFileInfoHashes  map[string]map[torrent.InfoHash]struct{}
}

func (me *Instance) handleEvents() {
	for e := range me.w.Events {
		log.Printf("event: %s", e)
		me.processFile(e.Name)
	}
}

func (me *Instance) handleErrors() {
	for err := range me.w.Errors {
		log.Printf("error in torrent directory watcher: %s", err)
	}
}

func torrentFileInfoHash(fileName string) (ih torrent.InfoHash, ok bool) {
	mi, _ := metainfo.LoadFromFile(fileName)
	if mi == nil {
		return
	}
	if 20 != copy(ih[:], mi.Info.Hash) {
		panic(mi.Info.Hash)
	}
	ok = true
	return
}

func magnetFileURIs(name string) (uris []string, err error) {
	f, err := os.Open(name)
	if err != nil {
		return
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		uris = append(uris, scanner.Text())
	}
	err = scanner.Err()
	return
}

func (me *Instance) removeAllFileMagnets(name string) {
	for ih := range me.magnetFileInfoHashes[name] {
		me.Events <- Event{
			InfoHash: ih,
			Change:   Removed,
		}
	}
}

func (me *Instance) removeTorrent(ih torrent.InfoHash) {
	me.Events <- Event{
		InfoHash: ih,
		Change:   Removed,
	}
}

func (me *Instance) processFile(name string) {
	name = filepath.Clean(name)
	log.Print(name)
	switch filepath.Ext(name) {
	case ".torrent":
		ih, ok := me.torrentFileInfoHashes[name]
		if ok {
			me.Events <- Event{
				TorrentFilePath: name,
				Change:          Removed,
				InfoHash:        ih,
			}
		}
		delete(me.torrentFileInfoHashes, name)
		ih, ok = torrentFileInfoHash(name)
		if ok {
			me.torrentFileInfoHashes[name] = ih
			me.Events <- Event{
				TorrentFilePath: name,
				Change:          Added,
				InfoHash:        ih,
			}
		}
	case ".magnet":
		me.removeAllFileMagnets(name)
		uris, err := magnetFileURIs(name)
		if err != nil {
			log.Print(err)
			break
		}
		for _, uri := range uris {
			m, err := torrent.ParseMagnetURI(uri)
			if err != nil {
				log.Printf("bad magnet uri in magnet file: %s", err)
				continue
			}
			me.removeTorrent(m.InfoHash)
			me.Events <- Event{
				Magnet: uri,
				Change: Added,
			}
		}
	default:
		return
	}
}

func (me *Instance) addDir() (err error) {
	f, err := os.Open(me.dirName)
	if err != nil {
		return
	}
	defer f.Close()
	names, err := f.Readdirnames(-1)
	if err != nil {
		return
	}
	for _, n := range names {
		me.processFile(filepath.Join(me.dirName, n))
	}
	return
}

func New(dirName string) (i *Instance, err error) {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return
	}
	err = w.Add(dirName)
	if err != nil {
		w.Close()
		return
	}
	i = &Instance{
		w:                     w,
		dirName:               dirName,
		Events:                make(chan Event),
		torrentFileInfoHashes: make(map[string]torrent.InfoHash, 20),
	}
	go func() {
		i.addDir()
		go i.handleEvents()
		go i.handleErrors()
	}()
	return
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Shopify/sarama"
	"encoding/json"
)

type Character struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	WikipediaURL string `json:"wikipediaUrl"`
}

type Fiction struct {
	ID           string `json:"id"`
	FictionType  string `json:"fictionType"`
	Title        string `json:"title"`
	CharacterIDs []string `json:"characterIds"`
}

var characters []Character = []Character{
	{ID: "CHARACTER_001", Name: "Hellboy", WikipediaURL: "https://en.wikipedia.org/wiki/Hellboy"},
	{ID: "CHARACTER_002", Name: "Darth Vader", WikipediaURL: "https://en.wikipedia.org/wiki/Darth_Vader"},
	{ID: "CHARACTER_003", Name: "Boba Fet", WikipediaURL: "https://en.wikipedia.org/wiki/Boba_Fett"},
	{ID: "CHARACTER_004", Name: "Harry Potter", WikipediaURL: "https://en.wikipedia.org/wiki/Harry_Potter"},
	{ID: "CHARACTER_005", Name: "Han Solo", WikipediaURL: "https://en.wikipedia.org/wiki/Han_Solo"},
	{ID: "CHARACTER_006", Name: "The Doctor", WikipediaURL: "https://en.wikipedia.org/wiki/The_Doctor_(Doctor_Who)"},
	{ID: "CHARACTER_007", Name: "Luke Skywalker", WikipediaURL: "https://en.wikipedia.org/wiki/Luke_Skywalker"},
	{ID: "CHARACTER_008", Name: "Buffy", WikipediaURL: "https://en.wikipedia.org/wiki/Buffy_Summers"},
	{ID: "CHARACTER_009", Name: "Godzilla", WikipediaURL: "https://en.wikipedia.org/wiki/Godzilla"},
	{ID: "CHARACTER_010", Name: "Ellen Ripley", WikipediaURL: "https://en.wikipedia.org/wiki/Ellen_Ripley"},
	{ID: "CHARACTER_011", Name: "Cthulhu", WikipediaURL: "https://en.wikipedia.org/wiki/Cthulhu"},
	{ID: "CHARACTER_012", Name: "Agent Smith", WikipediaURL: "https://en.wikipedia.org/wiki/Agent_Smith"},
	{ID: "CHARACTER_013", Name: "Bender", WikipediaURL: "https://en.wikipedia.org/wiki/Bender_(Futurama)"},
	{ID: "CHARACTER_014", Name: "Gandalf", WikipediaURL: "https://en.wikipedia.org/wiki/Gandalf"},
	{ID: "CHARACTER_015", Name: "Legolas", WikipediaURL: "https://en.wikipedia.org/wiki/Legolas"},
	{ID: "CHARACTER_016", Name: "Alien (Xenomorphs)", WikipediaURL: "https://en.wikipedia.org/wiki/Alien_(creature_in_Alien_franchise)"},
	{ID: "CHARACTER_017", Name: "Predator", WikipediaURL: "https://en.wikipedia.org/wiki/Predator_(alien)"},
	{ID: "CHARACTER_018", Name: "Chewbacca", WikipediaURL: "https://en.wikipedia.org/wiki/Chewbacca"},
	{ID: "CHARACTER_019", Name: "Princess Leia", WikipediaURL: "https://en.wikipedia.org/wiki/Princess_Leia"},
	{ID: "CHARACTER_020", Name: "Yoda", WikipediaURL: "https://en.wikipedia.org/wiki/Yoda"},
}

var fictions []Fiction = []Fiction{
	{ID: "FICTION_001", FictionType: "Comic Book", Title: "Hellboy", CharacterIDs: []string{
		"CHARACTER_001",
	}},
	{ID: "FICTION_002", FictionType: "Film Series", Title: "Star Wars", CharacterIDs: []string{
		"CHARACTER_002",
		"CHARACTER_003",
		"CHARACTER_005",
		"CHARACTER_007",
		"CHARACTER_018",
		"CHARACTER_019",
		"CHARACTER_020",
	}},
	{ID: "FICTION_003", FictionType: "Book Series", Title: "Harry Potter", CharacterIDs: []string{
		"CHARACTER_004",
	}},
	{ID: "FICTION_004", FictionType: "TV Series", Title: "Doctor Who", CharacterIDs: []string{
		"CHARACTER_006",
	}},
	{ID: "FICTION_005", FictionType: "TV Series", Title: "Buffy the Vampire Slayer", CharacterIDs: []string{
		"CHARACTER_008",
	}},
	{ID: "FICTION_006", FictionType: "Film Franchise", Title: "Godzilla", CharacterIDs: []string{
		"CHARACTER_009",
	}},
	{ID: "FICTION_007", FictionType: "Film Series", Title: "Aliens", CharacterIDs: []string{
		"CHARACTER_010",
		"CHARACTER_016",
	}},
	{ID: "FICTION_008", FictionType: "Short Story", Title: "The Call of Cthulhu", CharacterIDs: []string{
		"CHARACTER_011",
	}},
	{ID: "FICTION_009", FictionType: "Film Series", Title: "The Matrix", CharacterIDs: []string{
		"CHARACTER_012",
	}},
	{ID: "FICTION_010", FictionType: "TV Series", Title: "Futurama", CharacterIDs: []string{
		"CHARACTER_013",
	}},
	{ID: "FICTION_011", FictionType: "Book Series", Title: "The Lord of the Rings", CharacterIDs: []string{
		"CHARACTER_014",
		"CHARACTER_015",
	}},
	{ID: "FICTION_012", FictionType: "Film Series", Title: "Predator", CharacterIDs: []string{
		"CHARACTER_017",
	}},
}

func main() {
	config := sarama.NewConfig()
	config.Producer.Return.Successes = true
	producer, err := sarama.NewSyncProducer([]string{"127.0.0.1:9092"}, config)
	if err != nil {
		panic(err)
	}
	produceCharacters(producer)
	produceFictions(producer)
}

func produceFictions(producer sarama.SyncProducer) {
	for _, f := range fictions {
		bytes, err := json.Marshal(f)
		if err != nil {
			panic(err)
		}
		_, _, err = producer.SendMessage(&sarama.ProducerMessage{
			Topic:     "fictions",
			Key:       sarama.StringEncoder(f.ID),
			Value:     sarama.ByteEncoder(bytes),
			Metadata:  nil,
			Partition: 0,
		})
		if err != nil {
			panic(err)
		}
	}
}

func produceCharacters(producer sarama.SyncProducer) {
	for _, c := range characters {
		bytes, err := json.Marshal(c)
		if err != nil {
			panic(err)
		}
		_, _, err = producer.SendMessage(&sarama.ProducerMessage{
			Topic:     "characters",
			Key:       sarama.StringEncoder(c.ID),
			Value:     sarama.ByteEncoder(bytes),
			Metadata:  nil,
			Partition: 0,
		})
		if err != nil {
			panic(err)
		}
	}
}
<commit_msg>populate topics gofmt<commit_after>package main

import (
	"encoding/json"

	"github.com/Shopify/sarama"
)

// Character describes an item for "character" topic
type Character struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	WikipediaURL string `json:"wikipediaUrl"`
}

// Fiction describes an item for "fiction" topic
type Fiction struct {
	ID           string   `json:"id"`
	FictionType  string   `json:"fictionType"`
	Title        string   `json:"title"`
	CharacterIDs []string `json:"characterIds"`
}

var characters = []Character{
	{ID: "CHARACTER_001", Name: "Hellboy", WikipediaURL: "https://en.wikipedia.org/wiki/Hellboy"},
	{ID: "CHARACTER_002", Name: "Darth Vader", WikipediaURL: "https://en.wikipedia.org/wiki/Darth_Vader"},
	{ID: "CHARACTER_003", Name: "Boba Fet", WikipediaURL: "https://en.wikipedia.org/wiki/Boba_Fett"},
	{ID: "CHARACTER_004", Name: "Harry Potter", WikipediaURL: "https://en.wikipedia.org/wiki/Harry_Potter"},
	{ID: "CHARACTER_005", Name: "Han Solo", WikipediaURL: "https://en.wikipedia.org/wiki/Han_Solo"},
	{ID: "CHARACTER_006", Name: "The Doctor", WikipediaURL: "https://en.wikipedia.org/wiki/The_Doctor_(Doctor_Who)"},
	{ID: "CHARACTER_007", Name: "Luke Skywalker", WikipediaURL: "https://en.wikipedia.org/wiki/Luke_Skywalker"},
	{ID: "CHARACTER_008", Name: "Buffy", WikipediaURL: "https://en.wikipedia.org/wiki/Buffy_Summers"},
	{ID: "CHARACTER_009", Name: "Godzilla", WikipediaURL: "https://en.wikipedia.org/wiki/Godzilla"},
	{ID: "CHARACTER_010", Name: "Ellen Ripley", WikipediaURL: "https://en.wikipedia.org/wiki/Ellen_Ripley"},
	{ID: "CHARACTER_011", Name: "Cthulhu", WikipediaURL: "https://en.wikipedia.org/wiki/Cthulhu"},
	{ID: "CHARACTER_012", Name: "Agent Smith", WikipediaURL: "https://en.wikipedia.org/wiki/Agent_Smith"},
	{ID: "CHARACTER_013", Name: "Bender", WikipediaURL: "https://en.wikipedia.org/wiki/Bender_(Futurama)"},
	{ID: "CHARACTER_014", Name: "Gandalf", WikipediaURL: "https://en.wikipedia.org/wiki/Gandalf"},
	{ID: "CHARACTER_015", Name: "Legolas", WikipediaURL: "https://en.wikipedia.org/wiki/Legolas"},
	{ID: "CHARACTER_016", Name: "Alien (Xenomorphs)", WikipediaURL: "https://en.wikipedia.org/wiki/Alien_(creature_in_Alien_franchise)"},
	{ID: "CHARACTER_017", Name: "Predator", WikipediaURL: "https://en.wikipedia.org/wiki/Predator_(alien)"},
	{ID: "CHARACTER_018", Name: "Chewbacca", WikipediaURL: "https://en.wikipedia.org/wiki/Chewbacca"},
	{ID: "CHARACTER_019", Name: "Princess Leia", WikipediaURL: "https://en.wikipedia.org/wiki/Princess_Leia"},
	{ID: "CHARACTER_020", Name: "Yoda", WikipediaURL: "https://en.wikipedia.org/wiki/Yoda"},
}

var fictions = []Fiction{
	{ID: "FICTION_001", FictionType: "Comic Book", Title: "Hellboy", CharacterIDs: []string{
		"CHARACTER_001",
	}},
	{ID: "FICTION_002", FictionType: "Film Series", Title: "Star Wars", CharacterIDs: []string{
		"CHARACTER_002",
		"CHARACTER_003",
		"CHARACTER_005",
		"CHARACTER_007",
		"CHARACTER_018",
		"CHARACTER_019",
		"CHARACTER_020",
	}},
	{ID: "FICTION_003", FictionType: "Book Series", Title: "Harry Potter", CharacterIDs: []string{
		"CHARACTER_004",
	}},
	{ID: "FICTION_004", FictionType: "TV Series", Title: "Doctor Who", CharacterIDs: []string{
		"CHARACTER_006",
	}},
	{ID: "FICTION_005", FictionType: "TV Series", Title: "Buffy the Vampire Slayer", CharacterIDs: []string{
		"CHARACTER_008",
	}},
	{ID: "FICTION_006", FictionType: "Film Franchise", Title: "Godzilla", CharacterIDs: []string{
		"CHARACTER_009",
	}},
	{ID: "FICTION_007", FictionType: "Film Series", Title: "Aliens", CharacterIDs: []string{
		"CHARACTER_010",
		"CHARACTER_016",
	}},
	{ID: "FICTION_008", FictionType: "Short Story", Title: "The Call of Cthulhu", CharacterIDs: []string{
		"CHARACTER_011",
	}},
	{ID: "FICTION_009", FictionType: "Film Series", Title: "The Matrix", CharacterIDs: []string{
		"CHARACTER_012",
	}},
	{ID: "FICTION_010", FictionType: "TV Series", Title: "Futurama", CharacterIDs: []string{
		"CHARACTER_013",
	}},
	{ID: "FICTION_011", FictionType: "Book Series", Title: "The Lord of the Rings", CharacterIDs: []string{
		"CHARACTER_014",
		"CHARACTER_015",
	}},
	{ID: "FICTION_012", FictionType: "Film Series", Title: "Predator", CharacterIDs: []string{
		"CHARACTER_017",
	}},
}

func main() {
	config := sarama.NewConfig()
	config.Producer.Return.Successes = true
	producer, err := sarama.NewSyncProducer([]string{"127.0.0.1:9092"}, config)
	if err != nil {
		panic(err)
	}
	produceCharacters(producer)
	produceFictions(producer)
}

func produceFictions(producer sarama.SyncProducer) {
	for _, f := range fictions {
		bytes, err := json.Marshal(f)
		if err != nil {
			panic(err)
		}
		_, _, err = producer.SendMessage(&sarama.ProducerMessage{
			Topic:     "fictions",
			Key:       sarama.StringEncoder(f.ID),
			Value:     sarama.ByteEncoder(bytes),
			Metadata:  nil,
			Partition: 0,
		})
		if err != nil {
			panic(err)
		}
	}
}

func produceCharacters(producer sarama.SyncProducer) {
	for _, c := range characters {
		bytes, err := json.Marshal(c)
		if err != nil {
			panic(err)
		}
		_, _, err = producer.SendMessage(&sarama.ProducerMessage{
			Topic:     "characters",
			Key:       sarama.StringEncoder(c.ID),
			Value:     sarama.ByteEncoder(bytes),
			Metadata:  nil,
			Partition: 0,
		})
		if err != nil {
			panic(err)
		}
	}
}
<|endoftext|>


<commit_before>package volume

import (
	"fmt"
	"strings"
	"testing"

	"github.com/fsouza/go-dockerclient"
)

// Set up mocked Conplicity handler
type fakeHandler struct {
	Command []string
	Mounts  []string
}

func (h *fakeHandler) LaunchDuplicity(c, m []string) (docker.State, string, error) {
	fmt.Printf("Command: %s\n", strings.Join(c, " "))
	fmt.Printf("Mounts: %s\n", strings.Join(m, " "))

	return docker.State{}, "", nil
}

// Set up fake volume
var fakeVol = Volume{
	Name:            "Test",
	Target:          "/foo",
	BackupDir:       "/back",
	Mount:           "/mnt",
	FullIfOlderThan: "3W",
	RemoveOlderThan: "1Y",
	Client:          &fakeHandler{},
}

// TestNewVolume checks the creation of a new volume
func TestNewVolume(t *testing.T) {
	if fakeVol.Name != "Test" {
		t.Fatalf("Volume name is wrong. Expected Test, got %v", fakeVol.Name)
	}

	if fakeVol.Target != "/foo" {
		t.Fatalf("Volume target is wrong. Expected /foo, got %v", fakeVol.Target)
	}

	if fakeVol.BackupDir != "/back" {
		t.Fatalf("Volume backup dir is wrong. Expected /back, got %v", fakeVol.BackupDir)
	}

	if fakeVol.Mount != "/mnt" {
		t.Fatalf("Volume mount dir is wrong. Expected /mnt, got %v", fakeVol.Mount)
	}

	if fakeVol.FullIfOlderThan != "3W" {
		t.Fatalf("Volume FullIfOlderThan is wrong. Expected 3W, got %v", fakeVol.FullIfOlderThan)
	}

	if fakeVol.RemoveOlderThan != "1Y" {
		t.Fatalf("Volume RemoveOlderThan is wrong. Expected 1Y, got %v", fakeVol.RemoveOlderThan)
	}
}

// ExampleBackup checks the launching of a volume backup
func ExampleBackup() {
	fakeVol.Backup()
	// Output:
	// Command: --full-if-older-than 3W --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --allow-source-mismatch --name Test /back /foo
	// Mounts: /mnt duplicity_cache:/root/.cache/duplicity
}

// ExampleRemoveOld checks the removal of old backups
func ExampleRemoveOld() {
	fakeVol.RemoveOld()
	// Output:
	// Command: remove-older-than 1Y --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --force --name Test /foo
	// Mounts: duplicity_cache:/root/.cache/duplicity
}

// ExampleCleanup checks the cleanup of a backup
func ExampleCleanup() {
	fakeVol.Cleanup()
	// Output:
	// Command: cleanup --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --force --extra-clean --name Test /foo
	// Mounts: duplicity_cache:/root/.cache/duplicity
}

// ExampleVerify checks the verification of a backup
func ExampleVerify() {
	fakeVol.Verify()
	// Output:
	// Command: verify --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --allow-source-mismatch --name Test /foo /back
	// Mounts: /mnt duplicity_cache:/root/.cache/duplicity
}

// ExampleStatus checks the status of a backup
func ExampleStatus() {
	fakeVol.Status()
	// Output:
	// Command: collection-status --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --name Test /foo
	// Mounts: /mnt duplicity_cache:/root/.cache/duplicity
}
<commit_msg>Cleanup fakeHandler properties<commit_after>package volume

import (
	"fmt"
	"strings"
	"testing"

	"github.com/fsouza/go-dockerclient"
)

// Set up mocked Conplicity handler
type fakeHandler struct{}

func (h *fakeHandler) LaunchDuplicity(c, m []string) (docker.State, string, error) {
	fmt.Printf("Command: %s\n", strings.Join(c, " "))
	fmt.Printf("Mounts: %s\n", strings.Join(m, " "))

	return docker.State{}, "", nil
}

// Set up fake volume
var fakeVol = Volume{
	Name:            "Test",
	Target:          "/foo",
	BackupDir:       "/back",
	Mount:           "/mnt",
	FullIfOlderThan: "3W",
	RemoveOlderThan: "1Y",
	Client:          &fakeHandler{},
}

// TestNewVolume checks the creation of a new volume
func TestNewVolume(t *testing.T) {
	if fakeVol.Name != "Test" {
		t.Fatalf("Volume name is wrong. Expected Test, got %v", fakeVol.Name)
	}

	if fakeVol.Target != "/foo" {
		t.Fatalf("Volume target is wrong. Expected /foo, got %v", fakeVol.Target)
	}

	if fakeVol.BackupDir != "/back" {
		t.Fatalf("Volume backup dir is wrong. Expected /back, got %v", fakeVol.BackupDir)
	}

	if fakeVol.Mount != "/mnt" {
		t.Fatalf("Volume mount dir is wrong. Expected /mnt, got %v", fakeVol.Mount)
	}

	if fakeVol.FullIfOlderThan != "3W" {
		t.Fatalf("Volume FullIfOlderThan is wrong. Expected 3W, got %v", fakeVol.FullIfOlderThan)
	}

	if fakeVol.RemoveOlderThan != "1Y" {
		t.Fatalf("Volume RemoveOlderThan is wrong. Expected 1Y, got %v", fakeVol.RemoveOlderThan)
	}
}

// ExampleBackup checks the launching of a volume backup
func ExampleBackup() {
	fakeVol.Backup()
	// Output:
	// Command: --full-if-older-than 3W --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --allow-source-mismatch --name Test /back /foo
	// Mounts: /mnt duplicity_cache:/root/.cache/duplicity
}

// ExampleRemoveOld checks the removal of old backups
func ExampleRemoveOld() {
	fakeVol.RemoveOld()
	// Output:
	// Command: remove-older-than 1Y --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --force --name Test /foo
	// Mounts: duplicity_cache:/root/.cache/duplicity
}

// ExampleCleanup checks the cleanup of a backup
func ExampleCleanup() {
	fakeVol.Cleanup()
	// Output:
	// Command: cleanup --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --force --extra-clean --name Test /foo
	// Mounts: duplicity_cache:/root/.cache/duplicity
}

// ExampleVerify checks the verification of a backup
func ExampleVerify() {
	fakeVol.Verify()
	// Output:
	// Command: verify --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --allow-source-mismatch --name Test /foo /back
	// Mounts: /mnt duplicity_cache:/root/.cache/duplicity
}

// ExampleStatus checks the status of a backup
func ExampleStatus() {
	fakeVol.Status()
	// Output:
	// Command: collection-status --s3-use-new-style --ssh-options -oStrictHostKeyChecking=no --no-encryption --name Test /foo
	// Mounts: /mnt duplicity_cache:/root/.cache/duplicity
}
<|endoftext|>


<commit_before>// +build !windows

package log

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"syscall"
	"testing"
	"time"
)

type bufferOpener struct {
	bytes.Buffer
	nopen  int
	nclose int
}

func (c *bufferOpener) Close() error {
	c.nclose++
	return nil
}

func (c *bufferOpener) Open() (io.WriteCloser, error) {
	c.nopen++
	return c, nil
}

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

	var buf bufferOpener
	w, err := NewReopenWriter(&buf, syscall.SIGUSR1)
	if err != nil {
		t.Fatal(err)
	}

	w.Write([]byte("foobar"))

	syscall.Kill(os.Getpid(), syscall.SIGUSR1)
	time.Sleep(time.Second)

	w.Write([]byte("1234"))

	if buf.nopen != 2 {
		t.Errorf("number of open should be 2 but %v", buf.nopen)
	}
	if buf.nclose != 1 {
		t.Errorf("number of close should be 1 but %v", buf.nclose)
	}
	s := buf.String()
	if "foobar1234" != s {
		t.Errorf("written data should be \"foobar1234\" but \"%v\"", s)
	}
}

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

	f, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	f.Close()

	g, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	g.Close()

	w, err := NewFileReopener(f.Name(), syscall.SIGUSR2)
	if err != nil {
		t.Fatal(err)
	}

	lg := NewLogger()
	lg.SetOutput(w)
	lg.SetFormatter(Logfmt{})
	lg.Critical("hoge", nil)
	syscall.Kill(os.Getpid(), syscall.SIGUSR2)
	time.Sleep(100 * time.Millisecond)

	if err := os.Rename(f.Name(), g.Name()); err != nil {
		t.Fatal(err)
	}

	syscall.Kill(os.Getpid(), syscall.SIGUSR2)
	time.Sleep(100 * time.Millisecond)
	lg.Critical("fuga", nil)
	syscall.Kill(os.Getpid(), syscall.SIGUSR2)
	time.Sleep(100 * time.Millisecond)

	if hoge, err := ioutil.ReadFile(g.Name()); err != nil {
		t.Error(err)
	} else {
		if !bytes.Contains(hoge, []byte("hoge")) {
			t.Error("g must contain hoge")
		}
		if bytes.Contains(hoge, []byte("fuga")) {
			t.Error("g must not contain fuga")
		}
	}

	if fuga, err := ioutil.ReadFile(f.Name()); err != nil {
		t.Error(err)
	} else {
		if bytes.Contains(fuga, []byte("hoge")) {
			t.Error("f must not contain hoge")
		}
		if !bytes.Contains(fuga, []byte("fuga")) {
			t.Error("f must contain fuga")
		}
	}
}

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

	f, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	_, err = f.Write([]byte("abc"))
	if err != nil {
		t.Fatal(err)
	}
	f.Close()

	g, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	g.Close()

	w, err := NewFileReopener(f.Name(), syscall.SIGHUP)
	if err != nil {
		t.Fatal(err)
	}

	lg := NewLogger()
	lg.SetOutput(w)
	lg.SetFormatter(Logfmt{})
	lg.Critical("hoge", nil)

	if err := os.Rename(f.Name(), g.Name()); err != nil {
		t.Fatal(err)
	}

	syscall.Kill(os.Getpid(), syscall.SIGHUP)
	time.Sleep(100 * time.Millisecond)
	lg.Critical("fuga", nil)
	syscall.Kill(os.Getpid(), syscall.SIGHUP)
	time.Sleep(100 * time.Millisecond)

	if hoge, err := ioutil.ReadFile(g.Name()); err != nil {
		t.Error(err)
	} else {
		if !bytes.HasPrefix(hoge, []byte("abc\n")) {
			t.Error(`!bytes.HasPrefix(hoge, []byte("abc\n"))`)
		}
	}

	if fuga, err := ioutil.ReadFile(f.Name()); err != nil {
		t.Error(err)
	} else {
		if bytes.HasPrefix(fuga, []byte("\n")) {
			t.Error(`bytes.HasPrefix(fuga, []byte("\n"))`)
		}
	}
}
<commit_msg>[test] Remove temporary file after use.<commit_after>// +build !windows

package log

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"syscall"
	"testing"
	"time"
)

type bufferOpener struct {
	bytes.Buffer
	nopen  int
	nclose int
}

func (c *bufferOpener) Close() error {
	c.nclose++
	return nil
}

func (c *bufferOpener) Open() (io.WriteCloser, error) {
	c.nopen++
	return c, nil
}

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

	var buf bufferOpener
	w, err := NewReopenWriter(&buf, syscall.SIGUSR1)
	if err != nil {
		t.Fatal(err)
	}

	w.Write([]byte("foobar"))

	syscall.Kill(os.Getpid(), syscall.SIGUSR1)
	time.Sleep(time.Second)

	w.Write([]byte("1234"))

	if buf.nopen != 2 {
		t.Errorf("number of open should be 2 but %v", buf.nopen)
	}
	if buf.nclose != 1 {
		t.Errorf("number of close should be 1 but %v", buf.nclose)
	}
	s := buf.String()
	if "foobar1234" != s {
		t.Errorf("written data should be \"foobar1234\" but \"%v\"", s)
	}
}

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

	f, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	f.Close()
	defer os.Remove(f.Name())

	g, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	g.Close()
	defer os.Remove(g.Name())

	w, err := NewFileReopener(f.Name(), syscall.SIGUSR2)
	if err != nil {
		t.Fatal(err)
	}

	lg := NewLogger()
	lg.SetOutput(w)
	lg.SetFormatter(Logfmt{})
	lg.Critical("hoge", nil)
	syscall.Kill(os.Getpid(), syscall.SIGUSR2)
	time.Sleep(100 * time.Millisecond)

	if err := os.Rename(f.Name(), g.Name()); err != nil {
		t.Fatal(err)
	}

	syscall.Kill(os.Getpid(), syscall.SIGUSR2)
	time.Sleep(100 * time.Millisecond)
	lg.Critical("fuga", nil)
	syscall.Kill(os.Getpid(), syscall.SIGUSR2)
	time.Sleep(100 * time.Millisecond)

	if hoge, err := ioutil.ReadFile(g.Name()); err != nil {
		t.Error(err)
	} else {
		if !bytes.Contains(hoge, []byte("hoge")) {
			t.Error("g must contain hoge")
		}
		if bytes.Contains(hoge, []byte("fuga")) {
			t.Error("g must not contain fuga")
		}
	}

	if fuga, err := ioutil.ReadFile(f.Name()); err != nil {
		t.Error(err)
	} else {
		if bytes.Contains(fuga, []byte("hoge")) {
			t.Error("f must not contain hoge")
		}
		if !bytes.Contains(fuga, []byte("fuga")) {
			t.Error("f must contain fuga")
		}
	}
}

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

	f, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	_, err = f.Write([]byte("abc"))
	if err != nil {
		t.Fatal(err)
	}
	f.Close()
	defer os.Remove(f.Name())

	g, err := ioutil.TempFile("", "gotest")
	if err != nil {
		t.Fatal(err)
	}
	g.Close()
	defer os.Remove(g.Name())

	w, err := NewFileReopener(f.Name(), syscall.SIGHUP)
	if err != nil {
		t.Fatal(err)
	}

	lg := NewLogger()
	lg.SetOutput(w)
	lg.SetFormatter(Logfmt{})
	lg.Critical("hoge", nil)

	if err := os.Rename(f.Name(), g.Name()); err != nil {
		t.Fatal(err)
	}

	syscall.Kill(os.Getpid(), syscall.SIGHUP)
	time.Sleep(100 * time.Millisecond)
	lg.Critical("fuga", nil)
	syscall.Kill(os.Getpid(), syscall.SIGHUP)
	time.Sleep(100 * time.Millisecond)

	if hoge, err := ioutil.ReadFile(g.Name()); err != nil {
		t.Error(err)
	} else {
		if !bytes.HasPrefix(hoge, []byte("abc\n")) {
			t.Error(`!bytes.HasPrefix(hoge, []byte("abc\n"))`)
		}
	}

	if fuga, err := ioutil.ReadFile(f.Name()); err != nil {
		t.Error(err)
	} else {
		if bytes.HasPrefix(fuga, []byte("\n")) {
			t.Error(`bytes.HasPrefix(fuga, []byte("\n"))`)
		}
	}
}
<|endoftext|>


<commit_before>package replica

import (
	cmd "github.com/go-epaxos/epaxos/command"
)

type Accept struct {
	cmds   []cmd.Command
	seq    int
	deps   []InstanceIdType
	repId  int
	insId  InstanceIdType
	ballot uint64
}

type AcceptReply struct {
	ok     bool
	repId  int
	insId  InstanceIdType
	ballot uint64
	status int8
}

type Commit struct {
	cmds   []cmd.Command
	seq    int
	deps   []InstanceIdType
	repId  int
	insId  InstanceIdType
	ballot uint64
}

func (a *Accept) getType() uint8 {
	return acceptType
}

func (a *AcceptReply) getType() uint8 {
	return acceptReplyType
}

func (c *Commit) getType() uint8 {
	return commitType
}
<commit_msg>no need for ballot in commit<commit_after>package replica

import (
	cmd "github.com/go-epaxos/epaxos/command"
)

type Accept struct {
	cmds   []cmd.Command
	seq    int
	deps   []InstanceIdType
	repId  int
	insId  InstanceIdType
	ballot uint64
}

type AcceptReply struct {
	ok     bool
	repId  int
	insId  InstanceIdType
	ballot uint64
	status int8
}

type Commit struct {
	cmds   []cmd.Command
	seq    int
	deps   []InstanceIdType
	repId  int
	insId  InstanceIdType
	ballot uint64 // TODO: there should no need for ballot
}

func (a *Accept) getType() uint8 {
	return acceptType
}

func (a *AcceptReply) getType() uint8 {
	return acceptReplyType
}

func (c *Commit) getType() uint8 {
	return commitType
}
<|endoftext|>