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

package remote

import (
	"runtime"
	"testing"
	"time"

	"github.com/aykevl/dtsync/tree"
	"github.com/aykevl/dtsync/tree/memory"
)

func TestRemote(t *testing.T) {
	var fsList [2]*Client
	for i, _ := range fsList {
		var err error
		fsList[i], err = TestClient()
		if err != nil {
			t.Fatal("could not make test client:", err)
		}
	}
	fs1 := fsList[0]
	fs2 := fsList[1]
	fsCheck := memory.NewRoot()

	// Wait for a short while (1ms) to let the number of goroutines settle down.
	// This may be machine-dependent, and may need to be updated.
	time.Sleep(time.Millisecond)

	numRoutines := runtime.NumGoroutine()
	for i, tc := range [][2]tree.TestTree{
		{fs1, fsCheck},
		{fsCheck, fs1},
		{fs1, fs2},
		{fs2, fs1},
	} {
		tree.TreeTest(t, tc[0], tc[1])
		if num := runtime.NumGoroutine(); num != numRoutines {
			t.Errorf("remote test #%d: number of goroutines changed from %d to %d", i+1, numRoutines, num)
			numRoutines = num
		}
	}

	for i, fs := range fsList {
		err := fs.Close()
		fsList[i] = nil
		if err != nil {
			t.Error("could not close test client:", err)
		}
	}
}
<commit_msg>tree/remote: enforce that *Client implements RemoteTree<commit_after>// remote_test.go
//
// Copyright (c) 2016, Ayke van Laethem
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package remote

import (
	"runtime"
	"testing"
	"time"

	"github.com/aykevl/dtsync/tree"
	"github.com/aykevl/dtsync/tree/memory"
)

func TestRemote(t *testing.T) {
	var fsList [2]*Client
	for i, _ := range fsList {
		var err error
		fsList[i], err = TestClient()
		if err != nil {
			t.Fatal("could not make test client:", err)
		}
	}

	_ = tree.RemoteTree(fsList[0])

	fs1 := fsList[0]
	fs2 := fsList[1]
	fsCheck := memory.NewRoot()

	// Wait for a short while (1ms) to let the number of goroutines settle down.
	// This may be machine-dependent, and may need to be updated.
	time.Sleep(time.Millisecond)

	numRoutines := runtime.NumGoroutine()
	for i, tc := range [][2]tree.TestTree{
		{fs1, fsCheck},
		{fsCheck, fs1},
		{fs1, fs2},
		{fs2, fs1},
	} {
		tree.TreeTest(t, tc[0], tc[1])
		if num := runtime.NumGoroutine(); num != numRoutines {
			t.Errorf("remote test #%d: number of goroutines changed from %d to %d", i+1, numRoutines, num)
			numRoutines = num
		}
	}

	for i, fs := range fsList {
		err := fs.Close()
		fsList[i] = nil
		if err != nil {
			t.Error("could not close test client:", err)
		}
	}
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"os"

	"github.com/inconshreveable/log15"
)

var (
	// Log Is the global log variable.
	Log = log15.New()

	// stdHandler is the log handler with level applied
	stdHandler = log15.StreamHandler(os.Stdout, log15.LogfmtFormat())

	// Default handler used in the package.
	defaultHandler log15.Handler
)

func init() {
	SetDefaultLogHandler(log15.LvlFilterHandler(log15.LvlInfo, stdHandler))
	Log.SetHandler(defaultHandler)
}

// NewLog creates a new instance of the logger using the current default handler
// for its output.
func NewLog(ctx ...interface{}) log15.Logger {
	l := log15.New(ctx...)
	l.SetHandler(defaultHandler)
	return l
}

// Logf is short hand to create a message string using fmt.Sprintf.
func Logf(format string, args ...interface{}) string {
	return fmt.Sprintf(format, args...)
}

// SetDefaultLogHandler sets the handler for the logger. It wraps handlers in a SyncHandler. You
// should not pass in handlers that are already wrapped in a SyncHandler.
func SetDefaultLogHandler(handler log15.Handler) {
	defaultHandler = log15.SyncHandler(handler)
	Log.SetHandler(defaultHandler)
}

// Sets a new log level for the global logging and the default handler.
func SetLogLvl(lvl log15.Lvl) {
	SetDefaultLogHandler(log15.LvlFilterHandler(lvl, stdHandler))
	Log.SetHandler(defaultHandler)
}

// DefaultLogHandler returns the current handler. It can be used to create additional
// logger instances that all use the same handler for output.
func DefaultLogHandler() log15.Handler {
	return defaultHandler
}
<commit_msg>Refactor code to allow formated function calls for the different error levels.<commit_after>package app

import (
	"fmt"
	"os"

	"github.com/inconshreveable/log15"
)

type log struct {
	log15.Logger
}

var (
	// Log Is the global log variable.
	//Log = log15.New()
	Log = newLog()

	// stdHandler is the log handler with level applied
	stdHandler = log15.StreamHandler(os.Stdout, log15.LogfmtFormat())

	// Default handler used in the package.
	defaultHandler log15.Handler
)

func newLog() *log {
	return &log{
		Logger: log15.New(),
	}
}

func init() {
	SetDefaultLogHandler(log15.LvlFilterHandler(log15.LvlInfo, stdHandler))
	Log.SetHandler(defaultHandler)
}

// NewLog creates a new instance of the logger using the current default handler
// for its output.
func NewLog(ctx ...interface{}) log15.Logger {
	l := log15.New(ctx...)
	l.SetHandler(defaultHandler)
	return l
}

// Errorf will write a formatted Error to the default log.
func (l *log) Errorf(format string, args ...interface{}) {
	l.Error(fmt.Sprintf(format, args...))
}

// Debugf will write a formatted Debug to the default log.
func (l *log) Debugf(format string, args ...interface{}) {
	l.Debug(fmt.Sprintf(format, args...))
}

// Critf will write a formatted Crit to the default log.
func (l *log) Critf(format string, args ...interface{}) {
	l.Crit(fmt.Sprintf(format, args...))
}

// Infof will write a formatted Info to the default log.
func (l *log) Infof(format string, args ...interface{}) {
	l.Info(fmt.Sprintf(format, args...))
}

// Warnf will write a formatted Warn to the default log.
func (l *log) Warnf(format string, args ...interface{}) {
	l.Warn(fmt.Sprintf(format, args...))
}

// Logf is short hand to create a message string using fmt.Sprintf.
func Logf(format string, args ...interface{}) string {
	return fmt.Sprintf(format, args...)
}

// SetDefaultLogHandler sets the handler for the logger. It wraps handlers in a SyncHandler. You
// should not pass in handlers that are already wrapped in a SyncHandler.
func SetDefaultLogHandler(handler log15.Handler) {
	defaultHandler = log15.SyncHandler(handler)
	Log.SetHandler(defaultHandler)
}

// Sets a new log level for the global logging and the default handler.
func SetLogLvl(lvl log15.Lvl) {
	SetDefaultLogHandler(log15.LvlFilterHandler(lvl, stdHandler))
	Log.SetHandler(defaultHandler)
}

// DefaultLogHandler returns the current handler. It can be used to create additional
// logger instances that all use the same handler for output.
func DefaultLogHandler() log15.Handler {
	return defaultHandler
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"koding/newkite/kite"
	"koding/newkite/protocol"
	"time"
)

var port = flag.String("port", "", "port to bind itself")

func main() {
	flag.Parse()

	options := &kite.Options{
		Kitename:    "application",
		Version:     "1",
		Port:        *port,
		Region:      "localhost",
		Environment: "development",
		Username:    "devrim",
	}

	k := kite.New(options)
	go k.Start()

	query := protocol.KontrolQuery{
		Username:    "devrim",
		Environment: "development",
		Name:        "datastore",
	}

	// To demonstrate we can receive notifications matcing to our query.
	onEvent := func(e *protocol.KiteEvent) {
		fmt.Printf("--- kite event: %#v\n", e)
	}

	kites, err := k.Kontrol.GetKites(query, onEvent)
	if err != nil {
		fmt.Println(err)
		return
	}

	if len(kites) == 0 {
		fmt.Println("No datastore kite is available")
		return
	}

	datastore := kites[0]
	fmt.Println(datastore)
	err = datastore.Dial()
	if err != nil {
		fmt.Println("Cannot connect to remote datastore kite")
		return
	}

	set := func(k string, v string) {
		// we cant simply call, right ??
		// response, err := datastore.Call("set", k, v )
		response, err := datastore.Call("set", []string{k, v} )
		if err != nil {
			fmt.Println(err)
			return
		}

		var result int
		err = response.Unmarshal(&result)
		if err != nil {
			fmt.Println(err)
			return
		}

		fmt.Printf("input: %d  rpc result: %d\n", k, result)
	}

	get := func(k string) (error, string) {
		response, err := datastore.Call("get", k )
		if err != nil {
			fmt.Println(err)
			return err, ""
		}

		var result string
		err = response.Unmarshal(&result)
		if err != nil {
			fmt.Println(err)
			return err, ""
		}

		fmt.Printf("input: %d  rpc result: %d\n", k, result)
		return err, result
	}

	for {
		set("foo", "bar")
		_, v := get("foo")
		fmt.Println("get foo >>>", v == "bar")
		time.Sleep(time.Second)
	}
}
<commit_msg>kite: datastore kite: checking available kites is on kontrol now<commit_after>package main

import (
	"flag"
	"fmt"
	"koding/newkite/kite"
	"koding/newkite/protocol"
	"time"
)

var port = flag.String("port", "", "port to bind itself")

func main() {
	flag.Parse()

	options := &kite.Options{
		Kitename:    "application",
		Version:     "1",
		Port:        *port,
		Region:      "localhost",
		Environment: "development",
		Username:    "devrim",
	}

	k := kite.New(options)
	go k.Start()

	query := protocol.KontrolQuery{
		Username:    "devrim",
		Environment: "development",
		Name:        "datastore",
	}

	// To demonstrate we can receive notifications matcing to our query.
	onEvent := func(e *protocol.KiteEvent) {
		fmt.Printf("--- kite event: %#v\n", e)
	}

	kites, err := k.Kontrol.GetKites(query, onEvent)
	if err != nil {
		fmt.Println(err)
		return
	}

	datastore := kites[0]
	fmt.Println(datastore)
	err = datastore.Dial()
	if err != nil {
		fmt.Println("Cannot connect to remote datastore kite")
		return
	}

	set := func(k string, v string) {
		// we cant simply call, right ??
		// response, err := datastore.Call("set", k, v )
		response, err := datastore.Call("set", []string{k, v} )
		if err != nil {
			fmt.Println(err)
			return
		}

		var result int
		err = response.Unmarshal(&result)
		if err != nil {
			fmt.Println(err)
			return
		}

		fmt.Printf("input: %d  rpc result: %d\n", k, result)
	}

	get := func(k string) (error, string) {
		response, err := datastore.Call("get", k )
		if err != nil {
			fmt.Println(err)
			return err, ""
		}

		var result string
		err = response.Unmarshal(&result)
		if err != nil {
			fmt.Println(err)
			return err, ""
		}

		fmt.Printf("input: %d  rpc result: %d\n", k, result)
		return err, result
	}

	for {
		set("foo", "bar")
		_, v := get("foo")
		fmt.Println("get foo >>>", v == "bar")
		time.Sleep(time.Second)
	}
}
<|endoftext|>


<commit_before>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package pci

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"

	"github.com/jaypipes/pcidb"

	"github.com/jaypipes/ghw/pkg/context"
	"github.com/jaypipes/ghw/pkg/marshal"
	"github.com/jaypipes/ghw/pkg/option"
	"github.com/jaypipes/ghw/pkg/util"
)

var (
	regexAddress *regexp.Regexp = regexp.MustCompile(
		`^(([0-9a-f]{0,4}):)?([0-9a-f]{2}):([0-9a-f]{2})\.([0-9a-f]{1})$`,
	)
)

type Device struct {
	// The PCI address of the device
	Address   string         `json:"address"`
	Vendor    *pcidb.Vendor  `json:"vendor"`
	Product   *pcidb.Product `json:"product"`
	Subsystem *pcidb.Product `json:"subsystem"`
	// optional subvendor/sub-device information
	Class *pcidb.Class `json:"class"`
	// optional sub-class for the device
	Subclass *pcidb.Subclass `json:"subclass"`
	// optional programming interface
	ProgrammingInterface *pcidb.ProgrammingInterface `json:"programming_interface"`
}

type devIdent struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type devMarshallable struct {
	Address   string   `json:"address"`
	Vendor    devIdent `json:"vendor"`
	Product   devIdent `json:"product"`
	Subsystem devIdent `json:"subsystem"`
	Class     devIdent `json:"class""`
	Subclass  devIdent `json:"subclass"`
	Interface devIdent `json:"programming_interface"`
}

// NOTE(jaypipes) Device has a custom JSON marshaller because we don't want
// to serialize the entire PCIDB information for the Vendor (which includes all
// of the vendor's products, etc). Instead, we simply serialize the ID and
// human-readable name of the vendor, product, class, etc.
func (d *Device) MarshalJSON() ([]byte, error) {
	dm := devMarshallable{
		Address: d.Address,
		Vendor: devIdent{
			ID:   d.Vendor.ID,
			Name: d.Vendor.Name,
		},
		Product: devIdent{
			ID:   d.Product.ID,
			Name: d.Product.Name,
		},
		Subsystem: devIdent{
			ID:   d.Subsystem.ID,
			Name: d.Subsystem.Name,
		},
		Class: devIdent{
			ID:   d.Class.ID,
			Name: d.Class.Name,
		},
		Subclass: devIdent{
			ID:   d.Subclass.ID,
			Name: d.Subclass.Name,
		},
		Interface: devIdent{
			ID:   d.ProgrammingInterface.ID,
			Name: d.ProgrammingInterface.Name,
		},
	}
	return json.Marshal(dm)
}

func (d *Device) String() string {
	vendorName := util.UNKNOWN
	if d.Vendor != nil {
		vendorName = d.Vendor.Name
	}
	productName := util.UNKNOWN
	if d.Product != nil {
		productName = d.Product.Name
	}
	className := util.UNKNOWN
	if d.Class != nil {
		className = d.Class.Name
	}
	return fmt.Sprintf(
		"%s -> class: '%s' vendor: '%s' product: '%s'",
		d.Address,
		className,
		vendorName,
		productName,
	)
}

type Info struct {
	ctx *context.Context
	// All PCI devices on the host system
	Devices []*Device
	// hash of class ID -> class information
	// DEPRECATED. Will be removed in v1.0. Please use
	// github.com/jaypipes/pcidb to explore PCIDB information
	Classes map[string]*pcidb.Class `json:"-"`
	// hash of vendor ID -> vendor information
	// DEPRECATED. Will be removed in v1.0. Please use
	// github.com/jaypipes/pcidb to explore PCIDB information
	Vendors map[string]*pcidb.Vendor `json:"-"`
	// hash of vendor ID + product/device ID -> product information
	// DEPRECATED. Will be removed in v1.0. Please use
	// github.com/jaypipes/pcidb to explore PCIDB information
	Products map[string]*pcidb.Product `json:"-"`
}

func (i *Info) String() string {
	return fmt.Sprintf("PCI (%d devices)", len(i.Devices))
}

type Address struct {
	Domain   string
	Bus      string
	Slot     string
	Function string
}

// Given a string address, returns a complete Address struct, filled in with
// domain, bus, slot and function components. The address string may either
// be in $BUS:$SLOT.$FUNCTION (BSF) format or it can be a full PCI address
// that includes the 4-digit $DOMAIN information as well:
// $DOMAIN:$BUS:$SLOT.$FUNCTION.
//
// Returns "" if the address string wasn't a valid PCI address.
func AddressFromString(address string) *Address {
	addrLowered := strings.ToLower(address)
	matches := regexAddress.FindStringSubmatch(addrLowered)
	if len(matches) == 6 {
		dom := "0000"
		if matches[1] != "" {
			dom = matches[2]
		}
		return &Address{
			Domain:   dom,
			Bus:      matches[3],
			Slot:     matches[4],
			Function: matches[5],
		}
	}
	return nil
}

// New returns a pointer to an Info struct that contains information about the
// PCI devices on the host system
func New(opts ...*option.Option) (*Info, error) {
	ctx := context.New(opts...)
	info := &Info{ctx: ctx}
	if err := ctx.Do(info.load); err != nil {
		return nil, err
	}
	return info, nil
}

// simple private struct used to encapsulate PCI information in a top-level
// "pci" YAML/JSON map/object key
type pciPrinter struct {
	Info *Info `json:"pci"`
}

// YAMLString returns a string with the PCI information formatted as YAML
// under a top-level "pci:" key
func (i *Info) YAMLString() string {
	return marshal.SafeYAML(pciPrinter{i})
}

// JSONString returns a string with the PCI information formatted as JSON
// under a top-level "pci:" key
func (i *Info) JSONString(indent bool) string {
	return marshal.SafeJSON(pciPrinter{i}, indent)
}
<commit_msg>pci: fix typo in struct declaration<commit_after>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package pci

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"

	"github.com/jaypipes/pcidb"

	"github.com/jaypipes/ghw/pkg/context"
	"github.com/jaypipes/ghw/pkg/marshal"
	"github.com/jaypipes/ghw/pkg/option"
	"github.com/jaypipes/ghw/pkg/util"
)

var (
	regexAddress *regexp.Regexp = regexp.MustCompile(
		`^(([0-9a-f]{0,4}):)?([0-9a-f]{2}):([0-9a-f]{2})\.([0-9a-f]{1})$`,
	)
)

type Device struct {
	// The PCI address of the device
	Address   string         `json:"address"`
	Vendor    *pcidb.Vendor  `json:"vendor"`
	Product   *pcidb.Product `json:"product"`
	Subsystem *pcidb.Product `json:"subsystem"`
	// optional subvendor/sub-device information
	Class *pcidb.Class `json:"class"`
	// optional sub-class for the device
	Subclass *pcidb.Subclass `json:"subclass"`
	// optional programming interface
	ProgrammingInterface *pcidb.ProgrammingInterface `json:"programming_interface"`
}

type devIdent struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type devMarshallable struct {
	Address   string   `json:"address"`
	Vendor    devIdent `json:"vendor"`
	Product   devIdent `json:"product"`
	Subsystem devIdent `json:"subsystem"`
	Class     devIdent `json:"class"`
	Subclass  devIdent `json:"subclass"`
	Interface devIdent `json:"programming_interface"`
}

// NOTE(jaypipes) Device has a custom JSON marshaller because we don't want
// to serialize the entire PCIDB information for the Vendor (which includes all
// of the vendor's products, etc). Instead, we simply serialize the ID and
// human-readable name of the vendor, product, class, etc.
func (d *Device) MarshalJSON() ([]byte, error) {
	dm := devMarshallable{
		Address: d.Address,
		Vendor: devIdent{
			ID:   d.Vendor.ID,
			Name: d.Vendor.Name,
		},
		Product: devIdent{
			ID:   d.Product.ID,
			Name: d.Product.Name,
		},
		Subsystem: devIdent{
			ID:   d.Subsystem.ID,
			Name: d.Subsystem.Name,
		},
		Class: devIdent{
			ID:   d.Class.ID,
			Name: d.Class.Name,
		},
		Subclass: devIdent{
			ID:   d.Subclass.ID,
			Name: d.Subclass.Name,
		},
		Interface: devIdent{
			ID:   d.ProgrammingInterface.ID,
			Name: d.ProgrammingInterface.Name,
		},
	}
	return json.Marshal(dm)
}

func (d *Device) String() string {
	vendorName := util.UNKNOWN
	if d.Vendor != nil {
		vendorName = d.Vendor.Name
	}
	productName := util.UNKNOWN
	if d.Product != nil {
		productName = d.Product.Name
	}
	className := util.UNKNOWN
	if d.Class != nil {
		className = d.Class.Name
	}
	return fmt.Sprintf(
		"%s -> class: '%s' vendor: '%s' product: '%s'",
		d.Address,
		className,
		vendorName,
		productName,
	)
}

type Info struct {
	ctx *context.Context
	// All PCI devices on the host system
	Devices []*Device
	// hash of class ID -> class information
	// DEPRECATED. Will be removed in v1.0. Please use
	// github.com/jaypipes/pcidb to explore PCIDB information
	Classes map[string]*pcidb.Class `json:"-"`
	// hash of vendor ID -> vendor information
	// DEPRECATED. Will be removed in v1.0. Please use
	// github.com/jaypipes/pcidb to explore PCIDB information
	Vendors map[string]*pcidb.Vendor `json:"-"`
	// hash of vendor ID + product/device ID -> product information
	// DEPRECATED. Will be removed in v1.0. Please use
	// github.com/jaypipes/pcidb to explore PCIDB information
	Products map[string]*pcidb.Product `json:"-"`
}

func (i *Info) String() string {
	return fmt.Sprintf("PCI (%d devices)", len(i.Devices))
}

type Address struct {
	Domain   string
	Bus      string
	Slot     string
	Function string
}

// Given a string address, returns a complete Address struct, filled in with
// domain, bus, slot and function components. The address string may either
// be in $BUS:$SLOT.$FUNCTION (BSF) format or it can be a full PCI address
// that includes the 4-digit $DOMAIN information as well:
// $DOMAIN:$BUS:$SLOT.$FUNCTION.
//
// Returns "" if the address string wasn't a valid PCI address.
func AddressFromString(address string) *Address {
	addrLowered := strings.ToLower(address)
	matches := regexAddress.FindStringSubmatch(addrLowered)
	if len(matches) == 6 {
		dom := "0000"
		if matches[1] != "" {
			dom = matches[2]
		}
		return &Address{
			Domain:   dom,
			Bus:      matches[3],
			Slot:     matches[4],
			Function: matches[5],
		}
	}
	return nil
}

// New returns a pointer to an Info struct that contains information about the
// PCI devices on the host system
func New(opts ...*option.Option) (*Info, error) {
	ctx := context.New(opts...)
	info := &Info{ctx: ctx}
	if err := ctx.Do(info.load); err != nil {
		return nil, err
	}
	return info, nil
}

// simple private struct used to encapsulate PCI information in a top-level
// "pci" YAML/JSON map/object key
type pciPrinter struct {
	Info *Info `json:"pci"`
}

// YAMLString returns a string with the PCI information formatted as YAML
// under a top-level "pci:" key
func (i *Info) YAMLString() string {
	return marshal.SafeYAML(pciPrinter{i})
}

// JSONString returns a string with the PCI information formatted as JSON
// under a top-level "pci:" key
func (i *Info) JSONString(indent bool) string {
	return marshal.SafeJSON(pciPrinter{i}, indent)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	. "github.com/logrusorgru/aurora"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

var infile string
var subfile string
var toplevel string

var jasonfile string
var cmdtemplate string
var captioned bool
var completed string

// Variant struct for HLS variants
type Variant struct {
	Name      string `json:"name"`
	Aspect    string `json:"aspect"`
	Rate      string `json:"framerate"`
	Vbr       string `json:"vbitrate"`
	Abr       string `json:"abitrate"`
	Bandwidth string
}

// Create variant's destination directory
func (v *Variant) mkDest() string {
	dest := fmt.Sprintf("%s/%s", toplevel, v.Name)
	os.MkdirAll(dest, 0755)
	return dest
}

// This Variant method assembles the ffmpeg command
func (v *Variant) mkCmd(cmdtemplate string) string {
	data, err := ioutil.ReadFile(cmdtemplate)
	chk(err, "Error reading template file")
	inputs := infile
	if captioned {
		inputs = mkCaptionInputs(infile)
	}
	if hasSideCar() {
		inputs = mkSubInputs(infile, subfile)
	}
	r := strings.NewReplacer("INFILE", inputs, "ASPECT", v.Aspect,
		"VBITRATE", v.Vbr, "FRAMERATE", v.Rate, "ABITRATE", v.Abr,
		"TOPLEVEL", toplevel, "NAME", v.Name, "\n", " ")
	cmd := fmt.Sprintf("%s\n", r.Replace(string(data)))
	//fmt.Println(cmd)
	return cmd
}

// Read actual bitrate from first segment to set bandwidth in master.m3u8
func (v *Variant) readRate() {
	cmd := fmt.Sprintf("ffprobe -i %s/%s/index0.ts", toplevel, v.Name)
	data := chkExec(cmd)
	two := strings.Split(data, "bitrate: ")[1]
	rate := strings.Split(two, " kb/s")[0]
	v.Bandwidth = fmt.Sprintf("%v000", rate)
}

// Start transcoding the variant
func (v *Variant) start() {
	v.mkDest()
	fmt.Printf("* Variants: %s %s \r", Green(completed), v.Aspect)
	completed += fmt.Sprintf("%s ", v.Aspect)
	cmd := v.mkCmd(cmdtemplate)
	chkExec(cmd)
	v.readRate()
	if hasCapsOrSubs() {
		srcdir := fmt.Sprintf("%s/%s", toplevel, v.Name)
		mvCaptions(srcdir)
		captioned = false
		subfile = ""
	}
	fmt.Printf("* Variants: %s  \r", Green(completed))
}

// #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7483000,RESOLUTION=1920:1080,
// hd1920/index.m3u8
func (v *Variant) mkStanza() string {
	stanza := fmt.Sprintf("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=%v,RESOLUTION=%v", v.Bandwidth, v.Aspect)
	if hasCapsOrSubs() {
		stanza = fmt.Sprintf("%s,SUBTITLES=\"webvtt\"", stanza)
	}
	return stanza
}

func hasSideCar() bool {
	if subfile != "" {
		return true
	}
	return false
}
func hasCapsOrSubs() bool {
	if (captioned) || hasSideCar() {
		return true
	}
	return false
}

func chkExec(cmd string) string {
	// Executes external commands and checks for runtime errors
	parts := strings.Fields(cmd)
	data, err := exec.Command(parts[0], parts[1:]...).CombinedOutput()
	chk(err, fmt.Sprintf("Error running \n %s \n %v", cmd, string(data)))
	return string(data)
}

// probes for Closed Captions in video file.
func chkCaptions(mediafile string) {
	captioned = false
	cmd := fmt.Sprintf("ffprobe -i %s", mediafile)
	data := chkExec(cmd)
	if strings.Contains(data, "Captions") {
		captioned = true
	}
}

// Captions are segmented along with the first variant and then moved to toplevel/subs
func mvCaptions(srcdir string) {
	destdir := fmt.Sprintf("%s/subs", toplevel)
	os.MkdirAll(destdir, 0755)
	files, err := ioutil.ReadDir(srcdir)
	chk(err, "Error moving Captions")
	for _, f := range files {
		if strings.Contains(f.Name(), "vtt") {
			os.Rename(fmt.Sprintf("%s/%s", srcdir, f.Name()), fmt.Sprintf("%s/%s", destdir, f.Name()))
		}
	}
}

// return a string for file inputs in the ffmpeg command to extract 608 captions for vtt subtitles
func mkCaptionInputs(infile string) string {
	return fmt.Sprintf("%s -f lavfi -fix_sub_duration -i movie=%s[out0+subcc] ", infile, infile)
}

//return a string for file inputs in the ffmpeg command to use an external subtitle file for vtt subtitles
func mkSubInputs(infile string, subfile string) string {
	return fmt.Sprintf("%s -fix_sub_duration -i %s ", infile, subfile)
}

// return a subtitle stanza for use in the  master.m3u8
func mkSubStanza() string {
	return "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"webvtt\",NAME=\"English\",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE=\"en\",URI=\"subs/vtt_index.m3u8\"\n"
}

// Read json file for variants
func dataToVariants() []Variant {
	var variants []Variant
	data, err := ioutil.ReadFile(jasonfile)
	chk(err, "Error reading JSON file")
	json.Unmarshal(data, &variants)
	return variants
}

// Set the toplevel dir for variants by splitting video file name at the "."
func mkTopLevel() {
	if toplevel == "" {
		toplevel = strings.Split(infile, `.`)[0]
	}
	os.MkdirAll(toplevel, 0755)
}

// Generic catchall error checking
func chk(err error, mesg string) {
	if err != nil {
		fmt.Printf("%s\n", mesg)
		//panic(err)
	}
}

// Make all variants and write master.m3u8
func mkAll(variants []Variant) {
	mkTopLevel()
	if !(hasSideCar()) {
		chkCaptions(infile)
	}
	var m3u8Master = fmt.Sprintf("%s/master.m3u8", toplevel)
	fp, err := os.Create(m3u8Master)
	chk(err, "in mkAll")
	defer fp.Close()
	w := bufio.NewWriter(fp)
	w.WriteString("#EXTM3U\n")
	if hasCapsOrSubs() {
		w.WriteString(mkSubStanza())
	}
	fmt.Println("\n* Video file:", Cyan(infile), "\n* Toplevel:", Cyan(toplevel), "\n* Subtitle file:", Cyan(subfile), "\n* Captions:", Cyan(captioned))

	for _, v := range variants {
		v.start()
		w.WriteString(fmt.Sprintf("%s\n", v.mkStanza()))
		w.WriteString(fmt.Sprintf("%s/index.m3u8\n", v.Name))
	}
	fmt.Println("\n\n")
	w.Flush()
}

func main() {
	flag.StringVar(&infile, "i", "", "Video file to segment (required)")
	flag.StringVar(&subfile, "s", "", "subtitle file to segment (optional)")
	flag.StringVar(&toplevel, "d", "", "override top level directory for hls files (optional)")
	flag.StringVar(&jasonfile, "j", `./hls.json`, "JSON file of variants (optional)")
	flag.StringVar(&cmdtemplate, "t", `./cmd.template`, "command template file (optional)")

	flag.Parse()
	variants := dataToVariants()

	if infile != "" {
		mkAll(variants)
	} else {
		flag.PrintDefaults()
	}
}
<commit_msg>subtitle and caption func cleaning<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	. "github.com/logrusorgru/aurora"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

var infile string
var subfile string
var addsubs bool
var toplevel string
var webvtt bool
var jasonfile string
var cmdtemplate string
var completed string
var batch string

// Variant struct for HLS variants
type Variant struct {
	Name      string `json:"name"`
	Aspect    string `json:"aspect"`
	Rate      string `json:"framerate"`
	Vbr       string `json:"vbitrate"`
	Abr       string `json:"abitrate"`
	Bandwidth string
}

// Create variant's destination directory
func (v *Variant) mkDest() string {
	dest := fmt.Sprintf("%s/%s", toplevel, v.Name)
	os.MkdirAll(dest, 0755)
	return dest
}

func (v *Variant) mkInputs() string {
	inputs := fmt.Sprintf(" -i %s", infile)
	if addsubs {
		inputs = fmt.Sprintf(" -i %s -i %s/%s  ", infile, toplevel, subfile)
	}
	return inputs
}

// This Variant method assembles the ffmpeg command
func (v *Variant) mkCmd(cmdtemplate string) string {
	data, err := ioutil.ReadFile(cmdtemplate)
	chk(err, "Error reading template file")
	inputs := v.mkInputs()
	r := strings.NewReplacer("INFILE", inputs, "ASPECT", v.Aspect,
		"VBITRATE", v.Vbr, "FRAMERATE", v.Rate, "ABITRATE", v.Abr,
		"TOPLEVEL", toplevel, "NAME", v.Name, "\n", " ")
	cmd := fmt.Sprintf("%s\n", r.Replace(string(data)))
	//fmt.Println(cmd)
	return cmd
}

// Read actual bitrate from first segment to set bandwidth in master.m3u8
func (v *Variant) readRate() {
	cmd := fmt.Sprintf("ffprobe -i %s/%s/index0.ts", toplevel, v.Name)
	data := chkExec(cmd)
	two := strings.Split(data, "bitrate: ")[1]
	rate := strings.Split(two, " kb/s")[0]
	v.Bandwidth = fmt.Sprintf("%v000", rate)
}

// Start transcoding the variant
func (v *Variant) start() {
	v.mkDest()
	fmt.Printf("* Variants: %s %s \r", Cyan(completed), v.Aspect)
	completed += fmt.Sprintf("%s ", v.Aspect)
	cmd := v.mkCmd(cmdtemplate)
	chkExec(cmd)
	v.readRate()
	fmt.Printf("* Variants: %s  \r", Cyan(completed))
}

// #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7483000,RESOLUTION=1920:1080,
// hd1920/index.m3u8
func (v *Variant) mkStanza() string {
	stanza := fmt.Sprintf("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=%v,RESOLUTION=%v", v.Bandwidth, v.Aspect)
	if addsubs {
		stanza = fmt.Sprintf("%s,SUBTITLES=\"webvtt\"", stanza)
	}
	return stanza
}

func chkExec(cmd string) string {
	// Executes external commands and checks for runtime errors
	parts := strings.Fields(cmd)
	data, err := exec.Command(parts[0], parts[1:]...).CombinedOutput()
	chk(err, fmt.Sprintf("Error running \n %s \n %v", cmd, string(data)))
	return string(data)
}

// probes for Closed Captions in video file.
func hasCaptions() bool {
	cmd := fmt.Sprintf("ffprobe -i %s", infile)
	data := chkExec(cmd)
	if strings.Contains(data, "Captions") {
		return true
	}
	return false
}

// Captions are segmented along with the first variant and then moved to toplevel/subs
func mvCaptions(vardir string) {
	srcdir := fmt.Sprintf("%s/%s", toplevel, vardir)
	destdir := fmt.Sprintf("%s/subs", toplevel)
	os.MkdirAll(destdir, 0755)
	files, err := ioutil.ReadDir(srcdir)
	chk(err, "Error moving Captions")
	for _, f := range files {
		if strings.Contains(f.Name(), "vtt") {
			os.Rename(fmt.Sprintf("%s/%s", srcdir, f.Name()), fmt.Sprintf("%s/%s", destdir, f.Name()))
		}
	}
}

// return a subtitle stanza for use in the  master.m3u8
func mkSubStanza() string {
	return "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"webvtt\",NAME=\"English\",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE=\"en\",URI=\"subs/vtt_index.m3u8\"\n"
}

// Read json file for variants
func dataToVariants() []Variant {
	var variants []Variant
	data, err := ioutil.ReadFile(jasonfile)
	chk(err, "Error reading JSON file")
	json.Unmarshal(data, &variants)
	return variants
}

// Set the toplevel dir for variants by splitting video file name at the "."
func mkTopLevel() {
	if toplevel == "" {
		toplevel = strings.Split(infile, `.`)[0]
	}
	os.MkdirAll(toplevel, 0755)
}

func extractCaptions() string {
	fmt.Println("Extracting captions")
	assfile := fmt.Sprintf("%s.ass", toplevel)
	cmd := fmt.Sprintf("ffmpeg -y -f lavfi -fix_sub_duration -i movie=%s[out0+subcc] %s/%s", infile, toplevel, assfile)
	chkExec(cmd)
	return assfile
}

func mkSubfile() {
	if webvtt {
		return
	} else {
		addsubs = false
		if subfile == "" {
			if hasCaptions() {
				subfile = extractCaptions()
			}
		}
		if subfile != "" {
			addsubs = true
		}
	}
}

// Generic catchall error checking
func chk(err error, mesg string) {
	if err != nil {
		fmt.Printf("%s\n", mesg)
		//panic(err)
	}
}

// Make all variants and write master.m3u8
func mkAll(variants []Variant) {
	mkTopLevel()
	mkSubfile()
	var m3u8Master = fmt.Sprintf("%s/master.m3u8", toplevel)
	fp, err := os.Create(m3u8Master)
	chk(err, "in mkAll")
	defer fp.Close()
	w := bufio.NewWriter(fp)
	w.WriteString("#EXTM3U\n")

	fmt.Println("\n* Video file:", Cyan(infile), "\n* Toplevel:", Cyan(toplevel), "\n* Subtitle file:", Cyan(subfile))

	for _, v := range variants {
		v.start()
		if addsubs && !(webvtt) {
			mvCaptions(v.Name)
			w.WriteString(mkSubStanza())
			addsubs = false
			subfile = ""
			webvtt = true
		} else {
			fmt.Println("webvtt already added")
		}
		w.WriteString(fmt.Sprintf("%s\n", v.mkStanza()))
		w.WriteString(fmt.Sprintf("%s/index.m3u8\n", v.Name))
	}
	fmt.Println("\n\n")
	w.Flush()
}

func main() {
	flag.StringVar(&infile, "i", "", "Video file to segment (either -i or -b is required)")
	flag.StringVar(&subfile, "s", "", "subtitle file to segment (optional)")
	flag.StringVar(&toplevel, "d", "", "override top level directory for hls files (optional)")
	flag.StringVar(&jasonfile, "j", `./hls.json`, "JSON file of variants (optional)")
	flag.StringVar(&cmdtemplate, "t", `./cmd.template`, "command template file (optional)")
	flag.StringVar(&batch, "b", "", "batch mode, list multiple input files (either -i or -b is required)")

	flag.Parse()
	fmt.Println(batch)
	variants := dataToVariants()
	webvtt = false
	if batch != "" {
		batch = strings.Replace(batch, " ", ",", -1)
		for _, b := range strings.Split(batch, ",") {
			fmt.Println(b)
			webvtt = false
			infile = b
			completed = ""
			toplevel = ""
			mkTopLevel()
			variants := dataToVariants()
			mkAll(variants)
		}
	} else {
		if infile != "" {
			mkAll(variants)
		} else {
			flag.PrintDefaults()
		}

	}
}
<|endoftext|>


<commit_before>package bitarraygo

import (
	"testing"

	"fmt"
)

func Test_Set_on(t *testing.T) {
	tests := []struct {
		input  uint64
		expect uint64
	}{
		{0, 1},
		{1, 2},
		{2, 4},
		{3, 8},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.Set(j.input, true)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, expected %d, got %d.", j.input, j.expect, actual)
		}
	}
}

func Test_Set_off(t *testing.T) {
	tests := []struct {
		input  uint64
		expect uint64
	}{
		{0, 170},
		{1, 168},
		{2, 170},
		{3, 162},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.FromNumber(170)
		a.Set(j.input, false)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, expected %d, got %d.", j.input, j.expect, actual)
		}
	}
}

func Test_Get(t *testing.T) {
	tests := []struct {
		input  uint64
		expect bool
	}{
		{0, true},
		{1, false},
		{2, true},
		{3, false},
		{4, true},
		{5, true},
		{6, true},
	}

	a := NewBitArray(1)
	a.Set(0, true).
		Set(2, true).
		Set(4, true).
		Set(5, true).
		Set(6, true)

	for _, j := range tests {
		actual := a.Get(j.input)
		if actual != j.expect {
			t.Errorf("For %d, expected %t, got %t.", j.input, j.expect, actual)
		}
	}
}

func Test_Flip(t *testing.T) {
	type input struct {
		number uint64
		index  uint64
	}
	tests := []struct {
		input  input
		expect uint64
	}{
		{input{0, 0}, 1},
		{input{1, 0}, 0},
		{input{2, 0}, 3},
		{input{5, 1}, 7},
		{input{13, 2}, 9},
		{input{255, 7}, 127},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.FromNumber(j.input.number)
		a.Flip(j.input.index)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, %d, expected %d, got %d.",
				j.input.number, j.input.index, j.expect, actual)
		}
	}
}

func Test_FromNumber(t *testing.T) {
	tests := []struct {
		input  uint64
		expect uint64
	}{
		{0, 0},
		{1, 1},
		{37, 37},
		{255, 255},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.FromNumber(j.input)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, expected %d, got %d.", j.input, j.expect, actual)
		}
	}
}
<commit_msg>Remove dead pkg.<commit_after>package bitarraygo

import (
	"testing"
)

func Test_Set_on(t *testing.T) {
	tests := []struct {
		input  uint64
		expect uint64
	}{
		{0, 1},
		{1, 2},
		{2, 4},
		{3, 8},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.Set(j.input, true)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, expected %d, got %d.", j.input, j.expect, actual)
		}
	}
}

func Test_Set_off(t *testing.T) {
	tests := []struct {
		input  uint64
		expect uint64
	}{
		{0, 170},
		{1, 168},
		{2, 170},
		{3, 162},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.FromNumber(170)
		a.Set(j.input, false)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, expected %d, got %d.", j.input, j.expect, actual)
		}
	}
}

func Test_Get(t *testing.T) {
	tests := []struct {
		input  uint64
		expect bool
	}{
		{0, true},
		{1, false},
		{2, true},
		{3, false},
		{4, true},
		{5, true},
		{6, true},
	}

	a := NewBitArray(1)
	a.Set(0, true).
		Set(2, true).
		Set(4, true).
		Set(5, true).
		Set(6, true)

	for _, j := range tests {
		actual := a.Get(j.input)
		if actual != j.expect {
			t.Errorf("For %d, expected %t, got %t.", j.input, j.expect, actual)
		}
	}
}

func Test_Flip(t *testing.T) {
	type input struct {
		number uint64
		index  uint64
	}
	tests := []struct {
		input  input
		expect uint64
	}{
		{input{0, 0}, 1},
		{input{1, 0}, 0},
		{input{2, 0}, 3},
		{input{5, 1}, 7},
		{input{13, 2}, 9},
		{input{255, 7}, 127},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.FromNumber(j.input.number)
		a.Flip(j.input.index)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, %d, expected %d, got %d.",
				j.input.number, j.input.index, j.expect, actual)
		}
	}
}

func Test_FromNumber(t *testing.T) {
	tests := []struct {
		input  uint64
		expect uint64
	}{
		{0, 0},
		{1, 1},
		{37, 37},
		{255, 255},
	}

	for _, j := range tests {
		a := NewBitArray(1)
		a.FromNumber(j.input)
		actual := a.AsNumber()
		if actual != j.expect {
			t.Errorf("For %d, expected %d, got %d.", j.input, j.expect, actual)
		}
	}
}
<|endoftext|>


<commit_before>package slack

import (
	"encoding/json"
	"fmt"
	"log"
	"regexp"
	"strings"
)

const (
	slackEventTypeMessage = "message"

	maxMessageSize = 4000
)

// Processor type processes inbound events from Slack
type Processor struct {
	// Connection to Slack
	con *Connection

	// Slack user information relating to the bot account
	self User

	// a sequence number to uniquely identify sent messages and correlate with acks from Slack
	sequence int

	// map of event handler functions to handle types of Slack event
	eventHandlers map[string]func(*Processor, map[string]interface{})
}

// event type represents an event sent to Slack e.g. messages
type event struct {
	Id      int    `json:"id"`
	Type    string `json:"type"`
	Channel string `json:"channel"`
	Text    string `json:"text"`
}

// send Event to Slack
func (p *Processor) sendEvent(eventType string, channel string, text string) error {
	p.sequence++

	response := &event{Id: p.sequence, Type: eventType, Channel: channel, Text: text}

	responseJson, err := json.Marshal(response)
	if err != nil {
		return err
	}

	p.con.Write(responseJson)

	return nil
}

// Write the message on the specified channel to Slack
func (p *Processor) Write(channel string, text string) error {
	if len(text) <= maxMessageSize {
		return p.sendEvent(slackEventTypeMessage, channel, text)
	}

	for len(text) > 0 {
		if len(text) <= maxMessageSize {
			if err := p.sendEvent(slackEventTypeMessage, channel, text); err != nil {
				return err
			}
			text = ""
		} else {
			// split message at a convenient place
			maxSizeChunk := text[:maxMessageSize]

			var breakIndex int
			if lastLineBreak := strings.LastIndex(maxSizeChunk, "\n"); lastLineBreak > -1 {
				breakIndex = lastLineBreak
			} else if lastWordBreak := strings.LastIndexAny(maxSizeChunk, "\n\t .,/\\-(){}[]|=+*&"); lastWordBreak > -1 {
				breakIndex = lastWordBreak
			} else {
				breakIndex = maxMessageSize
			}

			if err := p.sendEvent(slackEventTypeMessage, channel, text[:breakIndex]); err != nil {
				return err
			}

			if breakIndex != maxMessageSize {
				breakIndex++
			}

			text = text[breakIndex:]
		}
	}

	return nil
}

// Start processing events from Slack
func (p *Processor) Start() {
	for {
		msg := p.con.Read()

		log.Printf("%s", msg)

		var data map[string]interface{}
		err := json.Unmarshal(msg, &data)

		if err != nil {
			fmt.Printf("%T\n%s\n%#v\n", err, err, err)
			switch v := err.(type) {
			case *json.SyntaxError:
				log.Println(string(msg[v.Offset-40 : v.Offset]))
			}
			log.Printf("%s", msg)
			continue
		}

		// if reply_to attribute is present the event is an ack' for a sent message
		_, isReply := data["reply_to"]
		subtype, ok := data["subtype"]
		var isMessageChangedEvent bool

		if ok {
			isMessageChangedEvent = (subtype.(string) == "message_changed" || subtype.(string) == "message_deleted")
		}

		if !isReply && !isMessageChangedEvent {
			handler, ok := p.eventHandlers[data["type"].(string)]

			if ok {
				handler(p, data)
			}
		}
	}
}

// type for callbacks to receive messages from Slack
type messageProcessor func(*Message)

// Starts processing events on the connection from Slack and passes any messages to the hear callback and only
// messages addressed to the bot to the respond callback
func EventProcessor(con *Connection, respond messageProcessor, hear messageProcessor) {
	p := Processor{
		con:  con,
		self: con.config.Self,
		eventHandlers: map[string]func(*Processor, map[string]interface{}){
			slackEventTypeMessage: func(p *Processor, event map[string]interface{}) {
				filterMessage(p, event, respond, hear)
			},
		},
	}

	p.Start()
}

// finds the full name of the Slack user for the specified user ID
func findUser(config Config, user string) (string, bool) {
	var users []User

	users = config.Users

	for i := 0; i < len(users); i++ {
		if users[i].Id == user {
			return users[i].RealName, true
		}
	}

	return "", false
}

// Invoke one of the specified callbacks for the message if appropriate
func filterMessage(p *Processor, data map[string]interface{}, respond messageProcessor, hear messageProcessor) {
	var userFullName string
	var userId string

	user, ok := data["user"]
	if ok {
		userId = user.(string)
		userFullName, _ = findUser(p.con.config, userId)
	}

	// process messages directed at Talbot
	r, _ := regexp.Compile("^(<@" + p.self.Id + ">|@?" + p.self.Name + "):? (.+)")

	text, ok := data["text"]
	if !ok {
		return
	}

	matches := r.FindStringSubmatch(text.(string))

	if len(matches) == 3 {
		if respond != nil {
			m := &Message{eventStream: p, responseStrategy: reply, Text: matches[2], From: userFullName, fromId: userId, channel: data["channel"].(string)}
			respond(m)
		}
	} else if data["channel"].(string)[0] == 'D' {
		if respond != nil {
			// process direct messages
			m := &Message{eventStream: p, responseStrategy: send, Text: text.(string), From: userFullName, fromId: userId, channel: data["channel"].(string)}
			respond(m)
		}
	} else {
		if hear != nil {
			m := &Message{eventStream: p, responseStrategy: send, Text: text.(string), From: userFullName, fromId: userId, channel: data["channel"].(string)}
			hear(m)
		}
	}
}
<commit_msg>removed redundant code<commit_after>package slack

import (
	"encoding/json"
	"fmt"
	"log"
	"regexp"
	"strings"
)

const (
	slackEventTypeMessage = "message"

	maxMessageSize = 4000
)

// Processor type processes inbound events from Slack
type Processor struct {
	// Connection to Slack
	con *Connection

	// Slack user information relating to the bot account
	self User

	// a sequence number to uniquely identify sent messages and correlate with acks from Slack
	sequence int

	// map of event handler functions to handle types of Slack event
	eventHandlers map[string]func(*Processor, map[string]interface{})
}

// event type represents an event sent to Slack e.g. messages
type event struct {
	Id      int    `json:"id"`
	Type    string `json:"type"`
	Channel string `json:"channel"`
	Text    string `json:"text"`
}

// send Event to Slack
func (p *Processor) sendEvent(eventType string, channel string, text string) error {
	p.sequence++

	response := &event{Id: p.sequence, Type: eventType, Channel: channel, Text: text}

	responseJson, err := json.Marshal(response)
	if err != nil {
		return err
	}

	p.con.Write(responseJson)

	return nil
}

// Write the message on the specified channel to Slack
func (p *Processor) Write(channel string, text string) error {
	for len(text) > 0 {
		if len(text) <= maxMessageSize {
			if err := p.sendEvent(slackEventTypeMessage, channel, text); err != nil {
				return err
			}
			text = ""
		} else {
			// split message at a convenient place
			maxSizeChunk := text[:maxMessageSize]

			var breakIndex int
			if lastLineBreak := strings.LastIndex(maxSizeChunk, "\n"); lastLineBreak > -1 {
				breakIndex = lastLineBreak
			} else if lastWordBreak := strings.LastIndexAny(maxSizeChunk, "\n\t .,/\\-(){}[]|=+*&"); lastWordBreak > -1 {
				breakIndex = lastWordBreak
			} else {
				breakIndex = maxMessageSize
			}

			if err := p.sendEvent(slackEventTypeMessage, channel, text[:breakIndex]); err != nil {
				return err
			}

			if breakIndex != maxMessageSize {
				breakIndex++
			}

			text = text[breakIndex:]
		}
	}

	return nil
}

// Start processing events from Slack
func (p *Processor) Start() {
	for {
		msg := p.con.Read()

		log.Printf("%s", msg)

		var data map[string]interface{}
		err := json.Unmarshal(msg, &data)

		if err != nil {
			fmt.Printf("%T\n%s\n%#v\n", err, err, err)
			switch v := err.(type) {
			case *json.SyntaxError:
				log.Println(string(msg[v.Offset-40 : v.Offset]))
			}
			log.Printf("%s", msg)
			continue
		}

		// if reply_to attribute is present the event is an ack' for a sent message
		_, isReply := data["reply_to"]
		subtype, ok := data["subtype"]
		var isMessageChangedEvent bool

		if ok {
			isMessageChangedEvent = (subtype.(string) == "message_changed" || subtype.(string) == "message_deleted")
		}

		if !isReply && !isMessageChangedEvent {
			handler, ok := p.eventHandlers[data["type"].(string)]

			if ok {
				handler(p, data)
			}
		}
	}
}

// type for callbacks to receive messages from Slack
type messageProcessor func(*Message)

// Starts processing events on the connection from Slack and passes any messages to the hear callback and only
// messages addressed to the bot to the respond callback
func EventProcessor(con *Connection, respond messageProcessor, hear messageProcessor) {
	p := Processor{
		con:  con,
		self: con.config.Self,
		eventHandlers: map[string]func(*Processor, map[string]interface{}){
			slackEventTypeMessage: func(p *Processor, event map[string]interface{}) {
				filterMessage(p, event, respond, hear)
			},
		},
	}

	p.Start()
}

// finds the full name of the Slack user for the specified user ID
func findUser(config Config, user string) (string, bool) {
	var users []User

	users = config.Users

	for i := 0; i < len(users); i++ {
		if users[i].Id == user {
			return users[i].RealName, true
		}
	}

	return "", false
}

// Invoke one of the specified callbacks for the message if appropriate
func filterMessage(p *Processor, data map[string]interface{}, respond messageProcessor, hear messageProcessor) {
	var userFullName string
	var userId string

	user, ok := data["user"]
	if ok {
		userId = user.(string)
		userFullName, _ = findUser(p.con.config, userId)
	}

	// process messages directed at Talbot
	r, _ := regexp.Compile("^(<@" + p.self.Id + ">|@?" + p.self.Name + "):? (.+)")

	text, ok := data["text"]
	if !ok {
		return
	}

	matches := r.FindStringSubmatch(text.(string))

	if len(matches) == 3 {
		if respond != nil {
			m := &Message{eventStream: p, responseStrategy: reply, Text: matches[2], From: userFullName, fromId: userId, channel: data["channel"].(string)}
			respond(m)
		}
	} else if data["channel"].(string)[0] == 'D' {
		if respond != nil {
			// process direct messages
			m := &Message{eventStream: p, responseStrategy: send, Text: text.(string), From: userFullName, fromId: userId, channel: data["channel"].(string)}
			respond(m)
		}
	} else {
		if hear != nil {
			m := &Message{eventStream: p, responseStrategy: send, Text: text.(string), From: userFullName, fromId: userId, channel: data["channel"].(string)}
			hear(m)
		}
	}
}
<|endoftext|>


<commit_before>// Package booking provides the use-case of booking a cargo. Used by views
// facing an administrator.
package booking

import (
	"errors"
	"time"

	"github.com/marcusolsson/goddd/cargo"
	"github.com/marcusolsson/goddd/location"
	"github.com/marcusolsson/goddd/routing"
)

// Service is the interface that provides booking methods.
type Service interface {
	// BookNewCargo registers a new cargo in the tracking system, not yet
	// routed.
	BookNewCargo(origin location.UNLocode, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error)

	// RequestPossibleRoutesForCargo requests a list of itineraries describing
	// possible routes for this cargo.
	RequestPossibleRoutesForCargo(trackingID cargo.TrackingID) []cargo.Itinerary

	// AssignCargoToRoute assigns a cargo to the route specified by the
	// itinerary.
	AssignCargoToRoute(trackingID cargo.TrackingID, itinerary cargo.Itinerary) error

	// ChangeDestination changes the destination of a cargo.
	ChangeDestination(trackingID cargo.TrackingID, unLocode location.UNLocode) error

	// Cargos returns a list of all cargos that have been booked.
	Cargos() []Cargo

	// Locations returns a list of registered locations.
	Locations() []Location
}

type service struct {
	cargoRepository         cargo.Repository
	locationRepository      location.Repository
	routingService          routing.Service
	handlingEventRepository cargo.HandlingEventRepository
}

func (s *service) AssignCargoToRoute(trackingID cargo.TrackingID, itinerary cargo.Itinerary) error {
	var err error

	c, err := s.cargoRepository.Find(trackingID)
	if err != nil {
		return err
	}

	c.AssignToRoute(itinerary)

	if err := s.cargoRepository.Store(c); err != nil {
		return err
	}

	return nil
}

func (s *service) BookNewCargo(origin, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) {
	trackingID := cargo.NextTrackingID()
	routeSpecification := cargo.RouteSpecification{
		Origin:          origin,
		Destination:     destination,
		ArrivalDeadline: arrivalDeadline,
	}

	c := cargo.New(trackingID, routeSpecification)

	s.cargoRepository.Store(*c)

	return c.TrackingID, nil
}

func (s *service) ChangeDestination(trackingID cargo.TrackingID, destination location.UNLocode) error {
	c, err := s.cargoRepository.Find(trackingID)
	if err != nil {
		return errors.New("Could not find cargo.")
	}

	l, err := s.locationRepository.Find(destination)
	if err != nil {
		return err
	}

	routeSpecification := cargo.RouteSpecification{
		Origin:          c.Origin,
		Destination:     l.UNLocode,
		ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
	}

	c.SpecifyNewRoute(routeSpecification)

	if err := s.cargoRepository.Store(c); err != nil {
		return err
	}

	return nil
}

func (s *service) RequestPossibleRoutesForCargo(trackingID cargo.TrackingID) []cargo.Itinerary {
	c, err := s.cargoRepository.Find(trackingID)
	if err != nil {
		return []cargo.Itinerary{}
	}

	return s.routingService.FetchRoutesForSpecification(c.RouteSpecification)
}

func (s *service) Cargos() []Cargo {
	cargos := s.cargoRepository.FindAll()
	var result []Cargo
	for _, c := range cargos {
		result = append(result, assemble(c, s.handlingEventRepository))
	}
	return result
}

func (s *service) Locations() []Location {
	var result []Location
	for _, v := range s.locationRepository.FindAll() {
		result = append(result, Location{
			UNLocode: string(v.UNLocode),
			Name:     v.Name,
		})
	}
	return result
}

// NewService creates a booking service with necessary dependencies.
func NewService(cr cargo.Repository, lr location.Repository, her cargo.HandlingEventRepository, rs routing.Service) Service {
	return &service{
		cargoRepository:         cr,
		locationRepository:      lr,
		handlingEventRepository: her,
		routingService:          rs,
	}
}

type Location struct {
	UNLocode string `json:"locode"`
	Name     string `json:"name"`
}

// Cargo is a read model for booking views.
type Cargo struct {
	ArrivalDeadline time.Time `json:"arrivalDeadline"`
	Destination     string    `json:"destination"`
	Legs            []Leg     `json:"legs,omitempty"`
	Misrouted       bool      `json:"misrouted"`
	Origin          string    `json:"origin"`
	Routed          bool      `json:"routed"`
	TrackingID      string    `json:"trackingId"`
}

// Leg is a read model for booking views.
type Leg struct {
	VoyageNumber string    `json:"voyageNumber"`
	From         string    `json:"from"`
	To           string    `json:"to"`
	LoadTime     time.Time `json:"loadTime"`
	UnloadTime   time.Time `json:"unloadTime"`
}

func assemble(c cargo.Cargo, her cargo.HandlingEventRepository) Cargo {
	return Cargo{
		TrackingID:      string(c.TrackingID),
		Origin:          string(c.Origin),
		Destination:     string(c.RouteSpecification.Destination),
		Misrouted:       c.Delivery.RoutingStatus == cargo.Misrouted,
		Routed:          !c.Itinerary.IsEmpty(),
		ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
		Legs:            assembleLegs(c),
	}
}

func assembleLegs(c cargo.Cargo) []Leg {
	var legs []Leg
	for _, l := range c.Itinerary.Legs {
		legs = append(legs, Leg{
			VoyageNumber: string(l.VoyageNumber),
			From:         string(l.LoadLocation),
			To:           string(l.UnloadLocation),
			LoadTime:     l.LoadTime,
			UnloadTime:   l.UnloadTime,
		})
	}
	return legs
}
<commit_msg>Fix linter errors<commit_after>// Package booking provides the use-case of booking a cargo. Used by views
// facing an administrator.
package booking

import (
	"errors"
	"time"

	"github.com/marcusolsson/goddd/cargo"
	"github.com/marcusolsson/goddd/location"
	"github.com/marcusolsson/goddd/routing"
)

// Service is the interface that provides booking methods.
type Service interface {
	// BookNewCargo registers a new cargo in the tracking system, not yet
	// routed.
	BookNewCargo(origin location.UNLocode, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error)

	// RequestPossibleRoutesForCargo requests a list of itineraries describing
	// possible routes for this cargo.
	RequestPossibleRoutesForCargo(trackingID cargo.TrackingID) []cargo.Itinerary

	// AssignCargoToRoute assigns a cargo to the route specified by the
	// itinerary.
	AssignCargoToRoute(trackingID cargo.TrackingID, itinerary cargo.Itinerary) error

	// ChangeDestination changes the destination of a cargo.
	ChangeDestination(trackingID cargo.TrackingID, unLocode location.UNLocode) error

	// Cargos returns a list of all cargos that have been booked.
	Cargos() []Cargo

	// Locations returns a list of registered locations.
	Locations() []Location
}

type service struct {
	cargoRepository         cargo.Repository
	locationRepository      location.Repository
	routingService          routing.Service
	handlingEventRepository cargo.HandlingEventRepository
}

func (s *service) AssignCargoToRoute(trackingID cargo.TrackingID, itinerary cargo.Itinerary) error {
	var err error

	c, err := s.cargoRepository.Find(trackingID)
	if err != nil {
		return err
	}

	c.AssignToRoute(itinerary)

	if err := s.cargoRepository.Store(c); err != nil {
		return err
	}

	return nil
}

func (s *service) BookNewCargo(origin, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) {
	trackingID := cargo.NextTrackingID()
	routeSpecification := cargo.RouteSpecification{
		Origin:          origin,
		Destination:     destination,
		ArrivalDeadline: arrivalDeadline,
	}

	c := cargo.New(trackingID, routeSpecification)

	s.cargoRepository.Store(*c)

	return c.TrackingID, nil
}

func (s *service) ChangeDestination(trackingID cargo.TrackingID, destination location.UNLocode) error {
	c, err := s.cargoRepository.Find(trackingID)
	if err != nil {
		return errors.New("Could not find cargo.")
	}

	l, err := s.locationRepository.Find(destination)
	if err != nil {
		return err
	}

	routeSpecification := cargo.RouteSpecification{
		Origin:          c.Origin,
		Destination:     l.UNLocode,
		ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
	}

	c.SpecifyNewRoute(routeSpecification)

	if err := s.cargoRepository.Store(c); err != nil {
		return err
	}

	return nil
}

func (s *service) RequestPossibleRoutesForCargo(trackingID cargo.TrackingID) []cargo.Itinerary {
	c, err := s.cargoRepository.Find(trackingID)
	if err != nil {
		return []cargo.Itinerary{}
	}

	return s.routingService.FetchRoutesForSpecification(c.RouteSpecification)
}

func (s *service) Cargos() []Cargo {
	cargos := s.cargoRepository.FindAll()
	var result []Cargo
	for _, c := range cargos {
		result = append(result, assemble(c, s.handlingEventRepository))
	}
	return result
}

func (s *service) Locations() []Location {
	var result []Location
	for _, v := range s.locationRepository.FindAll() {
		result = append(result, Location{
			UNLocode: string(v.UNLocode),
			Name:     v.Name,
		})
	}
	return result
}

// NewService creates a booking service with necessary dependencies.
func NewService(cr cargo.Repository, lr location.Repository, her cargo.HandlingEventRepository, rs routing.Service) Service {
	return &service{
		cargoRepository:         cr,
		locationRepository:      lr,
		handlingEventRepository: her,
		routingService:          rs,
	}
}

// Location is a read model for booking views.
type Location struct {
	UNLocode string `json:"locode"`
	Name     string `json:"name"`
}

// Cargo is a read model for booking views.
type Cargo struct {
	ArrivalDeadline time.Time `json:"arrivalDeadline"`
	Destination     string    `json:"destination"`
	Legs            []Leg     `json:"legs,omitempty"`
	Misrouted       bool      `json:"misrouted"`
	Origin          string    `json:"origin"`
	Routed          bool      `json:"routed"`
	TrackingID      string    `json:"trackingId"`
}

// Leg is a read model for booking views.
type Leg struct {
	VoyageNumber string    `json:"voyageNumber"`
	From         string    `json:"from"`
	To           string    `json:"to"`
	LoadTime     time.Time `json:"loadTime"`
	UnloadTime   time.Time `json:"unloadTime"`
}

func assemble(c cargo.Cargo, her cargo.HandlingEventRepository) Cargo {
	return Cargo{
		TrackingID:      string(c.TrackingID),
		Origin:          string(c.Origin),
		Destination:     string(c.RouteSpecification.Destination),
		Misrouted:       c.Delivery.RoutingStatus == cargo.Misrouted,
		Routed:          !c.Itinerary.IsEmpty(),
		ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
		Legs:            assembleLegs(c),
	}
}

func assembleLegs(c cargo.Cargo) []Leg {
	var legs []Leg
	for _, l := range c.Itinerary.Legs {
		legs = append(legs, Leg{
			VoyageNumber: string(l.VoyageNumber),
			From:         string(l.LoadLocation),
			To:           string(l.UnloadLocation),
			LoadTime:     l.LoadTime,
			UnloadTime:   l.UnloadTime,
		})
	}
	return legs
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"

	"github.com/mrjones/oauth"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func LoginWithTwitter(w http.ResponseWriter, r *http.Request) {

	c := oauth.NewConsumer(
		config.TWITTER_KEY,
		config.TWITTER_SECRET,
		oauth.ServiceProvider{
			RequestTokenUrl:   "https://api.twitter.com/oauth/request_token",
			AuthorizeTokenUrl: "https://api.twitter.com/oauth/authenticate",
			AccessTokenUrl:    "https://api.twitter.com/oauth/access_token",
		})

	profileUrl := "https://api.twitter.com/1.1/users/show.json"

	decoder := json.NewDecoder(r.Body)
	var requestPayload struct {
		OAuthToken    string `json:"oauth_token"`
		OAuthVerifier string `json:"oauth_verifier"`
	}
	err := decoder.Decode(&requestPayload)
	if err != nil && err != io.EOF {
		log.Println(err)
		return
	}

	// Part 1/2: Initial request from Satellizer.
	if requestPayload.OAuthToken == "" || requestPayload.OAuthVerifier == "" {

		// Step 1. Obtain request token for the authorization popup.
		requestToken, _, err := c.GetRequestTokenAndUrl(config.TWITTER_CALLBACK)
		if err != nil {
			log.Println(err)
			return
		}

		// Step 2. Redirect to the authorization screen.
		ServeJSON(w, r, &Response{
			"oauth_token":              requestToken.Token,
			"oauth_token_secret":       requestToken.Secret,
			"oauth_callback_confirmed": "true",
		}, 200)
	} else {
		// Part 2/2: Second request after Authorize app is clicked.
		requestToken := &oauth.RequestToken{requestPayload.OAuthToken, config.TWITTER_SECRET}

		// Step 3. Exchange oauth token and oauth verifier for access token.
		accessToken, err := c.AuthorizeToken(requestToken, requestPayload.OAuthVerifier)
		if err != nil {
			log.Println(err)
			return
		}

		// Step 4. Retrieve profile information about the current user.
		response, err := c.Get(
			profileUrl,
			map[string]string{"screen_name": accessToken.AdditionalData["screen_name"]},
			accessToken)

		if err != nil {
			log.Fatal(err)
		}
		defer response.Body.Close()

		bits, err := ioutil.ReadAll(response.Body)

		var profileData map[string]interface{}
		err = json.Unmarshal(bits, &profileData)

		db := GetDB(w, r)

		if IsTokenSet(r) {
			// Step 5a. Link user accounts.
			existingUser, errM := FindUserByQuery(db, bson.M{"twitter": accessToken.AdditionalData["user_id"]})
			if existingUser != nil {
				ServeJSON(w, r, &Response{
					"message": "There is already a Twitter account that belongs to you",
				}, 409)
				return
			}

			if errM != nil && errM.Reason != mgo.ErrNotFound {
				HandleModelError(w, r, errM)
				return
			}

			tokenData := GetToken(w, r)
			user, errM := FindUserById(db, bson.ObjectIdHex(tokenData.ID))
			if user == nil {
				ServeJSON(w, r, &Response{
					"message": "User not found",
				}, 400)
				return
			}

			if errM != nil && errM.Reason != mgo.ErrNotFound {
				HandleModelError(w, r, errM)
				return
			}

			user.Twitter = accessToken.AdditionalData["user_id"]
			if user.DisplayName == "" {
				user.DisplayName = accessToken.AdditionalData["screen_name"]
			}
			if user.Picture == "" {
				user.Picture = strings.Replace(profileData["profile_image_url"].(string), "_normal", "", 1)
			}

			err = user.Save(db)
			if err != nil {
				ISR(w, r, errors.New("Couldn't save user profile informations"))
			}

			SetToken(w, r, user)

		} else {
			// Step 5b. Create a new user account or return an existing one.
			existingUser, errM := FindUserByQuery(db, bson.M{"twitter": accessToken.AdditionalData["user_id"]})
			if existingUser != nil {
				SetToken(w, r, existingUser)
				return
			}
			if errM != nil && errM.Reason != mgo.ErrNotFound {
				HandleModelError(w, r, errM)
				return
			}

			user := NewUser()
			user.Email = accessToken.AdditionalData["user_id"] + "-satellizer@twitter.com"
			user.Twitter = accessToken.AdditionalData["user_id"]
			user.DisplayName = accessToken.AdditionalData["screen_name"]
			user.Picture = strings.Replace(profileData["profile_image_url"].(string), "_normal", "", 1)
			err = user.Save(db)
			if err != nil {
				ISR(w, r, err)
				return
			}

			SetToken(w, r, user)
		}

	}
}
<commit_msg>Switch to FindUserByProvider for twitter auth<commit_after>package main

import (
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"

	"github.com/mrjones/oauth"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func LoginWithTwitter(w http.ResponseWriter, r *http.Request) {

	c := oauth.NewConsumer(
		config.TWITTER_KEY,
		config.TWITTER_SECRET,
		oauth.ServiceProvider{
			RequestTokenUrl:   "https://api.twitter.com/oauth/request_token",
			AuthorizeTokenUrl: "https://api.twitter.com/oauth/authenticate",
			AccessTokenUrl:    "https://api.twitter.com/oauth/access_token",
		})

	profileUrl := "https://api.twitter.com/1.1/users/show.json"

	decoder := json.NewDecoder(r.Body)
	var requestPayload struct {
		OAuthToken    string `json:"oauth_token"`
		OAuthVerifier string `json:"oauth_verifier"`
	}
	err := decoder.Decode(&requestPayload)
	if err != nil && err != io.EOF {
		log.Println(err)
		return
	}

	// Part 1/2: Initial request from Satellizer.
	if requestPayload.OAuthToken == "" || requestPayload.OAuthVerifier == "" {

		// Step 1. Obtain request token for the authorization popup.
		requestToken, _, err := c.GetRequestTokenAndUrl(config.TWITTER_CALLBACK)
		if err != nil {
			log.Println(err)
			return
		}

		// Step 2. Redirect to the authorization screen.
		ServeJSON(w, r, &Response{
			"oauth_token":              requestToken.Token,
			"oauth_token_secret":       requestToken.Secret,
			"oauth_callback_confirmed": "true",
		}, 200)
	} else {
		// Part 2/2: Second request after Authorize app is clicked.
		requestToken := &oauth.RequestToken{requestPayload.OAuthToken, config.TWITTER_SECRET}

		// Step 3. Exchange oauth token and oauth verifier for access token.
		accessToken, err := c.AuthorizeToken(requestToken, requestPayload.OAuthVerifier)
		if err != nil {
			log.Println(err)
			return
		}

		// Step 4. Retrieve profile information about the current user.
		response, err := c.Get(
			profileUrl,
			map[string]string{"screen_name": accessToken.AdditionalData["screen_name"]},
			accessToken)

		if err != nil {
			log.Fatal(err)
		}
		defer response.Body.Close()

		bits, err := ioutil.ReadAll(response.Body)

		var profileData map[string]interface{}
		err = json.Unmarshal(bits, &profileData)

		db := GetDB(w, r)

		if IsTokenSet(r) {
			// Step 5a. Link user accounts.
			existingUser, errM := FindUserByProvider(db, "twitter", accessToken.AdditionalData["user_id"])
			if existingUser != nil {
				ServeJSON(w, r, &Response{
					"message": "There is already a Twitter account that belongs to you",
				}, 409)
				return
			}

			if errM != nil && errM.Reason != mgo.ErrNotFound {
				HandleModelError(w, r, errM)
				return
			}

			tokenData := GetToken(w, r)
			user, errM := FindUserById(db, bson.ObjectIdHex(tokenData.ID))
			if user == nil {
				ServeJSON(w, r, &Response{
					"message": "User not found",
				}, 400)
				return
			}

			if errM != nil && errM.Reason != mgo.ErrNotFound {
				HandleModelError(w, r, errM)
				return
			}

			user.Twitter = accessToken.AdditionalData["user_id"]
			if user.DisplayName == "" {
				user.DisplayName = accessToken.AdditionalData["screen_name"]
			}
			if user.Picture == "" {
				user.Picture = strings.Replace(profileData["profile_image_url"].(string), "_normal", "", 1)
			}

			err = user.Save(db)
			if err != nil {
				ISR(w, r, errors.New("Couldn't save user profile informations"))
			}

			SetToken(w, r, user)

		} else {
			// Step 5b. Create a new user account or return an existing one.
			existingUser, errM := FindUserByProvider(db, "twitter", accessToken.AdditionalData["user_id"])
			if existingUser != nil {
				SetToken(w, r, existingUser)
				return
			}
			if errM != nil && errM.Reason != mgo.ErrNotFound {
				HandleModelError(w, r, errM)
				return
			}

			user := NewUser()
			user.Email = accessToken.AdditionalData["user_id"] + "-satellizer@twitter.com"
			user.Twitter = accessToken.AdditionalData["user_id"]
			user.DisplayName = accessToken.AdditionalData["screen_name"]
			user.Picture = strings.Replace(profileData["profile_image_url"].(string), "_normal", "", 1)
			err = user.Save(db)
			if err != nil {
				ISR(w, r, err)
				return
			}

			SetToken(w, r, user)
		}

	}
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"regexp"
)

const runJobRegex = `run +job +(` + identifierRegex + `)`
const historyRegex = `history +(` + identifierRegex + `)`
const showHistoryRegex = `history +(` + identifierRegex + `) +(\d+)`

var runJobRe = regexp.MustCompile(`(?i:^\s*` + runJobRegex + `\s*$)`)
var historyRe = regexp.MustCompile(`(?i:^\s*` + historyRegex + `\s*$)`)
var showHistoryRe = regexp.MustCompile(`(?i:^\s*` + showHistoryRegex + `\s*$)`)

type jobCommand int

const (
	jobRun = iota
	history
	showHistory
)

// checkJobMatchersAndRun handles triggers, 'run job <foo>', 'history <foo>'
func (bot *botContext) checkJobMatchersAndRun() (messageMatched bool) {
	r := bot.makeRobot()
	// un-needed, but more clear
	messageMatched = false
	var runTask interface{}
	// First, check triggers
	for _, t := range bot.tasks.t {
		task, _, job := getTask(t)
		if job == nil {
			continue
		}
		if task.Disabled {
			msg := fmt.Sprintf("Skipping disabled job '%s', reason: %s", task.name, task.reason)
			Log(Trace, msg)
			bot.debugTask(t, msg, false)
			continue
		}
		Log(Trace, fmt.Sprintf("Checking triggers for job '%s'", task.name))
		triggers := job.Triggers
		bot.debugTask(t, fmt.Sprintf("Checking %d JobTriggers against message: '%s' from user '%s' in channel '%s'", len(triggers), bot.msg, bot.User, bot.Channel), false)
		for _, trigger := range triggers {
			Log(Trace, fmt.Sprintf("Checking '%s' against user '%s', channel '%s', regex: '%s'", bot.msg, trigger.User, trigger.Channel, trigger.Regex))
			if bot.User != trigger.User {
				bot.debugTask(t, fmt.Sprintf("User '%s' doesn't match trigger user '%s'", bot.User, trigger.User), false)
				continue
			}
			if bot.Channel != trigger.Channel {
				bot.debugTask(t, fmt.Sprintf("Channel '%s' doesn't match trigger", bot.Channel), false)
				continue
			}
			matches := trigger.re.FindAllStringSubmatch(bot.msg, -1)
			matched := false
			if matches != nil {
				bot.debugTask(t, fmt.Sprintf("Matched trigger regex '%s'", trigger.Regex), false)
				Log(Trace, fmt.Sprintf("Message '%s' matches trigger for job '%s'", bot.msg, task.name))
				triggerParams := matches[0][1:]
				numParams := len(trigger.Parameters)
				if numParams > 0 {
					// Assign match groups to parameters and set matched to true if no error
					if len(trigger.Parameters) == numParams {
						for i, v := range trigger.Parameters {
							bot.environment[v] = triggerParams[i]
						}
						matched = true
					} else {
						Log(Warn, fmt.Sprintf("Matched trigger regex '%s', but matched groups (%d) doesn't matched number of configured parameters (%d), ignoring", trigger.Regex, len(triggerParams), numParams))
						continue
					}
				} else {
					matched = true
					bot.User = task.User
				}
			} else {
				bot.debugTask(t, fmt.Sprintf("Not matched: %s", trigger.Regex), false)
			}
			if matched {
				if messageMatched {
					prevTask, _, _ := getTask(runTask)
					Log(Error, fmt.Sprintf("Message '%s' from user '%s' in channel '%s' matched triggers for multiple jobs: '%s' and '%s', ignoring", bot.msg, bot.User, bot.Channel, prevTask.name, task.name))
					emit(MultipleMatchesNoAction)
					return
				}
				messageMatched = true
				runTask = t
				break
			}
		} // end of triggerer checking
	} // end of job trigger checking
	if messageMatched {
		r.messageHeard()
		robot.RLock()
		if robot.shuttingDown {
			r.Say("Ignoring triggered job: shutting down")
			robot.RUnlock()
			return
		} else if robot.paused {
			r.Say("Ignoring triggered job: paused")
			robot.RUnlock()
			return
		}
		robot.RUnlock()
		// Jobs triggers should only match apps / bots, not real users!
		bot.bypassSecurityChecks = true
		bot.runPipeline(runTask, false, jobTrigger, "run")
		return
	}
	// Check for built-in job commands
	var jobCommand jobCommand
	var command string
	var args []string
	var jobName string
	var runIndex string
	matches := runJobRe.FindAllStringSubmatch(bot.msg, -1)
	if matches != nil {
		jobCommand = jobRun
		jobName = matches[0][1]
		messageMatched = true
	}
	if !messageMatched {
		matches = historyRe.FindAllStringSubmatch(bot.msg, -1)
		if matches != nil {
			jobCommand = history
			jobName = matches[0][1]
			messageMatched = true
		}
	}
	if !messageMatched {
		matches = showHistoryRe.FindAllStringSubmatch(bot.msg, -1)
		if matches != nil {
			jobCommand = showHistory
			jobName = matches[0][1]
			runIndex = matches[0][2]
			messageMatched = true
		}
	}
	if !messageMatched {
		return
	}
	t := bot.tasks.getTaskByName(jobName)
	if t == nil {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, I don't have a task named '%s' configured", jobName))
		return false
	}
	task, _, job := getTask(t)
	if job == nil {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, I don't have a job named '%s' configured", jobName))
		return false
	}
	if bot.Channel != task.Channel {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, job '%s' isn't available in this channel, try '%s'", jobName, task.Channel))
		return false
	}
	switch jobCommand {
	case jobRun:
		// TODO: prompt for required parameters & add to bot.environment
		// NOTE: 'run job' uses security checks in runPipeline
		bot.runPipeline(t, true, jobCmd, "run")
		return
	case history, showHistory:
		runTask = bot.tasks.getTaskByName("builtInhistory")
		if len(runIndex) > 0 {
			command = "showhistory"
		} else {
			command = "history"
		}
		args = []string{jobName, runIndex}
	}
	// NOTE: other job commands need security checks for the job being operated on
	if bot.checkAuthorization(t, "run") != Success {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, failed authorization for job '%s'", jobName))
		return
	}
	if !bot.elevated {
		eret, required := bot.checkElevation(t, command)
		if eret != Success {
			bot.makeRobot().Say("Elevation request failed")
			return
		}
		if required {
			bot.elevated = true
		}
	}
	bot.runPipeline(runTask, true, jobCmd, command, args...)
	return
}
<commit_msg>Run triggered jobs in configured channel<commit_after>package bot

import (
	"fmt"
	"regexp"
)

const runJobRegex = `run +job +(` + identifierRegex + `)`
const historyRegex = `history +(` + identifierRegex + `)`
const showHistoryRegex = `history +(` + identifierRegex + `) +(\d+)`

var runJobRe = regexp.MustCompile(`(?i:^\s*` + runJobRegex + `\s*$)`)
var historyRe = regexp.MustCompile(`(?i:^\s*` + historyRegex + `\s*$)`)
var showHistoryRe = regexp.MustCompile(`(?i:^\s*` + showHistoryRegex + `\s*$)`)

type jobCommand int

const (
	jobRun = iota
	history
	showHistory
)

// checkJobMatchersAndRun handles triggers, 'run job <foo>', 'history <foo>'
func (bot *botContext) checkJobMatchersAndRun() (messageMatched bool) {
	r := bot.makeRobot()
	// un-needed, but more clear
	messageMatched = false
	var runTask interface{}
	// First, check triggers
	for _, t := range bot.tasks.t {
		task, _, job := getTask(t)
		if job == nil {
			continue
		}
		if task.Disabled {
			msg := fmt.Sprintf("Skipping disabled job '%s', reason: %s", task.name, task.reason)
			Log(Trace, msg)
			bot.debugTask(t, msg, false)
			continue
		}
		Log(Trace, fmt.Sprintf("Checking triggers for job '%s'", task.name))
		triggers := job.Triggers
		bot.debugTask(t, fmt.Sprintf("Checking %d JobTriggers against message: '%s' from user '%s' in channel '%s'", len(triggers), bot.msg, bot.User, bot.Channel), false)
		for _, trigger := range triggers {
			Log(Trace, fmt.Sprintf("Checking '%s' against user '%s', channel '%s', regex: '%s'", bot.msg, trigger.User, trigger.Channel, trigger.Regex))
			if bot.User != trigger.User {
				bot.debugTask(t, fmt.Sprintf("User '%s' doesn't match trigger user '%s'", bot.User, trigger.User), false)
				continue
			}
			if bot.Channel != trigger.Channel {
				bot.debugTask(t, fmt.Sprintf("Channel '%s' doesn't match trigger", bot.Channel), false)
				continue
			}
			matches := trigger.re.FindAllStringSubmatch(bot.msg, -1)
			matched := false
			if matches != nil {
				bot.debugTask(t, fmt.Sprintf("Matched trigger regex '%s'", trigger.Regex), false)
				Log(Trace, fmt.Sprintf("Message '%s' matches trigger for job '%s'", bot.msg, task.name))
				triggerParams := matches[0][1:]
				numParams := len(trigger.Parameters)
				if numParams > 0 {
					// Assign match groups to parameters and set matched to true if no error
					if len(trigger.Parameters) == numParams {
						for i, v := range trigger.Parameters {
							bot.environment[v] = triggerParams[i]
						}
						matched = true
					} else {
						Log(Warn, fmt.Sprintf("Matched trigger regex '%s', but matched groups (%d) doesn't matched number of configured parameters (%d), ignoring", trigger.Regex, len(triggerParams), numParams))
						continue
					}
				} else {
					matched = true
					bot.User = task.User
				}
			} else {
				bot.debugTask(t, fmt.Sprintf("Not matched: %s", trigger.Regex), false)
			}
			if matched {
				if messageMatched {
					prevTask, _, _ := getTask(runTask)
					Log(Error, fmt.Sprintf("Message '%s' from user '%s' in channel '%s' matched triggers for multiple jobs: '%s' and '%s', ignoring", bot.msg, bot.User, bot.Channel, prevTask.name, task.name))
					emit(MultipleMatchesNoAction)
					return
				}
				messageMatched = true
				runTask = t
				bot.Channel = task.Channel
				break
			}
		} // end of triggerer checking
	} // end of job trigger checking
	if messageMatched {
		r.messageHeard()
		robot.RLock()
		if robot.shuttingDown {
			r.Say("Ignoring triggered job: shutting down")
			robot.RUnlock()
			return
		} else if robot.paused {
			r.Say("Ignoring triggered job: paused")
			robot.RUnlock()
			return
		}
		robot.RUnlock()
		// Jobs triggers should only match apps / bots, not real users!
		bot.bypassSecurityChecks = true
		bot.runPipeline(runTask, false, jobTrigger, "run")
		return
	}
	// Check for built-in job commands
	var jobCommand jobCommand
	var command string
	var args []string
	var jobName string
	var runIndex string
	matches := runJobRe.FindAllStringSubmatch(bot.msg, -1)
	if matches != nil {
		jobCommand = jobRun
		jobName = matches[0][1]
		messageMatched = true
	}
	if !messageMatched {
		matches = historyRe.FindAllStringSubmatch(bot.msg, -1)
		if matches != nil {
			jobCommand = history
			jobName = matches[0][1]
			messageMatched = true
		}
	}
	if !messageMatched {
		matches = showHistoryRe.FindAllStringSubmatch(bot.msg, -1)
		if matches != nil {
			jobCommand = showHistory
			jobName = matches[0][1]
			runIndex = matches[0][2]
			messageMatched = true
		}
	}
	if !messageMatched {
		return
	}
	t := bot.tasks.getTaskByName(jobName)
	if t == nil {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, I don't have a task named '%s' configured", jobName))
		return false
	}
	task, _, job := getTask(t)
	if job == nil {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, I don't have a job named '%s' configured", jobName))
		return false
	}
	if bot.Channel != task.Channel {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, job '%s' isn't available in this channel, try '%s'", jobName, task.Channel))
		return false
	}
	switch jobCommand {
	case jobRun:
		// TODO: prompt for required parameters & add to bot.environment
		// NOTE: 'run job' uses security checks in runPipeline
		bot.runPipeline(t, true, jobCmd, "run")
		return
	case history, showHistory:
		runTask = bot.tasks.getTaskByName("builtInhistory")
		if len(runIndex) > 0 {
			command = "showhistory"
		} else {
			command = "history"
		}
		args = []string{jobName, runIndex}
	}
	// NOTE: other job commands need security checks for the job being operated on
	if bot.checkAuthorization(t, "run") != Success {
		bot.makeRobot().Say(fmt.Sprintf("Sorry, failed authorization for job '%s'", jobName))
		return
	}
	if !bot.elevated {
		eret, required := bot.checkElevation(t, command)
		if eret != Success {
			bot.makeRobot().Say("Elevation request failed")
			return
		}
		if required {
			bot.elevated = true
		}
	}
	bot.runPipeline(runTask, true, jobCmd, command, args...)
	return
}
<|endoftext|>


<commit_before>package broker

import (
	"encoding/json"
	"github.com/emitter-io/emitter/config"
	"github.com/emitter-io/emitter/security"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestProcessKeygen(t *testing.T) {

	cfg := config.NewDefault()
	cfg.License = "zT83oDV0DWY5_JysbSTPTDr8KB0AAAAAAAAAAAAAAAI"
	svc, err := NewService(cfg)
	if err != nil {
		panic(err.Error())
	}
	svc.ContractProvider = security.NewSingleContractProvider(svc.License)

	channel := security.ParseChannel([]byte("emitter/keygen/"))
	message := keyGenMessage{
		Key:     "kBCZch5re3Ue-kpG1Aa8Vo7BYvXZ3UwR",
		Channel: "test",
		Type:    "rw",
	}
	payload, _ := json.Marshal(&message)

	err = ProcessKeyGen(svc, channel, payload)
	assert.Nil(t, err)
}
<commit_msg>api test<commit_after>package broker

import (
	"encoding/json"
	"github.com/emitter-io/emitter/config"
	"github.com/emitter-io/emitter/security"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestProcessKeygen(t *testing.T) {

	cfg := config.NewDefault()
	cfg.License = "zT83oDV0DWY5_JysbSTPTDr8KB0AAAAAAAAAAAAAAAI"
	svc, _ := NewService(cfg)
	svc.ContractProvider = security.NewSingleContractProvider(svc.License)

	channel := security.ParseChannel([]byte("emitter/keygen/"))
	message := keyGenMessage{
		Key:     "kBCZch5re3Ue-kpG1Aa8Vo7BYvXZ3UwR",
		Channel: "test",
		Type:    "rw",
	}
	payload, _ := json.Marshal(&message)

	err := ProcessKeyGen(svc, channel, payload)
	assert.Nil(t, err)
}
<|endoftext|>