<commit_before>package kubernetes

import (
	// "encoding/json"
	"fmt"

	"github.com/containerops/vessel/models"
	"k8s.io/kubernetes/pkg/api"
	// "k8s.io/kubernetes/pkg/api/unversioned"
	// "k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/util/intstr"
)

/*// pipelineMetadata struct for convert from pipelineVersion.MetaData
type piplineMetadata struct {
	name            string            `json:"name, omitempty"`
	namespace       string            `json:"namespace, omitempty"`
	selfLink        string            `json:"selflink, omitempty"`
	uid             types.UID         `json:"uid, omitempty"`
	createTimestamp unversioned.Time  `json:"createTimestamp, omitempty"`
	deleteTimestamp unversioned.Time  `json:"deleteTimestamp, omitempty"`
	timeoutDuration int64             `json:"timeoutDuration, omitempty"`
	labels          map[string]string `json:"labels, omitempty"`
	annotations     map[string]string `json:"annotations, omitempty"`
}

// pipelineSpec struct for convert from pipelineVersion.Spec
type piplineSpec struct {
	name                string `json:"name, omitempty"`
	replicas            int    `json:"replicas, omitempty"`
	dependencies        string `json:"dependencies, omitempty"`
	kind                string `json:"kind, omitempty"`
	statusCheckLink     string `json:"statusCheckLink, omitempty"`
	statusCheckInterval int64  `json:"statusCheckInterval, omitempty"`
	statusCheckCount    int64  `json:"statusCheckCount, omitempty"`
	imageName           string `json:"imagename, omitempty"`
	port                int    `json:"port, omitempty"`
}*/

/*
type PipelineVersion struct {
	Id            int64    `json:"id"`
	WorkspaceId   int64    `json:"workspaceId"`
	ProjectId     int64    `json:"projectId"`
	PipelineId    int64    `json:"pipelineId"`
	Namespace     string   `json:"namespace"`
	SelfLink      string   `json:"selfLink" gorm:"type:varchar(255)"`
	Created       int64    `json:"created"`
	Updated       int64    `json:"updated"`
	Labels        string   `json:"labels"`
	Annotations   string   `json:"annotations"`
	Detail        string   `json:"detail" gorm:"type:text"`
	StageVersions []string `json:"stageVersions"`
	Log           string   `json:"log" gorm:"type:text"`
	Status        int64    `json:"state"` // 0 not start    1 working    2 success     3 failed
	MetaData      string   `json:"metadata"`
	Spec          string   `json:"spec"`
}
*/
// unversioned.ReplicationController.ObjectMeta
// unversioned.ReplicationController.Spec

/*
api.ReplicationController{
				ObjectMeta: api.ObjectMeta{
					Name: "foo",
					Labels: map[string]string{
						"foo":  "bar",
						"name": "baz",
					},
				},
*/
/*
func StartK8SResource(pv *PipelineVersion) error {
	rc := &api.ReplicationController{}
	service := &api.Service{}

	var pvm piplineMetadata
	var pvs piplineSpec
	err := split(pv, &pvm, &pvs)
	if err != nil {
		return err
	}

	namespace := convert(pvm, pvs, rc, service)

	if _, err = CLIENT.ReplicationControllers(namespace).Create(rc); err != nil {
		fmt.Errorf("Create rc err : %v\n", err)
		return err
	}

	if _, err := CLIENT.Services(namespace).Create(service); err != nil {
		fmt.Errorf("Create service err : %v\n", err)
		return err
	}
	// writeBack(rcRes, serviceRes, &pvm, &pvs)
	return nil
}
*/

/*
rcRes = &api.ReplicationController{
		ObjectMeta: api.ObjectMeta{
			Name:      piplineSpec.Name,
			Namespace: piplineMetadata.Namespace,
			Labels: map[string]string{
				"app": piplineSpec.Name,
			},
		},
		Spec: api.ReplicationControllerSpec{
			Replicas: piplineSpec.Replicas,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name: piplineSpec.Name,
					Labels: map[string]string{
						"app": piplineSpec.Name,
					},
					Namespace: piplineMetadata.Namespace,
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						api.Container{
							Name:  piplineSpec.Name,
							Image: piplineSpec.ImageName,
							Ports: []api.ContainerPort{
								api.ContainerPort{
									Name:          piplineSpec.Name,
									ContainerPort: piplineSpec.Port,
								},
							},
						},
					},
				},
			},
			Selector: map[string]string{
				"app": piplineSpec.Name,
			},
		},
	}
*/

/*
	serviceRes = &api.Service{
		ObjectMeta: api.ObjectMeta{
			Name:      piplineSpec.Name,
			Namespace: piplineMetadata.Namespace,
			Labels: map[string]string{
				"app": piplineSpec.Name,
			},
		},
		Spec: api.ServiceSpec{
			Ports: []api.ServicePort{
				api.ServicePort{
					Port:       piplineSpec.Port,
					TargetPort: intstr.FromString(piplineSpec.Name),
				},
			},
			Selector: map[string]string{
				"app": piplineSpec.Name,
			},
		},
	}
*/

/*
namespace := &api.Namespace{
		ObjectMeta: api.ObjectMeta{Name: "foo"},
	}
	c := &simple.Client{
		Request: simple.Request{
			Method: "POST",
			Path:   testapi.Default.ResourcePath("namespaces", "", ""),
			Body:   namespace,
		},
		Response: simple.Response{StatusCode: 200, Body: namespace},
	}

	// from the source ns, provision a new global namespace "foo"
	response, err := c.Setup(t).Namespaces().Create(namespace)
*/
func StartK8SResource(pipelineversion *models.PipelineVersion) error {

	rc := &api.ReplicationController{
		ObjectMeta: api.ObjectMeta{
			Labels: map[string]string{},
		},
		Spec: api.ReplicationControllerSpec{
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Labels: map[string]string{},
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						api.Container{
							Ports: []api.ContainerPort{},
						},
					},
				},
			},
		},
	}

	service := &api.Service{
		ObjectMeta: api.ObjectMeta{
			Labels: map[string]string{},
		},
		Spec: api.ServiceSpec{
			Ports:    []api.ServicePort{},
			Selector: map[string]string{},
		},
	}

	piplineMetadata := pipelineversion.MetaData
	stagespecs := pipelineversion.StageSpecs

	for _, stagespec := range stagespecs {
		// rc := api.ReplicationController{}
		// service := api.Service{}
		container := api.Container{}

		rc.SetName(stagespec.Name)
		rc.SetNamespace(piplineMetadata.Namespace)
		rc.Labels["app"] = stagespec.Name
		rc.Spec.Replicas = stagespec.Replicas
		rc.Spec.Template.SetName(stagespec.Name)
		rc.Spec.Template.Labels["app"] = stagespec.Name
		container.Ports = append(container.Ports, api.ContainerPort{Name: stagespec.Name, ContainerPort: stagespec.Port})
		container.Name = stagespec.Name
		container.Image = stagespec.Image
		rc.Spec.Template.Spec.Containers = append(rc.Spec.Template.Spec.Containers, container)
		rc.Spec.Selector["app"] = stagespec.Name

		service.ObjectMeta.SetName(stagespec.Name)
		service.ObjectMeta.SetNamespace(piplineMetadata.Namespace)
		service.ObjectMeta.Labels["app"] = stagespec.Name
		service.Spec.Ports = append(service.Spec.Ports, api.ServicePort{Port: stagespec.Port, TargetPort: intstr.FromString(stagespec.Name)})
		service.Spec.Selector["app"] = stagespec.Name

		namespace := &api.Namespace{
			ObjectMeta: api.ObjectMeta{Name: piplineMetadata.Namespace},
		}
		_, err := CLIENT.Namespaces().Create(namespace)
		if err != nil {
			fmt.Errorf("Create namespace err : %v\n", err)
		}

		if _, err = CLIENT.ReplicationControllers(piplineMetadata.Namespace).Create(rc); err != nil {
			fmt.Errorf("Create rc err : %v\n", err)
			return err
		}
		// CLIENT.ReplicationControllers(namespace)

		if _, err := CLIENT.Services(piplineMetadata.Namespace).Create(service); err != nil {
			fmt.Errorf("Create service err : %v\n", err)
			return err
		}
		// namespaces = append(namespaces, piplineMetadata.Namespace)
	}

	// namespaces := convert(pm, pss, rc, service)
	/*
		if _, err = CLIENT.ReplicationControllers(namespace).Create(rc); err != nil {
			fmt.Errorf("Create rc err : %v\n", err)
			return err
		}

		if _, err := CLIENT.Services(namespace).Create(service); err != nil {
			fmt.Errorf("Create service err : %v\n", err)
			return err
		}*/
	// writeBack(rcRes, serviceRes, &pvm, &pvs)
	return nil
}

/*func convert(piplineMetadata models.PipelineMetaData, stagespecs []models.StageSpec,
rcRes *[]api.ReplicationController, serviceRes *[]api.Service) []string {
namespaces := make([]string)

for i, stagespec := range stagespecs {
	rc := api.ReplicationController{}
	service := api.Service{}
	container := api.Container{}

	rc.SetName(stagespec.Name)
	rc.SetNamespace(piplineMetadata.Namespace)
	rc.Labels["app"] = stagespec.Name
	rc.Spec.Replicas = stagespec.Replicsas
	rc.Spec.Template.SetName(stagespec.Name)
	rc.Spec.Template.Labels["app"] = stagespec.Name
	container.Ports = append(container.Ports, api.ContainerPort{Name: stagespec.Name, ContainerPort: stagespec.Port})
	container.Name = stagespec.Name
	container.Image = stagespec.Image
	rc.Spec.Template.Spec.Containers[i] = append(rc.Spec.Template.Spec.Containers[i], container)
	rc.Spec.Selector["app"] = stagespec.Name

	service.ObjectMeta.SetName(stagespec.Name)
	service.ObjectMeta.SetNamespace(piplineMetadata.Namespace)
	service.ObjectMeta.Labels["app"] = stagespec.Name
	service.Spec.Ports = append(service.Spec.Ports, api.ServicePort{Port: stagespec.Port, TargetPort: intstr.FromString(stagespec.Name)})
	service.Spec.Selector["app"] = stagespec.Name

	*rcRes = append(*rcRes, rc)
	*serviceRes = append(*serviceRes, service)
	namespaces = append(namespaces, piplineMetadata.Namespace)
}
*/
/*rcRes.Name = piplineSpec.name

rcRes.Namespace = piplineMetadata.namespace
//Use map["rc"] = Spec.name for temprory`
rcRes.Labels["rc"] = piplineSpec.name
rcRes.Spec.Replicas = piplineSpec.replicas
rcRes.Spec.Template.Name = piplineSpec.name
rcRes.Spec.Template.Labels["pod"] = piplineSpec.name
rcRes.Spec.Template.Namespace = piplineMetadata.namespace
rcRes.Spec.Template.Spec.Containers[0].Name = piplineSpec.name
rcRes.Spec.Template.Spec.Containers[0].Image = piplineSpec.imageName
rcRes.Spec.Template.Spec.Containers[0].Ports[0].Name = piplineSpec.name
rcRes.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort = piplineSpec.port
rcRes.Spec.Selector["app"] = piplineSpec.name

serviceRes.ObjectMeta.Name = piplineSpec.name
serviceRes.ObjectMeta.Namespace = piplineMetadata.namespace
serviceRes.ObjectMeta.Labels["service"] = piplineSpec.name
serviceRes.Spec.Ports[0].Port = piplineSpec.port
serviceRes.Spec.Ports[0].TargetPort = intstr.FromString(piplineSpec.name)
serviceRes.Spec.Selector["app"] = piplineSpec.name*/

/*
func split(pv *PipelineVersion, pvm *piplineMetadata, pvs *piplineSpec) error {
	err := json.Unmarshal([]byte(pv.MetaData), pvm)
	if err != nil {
		fmt.Errorf("Unmarshal PipelineVersion.ObjectMeta err : %v\n", err)
		return err
	}

	err = json.Unmarshal([]byte(pv.Spec), pvs)
	if err != nil {
		fmt.Errorf("Unmarshal PipelineVersion.Spec err : %v\n", err)
		return err
	}
	return nil
}
*/

/*func split(pipeline PiplelineInterface, pvm *piplineMetadata, pvs *piplineSpec) error {
	err := json.Unmarshal([]byte(pipeline.GetMetadata()), pvm)
	if err != nil {
		fmt.Errorf("Unmarshal pipeline.GetMetadata() err : %v\n", err)
		return err
	}

	err = json.Unmarshal([]byte(pipeline.GetSpec()), pvs)
	if err != nil {
		fmt.Errorf("Unmarshal pipeline.GetSpec() err : %v\n", err)
		return err
	}
	return nil
}*/

/*
rcRes = &api.ReplicationController{
		ObjectMeta: api.ObjectMeta{
			Name:      piplineSpec.Name,
			Namespace: piplineMetadata.Namespace,
			Labels: map[string]string{
				"app": piplineSpec.Name,
			},
		},
		Spec: api.ReplicationControllerSpec{
			Replicas: piplineSpec.Replicas,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name: piplineSpec.Name,
					Labels: map[string]string{
						"app": piplineSpec.Name,
					},
					Namespace: piplineMetadata.Namespace,
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						api.Container{
							Name:  piplineSpec.Name,
							Image: piplineSpec.ImageName,
							Ports: []api.ContainerPort{
								api.ContainerPort{
									Name:          piplineSpec.Name,
									ContainerPort: piplineSpec.Port,
								},
							},
						},
					},
				},
			},
			Selector: map[string]string{
				"app": piplineSpec.Name,
			},
		},
	}
*/
<commit_msg>runnable version for kube start<commit_after>package kubernetes

import (
	// "encoding/json"
	"fmt"

	"github.com/containerops/vessel/models"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/util/intstr"
)

/*Whole obj init for template, lay here for using with develop
rcRes = &api.ReplicationController{
		ObjectMeta: api.ObjectMeta{
			Name:      piplineSpec.Name,
			Namespace: piplineMetadata.Namespace,
			Labels: map[string]string{
				"app": piplineSpec.Name,
			},
		},
		Spec: api.ReplicationControllerSpec{
			Replicas: piplineSpec.Replicas,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name: piplineSpec.Name,
					Labels: map[string]string{
						"app": piplineSpec.Name,
					},
					Namespace: piplineMetadata.Namespace,
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						api.Container{
							Name:  piplineSpec.Name,
							Image: piplineSpec.ImageName,
							Ports: []api.ContainerPort{
								api.ContainerPort{
									Name:          piplineSpec.Name,
									ContainerPort: piplineSpec.Port,
								},
							},
						},
					},
				},
			},
			Selector: map[string]string{
				"app": piplineSpec.Name,
			},
		},
	}
*/

/*
	serviceRes = &api.Service{
		ObjectMeta: api.ObjectMeta{
			Name:      piplineSpec.Name,
			Namespace: piplineMetadata.Namespace,
			Labels: map[string]string{
				"app": piplineSpec.Name,
			},
		},
		Spec: api.ServiceSpec{
			Ports: []api.ServicePort{
				api.ServicePort{
					Port:       piplineSpec.Port,
					TargetPort: intstr.FromString(piplineSpec.Name),
				},
			},
			Selector: map[string]string{
				"app": piplineSpec.Name,
			},
		},
	}
*/

/*
namespace := &api.Namespace{
		ObjectMeta: api.ObjectMeta{Name: "foo"},
	}
	c := &simple.Client{
		Request: simple.Request{
			Method: "POST",
			Path:   testapi.Default.ResourcePath("namespaces", "", ""),
			Body:   namespace,
		},
		Response: simple.Response{StatusCode: 200, Body: namespace},
	}

	// from the source ns, provision a new global namespace "foo"
	response, err := c.Setup(t).Namespaces().Create(namespace)
*/
func StartK8SResource(pipelineversion *models.PipelineVersion) error {
	piplineMetadata := pipelineversion.MetaData
	stagespecs := pipelineversion.StageSpecs
	for _, stagespec := range stagespecs {
		rc := &api.ReplicationController{
			ObjectMeta: api.ObjectMeta{
				Labels: map[string]string{},
			},
			Spec: api.ReplicationControllerSpec{
				Template: &api.PodTemplateSpec{
					ObjectMeta: api.ObjectMeta{
						Labels: map[string]string{},
					},
				},
				Selector: map[string]string{},
			},
		}

		service := &api.Service{
			ObjectMeta: api.ObjectMeta{
				Labels: map[string]string{},
			},
			Spec: api.ServiceSpec{
				Selector: map[string]string{},
			},
		}
		rc.Spec.Template.Spec.Containers = make([]api.Container, 1)
		service.Spec.Ports = make([]api.ServicePort, 1)

		rc.SetName(stagespec.Name)
		// rc.SetNamespace(api.NamespaceDefault)
		rc.SetNamespace(piplineMetadata.Namespace)
		rc.Labels["app"] = stagespec.Name
		rc.Spec.Replicas = stagespec.Replicas
		rc.Spec.Template.SetName(stagespec.Name)
		rc.Spec.Template.Labels["app"] = stagespec.Name
		rc.Spec.Template.Spec.Containers[0] = api.Container{Ports: []api.ContainerPort{api.ContainerPort{
			Name:          stagespec.Name,
			ContainerPort: stagespec.Port}},
			Name:  stagespec.Name,
			Image: stagespec.Image}
		rc.Spec.Selector["app"] = stagespec.Name

		service.ObjectMeta.SetName(stagespec.Name)
		// service.ObjectMeta.SetNamespace(api.NamespaceDefault)
		service.ObjectMeta.SetNamespace(piplineMetadata.Namespace)
		service.ObjectMeta.Labels["app"] = stagespec.Name
		service.Spec.Ports[0] = api.ServicePort{Port: stagespec.Port, TargetPort: intstr.FromString(stagespec.Name)}
		service.Spec.Selector["app"] = stagespec.Name

		/*Conver to json string for debug

		a, err := json.Marshal(rc)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(string(a))
		}*/

		/*
			Going to support create namespace after we have namespace watch lib
			_, err := CLIENT.Namespaces().Get(piplineMetadata.Namespace)
			if err != nil {
				namespaceObj := &api.Namespace{
					ObjectMeta: api.ObjectMeta{Name: piplineMetadata.Namespace},
				}
				if _, err := CLIENT.Namespaces().Create(namespaceObj); err != nil {
					fmt.Errorf("Create namespace err : %v\n", err)
					return err
				}
				fmt.Println("dddddd")
			}*/

		if _, err := CLIENT.ReplicationControllers(piplineMetadata.Namespace).Create(rc); err != nil {
			fmt.Errorf("Create rc err : %v\n", err)
			return err
		}

		if _, err := CLIENT.Services(piplineMetadata.Namespace).Create(service); err != nil {
			fmt.Errorf("Create service err : %v\n", err)
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package ivy

import (
	"bytes"
	"github.com/stretchr/testify/assert"
	"image"
	"image/png"
	"testing"
)

func TestGMProcess(t *testing.T) {
	buffer := new(bytes.Buffer)
	png.Encode(buffer, image.NewRGBA(image.Rect(0, 0, 200, 200)))

	gm := NewGMProcessor()
	params, _ := ParseParams("r_100x100,c_50x50,g_c,q_50")
	img, err := gm.Process(params, "text.png", buffer)
	assert.NoError(t, err)
	assert.NotNil(t, img)
	assert.True(t, img.Len() > 0)
}

func TestGMGetGravity(t *testing.T) {
	gm := NewGMProcessor()
	assert.Equal(t, "NorthWest", gm.getGravity("nw"))
	assert.Equal(t, "North", gm.getGravity("n"))
	assert.Equal(t, "NorthEast", gm.getGravity("ne"))
	assert.Equal(t, "West", gm.getGravity("w"))
	assert.Equal(t, "Center", gm.getGravity("c"))
	assert.Equal(t, "East", gm.getGravity("e"))
	assert.Equal(t, "SouthWest", gm.getGravity("sw"))
	assert.Equal(t, "South", gm.getGravity("s"))
	assert.Equal(t, "SouthEast", gm.getGravity("se"))
	assert.Equal(t, "NorthWest", gm.getGravity("xx"))
}
<commit_msg>add test<commit_after>package ivy

import (
	"bytes"
	"github.com/stretchr/testify/assert"
	"image"
	"image/png"
	"testing"
)

func TestGMProcess(t *testing.T) {
	buffer := new(bytes.Buffer)
	png.Encode(buffer, image.NewRGBA(image.Rect(0, 0, 200, 200)))

	gm := NewGMProcessor()
	params, _ := ParseParams("r_100x100,c_50x50,g_c,q_50")
	img, err := gm.Process(params, "text.png", buffer)
	assert.NoError(t, err)
	assert.NotNil(t, img)
	assert.True(t, img.Len() > 0)

	params, _ = ParseParams("r_100x0,c_50x50,g_c,q_50")
	img, err = gm.Process(params, "text.png", buffer)
	assert.NoError(t, err)
	assert.NotNil(t, img)
	assert.True(t, img.Len() > 0)

	params, _ = ParseParams("r_0x100,c_50x50,g_c,q_50")
	img, err = gm.Process(params, "text.png", buffer)
	assert.NoError(t, err)
	assert.NotNil(t, img)
	assert.True(t, img.Len() > 0)
}

func TestGMGetGravity(t *testing.T) {
	gm := NewGMProcessor()
	assert.Equal(t, "NorthWest", gm.getGravity("nw"))
	assert.Equal(t, "North", gm.getGravity("n"))
	assert.Equal(t, "NorthEast", gm.getGravity("ne"))
	assert.Equal(t, "West", gm.getGravity("w"))
	assert.Equal(t, "Center", gm.getGravity("c"))
	assert.Equal(t, "East", gm.getGravity("e"))
	assert.Equal(t, "SouthWest", gm.getGravity("sw"))
	assert.Equal(t, "South", gm.getGravity("s"))
	assert.Equal(t, "SouthEast", gm.getGravity("se"))
	assert.Equal(t, "NorthWest", gm.getGravity("xx"))
}
<|endoftext|>


<commit_before>package gnuplot

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

type Plotter struct {
	configures map[string]string
}

func (p *Plotter) Init() {
	p.configures = map[string]string{}
}

func (p *Plotter) Configure(key, val string) {
	p.configures[key] = val
}

func (p *Plotter) GetC(key string) string {
	return p.configures[key]
}

var DefaultFunction2dSplitNum int = 1000

type Function2d struct {
	plotter  Plotter
	splitNum int
	f        func(float64) float64
}

func (fun *Function2d) Init() {
	fun.splitNum = DefaultFunction2dSplitNum
	fun.plotter.configures = map[string]string{
		"_xMin": "-10.0",
		"_xMax": "10.0"}
}

func (fun *Function2d) UpdatePlotter(plotter *Plotter) {
	for key, val := range plotter.configures {
		fun.plotter.configures[key] = val
	}
}

func (fun *Function2d) GetData() [][2]float64 { // TODO: テスト書く
	xMin, _ := strconv.ParseFloat(fun.plotter.configures["_xMin"], 32)
	xMax, _ := strconv.ParseFloat(fun.plotter.configures["_xMax"], 32)
	var sep = float64(xMax-xMin) / float64(fun.splitNum-1)

	var a [][2]float64
	for j := 0; j < fun.splitNum; j++ {
		t := xMin + float64(j)*sep
		y := fun.f(t)
		a = append(a, [2]float64{t, y})
	}
	return a
}

func (fun *Function2d) getGnuData() string {
	var s string
	for _, xs := range fun.GetData() {
		s += fmt.Sprintf("%f %f\n", xs[0], xs[1])
	}
	return s
}

func (fun *Function2d) SetF(_f func(float64) float64) {
	fun.f = _f
}

func (fun *Function2d) writeIntoGnufile(f os.File) {
	f.WriteString(fun.getGnuData())
}

var DefaultCurve2dSplitNum int = 100

type Curve2d struct {
	plotter  Plotter
	splitNum int
	c        func(float64) [2]float64
}

func (c *Curve2d) Init() {
	c.splitNum = DefaultCurve2dSplitNum
	c.plotter.configures = map[string]string{
		"_tMin": "-10.0",
		"_tMax": "10.0"}
}

func (c *Curve2d) UpdatePlotter(plotter *Plotter) {
	for key, val := range plotter.configures {
		c.plotter.Configure(key, val)
	}
}

func (c *Curve2d) GetData() [][2]float64 { // TODO: test
	tMin, _ := strconv.ParseFloat(c.plotter.configures["_tMin"], 32)
	tMax, _ := strconv.ParseFloat(c.plotter.configures["_tMax"], 32)
	var sep = float64(tMax-tMin) / float64(c.splitNum-1)

	var a [][2]float64
	for j := 0; j < c.splitNum; j++ {
		var t float64 = tMin + float64(j)*sep
		cs := c.c(tMin + t*float64(j))
		a = append(a, [2]float64{cs[0], cs[1]})
	}
	return a
}

// Graph
type Graph2d struct {
	plotter   Plotter
	functions []Function2d
	curves    []Curve2d
}

func (g *Graph2d) AppendFunc(f Function2d) {
	fmt.Println("before of AppendFunc")
	g.functions = append(g.functions, f)
	fmt.Println("after of AppendFunc")
}

func (g Graph2d) writeIntoFile(data string, f *os.File) {
	f.WriteString(data)
}

func (g Graph2d) exec_gnuplot() {
	// until
}

func (g Graph2d) gnuplot(funcFilenames []string, curveFilenames []string) string {
	var s string
	for j, _ := range g.functions {
		s += fmt.Sprintf("plot %v\n;", funcFilenames[j])
	}
	s += "\n"
	for j, _ := range g.curves {
		s += fmt.Sprintf("plot %v\n;", curveFilenames[j])
	}
	s += "pause -1;"
	s += "\n"
	return s
}

func (g *Graph2d) Run() {
	tmpDir := os.TempDir()

	// それぞれのfunctionのdataをtempファイルに書き込む
	// また, それらのファイルの名前を func_filenames []string に格納する
	var funcFilenames []string
	for _, fun := range g.functions {
		file, _ := ioutil.TempFile(tmpDir, "")
		defer func() {
			file.Close()
		}()
		g.writeIntoFile(fun.getGnuData(), file)
		funcFilenames = append(funcFilenames, file.Name())
	}

	// それぞれのcurveのdataをtempファイルに書き込む
	// また, それらのファイルの名前を curve_filenames []stringに格納する

	// 実行するgnuplotの実行ファイルをtempファイルに書き込む
	exec_file, _ := os.OpenFile("exec_gnu.gnu", os.O_CREATE|os.O_WRONLY, 0666)
	defer func() {
		exec_file.Close()
	}()
	fmt.Println(funcFilenames)
	exec_file.WriteString(fmt.Sprintf("plot \"%v\" w l; pause -1;", funcFilenames[0]))
	exec_file.Close()
}
<commit_msg>interface(getData).gnuplot<commit_after>package gnuplot

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

type Plotter struct {
	configures map[string]string
}

func (p *Plotter) Init() {
	p.configures = map[string]string{}
}

func (p *Plotter) Configure(key, val string) {
	p.configures[key] = val
}

func (p *Plotter) GetC(key string) string {
	return p.configures[key]
}

var DefaultFunction2dSplitNum int = 1000

type Function2d struct {
	plotter  Plotter
	splitNum int
	f        func(float64) float64
}

func (fun *Function2d) Init() {
	fun.splitNum = DefaultFunction2dSplitNum
	fun.plotter.configures = map[string]string{
		"_xMin": "-10.0",
		"_xMax": "10.0"}
}

func (fun *Function2d) UpdatePlotter(plotter *Plotter) {
	for key, val := range plotter.configures {
		fun.plotter.configures[key] = val
	}
}

func (fun *Function2d) GetData() [][2]float64 { // TODO: テスト書く
	xMin, _ := strconv.ParseFloat(fun.plotter.configures["_xMin"], 32)
	xMax, _ := strconv.ParseFloat(fun.plotter.configures["_xMax"], 32)
	var sep = float64(xMax-xMin) / float64(fun.splitNum-1)

	var a [][2]float64
	for j := 0; j < fun.splitNum; j++ {
		t := xMin + float64(j)*sep
		y := fun.f(t)
		a = append(a, [2]float64{t, y})
	}
	return a
}

func (fun *Function2d) getGnuData() string {
	var s string
	for _, xs := range fun.GetData() {
		s += fmt.Sprintf("%f %f\n", xs[0], xs[1])
	}
	return s
}

func (fun *Function2d) SetF(_f func(float64) float64) {
	fun.f = _f
}

func (fun Function2d) gnuplot(filename string) string {
	return fmt.Sprintf("plot %v\n;", filename)
}

func (fun *Function2d) writeIntoGnufile(f os.File) {
	f.WriteString(fun.getGnuData())
}

var DefaultCurve2dSplitNum int = 100

type Curve2d struct {
	plotter  Plotter
	splitNum int
	c        func(float64) [2]float64
}

func (c *Curve2d) Init() {
	c.splitNum = DefaultCurve2dSplitNum
	c.plotter.configures = map[string]string{
		"_tMin": "-10.0",
		"_tMax": "10.0"}
}

func (c *Curve2d) UpdatePlotter(plotter *Plotter) {
	for key, val := range plotter.configures {
		c.plotter.Configure(key, val)
	}
}

func (c *Curve2d) GetData() [][2]float64 { // TODO: test
	tMin, _ := strconv.ParseFloat(c.plotter.configures["_tMin"], 32)
	tMax, _ := strconv.ParseFloat(c.plotter.configures["_tMax"], 32)
	var sep = float64(tMax-tMin) / float64(c.splitNum-1)

	var a [][2]float64
	for j := 0; j < c.splitNum; j++ {
		var t float64 = tMin + float64(j)*sep
		cs := c.c(tMin + t*float64(j))
		a = append(a, [2]float64{cs[0], cs[1]})
	}
	return a
}

func (c Curve2d) gnuplot(fileName string) string {
	return fmt.Sprintf("plot %v\n;", fileName)
}

// Graph
type Graph2d struct {
	plotter   Plotter
	functions []Function2d
	curves    []Curve2d
}

func (g *Graph2d) AppendFunc(f Function2d) {
	fmt.Println("before of AppendFunc")
	g.functions = append(g.functions, f)
	fmt.Println("after of AppendFunc")
}

func (g Graph2d) writeIntoFile(data string, f *os.File) {
	f.WriteString(data)
}

func (g Graph2d) exec_gnuplot() {
	// until
}

func (g Graph2d) gnuplot(funcFilenames []string, curveFilenames []string) string {
	var s string
	for j, _ := range g.functions {
		s += g.functions[j].gnuplot(funcFilenames[j])
	}
	s += "\n"
	for j, _ := range g.curves {
		s += g.curves[j].gnuplot(curveFilenames[j])
	}
	s += "pause -1;"
	s += "\n"
	return s
}

func (g *Graph2d) Run() {
	tmpDir := os.TempDir()

	// それぞれのfunctionのdataをtempファイルに書き込む
	// また, それらのファイルの名前を func_filenames []string に格納する
	var funcFilenames []string
	for _, fun := range g.functions {
		file, _ := ioutil.TempFile(tmpDir, "")
		defer func() {
			file.Close()
		}()
		g.writeIntoFile(fun.getGnuData(), file)
		funcFilenames = append(funcFilenames, file.Name())
	}

	// それぞれのcurveのdataをtempファイルに書き込む
	// また, それらのファイルの名前を curve_filenames []stringに格納する

	// 実行するgnuplotの実行ファイルをtempファイルに書き込む
	exec_file, _ := os.OpenFile("exec_gnu.gnu", os.O_CREATE|os.O_WRONLY, 0666)
	defer func() {
		exec_file.Close()
	}()
	fmt.Println(funcFilenames)
	exec_file.WriteString(fmt.Sprintf("plot \"%v\" w l; pause -1;", funcFilenames[0]))
	exec_file.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/goburrow/modbus"
)

/*
### register mode = standard
=> register address = (mm x 100) + ppp - 1
   where mm <= 162 && ppp <= 99

### register mode = modified
=> register address = (mm x 256) + ppp - 1
   where mm <= 63 && ppp <= 255
*/

type Parameter struct {
	Menu  int
	Index int
	Size  uint16
}

// NewParameterFromMenu creates a parameter from a menu.index string.
func NewParameterFromMenu(menu string) (Parameter, error) {
	var err error
	var p Parameter

	toks := strings.Split(menu, ".")
	m, err := strconv.Atoi(toks[0])
	if err != nil {
		return p, err
	}
	i, err := strconv.Atoi(toks[1])
	if err != nil {
		return p, err
	}
	return Parameter{Menu: m, Index: i, Size: 1}, err
}

// NewParameter creates a parameter from its modbus address register.
func NewParameter(reg uint16) Parameter {
	return Parameter{
		Menu:  int(reg / 100),
		Index: int(reg%100) + 1,
		Size:  1,
	}
}

func (p Parameter) ToModbus() uint16 {
	return uint16(p.Menu*100 + p.Index - 1)
}

func (p Parameter) String() string {
	return fmt.Sprintf("%02d.%03d", p.Menu, p.Index)
}

type Motor struct {
	Address string
	c       modbus.Client
}

func NewMotor(addr string) Motor {
	return Motor{
		Address: addr,
		c:       modbus.TCPClient(addr),
	}
}

func (m *Motor) read(p Parameter) ([]byte, error) {
	o, err := m.c.ReadHoldingRegisters(p.ToModbus(), p.Size)
	if err != nil {
		return nil, err
	}
	return o, err
}

func (m *Motor) write(p Parameter, v []byte) ([]byte, error) {
	return m.c.WriteMultipleRegisters(p.ToModbus(), 1, v)
}
<commit_msg>motor: protect against invalid parameter values<commit_after>package main

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/goburrow/modbus"
)

/*
### register mode = standard
=> register address = (mm x 100) + ppp - 1
   where mm <= 162 && ppp <= 99

### register mode = modified
=> register address = (mm x 256) + ppp - 1
   where mm <= 63 && ppp <= 255
*/

type Parameter struct {
	Menu  int
	Index int
	Size  uint16
}

// NewParameterFromMenu creates a parameter from a menu.index string.
func NewParameterFromMenu(menu string) (Parameter, error) {
	var err error
	var p Parameter

	toks := strings.Split(menu, ".")
	m, err := strconv.Atoi(toks[0])
	if err != nil {
		return p, err
	}
	if m > 162 {
		return p, fmt.Errorf("motor: invalid menu value (%d>162) [pr=%s]", m, menu)
	}

	i, err := strconv.Atoi(toks[1])
	if err != nil {
		return p, err
	}
	if i >= 100 {
		return p, fmt.Errorf("motor: invalid index value (%d>=100) [pr=%s]", i, menu)
	}

	return Parameter{Menu: m, Index: i, Size: 1}, err
}

// NewParameter creates a parameter from its modbus address register.
func NewParameter(reg uint16) Parameter {
	return Parameter{
		Menu:  int(reg / 100),
		Index: int(reg%100) + 1,
		Size:  1,
	}
}

func (p Parameter) ToModbus() uint16 {
	return uint16(p.Menu*100 + p.Index - 1)
}

func (p Parameter) String() string {
	return fmt.Sprintf("%02d.%03d", p.Menu, p.Index)
}

type Motor struct {
	Address string
	c       modbus.Client
}

func NewMotor(addr string) Motor {
	return Motor{
		Address: addr,
		c:       modbus.TCPClient(addr),
	}
}

func (m *Motor) read(p Parameter) ([]byte, error) {
	o, err := m.c.ReadHoldingRegisters(p.ToModbus(), p.Size)
	if err != nil {
		return nil, err
	}
	return o, err
}

func (m *Motor) write(p Parameter, v []byte) ([]byte, error) {
	return m.c.WriteMultipleRegisters(p.ToModbus(), 1, v)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"fmt"

	"strings"

	"strconv"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	. "github.com/claudetech/loggo/default"
	"golang.org/x/net/context"
)

// Mount the fuse volume
func Mount(client *Drive, mountpoint string, mountOptions []string, uid, gid uint32, umask os.FileMode) error {
	Log.Infof("Mounting path %v", mountpoint)

	if _, err := os.Stat(mountpoint); os.IsNotExist(err) {
		Log.Debugf("Mountpoint doesn't exist, creating...")
		if err := os.MkdirAll(mountpoint, 0644); nil != err {
			Log.Debugf("%v", err)
			return fmt.Errorf("Could not create mount directory %v", mountpoint)
		}
	}

	fuse.Debug = func(msg interface{}) {
		Log.Tracef("FUSE %v", msg)
	}

	// Set mount options
	options := []fuse.MountOption{
		fuse.NoAppleDouble(),
		fuse.NoAppleXattr(),
	}
	for _, option := range mountOptions {
		if "allow_other" == option {
			options = append(options, fuse.AllowOther())
		} else if "allow_root" == option {
			options = append(options, fuse.AllowRoot())
		} else if "allow_dev" == option {
			options = append(options, fuse.AllowDev())
		} else if "allow_non_empty_mount" == option {
			options = append(options, fuse.AllowNonEmptyMount())
		} else if "allow_suid" == option {
			options = append(options, fuse.AllowSUID())
		} else if strings.Contains(option, "max_readahead=") {
			data := strings.Split(option, "=")
			value, err := strconv.ParseUint(data[1], 10, 32)
			if nil != err {
				Log.Debugf("%v", err)
				return fmt.Errorf("Could not parse max_readahead value")
			}
			options = append(options, fuse.MaxReadahead(uint32(value)))
		} else if "default_permissions" == option {
			options = append(options, fuse.DefaultPermissions())
		} else if "excl_create" == option {
			options = append(options, fuse.ExclCreate())
		} else if strings.Contains(option, "fs_name") {
			data := strings.Split(option, "=")
			options = append(options, fuse.FSName(data[1]))
		} else if "local_volume" == option {
			options = append(options, fuse.LocalVolume())
		} else if "writeback_cache" == option {
			options = append(options, fuse.WritebackCache())
		} else if strings.Contains(option, "volume_name") {
			data := strings.Split(option, "=")
			options = append(options, fuse.VolumeName(data[1]))
		} else if "read_only" == option {
			options = append(options, fuse.ReadOnly())
		} else {
			Log.Warningf("Fuse option %v is not supported, yet", option)
		}
	}

	c, err := fuse.Mount(mountpoint, options...)
	if err != nil {
		return err
	}
	defer c.Close()

	filesys := &FS{
		client: client,
		uid:    uid,
		gid:    gid,
		umask:  umask,
	}
	if err := fs.Serve(c, filesys); err != nil {
		return err
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Error mounting FUSE")
	}

	return Unmount(mountpoint, true)
}

// Unmount unmounts the mountpoint
func Unmount(mountpoint string, notify bool) error {
	if notify {
		Log.Infof("Unmounting path %v", mountpoint)
	}
	fuse.Unmount(mountpoint)
	return nil
}

// FS the fuse filesystem
type FS struct {
	client *Drive
	uid    uint32
	gid    uint32
	umask  os.FileMode
}

// Root returns the root path
func (f *FS) Root() (fs.Node, error) {
	object, err := f.client.GetRoot()
	if nil != err {
		Log.Warningf("%v", err)
		return nil, fmt.Errorf("Could not get root object")
	}
	return &Object{
		client: f.client,
		object: object,
		uid:    f.uid,
		gid:    f.gid,
		umask:  f.umask,
	}, nil
}

// Object represents one drive object
type Object struct {
	client *Drive
	object *APIObject
	buffer *Buffer
	uid    uint32
	gid    uint32
	umask  os.FileMode
}

// Attr returns the attributes for a directory
func (o *Object) Attr(ctx context.Context, attr *fuse.Attr) error {
	if o.object.IsDir {
		if o.umask > 0 {
			attr.Mode = os.ModeDir | o.umask
		} else {
			attr.Mode = os.ModeDir | 0755
		}
		attr.Size = 0
	} else {
		if o.umask > 0 {
			attr.Mode = o.umask
		} else {
			attr.Mode = 0644
		}
		attr.Size = o.object.Size
	}

	attr.Uid = uint32(o.uid)
	attr.Gid = uint32(o.gid)

	attr.Mtime = o.object.LastModified
	attr.Crtime = o.object.LastModified
	attr.Ctime = o.object.LastModified

	return nil
}

// ReadDirAll shows all files in the current directory
func (o *Object) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	objects, err := o.client.GetObjectsByParent(o.object.ObjectID)
	if nil != err {
		Log.Warningf("%v", err)
		return nil, fuse.ENOENT
	}

	dirs := []fuse.Dirent{}
	for _, object := range objects {
		dirs = append(dirs, fuse.Dirent{
			Name: object.Name,
			Type: fuse.DT_File,
		})
	}
	return dirs, nil
}

// Lookup tests if a file is existent in the current directory
func (o *Object) Lookup(ctx context.Context, name string) (fs.Node, error) {
	object, err := o.client.GetObjectByParentAndName(o.object.ObjectID, name)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fuse.ENOENT
	}

	return &Object{
		client: o.client,
		object: object,
		uid:    o.uid,
		gid:    o.gid,
		umask:  o.umask,
	}, nil
}

// Open opens a file for reading
func (o *Object) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	if req.Dir {
		return o, nil
	}

	buffer, err := o.client.Open(o.object)
	if nil != err {
		Log.Warningf("%v", err)
		return o, fuse.ENOENT
	}
	o.buffer = buffer

	return o, nil
}

// Release a stream
func (o *Object) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
	if nil != o.buffer {
		if err := o.buffer.Close(); nil != err {
			Log.Debugf("%v", err)
			Log.Warningf("Could not close buffer stream")
		}
	}
	return nil
}

// Read reads some bytes or the whole file
func (o *Object) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	buf, err := o.buffer.ReadBytes(req.Offset, int64(req.Size), false, 0)
	if nil != err {
		Log.Warningf("%v", err)
		return fuse.EIO
	}

	resp.Data = buf[:]
	return nil
}

// Remove deletes an element
func (o *Object) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	obj, err := o.client.GetObjectByParentAndName(o.object.ObjectID, req.Name)
	if nil != err {
		Log.Warningf("%v", err)
		return fuse.EIO
	}

	err = o.client.Remove(obj)
	if nil != err {
		Log.Warningf("%v", err)
		return fuse.EIO
	}

	return nil
}
<commit_msg>fixed readbytes call parameter<commit_after>package main

import (
	"os"

	"fmt"

	"strings"

	"strconv"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	. "github.com/claudetech/loggo/default"
	"golang.org/x/net/context"
)

// Mount the fuse volume
func Mount(client *Drive, mountpoint string, mountOptions []string, uid, gid uint32, umask os.FileMode) error {
	Log.Infof("Mounting path %v", mountpoint)

	if _, err := os.Stat(mountpoint); os.IsNotExist(err) {
		Log.Debugf("Mountpoint doesn't exist, creating...")
		if err := os.MkdirAll(mountpoint, 0644); nil != err {
			Log.Debugf("%v", err)
			return fmt.Errorf("Could not create mount directory %v", mountpoint)
		}
	}

	fuse.Debug = func(msg interface{}) {
		Log.Tracef("FUSE %v", msg)
	}

	// Set mount options
	options := []fuse.MountOption{
		fuse.NoAppleDouble(),
		fuse.NoAppleXattr(),
	}
	for _, option := range mountOptions {
		if "allow_other" == option {
			options = append(options, fuse.AllowOther())
		} else if "allow_root" == option {
			options = append(options, fuse.AllowRoot())
		} else if "allow_dev" == option {
			options = append(options, fuse.AllowDev())
		} else if "allow_non_empty_mount" == option {
			options = append(options, fuse.AllowNonEmptyMount())
		} else if "allow_suid" == option {
			options = append(options, fuse.AllowSUID())
		} else if strings.Contains(option, "max_readahead=") {
			data := strings.Split(option, "=")
			value, err := strconv.ParseUint(data[1], 10, 32)
			if nil != err {
				Log.Debugf("%v", err)
				return fmt.Errorf("Could not parse max_readahead value")
			}
			options = append(options, fuse.MaxReadahead(uint32(value)))
		} else if "default_permissions" == option {
			options = append(options, fuse.DefaultPermissions())
		} else if "excl_create" == option {
			options = append(options, fuse.ExclCreate())
		} else if strings.Contains(option, "fs_name") {
			data := strings.Split(option, "=")
			options = append(options, fuse.FSName(data[1]))
		} else if "local_volume" == option {
			options = append(options, fuse.LocalVolume())
		} else if "writeback_cache" == option {
			options = append(options, fuse.WritebackCache())
		} else if strings.Contains(option, "volume_name") {
			data := strings.Split(option, "=")
			options = append(options, fuse.VolumeName(data[1]))
		} else if "read_only" == option {
			options = append(options, fuse.ReadOnly())
		} else {
			Log.Warningf("Fuse option %v is not supported, yet", option)
		}
	}

	c, err := fuse.Mount(mountpoint, options...)
	if err != nil {
		return err
	}
	defer c.Close()

	filesys := &FS{
		client: client,
		uid:    uid,
		gid:    gid,
		umask:  umask,
	}
	if err := fs.Serve(c, filesys); err != nil {
		return err
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Error mounting FUSE")
	}

	return Unmount(mountpoint, true)
}

// Unmount unmounts the mountpoint
func Unmount(mountpoint string, notify bool) error {
	if notify {
		Log.Infof("Unmounting path %v", mountpoint)
	}
	fuse.Unmount(mountpoint)
	return nil
}

// FS the fuse filesystem
type FS struct {
	client *Drive
	uid    uint32
	gid    uint32
	umask  os.FileMode
}

// Root returns the root path
func (f *FS) Root() (fs.Node, error) {
	object, err := f.client.GetRoot()
	if nil != err {
		Log.Warningf("%v", err)
		return nil, fmt.Errorf("Could not get root object")
	}
	return &Object{
		client: f.client,
		object: object,
		uid:    f.uid,
		gid:    f.gid,
		umask:  f.umask,
	}, nil
}

// Object represents one drive object
type Object struct {
	client *Drive
	object *APIObject
	buffer *Buffer
	uid    uint32
	gid    uint32
	umask  os.FileMode
}

// Attr returns the attributes for a directory
func (o *Object) Attr(ctx context.Context, attr *fuse.Attr) error {
	if o.object.IsDir {
		if o.umask > 0 {
			attr.Mode = os.ModeDir | o.umask
		} else {
			attr.Mode = os.ModeDir | 0755
		}
		attr.Size = 0
	} else {
		if o.umask > 0 {
			attr.Mode = o.umask
		} else {
			attr.Mode = 0644
		}
		attr.Size = o.object.Size
	}

	attr.Uid = uint32(o.uid)
	attr.Gid = uint32(o.gid)

	attr.Mtime = o.object.LastModified
	attr.Crtime = o.object.LastModified
	attr.Ctime = o.object.LastModified

	return nil
}

// ReadDirAll shows all files in the current directory
func (o *Object) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	objects, err := o.client.GetObjectsByParent(o.object.ObjectID)
	if nil != err {
		Log.Warningf("%v", err)
		return nil, fuse.ENOENT
	}

	dirs := []fuse.Dirent{}
	for _, object := range objects {
		dirs = append(dirs, fuse.Dirent{
			Name: object.Name,
			Type: fuse.DT_File,
		})
	}
	return dirs, nil
}

// Lookup tests if a file is existent in the current directory
func (o *Object) Lookup(ctx context.Context, name string) (fs.Node, error) {
	object, err := o.client.GetObjectByParentAndName(o.object.ObjectID, name)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fuse.ENOENT
	}

	return &Object{
		client: o.client,
		object: object,
		uid:    o.uid,
		gid:    o.gid,
		umask:  o.umask,
	}, nil
}

// Open opens a file for reading
func (o *Object) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	if req.Dir {
		return o, nil
	}

	buffer, err := o.client.Open(o.object)
	if nil != err {
		Log.Warningf("%v", err)
		return o, fuse.ENOENT
	}
	o.buffer = buffer

	return o, nil
}

// Release a stream
func (o *Object) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
	if nil != o.buffer {
		if err := o.buffer.Close(); nil != err {
			Log.Debugf("%v", err)
			Log.Warningf("Could not close buffer stream")
		}
	}
	return nil
}

// Read reads some bytes or the whole file
func (o *Object) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	buf, err := o.buffer.ReadBytes(req.Offset, int64(req.Size), 0)
	if nil != err {
		Log.Warningf("%v", err)
		return fuse.EIO
	}

	resp.Data = buf[:]
	return nil
}

// Remove deletes an element
func (o *Object) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	obj, err := o.client.GetObjectByParentAndName(o.object.ObjectID, req.Name)
	if nil != err {
		Log.Warningf("%v", err)
		return fuse.EIO
	}

	err = o.client.Remove(obj)
	if nil != err {
		Log.Warningf("%v", err)
		return fuse.EIO
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"

	"github.com/rfjakob/gocryptfs/internal/configfile"
	"github.com/rfjakob/gocryptfs/internal/cryptocore"
	"github.com/rfjakob/gocryptfs/internal/fusefrontend"
	"github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

// doMount mounts an encrypted directory.
// Called from main.
func doMount(args *argContainer) int {
	// Check mountpoint
	var err error
	args.mountpoint, err = filepath.Abs(flagSet.Arg(1))
	if err != nil {
		tlog.Fatal.Printf("Invalid mountpoint: %v", err)
		os.Exit(ErrExitMountPoint)
	}
	// We cannot mount "/home/user/.cipher" at "/home/user" because the mount
	// will hide ".cipher" also for us.
	if args.cipherdir == args.mountpoint || strings.HasPrefix(args.cipherdir, args.mountpoint+"/") {
		tlog.Fatal.Printf("Mountpoint %q would shadow cipherdir %q, this is not supported",
			args.mountpoint, args.cipherdir)
		os.Exit(ErrExitMountPoint)
	}
	if args.nonempty {
		err = checkDir(args.mountpoint)
	} else {
		err = checkDirEmpty(args.mountpoint)
	}
	if err != nil {
		tlog.Fatal.Printf("Invalid mountpoint: %v", err)
		os.Exit(ErrExitMountPoint)
	}
	// Get master key
	var masterkey []byte
	var confFile *configfile.ConfFile
	if args.masterkey != "" {
		// "-masterkey"
		masterkey = parseMasterKey(args.masterkey)
	} else if args.zerokey {
		// "-zerokey"
		tlog.Info.Printf("Using all-zero dummy master key.")
		tlog.Info.Printf(tlog.ColorYellow +
			"ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING." +
			tlog.ColorReset)
		masterkey = make([]byte, cryptocore.KeyLen)
	} else {
		// Load master key from config file
		masterkey, confFile = loadConfig(args)
		printMasterKey(masterkey)
	}
	// Initialize FUSE server
	tlog.Debug.Printf("cli args: %v", args)
	srv := initFuseFrontend(masterkey, args, confFile)
	tlog.Info.Println(tlog.ColorGreen + "Filesystem mounted and ready." + tlog.ColorReset)
	// We have been forked into the background, as evidenced by the set
	// "notifypid".
	var paniclog *os.File
	if args.notifypid > 0 {
		// Chdir to the root directory so we don't block unmounting the CWD
		os.Chdir("/")
		// Switch to syslog
		if !args.nosyslog {
			paniclog, err = ioutil.TempFile("", "gocryptfs_paniclog.")
			if err != nil {
				tlog.Fatal.Printf("Failed to create gocryptfs_paniclog: %v", err)
				os.Exit(ErrExitMount)
			}
			// Switch all of our logs and the generic logger to syslog
			tlog.Info.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_INFO)
			tlog.Debug.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_DEBUG)
			tlog.Warn.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_WARNING)
			tlog.SwitchLoggerToSyslog(syslog.LOG_USER | syslog.LOG_WARNING)
			// Daemons should close all fds (and we don't want to get killed by
			// SIGPIPE if any of those get closed on the other end)
			os.Stdin.Close()
			// Redirect stdout and stderr to /tmp/gocryptfs_paniclog.NNNNNN
			// instead of closing them so users have a chance to get the
			// backtrace on a panic.
			// https://github.com/golang/go/issues/325#issuecomment-66049178
			syscall.Dup2(int(paniclog.Fd()), 1)
			syscall.Dup2(int(paniclog.Fd()), 2)
		}
		// Send SIGUSR1 to our parent
		sendUsr1(args.notifypid)
	}
	// Wait for SIGINT in the background and unmount ourselves if we get it.
	// This prevents a dangling "Transport endpoint is not connected"
	// mountpoint if the user hits CTRL-C.
	handleSigint(srv, args.mountpoint)
	// Jump into server loop. Returns when it gets an umount request from the kernel.
	srv.Serve()
	// Delete empty paniclogs
	if paniclog != nil {
		fi, err := paniclog.Stat()
		if err != nil {
			tlog.Warn.Printf("paniclog fstat error: %v", err)
		} else if fi.Size() > 0 {
			tlog.Warn.Printf("paniclog at %q is not empty (size %d). Not deleting it.",
				paniclog.Name(), fi.Size())
		} else {
			syscall.Unlink(paniclog.Name())
		}
	}
	return 0
}

// initFuseFrontend - initialize gocryptfs/fusefrontend
// Calls os.Exit on errors
func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server {
	// Reconciliate CLI and config file arguments into a fusefrontend.Args struct
	// that is passed to the filesystem implementation
	cryptoBackend := cryptocore.BackendGoGCM
	if args.openssl {
		cryptoBackend = cryptocore.BackendOpenSSL
	}
	if args.aessiv {
		cryptoBackend = cryptocore.BackendAESSIV
	}
	frontendArgs := fusefrontend.Args{
		Cipherdir:      args.cipherdir,
		Masterkey:      key,
		PlaintextNames: args.plaintextnames,
		LongNames:      args.longnames,
		CryptoBackend:  cryptoBackend,
		ConfigCustom:   args._configCustom,
	}
	// confFile is nil when "-zerokey" or "-masterkey" was used
	if confFile != nil {
		// Settings from the config file override command line args
		frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames)
		if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
			frontendArgs.CryptoBackend = cryptocore.BackendAESSIV
		} else if args.reverse {
			tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file")
			os.Exit(ErrExitUsage)
		}
	}
	// If allow_other is set and we run as root, try to give newly created files to
	// the right user.
	if args.allow_other && os.Getuid() == 0 {
		frontendArgs.PreserveOwner = true
	}
	jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t")
	tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes))
	var finalFs pathfs.FileSystem
	if args.reverse {
		finalFs = fusefrontend_reverse.NewFS(frontendArgs)
	} else {
		finalFs = fusefrontend.NewFS(frontendArgs)
	}
	pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
	pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
	fuseOpts := &nodefs.Options{
		// These options are to be compatible with libfuse defaults,
		// making benchmarking easier.
		NegativeTimeout: time.Second,
		AttrTimeout:     time.Second,
		EntryTimeout:    time.Second,
	}
	conn := nodefs.NewFileSystemConnector(pathFs.Root(), fuseOpts)
	var mOpts fuse.MountOptions
	mOpts.AllowOther = false
	if args.allow_other {
		tlog.Info.Printf(tlog.ColorYellow + "The option \"-allow_other\" is set. Make sure the file " +
			"permissions protect your data from unwanted access." + tlog.ColorReset)
		mOpts.AllowOther = true
		// Make the kernel check the file permissions for us
		mOpts.Options = append(mOpts.Options, "default_permissions")
	}
	if args.nonempty {
		mOpts.Options = append(mOpts.Options, "nonempty")
	}
	// Set values shown in "df -T" and friends
	// First column, "Filesystem"
	mOpts.Options = append(mOpts.Options, "fsname="+args.cipherdir)
	// Second column, "Type", will be shown as "fuse." + Name
	mOpts.Name = "gocryptfs"
	if args.reverse {
		mOpts.Name += "-reverse"
	}

	// The kernel enforces read-only operation, we just have to pass "ro".
	// Reverse mounts are always read-only
	if args.ro || args.reverse {
		mOpts.Options = append(mOpts.Options, "ro")
	}
	// Add additional mount options (if any) after the stock ones, so the user has
	// a chance to override them.
	if args.ko != "" {
		parts := strings.Split(args.ko, ",")
		tlog.Debug.Printf("Adding -ko mount options: %v", parts)
		mOpts.Options = append(mOpts.Options, parts...)
	}
	srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts)
	if err != nil {
		tlog.Fatal.Printf("Mount failed: %v", err)
		os.Exit(ErrExitMount)
	}
	srv.SetDebug(args.fusedebug)

	// All FUSE file and directory create calls carry explicit permission
	// information. We need an unrestricted umask to create the files and
	// directories with the requested permissions.
	syscall.Umask(0000)

	return srv
}

func handleSigint(srv *fuse.Server, mountpoint string) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	signal.Notify(ch, syscall.SIGTERM)
	go func() {
		<-ch
		err := srv.Unmount()
		if err != nil {
			tlog.Warn.Print(err)
			tlog.Info.Printf("Trying lazy unmount")
			cmd := exec.Command("fusermount", "-u", "-z", mountpoint)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Run()
		}
		os.Exit(1)
	}()
}
<commit_msg>main: print "args" slightly prettier<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"

	"github.com/rfjakob/gocryptfs/internal/configfile"
	"github.com/rfjakob/gocryptfs/internal/cryptocore"
	"github.com/rfjakob/gocryptfs/internal/fusefrontend"
	"github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

// doMount mounts an encrypted directory.
// Called from main.
func doMount(args *argContainer) int {
	// Check mountpoint
	var err error
	args.mountpoint, err = filepath.Abs(flagSet.Arg(1))
	if err != nil {
		tlog.Fatal.Printf("Invalid mountpoint: %v", err)
		os.Exit(ErrExitMountPoint)
	}
	// We cannot mount "/home/user/.cipher" at "/home/user" because the mount
	// will hide ".cipher" also for us.
	if args.cipherdir == args.mountpoint || strings.HasPrefix(args.cipherdir, args.mountpoint+"/") {
		tlog.Fatal.Printf("Mountpoint %q would shadow cipherdir %q, this is not supported",
			args.mountpoint, args.cipherdir)
		os.Exit(ErrExitMountPoint)
	}
	if args.nonempty {
		err = checkDir(args.mountpoint)
	} else {
		err = checkDirEmpty(args.mountpoint)
	}
	if err != nil {
		tlog.Fatal.Printf("Invalid mountpoint: %v", err)
		os.Exit(ErrExitMountPoint)
	}
	// Get master key
	var masterkey []byte
	var confFile *configfile.ConfFile
	if args.masterkey != "" {
		// "-masterkey"
		masterkey = parseMasterKey(args.masterkey)
	} else if args.zerokey {
		// "-zerokey"
		tlog.Info.Printf("Using all-zero dummy master key.")
		tlog.Info.Printf(tlog.ColorYellow +
			"ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING." +
			tlog.ColorReset)
		masterkey = make([]byte, cryptocore.KeyLen)
	} else {
		// Load master key from config file
		masterkey, confFile = loadConfig(args)
		printMasterKey(masterkey)
	}
	// We cannot use JSON for pretty-printing as the fields are unexported
	tlog.Debug.Printf("cli args: %#v", args)
	// Initialize FUSE server
	srv := initFuseFrontend(masterkey, args, confFile)
	tlog.Info.Println(tlog.ColorGreen + "Filesystem mounted and ready." + tlog.ColorReset)
	// We have been forked into the background, as evidenced by the set
	// "notifypid".
	var paniclog *os.File
	if args.notifypid > 0 {
		// Chdir to the root directory so we don't block unmounting the CWD
		os.Chdir("/")
		// Switch to syslog
		if !args.nosyslog {
			paniclog, err = ioutil.TempFile("", "gocryptfs_paniclog.")
			if err != nil {
				tlog.Fatal.Printf("Failed to create gocryptfs_paniclog: %v", err)
				os.Exit(ErrExitMount)
			}
			// Switch all of our logs and the generic logger to syslog
			tlog.Info.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_INFO)
			tlog.Debug.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_DEBUG)
			tlog.Warn.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_WARNING)
			tlog.SwitchLoggerToSyslog(syslog.LOG_USER | syslog.LOG_WARNING)
			// Daemons should close all fds (and we don't want to get killed by
			// SIGPIPE if any of those get closed on the other end)
			os.Stdin.Close()
			// Redirect stdout and stderr to /tmp/gocryptfs_paniclog.NNNNNN
			// instead of closing them so users have a chance to get the
			// backtrace on a panic.
			// https://github.com/golang/go/issues/325#issuecomment-66049178
			syscall.Dup2(int(paniclog.Fd()), 1)
			syscall.Dup2(int(paniclog.Fd()), 2)
		}
		// Send SIGUSR1 to our parent
		sendUsr1(args.notifypid)
	}
	// Wait for SIGINT in the background and unmount ourselves if we get it.
	// This prevents a dangling "Transport endpoint is not connected"
	// mountpoint if the user hits CTRL-C.
	handleSigint(srv, args.mountpoint)
	// Jump into server loop. Returns when it gets an umount request from the kernel.
	srv.Serve()
	// Delete empty paniclogs
	if paniclog != nil {
		fi, err := paniclog.Stat()
		if err != nil {
			tlog.Warn.Printf("paniclog fstat error: %v", err)
		} else if fi.Size() > 0 {
			tlog.Warn.Printf("paniclog at %q is not empty (size %d). Not deleting it.",
				paniclog.Name(), fi.Size())
		} else {
			syscall.Unlink(paniclog.Name())
		}
	}
	return 0
}

// initFuseFrontend - initialize gocryptfs/fusefrontend
// Calls os.Exit on errors
func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server {
	// Reconciliate CLI and config file arguments into a fusefrontend.Args struct
	// that is passed to the filesystem implementation
	cryptoBackend := cryptocore.BackendGoGCM
	if args.openssl {
		cryptoBackend = cryptocore.BackendOpenSSL
	}
	if args.aessiv {
		cryptoBackend = cryptocore.BackendAESSIV
	}
	frontendArgs := fusefrontend.Args{
		Cipherdir:      args.cipherdir,
		Masterkey:      key,
		PlaintextNames: args.plaintextnames,
		LongNames:      args.longnames,
		CryptoBackend:  cryptoBackend,
		ConfigCustom:   args._configCustom,
	}
	// confFile is nil when "-zerokey" or "-masterkey" was used
	if confFile != nil {
		// Settings from the config file override command line args
		frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames)
		if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
			frontendArgs.CryptoBackend = cryptocore.BackendAESSIV
		} else if args.reverse {
			tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file")
			os.Exit(ErrExitUsage)
		}
	}
	// If allow_other is set and we run as root, try to give newly created files to
	// the right user.
	if args.allow_other && os.Getuid() == 0 {
		frontendArgs.PreserveOwner = true
	}
	jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t")
	tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes))
	var finalFs pathfs.FileSystem
	if args.reverse {
		finalFs = fusefrontend_reverse.NewFS(frontendArgs)
	} else {
		finalFs = fusefrontend.NewFS(frontendArgs)
	}
	pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
	pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)
	fuseOpts := &nodefs.Options{
		// These options are to be compatible with libfuse defaults,
		// making benchmarking easier.
		NegativeTimeout: time.Second,
		AttrTimeout:     time.Second,
		EntryTimeout:    time.Second,
	}
	conn := nodefs.NewFileSystemConnector(pathFs.Root(), fuseOpts)
	var mOpts fuse.MountOptions
	mOpts.AllowOther = false
	if args.allow_other {
		tlog.Info.Printf(tlog.ColorYellow + "The option \"-allow_other\" is set. Make sure the file " +
			"permissions protect your data from unwanted access." + tlog.ColorReset)
		mOpts.AllowOther = true
		// Make the kernel check the file permissions for us
		mOpts.Options = append(mOpts.Options, "default_permissions")
	}
	if args.nonempty {
		mOpts.Options = append(mOpts.Options, "nonempty")
	}
	// Set values shown in "df -T" and friends
	// First column, "Filesystem"
	mOpts.Options = append(mOpts.Options, "fsname="+args.cipherdir)
	// Second column, "Type", will be shown as "fuse." + Name
	mOpts.Name = "gocryptfs"
	if args.reverse {
		mOpts.Name += "-reverse"
	}

	// The kernel enforces read-only operation, we just have to pass "ro".
	// Reverse mounts are always read-only
	if args.ro || args.reverse {
		mOpts.Options = append(mOpts.Options, "ro")
	}
	// Add additional mount options (if any) after the stock ones, so the user has
	// a chance to override them.
	if args.ko != "" {
		parts := strings.Split(args.ko, ",")
		tlog.Debug.Printf("Adding -ko mount options: %v", parts)
		mOpts.Options = append(mOpts.Options, parts...)
	}
	srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts)
	if err != nil {
		tlog.Fatal.Printf("Mount failed: %v", err)
		os.Exit(ErrExitMount)
	}
	srv.SetDebug(args.fusedebug)

	// All FUSE file and directory create calls carry explicit permission
	// information. We need an unrestricted umask to create the files and
	// directories with the requested permissions.
	syscall.Umask(0000)

	return srv
}

func handleSigint(srv *fuse.Server, mountpoint string) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	signal.Notify(ch, syscall.SIGTERM)
	go func() {
		<-ch
		err := srv.Unmount()
		if err != nil {
			tlog.Warn.Print(err)
			tlog.Info.Printf("Trying lazy unmount")
			cmd := exec.Command("fusermount", "-u", "-z", mountpoint)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Run()
		}
		os.Exit(1)
	}()
}
<|endoftext|>


<commit_before>package dht

import (
	"context"
	"io"

	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
	mstream "github.com/multiformats/go-multistream"
)

// netNotifiee defines methods to be used with the IpfsDHT
type netNotifiee IpfsDHT

func (nn *netNotifiee) DHT() *IpfsDHT {
	return (*IpfsDHT)(nn)
}

type peerTracker struct {
	refcount int
	cancel   func()
}

func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
	dht := nn.DHT()
	select {
	case <-dht.Process().Closing():
		return
	default:
	}

	dht.plk.Lock()
	defer dht.plk.Unlock()

	conn, ok := nn.peers[v.RemotePeer()]
	if ok {
		conn.refcount += 1
		return
	}

	ctx, cancel := context.WithCancel(dht.Context())

	nn.peers[v.RemotePeer()] = &peerTracker{
		refcount: 1,
		cancel:   cancel,
	}

	go func() {

		// Note: We *could* just check the peerstore to see if the remote side supports the dht
		// protocol, but its not clear that that information will make it into the peerstore
		// by the time this notification is sent. So just to be very careful, we brute force this
		// and open a new stream

		for {
			s, err := dht.host.NewStream(ctx, v.RemotePeer(), ProtocolDHT, ProtocolDHTOld)

			// Canceled.
			if ctx.Err() != nil {
				return
			}

			switch err {
			case nil:
				s.Close()
				dht.plk.Lock()
				defer dht.plk.Unlock()

				// Check if canceled again under the lock.
				if ctx.Err() == nil {
					dht.Update(dht.Context(), v.RemotePeer())
				}
			case io.EOF:
				// Connection died but we may still have *an* open connection so try again.
				continue
			case mstream.ErrNotSupported:
				// Client mode only, don't bother adding them to our routing table
			default:
				// real error? thats odd
				log.Errorf("checking dht client type: %s", err)
			}
			return
		}
	}()
}

func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
	dht := nn.DHT()
	select {
	case <-dht.Process().Closing():
		return
	default:
	}

	dht.plk.Lock()
	defer dht.plk.Unlock()

	conn, ok := nn.peers[v.RemotePeer()]
	if !ok {
		// Unmatched disconnects are fine. It just means that we were
		// already connected when we registered the listener.
		return
	}
	conn.refcount -= 1
	if conn.refcount == 0 {
		delete(nn.peers, v.RemotePeer())
		conn.cancel()
		dht.routingTable.Remove(v.RemotePeer())
	}
}

func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {}
func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {}
func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr)      {}
func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}
<commit_msg>fix race condition where we might not close an opened stream.<commit_after>package dht

import (
	"context"
	"io"

	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
	mstream "github.com/multiformats/go-multistream"
)

// netNotifiee defines methods to be used with the IpfsDHT
type netNotifiee IpfsDHT

func (nn *netNotifiee) DHT() *IpfsDHT {
	return (*IpfsDHT)(nn)
}

type peerTracker struct {
	refcount int
	cancel   func()
}

func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
	dht := nn.DHT()
	select {
	case <-dht.Process().Closing():
		return
	default:
	}

	dht.plk.Lock()
	defer dht.plk.Unlock()

	conn, ok := nn.peers[v.RemotePeer()]
	if ok {
		conn.refcount += 1
		return
	}

	ctx, cancel := context.WithCancel(dht.Context())

	nn.peers[v.RemotePeer()] = &peerTracker{
		refcount: 1,
		cancel:   cancel,
	}

	go func() {

		// Note: We *could* just check the peerstore to see if the remote side supports the dht
		// protocol, but its not clear that that information will make it into the peerstore
		// by the time this notification is sent. So just to be very careful, we brute force this
		// and open a new stream

		for {
			s, err := dht.host.NewStream(ctx, v.RemotePeer(), ProtocolDHT, ProtocolDHTOld)

			switch err {
			case nil:
				s.Close()
				dht.plk.Lock()
				defer dht.plk.Unlock()

				// Check if canceled under the lock.
				if ctx.Err() == nil {
					dht.Update(dht.Context(), v.RemotePeer())
				}
			case io.EOF:
				if ctx.Err() == nil {
					// Connection died but we may still have *an* open connection (context not canceled) so try again.
					continue
				}
			case mstream.ErrNotSupported:
				// Client mode only, don't bother adding them to our routing table
			default:
				// real error? thats odd
				log.Errorf("checking dht client type: %s", err)
			}
			return
		}
	}()
}

func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
	dht := nn.DHT()
	select {
	case <-dht.Process().Closing():
		return
	default:
	}

	dht.plk.Lock()
	defer dht.plk.Unlock()

	conn, ok := nn.peers[v.RemotePeer()]
	if !ok {
		// Unmatched disconnects are fine. It just means that we were
		// already connected when we registered the listener.
		return
	}
	conn.refcount -= 1
	if conn.refcount == 0 {
		delete(nn.peers, v.RemotePeer())
		conn.cancel()
		dht.routingTable.Remove(v.RemotePeer())
	}
}

func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {}
func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {}
func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr)      {}
func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}
<|endoftext|>


<commit_before>/*
Package goevent is event dispatcher.

Listen for event:

    e := goevent.New()
    e.On(func(i int, s string){
      fmt.Printf("%d: %s\n", i, s)
    })

Trigger:

    e.Trigger(1, "foo")

Use event table:

    table := goevent.NewTable()
    table.On("foo", func(i int){
      fmt.Printf("foo: %d\n", i)
    })
    table.On("bar", func(s string){
      fmt.Printf("bar: %s\n", s)
    })

    table.Trigger("foo", 1)
    table.Trigger("bar", "hoge")
    table.Trigger("bar", 38)    // retrun error
*/
package goevent

import (
	"fmt"
	"reflect"
	"sync"
)

// Event is an event.
type Event interface {
	Trigger(args ...interface{}) error
	// f is a function
	On(f interface{}) error
	Off(f interface{}) error
}

type event struct {
	// listeners are listener functions.
	listeners []reflect.Value
	lmu       sync.RWMutex

	argTypes []reflect.Type
	tmu      sync.RWMutex
}

// New creates a new event.
func New() Event {
	return &event{}
}

var _ Event = New()

func (p *event) Trigger(args ...interface{}) error {
	p.lmu.Lock()
	defer p.lmu.Unlock()

	arguments := make([]reflect.Value, 0, len(args))
	argTypes := make([]reflect.Type, 0, len(args))
	for _, v := range args {
		arguments = append(arguments, reflect.ValueOf(v))
		argTypes = append(argTypes, reflect.TypeOf(v))
	}

	err := p.validateArgs(argTypes)
	if err != nil {
		return err
	}

	wg := sync.WaitGroup{}
	wg.Add(len(p.listeners))
	for _, fn := range p.listeners {
		go func(f reflect.Value) {
			defer wg.Done()
			f.Call(arguments)
		}(fn)
	}

	wg.Wait()
	return nil
}

// Start to listen an event.
func (p *event) On(f interface{}) error {
	fn, err := p.checkFuncSignature(f)
	if err != nil {
		return err
	}

	p.lmu.Lock()
	defer p.lmu.Unlock()
	p.listeners = append(p.listeners, *fn)

	return nil
}

// Stop listening an event.
func (p *event) Off(f interface{}) error {
	fn := reflect.ValueOf(f)

	p.lmu.Lock()
	defer p.lmu.Unlock()
	l := len(p.listeners)
	m := l // for error check
	for i := 0; i < l; i++ {
		if fn == p.listeners[i] {
			// XXX: GC Ref: http://jxck.hatenablog.com/entry/golang-slice-internals
			p.listeners = append(p.listeners[:i], p.listeners[i+1:]...)
			l--
			i--
		}
	}

	if l == m {
		return fmt.Errorf("Listener does't exists")
	}
	return nil
}

// retrun function as reflect.Value
// retrun error if f isn't function, argument is invalid
func (p *event) checkFuncSignature(f interface{}) (*reflect.Value, error) {
	fn := reflect.ValueOf(f)
	if fn.Kind() != reflect.Func {
		return nil, fmt.Errorf("Argument should be a function")
	}

	types := fnArgTypes(fn)

	p.lmu.RLock()
	defer p.lmu.RUnlock()
	if len(p.listeners) == 0 {
		p.tmu.Lock()
		defer p.tmu.Unlock()
		p.argTypes = types
		return &fn, nil
	}

	err := p.validateArgs(types)
	if err != nil {
		return nil, err
	}

	return &fn, nil
}

// if argument size or type are different return error.
func (p *event) validateArgs(types []reflect.Type) error {
	p.tmu.RLock()
	defer p.tmu.RUnlock()
	if len(types) != len(p.argTypes) {
		return fmt.Errorf("Argument length expected %d, but got %d", len(p.argTypes), len(types))
	}
	for i, t := range types {
		if t != p.argTypes[i] {
			return fmt.Errorf("Argument Error. Args[%d] expected %s, but got %s", i, p.argTypes[i], t)
		}
	}

	return nil
}

// return argument types.
func fnArgTypes(fn reflect.Value) []reflect.Type {
	fnType := fn.Type()
	fnNum := fnType.NumIn()

	types := make([]reflect.Type, 0, fnNum)

	for i := 0; i < fnNum; i++ {
		types = append(types, fnType.In(i))
	}

	return types
}
<commit_msg>fix lock<commit_after>/*
Package goevent is event dispatcher.

Listen for event:

    e := goevent.New()
    e.On(func(i int, s string){
      fmt.Printf("%d: %s\n", i, s)
    })

Trigger:

    e.Trigger(1, "foo")

Use event table:

    table := goevent.NewTable()
    table.On("foo", func(i int){
      fmt.Printf("foo: %d\n", i)
    })
    table.On("bar", func(s string){
      fmt.Printf("bar: %s\n", s)
    })

    table.Trigger("foo", 1)
    table.Trigger("bar", "hoge")
    table.Trigger("bar", 38)    // retrun error
*/
package goevent

import (
	"fmt"
	"reflect"
	"sync"
)

// Event is an event.
type Event interface {
	Trigger(args ...interface{}) error
	// f is a function
	On(f interface{}) error
	Off(f interface{}) error
}

type event struct {
	// listeners are listener functions.
	listeners []reflect.Value
	lmu       sync.RWMutex

	argTypes []reflect.Type
	tmu      sync.RWMutex
}

// New creates a new event.
func New() Event {
	return &event{}
}

var _ Event = New()

func (p *event) Trigger(args ...interface{}) error {

	arguments := make([]reflect.Value, 0, len(args))
	argTypes := make([]reflect.Type, 0, len(args))
	for _, v := range args {
		arguments = append(arguments, reflect.ValueOf(v))
		argTypes = append(argTypes, reflect.TypeOf(v))
	}

	err := p.validateArgs(argTypes)
	if err != nil {
		return err
	}

	p.lmu.RLock()
	defer p.lmu.RUnlock()

	wg := sync.WaitGroup{}
	wg.Add(len(p.listeners))
	for _, fn := range p.listeners {
		go func(f reflect.Value) {
			defer wg.Done()
			f.Call(arguments)
		}(fn)
	}

	wg.Wait()
	return nil
}

// Start to listen an event.
func (p *event) On(f interface{}) error {
	fn, err := p.checkFuncSignature(f)
	if err != nil {
		return err
	}

	p.lmu.Lock()
	defer p.lmu.Unlock()
	p.listeners = append(p.listeners, *fn)

	return nil
}

// Stop listening an event.
func (p *event) Off(f interface{}) error {
	fn := reflect.ValueOf(f)

	p.lmu.Lock()
	defer p.lmu.Unlock()
	l := len(p.listeners)
	m := l // for error check
	for i := 0; i < l; i++ {
		if fn == p.listeners[i] {
			// XXX: GC Ref: http://jxck.hatenablog.com/entry/golang-slice-internals
			p.listeners = append(p.listeners[:i], p.listeners[i+1:]...)
			l--
			i--
		}
	}

	if l == m {
		return fmt.Errorf("Listener does't exists")
	}
	return nil
}

// retrun function as reflect.Value
// retrun error if f isn't function, argument is invalid
func (p *event) checkFuncSignature(f interface{}) (*reflect.Value, error) {
	fn := reflect.ValueOf(f)
	if fn.Kind() != reflect.Func {
		return nil, fmt.Errorf("Argument should be a function")
	}

	types := fnArgTypes(fn)

	p.lmu.RLock()
	defer p.lmu.RUnlock()
	if len(p.listeners) == 0 {
		p.tmu.Lock()
		defer p.tmu.Unlock()
		p.argTypes = types
		return &fn, nil
	}

	err := p.validateArgs(types)
	if err != nil {
		return nil, err
	}

	return &fn, nil
}

// if argument size or type are different return error.
func (p *event) validateArgs(types []reflect.Type) error {
	p.tmu.RLock()
	defer p.tmu.RUnlock()
	if len(types) != len(p.argTypes) {
		return fmt.Errorf("Argument length expected %d, but got %d", len(p.argTypes), len(types))
	}
	for i, t := range types {
		if t != p.argTypes[i] {
			return fmt.Errorf("Argument Error. Args[%d] expected %s, but got %s", i, p.argTypes[i], t)
		}
	}

	return nil
}

// return argument types.
func fnArgTypes(fn reflect.Value) []reflect.Type {
	fnType := fn.Type()
	fnNum := fnType.NumIn()

	types := make([]reflect.Type, 0, fnNum)

	for i := 0; i < fnNum; i++ {
		types = append(types, fnType.In(i))
	}

	return types
}
<|endoftext|>


<commit_before>package engi

import (
	"log"
)

type Systemer interface {
	Update(entity *Entity, dt float32)
	Name() string
	Priority() int
	Pre()
	Post()
	New()
	Entities() []*Entity
	AddEntity(entity *Entity)
}

type System struct {
	entities []*Entity
}

func (s System) New()  {}
func (s System) Pre()  {}
func (s System) Post() {}

func (s System) Priority() int {
	return 0
}

func (s System) Entities() []*Entity {
	return s.entities
}

func (s *System) AddEntity(entity *Entity) {
	s.entities = append(s.entities, entity)
}

type CollisionSystem struct {
	*System
}

func (cs *CollisionSystem) New() {
	cs.System = &System{}
}

func (cs *CollisionSystem) Update(entity *Entity, dt float32) {
	space, hasSpace := entity.GetComponent("SpaceComponent").(*SpaceComponent)
	collisionMaster, hasCollisionMaster := entity.GetComponent("CollisionMasterComponent").(*CollisionMasterComponent)
	if hasSpace && hasCollisionMaster {
		log.Println("Youre in the club", space, collisionMaster)
		for _, other := range cs.Entities() {
			if other.ID() != entity.ID() {
				otherSpace, otherHasSpace := other.GetComponent("SpaceComponent").(*SpaceComponent)
				if otherHasSpace {
					entityAABB := space.AABB()
					otherAABB := otherSpace.AABB()
					if IsIntersecting(entityAABB, otherAABB) {
						mtd := MinimumTranslation(entityAABB, otherAABB)
						log.Println(mtd)
						space.Position.X += mtd.X
						space.Position.Y += mtd.Y
						log.Println("ARE COLLIDING? I THKN SO")
					}
				}
			}
		}
	}
}

func (cs CollisionSystem) Name() string {
	return "CollisionSystem"
}
<commit_msg>Cleaning up<commit_after>package engi

import (
	"log"
)

type Systemer interface {
	Update(entity *Entity, dt float32)
	Name() string
	Priority() int
	Pre()
	Post()
	New()
	Entities() []*Entity
	AddEntity(entity *Entity)
}

type System struct {
	entities []*Entity
}

func (s System) New()  {}
func (s System) Pre()  {}
func (s System) Post() {}

func (s System) Priority() int {
	return 0
}

func (s System) Entities() []*Entity {
	return s.entities
}

func (s *System) AddEntity(entity *Entity) {
	s.entities = append(s.entities, entity)
}

type CollisionSystem struct {
	*System
}

func (cs *CollisionSystem) New() {
	cs.System = &System{}
}

func (cs *CollisionSystem) Update(entity *Entity, dt float32) {
	space, hasSpace := entity.GetComponent("SpaceComponent").(*SpaceComponent)
	_, hasCollisionMaster := entity.GetComponent("CollisionMasterComponent").(*CollisionMasterComponent)
	if hasSpace && hasCollisionMaster {
		log.Println("Youre in the club", space, collisionMaster)
		for _, other := range cs.Entities() {
			if other.ID() != entity.ID() {
				otherSpace, otherHasSpace := other.GetComponent("SpaceComponent").(*SpaceComponent)
				if otherHasSpace {
					entityAABB := space.AABB()
					otherAABB := otherSpace.AABB()
					if IsIntersecting(entityAABB, otherAABB) {
						mtd := MinimumTranslation(entityAABB, otherAABB)
						space.Position.X += mtd.X
						space.Position.Y += mtd.Y
					}
				}
			}
		}
	}
}

func (cs CollisionSystem) Name() string {
	return "CollisionSystem"
}
<|endoftext|>


<commit_before>// package merkledag implements the ipfs Merkle DAG datastructures.
package merkledag

import (
	"fmt"
	"sync"
	"time"

	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
	blocks "github.com/jbenet/go-ipfs/blocks"
	bserv "github.com/jbenet/go-ipfs/blockservice"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("merkledag")
var ErrNotFound = fmt.Errorf("merkledag: not found")

// NodeMap maps u.Keys to Nodes.
// We cannot use []byte/Multihash for keys :(
// so have to convert Multihash bytes to string (u.Key)
type NodeMap map[u.Key]*Node

// DAGService is an IPFS Merkle DAG service.
type DAGService interface {
	Add(*Node) (u.Key, error)
	AddRecursive(*Node) error
	Get(u.Key) (*Node, error)
	Remove(*Node) error

	// GetDAG returns, in order, all the single leve child
	// nodes of the passed in node.
	GetDAG(context.Context, *Node) <-chan *Node
}

func NewDAGService(bs *bserv.BlockService) DAGService {
	return &dagService{bs}
}

// Node represents a node in the IPFS Merkle DAG.
// nodes have opaque data and a set of navigable links.
type Node struct {
	Links []*Link
	Data  []byte

	// cache encoded/marshaled value
	encoded []byte

	cached mh.Multihash
}

// Link represents an IPFS Merkle DAG Link between Nodes.
type Link struct {
	// utf string name. should be unique per object
	Name string // utf8

	// cumulative size of target object
	Size uint64

	// multihash of the target object
	Hash mh.Multihash

	// a ptr to the actual node for graph manipulation
	Node *Node
}

// MakeLink creates a link to the given node
func MakeLink(n *Node) (*Link, error) {
	s, err := n.Size()
	if err != nil {
		return nil, err
	}

	h, err := n.Multihash()
	if err != nil {
		return nil, err
	}
	return &Link{
		Size: s,
		Hash: h,
	}, nil
}

// GetNode returns the MDAG Node that this link points to
func (l *Link) GetNode(serv DAGService) (*Node, error) {
	if l.Node != nil {
		return l.Node, nil
	}

	return serv.Get(u.Key(l.Hash))
}

// AddNodeLink adds a link to another node.
func (n *Node) AddNodeLink(name string, that *Node) error {
	lnk, err := MakeLink(that)
	if err != nil {
		return err
	}
	lnk.Name = name
	lnk.Node = that

	n.Links = append(n.Links, lnk)
	return nil
}

// AddNodeLink adds a link to another node. without keeping a reference to
// the child node
func (n *Node) AddNodeLinkClean(name string, that *Node) error {
	lnk, err := MakeLink(that)
	if err != nil {
		return err
	}
	lnk.Name = name

	n.Links = append(n.Links, lnk)
	return nil
}

// Remove a link on this node by the given name
func (n *Node) RemoveNodeLink(name string) error {
	for i, l := range n.Links {
		if l.Name == name {
			n.Links = append(n.Links[:i], n.Links[i+1:]...)
			return nil
		}
	}
	return ErrNotFound
}

// Copy returns a copy of the node.
// NOTE: does not make copies of Node objects in the links.
func (n *Node) Copy() *Node {
	nnode := new(Node)
	nnode.Data = make([]byte, len(n.Data))
	copy(nnode.Data, n.Data)

	nnode.Links = make([]*Link, len(n.Links))
	copy(nnode.Links, n.Links)
	return nnode
}

// Size returns the total size of the data addressed by node,
// including the total sizes of references.
func (n *Node) Size() (uint64, error) {
	b, err := n.Encoded(false)
	if err != nil {
		return 0, err
	}

	s := uint64(len(b))
	for _, l := range n.Links {
		s += l.Size
	}
	return s, nil
}

// Multihash hashes the encoded data of this node.
func (n *Node) Multihash() (mh.Multihash, error) {
	// Note: Encoded generates the hash and puts it in n.cached.
	_, err := n.Encoded(false)
	if err != nil {
		return nil, err
	}

	return n.cached, nil
}

// Key returns the Multihash as a key, for maps.
func (n *Node) Key() (u.Key, error) {
	h, err := n.Multihash()
	return u.Key(h), err
}

// dagService is an IPFS Merkle DAG service.
// - the root is virtual (like a forest)
// - stores nodes' data in a BlockService
// TODO: should cache Nodes that are in memory, and be
//       able to free some of them when vm pressure is high
type dagService struct {
	Blocks *bserv.BlockService
}

// Add adds a node to the dagService, storing the block in the BlockService
func (n *dagService) Add(nd *Node) (u.Key, error) {
	k, _ := nd.Key()
	log.Debugf("DagService Add [%s]", k)
	if n == nil {
		return "", fmt.Errorf("dagService is nil")
	}

	d, err := nd.Encoded(false)
	if err != nil {
		return "", err
	}

	b := new(blocks.Block)
	b.Data = d
	b.Multihash, err = nd.Multihash()
	if err != nil {
		return "", err
	}

	return n.Blocks.AddBlock(b)
}

// AddRecursive adds the given node and all child nodes to the BlockService
func (n *dagService) AddRecursive(nd *Node) error {
	_, err := n.Add(nd)
	if err != nil {
		log.Info("AddRecursive Error: %s\n", err)
		return err
	}

	for _, link := range nd.Links {
		if link.Node != nil {
			err := n.AddRecursive(link.Node)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// Get retrieves a node from the dagService, fetching the block in the BlockService
func (n *dagService) Get(k u.Key) (*Node, error) {
	if n == nil {
		return nil, fmt.Errorf("dagService is nil")
	}

	ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
	b, err := n.Blocks.GetBlock(ctx, k)
	if err != nil {
		return nil, err
	}

	return Decoded(b.Data)
}

// Remove deletes the given node and all of its children from the BlockService
func (n *dagService) Remove(nd *Node) error {
	for _, l := range nd.Links {
		if l.Node != nil {
			n.Remove(l.Node)
		}
	}
	k, err := nd.Key()
	if err != nil {
		return err
	}
	return n.Blocks.DeleteBlock(k)
}

// FetchGraph asynchronously fetches all nodes that are children of the given
// node, and returns a channel that may be waited upon for the fetch to complete
func FetchGraph(ctx context.Context, root *Node, serv DAGService) chan struct{} {
	log.Warning("Untested.")
	var wg sync.WaitGroup
	done := make(chan struct{})

	for _, l := range root.Links {
		wg.Add(1)
		go func(lnk *Link) {

			// Signal child is done on way out
			defer wg.Done()
			select {
			case <-ctx.Done():
				return
			}

			nd, err := lnk.GetNode(serv)
			if err != nil {
				log.Error(err)
				return
			}

			// Wait for children to finish
			<-FetchGraph(ctx, nd, serv)
		}(l)
	}

	go func() {
		wg.Wait()
		done <- struct{}{}
	}()

	return done
}

// Searches this nodes links for one to the given key,
// returns the index of said link
func FindLink(n *Node, k u.Key, found []*Node) (int, error) {
	for i, lnk := range n.Links {
		if u.Key(lnk.Hash) == k && found[i] == nil {
			return i, nil
		}
	}
	return -1, u.ErrNotFound
}

// GetDAG will fill out all of the links of the given Node.
// It returns a channel of nodes, which the caller can receive
// all the child nodes of 'root' on, in proper order.
func (ds *dagService) GetDAG(ctx context.Context, root *Node) <-chan *Node {
	sig := make(chan *Node)
	go func() {
		var keys []u.Key
		nodes := make([]*Node, len(root.Links))

		for _, lnk := range root.Links {
			keys = append(keys, u.Key(lnk.Hash))
		}

		blkchan := ds.Blocks.GetBlocks(ctx, keys)

		next := 0
		for blk := range blkchan {
			i, err := FindLink(root, blk.Key(), nodes)
			if err != nil {
				// NB: can only occur as a result of programmer error
				panic("Received block that wasnt in this nodes links!")
			}

			nd, err := Decoded(blk.Data)
			if err != nil {
				// NB: can occur in normal situations, with improperly formatted
				//		input data
				log.Error("Got back bad block!")
				break
			}
			nodes[i] = nd
			for { //Check for duplicate links
				ni, err := FindLink(root, blk.Key(), nodes)
				if err != nil {
					break
				}
				nodes[ni] = nd
			}

			if next == i {
				sig <- nd
				next++
				for ; next < len(nodes) && nodes[next] != nil; next++ {
					sig <- nodes[next]
				}
			}
		}
		if next < len(nodes) {
			// TODO: bubble errors back up.
			log.Errorf("Did not receive correct number of nodes!")
		}
		close(sig)
	}()

	return sig
}
<commit_msg>style(merkle): move var dec closer to use<commit_after>// package merkledag implements the ipfs Merkle DAG datastructures.
package merkledag

import (
	"fmt"
	"sync"
	"time"

	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
	blocks "github.com/jbenet/go-ipfs/blocks"
	bserv "github.com/jbenet/go-ipfs/blockservice"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("merkledag")
var ErrNotFound = fmt.Errorf("merkledag: not found")

// NodeMap maps u.Keys to Nodes.
// We cannot use []byte/Multihash for keys :(
// so have to convert Multihash bytes to string (u.Key)
type NodeMap map[u.Key]*Node

// DAGService is an IPFS Merkle DAG service.
type DAGService interface {
	Add(*Node) (u.Key, error)
	AddRecursive(*Node) error
	Get(u.Key) (*Node, error)
	Remove(*Node) error

	// GetDAG returns, in order, all the single leve child
	// nodes of the passed in node.
	GetDAG(context.Context, *Node) <-chan *Node
}

func NewDAGService(bs *bserv.BlockService) DAGService {
	return &dagService{bs}
}

// Node represents a node in the IPFS Merkle DAG.
// nodes have opaque data and a set of navigable links.
type Node struct {
	Links []*Link
	Data  []byte

	// cache encoded/marshaled value
	encoded []byte

	cached mh.Multihash
}

// Link represents an IPFS Merkle DAG Link between Nodes.
type Link struct {
	// utf string name. should be unique per object
	Name string // utf8

	// cumulative size of target object
	Size uint64

	// multihash of the target object
	Hash mh.Multihash

	// a ptr to the actual node for graph manipulation
	Node *Node
}

// MakeLink creates a link to the given node
func MakeLink(n *Node) (*Link, error) {
	s, err := n.Size()
	if err != nil {
		return nil, err
	}

	h, err := n.Multihash()
	if err != nil {
		return nil, err
	}
	return &Link{
		Size: s,
		Hash: h,
	}, nil
}

// GetNode returns the MDAG Node that this link points to
func (l *Link) GetNode(serv DAGService) (*Node, error) {
	if l.Node != nil {
		return l.Node, nil
	}

	return serv.Get(u.Key(l.Hash))
}

// AddNodeLink adds a link to another node.
func (n *Node) AddNodeLink(name string, that *Node) error {
	lnk, err := MakeLink(that)
	if err != nil {
		return err
	}
	lnk.Name = name
	lnk.Node = that

	n.Links = append(n.Links, lnk)
	return nil
}

// AddNodeLink adds a link to another node. without keeping a reference to
// the child node
func (n *Node) AddNodeLinkClean(name string, that *Node) error {
	lnk, err := MakeLink(that)
	if err != nil {
		return err
	}
	lnk.Name = name

	n.Links = append(n.Links, lnk)
	return nil
}

// Remove a link on this node by the given name
func (n *Node) RemoveNodeLink(name string) error {
	for i, l := range n.Links {
		if l.Name == name {
			n.Links = append(n.Links[:i], n.Links[i+1:]...)
			return nil
		}
	}
	return ErrNotFound
}

// Copy returns a copy of the node.
// NOTE: does not make copies of Node objects in the links.
func (n *Node) Copy() *Node {
	nnode := new(Node)
	nnode.Data = make([]byte, len(n.Data))
	copy(nnode.Data, n.Data)

	nnode.Links = make([]*Link, len(n.Links))
	copy(nnode.Links, n.Links)
	return nnode
}

// Size returns the total size of the data addressed by node,
// including the total sizes of references.
func (n *Node) Size() (uint64, error) {
	b, err := n.Encoded(false)
	if err != nil {
		return 0, err
	}

	s := uint64(len(b))
	for _, l := range n.Links {
		s += l.Size
	}
	return s, nil
}

// Multihash hashes the encoded data of this node.
func (n *Node) Multihash() (mh.Multihash, error) {
	// Note: Encoded generates the hash and puts it in n.cached.
	_, err := n.Encoded(false)
	if err != nil {
		return nil, err
	}

	return n.cached, nil
}

// Key returns the Multihash as a key, for maps.
func (n *Node) Key() (u.Key, error) {
	h, err := n.Multihash()
	return u.Key(h), err
}

// dagService is an IPFS Merkle DAG service.
// - the root is virtual (like a forest)
// - stores nodes' data in a BlockService
// TODO: should cache Nodes that are in memory, and be
//       able to free some of them when vm pressure is high
type dagService struct {
	Blocks *bserv.BlockService
}

// Add adds a node to the dagService, storing the block in the BlockService
func (n *dagService) Add(nd *Node) (u.Key, error) {
	k, _ := nd.Key()
	log.Debugf("DagService Add [%s]", k)
	if n == nil {
		return "", fmt.Errorf("dagService is nil")
	}

	d, err := nd.Encoded(false)
	if err != nil {
		return "", err
	}

	b := new(blocks.Block)
	b.Data = d
	b.Multihash, err = nd.Multihash()
	if err != nil {
		return "", err
	}

	return n.Blocks.AddBlock(b)
}

// AddRecursive adds the given node and all child nodes to the BlockService
func (n *dagService) AddRecursive(nd *Node) error {
	_, err := n.Add(nd)
	if err != nil {
		log.Info("AddRecursive Error: %s\n", err)
		return err
	}

	for _, link := range nd.Links {
		if link.Node != nil {
			err := n.AddRecursive(link.Node)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// Get retrieves a node from the dagService, fetching the block in the BlockService
func (n *dagService) Get(k u.Key) (*Node, error) {
	if n == nil {
		return nil, fmt.Errorf("dagService is nil")
	}

	ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
	b, err := n.Blocks.GetBlock(ctx, k)
	if err != nil {
		return nil, err
	}

	return Decoded(b.Data)
}

// Remove deletes the given node and all of its children from the BlockService
func (n *dagService) Remove(nd *Node) error {
	for _, l := range nd.Links {
		if l.Node != nil {
			n.Remove(l.Node)
		}
	}
	k, err := nd.Key()
	if err != nil {
		return err
	}
	return n.Blocks.DeleteBlock(k)
}

// FetchGraph asynchronously fetches all nodes that are children of the given
// node, and returns a channel that may be waited upon for the fetch to complete
func FetchGraph(ctx context.Context, root *Node, serv DAGService) chan struct{} {
	log.Warning("Untested.")
	var wg sync.WaitGroup
	done := make(chan struct{})

	for _, l := range root.Links {
		wg.Add(1)
		go func(lnk *Link) {

			// Signal child is done on way out
			defer wg.Done()
			select {
			case <-ctx.Done():
				return
			}

			nd, err := lnk.GetNode(serv)
			if err != nil {
				log.Error(err)
				return
			}

			// Wait for children to finish
			<-FetchGraph(ctx, nd, serv)
		}(l)
	}

	go func() {
		wg.Wait()
		done <- struct{}{}
	}()

	return done
}

// Searches this nodes links for one to the given key,
// returns the index of said link
func FindLink(n *Node, k u.Key, found []*Node) (int, error) {
	for i, lnk := range n.Links {
		if u.Key(lnk.Hash) == k && found[i] == nil {
			return i, nil
		}
	}
	return -1, u.ErrNotFound
}

// GetDAG will fill out all of the links of the given Node.
// It returns a channel of nodes, which the caller can receive
// all the child nodes of 'root' on, in proper order.
func (ds *dagService) GetDAG(ctx context.Context, root *Node) <-chan *Node {
	sig := make(chan *Node)
	go func() {
		var keys []u.Key
		for _, lnk := range root.Links {
			keys = append(keys, u.Key(lnk.Hash))
		}
		blkchan := ds.Blocks.GetBlocks(ctx, keys)

		nodes := make([]*Node, len(root.Links))
		next := 0
		for blk := range blkchan {
			i, err := FindLink(root, blk.Key(), nodes)
			if err != nil {
				// NB: can only occur as a result of programmer error
				panic("Received block that wasnt in this nodes links!")
			}

			nd, err := Decoded(blk.Data)
			if err != nil {
				// NB: can occur in normal situations, with improperly formatted
				//		input data
				log.Error("Got back bad block!")
				break
			}
			nodes[i] = nd
			for { //Check for duplicate links
				ni, err := FindLink(root, blk.Key(), nodes)
				if err != nil {
					break
				}
				nodes[ni] = nd
			}

			if next == i {
				sig <- nd
				next++
				for ; next < len(nodes) && nodes[next] != nil; next++ {
					sig <- nodes[next]
				}
			}
		}
		if next < len(nodes) {
			// TODO: bubble errors back up.
			log.Errorf("Did not receive correct number of nodes!")
		}
		close(sig)
	}()

	return sig
}
<|endoftext|>


<commit_before>// Synchronization built on top of Redis.
// Depends on github.com/garyburd/redigo/redis
package redisync

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"io/ioutil"
	"os"
	"sync"
	"time"
)

type Mutex struct {
	// The key used in Redis.
	Name string
	// The amount of time before Redis will expire the lock.
	Ttl time.Duration
	// The time to sleep before retrying a lock attempt.
	Backoff time.Duration
	// A uuid representing the local instantiation of the mutex.
	id string
	// Local conrrency controll.
	l sync.Mutex
	// See lock.lua
	lock *redis.Script
	// See unlock.lua
	unlock *redis.Script
}

// Each lock will have a name which corresponds to a key in the Redis server.
// The mutex will also be initialized with a uuid. The mutex uuid
// can be used to extend the TTL for the lock.
func NewMutex(name string, ttl time.Duration) *Mutex {
	m := new(Mutex)
	m.Name = name
	m.Ttl = ttl
	m.Backoff = time.Second
	m.id = uuid()
	m.lock = redis.NewScript(1, readSource("./lock.lua"))
	m.unlock = redis.NewScript(1, readSource("./unlock.lua"))
	return m
}

// With similar behaviour to Go's sync pkg,
// this function will sleep until TryLock() returns true.
// The connection will be used once to execute the lock script.
func (m *Mutex) Lock(c redis.Conn) {
	for {
		if m.TryLock(c) {
			return
		}
		time.Sleep(m.Backoff)
	}
}

// Makes a single attempt to acquire the lock.
// Locking a mutex which has already been locked
// using the mutex uuid will result in the TTL of the mutex being extended.
// The connection will be used once to execute the lock script.
func (m *Mutex) TryLock(c redis.Conn) bool {
	m.l.Lock()
	defer m.l.Unlock()

	reply, err := m.lock.Do(c, m.Name, m.id, m.Ttl.Seconds())
	if err != nil {
		return false
	}
	return reply.(int64) == 1
}

// If the local mutex uuid matches the uuid in Redis,
// the lock will be deleted.
// The connection will be used once to execute the unlock script.
func (m *Mutex) Unlock(c redis.Conn) (bool, error) {
	m.l.Lock()
	defer m.l.Unlock()
	reply, err := m.unlock.Do(c, m.Name, m.id)
	if err != nil {
		return false, err
	}
	return reply.(int64) == 1, nil
}

func readSource(name string) string {
	src, err := ioutil.ReadFile(name)
	if err != nil {
		panic("redisync: Unable to read unlock.lua")
	}
	return string(src)
}

func uuid() string {
	f, _ := os.Open("/dev/urandom")
	b := make([]byte, 16)
	f.Read(b)
	f.Close()
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
<commit_msg>provide correct file reading support<commit_after>// Synchronization built on top of Redis.
// Depends on github.com/garyburd/redigo/redis
package redisync

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"io/ioutil"
	"os"
	"sync"
	"time"
)

type Mutex struct {
	// The key used in Redis.
	Name string
	// The amount of time before Redis will expire the lock.
	Ttl time.Duration
	// The time to sleep before retrying a lock attempt.
	Backoff time.Duration
	// A uuid representing the local instantiation of the mutex.
	id string
	// Local conrrency controll.
	l sync.Mutex
	// See lock.lua
	lock *redis.Script
	// See unlock.lua
	unlock *redis.Script
}

// Each lock will have a name which corresponds to a key in the Redis server.
// The mutex will also be initialized with a uuid. The mutex uuid
// can be used to extend the TTL for the lock.
func NewMutex(name string, ttl time.Duration) *Mutex {
	m := new(Mutex)
	m.Name = name
	m.Ttl = ttl
	m.Backoff = time.Second
	m.id = uuid()
	m.lock = redis.NewScript(1, readSource("lock.lua"))
	m.unlock = redis.NewScript(1, readSource("unlock.lua"))
	return m
}

// With similar behaviour to Go's sync pkg,
// this function will sleep until TryLock() returns true.
// The connection will be used once to execute the lock script.
func (m *Mutex) Lock(c redis.Conn) {
	for {
		if m.TryLock(c) {
			return
		}
		time.Sleep(m.Backoff)
	}
}

// Makes a single attempt to acquire the lock.
// Locking a mutex which has already been locked
// using the mutex uuid will result in the TTL of the mutex being extended.
// The connection will be used once to execute the lock script.
func (m *Mutex) TryLock(c redis.Conn) bool {
	m.l.Lock()
	defer m.l.Unlock()

	reply, err := m.lock.Do(c, m.Name, m.id, m.Ttl.Seconds())
	if err != nil {
		return false
	}
	return reply.(int64) == 1
}

// If the local mutex uuid matches the uuid in Redis,
// the lock will be deleted.
// The connection will be used once to execute the unlock script.
func (m *Mutex) Unlock(c redis.Conn) (bool, error) {
	m.l.Lock()
	defer m.l.Unlock()
	reply, err := m.unlock.Do(c, m.Name, m.id)
	if err != nil {
		return false, err
	}
	return reply.(int64) == 1, nil
}

func readSource(name string) string {
	path := os.Getenv("GOPATH")
	prefix := path + "/src/github.com/ryandotsmith/redisync/"
	src, err := ioutil.ReadFile(prefix + name)
	if err != nil {
		panic("redisync: Unable to read unlock.lua")
	}
	return string(src)
}

func uuid() string {
	f, _ := os.Open("/dev/urandom")
	b := make([]byte, 16)
	f.Read(b)
	f.Close()
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
<|endoftext|>