<commit_before>package scheduler

import (
	"fmt"
)

// Job defines a nomad job specification
type Job struct {
	Region      string
	ID          string
	Name        string
	Type        string
	Priority    int
	AllAtOnce   bool
	Datacenters []string
	Constraints []Constraint
	TaskGroups  []TaskGroup
	Update      Update
}

// Constraint defines a job/task contraint
type Constraint struct {
	LTarget string
	RTarget string
	Operand string
}

// Update defines the update stanza
type Update struct {
	Stagger     int64
	MaxParallel int
}

// TaskGroups defines the task_group stanza
type TaskGroup struct {
	Name          string
	Count         int
	Constraints   []string
	Tasks         []Task
	Resources     Resources
	RestartPolicy RestartPolicy
	Meta          map[string]string
}

// Task defines a job task
type Task struct {
	Name            string
	Driver          string
	Config          Config
	Env             map[string]string
	Services        []NomadService
	Meta            map[string]string
	LogConfig       LogConfig
	Templates       []Template
	Artifacts       []Artifact
	Resources       Resources
	DispatchPayload DispatchPayload
}

// DispatchPayload configures tast to have access to dispatch payload
type DispatchPayload struct {
	File string
}

// Resources defines the resources to allocate to a task
type Resources struct {
	CPU      int
	MemoryMB int
	IOPS     int
	Networks []Network
}

// Network defines network allocation
type Network struct {
	MBits        int
	DynamicPorts []DynamicPort
}

// RestartPolicy defines restart policy
type RestartPolicy struct {
	Interval int64
	Attempts int
	Delay    int64
	Mode     string
}

// DynamicPort defines a dynamic port allocation
type DynamicPort struct {
	Label string
}

// Artifact defines an artifact to be downloaded
type Artifact struct {
	GetterSource  string
	RelativeDest  string
	GetterOptions map[string]string
}

// Template defines template objects to render for the task
type Template struct {
	SourcePath   string
	DestPath     string
	EmbeddedTmpl string
	ChangeMode   string
	ChangeSignal string
	Splay        int64
}

// LogConfig defines log configurations
type LogConfig struct {
	MaxFiles      int
	MaxFileSizeMB int
}

// NomadService defines a service
type NomadService struct {
	Name      string
	Tags      []string
	PortLabel string
	Checks    []Check
}

// Check defines a service check
type Check struct {
	ID       string `json:"Id"`
	Name     string
	Type     string
	Path     string
	Port     string
	Timeout  int64
	Interval int64
	Protocol string
}

// Config defines a driver/task configuration
type Config struct {
	Command string   `json:"command"`
	Args    []string `json:"args"`
}

// NomadJob represents a nomad job
type NomadJob struct {
	Job *Job
}

// NewJob creates a new job with some default values.
func NewJob(connectorVersion, id string, count int) *NomadJob {
	return &NomadJob{
		Job: &Job{
			Region:      "",
			ID:          id,
			Name:        id,
			Type:        "service",
			Priority:    50,
			AllAtOnce:   false,
			Datacenters: []string{},
			Constraints: []Constraint{
				Constraint{
					LTarget: "${attr.kernel.name}",
					RTarget: "linux",
					Operand: "=",
				},
			},
			TaskGroups: []TaskGroup{
				TaskGroup{
					Name:  fmt.Sprintf("tskgrp-%s", id),
					Count: count,
					Tasks: []Task{
						Task{
							Name:   fmt.Sprintf("task-%s", id),
							Driver: "raw_exec",
							Config: Config{
								Command: "bash",
								Args:    []string{"runner.sh"},
							},
							Env: map[string]string{
								"CONNECTOR_VERSION":   connectorVersion,
								"COCOON_ID":           id,
								"CONTAINER_ID":        id,
								"COCOON_CODE_URL":     "",
								"COCOON_CODE_TAG":     "",
								"COCOON_CODE_LANG":    "",
								"COCOON_BUILD_PARAMS": "",
								"COCOON_DISK_LIMIT":   "",
								// The name of the connector runner script and a link to the script.
								// The runner script will fetch and run whatever is found in this environment vars.
								"RUN_SCRIPT_NAME": "run-connector.sh",
								"RUN_SCRIPT_URL":  "https://rawgit.com/ncodes/cocoon/master/scripts/run-connector.sh",
							},
							Services: []NomadService{
								NomadService{
									Name:      fmt.Sprintf("cocoons-%s", id),
									Tags:      []string{id},
									PortLabel: "CONNECTOR_RPC",
								},
							},
							Meta: map[string]string{},
							LogConfig: LogConfig{
								MaxFiles:      10,
								MaxFileSizeMB: 10,
							},
							Templates: []Template{},
							Artifacts: []Artifact{
								Artifact{
									GetterSource: "https://rawgit.com/ncodes/cocoon/master/scripts/runner.sh",
								},
							},
							Resources: Resources{
								CPU:      0,
								MemoryMB: 0,
								IOPS:     0,
								Networks: []Network{
									Network{
										MBits: 1,
										DynamicPorts: []DynamicPort{
											DynamicPort{Label: "CONNECTOR_RPC"},
											DynamicPort{Label: "COCOON_RPC"},
										},
									},
								},
							},
							DispatchPayload: DispatchPayload{},
						},
					},
					Resources: Resources{
						CPU:      0,
						MemoryMB: 0,
						IOPS:     0,
						Networks: []Network{},
					},
					RestartPolicy: RestartPolicy{
						Interval: 300000000000,
						Attempts: 10,
						Delay:    25000000000,
						Mode:     "delay",
					},
					Meta: map[string]string{},
				},
			},
			Update: Update{
				Stagger:     10000000000,
				MaxParallel: 1,
			},
		},
	}
}

// GetSpec returns the job's specification
func (j *NomadJob) GetSpec() *Job {
	return j.Job
}
<commit_msg>set bare minimum default<commit_after>package scheduler

import (
	"fmt"
)

// Job defines a nomad job specification
type Job struct {
	Region      string
	ID          string
	Name        string
	Type        string
	Priority    int
	AllAtOnce   bool
	Datacenters []string
	Constraints []Constraint
	TaskGroups  []TaskGroup
	Update      Update
}

// Constraint defines a job/task contraint
type Constraint struct {
	LTarget string
	RTarget string
	Operand string
}

// Update defines the update stanza
type Update struct {
	Stagger     int64
	MaxParallel int
}

// TaskGroups defines the task_group stanza
type TaskGroup struct {
	Name          string
	Count         int
	Constraints   []string
	Tasks         []Task
	Resources     Resources
	RestartPolicy RestartPolicy
	Meta          map[string]string
}

// Task defines a job task
type Task struct {
	Name            string
	Driver          string
	Config          Config
	Env             map[string]string
	Services        []NomadService
	Meta            map[string]string
	LogConfig       LogConfig
	Templates       []Template
	Artifacts       []Artifact
	Resources       Resources
	DispatchPayload DispatchPayload
}

// DispatchPayload configures tast to have access to dispatch payload
type DispatchPayload struct {
	File string
}

// Resources defines the resources to allocate to a task
type Resources struct {
	CPU      int
	MemoryMB int
	IOPS     int
	Networks []Network
}

// Network defines network allocation
type Network struct {
	MBits        int
	DynamicPorts []DynamicPort
}

// RestartPolicy defines restart policy
type RestartPolicy struct {
	Interval int64
	Attempts int
	Delay    int64
	Mode     string
}

// DynamicPort defines a dynamic port allocation
type DynamicPort struct {
	Label string
}

// Artifact defines an artifact to be downloaded
type Artifact struct {
	GetterSource  string
	RelativeDest  string
	GetterOptions map[string]string
}

// Template defines template objects to render for the task
type Template struct {
	SourcePath   string
	DestPath     string
	EmbeddedTmpl string
	ChangeMode   string
	ChangeSignal string
	Splay        int64
}

// LogConfig defines log configurations
type LogConfig struct {
	MaxFiles      int
	MaxFileSizeMB int
}

// NomadService defines a service
type NomadService struct {
	Name      string
	Tags      []string
	PortLabel string
	Checks    []Check
}

// Check defines a service check
type Check struct {
	ID       string `json:"Id"`
	Name     string
	Type     string
	Path     string
	Port     string
	Timeout  int64
	Interval int64
	Protocol string
}

// Config defines a driver/task configuration
type Config struct {
	Command string   `json:"command"`
	Args    []string `json:"args"`
}

// NomadJob represents a nomad job
type NomadJob struct {
	Job *Job
}

// NewJob creates a new job with some default values.
func NewJob(connectorVersion, id string, count int) *NomadJob {
	return &NomadJob{
		Job: &Job{
			Region:      "",
			ID:          id,
			Name:        id,
			Type:        "service",
			Priority:    50,
			AllAtOnce:   false,
			Datacenters: []string{},
			Constraints: []Constraint{
				Constraint{
					LTarget: "${attr.kernel.name}",
					RTarget: "linux",
					Operand: "=",
				},
			},
			TaskGroups: []TaskGroup{
				TaskGroup{
					Name:  fmt.Sprintf("tskgrp-%s", id),
					Count: count,
					Tasks: []Task{
						Task{
							Name:   fmt.Sprintf("task-%s", id),
							Driver: "raw_exec",
							Config: Config{
								Command: "bash",
								Args:    []string{"runner.sh"},
							},
							Env: map[string]string{
								"CONNECTOR_VERSION":   connectorVersion,
								"COCOON_ID":           id,
								"CONTAINER_ID":        id,
								"COCOON_CODE_URL":     "",
								"COCOON_CODE_TAG":     "",
								"COCOON_CODE_LANG":    "",
								"COCOON_BUILD_PARAMS": "",
								"COCOON_DISK_LIMIT":   "",
								// The name of the connector runner script and a link to the script.
								// The runner script will fetch and run whatever is found in this environment vars.
								"RUN_SCRIPT_NAME": "run-connector.sh",
								"RUN_SCRIPT_URL":  "https://rawgit.com/ncodes/cocoon/master/scripts/run-connector.sh",
							},
							Services: []NomadService{
								NomadService{
									Name:      fmt.Sprintf("cocoons-%s", id),
									Tags:      []string{id},
									PortLabel: "CONNECTOR_RPC",
								},
							},
							Meta: map[string]string{},
							LogConfig: LogConfig{
								MaxFiles:      10,
								MaxFileSizeMB: 10,
							},
							Templates: []Template{},
							Artifacts: []Artifact{
								Artifact{
									GetterSource: "https://rawgit.com/ncodes/cocoon/master/scripts/runner.sh",
								},
							},
							Resources: Resources{
								CPU:      20,
								MemoryMB: 10,
								IOPS:     0,
								Networks: []Network{
									Network{
										MBits: 1,
										DynamicPorts: []DynamicPort{
											DynamicPort{Label: "CONNECTOR_RPC"},
											DynamicPort{Label: "COCOON_RPC"},
										},
									},
								},
							},
							DispatchPayload: DispatchPayload{},
						},
					},
					Resources: Resources{
						CPU:      20,
						MemoryMB: 10,
						IOPS:     0,
						Networks: []Network{},
					},
					RestartPolicy: RestartPolicy{
						Interval: 300000000000,
						Attempts: 10,
						Delay:    25000000000,
						Mode:     "delay",
					},
					Meta: map[string]string{},
				},
			},
			Update: Update{
				Stagger:     10000000000,
				MaxParallel: 1,
			},
		},
	}
}

// GetSpec returns the job's specification
func (j *NomadJob) GetSpec() *Job {
	return j.Job
}
<|endoftext|>


<commit_before>package main

import(
	"fmt"
	"Golly/parser"
	"strconv"
)

type baseType int
const(
	Int baseType = iota
	Float
	Char
	Symbol
	List
	FuncDef
	VarDef
)

type FuncParem struct{
	Name string
	TypeID int64
}

type FunctionDef struct{
	NumParems int16
	Parems []FuncParem
	ReturnVals []FuncParem
}

type TypeDef struct{
	Name string
	Order int32
}

type Union struct{
	CurType int16
	Types []string
}

type EnvBinding struct{
	Name string
	Binding interface{}
}

type Environment []EnvBinding

func (env Environment) findBinding(name string, recur bool) *EnvBinding{
	for i, _ := range env{
		if env[i].Name == name{
			return &env[i]
		}
	}
	if recur{
		if len(env) == 0{
			panic("Error: root environment is empty!\n")
		}
		if parentEnv, ok := env[0].Binding.(Environment); ok {
			return parentEnv.findBinding(name, true)
		} else {
			return nil
		}
	}
	return nil
}

func (env *Environment) addBinding(recur bool) *EnvBinding{
	if recur{
		if parentEnv, ok := (*env)[0].Binding.(Environment); ok {
			return parentEnv.addBinding(true)
		} else {
			*env = append(*env, EnvBinding{})
			return &((*env)[len(*env)])
		}
	}else{
		*env = append(*env, EnvBinding{})
		return &((*env)[len(*env)])
	}
}

type ListCell struct{
	TypeName string
	Value interface{}
	Mutable bool
}

type CellList struct{
	Cells []ListCell
	Environment []EnvBinding
}

func defGlobal(environ *[]EnvBinding) *EnvBinding{
	if parentEnv, ok := (*environ)[0].Binding.([]EnvBinding); ok {
		return defGlobal(&parentEnv)
	} else {
		*environ = append(*environ, EnvBinding{})
		return &((*environ)[len(*environ)])
	}
}

func evalNumToken(num *Parser.Token, lineNum int, caller string)(ListCell){
	newValue := ListCell{}
			if (*num).LitType == Parser.FixNum{
				floatval, err := strconv.ParseFloat((*num).Value, 32)
				if err != nil{
					errMsg := fmt.Sprintf("Error: cannot parse string %v to float in %v at line %v.\n", (*num).Value, caller, lineNum)
					panic(errMsg)
				}else{
					newValue.Value = floatval
					newValue.TypeName = "float"
				}
			}else if (*num).LitType == Parser.FixNum{
				intval, err := strconv.Atoi((*num).Value)
				if err != nil{
					errMsg := fmt.Sprintf("Error: cannot parse string %v to int in %v at line %v.\n", (*num).Value, caller, lineNum)
					panic(errMsg)
				}else{
					newValue.Value = intval
					newValue.TypeName = "int"
				}
			}
	return newValue
}

func evalIdToken(identifierName *Parser.Token, env *Environment, lineNum int, caller string)(interface{}){
	var newValue interface{}
	valueReferenced := env.findBinding((*identifierName).Value, true)
			if valueReferenced == nil{
				errMsg := fmt.Sprintf("Error: attempting to evalute var %v in %v at line %v, but that var is unbound.\n", (*identifierName).Value, caller, lineNum)
				panic(errMsg)
			}else{
				newValue = valueReferenced.Binding
			}
	return newValue
}
func bindVars(list *Parser.Token, env Environment, lineNum int, global, mut bool, caller string)Environment{
	for i := 0; i < len(list.ListVals); i++{
		val := &list.ListVals[i]
		if val.Type != Parser.IdToken{
			errMsg := fmt.Sprintf("Error: attempting to assign to a non-identifier in %v at line %v.\n", caller, lineNum)
			panic(errMsg)
		}
		prevBinding := env.findBinding(val.Value, global)
		var newBinding *EnvBinding
		if prevBinding != nil{
			if boundVal, ok := (*prevBinding).Binding.(ListCell); ok {
				if !boundVal.Mutable{
					errMsg := fmt.Sprintf("Error: attempting to assign to an immutable identifier in %v at line %v.\n", caller, lineNum)
					panic(errMsg)
				}else{
					newBinding = prevBinding
				}
			} else {
				errMsg := fmt.Sprintf("Error: malformed environment binding encountered in binding for %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			}
		}else{
			newBinding = env.addBinding(global)
		}
		if i >= len(list.ListVals){
			errMsg := fmt.Sprintf("Error: nothing to assign to %v in %v at line %v.\n", val.Value, caller, lineNum)
			panic(errMsg)
		}
		nextVal := &list.ListVals[i+1]
		newBinding.Name = val.Value
		newValue := ListCell{TypeName: "undecided", Mutable: mut}
		typeNameAnnotated := ""
		switch (*nextVal).Type {
		case Parser.LiteralToken:
			newValue = evalNumToken(nextVal,lineNum,caller)
		case Parser.DefToken:
			errMsg := fmt.Sprintf("Error: attempting to assign reserved name %v to %v in %v at line %v.\n", (*nextVal).Value, val.Value, caller, lineNum)
			panic(errMsg)
		case Parser.ListToken:
			newValue.Value = evalListToken(nextVal)
		case Parser.TypeAnnToken:
			if i >= len(list.ListVals)+1{
				errMsg := fmt.Sprintf("Error: no type provided in assignment to %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			}
			nextValType := &list.ListVals[i+2]
			newValueType := ListCell{}
			newNameFound := false
			switch (*nextValType).Type {
			case Parser.LiteralToken:
				errMsg := fmt.Sprintf("Error: attempting use a numeric literal as the type for %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			case Parser.DefToken:
				errMsg := fmt.Sprintf("Error: attempting use a reserved name as the type for %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			case Parser.ListToken:
				newValueType = evalListToken(nextVal)
				if newValueType.TypeName != "type"{
					errMsg := fmt.Sprintf("Error: attempting to assign something that is not a type, but a %v, to %v in %v at line %v.\n", newValueType.TypeName, val.Value, caller, lineNum)
					panic(errMsg)
				}
				newNameFound = true
			case Parser.TypeAnnToken:
				errMsg := fmt.Sprintf("Error: misplaced type annotation marker in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			}
			typeName := nextValType.Value
			if newNameFound{
				if foundTypeActual, ok := newValueType.Value.(TypeDef); ok {
					typeName = foundTypeActual.Name
				}else{
					errMsg := fmt.Sprintf("Error: cell claiming to be a type actually contains something else, in %v at line %v.\n", caller, lineNum)
					panic(errMsg)
				}
			}
			namesBinding := env.findBinding(typeName, true)
			if _, ok := namesBinding.Binding.(TypeDef); ok{
				typeNameAnnotated = typeName
			}else{
				errMsg := fmt.Sprintf("Error: attempting to assign type %v to %v in %v at line %v, but that type is not bound.\n", typeName, val.Value, caller, lineNum)
				panic(errMsg)
			}
		}
		if newValue.TypeName != "undecided" && newValue.TypeName != typeNameAnnotated{
			errMsg := fmt.Sprintf("Error: attempting to assign type %v to %v in %v at line %v, but it is already of type %v.\n", typeNameAnnotated, val.Value, caller, lineNum, newValue.TypeName)
			panic(errMsg)
		}else if typeNameAnnotated != ""{
			newValue.TypeName = typeNameAnnotated
		}
		newBinding.Binding = newValue
	}
	return env
}

func evalListToken(list *Parser.Token)(ListCell){
	firstVal := &list.ListVals[0]
//	initCellList := CellList{}
	initEnvironment := Environment{}
	switch firstVal.Type{
	case Parser.LiteralToken:
		errMsg := fmt.Sprintf("Error: attempting to evaluate a literal, %v, at line %v.\n", firstVal.Value, firstVal.LineNum)
		panic(errMsg)
	case Parser.DefToken:
		defKind := &firstVal.Value
		if len(list.ListVals) < 3{
			errMsg := fmt.Sprintf("Error: too few arguments to %v at line %v.\n", defKind, firstVal.LineNum)
			panic(errMsg)
		}else if list.ListVals[1].Type != Parser.ListToken{
			errMsg := fmt.Sprintf("Error: first argument (%v) to %v at line %v is not a list.\n",list.ListVals[1].Value, defKind, firstVal.LineNum)
			panic(errMsg)
		}else if list.ListVals[2].Type != Parser.ListToken{
			errMsg := fmt.Sprintf("Error: second argument (%v) to %v  at line %v is not a list.\n",list.ListVals[2].Value, defKind, firstVal.LineNum)
			panic(errMsg)
		}else if len(list.ListVals) > 3{
			errMsg := fmt.Sprintf("Error: too many arguments to %v at line %v.\n",defKind, firstVal.LineNum)
			panic(errMsg)
		}
		initEnvironment = bindVars(&list.ListVals[1], initEnvironment, firstVal.LineNum, true, true, "let")

	}
	return ListCell{}
}

func main(){
	//types := []string{"Int", "Float", "Char", "Symbol", "List"}
	input := `(let (a 1) (b 2))`
	res := Parser.Lex(&input)
	tokens := Parser.ParseList(res, 0)
	for _, tok := range tokens.ListVals{
		fmt.Println(tok)
	}
	evalListToken(&tokens.ListVals[0])
}
<commit_msg>Improved type handling.<commit_after>package main

import(
	"fmt"
	"Golly/parser"
	"strconv"
)

type baseType int
const(
	Int baseType = iota
	Float
	Char
	Symbol
	List
	FuncDef
	VarDef
)

type FuncParem struct{
	Name string
	TypeID int64
}

type FunctionDef struct{
	NumParems int16
	Parems []FuncParem
	ReturnVals []FuncParem
}

type singleType struct{
	Inputs []string
	Outputs []string
	Order int8
}

type TypeDef struct{
	Name string
	Types []singleType
}

type Union struct{
	CurType int16
	Types []string
}

type EnvBinding struct{
	Name string
	Binding ListCell
}

type Environment []EnvBinding

func (env Environment) findBinding(name string, recur bool) *EnvBinding{
	for i, _ := range env{
		if env[i].Name == name{
			return &env[i]
		}
	}
	if recur{
		if len(env) == 0{
			panic("Error: root environment is empty!\n")
		}
		if env[0].Binding.TypeName == "environment"{
			if parentEnv, ok := env[0].Binding.Value.(Environment); ok {
				return parentEnv.findBinding(name, true)
			}else{
				panic("Error: encountered an environment-typed cell that contained no environment! This shouldn't happen; report it as a bug.\n")
			}
		}else{
			return nil
		}
	}
	return nil
}

func (env *Environment) addBinding(recur bool) *EnvBinding{
	if recur{
		if (*env)[0].Binding.TypeName == "environment"{
			if parentEnv, ok := (*env)[0].Binding.Value.(Environment); ok {
				return parentEnv.addBinding(true)
			}else{
				panic("Error: encountered an environment-typed cell that contained no environment! This shouldn't happen; report it as a bug.\n")
			}
		}else {
			*env = append(*env, EnvBinding{})
			return &((*env)[len(*env)])
		}
	}else{
		*env = append(*env, EnvBinding{})
		return &((*env)[len(*env)])
	}
}

type ListCell struct{
	TypeName string
	Value interface{}
	Mutable bool
}

type CellList struct{
	Cells []ListCell
	Environment []EnvBinding
}

func evalNumToken(num *Parser.Token, lineNum int, caller string)(ListCell){
	newValue := ListCell{}
			if (*num).LitType == Parser.FixNum{
				floatval, err := strconv.ParseFloat((*num).Value, 32)
				if err != nil{
					errMsg := fmt.Sprintf("Error: cannot parse string %v to float in %v at line %v.\n", (*num).Value, caller, lineNum)
					panic(errMsg)
				}else{
					newValue.Value = floatval
					newValue.TypeName = "float"
				}
			}else if (*num).LitType == Parser.FixNum{
				intval, err := strconv.Atoi((*num).Value)
				if err != nil{
					errMsg := fmt.Sprintf("Error: cannot parse string %v to int in %v at line %v.\n", (*num).Value, caller, lineNum)
					panic(errMsg)
				}else{
					newValue.Value = intval
					newValue.TypeName = "int"
				}
			}
	return newValue
}

func evalIdToken(identifierName *Parser.Token, env *Environment, lineNum int, caller string)(interface{}){
	var newValue interface{}
	valueReferenced := env.findBinding((*identifierName).Value, true)
			if valueReferenced == nil{
				errMsg := fmt.Sprintf("Error: attempting to evalute var %v in %v at line %v, but that var is unbound.\n", (*identifierName).Value, caller, lineNum)
				panic(errMsg)
			}else{
				newValue = valueReferenced.Binding
			}
	return newValue
}
func bindVars(list *Parser.Token, env Environment, lineNum int, global, mut bool, caller string)Environment{
	for i := 0; i < len(list.ListVals); i++{
		val := &list.ListVals[i]
		if val.Type != Parser.IdToken{
			errMsg := fmt.Sprintf("Error: attempting to assign to a non-identifier in %v at line %v.\n", caller, lineNum)
			panic(errMsg)
		}
		prevBinding := env.findBinding(val.Value, global)
		var newBinding *EnvBinding
		if prevBinding != nil{
			if !(*prevBinding).Binding.Mutable{
				errMsg := fmt.Sprintf("Error: attempting to assign to an immutable identifier in %v at line %v.\n", caller, lineNum)
				panic(errMsg)
			}else{
				newBinding = prevBinding
			}
		}else{
			newBinding = env.addBinding(global)
		}
		if i >= len(list.ListVals){
			errMsg := fmt.Sprintf("Error: nothing to assign to %v in %v at line %v.\n", val.Value, caller, lineNum)
			panic(errMsg)
		}
		nextVal := &list.ListVals[i+1]
		newBinding.Name = val.Value
		newValue := ListCell{TypeName: "undecided", Mutable: mut}
		typeNameAnnotated := ""
		switch (*nextVal).Type {
		case Parser.LiteralToken:
			newValue = evalNumToken(nextVal,lineNum,caller)
		case Parser.DefToken:
			errMsg := fmt.Sprintf("Error: attempting to assign reserved name %v to %v in %v at line %v.\n", (*nextVal).Value, val.Value, caller, lineNum)
			panic(errMsg)
		case Parser.ListToken:
			newValue.Value = evalListToken(nextVal)
		case Parser.TypeAnnToken:
			if i >= len(list.ListVals)+1{
				errMsg := fmt.Sprintf("Error: no type provided in assignment to %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			}
			nextValType := &list.ListVals[i+2]
			newValueType := ListCell{}
			newNameFound := false
			switch (*nextValType).Type {
			case Parser.LiteralToken:
				errMsg := fmt.Sprintf("Error: attempting use a numeric literal as the type for %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			case Parser.DefToken:
				errMsg := fmt.Sprintf("Error: attempting use a reserved name as the type for %v in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			case Parser.ListToken:
				newValueType = evalListToken(nextVal)
				if newValueType.TypeName != "type"{
					errMsg := fmt.Sprintf("Error: attempting to assign something that is not a type, but a %v, to %v in %v at line %v.\n", newValueType.TypeName, val.Value, caller, lineNum)
					panic(errMsg)
				}
				newNameFound = true
			case Parser.TypeAnnToken:
				errMsg := fmt.Sprintf("Error: misplaced type annotation marker in %v at line %v.\n", val.Value, caller, lineNum)
				panic(errMsg)
			}
			typeName := nextValType.Value
			if newNameFound{
				if foundTypeActual, ok := newValueType.Value.(TypeDef); ok {
					typeName = foundTypeActual.Name
				}else{
					errMsg := fmt.Sprintf("Error: cell claiming to be a type actually contains something else, in %v at line %v.\n", caller, lineNum)
					panic(errMsg)
				}
			}
			namesBinding := env.findBinding(typeName, true)
			if namesBinding.Binding.TypeName == "type"{
				typeNameAnnotated = typeName
			}else{
				errMsg := fmt.Sprintf("Error: attempting to assign type %v to %v in %v at line %v, but that type is not bound.\n", typeName, val.Value, caller, lineNum)
				panic(errMsg)
			}
		}
		if newValue.TypeName != "undecided" && newValue.TypeName != typeNameAnnotated{
			errMsg := fmt.Sprintf("Error: attempting to assign type %v to %v in %v at line %v, but it is already of type %v.\n", typeNameAnnotated, val.Value, caller, lineNum, newValue.TypeName)
			panic(errMsg)
		}else if typeNameAnnotated != ""{
			newValue.TypeName = typeNameAnnotated
		}
		newBinding.Binding = newValue
	}
	return env
}

func evalListToken(list *Parser.Token)(ListCell){
	firstVal := &list.ListVals[0]
//	initCellList := CellList{}
	initEnvironment := Environment{}
	switch firstVal.Type{
	case Parser.LiteralToken:
		errMsg := fmt.Sprintf("Error: attempting to evaluate a literal, %v, at line %v.\n", firstVal.Value, firstVal.LineNum)
		panic(errMsg)
	case Parser.DefToken:
		defKind := &firstVal.Value
		if len(list.ListVals) < 3{
			errMsg := fmt.Sprintf("Error: too few arguments to %v at line %v.\n", defKind, firstVal.LineNum)
			panic(errMsg)
		}else if list.ListVals[1].Type != Parser.ListToken{
			errMsg := fmt.Sprintf("Error: first argument (%v) to %v at line %v is not a list.\n",list.ListVals[1].Value, defKind, firstVal.LineNum)
			panic(errMsg)
		}else if list.ListVals[2].Type != Parser.ListToken{
			errMsg := fmt.Sprintf("Error: second argument (%v) to %v  at line %v is not a list.\n",list.ListVals[2].Value, defKind, firstVal.LineNum)
			panic(errMsg)
		}else if len(list.ListVals) > 3{
			errMsg := fmt.Sprintf("Error: too many arguments to %v at line %v.\n",defKind, firstVal.LineNum)
			panic(errMsg)
		}
		initEnvironment = bindVars(&list.ListVals[1], initEnvironment, firstVal.LineNum, true, true, "let")

	}
	return ListCell{}
}

func main(){
	//types := []string{"Int", "Float", "Char", "Symbol", "List"}
	input := `(let (a 1) (b 2))`
	res := Parser.Lex(&input)
	tokens := Parser.ParseList(res, 0)
	for _, tok := range tokens.ListVals{
		fmt.Println(tok)
	}
	evalListToken(&tokens.ListVals[0])
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"fmt"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/dal"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/handlers"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/libenv"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/libunix"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/middlewares"
	"github.com/carbocation/interpose"
	gorilla_mux "github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"github.com/Sirupsen/logrus"
	"github.com/tylerb/graceful"
	"net/http"
	"time"
)

func init() {
	gob.Register(&dal.UserRow{})
}

// NewApplication is the constructor for Application struct.
func NewApplication() (*Application, error) {
	u, err := libunix.CurrentUser()
	if err != nil {
		return nil, err
	}

	dsn := libenv.EnvWithDefault("DSN", fmt.Sprintf("postgres://%v@localhost:5432/$GO_BOOTSTRAP_PROJECT_NAME?sslmode=disable", u))

	db, err := sqlx.Connect("postgres", dsn)
	if err != nil {
		return nil, err
	}

	cookieStoreSecret := libenv.EnvWithDefault("COOKIE_SECRET", "$GO_BOOTSTRAP_COOKIE_SECRET")

	rm := &Application{}
	rm.dsn = dsn
	rm.db = db
	rm.cookieStore = sessions.NewCookieStore([]byte(cookieStoreSecret))

	return rm, err
}

// Application is the application object that runs HTTP server.
type Application struct {
	dsn         string
	db          *sqlx.DB
	cookieStore *sessions.CookieStore
}

func (rm *Application) middlewareStruct() (*interpose.Middleware, error) {
	middle := interpose.New()
	middle.Use(middlewares.SetDB(rm.db))
	middle.Use(middlewares.SetCookieStore(rm.cookieStore))

	middle.UseHandler(rm.mux())

	return middle, nil
}

func (rm *Application) mux() *gorilla_mux.Router {
	MustLogin := middlewares.MustLogin

	router := gorilla_mux.NewRouter()

	router.Handle("/", MustLogin(http.HandlerFunc(handlers.GetHome))).Methods("GET")

	router.HandleFunc("/signup", handlers.GetSignup).Methods("GET")
	router.HandleFunc("/signup", handlers.PostSignup).Methods("POST")
	router.HandleFunc("/login", handlers.GetLogin).Methods("GET")
	router.HandleFunc("/login", handlers.PostLogin).Methods("POST")
	router.HandleFunc("/logout", handlers.GetLogout).Methods("GET")

	router.Handle("/users/{id:[0-9]+}", MustLogin(http.HandlerFunc(handlers.PostPutDeleteUsersID))).Methods("POST", "PUT", "DELETE")

	// Path of static files must be last!
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("static")))

	return router
}

func main() {
	app, err := NewApplication()
	if err != nil {
		logrus.Fatal(err.Error())
	}

	middle, err := app.middlewareStruct()
	if err != nil {
		logrus.Fatal(err.Error())
	}

	serverAddress := libenv.EnvWithDefault("HTTP_ADDR", ":8888")
	certFile := libenv.EnvWithDefault("HTTP_CERT_FILE", "")
	keyFile := libenv.EnvWithDefault("HTTP_KEY_FILE", "")
	drainIntervalString := libenv.EnvWithDefault("HTTP_DRAIN_INTERVAL", "1s")

	drainInterval, err := time.ParseDuration(drainIntervalString)
	if err != nil {
		logrus.Fatal(err.Error())
	}

	srv := &graceful.Server{
		Timeout: drainInterval,
		Server:  &http.Server{Addr: serverAddress, Handler: middle},
	}

	logrus.Infoln("Running HTTP server on "+ serverAddress)
	if certFile != "" && keyFile != "" {
		srv.ListenAndServeTLS(certFile, keyFile)
	} else {
		srv.ListenAndServe()
	}
}
<commit_msg>cleanup self pointer on main.go<commit_after>package main

import (
	"encoding/gob"
	"fmt"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/dal"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/handlers"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/libenv"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/libunix"
	"$GO_BOOTSTRAP_REPO_NAME/$GO_BOOTSTRAP_REPO_USER/$GO_BOOTSTRAP_PROJECT_NAME/middlewares"
	"github.com/carbocation/interpose"
	gorilla_mux "github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"github.com/Sirupsen/logrus"
	"github.com/tylerb/graceful"
	"net/http"
	"time"
)

func init() {
	gob.Register(&dal.UserRow{})
}

// NewApplication is the constructor for Application struct.
func NewApplication() (*Application, error) {
	u, err := libunix.CurrentUser()
	if err != nil {
		return nil, err
	}

	dsn := libenv.EnvWithDefault("DSN", fmt.Sprintf("postgres://%v@localhost:5432/$GO_BOOTSTRAP_PROJECT_NAME?sslmode=disable", u))

	db, err := sqlx.Connect("postgres", dsn)
	if err != nil {
		return nil, err
	}

	cookieStoreSecret := libenv.EnvWithDefault("COOKIE_SECRET", "$GO_BOOTSTRAP_COOKIE_SECRET")

	app := &Application{}
	app.dsn = dsn
	app.db = db
	app.cookieStore = sessions.NewCookieStore([]byte(cookieStoreSecret))

	return app, err
}

// Application is the application object that runs HTTP server.
type Application struct {
	dsn         string
	db          *sqlx.DB
	cookieStore *sessions.CookieStore
}

func (app *Application) middlewareStruct() (*interpose.Middleware, error) {
	middle := interpose.New()
	middle.Use(middlewares.SetDB(app.db))
	middle.Use(middlewares.SetCookieStore(app.cookieStore))

	middle.UseHandler(app.mux())

	return middle, nil
}

func (app *Application) mux() *gorilla_mux.Router {
	MustLogin := middlewares.MustLogin

	router := gorilla_mux.NewRouter()

	router.Handle("/", MustLogin(http.HandlerFunc(handlers.GetHome))).Methods("GET")

	router.HandleFunc("/signup", handlers.GetSignup).Methods("GET")
	router.HandleFunc("/signup", handlers.PostSignup).Methods("POST")
	router.HandleFunc("/login", handlers.GetLogin).Methods("GET")
	router.HandleFunc("/login", handlers.PostLogin).Methods("POST")
	router.HandleFunc("/logout", handlers.GetLogout).Methods("GET")

	router.Handle("/users/{id:[0-9]+}", MustLogin(http.HandlerFunc(handlers.PostPutDeleteUsersID))).Methods("POST", "PUT", "DELETE")

	// Path of static files must be last!
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("static")))

	return router
}

func main() {
	app, err := NewApplication()
	if err != nil {
		logrus.Fatal(err.Error())
	}

	middle, err := app.middlewareStruct()
	if err != nil {
		logrus.Fatal(err.Error())
	}

	serverAddress := libenv.EnvWithDefault("HTTP_ADDR", ":8888")
	certFile := libenv.EnvWithDefault("HTTP_CERT_FILE", "")
	keyFile := libenv.EnvWithDefault("HTTP_KEY_FILE", "")
	drainIntervalString := libenv.EnvWithDefault("HTTP_DRAIN_INTERVAL", "1s")

	drainInterval, err := time.ParseDuration(drainIntervalString)
	if err != nil {
		logrus.Fatal(err.Error())
	}

	srv := &graceful.Server{
		Timeout: drainInterval,
		Server:  &http.Server{Addr: serverAddress, Handler: middle},
	}

	logrus.Infoln("Running HTTP server on "+ serverAddress)
	if certFile != "" && keyFile != "" {
		srv.ListenAndServeTLS(certFile, keyFile)
	} else {
		srv.ListenAndServe()
	}
}
<|endoftext|>


<commit_before>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "strings"
)

type Channel struct {
    ircd *Ircd // Pointer to the IRCd instance.

    name string // The name of the channel.
    topic string // The topic of the channel.

    joining chan *Client // Channel of Joining Members.
    parting chan *Client // Channel of Members whom are leaving.
    read_topic chan chan string // Channel for synchronous read of the topic.
    private_messages chan *PrivateMessage // Channel of private messages.

    clients *ClientSet // Client Members.
}

func NewChannel(ircd *Ircd, name string) *Channel {
    channel := new(Channel)

    // Channel Name.
    channel.name = name

    // Default to Empty Topic.
    channel.topic = ""

    // The IRCd.
    channel.ircd = ircd

    // Clients.
    channel.clients = NewClientSet()

    // Channels.
    channel.joining = make(chan *Client)
    channel.parting = make(chan *Client)
    channel.read_topic = make(chan chan string)
    channel.private_messages = make(chan *PrivateMessage)

    // Message Handler.
    go channel.Handler()

    return channel
}

func (this *Channel) Handler() {
    this.Printf("Starting Channel Handler")
    defer this.Printf("Leaving Channel Handler")

    // The IRCd.
    ircd := this.ircd

    for {
        select {
            case joining_client := <-this.joining:
                this.Printf("Client '%s' joined.", joining_client)

                // This is true, if our joining client is the creator of the channel.
                //   creator := this.clients.Len() == 0

                // Insert our new client.
                this.clients.Insert(joining_client)

                // Send JOIN message to all clients.
                this.clients.ForEach(func (client *Client) {
                    client.ChannelJoin(joining_client, this)
                })

                // Client Names.
                names := this.clients.Names()

                // NOTE: See RB codebase for information about the "=" here.
                joining_client.SendNumeric(RPL_NAMREPLY, ircd.Me(), joining_client.Nickname(), "=", this.name, strings.Join(names, " "))

                // FIXME: This could become a long message for large channels.
                joining_client.SendNumeric(RPL_ENDOFNAMES, ircd.Me(), joining_client.Nickname(), this.name)

            case parting_client := <-this.parting:
                this.Printf("Client '%s' left.", parting_client)

                // Send PART message to all clients, including ourself.
                this.clients.ForEach(func (client *Client) {
                    client.ChannelPart(parting_client, this)
                })

                // Remove our client.
                this.clients.Delete(parting_client)

                // Last member left?
                if this.clients.Len() == 0 {
                    // Unregister.
                    this.Unregister()

                    // Shutdown.
                    return
                }

            case topic_reader := <-this.read_topic:
                // Send topic.
                topic_reader<-this.topic

            case message := <-this.private_messages:
                // Source Client.
                source := message.Source()

                // Broadcast to each client, except the source.
                this.clients.ForEach(func (client *Client) {
                    // FIXME: Should we compare source.Nickname() with
                    // client.Nickname() here?
                    if source == client {
                        // Don't send message to ourself.
                        return
                    }

                    // Send message.
                    client.PrivateMessage(message)
                })
        }
    }
}

func (this *Channel) Join(client *Client) {
    this.joining<-client
}

func (this *Channel) Part(client *Client) {
    this.parting<-client
}

func (this *Channel) Topic() string {
    c := make(chan string)
    this.read_topic<-c
    return <-c
}

func (this *Channel) PrivateMessage(message *PrivateMessage) {
    this.private_messages<-message
}

func (this *Channel) Unregister() {
    this.ircd.UnregisterChannel(this)
}

func (this *Channel) Name() string {
    return this.name
}

func (this *Channel) String() string {
    return this.name
}

func (this *Channel) Printf(format string, a...interface{}) {
    this.ircd.Printf(this.String() + ": " + format, a...)
}
<commit_msg>Add ClientCount() to the Channel type.<commit_after>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "strings"
)

type Channel struct {
    ircd *Ircd // Pointer to the IRCd instance.

    name string // The name of the channel.
    topic string // The topic of the channel.

    joining chan *Client // Channel of Joining Members.
    parting chan *Client // Channel of Members whom are leaving.
    read_topic chan chan string // Channel for synchronous read of the topic.
    read_client_count chan chan int // Channel for reading the client count of the channel.
    private_messages chan *PrivateMessage // Channel of private messages.

    clients *ClientSet // Client Members.
}

func NewChannel(ircd *Ircd, name string) *Channel {
    channel := new(Channel)

    // Channel Name.
    channel.name = name

    // Default to Empty Topic.
    channel.topic = ""

    // The IRCd.
    channel.ircd = ircd

    // Clients.
    channel.clients = NewClientSet()

    // Channels.
    channel.joining = make(chan *Client)
    channel.parting = make(chan *Client)
    channel.read_topic = make(chan chan string)
    channel.private_messages = make(chan *PrivateMessage)
    channel.read_client_count = make(chan chan int)

    // Message Handler.
    go channel.Handler()

    return channel
}

func (this *Channel) Handler() {
    this.Printf("Starting Channel Handler")
    defer this.Printf("Leaving Channel Handler")

    // The IRCd.
    ircd := this.ircd

    for {
        select {
            case joining_client := <-this.joining:
                this.Printf("Client '%s' joined.", joining_client)

                // This is true, if our joining client is the creator of the channel.
                //   creator := this.clients.Len() == 0

                // Insert our new client.
                this.clients.Insert(joining_client)

                // Send JOIN message to all clients.
                this.clients.ForEach(func (client *Client) {
                    client.ChannelJoin(joining_client, this)
                })

                // Client Names.
                names := this.clients.Names()

                // NOTE: See RB codebase for information about the "=" here.
                joining_client.SendNumeric(RPL_NAMREPLY, ircd.Me(), joining_client.Nickname(), "=", this.name, strings.Join(names, " "))

                // FIXME: This could become a long message for large channels.
                joining_client.SendNumeric(RPL_ENDOFNAMES, ircd.Me(), joining_client.Nickname(), this.name)

            case parting_client := <-this.parting:
                this.Printf("Client '%s' left.", parting_client)

                // Send PART message to all clients, including ourself.
                this.clients.ForEach(func (client *Client) {
                    client.ChannelPart(parting_client, this)
                })

                // Remove our client.
                this.clients.Delete(parting_client)

                // Last member left?
                if this.clients.Len() == 0 {
                    // Unregister.
                    this.Unregister()

                    // Shutdown.
                    return
                }

            case topic_reader := <-this.read_topic:
                // Send topic.
                topic_reader<-this.topic

            case client_count_reader := <-this.read_client_count:
                // Send the client count.
                client_count_reader<-this.clients.Len()

            case message := <-this.private_messages:
                // Source Client.
                source := message.Source()

                // Broadcast to each client, except the source.
                this.clients.ForEach(func (client *Client) {
                    // FIXME: Should we compare source.Nickname() with
                    // client.Nickname() here?
                    if source == client {
                        // Don't send message to ourself.
                        return
                    }

                    // Send message.
                    client.PrivateMessage(message)
                })
        }
    }
}

func (this *Channel) Join(client *Client) {
    this.joining<-client
}

func (this *Channel) Part(client *Client) {
    this.parting<-client
}

func (this *Channel) Topic() string {
    c := make(chan string)
    this.read_topic<-c
    return <-c
}

func (this *Channel) ClientCount() chan int {
    c := make(chan int)
    this.read_client_count<-c
    return c
}

func (this *Channel) PrivateMessage(message *PrivateMessage) {
    this.private_messages<-message
}

func (this *Channel) Unregister() {
    this.ircd.UnregisterChannel(this)
}

func (this *Channel) Name() string {
    return this.name
}

func (this *Channel) String() string {
    return this.name
}

func (this *Channel) Printf(format string, a...interface{}) {
    this.ircd.Printf(this.String() + ": " + format, a...)
}
<|endoftext|>


<commit_before>package cli

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	humanize "github.com/dustin/go-humanize"
	"github.com/schollz/croc/src/croc"
	"github.com/schollz/croc/src/utils"
	"github.com/skratchdot/open-golang/open"
	"github.com/urfave/cli"
)

var Version string
var codePhrase string
var cr *croc.Croc

func Run() {
	app := cli.NewApp()
	app.Name = "croc"
	if Version == "" {
		Version = "dev"
	}

	app.Version = Version
	app.Compiled = time.Now()
	app.Usage = "easily and securely transfer stuff from one computer to another"
	app.UsageText = "croc allows any two computers to directly and securely transfer files"
	// app.ArgsUsage = "[args and such]"
	app.Commands = []cli.Command{
		{
			Name:        "send",
			Usage:       "send a file",
			Description: "send a file over the relay",
			ArgsUsage:   "[filename]",
			Flags: []cli.Flag{
				cli.BoolFlag{Name: "no-compress, o", Usage: "disable compression"},
				cli.BoolFlag{Name: "no-encrypt, e", Usage: "disable encryption"},
				cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"},
			},
			HelpName: "croc send",
			Action: func(c *cli.Context) error {
				return send(c)
			},
		},
		{
			Name:        "relay",
			Usage:       "start a croc relay",
			Description: "the croc relay will handle websocket and TCP connections",
			Flags:       []cli.Flag{},
			HelpName:    "croc relay",
			Action: func(c *cli.Context) error {
				return relay(c)
			},
		},
		{
			Name:        "config",
			Usage:       "generates a config file",
			Description: "the croc config can be used to set static parameters",
			Flags:       []cli.Flag{},
			HelpName:    "croc config",
			Action: func(c *cli.Context) error {
				return saveDefaultConfig(c)
			},
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "addr", Value: "croc4.schollz.com", Usage: "address of the public relay"},
		cli.StringFlag{Name: "addr-ws", Value: "8153", Usage: "port of the public relay websocket server to connect"},
		cli.StringFlag{Name: "addr-tcp", Value: "8154,8155,8156,8157,8158,8159,8160,8161", Usage: "tcp ports of the public relay server to connect"},
		cli.BoolFlag{Name: "no-local", Usage: "disable local mode"},
		cli.BoolFlag{Name: "local", Usage: "use only local mode"},
		cli.BoolFlag{Name: "debug", Usage: "increase verbosity (a lot)"},
		cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
		cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"},
		cli.BoolFlag{Name: "force-tcp", Usage: "force TCP"},
		cli.BoolFlag{Name: "force-web", Usage: "force websockets"},
		cli.StringFlag{Name: "port", Value: "8153", Usage: "port that the websocket listens on"},
		cli.StringFlag{Name: "tcp-port", Value: "8154,8155,8156,8157,8158,8159,8160,8161", Usage: "ports that the tcp server listens on"},
		cli.StringFlag{Name: "curve", Value: "siec", Usage: "specify elliptic curve to use for PAKE (p256, p384, p521, siec)"},
	}
	app.EnableBashCompletion = true
	app.HideHelp = false
	app.HideVersion = false
	app.BashComplete = func(c *cli.Context) {
		fmt.Fprintf(c.App.Writer, "send\nreceive\relay")
	}
	app.Action = func(c *cli.Context) error {
		return receive(c)
	}
	app.Before = func(c *cli.Context) error {
		cr = croc.Init(c.GlobalBool("debug"))
		cr.Version = Version
		cr.AllowLocalDiscovery = true
		cr.Address = c.GlobalString("addr")
		cr.AddressTCPPorts = strings.Split(c.GlobalString("addr-tcp"), ",")
		cr.AddressWebsocketPort = c.GlobalString("addr-ws")
		cr.NoRecipientPrompt = c.GlobalBool("yes")
		cr.Stdout = c.GlobalBool("stdout")
		cr.LocalOnly = c.GlobalBool("local")
		cr.NoLocal = c.GlobalBool("no-local")
		cr.ShowText = true
		cr.RelayWebsocketPort = c.String("port")
		cr.RelayTCPPorts = strings.Split(c.String("tcp-port"), ",")
		cr.CurveType = c.String("curve")
		if c.GlobalBool("force-tcp") {
			cr.ForceSend = 2
		}
		if c.GlobalBool("force-web") {
			cr.ForceSend = 1
		}
		return nil
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Printf("\nerror: %s", err.Error())
	}
}

func saveDefaultConfig(c *cli.Context) error {
	return croc.SaveDefaultConfig()
}

func send(c *cli.Context) error {
	stat, _ := os.Stdin.Stat()
	var fname string
	if (stat.Mode() & os.ModeCharDevice) == 0 {
		f, err := ioutil.TempFile(".", "croc-stdin-")
		if err != nil {
			return err
		}
		_, err = io.Copy(f, os.Stdin)
		if err != nil {
			return err
		}
		err = f.Close()
		if err != nil {
			return err
		}
		fname = f.Name()
		defer func() {
			err = os.Remove(fname)
			if err != nil {
				log.Println(err)
			}
		}()
	} else {
		fname = c.Args().First()
	}
	if fname == "" {
		return errors.New("must specify file: croc send [filename]")
	}
	cr.UseCompression = !c.Bool("no-compress")
	cr.UseEncryption = !c.Bool("no-encrypt")
	if c.String("code") != "" {
		cr.Codephrase = c.String("code")
	}
	cr.LoadConfig()
	if len(cr.Codephrase) == 0 {
		// generate code phrase
		cr.Codephrase = utils.GetRandomName()
	}

	// print the text
	finfo, err := os.Stat(fname)
	if err != nil {
		return err
	}
	fname, _ = filepath.Abs(fname)
	fname = filepath.Clean(fname)
	_, filename := filepath.Split(fname)
	fileOrFolder := "file"
	fsize := finfo.Size()
	if finfo.IsDir() {
		fileOrFolder = "folder"
		fsize, err = dirSize(fname)
		if err != nil {
			return err
		}
	}
	fmt.Fprintf(os.Stderr,
		"Sending %s %s named '%s'\nCode is: %s\nOn the other computer, please run:\n\ncroc %s\n\n",
		humanize.Bytes(uint64(fsize)),
		fileOrFolder,
		filename,
		cr.Codephrase,
		cr.Codephrase,
	)
	return cr.Send(fname, cr.Codephrase)
}

func receive(c *cli.Context) error {
	if c.GlobalString("code") != "" {
		codePhrase = c.GlobalString("code")
	}
	if c.Args().First() != "" {
		codePhrase = c.Args().First()
	}
	openFolder := false
	if len(os.Args) == 1 {
		// open folder since they didn't give any arguments
		openFolder = true
	}
	if codePhrase == "" {
		codePhrase = utils.GetInput("Enter receive code: ")
	}
	err := cr.Receive(codePhrase)
	if err == nil && openFolder {
		cwd, _ := os.Getwd()
		open.Run(cwd)
	}
	return err
}

func relay(c *cli.Context) error {
	return cr.Relay()
}

func dirSize(path string) (int64, error) {
	var size int64
	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			size += info.Size()
		}
		return err
	})
	return size, err
}
<commit_msg>recipient also uses codephrase<commit_after>package cli

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	humanize "github.com/dustin/go-humanize"
	"github.com/schollz/croc/src/croc"
	"github.com/schollz/croc/src/utils"
	"github.com/skratchdot/open-golang/open"
	"github.com/urfave/cli"
)

var Version string
var cr *croc.Croc

func Run() {
	app := cli.NewApp()
	app.Name = "croc"
	if Version == "" {
		Version = "dev"
	}

	app.Version = Version
	app.Compiled = time.Now()
	app.Usage = "easily and securely transfer stuff from one computer to another"
	app.UsageText = "croc allows any two computers to directly and securely transfer files"
	// app.ArgsUsage = "[args and such]"
	app.Commands = []cli.Command{
		{
			Name:        "send",
			Usage:       "send a file",
			Description: "send a file over the relay",
			ArgsUsage:   "[filename]",
			Flags: []cli.Flag{
				cli.BoolFlag{Name: "no-compress, o", Usage: "disable compression"},
				cli.BoolFlag{Name: "no-encrypt, e", Usage: "disable encryption"},
				cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"},
			},
			HelpName: "croc send",
			Action: func(c *cli.Context) error {
				return send(c)
			},
		},
		{
			Name:        "relay",
			Usage:       "start a croc relay",
			Description: "the croc relay will handle websocket and TCP connections",
			Flags:       []cli.Flag{},
			HelpName:    "croc relay",
			Action: func(c *cli.Context) error {
				return relay(c)
			},
		},
		{
			Name:        "config",
			Usage:       "generates a config file",
			Description: "the croc config can be used to set static parameters",
			Flags:       []cli.Flag{},
			HelpName:    "croc config",
			Action: func(c *cli.Context) error {
				return saveDefaultConfig(c)
			},
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "addr", Value: "croc4.schollz.com", Usage: "address of the public relay"},
		cli.StringFlag{Name: "addr-ws", Value: "8153", Usage: "port of the public relay websocket server to connect"},
		cli.StringFlag{Name: "addr-tcp", Value: "8154,8155,8156,8157,8158,8159,8160,8161", Usage: "tcp ports of the public relay server to connect"},
		cli.BoolFlag{Name: "no-local", Usage: "disable local mode"},
		cli.BoolFlag{Name: "local", Usage: "use only local mode"},
		cli.BoolFlag{Name: "debug", Usage: "increase verbosity (a lot)"},
		cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
		cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"},
		cli.BoolFlag{Name: "force-tcp", Usage: "force TCP"},
		cli.BoolFlag{Name: "force-web", Usage: "force websockets"},
		cli.StringFlag{Name: "port", Value: "8153", Usage: "port that the websocket listens on"},
		cli.StringFlag{Name: "tcp-port", Value: "8154,8155,8156,8157,8158,8159,8160,8161", Usage: "ports that the tcp server listens on"},
		cli.StringFlag{Name: "curve", Value: "siec", Usage: "specify elliptic curve to use for PAKE (p256, p384, p521, siec)"},
	}
	app.EnableBashCompletion = true
	app.HideHelp = false
	app.HideVersion = false
	app.BashComplete = func(c *cli.Context) {
		fmt.Fprintf(c.App.Writer, "send\nreceive\relay")
	}
	app.Action = func(c *cli.Context) error {
		return receive(c)
	}
	app.Before = func(c *cli.Context) error {
		cr = croc.Init(c.GlobalBool("debug"))
		cr.Version = Version
		cr.AllowLocalDiscovery = true
		cr.Address = c.GlobalString("addr")
		cr.AddressTCPPorts = strings.Split(c.GlobalString("addr-tcp"), ",")
		cr.AddressWebsocketPort = c.GlobalString("addr-ws")
		cr.NoRecipientPrompt = c.GlobalBool("yes")
		cr.Stdout = c.GlobalBool("stdout")
		cr.LocalOnly = c.GlobalBool("local")
		cr.NoLocal = c.GlobalBool("no-local")
		cr.ShowText = true
		cr.RelayWebsocketPort = c.String("port")
		cr.RelayTCPPorts = strings.Split(c.String("tcp-port"), ",")
		cr.CurveType = c.String("curve")
		if c.GlobalBool("force-tcp") {
			cr.ForceSend = 2
		}
		if c.GlobalBool("force-web") {
			cr.ForceSend = 1
		}
		return nil
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Printf("\nerror: %s", err.Error())
	}
}

func saveDefaultConfig(c *cli.Context) error {
	return croc.SaveDefaultConfig()
}

func send(c *cli.Context) error {
	stat, _ := os.Stdin.Stat()
	var fname string
	if (stat.Mode() & os.ModeCharDevice) == 0 {
		f, err := ioutil.TempFile(".", "croc-stdin-")
		if err != nil {
			return err
		}
		_, err = io.Copy(f, os.Stdin)
		if err != nil {
			return err
		}
		err = f.Close()
		if err != nil {
			return err
		}
		fname = f.Name()
		defer func() {
			err = os.Remove(fname)
			if err != nil {
				log.Println(err)
			}
		}()
	} else {
		fname = c.Args().First()
	}
	if fname == "" {
		return errors.New("must specify file: croc send [filename]")
	}
	cr.UseCompression = !c.Bool("no-compress")
	cr.UseEncryption = !c.Bool("no-encrypt")
	if c.String("code") != "" {
		cr.Codephrase = c.String("code")
	}
	cr.LoadConfig()
	if len(cr.Codephrase) == 0 {
		// generate code phrase
		cr.Codephrase = utils.GetRandomName()
	}

	// print the text
	finfo, err := os.Stat(fname)
	if err != nil {
		return err
	}
	fname, _ = filepath.Abs(fname)
	fname = filepath.Clean(fname)
	_, filename := filepath.Split(fname)
	fileOrFolder := "file"
	fsize := finfo.Size()
	if finfo.IsDir() {
		fileOrFolder = "folder"
		fsize, err = dirSize(fname)
		if err != nil {
			return err
		}
	}
	fmt.Fprintf(os.Stderr,
		"Sending %s %s named '%s'\nCode is: %s\nOn the other computer, please run:\n\ncroc %s\n\n",
		humanize.Bytes(uint64(fsize)),
		fileOrFolder,
		filename,
		cr.Codephrase,
		cr.Codephrase,
	)
	return cr.Send(fname, cr.Codephrase)
}

func receive(c *cli.Context) error {
	if c.GlobalString("code") != "" {
		cr.Codephrase = c.GlobalString("code")
	}
	if c.Args().First() != "" {
		cr.Codephrase = c.Args().First()
	}
	cr.LoadConfig()
	openFolder := false
	if len(os.Args) == 1 {
		// open folder since they didn't give any arguments
		openFolder = true
	}
	if cr.Codephrase == "" {
		cr.Codephrase = utils.GetInput("Enter receive code: ")
	}
	err := cr.Receive(cr.Codephrase)
	if err == nil && openFolder {
		cwd, _ := os.Getwd()
		open.Run(cwd)
	}
	return err
}

func relay(c *cli.Context) error {
	return cr.Relay()
}

func dirSize(path string) (int64, error) {
	var size int64
	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			size += info.Size()
		}
		return err
	})
	return size, err
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function == "delete" {
		// Deletes an entity from its state
		return t.delete(stub, args)
	}

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Avalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Bvalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	if err != nil {
		return nil, errors.New("Invalid transaction amount, expecting a integer value")
	}
	Aval = Aval - X
	Bval = Bval + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var A string // Entities
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return Avalbytes, nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<commit_msg>Update chaincode_example02.go<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function == "delete" {
		// Deletes an entity from its state
		return t.delete(stub, args)
	}

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Avalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Bvalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	if err != nil {
		return nil, errors.New("Invalid transaction amount, expecting a integer value")
	}
	Aval = Aval - X
	Bval = Bval + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var A string // Entities
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return Avalbytes, nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 Conformal Systems LLC <info@conformal.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"sync"
	"time"

	"github.com/btcsuite/btcd/btcjson/v2/btcjson"
	"github.com/btcsuite/btcd/wire"
	rpc "github.com/btcsuite/btcrpcclient"
	"github.com/btcsuite/btcutil"
)

// minFee is the minimum tx fee that can be paid
const minFee btcutil.Amount = 1e4 // 0.0001 BTC

// utxoQueue is the queue of utxos belonging to a actor
// utxos are queued after a block is received and are dispatched
// to their respective owner from com.poolUtxos
// they are dequeued from simulateTx and splitUtxos
type utxoQueue struct {
	utxos   []*TxOut
	enqueue chan *TxOut
	dequeue chan *TxOut
}

// Actor describes an actor on the simulation network.  Each actor runs
// independantly without external input to decide it's behavior.
type Actor struct {
	*Node
	quit             chan struct{}
	wg               sync.WaitGroup
	ownedAddresses   []btcutil.Address
	utxoQueue        *utxoQueue
	miningAddr       chan btcutil.Address
	walletPassphrase string
}

// TxOut is a valid tx output that can be used to generate transactions
type TxOut struct {
	OutPoint *wire.OutPoint
	Amount   btcutil.Amount
}

// NewActor creates a new actor which runs its own wallet process connecting
// to the btcd node server specified by node, and listening for simulator
// websocket connections on the specified port.
func NewActor(node *Node, port uint16) (*Actor, error) {
	// Please don't run this as root.
	if port < 1024 {
		return nil, errors.New("invalid actor port")
	}

	// Set btcwallet node args
	args, err := newBtcwalletArgs(port, node.Args.(*btcdArgs))
	if err != nil {
		return nil, err
	}

	logFile, err := getLogFile(args.prefix)
	if err != nil {
		log.Printf("Cannot get log file, logging disabled: %v", err)
	}
	btcwallet, err := NewNodeFromArgs(args, nil, logFile)
	if err != nil {
		return nil, err
	}

	a := Actor{
		Node:             btcwallet,
		quit:             make(chan struct{}),
		ownedAddresses:   make([]btcutil.Address, *maxAddresses),
		miningAddr:       make(chan btcutil.Address),
		walletPassphrase: "password",
		utxoQueue: &utxoQueue{
			enqueue: make(chan *TxOut),
			dequeue: make(chan *TxOut),
		},
	}
	return &a, nil
}

// Start creates the command to execute a wallet process and starts the
// command in the background, attaching the command's stderr and stdout
// to the passed writers. Nil writers may be used to discard output.
//
// In addition to starting the wallet process, this runs goroutines to
// handle wallet notifications and requests the wallet process to create
// an intial encrypted wallet, so that it can actually send and receive BTC.
//
// If the RPC client connection cannot be established or wallet cannot
// be created, the wallet process is killed and the actor directory
// removed.
func (a *Actor) Start(stderr, stdout io.Writer, com *Communication) error {
	connected := make(chan struct{})
	const timeoutSecs int64 = 3600 * 24

	if err := a.Node.Start(); err != nil {
		a.Shutdown()
		com.errChan <- struct{}{}
		return err
	}

	ntfnHandlers := &rpc.NotificationHandlers{
		OnClientConnected: func() {
			connected <- struct{}{}
		},
	}
	a.handlers = ntfnHandlers

	if err := a.Connect(); err != nil {
		a.Shutdown()
		com.errChan <- struct{}{}
		return err
	}

	// Wait for btcd to connect
	<-connected

	// Wait for wallet sync
	for i := 0; i < *maxConnRetries; i++ {
		if _, err := a.client.GetBalance(""); err != nil {
			time.Sleep(time.Duration(i) * 50 * time.Millisecond)
			continue
		}
		break
	}

	// Create wallet addresses and unlock wallet.
	log.Printf("%s: Creating wallet addresses...", a)
	for i := range a.ownedAddresses {
		fmt.Printf("\r%d/%d", i+1, len(a.ownedAddresses))
		addr, err := a.client.GetNewAddress()
		if err != nil {
			log.Printf("%s: Cannot create address #%d", a, i+1)
			com.errChan <- struct{}{}
			return err
		}
		a.ownedAddresses[i] = addr
	}
	fmt.Printf("\n")

	if err := a.client.WalletPassphrase(a.walletPassphrase, timeoutSecs); err != nil {
		log.Printf("%s: Cannot unlock wallet: %v", a, err)
		com.errChan <- struct{}{}
		return err
	}

	// Send a random address that will be used by the cpu miner.
	a.miningAddr <- a.ownedAddresses[rand.Int()%len(a.ownedAddresses)]

	// Start a goroutine that queues up a set of utxos belonging to this
	// actor. The utxos are sent from com.poolUtxos which in turn receives
	// block notifications from sim.go
	a.wg.Add(1)
	go a.queueUtxos()

	// Start a goroutine to simulate transactions.
	a.wg.Add(1)
	go a.simulateTx(com.downstream, com.txpool)

	// Start a goroutine to split utxos
	a.wg.Add(1)
	go a.splitUtxos(com.split, com.txpool)

	return nil
}

// simulateTx runs as a goroutine and simulates transactions between actors
//
// It receives a random address downstream, dequeues a utxo, sends a raw
// transaction to the address using the utxo as input
func (a *Actor) simulateTx(downstream <-chan btcutil.Address, txpool chan<- struct{}) {
	defer a.wg.Done()

	for {
		select {
		case utxo := <-a.utxoQueue.dequeue:
			select {
			case addr := <-downstream:
				// Create a raw transaction
				inputs := []btcjson.TransactionInput{{
					Txid: utxo.OutPoint.Hash.String(),
					Vout: utxo.OutPoint.Index,
				}}

				// Provide a fees of minFee to ensure the tx gets mined
				// the utxo amount is guaranteed to be > maxSplit*minFee
				amt := utxo.Amount - minFee
				amounts := map[btcutil.Address]btcutil.Amount{
					addr: amt,
				}

				err := a.sendRawTransaction(inputs, amounts)
				if err != nil {
					log.Printf("%s: Error sending raw transaction: %v", a, err)
					select {
					case txpool <- struct{}{}:
					case <-a.quit:
						return
					}
					continue
				}

			case <-a.quit:
				return
			}
		case <-a.quit:
			return
		}
	}
}

// splitUtxos runs as a goroutine and builds up a large set of utxos that
// can be used to simulate large tx/block ratios
//
// It receives a 'split' which is int that indicates the number of resultant utxos
// the tx is sent to addresses from the same actor since we're only interested in
// building up the utxo set
func (a *Actor) splitUtxos(split <-chan int, txpool chan<- struct{}) {
	defer a.wg.Done()

	for {
		select {
		case utxo := <-a.utxoQueue.dequeue:
			select {
			case split := <-split:
				// Create a raw transaction
				inputs := []btcjson.TransactionInput{{
					Txid: utxo.OutPoint.Hash.String(),
					Vout: utxo.OutPoint.Index,
				}}

				// Provide a fees of minFee to ensure the tx gets mined
				// the utxo amount is guaranteed to be > maxSplit*minFee
				amt := utxo.Amount - minFee
				amounts := map[btcutil.Address]btcutil.Amount{}

				// Create a output of random amount and sent it
				// to a random address from the address space
				// total number of outputs is split+1, taking into
				// account this utxo which is consumed in the process

				// set a rand start index for getting different random addrs
				randomIndex := rand.Int() % len(a.ownedAddresses)
				for i := 0; i <= split; i++ {
					var to btcutil.Address
					var change btcutil.Amount
					// pick a random address
					if randomIndex+i < len(a.ownedAddresses) {
						to = a.ownedAddresses[randomIndex+i]
					} else {
						// wrap around incase of an overflow
						to = a.ownedAddresses[randomIndex+i-len(a.ownedAddresses)]
					}
					if i == split {
						// last split, so just set the change
						change = amt
					} else {
						// pick a random change amount which is less than amt
						// but have a lower bound at minFee
						change = btcutil.Amount(rand.Int63n(int64(amt) / 2))
						if change < minFee {
							change = minFee
						}
						amt -= change
					}
					amounts[to] = change
				}

				err := a.sendRawTransaction(inputs, amounts)
				if err != nil {
					log.Printf("%s: Error sending raw transaction: %v", a, err)
					select {
					case txpool <- struct{}{}:
					case <-a.quit:
						return
					}
					continue
				}

			case <-a.quit:
				return
			}
		case <-a.quit:
			return
		}
	}
}

// sendRawTransaction creates a raw transaction, signs it and sends it
func (a *Actor) sendRawTransaction(inputs []btcjson.TransactionInput, amounts map[btcutil.Address]btcutil.Amount) error {
	msgTx, err := a.client.CreateRawTransaction(inputs, amounts)
	if err != nil {
		return err
	}
	// sign it
	msgTx, ok, err := a.client.SignRawTransaction(msgTx)
	if err != nil {
		return err
	}
	if !ok {
		return err
	}
	// and finally send it.
	if _, err := a.client.SendRawTransaction(msgTx, false); err != nil {
		return err
	}
	return nil
}

// queueUtxos receives utxos belonging to this actor and queues them up
func (a *Actor) queueUtxos() {
	defer a.wg.Done()

	enqueue := a.utxoQueue.enqueue
	var dequeue chan *TxOut
	var next *TxOut
out:
	for {
		select {
		case n, ok := <-enqueue:
			if !ok {
				// If no utxos are queued for handling,
				// the queue is finished.
				if len(a.utxoQueue.utxos) == 0 {
					break out
				}
				// nil channel so no more reads can occur.
				enqueue = nil
				continue
			}
			if len(a.utxoQueue.utxos) == 0 {
				next = n
				dequeue = a.utxoQueue.dequeue
			}
			a.utxoQueue.utxos = append(a.utxoQueue.utxos, n)
		case dequeue <- next:
			a.utxoQueue.utxos[0] = nil
			a.utxoQueue.utxos = a.utxoQueue.utxos[1:]
			if len(a.utxoQueue.utxos) != 0 {
				next = a.utxoQueue.utxos[0]
			} else {
				// If no more utxos can be enqueued, the
				// queue is finished.
				if enqueue == nil {
					break out
				}
				dequeue = nil
			}
		case <-a.quit:
			break out
		}
	}
	close(a.utxoQueue.dequeue)
}

// Shutdown performs a shutdown down the actor by first signalling
// all goroutines to stop, waiting for them to stop and them cleaning up
func (a *Actor) Shutdown() {
	select {
	case <-a.quit:
	default:
		close(a.quit)
		a.WaitForShutdown()
		a.Node.Shutdown()
	}
}

// WaitForShutdown waits until every actor goroutine has returned
func (a *Actor) WaitForShutdown() {
	a.wg.Wait()
}
<commit_msg>Update btcjson path import paths to new location.<commit_after>/*
 * Copyright (c) 2014-2015 Conformal Systems LLC <info@conformal.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"sync"
	"time"

	"github.com/btcsuite/btcd/btcjson"
	"github.com/btcsuite/btcd/wire"
	rpc "github.com/btcsuite/btcrpcclient"
	"github.com/btcsuite/btcutil"
)

// minFee is the minimum tx fee that can be paid
const minFee btcutil.Amount = 1e4 // 0.0001 BTC

// utxoQueue is the queue of utxos belonging to a actor
// utxos are queued after a block is received and are dispatched
// to their respective owner from com.poolUtxos
// they are dequeued from simulateTx and splitUtxos
type utxoQueue struct {
	utxos   []*TxOut
	enqueue chan *TxOut
	dequeue chan *TxOut
}

// Actor describes an actor on the simulation network.  Each actor runs
// independantly without external input to decide it's behavior.
type Actor struct {
	*Node
	quit             chan struct{}
	wg               sync.WaitGroup
	ownedAddresses   []btcutil.Address
	utxoQueue        *utxoQueue
	miningAddr       chan btcutil.Address
	walletPassphrase string
}

// TxOut is a valid tx output that can be used to generate transactions
type TxOut struct {
	OutPoint *wire.OutPoint
	Amount   btcutil.Amount
}

// NewActor creates a new actor which runs its own wallet process connecting
// to the btcd node server specified by node, and listening for simulator
// websocket connections on the specified port.
func NewActor(node *Node, port uint16) (*Actor, error) {
	// Please don't run this as root.
	if port < 1024 {
		return nil, errors.New("invalid actor port")
	}

	// Set btcwallet node args
	args, err := newBtcwalletArgs(port, node.Args.(*btcdArgs))
	if err != nil {
		return nil, err
	}

	logFile, err := getLogFile(args.prefix)
	if err != nil {
		log.Printf("Cannot get log file, logging disabled: %v", err)
	}
	btcwallet, err := NewNodeFromArgs(args, nil, logFile)
	if err != nil {
		return nil, err
	}

	a := Actor{
		Node:             btcwallet,
		quit:             make(chan struct{}),
		ownedAddresses:   make([]btcutil.Address, *maxAddresses),
		miningAddr:       make(chan btcutil.Address),
		walletPassphrase: "password",
		utxoQueue: &utxoQueue{
			enqueue: make(chan *TxOut),
			dequeue: make(chan *TxOut),
		},
	}
	return &a, nil
}

// Start creates the command to execute a wallet process and starts the
// command in the background, attaching the command's stderr and stdout
// to the passed writers. Nil writers may be used to discard output.
//
// In addition to starting the wallet process, this runs goroutines to
// handle wallet notifications and requests the wallet process to create
// an intial encrypted wallet, so that it can actually send and receive BTC.
//
// If the RPC client connection cannot be established or wallet cannot
// be created, the wallet process is killed and the actor directory
// removed.
func (a *Actor) Start(stderr, stdout io.Writer, com *Communication) error {
	connected := make(chan struct{})
	const timeoutSecs int64 = 3600 * 24

	if err := a.Node.Start(); err != nil {
		a.Shutdown()
		com.errChan <- struct{}{}
		return err
	}

	ntfnHandlers := &rpc.NotificationHandlers{
		OnClientConnected: func() {
			connected <- struct{}{}
		},
	}
	a.handlers = ntfnHandlers

	if err := a.Connect(); err != nil {
		a.Shutdown()
		com.errChan <- struct{}{}
		return err
	}

	// Wait for btcd to connect
	<-connected

	// Wait for wallet sync
	for i := 0; i < *maxConnRetries; i++ {
		if _, err := a.client.GetBalance(""); err != nil {
			time.Sleep(time.Duration(i) * 50 * time.Millisecond)
			continue
		}
		break
	}

	// Create wallet addresses and unlock wallet.
	log.Printf("%s: Creating wallet addresses...", a)
	for i := range a.ownedAddresses {
		fmt.Printf("\r%d/%d", i+1, len(a.ownedAddresses))
		addr, err := a.client.GetNewAddress()
		if err != nil {
			log.Printf("%s: Cannot create address #%d", a, i+1)
			com.errChan <- struct{}{}
			return err
		}
		a.ownedAddresses[i] = addr
	}
	fmt.Printf("\n")

	if err := a.client.WalletPassphrase(a.walletPassphrase, timeoutSecs); err != nil {
		log.Printf("%s: Cannot unlock wallet: %v", a, err)
		com.errChan <- struct{}{}
		return err
	}

	// Send a random address that will be used by the cpu miner.
	a.miningAddr <- a.ownedAddresses[rand.Int()%len(a.ownedAddresses)]

	// Start a goroutine that queues up a set of utxos belonging to this
	// actor. The utxos are sent from com.poolUtxos which in turn receives
	// block notifications from sim.go
	a.wg.Add(1)
	go a.queueUtxos()

	// Start a goroutine to simulate transactions.
	a.wg.Add(1)
	go a.simulateTx(com.downstream, com.txpool)

	// Start a goroutine to split utxos
	a.wg.Add(1)
	go a.splitUtxos(com.split, com.txpool)

	return nil
}

// simulateTx runs as a goroutine and simulates transactions between actors
//
// It receives a random address downstream, dequeues a utxo, sends a raw
// transaction to the address using the utxo as input
func (a *Actor) simulateTx(downstream <-chan btcutil.Address, txpool chan<- struct{}) {
	defer a.wg.Done()

	for {
		select {
		case utxo := <-a.utxoQueue.dequeue:
			select {
			case addr := <-downstream:
				// Create a raw transaction
				inputs := []btcjson.TransactionInput{{
					Txid: utxo.OutPoint.Hash.String(),
					Vout: utxo.OutPoint.Index,
				}}

				// Provide a fees of minFee to ensure the tx gets mined
				// the utxo amount is guaranteed to be > maxSplit*minFee
				amt := utxo.Amount - minFee
				amounts := map[btcutil.Address]btcutil.Amount{
					addr: amt,
				}

				err := a.sendRawTransaction(inputs, amounts)
				if err != nil {
					log.Printf("%s: Error sending raw transaction: %v", a, err)
					select {
					case txpool <- struct{}{}:
					case <-a.quit:
						return
					}
					continue
				}

			case <-a.quit:
				return
			}
		case <-a.quit:
			return
		}
	}
}

// splitUtxos runs as a goroutine and builds up a large set of utxos that
// can be used to simulate large tx/block ratios
//
// It receives a 'split' which is int that indicates the number of resultant utxos
// the tx is sent to addresses from the same actor since we're only interested in
// building up the utxo set
func (a *Actor) splitUtxos(split <-chan int, txpool chan<- struct{}) {
	defer a.wg.Done()

	for {
		select {
		case utxo := <-a.utxoQueue.dequeue:
			select {
			case split := <-split:
				// Create a raw transaction
				inputs := []btcjson.TransactionInput{{
					Txid: utxo.OutPoint.Hash.String(),
					Vout: utxo.OutPoint.Index,
				}}

				// Provide a fees of minFee to ensure the tx gets mined
				// the utxo amount is guaranteed to be > maxSplit*minFee
				amt := utxo.Amount - minFee
				amounts := map[btcutil.Address]btcutil.Amount{}

				// Create a output of random amount and sent it
				// to a random address from the address space
				// total number of outputs is split+1, taking into
				// account this utxo which is consumed in the process

				// set a rand start index for getting different random addrs
				randomIndex := rand.Int() % len(a.ownedAddresses)
				for i := 0; i <= split; i++ {
					var to btcutil.Address
					var change btcutil.Amount
					// pick a random address
					if randomIndex+i < len(a.ownedAddresses) {
						to = a.ownedAddresses[randomIndex+i]
					} else {
						// wrap around incase of an overflow
						to = a.ownedAddresses[randomIndex+i-len(a.ownedAddresses)]
					}
					if i == split {
						// last split, so just set the change
						change = amt
					} else {
						// pick a random change amount which is less than amt
						// but have a lower bound at minFee
						change = btcutil.Amount(rand.Int63n(int64(amt) / 2))
						if change < minFee {
							change = minFee
						}
						amt -= change
					}
					amounts[to] = change
				}

				err := a.sendRawTransaction(inputs, amounts)
				if err != nil {
					log.Printf("%s: Error sending raw transaction: %v", a, err)
					select {
					case txpool <- struct{}{}:
					case <-a.quit:
						return
					}
					continue
				}

			case <-a.quit:
				return
			}
		case <-a.quit:
			return
		}
	}
}

// sendRawTransaction creates a raw transaction, signs it and sends it
func (a *Actor) sendRawTransaction(inputs []btcjson.TransactionInput, amounts map[btcutil.Address]btcutil.Amount) error {
	msgTx, err := a.client.CreateRawTransaction(inputs, amounts)
	if err != nil {
		return err
	}
	// sign it
	msgTx, ok, err := a.client.SignRawTransaction(msgTx)
	if err != nil {
		return err
	}
	if !ok {
		return err
	}
	// and finally send it.
	if _, err := a.client.SendRawTransaction(msgTx, false); err != nil {
		return err
	}
	return nil
}

// queueUtxos receives utxos belonging to this actor and queues them up
func (a *Actor) queueUtxos() {
	defer a.wg.Done()

	enqueue := a.utxoQueue.enqueue
	var dequeue chan *TxOut
	var next *TxOut
out:
	for {
		select {
		case n, ok := <-enqueue:
			if !ok {
				// If no utxos are queued for handling,
				// the queue is finished.
				if len(a.utxoQueue.utxos) == 0 {
					break out
				}
				// nil channel so no more reads can occur.
				enqueue = nil
				continue
			}
			if len(a.utxoQueue.utxos) == 0 {
				next = n
				dequeue = a.utxoQueue.dequeue
			}
			a.utxoQueue.utxos = append(a.utxoQueue.utxos, n)
		case dequeue <- next:
			a.utxoQueue.utxos[0] = nil
			a.utxoQueue.utxos = a.utxoQueue.utxos[1:]
			if len(a.utxoQueue.utxos) != 0 {
				next = a.utxoQueue.utxos[0]
			} else {
				// If no more utxos can be enqueued, the
				// queue is finished.
				if enqueue == nil {
					break out
				}
				dequeue = nil
			}
		case <-a.quit:
			break out
		}
	}
	close(a.utxoQueue.dequeue)
}

// Shutdown performs a shutdown down the actor by first signalling
// all goroutines to stop, waiting for them to stop and them cleaning up
func (a *Actor) Shutdown() {
	select {
	case <-a.quit:
	default:
		close(a.quit)
		a.WaitForShutdown()
		a.Node.Shutdown()
	}
}

// WaitForShutdown waits until every actor goroutine has returned
func (a *Actor) WaitForShutdown() {
	a.wg.Wait()
}
<|endoftext|>