<commit_before>// Code generated by protoc-gen-gogo.
// source: identify.proto
// DO NOT EDIT!

/*
Package identify_pb is a generated protocol buffer package.

It is generated from these files:
	identify.proto

It has these top-level messages:
	Identify
*/
package identify_pb

import proto "code.google.com/p/gogoprotobuf/proto"
import json "encoding/json"
import math "math"

// Reference proto, json, and math imports to suppress error if they are not otherwise used.
var _ = proto.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf

type Identify struct {
	// protocolVersion determines compatibility between peers
	ProtocolVersion *string `protobuf:"bytes,5,opt,name=protocolVersion" json:"protocolVersion,omitempty"`
	// agentVersion is like a UserAgent string in browsers, or client version in bittorrent
	// includes the client name and client.
	AgentVersion *string `protobuf:"bytes,6,opt,name=agentVersion" json:"agentVersion,omitempty"`
	// publicKey is this node's public key (which also gives its node.ID)
	// - may not need to be sent, as secure channel implies it has been sent.
	// - then again, if we change / disable secure channel, may still want it.
	PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"`
	// listenAddrs are the multiaddrs the sender node listens for open connections on
	ListenAddrs [][]byte `protobuf:"bytes,2,rep,name=listenAddrs" json:"listenAddrs,omitempty"`
	// oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
	// this is useful information to convey to the other side, as it helps the remote endpoint
	// determine whether its connection to the local peer goes through NAT.
	ObservedAddr []byte `protobuf:"bytes,4,opt,name=observedAddr" json:"observedAddr,omitempty"`
	// protocols are the services this node is running
	Protocols        []string `protobuf:"bytes,3,rep,name=protocols" json:"protocols,omitempty"`
	XXX_unrecognized []byte   `json:"-"`
}

func (m *Identify) Reset()         { *m = Identify{} }
func (m *Identify) String() string { return proto.CompactTextString(m) }
func (*Identify) ProtoMessage()    {}

func (m *Identify) GetProtocolVersion() string {
	if m != nil && m.ProtocolVersion != nil {
		return *m.ProtocolVersion
	}
	return ""
}

func (m *Identify) GetAgentVersion() string {
	if m != nil && m.AgentVersion != nil {
		return *m.AgentVersion
	}
	return ""
}

func (m *Identify) GetPublicKey() []byte {
	if m != nil {
		return m.PublicKey
	}
	return nil
}

func (m *Identify) GetListenAddrs() [][]byte {
	if m != nil {
		return m.ListenAddrs
	}
	return nil
}

func (m *Identify) GetObservedAddr() []byte {
	if m != nil {
		return m.ObservedAddr
	}
	return nil
}

func (m *Identify) GetProtocols() []string {
	if m != nil {
		return m.Protocols
	}
	return nil
}

func init() {
}
<commit_msg>vendor identify pb<commit_after>// Code generated by protoc-gen-gogo.
// source: identify.proto
// DO NOT EDIT!

/*
Package identify_pb is a generated protocol buffer package.

It is generated from these files:
	identify.proto

It has these top-level messages:
	Identify
*/
package identify_pb

import proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/proto"
import json "encoding/json"
import math "math"

// Reference proto, json, and math imports to suppress error if they are not otherwise used.
var _ = proto.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf

type Identify struct {
	// protocolVersion determines compatibility between peers
	ProtocolVersion *string `protobuf:"bytes,5,opt,name=protocolVersion" json:"protocolVersion,omitempty"`
	// agentVersion is like a UserAgent string in browsers, or client version in bittorrent
	// includes the client name and client.
	AgentVersion *string `protobuf:"bytes,6,opt,name=agentVersion" json:"agentVersion,omitempty"`
	// publicKey is this node's public key (which also gives its node.ID)
	// - may not need to be sent, as secure channel implies it has been sent.
	// - then again, if we change / disable secure channel, may still want it.
	PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"`
	// listenAddrs are the multiaddrs the sender node listens for open connections on
	ListenAddrs [][]byte `protobuf:"bytes,2,rep,name=listenAddrs" json:"listenAddrs,omitempty"`
	// oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
	// this is useful information to convey to the other side, as it helps the remote endpoint
	// determine whether its connection to the local peer goes through NAT.
	ObservedAddr []byte `protobuf:"bytes,4,opt,name=observedAddr" json:"observedAddr,omitempty"`
	// protocols are the services this node is running
	Protocols        []string `protobuf:"bytes,3,rep,name=protocols" json:"protocols,omitempty"`
	XXX_unrecognized []byte   `json:"-"`
}

func (m *Identify) Reset()         { *m = Identify{} }
func (m *Identify) String() string { return proto.CompactTextString(m) }
func (*Identify) ProtoMessage()    {}

func (m *Identify) GetProtocolVersion() string {
	if m != nil && m.ProtocolVersion != nil {
		return *m.ProtocolVersion
	}
	return ""
}

func (m *Identify) GetAgentVersion() string {
	if m != nil && m.AgentVersion != nil {
		return *m.AgentVersion
	}
	return ""
}

func (m *Identify) GetPublicKey() []byte {
	if m != nil {
		return m.PublicKey
	}
	return nil
}

func (m *Identify) GetListenAddrs() [][]byte {
	if m != nil {
		return m.ListenAddrs
	}
	return nil
}

func (m *Identify) GetObservedAddr() []byte {
	if m != nil {
		return m.ObservedAddr
	}
	return nil
}

func (m *Identify) GetProtocols() []string {
	if m != nil {
		return m.Protocols
	}
	return nil
}

func init() {
}
<|endoftext|>


<commit_before>package types

import (
	"encoding/json"
	"fmt"
	"sort"
)

var ValidOSArch = map[string][]string{
	"linux":   {"amd64", "i386"},
	"freebsd": {"amd64", "i386", "arm"},
	"darwin":  {"x86_64", "i386"},
}

type Labels []Label

type labels Labels

type Label struct {
	Name  ACName `json:"name"`
	Value string `json:"value"`
}

func (l Labels) assertValid() error {
	seen := map[ACName]string{}
	for _, lbl := range l {
		if lbl.Name == "name" {
			return fmt.Errorf(`invalid label name: "name"`)
		}
		_, ok := seen[lbl.Name]
		if ok {
			return fmt.Errorf(`duplicate labels of name %q`, lbl.Name)
		}
		seen[lbl.Name] = lbl.Value
	}
	if os, ok := seen["os"]; ok {
		if validArchs, ok := ValidOSArch[os]; !ok {
			// Not a whitelisted OS. TODO: how to warn rather than fail?
			validOses := make([]string, 0, len(ValidOSArch))
			for validOs := range ValidOSArch {
				validOses = append(validOses, validOs)
			}
			sort.Strings(validOses)
			return fmt.Errorf(`bad os %#v (must be one of: %v)`, os, validOses)
		} else {
			// Whitelisted OS. We check arch here, as arch makes sense only
			// when os is defined.
			if arch, ok := seen["arch"]; ok {
				found := false
				for _, validArch := range validArchs {
					if arch == validArch {
						found = true
						break
					}
				}
				if !found {
					return fmt.Errorf(`bad arch %#v for %v (must be one of: %v)`, arch, os, validArchs)
				}
			}
		}
	}
	return nil
}

func (l Labels) MarshalJSON() ([]byte, error) {
	if err := l.assertValid(); err != nil {
		return nil, err
	}
	return json.Marshal(labels(l))
}

func (l *Labels) UnmarshalJSON(data []byte) error {
	var jl labels
	if err := json.Unmarshal(data, &jl); err != nil {
		return err
	}
	nl := Labels(jl)
	if err := nl.assertValid(); err != nil {
		return err
	}
	*l = nl
	return nil
}

// Get retrieves the value of the label by the given name from Labels, if it exists
func (l Labels) Get(name string) (val string, ok bool) {
	for _, lbl := range l {
		if lbl.Name.String() == name {
			return lbl.Value, true
		}
	}
	return "", false
}
<commit_msg>schema: add a LabelsFromMap function.<commit_after>package types

import (
	"encoding/json"
	"fmt"
	"sort"
)

var ValidOSArch = map[string][]string{
	"linux":   {"amd64", "i386"},
	"freebsd": {"amd64", "i386", "arm"},
	"darwin":  {"x86_64", "i386"},
}

type Labels []Label

type labels Labels

type Label struct {
	Name  ACName `json:"name"`
	Value string `json:"value"`
}

func (l Labels) assertValid() error {
	seen := map[ACName]string{}
	for _, lbl := range l {
		if lbl.Name == "name" {
			return fmt.Errorf(`invalid label name: "name"`)
		}
		_, ok := seen[lbl.Name]
		if ok {
			return fmt.Errorf(`duplicate labels of name %q`, lbl.Name)
		}
		seen[lbl.Name] = lbl.Value
	}
	if os, ok := seen["os"]; ok {
		if validArchs, ok := ValidOSArch[os]; !ok {
			// Not a whitelisted OS. TODO: how to warn rather than fail?
			validOses := make([]string, 0, len(ValidOSArch))
			for validOs := range ValidOSArch {
				validOses = append(validOses, validOs)
			}
			sort.Strings(validOses)
			return fmt.Errorf(`bad os %#v (must be one of: %v)`, os, validOses)
		} else {
			// Whitelisted OS. We check arch here, as arch makes sense only
			// when os is defined.
			if arch, ok := seen["arch"]; ok {
				found := false
				for _, validArch := range validArchs {
					if arch == validArch {
						found = true
						break
					}
				}
				if !found {
					return fmt.Errorf(`bad arch %#v for %v (must be one of: %v)`, arch, os, validArchs)
				}
			}
		}
	}
	return nil
}

func (l Labels) MarshalJSON() ([]byte, error) {
	if err := l.assertValid(); err != nil {
		return nil, err
	}
	return json.Marshal(labels(l))
}

func (l *Labels) UnmarshalJSON(data []byte) error {
	var jl labels
	if err := json.Unmarshal(data, &jl); err != nil {
		return err
	}
	nl := Labels(jl)
	if err := nl.assertValid(); err != nil {
		return err
	}
	*l = nl
	return nil
}

// Get retrieves the value of the label by the given name from Labels, if it exists
func (l Labels) Get(name string) (val string, ok bool) {
	for _, lbl := range l {
		if lbl.Name.String() == name {
			return lbl.Value, true
		}
	}
	return "", false
}

func LabelsFromMap(labelsMap map[ACName]string) (Labels, error) {
	labels := Labels{}
	for n, v := range labelsMap {
		labels = append(labels, Label{Name: n, Value: v})
	}
	if err := labels.assertValid(); err != nil {
		return nil, err
	}
	return labels, nil
}
<|endoftext|>


<commit_before>package sign

import "time"

// Constants we expect might be used by other packages
// TODO: can this be replaced by the application using the signer?
var ROUND_TIME time.Duration = 5000 * time.Second
var HEARTBEAT = ROUND_TIME + ROUND_TIME/2

var RoundsPerView int64 = 200

var FALSE int64 = 0
var TRUE int64 = 1
<commit_msg>changed round time<commit_after>package sign

import "time"

// Constants we expect might be used by other packages
// TODO: can this be replaced by the application using the signer?
var ROUND_TIME time.Duration = 10 * time.Second
var HEARTBEAT = ROUND_TIME + ROUND_TIME/2

var RoundsPerView int64 = 200

var FALSE int64 = 0
var TRUE int64 = 1
<|endoftext|>


<commit_before>package gitstats

import (
	"os"
	"testing"

	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/control/plugin/cpolicy"
	"github.com/intelsdi-x/snap/core"
	"github.com/intelsdi-x/snap/core/cdata"
	"github.com/intelsdi-x/snap/core/ctypes"
	. "github.com/smartystreets/goconvey/convey"
)

func TestGitstatsPlugin(t *testing.T) {
	Convey("Meta should return metadata for the plugin", t, func() {
		meta := Meta()
		So(meta.Name, ShouldResemble, Name)
		So(meta.Version, ShouldResemble, Version)
		So(meta.Type, ShouldResemble, plugin.CollectorPluginType)
	})

	Convey("Create Gitstats Collector", t, func() {
		collector := &Gitstats{}
		Convey("So Gitstats collector should not be nil", func() {
			So(collector, ShouldNotBeNil)
		})
		Convey("So Gitstats collector should be of Gitstats type", func() {
			So(collector, ShouldHaveSameTypeAs, &Gitstats{})
		})
		Convey("collector.GetConfigPolicy() should return a config policy", func() {
			configPolicy, _ := collector.GetConfigPolicy()
			Convey("So config policy should not be nil", func() {
				So(configPolicy, ShouldNotBeNil)
			})
			Convey("So config policy should be a cpolicy.ConfigPolicy", func() {
				So(configPolicy, ShouldHaveSameTypeAs, &cpolicy.ConfigPolicy{})
			})
			Convey("So config policy namespace should be /raintank/Gitstats", func() {
				conf := configPolicy.Get([]string{"raintank", "apps", "gitstats"})
				So(conf, ShouldNotBeNil)
				So(conf.HasRules(), ShouldBeTrue)
				tables := conf.RulesAsTable()
				So(len(tables), ShouldEqual, 3)
				for _, rule := range tables {
					So(rule.Name, ShouldBeIn, "access_token", "user", "repo")
					switch rule.Name {
					case "access_token":
						So(rule.Required, ShouldBeTrue)
						So(rule.Type, ShouldEqual, "string")
					case "user":
						So(rule.Required, ShouldBeFalse)
						So(rule.Type, ShouldEqual, "string")
					case "repo":
						So(rule.Required, ShouldBeFalse)
						So(rule.Type, ShouldEqual, "string")
					}
				}
			})
		})
	})
}

func TestGitstatsCollectMetrics(t *testing.T) {
	cfg := setupCfg("woodsaj", "")

	Convey("Ping collector", t, func() {
		p := &Gitstats{}
		mt, err := p.GetMetricTypes(cfg)
		if err != nil {
			t.Fatal("failed to get metricTypes", err)
		}
		So(len(mt), ShouldBeGreaterThan, 0)
		for _, m := range mt {
			t.Log(m.Namespace().String())
		}
		Convey("collect metrics", func() {
			mts := []plugin.MetricType{
				plugin.MetricType{
					Namespace_: core.NewNamespace(
						"raintank", "apps", "gitstats", "user", "*", "followers"),
					Config_: cfg.ConfigDataNode,
				},
			}
			metrics, err := p.CollectMetrics(mts)
			So(err, ShouldBeNil)
			So(metrics, ShouldNotBeNil)
			So(len(metrics), ShouldEqual, 1)
			So(metrics[0].Namespace()[0].Value, ShouldEqual, "raintank")
			So(metrics[0].Namespace()[1].Value, ShouldEqual, "apps")
			So(metrics[0].Namespace()[2].Value, ShouldEqual, "gitstats")
			for _, m := range metrics {
				So(m.Namespace()[3].Value, ShouldEqual, "user")
				So(m.Namespace()[4].Value, ShouldEqual, "woodsaj")
				t.Log(m.Namespace().String(), m.Data())
			}
		})
	})
}

func setupCfg(user, repo string) plugin.ConfigType {
	node := cdata.NewNode()
	node.AddItem("access_token", ctypes.ConfigValueStr{Value: os.Getenv("GITSTATS_ACCESS_TOKEN")})
	node.AddItem("user", ctypes.ConfigValueStr{Value: user})
	node.AddItem("repo", ctypes.ConfigValueStr{Value: repo})
	return plugin.ConfigType{ConfigDataNode: node}
}
<commit_msg>skip integration test if ACCESS_TOKEN not set in ENV<commit_after>package gitstats

import (
	"os"
	"testing"

	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/control/plugin/cpolicy"
	"github.com/intelsdi-x/snap/core"
	"github.com/intelsdi-x/snap/core/cdata"
	"github.com/intelsdi-x/snap/core/ctypes"
	. "github.com/smartystreets/goconvey/convey"
)

func TestGitstatsPlugin(t *testing.T) {
	Convey("Meta should return metadata for the plugin", t, func() {
		meta := Meta()
		So(meta.Name, ShouldResemble, Name)
		So(meta.Version, ShouldResemble, Version)
		So(meta.Type, ShouldResemble, plugin.CollectorPluginType)
	})

	Convey("Create Gitstats Collector", t, func() {
		collector := &Gitstats{}
		Convey("So Gitstats collector should not be nil", func() {
			So(collector, ShouldNotBeNil)
		})
		Convey("So Gitstats collector should be of Gitstats type", func() {
			So(collector, ShouldHaveSameTypeAs, &Gitstats{})
		})
		Convey("collector.GetConfigPolicy() should return a config policy", func() {
			configPolicy, _ := collector.GetConfigPolicy()
			Convey("So config policy should not be nil", func() {
				So(configPolicy, ShouldNotBeNil)
			})
			Convey("So config policy should be a cpolicy.ConfigPolicy", func() {
				So(configPolicy, ShouldHaveSameTypeAs, &cpolicy.ConfigPolicy{})
			})
			Convey("So config policy namespace should be /raintank/Gitstats", func() {
				conf := configPolicy.Get([]string{"raintank", "apps", "gitstats"})
				So(conf, ShouldNotBeNil)
				So(conf.HasRules(), ShouldBeTrue)
				tables := conf.RulesAsTable()
				So(len(tables), ShouldEqual, 3)
				for _, rule := range tables {
					So(rule.Name, ShouldBeIn, "access_token", "user", "repo")
					switch rule.Name {
					case "access_token":
						So(rule.Required, ShouldBeTrue)
						So(rule.Type, ShouldEqual, "string")
					case "user":
						So(rule.Required, ShouldBeFalse)
						So(rule.Type, ShouldEqual, "string")
					case "repo":
						So(rule.Required, ShouldBeFalse)
						So(rule.Type, ShouldEqual, "string")
					}
				}
			})
		})
	})
}

func TestGitstatsCollectMetrics(t *testing.T) {
	if os.Getenv("GITSTATS_ACCESS_TOKEN") == "" {
		return
	}
	cfg := setupCfg("woodsaj", "")

	Convey("Ping collector", t, func() {
		p := &Gitstats{}
		mt, err := p.GetMetricTypes(cfg)
		if err != nil {
			t.Fatal("failed to get metricTypes", err)
		}
		So(len(mt), ShouldBeGreaterThan, 0)
		for _, m := range mt {
			t.Log(m.Namespace().String())
		}
		Convey("collect metrics", func() {
			mts := []plugin.MetricType{
				plugin.MetricType{
					Namespace_: core.NewNamespace(
						"raintank", "apps", "gitstats", "user", "*", "followers"),
					Config_: cfg.ConfigDataNode,
				},
			}
			metrics, err := p.CollectMetrics(mts)
			So(err, ShouldBeNil)
			So(metrics, ShouldNotBeNil)
			So(len(metrics), ShouldEqual, 1)
			So(metrics[0].Namespace()[0].Value, ShouldEqual, "raintank")
			So(metrics[0].Namespace()[1].Value, ShouldEqual, "apps")
			So(metrics[0].Namespace()[2].Value, ShouldEqual, "gitstats")
			for _, m := range metrics {
				So(m.Namespace()[3].Value, ShouldEqual, "user")
				So(m.Namespace()[4].Value, ShouldEqual, "woodsaj")
				t.Log(m.Namespace().String(), m.Data())
			}
		})
	})
}

func setupCfg(user, repo string) plugin.ConfigType {
	node := cdata.NewNode()
	node.AddItem("access_token", ctypes.ConfigValueStr{Value: os.Getenv("GITSTATS_ACCESS_TOKEN")})
	node.AddItem("user", ctypes.ConfigValueStr{Value: user})
	node.AddItem("repo", ctypes.ConfigValueStr{Value: repo})
	return plugin.ConfigType{ConfigDataNode: node}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/peterh/liner"
)

type Shell struct {
	shell  *liner.State
	prompt string
	cmds   map[string]shellCmd
	hist   string
	motor  Motor
}

func NewShell() *Shell {
	sh := &Shell{
		shell:  liner.NewLiner(),
		prompt: "mbus> ",
		hist:   filepath.Join(".", ".fcs_lpc_motor_history"),
		motor:  NewMotor("134.158.125.223:502"),
	}

	sh.shell.SetCtrlCAborts(true)
	sh.shell.SetCompleter(func(line string) (c []string) {
		for n := range sh.cmds {
			if strings.HasPrefix(n, strings.ToLower(line)) {
				c = append(c, n)
			}
		}
		return
	})

	if f, err := os.Open(sh.hist); err == nil {
		sh.shell.ReadHistory(f)
		f.Close()
	}

	sh.cmds = map[string]shellCmd{
		"dump": sh.cmdDump,
		"get":  sh.cmdGet,
		"quit": sh.cmdQuit,
		"set":  sh.cmdSet,
	}
	return sh
}

type shellCmd func(args []string) error

func (sh *Shell) Close() error {
	if f, err := os.Create(sh.hist); err != nil {
		log.Print("error writing history file: ", err)
	} else {
		sh.shell.WriteHistory(f)
		f.Close()
	}
	fmt.Printf("\n")
	return sh.shell.Close()
}

func (sh *Shell) run() error {
	for {
		raw, err := sh.shell.Prompt(sh.prompt)
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return err
		}
		// log.Printf("got: %q\n", raw)
		raw = strings.TrimSpace(raw)
		if raw == "" {
			continue
		}
		toks := strings.Split(raw, " ")
		err = sh.dispatch(toks)
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return err
		}
		sh.shell.AppendHistory(raw)
	}

	return nil
}

func (sh *Shell) dispatch(toks []string) error {
	var err error
	fct, ok := sh.cmds[toks[0]]
	if !ok {
		err = fmt.Errorf("invalid command [%s]", toks[0])
		log.Printf("error: %v\n", err)
		return err
	}

	return fct(toks[1:])
}

func (sh *Shell) cmdQuit(args []string) error {
	return io.EOF
}

func (sh *Shell) cmdGet(args []string) error {
	param, err := sh.parseParam(args[0])
	if err != nil {
		return err
	}

	o, err := sh.motor.read(param)
	if err != nil {
		return err
	}
	hex := make([]string, len(o))
	dec := make([]string, len(o))
	for i, v := range o {
		hex[i] = fmt.Sprintf("0x%02x", v)
		dec[i] = fmt.Sprintf("%3d", v)
	}
	log.Printf(
		"Pr-%v: [%s] [%s] (%v)\n",
		param,
		strings.Join(hex, " "),
		strings.Join(dec, " "),
		codec.Uint16(o),
	)

	return err
}

func (sh *Shell) cmdSet(args []string) error {
	param, err := sh.parseParam(args[0])
	if err != nil {
		return err
	}
	log.Printf("set Pr-%v [%s]...\n", param, args[1])
	return err
}

func (sh *Shell) cmdDump(args []string) error {
	var err error
	return err
}

func (sh *Shell) parseParam(arg string) (Parameter, error) {
	var err error
	var p Parameter

	if strings.Contains(arg, ".") {
		return NewParameterFromMenu(arg)
	}

	var reg uint64
	var base = 10
	if strings.HasPrefix(arg, "0x") {
		base = 16
		arg = arg[len("0x"):]
	}
	reg, err = strconv.ParseUint(arg, base, 64)
	if err != nil {
		return p, err
	}
	p = NewParameter(uint16(reg))
	return p, err
}
<commit_msg>shell: add ability to switch motors<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/peterh/liner"
)

type Shell struct {
	shell  *liner.State
	prompt string
	cmds   map[string]shellCmd
	hist   string
	motor  Motor
}

func NewShell() *Shell {
	sh := &Shell{
		shell:  liner.NewLiner(),
		prompt: "mbus> ",
		hist:   filepath.Join(".", ".fcs_lpc_motor_history"),
		motor:  NewMotor("134.158.125.223:502"),
	}

	sh.shell.SetCtrlCAborts(true)
	sh.shell.SetCompleter(func(line string) (c []string) {
		for n := range sh.cmds {
			if strings.HasPrefix(n, strings.ToLower(line)) {
				c = append(c, n)
			}
		}
		return
	})

	if f, err := os.Open(sh.hist); err == nil {
		sh.shell.ReadHistory(f)
		f.Close()
	}

	sh.cmds = map[string]shellCmd{
		"dump":  sh.cmdDump,
		"get":   sh.cmdGet,
		"motor": sh.cmdMotor,
		"quit":  sh.cmdQuit,
		"set":   sh.cmdSet,
	}
	return sh
}

type shellCmd func(args []string) error

func (sh *Shell) Close() error {
	if f, err := os.Create(sh.hist); err != nil {
		log.Print("error writing history file: ", err)
	} else {
		sh.shell.WriteHistory(f)
		f.Close()
	}
	fmt.Printf("\n")
	return sh.shell.Close()
}

func (sh *Shell) run() error {
	for {
		raw, err := sh.shell.Prompt(sh.prompt)
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return err
		}
		// log.Printf("got: %q\n", raw)
		raw = strings.TrimSpace(raw)
		if raw == "" {
			continue
		}
		toks := strings.Split(raw, " ")
		err = sh.dispatch(toks)
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return err
		}
		sh.shell.AppendHistory(raw)
	}

	return nil
}

func (sh *Shell) dispatch(toks []string) error {
	var err error
	fct, ok := sh.cmds[toks[0]]
	if !ok {
		err = fmt.Errorf("invalid command [%s]", toks[0])
		log.Printf("error: %v\n", err)
		return err
	}

	return fct(toks[1:])
}

func (sh *Shell) cmdQuit(args []string) error {
	return io.EOF
}

func (sh *Shell) cmdGet(args []string) error {
	param, err := sh.parseParam(args[0])
	if err != nil {
		return err
	}

	o, err := sh.motor.read(param)
	if err != nil {
		return err
	}
	hex := make([]string, len(o))
	dec := make([]string, len(o))
	for i, v := range o {
		hex[i] = fmt.Sprintf("0x%02x", v)
		dec[i] = fmt.Sprintf("%3d", v)
	}
	log.Printf(
		"Pr-%v: [%s] [%s] (%v)\n",
		param,
		strings.Join(hex, " "),
		strings.Join(dec, " "),
		codec.Uint16(o),
	)

	return err
}

func (sh *Shell) cmdSet(args []string) error {
	param, err := sh.parseParam(args[0])
	if err != nil {
		return err
	}
	log.Printf("set Pr-%v [%s]...\n", param, args[1])
	return err
}

func (sh *Shell) cmdDump(args []string) error {
	var err error
	return err
}

func (sh *Shell) cmdMotor(args []string) error {
	switch len(args) {
	case 0:
		log.Printf("connected to [%s]\n", sh.motor.Address)
		return nil
	case 1:
		sh.motor = NewMotor(args[0])
		return nil
	default:
		return fmt.Errorf("cmd-motor: too many arguments (%d)", len(args))
	}
	return nil
}

func (sh *Shell) parseParam(arg string) (Parameter, error) {
	var err error
	var p Parameter

	if strings.Contains(arg, ".") {
		return NewParameterFromMenu(arg)
	}

	var reg uint64
	var base = 10
	if strings.HasPrefix(arg, "0x") {
		base = 16
		arg = arg[len("0x"):]
	}
	reg, err = strconv.ParseUint(arg, base, 64)
	if err != nil {
		return p, err
	}
	p = NewParameter(uint16(reg))
	return p, err
}
<|endoftext|>


<commit_before>package space

import (
	"fmt"
	"io/ioutil"
	"path"
	"strings"

	"github.com/pivotalservices/cf-mgmt/cloudcontroller"
	"github.com/pivotalservices/cf-mgmt/ldap"
	"github.com/pivotalservices/cf-mgmt/organization"
	"github.com/pivotalservices/cf-mgmt/uaac"
	"github.com/pivotalservices/cf-mgmt/utils"
	"github.com/xchapter7x/lo"
)

//NewManager -
func NewManager(sysDomain, token, uaacToken string) (mgr Manager) {
	cloudController := cloudcontroller.NewManager(fmt.Sprintf("https://api.%s", sysDomain), token)
	ldapMgr := ldap.NewManager()
	uaacMgr := uaac.NewManager(sysDomain, uaacToken)
	return &DefaultSpaceManager{
		UAACMgr:         uaacMgr,
		CloudController: cloudController,
		OrgMgr:          organization.NewManager(sysDomain, token, uaacToken),
		LdapMgr:         ldapMgr,
		UtilsMgr:        utils.NewDefaultManager(),
		UserMgr:         NewUserManager(cloudController, ldapMgr, uaacMgr),
	}
}

func (m *DefaultSpaceManager) GetSpaceConfigs(configDir string) ([]*InputUpdateSpaces, error) {

	spaceDefaults := &InputUpdateSpaces{}
	m.UtilsMgr.LoadFile(path.Join(configDir, "spaceDefaults.yml"), spaceDefaults)
	if files, err := utils.NewDefaultManager().FindFiles(configDir, "spaceConfig.yml"); err == nil {
		spaceConfigs := []*InputUpdateSpaces{}
		for _, f := range files {
			lo.G.Info("Processing space file", f)
			input := &InputUpdateSpaces{}
			if err = m.UtilsMgr.LoadFile(f, input); err == nil {
				input.Developer.LdapUsers = append(input.Developer.LdapUsers, spaceDefaults.Developer.LdapUsers...)
				input.Developer.Users = append(input.Developer.Users, spaceDefaults.Developer.Users...)
				input.Auditor.LdapUsers = append(input.Auditor.LdapUsers, spaceDefaults.Auditor.LdapUsers...)
				input.Auditor.Users = append(input.Auditor.Users, spaceDefaults.Auditor.Users...)
				input.Manager.LdapUsers = append(input.Manager.LdapUsers, spaceDefaults.Manager.LdapUsers...)
				input.Manager.Users = append(input.Manager.Users, spaceDefaults.Manager.Users...)

				spaceConfigs = append(spaceConfigs, input)
				if input.EnableSecurityGroup {
					securityGroupFile := strings.Replace(f, "spaceConfig.yml", "security-group.json", -1)
					lo.G.Debug("Loading security group contents", securityGroupFile)
					var bytes []byte
					if bytes, err = ioutil.ReadFile(securityGroupFile); err == nil {
						lo.G.Debug("setting security group contents", string(bytes))
						input.SecurityGroupContents = string(bytes)
					} else {
						return nil, err
					}
				}
			} else {
				return nil, err
			}
		}

		return spaceConfigs, nil
	} else {
		return nil, err
	}
}

//CreateApplicationSecurityGroups -
func (m *DefaultSpaceManager) CreateApplicationSecurityGroups(configDir string) error {
	var targetSGGUID string
	var sgs map[string]string
	var space *cloudcontroller.Space

	if spaceConfigs, err := m.GetSpaceConfigs(configDir); err != nil {
		return err
	} else {
		for _, input := range spaceConfigs {
			if input.EnableSecurityGroup {
				if space, err = m.FindSpace(input.Org, input.Space); err == nil {
					sgName := fmt.Sprintf("%s-%s", input.Org, input.Space)
					if sgs, err = m.CloudController.ListSecurityGroups(); err == nil {
						if sgGUID, ok := sgs[sgName]; ok {
							lo.G.Info("Updating security group", sgName)
							if err = m.CloudController.UpdateSecurityGroup(sgGUID, sgName, input.SecurityGroupContents); err == nil {
								lo.G.Info("Binding security group", sgName, "to space", space.Entity.Name)
								m.CloudController.AssignSecurityGroupToSpace(space.MetaData.GUID, sgGUID)
							}
						} else {
							lo.G.Info("Creating security group", sgName)
							if targetSGGUID, err = m.CloudController.CreateSecurityGroup(sgName, input.SecurityGroupContents); err == nil {
								lo.G.Info("Binding security group", sgName, "to space", space.Entity.Name)
								m.CloudController.AssignSecurityGroupToSpace(space.MetaData.GUID, targetSGGUID)
							}
						}
					}
				}
			}
		}
	}
	return nil
}

//CreateQuotas -
func (m *DefaultSpaceManager) CreateQuotas(configDir string) error {
	var quotas map[string]string
	var space *cloudcontroller.Space
	var targetQuotaGUID string

	if spaceConfigs, err := m.GetSpaceConfigs(configDir); err != nil {
		return err
	} else {
		for _, input := range spaceConfigs {
			if input.EnableSpaceQuota {
				if space, err = m.FindSpace(input.Org, input.Space); err == nil {
					quotaName := space.Entity.Name
					if quotas, err = m.CloudController.ListAllSpaceQuotasForOrg(space.Entity.OrgGUID); err == nil {
						if quotaGUID, ok := quotas[quotaName]; ok {
							lo.G.Info("Updating quota", quotaName)
							if err = m.CloudController.UpdateSpaceQuota(space.Entity.OrgGUID, quotaGUID,
								quotaName, input.MemoryLimit, input.InstanceMemoryLimit, input.TotalRoutes, input.TotalServices, input.PaidServicePlansAllowed); err == nil {
								lo.G.Info("Assigning", quotaName, "to", space.Entity.Name)
								m.CloudController.AssignQuotaToSpace(space.MetaData.GUID, quotaGUID)
							}
						} else {
							lo.G.Info("Creating quota", quotaName)
							if targetQuotaGUID, err = m.CloudController.CreateSpaceQuota(space.Entity.OrgGUID,
								quotaName, input.MemoryLimit, input.InstanceMemoryLimit, input.TotalRoutes, input.TotalServices, input.PaidServicePlansAllowed); err == nil {
								lo.G.Info("Assigning", quotaName, "to", space.Entity.Name)
								m.CloudController.AssignQuotaToSpace(space.MetaData.GUID, targetQuotaGUID)
							}
						}
					}
				}
			}
		}
	}
	return nil
}

//UpdateSpaces -
func (m *DefaultSpaceManager) UpdateSpaces(configDir string) error {
	var space *cloudcontroller.Space

	if spaceConfigs, err := m.GetSpaceConfigs(configDir); err != nil {
		return err
	} else {
		for _, input := range spaceConfigs {
			if space, err = m.FindSpace(input.Org, input.Space); err == nil {
				lo.G.Info("Processing space", space.Entity.Name)
				if input.AllowSSH != space.Entity.AllowSSH {
					if err = m.CloudController.UpdateSpaceSSH(input.AllowSSH, space.MetaData.GUID); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

//UpdateSpaceUsers -
func (m *DefaultSpaceManager) UpdateSpaceUsers(configDir, ldapBindPassword string) error {
	var config *ldap.Config
	var uaacUsers map[string]string
	var err error

	config, err = m.LdapMgr.GetConfig(configDir, ldapBindPassword)
	if err != nil {
		lo.G.Error(err)
		return err
	}

	uaacUsers, err = m.UAACMgr.ListUsers()

	if err != nil {
		lo.G.Error(err)
		return err
	}

	var spaceConfigs []*InputUpdateSpaces

	if spaceConfigs, err = m.GetSpaceConfigs(configDir); err != nil {
		lo.G.Error(err)
		return err
	}

	for _, input := range spaceConfigs {
		if err = m.updateSpaceUsers(config, input, uaacUsers); err != nil {
			return err
		}
	}

	return nil
}

func (m *DefaultSpaceManager) updateSpaceUsers(config *ldap.Config, input *InputUpdateSpaces, uaacUsers map[string]string) error {
	if space, err := m.FindSpace(input.Org, input.Space); err == nil {
		if err = m.UserMgr.UpdateSpaceUsers(config, uaacUsers, UpdateUsersInput{
			SpaceName:     space.Entity.Name,
			SpaceGUID:     space.MetaData.GUID,
			OrgName:       input.Org,
			OrgGUID:       space.Entity.OrgGUID,
			Role:          "developers",
			LdapGroupName: input.GetDeveloperGroup(),
			LdapUsers:     input.Developer.LdapUsers,
			Users:         input.Developer.Users,
			RemoveUsers:   input.RemoveUsers,
		}); err != nil {
			return err
		}

		if err = m.UserMgr.UpdateSpaceUsers(config, uaacUsers,
			UpdateUsersInput{
				SpaceName:     space.Entity.Name,
				SpaceGUID:     space.MetaData.GUID,
				OrgGUID:       space.Entity.OrgGUID,
				OrgName:       input.Org,
				Role:          "managers",
				LdapGroupName: input.GetManagerGroup(),
				LdapUsers:     input.Manager.LdapUsers,
				Users:         input.Manager.Users,
				RemoveUsers:   input.RemoveUsers,
			}); err != nil {
			return err
		}
		if err = m.UserMgr.UpdateSpaceUsers(config, uaacUsers,
			UpdateUsersInput{
				SpaceName:     space.Entity.Name,
				SpaceGUID:     space.MetaData.GUID,
				OrgGUID:       space.Entity.OrgGUID,
				OrgName:       input.Org,
				Role:          "auditors",
				LdapGroupName: input.GetAuditorGroup(),
				LdapUsers:     input.Auditor.LdapUsers,
				Users:         input.Auditor.Users,
				RemoveUsers:   input.RemoveUsers,
			}); err != nil {
			return err
		}
		return nil
	} else {
		return err
	}
}

//FindSpace -
func (m *DefaultSpaceManager) FindSpace(orgName, spaceName string) (*cloudcontroller.Space, error) {
	if orgGUID, err := m.OrgMgr.GetOrgGUID(orgName); err != nil {
		return nil, err
	} else {
		if spaces, err := m.CloudController.ListSpaces(orgGUID); err == nil {
			for _, theSpace := range spaces {
				if theSpace.Entity.Name == spaceName {
					return theSpace, nil
				}
			}
			return nil, fmt.Errorf("Space [%s] not found in org [%s]", spaceName, orgName)
		} else {
			return nil, err
		}
	}
}

func (m *DefaultSpaceManager) GetSpaceConfigList(configDir string) ([]InputCreateSpaces, error) {

	if files, err := m.UtilsMgr.FindFiles(configDir, "spaces.yml"); err != nil {
		return nil, err
	} else {
		spaceList := []InputCreateSpaces{}
		for _, f := range files {
			lo.G.Info("Processing space file", f)
			input := InputCreateSpaces{}
			if err := m.UtilsMgr.LoadFile(f, &input); err == nil {
				spaceList = append(spaceList, input)
			}
		}
		return spaceList, nil
	}
}

//CreateSpaces -
func (m *DefaultSpaceManager) CreateSpaces(configDir, ldapBindPassword string) error {

	if configSpaceList, err := m.GetSpaceConfigList(configDir); err != nil {
		return err
	} else {
		for _, input := range configSpaceList {
			if len(input.Spaces) >= 0 {
				var orgGUID string
				if orgGUID, err = m.OrgMgr.GetOrgGUID(input.Org); err != nil {
					return err
				}
				var spaces []*cloudcontroller.Space
				if spaces, err = m.CloudController.ListSpaces(orgGUID); err == nil {
					for _, spaceName := range input.Spaces {
						if m.doesSpaceExist(spaces, spaceName) {
							lo.G.Info(fmt.Sprintf("[%s] space already exists", spaceName))
						} else {
							lo.G.Info(fmt.Sprintf("Creating [%s] space in [%s] org", spaceName, input.Org))
							if err = m.CloudController.CreateSpace(spaceName, orgGUID); err == nil {
								if err = m.UpdateSpaceWithDefaults(configDir, spaceName, input.Org, ldapBindPassword); err != nil {
									lo.G.Error(err)
									return err
								}
							} else {
								lo.G.Error(err)
								return err
							}
						}
					}
				}
			}
		}
		return nil
	}
}

func (m *DefaultSpaceManager) UpdateSpaceWithDefaults(configDir, spaceName, orgName, ldapBindPassword string) error {
	defaultSpaceConfigFile := configDir + "/spaceDefaults.yml"
	if m.UtilsMgr.FileOrDirectoryExists(defaultSpaceConfigFile) {
		var config *ldap.Config
		var uaacUsers map[string]string
		var err error
		if ldapBindPassword == "" {
			config = &ldap.Config{
				Enabled: false,
			}
		} else {
			if config, err = m.LdapMgr.GetConfig(configDir, ldapBindPassword); err != nil {
				lo.G.Error(err)
				return err
			}
		}

		if uaacUsers, err = m.UAACMgr.ListUsers(); err != nil {
			lo.G.Error(err)
			return err
		}

		var defaultSpaceConfig *InputUpdateSpaces

		if err = m.UtilsMgr.LoadFile(defaultSpaceConfigFile, &defaultSpaceConfig); err == nil {
			defaultSpaceConfig.Org = orgName
			defaultSpaceConfig.Space = spaceName
			if err = m.updateSpaceUsers(config, defaultSpaceConfig, uaacUsers); err != nil {
				return err
			} else {
				return nil
			}
		} else {
			lo.G.Error(err)
			return err
		}
	} else {
		lo.G.Info(defaultSpaceConfigFile, "doesn't exist")
		return nil
	}
}

func (m *DefaultSpaceManager) doesSpaceExist(spaces []*cloudcontroller.Space, spaceName string) (result bool) {
	result = false
	for _, space := range spaces {
		if space.Entity.Name == spaceName {
			result = true
			return
		}
	}
	return

}
<commit_msg>space cleanup<commit_after>package space

import (
	"fmt"
	"io/ioutil"
	"path"
	"path/filepath"
	"strings"

	"github.com/pivotalservices/cf-mgmt/cloudcontroller"
	"github.com/pivotalservices/cf-mgmt/ldap"
	"github.com/pivotalservices/cf-mgmt/organization"
	"github.com/pivotalservices/cf-mgmt/uaac"
	"github.com/pivotalservices/cf-mgmt/utils"
	"github.com/xchapter7x/lo"
)

//NewManager -
func NewManager(sysDomain, token, uaacToken string) (mgr Manager) {
	cloudController := cloudcontroller.NewManager(fmt.Sprintf("https://api.%s", sysDomain), token)
	ldapMgr := ldap.NewManager()
	uaacMgr := uaac.NewManager(sysDomain, uaacToken)
	return &DefaultSpaceManager{
		UAACMgr:         uaacMgr,
		CloudController: cloudController,
		OrgMgr:          organization.NewManager(sysDomain, token, uaacToken),
		LdapMgr:         ldapMgr,
		UtilsMgr:        utils.NewDefaultManager(),
		UserMgr:         NewUserManager(cloudController, ldapMgr, uaacMgr),
	}
}

func (m *DefaultSpaceManager) GetSpaceConfigs(configDir string) ([]*InputUpdateSpaces, error) {

	spaceDefaults := &InputUpdateSpaces{}
	m.UtilsMgr.LoadFile(path.Join(configDir, "spaceDefaults.yml"), spaceDefaults)
	if files, err := utils.NewDefaultManager().FindFiles(configDir, "spaceConfig.yml"); err == nil {
		spaceConfigs := []*InputUpdateSpaces{}
		for _, f := range files {
			lo.G.Info("Processing space file", f)
			input := &InputUpdateSpaces{}
			if err = m.UtilsMgr.LoadFile(f, input); err == nil {
				input.Developer.LdapUsers = append(input.Developer.LdapUsers, spaceDefaults.Developer.LdapUsers...)
				input.Developer.Users = append(input.Developer.Users, spaceDefaults.Developer.Users...)
				input.Auditor.LdapUsers = append(input.Auditor.LdapUsers, spaceDefaults.Auditor.LdapUsers...)
				input.Auditor.Users = append(input.Auditor.Users, spaceDefaults.Auditor.Users...)
				input.Manager.LdapUsers = append(input.Manager.LdapUsers, spaceDefaults.Manager.LdapUsers...)
				input.Manager.Users = append(input.Manager.Users, spaceDefaults.Manager.Users...)

				spaceConfigs = append(spaceConfigs, input)
				if input.EnableSecurityGroup {
					securityGroupFile := strings.Replace(f, "spaceConfig.yml", "security-group.json", -1)
					lo.G.Debug("Loading security group contents", securityGroupFile)
					var bytes []byte
					if bytes, err = ioutil.ReadFile(securityGroupFile); err == nil {
						lo.G.Debug("setting security group contents", string(bytes))
						input.SecurityGroupContents = string(bytes)
					} else {
						return nil, err
					}
				}
			} else {
				return nil, err
			}
		}

		return spaceConfigs, nil
	} else {
		return nil, err
	}
}

//CreateApplicationSecurityGroups -
func (m *DefaultSpaceManager) CreateApplicationSecurityGroups(configDir string) error {
	var targetSGGUID string
	var sgs map[string]string
	var space *cloudcontroller.Space

	if spaceConfigs, err := m.GetSpaceConfigs(configDir); err != nil {
		return err
	} else {
		for _, input := range spaceConfigs {
			if input.EnableSecurityGroup {
				if space, err = m.FindSpace(input.Org, input.Space); err == nil {
					sgName := fmt.Sprintf("%s-%s", input.Org, input.Space)
					if sgs, err = m.CloudController.ListSecurityGroups(); err == nil {
						if sgGUID, ok := sgs[sgName]; ok {
							lo.G.Info("Updating security group", sgName)
							if err = m.CloudController.UpdateSecurityGroup(sgGUID, sgName, input.SecurityGroupContents); err == nil {
								lo.G.Info("Binding security group", sgName, "to space", space.Entity.Name)
								m.CloudController.AssignSecurityGroupToSpace(space.MetaData.GUID, sgGUID)
							}
						} else {
							lo.G.Info("Creating security group", sgName)
							if targetSGGUID, err = m.CloudController.CreateSecurityGroup(sgName, input.SecurityGroupContents); err == nil {
								lo.G.Info("Binding security group", sgName, "to space", space.Entity.Name)
								m.CloudController.AssignSecurityGroupToSpace(space.MetaData.GUID, targetSGGUID)
							}
						}
					}
				}
			}
		}
	}
	return nil
}

//CreateQuotas -
func (m *DefaultSpaceManager) CreateQuotas(configDir string) error {
	var quotas map[string]string
	var space *cloudcontroller.Space
	var targetQuotaGUID string

	if spaceConfigs, err := m.GetSpaceConfigs(configDir); err != nil {
		return err
	} else {
		for _, input := range spaceConfigs {
			if input.EnableSpaceQuota {
				if space, err = m.FindSpace(input.Org, input.Space); err == nil {
					quotaName := space.Entity.Name
					if quotas, err = m.CloudController.ListAllSpaceQuotasForOrg(space.Entity.OrgGUID); err == nil {
						if quotaGUID, ok := quotas[quotaName]; ok {
							lo.G.Info("Updating quota", quotaName)
							if err = m.CloudController.UpdateSpaceQuota(space.Entity.OrgGUID, quotaGUID,
								quotaName, input.MemoryLimit, input.InstanceMemoryLimit, input.TotalRoutes, input.TotalServices, input.PaidServicePlansAllowed); err == nil {
								lo.G.Info("Assigning", quotaName, "to", space.Entity.Name)
								m.CloudController.AssignQuotaToSpace(space.MetaData.GUID, quotaGUID)
							}
						} else {
							lo.G.Info("Creating quota", quotaName)
							if targetQuotaGUID, err = m.CloudController.CreateSpaceQuota(space.Entity.OrgGUID,
								quotaName, input.MemoryLimit, input.InstanceMemoryLimit, input.TotalRoutes, input.TotalServices, input.PaidServicePlansAllowed); err == nil {
								lo.G.Info("Assigning", quotaName, "to", space.Entity.Name)
								m.CloudController.AssignQuotaToSpace(space.MetaData.GUID, targetQuotaGUID)
							}
						}
					}
				}
			}
		}
	}
	return nil
}

//UpdateSpaces -
func (m *DefaultSpaceManager) UpdateSpaces(configDir string) error {
	var space *cloudcontroller.Space

	if spaceConfigs, err := m.GetSpaceConfigs(configDir); err != nil {
		return err
	} else {
		for _, input := range spaceConfigs {
			if space, err = m.FindSpace(input.Org, input.Space); err == nil {
				lo.G.Info("Processing space", space.Entity.Name)
				if input.AllowSSH != space.Entity.AllowSSH {
					if err = m.CloudController.UpdateSpaceSSH(input.AllowSSH, space.MetaData.GUID); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

//UpdateSpaceUsers -
func (m *DefaultSpaceManager) UpdateSpaceUsers(configDir, ldapBindPassword string) error {
	var config *ldap.Config
	var uaacUsers map[string]string
	var err error

	config, err = m.LdapMgr.GetConfig(configDir, ldapBindPassword)
	if err != nil {
		lo.G.Error(err)
		return err
	}

	uaacUsers, err = m.UAACMgr.ListUsers()

	if err != nil {
		lo.G.Error(err)
		return err
	}

	var spaceConfigs []*InputUpdateSpaces

	if spaceConfigs, err = m.GetSpaceConfigs(configDir); err != nil {
		lo.G.Error(err)
		return err
	}

	for _, input := range spaceConfigs {
		if err = m.updateSpaceUsers(config, input, uaacUsers); err != nil {
			return err
		}
	}

	return nil
}

func (m *DefaultSpaceManager) updateSpaceUsers(config *ldap.Config, input *InputUpdateSpaces, uaacUsers map[string]string) error {
	if space, err := m.FindSpace(input.Org, input.Space); err == nil {
		if err = m.UserMgr.UpdateSpaceUsers(config, uaacUsers, UpdateUsersInput{
			SpaceName:     space.Entity.Name,
			SpaceGUID:     space.MetaData.GUID,
			OrgName:       input.Org,
			OrgGUID:       space.Entity.OrgGUID,
			Role:          "developers",
			LdapGroupName: input.GetDeveloperGroup(),
			LdapUsers:     input.Developer.LdapUsers,
			Users:         input.Developer.Users,
			RemoveUsers:   input.RemoveUsers,
		}); err != nil {
			return err
		}

		if err = m.UserMgr.UpdateSpaceUsers(config, uaacUsers,
			UpdateUsersInput{
				SpaceName:     space.Entity.Name,
				SpaceGUID:     space.MetaData.GUID,
				OrgGUID:       space.Entity.OrgGUID,
				OrgName:       input.Org,
				Role:          "managers",
				LdapGroupName: input.GetManagerGroup(),
				LdapUsers:     input.Manager.LdapUsers,
				Users:         input.Manager.Users,
				RemoveUsers:   input.RemoveUsers,
			}); err != nil {
			return err
		}
		if err = m.UserMgr.UpdateSpaceUsers(config, uaacUsers,
			UpdateUsersInput{
				SpaceName:     space.Entity.Name,
				SpaceGUID:     space.MetaData.GUID,
				OrgGUID:       space.Entity.OrgGUID,
				OrgName:       input.Org,
				Role:          "auditors",
				LdapGroupName: input.GetAuditorGroup(),
				LdapUsers:     input.Auditor.LdapUsers,
				Users:         input.Auditor.Users,
				RemoveUsers:   input.RemoveUsers,
			}); err != nil {
			return err
		}
		return nil
	} else {
		return err
	}
}

//FindSpace -
func (m *DefaultSpaceManager) FindSpace(orgName, spaceName string) (*cloudcontroller.Space, error) {
	if orgGUID, err := m.OrgMgr.GetOrgGUID(orgName); err != nil {
		return nil, err
	} else {
		if spaces, err := m.CloudController.ListSpaces(orgGUID); err == nil {
			for _, theSpace := range spaces {
				if theSpace.Entity.Name == spaceName {
					return theSpace, nil
				}
			}
			return nil, fmt.Errorf("Space [%s] not found in org [%s]", spaceName, orgName)
		} else {
			return nil, err
		}
	}
}

func (m *DefaultSpaceManager) GetSpaceConfigList(configDir string) ([]InputCreateSpaces, error) {

	if files, err := m.UtilsMgr.FindFiles(configDir, "spaces.yml"); err != nil {
		return nil, err
	} else {
		spaceList := []InputCreateSpaces{}
		for _, f := range files {
			lo.G.Info("Processing space file", f)
			input := InputCreateSpaces{}
			if err := m.UtilsMgr.LoadFile(f, &input); err == nil {
				spaceList = append(spaceList, input)
			}
		}
		return spaceList, nil
	}
}

//CreateSpaces -
func (m *DefaultSpaceManager) CreateSpaces(configDir, ldapBindPassword string) error {

	if configSpaceList, err := m.GetSpaceConfigList(configDir); err != nil {
		return err
	} else {
		for _, input := range configSpaceList {
			if len(input.Spaces) >= 0 {
				var orgGUID string
				if orgGUID, err = m.OrgMgr.GetOrgGUID(input.Org); err != nil {
					return err
				}
				var spaces []*cloudcontroller.Space
				if spaces, err = m.CloudController.ListSpaces(orgGUID); err == nil {
					for _, spaceName := range input.Spaces {
						if m.doesSpaceExist(spaces, spaceName) {
							lo.G.Info(fmt.Sprintf("[%s] space already exists", spaceName))
						} else {
							lo.G.Info(fmt.Sprintf("Creating [%s] space in [%s] org", spaceName, input.Org))
							if err = m.CloudController.CreateSpace(spaceName, orgGUID); err == nil {
								if err = m.UpdateSpaceWithDefaults(configDir, spaceName, input.Org, ldapBindPassword); err != nil {
									lo.G.Error(err)
									return err
								}
							} else {
								lo.G.Error(err)
								return err
							}
						}
					}
				}
			}
		}
		return nil
	}
}

func (m *DefaultSpaceManager) UpdateSpaceWithDefaults(configDir, spaceName, orgName, ldapBindPassword string) error {
	defaultSpaceConfigFile := filepath.Join(configDir, "spaceDefaults.yml")
	if m.UtilsMgr.FileOrDirectoryExists(defaultSpaceConfigFile) {
		var config *ldap.Config
		var err error
		if ldapBindPassword == "" {
			config = &ldap.Config{
				Enabled: false,
			}
		} else {
			if config, err = m.LdapMgr.GetConfig(configDir, ldapBindPassword); err != nil {
				lo.G.Error(err)
				return err
			}
		}

		var uaacUsers map[string]string
		if uaacUsers, err = m.UAACMgr.ListUsers(); err != nil {
			lo.G.Error(err)
			return err
		}

		var defaultSpaceConfig *InputUpdateSpaces
		if err = m.UtilsMgr.LoadFile(defaultSpaceConfigFile, &defaultSpaceConfig); err != nil {
			lo.G.Info(defaultSpaceConfigFile, "doesn't exist")
			return nil
		}
		defaultSpaceConfig.Org = orgName
		defaultSpaceConfig.Space = spaceName
		if err = m.updateSpaceUsers(config, defaultSpaceConfig, uaacUsers); err != nil {
			return err
		}
	}
	return nil
}

func (m *DefaultSpaceManager) doesSpaceExist(spaces []*cloudcontroller.Space, spaceName string) bool {
	for _, space := range spaces {
		if space.Entity.Name == spaceName {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>/*
 * Pure Go SMART library
 * Copyright 2017 Daniel Swarbrick
 */

package smart

import (
	"encoding/binary"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"unsafe"

	"github.com/BurntSushi/toml"
)

// SMART attribute conversion rule
type attrConv struct {
	Conv string
	Name string
}

type driveModel struct {
	Family         string
	ModelRegex     string
	FirmwareRegex  string
	WarningMsg     string
	Presets        map[string]attrConv
	CompiledRegexp *regexp.Regexp
}

type driveDb struct {
	Drives []driveModel
}

// Individual SMART attribute (12 bytes)
type smartAttr struct {
	Id          uint8
	Flags       uint16
	Value       uint8   // normalised value
	Worst       uint8   // worst value
	VendorBytes [6]byte // vendor-specific (and sometimes device-specific) data
	Reserved    uint8
}

// Page of 30 SMART attributes as per ATA spec
type smartPage struct {
	Version uint16
	Attrs   [30]smartAttr
}

var nativeEndian binary.ByteOrder

// Determine native endianness of system
func init() {
	i := uint32(1)
	b := (*[4]byte)(unsafe.Pointer(&i))
	if b[0] == 1 {
		nativeEndian = binary.LittleEndian
	} else {
		nativeEndian = binary.BigEndian
	}
}

// lookupDrive returns the most appropriate driveModel for a given ATA IDENTIFY value
func (db *driveDb) lookupDrive(ident []byte) driveModel {
	var model, defaultModel driveModel

	for _, d := range db.Drives {
		// Skip placeholder entry
		if strings.HasPrefix(d.Family, "$Id") {
			continue
		}

		if d.Family == "DEFAULT" {
			defaultModel = d
			continue
		}

		if d.CompiledRegexp.Match(ident) {
			model = d

			// Inherit presets from defaultModel
			for id, p := range defaultModel.Presets {
				if _, exists := model.Presets[id]; exists {
					// Some drives override the conv but don't specify a name, so copy it from default
					if model.Presets[id].Name == "" {
						model.Presets[id] = attrConv{Name: p.Name, Conv: model.Presets[id].Conv}
					}
				} else {
					model.Presets[id] = p
				}
			}

			break
		}
	}

	return model
}

// openDriveDb opens a .toml formatted drive database, unmarshalls it, and returns a driveDb
func openDriveDb(dbfile string) (driveDb, error) {
	var db driveDb

	if _, err := toml.DecodeFile(dbfile, &db); err != nil {
		return db, fmt.Errorf("Cannot open / parse drive DB: %s", err)
	}

	for i, d := range db.Drives {
		db.Drives[i].CompiledRegexp, _ = regexp.Compile(d.ModelRegex)
	}

	return db, nil
}

// decodeVendorBytes decodes the six-byte vendor byte array based on the conversion rule passed as
// conv. The conversion may also include the reserved byte, normalised value or worst value byte.
func (sa *smartAttr) decodeVendorBytes(conv string) (r uint64) {
	vb := sa.VendorBytes

	// TODO: Complete other attr conversion, honour specified byte order
	switch conv {
	case "raw16(raw16)", "raw16(avg16)":
		r = uint64(vb[0]) | uint64(vb[1])<<8
	case "raw24(raw8)", "raw24/raw24", "raw24/raw32":
		r = uint64(vb[0]) | uint64(vb[1])<<8 | uint64(vb[2])<<16
	case "raw48":
		r = uint64(vb[0]) | uint64(vb[1])<<8 | uint64(vb[2])<<16 |
			uint64(vb[3])<<24 | uint64(vb[4])<<32 | uint64(vb[5])<<40
	case "raw56":
		r = uint64(vb[0]) | uint64(vb[1])<<8 | uint64(vb[2])<<16 | uint64(vb[3])<<24 |
			uint64(vb[4])<<32 | uint64(vb[5])<<40 | uint64(sa.Reserved)<<48
	case "tempminmax":
		// This is device specific!
		r = uint64(vb[0])
	}

	return r
}

func printSMART(smart smartPage, drive driveModel) {
	fmt.Printf("\nSMART structure version: %d\n", smart.Version)
	fmt.Printf("ID# ATTRIBUTE_NAME           FLAG     VALUE WORST RESERVED RAW_VALUE     VENDOR_BYTES\n")

	for _, attr := range smart.Attrs {
		var (
			rawValue uint64
			conv     attrConv
		)

		if attr.Id == 0 {
			break
		}

		conv, ok := drive.Presets[strconv.Itoa(int(attr.Id))]
		if ok {
			rawValue = attr.decodeVendorBytes(conv.Conv)
		}

		fmt.Printf("%3d %-24s %#04x   %03d   %03d   %03d      %-12d  %v (%s)\n",
			attr.Id, conv.Name, attr.Flags, attr.Value, attr.Worst, attr.Reserved,
			rawValue, attr.VendorBytes, conv.Conv)
	}
}
<commit_msg>Decode pre-fail / advisory bit and online data collection bit from attribute flags<commit_after>/*
 * Pure Go SMART library
 * Copyright 2017 Daniel Swarbrick
 */

package smart

import (
	"encoding/binary"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"unsafe"

	"github.com/BurntSushi/toml"
)

// SMART attribute conversion rule
type attrConv struct {
	Conv string
	Name string
}

type driveModel struct {
	Family         string
	ModelRegex     string
	FirmwareRegex  string
	WarningMsg     string
	Presets        map[string]attrConv
	CompiledRegexp *regexp.Regexp
}

type driveDb struct {
	Drives []driveModel
}

// Individual SMART attribute (12 bytes)
type smartAttr struct {
	Id          uint8
	Flags       uint16
	Value       uint8   // normalised value
	Worst       uint8   // worst value
	VendorBytes [6]byte // vendor-specific (and sometimes device-specific) data
	Reserved    uint8
}

// Page of 30 SMART attributes as per ATA spec
type smartPage struct {
	Version uint16
	Attrs   [30]smartAttr
}

var nativeEndian binary.ByteOrder

// Determine native endianness of system
func init() {
	i := uint32(1)
	b := (*[4]byte)(unsafe.Pointer(&i))
	if b[0] == 1 {
		nativeEndian = binary.LittleEndian
	} else {
		nativeEndian = binary.BigEndian
	}
}

// lookupDrive returns the most appropriate driveModel for a given ATA IDENTIFY value
func (db *driveDb) lookupDrive(ident []byte) driveModel {
	var model, defaultModel driveModel

	for _, d := range db.Drives {
		// Skip placeholder entry
		if strings.HasPrefix(d.Family, "$Id") {
			continue
		}

		if d.Family == "DEFAULT" {
			defaultModel = d
			continue
		}

		if d.CompiledRegexp.Match(ident) {
			model = d

			// Inherit presets from defaultModel
			for id, p := range defaultModel.Presets {
				if _, exists := model.Presets[id]; exists {
					// Some drives override the conv but don't specify a name, so copy it from default
					if model.Presets[id].Name == "" {
						model.Presets[id] = attrConv{Name: p.Name, Conv: model.Presets[id].Conv}
					}
				} else {
					model.Presets[id] = p
				}
			}

			break
		}
	}

	return model
}

// openDriveDb opens a .toml formatted drive database, unmarshalls it, and returns a driveDb
func openDriveDb(dbfile string) (driveDb, error) {
	var db driveDb

	if _, err := toml.DecodeFile(dbfile, &db); err != nil {
		return db, fmt.Errorf("Cannot open / parse drive DB: %s", err)
	}

	for i, d := range db.Drives {
		db.Drives[i].CompiledRegexp, _ = regexp.Compile(d.ModelRegex)
	}

	return db, nil
}

// decodeVendorBytes decodes the six-byte vendor byte array based on the conversion rule passed as
// conv. The conversion may also include the reserved byte, normalised value or worst value byte.
func (sa *smartAttr) decodeVendorBytes(conv string) (r uint64) {
	vb := sa.VendorBytes

	// TODO: Complete other attr conversion, honour specified byte order
	switch conv {
	case "raw16(raw16)", "raw16(avg16)":
		r = uint64(vb[0]) | uint64(vb[1])<<8
	case "raw24(raw8)", "raw24/raw24", "raw24/raw32":
		r = uint64(vb[0]) | uint64(vb[1])<<8 | uint64(vb[2])<<16
	case "raw48":
		r = uint64(vb[0]) | uint64(vb[1])<<8 | uint64(vb[2])<<16 |
			uint64(vb[3])<<24 | uint64(vb[4])<<32 | uint64(vb[5])<<40
	case "raw56":
		r = uint64(vb[0]) | uint64(vb[1])<<8 | uint64(vb[2])<<16 | uint64(vb[3])<<24 |
			uint64(vb[4])<<32 | uint64(vb[5])<<40 | uint64(sa.Reserved)<<48
	case "tempminmax":
		// This is device specific!
		r = uint64(vb[0])
	}

	return r
}

func printSMART(smart smartPage, drive driveModel) {
	fmt.Printf("\nSMART structure version: %d\n", smart.Version)
	fmt.Printf("ID# ATTRIBUTE_NAME           FLAG     VALUE WORST RESERVED TYPE     UPDATED RAW_VALUE     VENDOR_BYTES\n")

	for _, attr := range smart.Attrs {
		var (
			rawValue              uint64
			conv                  attrConv
			attrType, attrUpdated string
		)

		if attr.Id == 0 {
			break
		}

		conv, ok := drive.Presets[strconv.Itoa(int(attr.Id))]
		if ok {
			rawValue = attr.decodeVendorBytes(conv.Conv)
		}

		// Pre-fail / advisory bit
		if attr.Flags&0x0001 > 0 {
			attrType = "Pre-fail"
		} else {
			attrType = "Old_age"
		}

		// Online data collection bit
		if attr.Flags&0x0002 > 0 {
			attrUpdated = "Always"
		} else {
			attrUpdated = "Offline"
		}

		fmt.Printf("%3d %-24s %#04x   %03d   %03d   %03d      %-8s %-7s %-12d  %v (%s)\n",
			attr.Id, conv.Name, attr.Flags, attr.Value, attr.Worst, attr.Reserved, attrType,
			attrUpdated, rawValue, attr.VendorBytes, conv.Conv)
	}
}
<|endoftext|>


<commit_before>package serial

/*

#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

#include <linux/serial.h>

// Define (eventually) missing constants
#ifndef IUCLC
	static const tcflag_t IUCLC = 0;
#endif

// ioctl call is not available through syscall package
//int ioctl_wrapper(int d, unsigned long request) {
//	return ioctl(d, request);
//}

//int fcntl_wrapper(int fd, int cmd, int arg) {
//	return fcntl(fd, cmd, arg);
//}

// Gain exclusive access to serial port
void setTIOCEXCL(int handle) {
#if defined TIOCEXCL
	ioctl(handle, TIOCEXCL);
#endif
}

// Release exclusive access to serial port
void setTIOCNXCL(int handle) {
#if defined TIOCNXCL
	ioctl(handle, TIOCNXCL);
#endif
}

//int selectRead(int handle) {
//	fd_set rfds;
//	FD_ZERO(&rfds);
//	FD_SET(handle, &rfds);
//  int ret = select(handle+1, &rfds, NULL, NULL, NULL);
//	if (ret==-1)
//		return -1;
//	else
//		return 0;
//}

*/
import "C"
import "io/ioutil"
import "regexp"
import "syscall"

// native syscall wrapper functions

func getExclusiveAccess(handle int) error {
	_, err := C.setTIOCEXCL(C.int(handle))
	return err
}

func releaseExclusiveAccess(handle int) error {
	_, err := C.setTIOCNXCL(C.int(handle))
	return err
}

func getTermSettings(handle int) (*C.struct_termios, error) {
	settings := new(C.struct_termios)
	_, err := C.tcgetattr(C.int(handle), settings)
	return settings, err
}

func setTermSettings(handle int, settings *C.struct_termios) error {
	_, err := C.tcsetattr(C.int(handle), C.TCSANOW, settings)
	return err
}

func getErrno(err error) int {
	return int(err.(syscall.Errno))
}

// OS dependent values

const devFolder = "/dev"
const regexFilter = "(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO)[0-9]{1,3}"

// opaque type that implements SerialPort interface for linux
type linuxSerialPort struct {
	Handle int
}

func GetPortsList() ([]string, error) {
	files, err := ioutil.ReadDir(devFolder)
	if err != nil {
		return nil, err
	}

	ports := make([]string, len(files))
	found := 0
	for _, f := range files {
		// Skip folders
		if f.IsDir() {
			continue
		}

		// Keep only devices with the correct name
		match, err := regexp.MatchString(regexFilter, f.Name())
		if err != nil {
			return nil, err
		}
		if !match {
			continue
		}

		portName := devFolder + "/" + f.Name()

		// Check if serial port is real or is a placeholder serial port "ttySxx"
		if f.Name()[:4] == "ttyS" {
			port, err := OpenPort(portName, false)
			if err != nil {
				serr, ok := err.(*SerialPortError)
				if ok && serr.Code() == ERROR_INVALID_SERIAL_PORT {
					continue
				}
			} else {
				port.Close()
			}
		}

		// Save found serial port in the resulting list
		ports[found] = portName
		found++
	}

	ports = ports[:found]
	return ports, nil
}

func (port *linuxSerialPort) Close() error {
	releaseExclusiveAccess(port.Handle)
	return syscall.Close(port.Handle)
}

func (port *linuxSerialPort) Read(p []byte) (n int, err error) {
	return syscall.Read(port.Handle, p)
}

func (port *linuxSerialPort) Write(p []byte) (n int, err error) {
	return syscall.Write(port.Handle, p)
}

var baudrateMap = map[int]C.speed_t{
	0:       C.B0,
	50:      C.B50,
	75:      C.B75,
	110:     C.B110,
	134:     C.B134,
	150:     C.B150,
	200:     C.B200,
	300:     C.B300,
	600:     C.B600,
	1200:    C.B1200,
	1800:    C.B1800,
	2400:    C.B2400,
	4800:    C.B4800,
	9600:    C.B9600,
	19200:   C.B19200,
	38400:   C.B38400,
	57600:   C.B57600,
	115200:  C.B115200,
	230400:  C.B230400,
	460800:  C.B460800,
	500000:  C.B500000,
	576000:  C.B576000,
	921600:  C.B921600,
	1000000: C.B1000000,
	1152000: C.B1152000,
	1500000: C.B1500000,
	2000000: C.B2000000,
	2500000: C.B2500000,
	3000000: C.B3000000,
	3500000: C.B3500000,
	4000000: C.B4000000,
}

func (port *linuxSerialPort) SetSpeed(speed int) error {
	baudrate, ok := baudrateMap[speed]
	if !ok {
		return &SerialPortError{code: ERROR_INVALID_PORT_SPEED}
	}
	settings, err := getTermSettings(port.Handle)
	if err != nil {
		return err
	}
	C.cfsetispeed(settings, baudrate)
	C.cfsetospeed(settings, baudrate)
	return setTermSettings(port.Handle, settings)
}

func OpenPort(portName string, exclusive bool) (SerialPort, error) {
	handle, err := syscall.Open(portName, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY, 0)
	if err != nil {
		switch err {
		case syscall.EBUSY:
			return nil, &SerialPortError{code: ERROR_PORT_BUSY}
		case syscall.EACCES:
			return nil, &SerialPortError{code: ERROR_PERMISSION_DENIED}
		}
		return nil, err
	}

	// Setup serial port with defaults

	settings, err := getTermSettings(handle)
	if err != nil {
		syscall.Close(handle)
		return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT}
	}

	// Set local mode
  settings.c_cflag |= C.CREAD | C.CLOCAL

	// Set raw mode
  settings.c_lflag &= ^C.tcflag_t(C.ICANON | C.ECHO | C.ECHOE | C.ECHOK | C.ECHONL | C.ECHOCTL | C.ECHOPRT | C.ECHOKE | C.ISIG | C.IEXTEN)
  settings.c_iflag &= ^C.tcflag_t(C.IXON | C.IXOFF | C.IXANY | C.INPCK | C.IGNPAR | C.PARMRK | C.ISTRIP | C.IGNBRK | C.BRKINT | C.INLCR | C.IGNCR | C.ICRNL | C.IUCLC)
  settings.c_oflag &= ^C.tcflag_t(C.OPOST)

	// Block reads until at least one char is available (no timeout)
	settings.c_cc[C.VMIN] = 1;
	settings.c_cc[C.VTIME] = 0;

	err = setTermSettings(handle, settings)
	if err != nil {
		syscall.Close(handle)
		return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT}
	}
/*
    settings->c_cflag &= ~CRTSCTS;
*/
	syscall.SetNonblock(handle, false)

	if exclusive {
		getExclusiveAccess(handle)
	}

	serialPort := &linuxSerialPort{
		Handle: handle,
	}
	return serialPort, nil
}

// vi:ts=2
<commit_msg>fixed indent<commit_after>package serial

/*

#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

#include <linux/serial.h>

// Define (eventually) missing constants
#ifndef IUCLC
	static const tcflag_t IUCLC = 0;
#endif

// ioctl call is not available through syscall package
//int ioctl_wrapper(int d, unsigned long request) {
//	return ioctl(d, request);
//}

//int fcntl_wrapper(int fd, int cmd, int arg) {
//	return fcntl(fd, cmd, arg);
//}

// Gain exclusive access to serial port
void setTIOCEXCL(int handle) {
#if defined TIOCEXCL
	ioctl(handle, TIOCEXCL);
#endif
}

// Release exclusive access to serial port
void setTIOCNXCL(int handle) {
#if defined TIOCNXCL
	ioctl(handle, TIOCNXCL);
#endif
}

//int selectRead(int handle) {
//	fd_set rfds;
//	FD_ZERO(&rfds);
//	FD_SET(handle, &rfds);
//  int ret = select(handle+1, &rfds, NULL, NULL, NULL);
//	if (ret==-1)
//		return -1;
//	else
//		return 0;
//}

*/
import "C"
import "io/ioutil"
import "regexp"
import "syscall"

// native syscall wrapper functions

func getExclusiveAccess(handle int) error {
	_, err := C.setTIOCEXCL(C.int(handle))
	return err
}

func releaseExclusiveAccess(handle int) error {
	_, err := C.setTIOCNXCL(C.int(handle))
	return err
}

func getTermSettings(handle int) (*C.struct_termios, error) {
	settings := new(C.struct_termios)
	_, err := C.tcgetattr(C.int(handle), settings)
	return settings, err
}

func setTermSettings(handle int, settings *C.struct_termios) error {
	_, err := C.tcsetattr(C.int(handle), C.TCSANOW, settings)
	return err
}

func getErrno(err error) int {
	return int(err.(syscall.Errno))
}

// OS dependent values

const devFolder = "/dev"
const regexFilter = "(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO)[0-9]{1,3}"

// opaque type that implements SerialPort interface for linux
type linuxSerialPort struct {
	Handle int
}

func GetPortsList() ([]string, error) {
	files, err := ioutil.ReadDir(devFolder)
	if err != nil {
		return nil, err
	}

	ports := make([]string, len(files))
	found := 0
	for _, f := range files {
		// Skip folders
		if f.IsDir() {
			continue
		}

		// Keep only devices with the correct name
		match, err := regexp.MatchString(regexFilter, f.Name())
		if err != nil {
			return nil, err
		}
		if !match {
			continue
		}

		portName := devFolder + "/" + f.Name()

		// Check if serial port is real or is a placeholder serial port "ttySxx"
		if f.Name()[:4] == "ttyS" {
			port, err := OpenPort(portName, false)
			if err != nil {
				serr, ok := err.(*SerialPortError)
				if ok && serr.Code() == ERROR_INVALID_SERIAL_PORT {
					continue
				}
			} else {
				port.Close()
			}
		}

		// Save found serial port in the resulting list
		ports[found] = portName
		found++
	}

	ports = ports[:found]
	return ports, nil
}

func (port *linuxSerialPort) Close() error {
	releaseExclusiveAccess(port.Handle)
	return syscall.Close(port.Handle)
}

func (port *linuxSerialPort) Read(p []byte) (n int, err error) {
	return syscall.Read(port.Handle, p)
}

func (port *linuxSerialPort) Write(p []byte) (n int, err error) {
	return syscall.Write(port.Handle, p)
}

var baudrateMap = map[int]C.speed_t{
	0:       C.B0,
	50:      C.B50,
	75:      C.B75,
	110:     C.B110,
	134:     C.B134,
	150:     C.B150,
	200:     C.B200,
	300:     C.B300,
	600:     C.B600,
	1200:    C.B1200,
	1800:    C.B1800,
	2400:    C.B2400,
	4800:    C.B4800,
	9600:    C.B9600,
	19200:   C.B19200,
	38400:   C.B38400,
	57600:   C.B57600,
	115200:  C.B115200,
	230400:  C.B230400,
	460800:  C.B460800,
	500000:  C.B500000,
	576000:  C.B576000,
	921600:  C.B921600,
	1000000: C.B1000000,
	1152000: C.B1152000,
	1500000: C.B1500000,
	2000000: C.B2000000,
	2500000: C.B2500000,
	3000000: C.B3000000,
	3500000: C.B3500000,
	4000000: C.B4000000,
}

func (port *linuxSerialPort) SetSpeed(speed int) error {
	baudrate, ok := baudrateMap[speed]
	if !ok {
		return &SerialPortError{code: ERROR_INVALID_PORT_SPEED}
	}
	settings, err := getTermSettings(port.Handle)
	if err != nil {
		return err
	}
	C.cfsetispeed(settings, baudrate)
	C.cfsetospeed(settings, baudrate)
	return setTermSettings(port.Handle, settings)
}

func OpenPort(portName string, exclusive bool) (SerialPort, error) {
	handle, err := syscall.Open(portName, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY, 0)
	if err != nil {
		switch err {
		case syscall.EBUSY:
			return nil, &SerialPortError{code: ERROR_PORT_BUSY}
		case syscall.EACCES:
			return nil, &SerialPortError{code: ERROR_PERMISSION_DENIED}
		}
		return nil, err
	}

	// Setup serial port with defaults

	settings, err := getTermSettings(handle)
	if err != nil {
		syscall.Close(handle)
		return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT}
	}

	// Set local mode
	settings.c_cflag |= C.CREAD | C.CLOCAL

	// Set raw mode
	settings.c_lflag &= ^C.tcflag_t(C.ICANON | C.ECHO | C.ECHOE | C.ECHOK | C.ECHONL | C.ECHOCTL | C.ECHOPRT | C.ECHOKE | C.ISIG | C.IEXTEN)
	settings.c_iflag &= ^C.tcflag_t(C.IXON | C.IXOFF | C.IXANY | C.INPCK | C.IGNPAR | C.PARMRK | C.ISTRIP | C.IGNBRK | C.BRKINT | C.INLCR | C.IGNCR | C.ICRNL | C.IUCLC)
	settings.c_oflag &= ^C.tcflag_t(C.OPOST)

	// Block reads until at least one char is available (no timeout)
	settings.c_cc[C.VMIN] = 1
	settings.c_cc[C.VTIME] = 0

	err = setTermSettings(handle, settings)
	if err != nil {
		syscall.Close(handle)
		return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT}
	}
	/*
	   settings->c_cflag &= ~CRTSCTS;
	*/
	syscall.SetNonblock(handle, false)

	if exclusive {
		getExclusiveAccess(handle)
	}

	serialPort := &linuxSerialPort{
		Handle: handle,
	}
	return serialPort, nil
}

// vi:ts=2
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strings"
	"sync"
)

var META_VERSION = 1
var BASE_PORT = 10000
var globalWorldBaseDir string
var globalServerMap = NewServerMap()
var globalIdSequence = NewIdSequence(0)
var globalPortMapper = NewPortMapper()

type PortMapper struct {
	portSequence int
	freePorts    []int
	mutex        sync.Mutex
}

func (pm *PortMapper) getPort() int {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	if len(pm.freePorts) == 0 {
		result := pm.portSequence
		pm.portSequence++
		return result
	}
	result := pm.freePorts[len(pm.freePorts)-1]
	pm.freePorts = pm.freePorts[:len(pm.freePorts)-1]
	return result
}

func (pm *PortMapper) freePort(port int) {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	pm.freePorts = append(pm.freePorts, port)
}

func NewPortMapper() *PortMapper {
	return &PortMapper{
		freePorts: make([]int, 0, 10),
	}
}

type IdSequence struct {
	nextValue int
	mutex     sync.Mutex
}

func (is *IdSequence) getId() int {
	is.mutex.Lock()
	defer is.mutex.Unlock()
	result := is.nextValue
	is.nextValue++
	return result
}

func (is *IdSequence) updateSequence(usedValue int) {
	if usedValue >= is.nextValue {
		is.nextValue = usedValue + 1
	}
}

func NewIdSequence(start int) *IdSequence {
	return &IdSequence{
		nextValue: start,
	}
}

type Server struct {
	Id         int
	CreatorId  int
	Name       string
	PortOffset int
	Handle     *exec.Cmd `json:"-"`
}

func NewServer(id int, creatorId int, name string) *Server {
	if id < 0 {
		id = globalIdSequence.getId()
	}
	return &Server{
		Id:         id,
		CreatorId:  creatorId,
		Name:       strings.TrimSpace(name),
		PortOffset: globalPortMapper.getPort(),
	}
}

type ServerMap struct {
	servers map[string]*Server
	mutex   sync.Mutex
}

func (sm *ServerMap) Put(server *Server) {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	sm.servers[str(server.Id)] = server
}

func (sm *ServerMap) Get(id int) *Server {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	return sm.servers[str(id)]
}

func (sm *ServerMap) Remove(id int) *Server {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	server := sm.servers[str(id)]
	delete(sm.servers, str(id))
	return server
}

func (sm *ServerMap) Encode(w io.Writer) error {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	err := json.NewEncoder(w).Encode(sm.servers)
	return err
}

func NewServerMap() *ServerMap {
	return &ServerMap{
		servers: make(map[string]*Server),
	}
}

func runServer(server *Server) {
	app := "./server"
	args := []string{
		"-client", "client",
		"-world", worldDir(server.Id),
		"-host", ":" + str(BASE_PORT+server.PortOffset),
	}

	cmd := exec.Command(app, args...)
	server.Handle = cmd
	globalServerMap.Put(server)
	err := cmd.Run()

	if err != nil {
		log.Println(err.Error())
	}
}

type ApiGeneric struct {
	ServerId int
}

type ApiCreate struct {
	CreatorId  int
	ServerName string
}

type ServerListResponse struct {
	List map[string]Server
}

func parseGenericRequest(r *http.Request) (ApiGeneric, error) {
	var result ApiGeneric
	err := json.NewDecoder(r.Body).Decode(&result)
	if err != nil {
		log.Println("Error while parsing generic request")
		return result, err
	}
	return result, nil
}

func getHandler(w http.ResponseWriter, r *http.Request) {
	request, err := parseGenericRequest(r)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	server := globalServerMap.Get(request.ServerId)
	if server == nil {
		http.NotFound(w, r)
		return
	}

	err = json.NewEncoder(w).Encode(server)
	if err != nil {
		log.Println("Error marshalling server")
		http.Error(w, err.Error(), 500)
	}
}

func listHandler(w http.ResponseWriter, r *http.Request) {
	err := globalServerMap.Encode(w)
	if err != nil {
		http.Error(w, err.Error(), 500)
	}
}

func createHandler(w http.ResponseWriter, r *http.Request) {
	var request ApiCreate
	err := json.NewDecoder(r.Body).Decode(&request)
	if err != nil {
		log.Println("Error parsing create request", err)
		http.Error(w, err.Error(), 500)
	}

	server := NewServer(-1, request.CreatorId, request.ServerName)
	saveServer(server)
	go runServer(server)
}

func deleteHandler(w http.ResponseWriter, r *http.Request) {
	request, err := parseGenericRequest(r)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	server := globalServerMap.Remove(request.ServerId)
	err = server.Handle.Process.Kill()
	if err != nil {
		log.Println("Error while sending SIG_DEATH to running server", err)
	}
	_, err = server.Handle.Process.Wait()
	if err != nil {
		log.Println("Error while waiting on process.", err)
	}
	globalPortMapper.freePort(server.PortOffset)
}

func saveServer(server *Server) {
	err := os.MkdirAll(worldDir(server.Id), 0755)
	if err != nil {
		log.Println("Error creating required directories:", err)
		return
	}

	file, err := os.Create(path.Join(worldDir(server.Id), "meta.server"))
	if err != nil {
		log.Println("Error creating file to save server:", err)
		return
	}
	defer file.Close()

	err = json.NewEncoder(file).Encode(server)
	if err != nil {
		log.Println("Error encoding meta data.", err)
	}
}

func loadServers() {
	files, err := ioutil.ReadDir(globalWorldBaseDir)
	if err != nil {
		log.Println("Error reading base world directory")
		return
	}

	for _, fileInfo := range files {
		loadServer(fileInfo)
	}
}

func loadServer(fileInfo os.FileInfo) {
	if !fileInfo.IsDir() {
		return
	}

	file, err := os.Open(path.Join(globalWorldBaseDir, fileInfo.Name(), "meta.server"))
	if err != nil {
		log.Println("Error opening server meta data:", err)
		return
	}
	defer file.Close()

	var server Server
	err = json.NewDecoder(file).Decode(&server)
	if err != nil {
		log.Println("Error while parsing meta json for", fileInfo.Name(), err)
		return
	}

	server.PortOffset = globalPortMapper.getPort()
	globalIdSequence.updateSequence(server.Id)
	go runServer(&server)
}

func main() {
	worldFolder := flag.String("worlds", "worlds/", "Sets the base folder used to store the worlds.")
	flag.Parse()
	globalWorldBaseDir = *worldFolder

	loadServers()

	runtime.GOMAXPROCS(runtime.NumCPU())

	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/list", listHandler)
	http.HandleFunc("/create", createHandler)
	http.HandleFunc("/delete", deleteHandler)
	err := http.ListenAndServe(":3001", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

// Utility function
func str(i int) string {
	return fmt.Sprintf("%d", i)
}

func worldDir(serverId int) string {
	return path.Join(globalWorldBaseDir, "world"+str(serverId))
}
<commit_msg>Print errors in a more useful way for a couple of places<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strings"
	"sync"
)

var META_VERSION = 1
var BASE_PORT = 10000
var globalWorldBaseDir string
var globalServerMap = NewServerMap()
var globalIdSequence = NewIdSequence(0)
var globalPortMapper = NewPortMapper()

type PortMapper struct {
	portSequence int
	freePorts    []int
	mutex        sync.Mutex
}

func (pm *PortMapper) getPort() int {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	if len(pm.freePorts) == 0 {
		result := pm.portSequence
		pm.portSequence++
		return result
	}
	result := pm.freePorts[len(pm.freePorts)-1]
	pm.freePorts = pm.freePorts[:len(pm.freePorts)-1]
	return result
}

func (pm *PortMapper) freePort(port int) {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	pm.freePorts = append(pm.freePorts, port)
}

func NewPortMapper() *PortMapper {
	return &PortMapper{
		freePorts: make([]int, 0, 10),
	}
}

type IdSequence struct {
	nextValue int
	mutex     sync.Mutex
}

func (is *IdSequence) getId() int {
	is.mutex.Lock()
	defer is.mutex.Unlock()
	result := is.nextValue
	is.nextValue++
	return result
}

func (is *IdSequence) updateSequence(usedValue int) {
	if usedValue >= is.nextValue {
		is.nextValue = usedValue + 1
	}
}

func NewIdSequence(start int) *IdSequence {
	return &IdSequence{
		nextValue: start,
	}
}

type Server struct {
	Id         int
	CreatorId  int
	Name       string
	PortOffset int
	Handle     *exec.Cmd `json:"-"`
}

func NewServer(id int, creatorId int, name string) *Server {
	if id < 0 {
		id = globalIdSequence.getId()
	}
	return &Server{
		Id:         id,
		CreatorId:  creatorId,
		Name:       strings.TrimSpace(name),
		PortOffset: globalPortMapper.getPort(),
	}
}

type ServerMap struct {
	servers map[string]*Server
	mutex   sync.Mutex
}

func (sm *ServerMap) Put(server *Server) {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	sm.servers[str(server.Id)] = server
}

func (sm *ServerMap) Get(id int) *Server {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	return sm.servers[str(id)]
}

func (sm *ServerMap) Remove(id int) *Server {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	server := sm.servers[str(id)]
	delete(sm.servers, str(id))
	return server
}

func (sm *ServerMap) Encode(w io.Writer) error {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	err := json.NewEncoder(w).Encode(sm.servers)
	return err
}

func NewServerMap() *ServerMap {
	return &ServerMap{
		servers: make(map[string]*Server),
	}
}

func runServer(server *Server) {
	app := "./server"
	args := []string{
		"-client", "client",
		"-world", worldDir(server.Id),
		"-host", ":" + str(BASE_PORT+server.PortOffset),
	}

	cmd := exec.Command(app, args...)
	server.Handle = cmd
	globalServerMap.Put(server)
	err := cmd.Run()

	if err != nil {
		log.Println("Error running the server:", err)
	}
}

type ApiGeneric struct {
	ServerId int
}

type ApiCreate struct {
	CreatorId  int
	ServerName string
}

type ServerListResponse struct {
	List map[string]Server
}

func parseGenericRequest(r *http.Request) (ApiGeneric, error) {
	var result ApiGeneric
	err := json.NewDecoder(r.Body).Decode(&result)
	if err != nil {
		log.Println("Error while parsing generic request", err)
		return result, err
	}
	return result, nil
}

func getHandler(w http.ResponseWriter, r *http.Request) {
	request, err := parseGenericRequest(r)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	server := globalServerMap.Get(request.ServerId)
	if server == nil {
		http.NotFound(w, r)
		return
	}

	err = json.NewEncoder(w).Encode(server)
	if err != nil {
		log.Println("Error marshalling server")
		http.Error(w, err.Error(), 500)
	}
}

func listHandler(w http.ResponseWriter, r *http.Request) {
	err := globalServerMap.Encode(w)
	if err != nil {
		http.Error(w, err.Error(), 500)
	}
}

func createHandler(w http.ResponseWriter, r *http.Request) {
	var request ApiCreate
	err := json.NewDecoder(r.Body).Decode(&request)
	if err != nil {
		log.Println("Error parsing create request", err)
		http.Error(w, err.Error(), 500)
	}

	server := NewServer(-1, request.CreatorId, request.ServerName)
	saveServer(server)
	go runServer(server)
}

func deleteHandler(w http.ResponseWriter, r *http.Request) {
	request, err := parseGenericRequest(r)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	server := globalServerMap.Remove(request.ServerId)
	err = server.Handle.Process.Kill()
	if err != nil {
		log.Println("Error while sending SIG_DEATH to running server", err)
	}
	_, err = server.Handle.Process.Wait()
	if err != nil {
		log.Println("Error while waiting on process.", err)
	}
	globalPortMapper.freePort(server.PortOffset)
}

func saveServer(server *Server) {
	err := os.MkdirAll(worldDir(server.Id), 0755)
	if err != nil {
		log.Println("Error creating required directories:", err)
		return
	}

	file, err := os.Create(path.Join(worldDir(server.Id), "meta.server"))
	if err != nil {
		log.Println("Error creating file to save server:", err)
		return
	}
	defer file.Close()

	err = json.NewEncoder(file).Encode(server)
	if err != nil {
		log.Println("Error encoding meta data.", err)
	}
}

func loadServers() {
	files, err := ioutil.ReadDir(globalWorldBaseDir)
	if err != nil {
		log.Println("Error reading base world directory")
		return
	}

	for _, fileInfo := range files {
		loadServer(fileInfo)
	}
}

func loadServer(fileInfo os.FileInfo) {
	if !fileInfo.IsDir() {
		return
	}

	file, err := os.Open(path.Join(globalWorldBaseDir, fileInfo.Name(), "meta.server"))
	if err != nil {
		log.Println("Error opening server meta data:", err)
		return
	}
	defer file.Close()

	var server Server
	err = json.NewDecoder(file).Decode(&server)
	if err != nil {
		log.Println("Error while parsing meta json for", fileInfo.Name(), err)
		return
	}

	server.PortOffset = globalPortMapper.getPort()
	globalIdSequence.updateSequence(server.Id)
	go runServer(&server)
}

func main() {
	worldFolder := flag.String("worlds", "worlds/", "Sets the base folder used to store the worlds.")
	flag.Parse()
	globalWorldBaseDir = *worldFolder

	loadServers()

	runtime.GOMAXPROCS(runtime.NumCPU())

	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/list", listHandler)
	http.HandleFunc("/create", createHandler)
	http.HandleFunc("/delete", deleteHandler)
	err := http.ListenAndServe(":3001", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

// Utility function
func str(i int) string {
	return fmt.Sprintf("%d", i)
}

func worldDir(serverId int) string {
	return path.Join(globalWorldBaseDir, "world"+str(serverId))
}
<|endoftext|>


<commit_before>package slack

import (
	"context"
	"net/url"
	"strconv"
)

const (
	DEFAULT_STARS_USER  = ""
	DEFAULT_STARS_COUNT = 100
	DEFAULT_STARS_PAGE  = 1
)

type StarsParameters struct {
	User  string
	Count int
	Page  int
}

type StarredItem Item

type listResponseFull struct {
	Items  []Item `json:"items"`
	Paging `json:"paging"`
	SlackResponse
}

// NewStarsParameters initialises StarsParameters with default values
func NewStarsParameters() StarsParameters {
	return StarsParameters{
		User:  DEFAULT_STARS_USER,
		Count: DEFAULT_STARS_COUNT,
		Page:  DEFAULT_STARS_PAGE,
	}
}

// AddStar stars an item in a channel
func (api *Client) AddStar(channel string, item ItemRef) error {
	return api.AddStarContext(context.Background(), channel, item)
}

// AddStarContext stars an item in a channel with a custom context
func (api *Client) AddStarContext(ctx context.Context, channel string, item ItemRef) error {
	values := url.Values{
		"channel": {channel},
		"token":   {api.token},
	}
	if item.Timestamp != "" {
		values.Set("timestamp", item.Timestamp)
	}
	if item.File != "" {
		values.Set("file", item.File)
	}
	if item.Comment != "" {
		values.Set("file_comment", item.Comment)
	}

	response := &SlackResponse{}
	if err := api.postMethod(ctx, "stars.add", values, response); err != nil {
		return err
	}

	return response.Err()
}

// RemoveStar removes a starred item from a channel
func (api *Client) RemoveStar(channel string, item ItemRef) error {
	return api.RemoveStarContext(context.Background(), channel, item)
}

// RemoveStarContext removes a starred item from a channel with a custom context
func (api *Client) RemoveStarContext(ctx context.Context, channel string, item ItemRef) error {
	values := url.Values{
		"channel": {channel},
		"token":   {api.token},
	}
	if item.Timestamp != "" {
		values.Set("timestamp", item.Timestamp)
	}
	if item.File != "" {
		values.Set("file", item.File)
	}
	if item.Comment != "" {
		values.Set("file_comment", item.Comment)
	}

	response := &SlackResponse{}
	if err := api.postMethod(ctx, "stars.remove", values, response); err != nil {
		return err
	}

	return response.Err()
}

// ListStars returns information about the stars a user added
func (api *Client) ListStars(params StarsParameters) ([]Item, *Paging, error) {
	return api.ListStarsContext(context.Background(), params)
}

// ListStarsContext returns information about the stars a user added with a custom context
func (api *Client) ListStarsContext(ctx context.Context, params StarsParameters) ([]Item, *Paging, error) {
	values := url.Values{
		"token": {api.token},
	}
	if params.User != DEFAULT_STARS_USER {
		values.Add("user", params.User)
	}
	if params.Count != DEFAULT_STARS_COUNT {
		values.Add("count", strconv.Itoa(params.Count))
	}
	if params.Page != DEFAULT_STARS_PAGE {
		values.Add("page", strconv.Itoa(params.Page))
	}

	response := &listResponseFull{}
	err := api.postMethod(ctx, "stars.list", values, response)
	if err != nil {
		return nil, nil, err
	}

	if err := response.Err(); err != nil {
		return nil, nil, err
	}

	return response.Items, &response.Paging, nil
}

// GetStarred returns a list of StarredItem items.
//
// The user then has to iterate over them and figure out what they should
// be looking at according to what is in the Type.
//    for _, item := range items {
//        switch c.Type {
//        case "file_comment":
//            log.Println(c.Comment)
//        case "file":
//             ...
//
//    }
// This function still exists to maintain backwards compatibility.
// I exposed it as returning []StarredItem, so it shall stay as StarredItem
func (api *Client) GetStarred(params StarsParameters) ([]StarredItem, *Paging, error) {
	return api.GetStarredContext(context.Background(), params)
}

// GetStarredContext returns a list of StarredItem items with a custom context
//
// For more details see GetStarred
func (api *Client) GetStarredContext(ctx context.Context, params StarsParameters) ([]StarredItem, *Paging, error) {
	items, paging, err := api.ListStarsContext(ctx, params)
	if err != nil {
		return nil, nil, err
	}
	starredItems := make([]StarredItem, len(items))
	for i, item := range items {
		starredItems[i] = StarredItem(item)
	}
	return starredItems, paging, nil
}

type listResponsePaginated struct {
	Items []Item `json:"items"`
	SlackResponse
	Metadata ResponseMetadata `json:"response_metadata"`
}

// StarredItemPagination allows for paginating over the starred items
type StarredItemPagination struct {
	Items        []Item
	limit        int
	previousResp *ResponseMetadata
	c            *Client
}

// ListStarsOption options for the GetUsers method call.
type ListStarsOption func(*StarredItemPagination)

// ListAllStars returns the complete list of starred items
func (api *Client) ListAllStars() ([]Item, error) {
	return api.ListStarsPaginatedContext(context.Background())
}

// ListStarsPaginatedContext returns the list of users (with their detailed information) with a custom context
func (api *Client) ListStarsPaginatedContext(ctx context.Context) (results []Item, err error) {
	var p StarredItemPagination

	for p = api.ListStarsPaginated(); !p.done(err); p, err = p.next(ctx) {
		results = append(results, p.Items...)
	}

	return results, p.failure(err)
}

// ListStarsPaginated fetches users in a paginated fashion, see ListStarsPaginationContext for usage.
func (api *Client) ListStarsPaginated(options ...ListStarsOption) StarredItemPagination {
	return newStarPagination(api, options...)
}

func newStarPagination(c *Client, options ...ListStarsOption) (sip StarredItemPagination) {
	sip = StarredItemPagination{
		c:     c,
		limit: 200, // per slack api documentation.
	}

	for _, opt := range options {
		opt(&sip)
	}

	return sip
}

// done checks if the pagination has completed
func (StarredItemPagination) done(err error) bool {
	return err == errPaginationComplete
}

// done checks if pagination failed.
func (t StarredItemPagination) failure(err error) error {
	if t.done(err) {
		return nil
	}

	return err
}

// next gets the next list of starred items based on the cursor value
func (t StarredItemPagination) next(ctx context.Context) (_ StarredItemPagination, err error) {
	var (
		resp *listResponsePaginated
	)

	if t.c == nil || (t.previousResp != nil && t.previousResp.Cursor == "") {
		return t, errPaginationComplete
	}

	t.previousResp = t.previousResp.initialize()

	values := url.Values{
		"limit":  {strconv.Itoa(t.limit)},
		"token":  {t.c.token},
		"cursor": {t.previousResp.Cursor},
	}

	if err = t.c.postMethod(ctx, "stars.list", values, &resp); err != nil {
		return t, err
	}

	t.previousResp = &resp.Metadata
	t.Items = resp.Items

	return t, nil
}
<commit_msg>change ListStarsPaginatedContext to ListAllStarsContext<commit_after>package slack

import (
	"context"
	"net/url"
	"strconv"
)

const (
	DEFAULT_STARS_USER  = ""
	DEFAULT_STARS_COUNT = 100
	DEFAULT_STARS_PAGE  = 1
)

type StarsParameters struct {
	User  string
	Count int
	Page  int
}

type StarredItem Item

type listResponseFull struct {
	Items  []Item `json:"items"`
	Paging `json:"paging"`
	SlackResponse
}

// NewStarsParameters initialises StarsParameters with default values
func NewStarsParameters() StarsParameters {
	return StarsParameters{
		User:  DEFAULT_STARS_USER,
		Count: DEFAULT_STARS_COUNT,
		Page:  DEFAULT_STARS_PAGE,
	}
}

// AddStar stars an item in a channel
func (api *Client) AddStar(channel string, item ItemRef) error {
	return api.AddStarContext(context.Background(), channel, item)
}

// AddStarContext stars an item in a channel with a custom context
func (api *Client) AddStarContext(ctx context.Context, channel string, item ItemRef) error {
	values := url.Values{
		"channel": {channel},
		"token":   {api.token},
	}
	if item.Timestamp != "" {
		values.Set("timestamp", item.Timestamp)
	}
	if item.File != "" {
		values.Set("file", item.File)
	}
	if item.Comment != "" {
		values.Set("file_comment", item.Comment)
	}

	response := &SlackResponse{}
	if err := api.postMethod(ctx, "stars.add", values, response); err != nil {
		return err
	}

	return response.Err()
}

// RemoveStar removes a starred item from a channel
func (api *Client) RemoveStar(channel string, item ItemRef) error {
	return api.RemoveStarContext(context.Background(), channel, item)
}

// RemoveStarContext removes a starred item from a channel with a custom context
func (api *Client) RemoveStarContext(ctx context.Context, channel string, item ItemRef) error {
	values := url.Values{
		"channel": {channel},
		"token":   {api.token},
	}
	if item.Timestamp != "" {
		values.Set("timestamp", item.Timestamp)
	}
	if item.File != "" {
		values.Set("file", item.File)
	}
	if item.Comment != "" {
		values.Set("file_comment", item.Comment)
	}

	response := &SlackResponse{}
	if err := api.postMethod(ctx, "stars.remove", values, response); err != nil {
		return err
	}

	return response.Err()
}

// ListStars returns information about the stars a user added
func (api *Client) ListStars(params StarsParameters) ([]Item, *Paging, error) {
	return api.ListStarsContext(context.Background(), params)
}

// ListStarsContext returns information about the stars a user added with a custom context
func (api *Client) ListStarsContext(ctx context.Context, params StarsParameters) ([]Item, *Paging, error) {
	values := url.Values{
		"token": {api.token},
	}
	if params.User != DEFAULT_STARS_USER {
		values.Add("user", params.User)
	}
	if params.Count != DEFAULT_STARS_COUNT {
		values.Add("count", strconv.Itoa(params.Count))
	}
	if params.Page != DEFAULT_STARS_PAGE {
		values.Add("page", strconv.Itoa(params.Page))
	}

	response := &listResponseFull{}
	err := api.postMethod(ctx, "stars.list", values, response)
	if err != nil {
		return nil, nil, err
	}

	if err := response.Err(); err != nil {
		return nil, nil, err
	}

	return response.Items, &response.Paging, nil
}

// GetStarred returns a list of StarredItem items.
//
// The user then has to iterate over them and figure out what they should
// be looking at according to what is in the Type.
//    for _, item := range items {
//        switch c.Type {
//        case "file_comment":
//            log.Println(c.Comment)
//        case "file":
//             ...
//
//    }
// This function still exists to maintain backwards compatibility.
// I exposed it as returning []StarredItem, so it shall stay as StarredItem
func (api *Client) GetStarred(params StarsParameters) ([]StarredItem, *Paging, error) {
	return api.GetStarredContext(context.Background(), params)
}

// GetStarredContext returns a list of StarredItem items with a custom context
//
// For more details see GetStarred
func (api *Client) GetStarredContext(ctx context.Context, params StarsParameters) ([]StarredItem, *Paging, error) {
	items, paging, err := api.ListStarsContext(ctx, params)
	if err != nil {
		return nil, nil, err
	}
	starredItems := make([]StarredItem, len(items))
	for i, item := range items {
		starredItems[i] = StarredItem(item)
	}
	return starredItems, paging, nil
}

type listResponsePaginated struct {
	Items []Item `json:"items"`
	SlackResponse
	Metadata ResponseMetadata `json:"response_metadata"`
}

// StarredItemPagination allows for paginating over the starred items
type StarredItemPagination struct {
	Items        []Item
	limit        int
	previousResp *ResponseMetadata
	c            *Client
}

// ListStarsOption options for the GetUsers method call.
type ListStarsOption func(*StarredItemPagination)

// ListAllStars returns the complete list of starred items
func (api *Client) ListAllStars() ([]Item, error) {
	return api.ListAllStarsContext(context.Background())
}

// ListAllStarsContext returns the list of users (with their detailed information) with a custom context
func (api *Client) ListAllStarsContext(ctx context.Context) (results []Item, err error) {
	var p StarredItemPagination

	for p = api.ListStarsPaginated(); !p.done(err); p, err = p.next(ctx) {
		results = append(results, p.Items...)
	}

	return results, p.failure(err)
}

// ListStarsPaginated fetches users in a paginated fashion, see ListStarsPaginationContext for usage.
func (api *Client) ListStarsPaginated(options ...ListStarsOption) StarredItemPagination {
	return newStarPagination(api, options...)
}

func newStarPagination(c *Client, options ...ListStarsOption) (sip StarredItemPagination) {
	sip = StarredItemPagination{
		c:     c,
		limit: 200, // per slack api documentation.
	}

	for _, opt := range options {
		opt(&sip)
	}

	return sip
}

// done checks if the pagination has completed
func (StarredItemPagination) done(err error) bool {
	return err == errPaginationComplete
}

// done checks if pagination failed.
func (t StarredItemPagination) failure(err error) error {
	if t.done(err) {
		return nil
	}

	return err
}

// next gets the next list of starred items based on the cursor value
func (t StarredItemPagination) next(ctx context.Context) (_ StarredItemPagination, err error) {
	var (
		resp *listResponsePaginated
	)

	if t.c == nil || (t.previousResp != nil && t.previousResp.Cursor == "") {
		return t, errPaginationComplete
	}

	t.previousResp = t.previousResp.initialize()

	values := url.Values{
		"limit":  {strconv.Itoa(t.limit)},
		"token":  {t.c.token},
		"cursor": {t.previousResp.Cursor},
	}

	if err = t.c.postMethod(ctx, "stars.list", values, &resp); err != nil {
		return t, err
	}

	t.previousResp = &resp.Metadata
	t.Items = resp.Items

	return t, nil
}
<|endoftext|>