<commit_before>package interpreter

import "io"
import "os"
import "os/exec"
import "regexp"

type NextT int

const (
	THROUGH  NextT = 0
	CONTINUE NextT = 1
	SHUTDOWN NextT = 2
)

type Stdio struct {
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

type ArgsHookT func(args []string) []string

var argsHook = func(args []string) []string {
	return args
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(*exec.Cmd, bool, io.Closer) (NextT, error)

var hook = func(*exec.Cmd, bool, io.Closer) (NextT, error) {
	return THROUGH, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var errorStatusPattern = regexp.MustCompile("^exit status ([0-9]+)")
var ErrorLevel string

func Interpret(text string, stdio *Stdio) (NextT, error) {
	statement := Parse(text)
	return InterpretStatement(&statement, stdio)
}
func InterpretStatement(statements *[][]StatementT, stdio *Stdio) (NextT, error) {
	for _, pipeline := range *statements {
		var pipeIn *os.File = nil
		for _, state := range pipeline {
			//fmt.Println(state)
			var cmd exec.Cmd
			if stdio == nil {
				cmd.Stdin = os.Stdin
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
			} else {
				if stdio.Stderr != nil {
					cmd.Stdin = stdio.Stdin
				} else {
					cmd.Stdin = os.Stdin
				}
				if stdio.Stdout != nil {
					cmd.Stdout = stdio.Stdout
				} else {
					cmd.Stdout = os.Stdout
				}
				if stdio.Stderr != nil {
					cmd.Stderr = stdio.Stderr
				} else {
					cmd.Stderr = os.Stderr
				}
			}
			if pipeIn != nil {
				cmd.Stdin = pipeIn
				pipeIn = nil
			}
			if state.Redirect[0].Path != "" {
				fd, err := os.Open(state.Redirect[0].Path)
				if err != nil {
					return CONTINUE, err
				}
				defer fd.Close()
				cmd.Stdin = fd
			}
			if state.Redirect[1].Path != "" {
				var fd *os.File
				var err error
				if state.Redirect[1].IsAppend {
					fd, err = os.OpenFile(state.Redirect[1].Path, os.O_APPEND, 0666)
				} else {
					fd, err = os.OpenFile(state.Redirect[1].Path, os.O_CREATE, 0666)
				}
				if err != nil {
					return CONTINUE, err
				}
				defer fd.Close()
				cmd.Stdout = fd
			}
			if state.Redirect[2].Path != "" {
				var fd *os.File
				var err error
				if state.Redirect[2].IsAppend {
					fd, err = os.OpenFile(state.Redirect[2].Path, os.O_APPEND, 0666)
				} else {
					fd, err = os.OpenFile(state.Redirect[2].Path, os.O_CREATE, 0666)
				}
				if err != nil {
					return CONTINUE, err
				}
				defer fd.Close()
				cmd.Stderr = fd
			}
			var err error = nil
			var pipeOut *os.File = nil
			if state.Term == "|" {
				pipeIn, pipeOut, err = os.Pipe()
				if err != nil {
					return CONTINUE, err
				}
				defer pipeIn.Close()
				cmd.Stdout = pipeOut
			}
			var whatToDo NextT

			isBackGround := (state.Term == "|" || state.Term == "&")

			if len(state.Argv) > 0 {
				if argsHook != nil {
					state.Argv = argsHook(state.Argv)
				}
				cmd.Args = state.Argv
				whatToDo, err = hook(&cmd, isBackGround, pipeOut)
				if whatToDo == THROUGH {
					cmd.Path, err = exec.LookPath(state.Argv[0])
					if err == nil {
						if isBackGround {
							err = cmd.Start()
						} else {
							err = cmd.Run()
						}
					}
				} else {
					pipeOut = nil
				}
			}
			if pipeOut != nil {
				pipeOut.Close()
			}
			if err != nil {
				m := errorStatusPattern.FindStringSubmatch(err.Error())
				if m != nil {
					ErrorLevel = m[1]
				} else {
					ErrorLevel = "0"
				}
				err = nil
			} else {
				ErrorLevel = "0"
			}
			if whatToDo == SHUTDOWN {
				return SHUTDOWN, err
			}
			if err != nil {
				return CONTINUE, err
			}
		}
	}
	return CONTINUE, nil
}
<commit_msg>コマンドが見付からなかった時にエラーが出なくなっていた不具合を修正<commit_after>package interpreter

import "io"
import "os"
import "os/exec"
import "regexp"

type NextT int

const (
	THROUGH  NextT = 0
	CONTINUE NextT = 1
	SHUTDOWN NextT = 2
)

type Stdio struct {
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

type ArgsHookT func(args []string) []string

var argsHook = func(args []string) []string {
	return args
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(*exec.Cmd, bool, io.Closer) (NextT, error)

var hook = func(*exec.Cmd, bool, io.Closer) (NextT, error) {
	return THROUGH, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var errorStatusPattern = regexp.MustCompile("^exit status ([0-9]+)")
var ErrorLevel string

func Interpret(text string, stdio *Stdio) (NextT, error) {
	statement := Parse(text)
	return InterpretStatement(&statement, stdio)
}
func InterpretStatement(statements *[][]StatementT, stdio *Stdio) (NextT, error) {
	for _, pipeline := range *statements {
		var pipeIn *os.File = nil
		for _, state := range pipeline {
			//fmt.Println(state)
			var cmd exec.Cmd
			if stdio == nil {
				cmd.Stdin = os.Stdin
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
			} else {
				if stdio.Stderr != nil {
					cmd.Stdin = stdio.Stdin
				} else {
					cmd.Stdin = os.Stdin
				}
				if stdio.Stdout != nil {
					cmd.Stdout = stdio.Stdout
				} else {
					cmd.Stdout = os.Stdout
				}
				if stdio.Stderr != nil {
					cmd.Stderr = stdio.Stderr
				} else {
					cmd.Stderr = os.Stderr
				}
			}
			if pipeIn != nil {
				cmd.Stdin = pipeIn
				pipeIn = nil
			}
			if state.Redirect[0].Path != "" {
				fd, err := os.Open(state.Redirect[0].Path)
				if err != nil {
					return CONTINUE, err
				}
				defer fd.Close()
				cmd.Stdin = fd
			}
			if state.Redirect[1].Path != "" {
				var fd *os.File
				var err error
				if state.Redirect[1].IsAppend {
					fd, err = os.OpenFile(state.Redirect[1].Path, os.O_APPEND, 0666)
				} else {
					fd, err = os.OpenFile(state.Redirect[1].Path, os.O_CREATE, 0666)
				}
				if err != nil {
					return CONTINUE, err
				}
				defer fd.Close()
				cmd.Stdout = fd
			}
			if state.Redirect[2].Path != "" {
				var fd *os.File
				var err error
				if state.Redirect[2].IsAppend {
					fd, err = os.OpenFile(state.Redirect[2].Path, os.O_APPEND, 0666)
				} else {
					fd, err = os.OpenFile(state.Redirect[2].Path, os.O_CREATE, 0666)
				}
				if err != nil {
					return CONTINUE, err
				}
				defer fd.Close()
				cmd.Stderr = fd
			}
			var err error = nil
			var pipeOut *os.File = nil
			if state.Term == "|" {
				pipeIn, pipeOut, err = os.Pipe()
				if err != nil {
					return CONTINUE, err
				}
				defer pipeIn.Close()
				cmd.Stdout = pipeOut
			}
			var whatToDo NextT

			isBackGround := (state.Term == "|" || state.Term == "&")

			if len(state.Argv) > 0 {
				if argsHook != nil {
					state.Argv = argsHook(state.Argv)
				}
				cmd.Args = state.Argv
				whatToDo, err = hook(&cmd, isBackGround, pipeOut)
				if whatToDo == THROUGH {
					cmd.Path, err = exec.LookPath(state.Argv[0])
					if err == nil {
						if isBackGround {
							err = cmd.Start()
						} else {
							err = cmd.Run()
						}
					}
				} else {
					pipeOut = nil
				}
			}
			if pipeOut != nil {
				pipeOut.Close()
			}
			if err != nil {
				m := errorStatusPattern.FindStringSubmatch(err.Error())
				if m != nil {
					ErrorLevel = m[1]
					err = nil
				} else {
					ErrorLevel = "-1"
				}
			} else {
				ErrorLevel = "0"
			}
			if whatToDo == SHUTDOWN {
				return SHUTDOWN, err
			}
			if err != nil {
				return CONTINUE, err
			}
		}
	}
	return CONTINUE, nil
}
<|endoftext|>


<commit_before>// Package mqtttest provides utilities for MQTT testing.
package mqtttest

import (
	"bytes"
	"errors"
	"sync/atomic"
	"testing"
	"time"

	"github.com/pascaldekloe/mqtt"
)

// Transfer defines a message exchange.
type Transfer struct {
	Message []byte // payload
	Topic   string // destination
	Err     error  // result
}

// NewReadSlicesStub returns a new stub for mqtt.Client ReadSlices with a fixed
// return value.
func NewReadSlicesStub(fix Transfer) func() (message, topic []byte, err error) {
	return func() (message, topic []byte, err error) {
		// use copies to prevent some hard to trace issues
		message = make([]byte, len(fix.Message))
		copy(message, fix.Message)
		topic = []byte(fix.Topic)
		return message, topic, fix.Err
	}
}

// NewReadSlicesMock returns a new mock for mqtt.Client ReadSlices, which
// returns the Transfers in order of appearance.
func NewReadSlicesMock(t testing.TB, want ...Transfer) func() (message, topic []byte, err error) {
	t.Helper()

	var wantIndex uint64

	t.Cleanup(func() {
		if n := uint64(len(want)) - atomic.LoadUint64(&wantIndex); n > 0 {
			t.Errorf("want %d more MQTT ReadSlices", n)
		}
	})

	return func() (message, topic []byte, err error) {
		i := atomic.AddUint64(&wantIndex, 1) - 1
		if i >= uint64(len(want)) {
			err = errors.New("unwanted MQTT ReadSlices")
			t.Error(err)
			return
		}

		return NewReadSlicesStub(want[i])()
	}
}

// NewPublishMock returns a new mock for mqtt.Client Publish, which compares the
// invocation with want in order of appearance.
func NewPublishMock(t testing.TB, want ...Transfer) func(quit <-chan struct{}, message []byte, topic string) error {
	t.Helper()

	var wantIndex uint64

	t.Cleanup(func() {
		if n := uint64(len(want)) - atomic.LoadUint64(&wantIndex); n > 0 {
			t.Errorf("want %d more MQTT publishes", n)
		}
	})

	return func(quit <-chan struct{}, message []byte, topic string) error {
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			break
		}

		i := atomic.AddUint64(&wantIndex, 1) - 1
		if i >= uint64(len(want)) {
			t.Errorf("unwanted MQTT publish of %#x to %q", message, topic)
			return nil
		}
		transfer := want[i]

		if !bytes.Equal(message, transfer.Message) && topic != transfer.Topic {
			t.Errorf("got MQTT publish of %#x to %q, want %#x to %q", message, topic, transfer.Message, transfer.Topic)
		}
		return transfer.Err
	}
}

// NewPublishStub returns a new stub for mqtt.Client Publish with a fixed return
// value.
func NewPublishStub(fix error) func(quit <-chan struct{}, message []byte, topic string) error {
	return func(quit <-chan struct{}, message []byte, topic string) error {
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			return fix
		}
	}
}

// ExchangeBlock prevents exchange <-chan error submission.
type ExchangeBlock struct {
	Delay time.Duration // zero defaults to indefinite
}

// Error implements the standard error interface.
func (b ExchangeBlock) Error() string {
	return "mqtttest: ExchangeBlock used as an error"
}

// NewPublishExchangeStub returns a stub for mqtt.Client PublishAtLeastOnce or
// PublishExactlyOnce with a fixed return value.
//
// The exchangeFix errors are applied to the exchange return, with an option for
// ExchangeBlock entries. An mqtt.ErrClosed in the exchangeFix keeps the
// exchange channel open (without an extra ExchangeBlock entry).
func NewPublishExchangeStub(errFix error, exchangeFix ...error) func(message []byte, topic string) (exchange <-chan error, err error) {
	if errFix != nil && len(exchangeFix) != 0 {
		panic("exchangeFix entries with non-nil errFix")
	}
	var block ExchangeBlock
	for i, err := range exchangeFix {
		switch {
		case err == nil:
			panic("nil entry in exchangeFix")
		case errors.Is(err, mqtt.ErrClosed):
			if i+1 < len(exchangeFix) {
				panic("followup on mqtt.ErrClosed exchangeFix entry")
			}
		case errors.As(err, &block):
			if block.Delay == 0 && i+1 < len(exchangeFix) {
				panic("followup on indefinite ExchangeBlock exchangeFix entry")
			}
		}
	}

	return func(message []byte, topic string) (exchange <-chan error, err error) {
		if errFix != nil {
			return nil, errFix
		}

		ch := make(chan error, len(exchangeFix))
		go func() {
			var block ExchangeBlock
			for _, err := range exchangeFix {
				switch {
				default:
					ch <- err
				case errors.Is(err, mqtt.ErrClosed):
					ch <- err
					return // without close
				case errors.As(err, &block):
					if block.Delay == 0 {
						return // without close
					}
					time.Sleep(block.Delay)
				}
			}
			close(ch)
		}()
		return ch, nil
	}
}

// NewSubscribeStub returns a stub for mqtt.Client Subscribe with a fixed return
// value.
func NewSubscribeStub(fix error) func(quit <-chan struct{}, topicFilters ...string) error {
	return newSubscribeStub("subscribe", fix)
}

// NewUnsubscribeStub returns a stub for mqtt.Client Unsubscribe with a fixed
// return value.
func NewUnsubscribeStub(fix error) func(quit <-chan struct{}, topicFilters ...string) error {
	return newSubscribeStub("unsubscribe", fix)
}

func newSubscribeStub(name string, fix error) func(quit <-chan struct{}, topicFilters ...string) error {
	return func(quit <-chan struct{}, topicFilters ...string) error {
		if len(topicFilters) == 0 {
			// TODO(pascaldekloe): move validation to internal
			// package and then return appropriate errors here.
			panic("MQTT " + name + " without topic filters")
		}
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			break
		}
		return fix
	}
}

// Filter defines a subscription exchange.
type Filter struct {
	Topics []string // order is ignored
	Err    error    // result
}

// NewSubscribeMock returns a new mock for mqtt.Client Subscribe, which compares
// the invocation with want in order of appearece.
func NewSubscribeMock(t testing.TB, want ...Filter) func(quit <-chan struct{}, topicFilters ...string) error {
	t.Helper()
	return newSubscribeMock("subscribe", t, want...)
}

// NewUnsubscribeMock returns a new mock for mqtt.Client Unsubscribe, which
// compares the invocation with want in order of appearece.
func NewUnsubscribeMock(t testing.TB, want ...Filter) func(quit <-chan struct{}, topicFilters ...string) error {
	t.Helper()
	return newSubscribeMock("unsubscribe", t, want...)
}

func newSubscribeMock(name string, t testing.TB, want ...Filter) func(quit <-chan struct{}, topicFilters ...string) error {
	t.Helper()

	var wantIndex uint64

	t.Cleanup(func() {
		if n := uint64(len(want)) - atomic.LoadUint64(&wantIndex); n > 0 {
			t.Errorf("want %d more MQTT %ss", n, name)
		}
	})

	return func(quit <-chan struct{}, topicFilters ...string) error {
		if len(topicFilters) == 0 {
			t.Fatalf("MQTT %s without topic filters", name)
		}
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			break
		}

		i := atomic.AddUint64(&wantIndex, 1) - 1
		if i >= uint64(len(want)) {
			t.Errorf("unwanted MQTT %s of %q", name, topicFilters)
		}
		filter := want[i]

		todo := make(map[string]struct{}, len(filter.Topics))
		for _, topic := range filter.Topics {
			todo[topic] = struct{}{}
		}
		var wrong []string
		for _, filter := range topicFilters {
			if _, ok := todo[filter]; ok {
				delete(todo, filter)
			} else {
				wrong = append(wrong, filter)
			}
		}
		if len(wrong) != 0 {
			t.Errorf("unwanted MQTT %s of %q (out of %q)", name, wrong, filter.Topics)
		}
		if len(todo) != 0 {
			var miss []string
			for filter := range todo {
				miss = append(miss, filter)
			}
			t.Errorf("no MQTT %s of %q (out of %q)", name, miss, filter.Topics)
		}

		return filter.Err
	}
}
<commit_msg>Testing Helper needs to be on each function, including the nested ones.<commit_after>// Package mqtttest provides utilities for MQTT testing.
package mqtttest

import (
	"bytes"
	"errors"
	"sync/atomic"
	"testing"
	"time"

	"github.com/pascaldekloe/mqtt"
)

// Transfer defines a message exchange.
type Transfer struct {
	Message []byte // payload
	Topic   string // destination
	Err     error  // result
}

// NewReadSlicesStub returns a new stub for mqtt.Client ReadSlices with a fixed
// return value.
func NewReadSlicesStub(fix Transfer) func() (message, topic []byte, err error) {
	return func() (message, topic []byte, err error) {
		// use copies to prevent some hard to trace issues
		message = make([]byte, len(fix.Message))
		copy(message, fix.Message)
		topic = []byte(fix.Topic)
		return message, topic, fix.Err
	}
}

// NewReadSlicesMock returns a new mock for mqtt.Client ReadSlices, which
// returns the Transfers in order of appearance.
func NewReadSlicesMock(t testing.TB, want ...Transfer) func() (message, topic []byte, err error) {
	t.Helper()

	var wantIndex uint64

	t.Cleanup(func() {
		t.Helper()

		if n := uint64(len(want)) - atomic.LoadUint64(&wantIndex); n > 0 {
			t.Errorf("want %d more MQTT ReadSlices", n)
		}
	})

	return func() (message, topic []byte, err error) {
		t.Helper()

		i := atomic.AddUint64(&wantIndex, 1) - 1
		if i >= uint64(len(want)) {
			err = errors.New("unwanted MQTT ReadSlices")
			t.Error(err)
			return
		}

		return NewReadSlicesStub(want[i])()
	}
}

// NewPublishMock returns a new mock for mqtt.Client Publish, which compares the
// invocation with want in order of appearance.
func NewPublishMock(t testing.TB, want ...Transfer) func(quit <-chan struct{}, message []byte, topic string) error {
	t.Helper()

	var wantIndex uint64

	t.Cleanup(func() {
		if n := uint64(len(want)) - atomic.LoadUint64(&wantIndex); n > 0 {
			t.Errorf("want %d more MQTT publishes", n)
		}
	})

	return func(quit <-chan struct{}, message []byte, topic string) error {
		t.Helper()

		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			break
		}

		i := atomic.AddUint64(&wantIndex, 1) - 1
		if i >= uint64(len(want)) {
			t.Errorf("unwanted MQTT publish of %#x to %q", message, topic)
			return nil
		}
		transfer := want[i]

		if !bytes.Equal(message, transfer.Message) && topic != transfer.Topic {
			t.Errorf("got MQTT publish of %#x to %q, want %#x to %q", message, topic, transfer.Message, transfer.Topic)
		}
		return transfer.Err
	}
}

// NewPublishStub returns a new stub for mqtt.Client Publish with a fixed return
// value.
func NewPublishStub(fix error) func(quit <-chan struct{}, message []byte, topic string) error {
	return func(quit <-chan struct{}, message []byte, topic string) error {
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			return fix
		}
	}
}

// ExchangeBlock prevents exchange <-chan error submission.
type ExchangeBlock struct {
	Delay time.Duration // zero defaults to indefinite
}

// Error implements the standard error interface.
func (b ExchangeBlock) Error() string {
	return "mqtttest: ExchangeBlock used as an error"
}

// NewPublishExchangeStub returns a stub for mqtt.Client PublishAtLeastOnce or
// PublishExactlyOnce with a fixed return value.
//
// The exchangeFix errors are applied to the exchange return, with an option for
// ExchangeBlock entries. An mqtt.ErrClosed in the exchangeFix keeps the
// exchange channel open (without an extra ExchangeBlock entry).
func NewPublishExchangeStub(errFix error, exchangeFix ...error) func(message []byte, topic string) (exchange <-chan error, err error) {
	if errFix != nil && len(exchangeFix) != 0 {
		panic("exchangeFix entries with non-nil errFix")
	}
	var block ExchangeBlock
	for i, err := range exchangeFix {
		switch {
		case err == nil:
			panic("nil entry in exchangeFix")
		case errors.Is(err, mqtt.ErrClosed):
			if i+1 < len(exchangeFix) {
				panic("followup on mqtt.ErrClosed exchangeFix entry")
			}
		case errors.As(err, &block):
			if block.Delay == 0 && i+1 < len(exchangeFix) {
				panic("followup on indefinite ExchangeBlock exchangeFix entry")
			}
		}
	}

	return func(message []byte, topic string) (exchange <-chan error, err error) {
		if errFix != nil {
			return nil, errFix
		}

		ch := make(chan error, len(exchangeFix))
		go func() {
			var block ExchangeBlock
			for _, err := range exchangeFix {
				switch {
				default:
					ch <- err
				case errors.Is(err, mqtt.ErrClosed):
					ch <- err
					return // without close
				case errors.As(err, &block):
					if block.Delay == 0 {
						return // without close
					}
					time.Sleep(block.Delay)
				}
			}
			close(ch)
		}()
		return ch, nil
	}
}

// NewSubscribeStub returns a stub for mqtt.Client Subscribe with a fixed return
// value.
func NewSubscribeStub(fix error) func(quit <-chan struct{}, topicFilters ...string) error {
	return newSubscribeStub("subscribe", fix)
}

// NewUnsubscribeStub returns a stub for mqtt.Client Unsubscribe with a fixed
// return value.
func NewUnsubscribeStub(fix error) func(quit <-chan struct{}, topicFilters ...string) error {
	return newSubscribeStub("unsubscribe", fix)
}

func newSubscribeStub(name string, fix error) func(quit <-chan struct{}, topicFilters ...string) error {
	return func(quit <-chan struct{}, topicFilters ...string) error {
		if len(topicFilters) == 0 {
			// TODO(pascaldekloe): move validation to internal
			// package and then return appropriate errors here.
			panic("MQTT " + name + " without topic filters")
		}
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			break
		}
		return fix
	}
}

// Filter defines a subscription exchange.
type Filter struct {
	Topics []string // order is ignored
	Err    error    // result
}

// NewSubscribeMock returns a new mock for mqtt.Client Subscribe, which compares
// the invocation with want in order of appearece.
func NewSubscribeMock(t testing.TB, want ...Filter) func(quit <-chan struct{}, topicFilters ...string) error {
	t.Helper()
	return newSubscribeMock("subscribe", t, want...)
}

// NewUnsubscribeMock returns a new mock for mqtt.Client Unsubscribe, which
// compares the invocation with want in order of appearece.
func NewUnsubscribeMock(t testing.TB, want ...Filter) func(quit <-chan struct{}, topicFilters ...string) error {
	t.Helper()
	return newSubscribeMock("unsubscribe", t, want...)
}

func newSubscribeMock(name string, t testing.TB, want ...Filter) func(quit <-chan struct{}, topicFilters ...string) error {
	t.Helper()

	var wantIndex uint64

	t.Cleanup(func() {
		if n := uint64(len(want)) - atomic.LoadUint64(&wantIndex); n > 0 {
			t.Errorf("want %d more MQTT %ss", n, name)
		}
	})

	return func(quit <-chan struct{}, topicFilters ...string) error {
		t.Helper()
		if len(topicFilters) == 0 {
			t.Fatalf("MQTT %s without topic filters", name)
		}
		select {
		case <-quit:
			return mqtt.ErrCanceled
		default:
			break
		}

		i := atomic.AddUint64(&wantIndex, 1) - 1
		if i >= uint64(len(want)) {
			t.Errorf("unwanted MQTT %s of %q", name, topicFilters)
		}
		filter := want[i]

		todo := make(map[string]struct{}, len(filter.Topics))
		for _, topic := range filter.Topics {
			todo[topic] = struct{}{}
		}
		var wrong []string
		for _, filter := range topicFilters {
			if _, ok := todo[filter]; ok {
				delete(todo, filter)
			} else {
				wrong = append(wrong, filter)
			}
		}
		if len(wrong) != 0 {
			t.Errorf("unwanted MQTT %s of %q (out of %q)", name, wrong, filter.Topics)
		}
		if len(todo) != 0 {
			var miss []string
			for filter := range todo {
				miss = append(miss, filter)
			}
			t.Errorf("no MQTT %s of %q (out of %q)", name, miss, filter.Topics)
		}

		return filter.Err
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/go-martini/martini"
	//"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/sessions"
	"io/ioutil"
	"log"
)

var CFG Config

func main() {
	cfgBytes, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(cfgBytes, &CFG)

	if err != nil {
		log.Fatal(err)
	}

	m := martini.Classic()

	m.Use(martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/o"}))
	m.Use(MongoDB())

	m.Use(sessions.Sessions("session", sessions.NewCookieStore([]byte("session"))))
	m.Use(Oauth2Handler())

	InitTicketService(m)
	InitializeUserService(m)
	InitializeDepartmentService(m)
	InitTicketService(m)

	//m.Use(gzip.All())
	m.RunOnAddr(":80")

}
<commit_msg>Self-Creating config<commit_after>package main

import (
	"encoding/json"
	"github.com/go-martini/martini"
	//"github.com/martini-contrib/gzip"
	"fmt"
	"github.com/martini-contrib/sessions"
	"io/ioutil"
	"log"
)

var CFG Config

func main() {
	println("Looking for config.json")
	cfgBytes, err := ioutil.ReadFile("config.json")

	// There was an error reading the config file, may not exist
	if err != nil {
		// Attempt to read the data in from the console

		print("Enter your ClientID     : ")
		var clientid, secret, host string
		_, err := fmt.Scanf("%s\n", &clientid)
		if err != nil {
			log.Fatal(err)
		}

		print("Enter your Client Secret: ")
		_, err = fmt.Scanf("%s\n", &secret)
		if err != nil {
			log.Fatal(err)
		}

		print("Enter your Host Name    : ")
		_, err = fmt.Scanf("%s\n", &host)
		if err != nil {
			log.Fatal(err)
		}

		CFG.ClientID = clientid
		CFG.ClientSecret = secret
		CFG.RedirectURI = host + "/o/token"

		cfgBytes, err = json.Marshal(&CFG)

		err = ioutil.WriteFile("config.json", cfgBytes, 0755)

		// We were unable to save, continue on anyhow
		if err != nil {
			println("Unable to save config")
		}
	}
	err = json.Unmarshal(cfgBytes, &CFG)

	if err != nil {
		log.Fatal(err)
	}

	m := martini.Classic()

	m.Use(martini.Static("assets", martini.StaticOptions{Fallback: "/index.html", Exclude: "/o"}))
	m.Use(MongoDB())

	m.Use(sessions.Sessions("session", sessions.NewCookieStore([]byte("session"))))
	m.Use(Oauth2Handler())

	InitTicketService(m)
	InitializeUserService(m)
	InitializeDepartmentService(m)
	InitTicketService(m)

	//m.Use(gzip.All())
	m.RunOnAddr(":80")

}
<|endoftext|>


<commit_before>package line

// ReceivedMessage ...
type ReceivedMessage struct {
	Result []Result `json:"result"`
}

// Result ...
type Result struct {
	ID          string   `json:"id"`
	From        string   `json:"from"`
	FromChannel int      `json:"fromChannel"`
	To          []string `json:"to"`
	ToChannel   int      `json:"toChannel"`
	EventType   string   `json:"eventType"`
	Content     Content  `json:"content"`
}

// SingleMessage ..
type SingleMessage struct {
	To        []string `json:"to"`
	ToChannel int      `json:"toChannel"`
	EventType string   `json:"eventType"`
	Content   Content  `json:"content"`
}

// Content ...
type Content struct {
	ID                 string          `json:"id"`
	ContentType        int             `json:"contentType"`
	From               string          `json:"from"`
	CreatedTime        int             `json:"createdTime"`
	To                 []string        `json:"to"`
	ToType             int             `json:"toType"`
	Text               string          `json:"text"`
	Location           Location        `json:"location"`
	ContentMetadata    ContentMetadata `json:"contentMetadata"`
	OriginalContentURL string          `json:"originalContentUrl"`
	PreviewImageURL    string          `json:"previewImageUrl"`
}

// Location ...
type Location struct {
	Title     string  `json:"title"`
	Address   string  `json:"address"`
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

// ContentMetadata ...
type ContentMetadata struct {
	STKID       string `json:"STKID"`
	STKPKGID    string `json:"STKPKGID"`
	STKVER      string `json:"STKVER"`
	STKTXT      string `json:"STKTXT"`
	MID         string `json:"mid"`
	DisplayName string `json:"displayName"`
	AUDLEN      string `json:"AUDLEN"`
	DOWNLOADURL string `json:"DOWNLOAD_URL"`
	SPECREV     string `json:"SPEC_REV"`
	ALTTEXT     string `json:"ALT_TEXT"`
	MARKUPJSON  string `json:"MARKUP_JSON"`
}

// UserProfiles ...
type UserProfiles struct {
	Contacts []Profile `json:"contacts"`
	Count    int       `json:"coudnt"`
	Display  int       `json:"display"`
	Start    int       `json:"start"`
	Total    int       `json:"total"`
}

// Profile ...
type Profile struct {
	DisplayName   string `json:"displayName"`
	MID           string `json:"mid"`
	PictureURL    string `json:"pictureUrl"`
	StatusMessage string `json:"statusMessage"`
}

// MultipleMessage ...
type MultipleMessage struct {
	To        []string        `json:"to"`
	ToChannel int             `json:"toChannel"`
	EventType string          `json:"eventType"`
	Content   MultipleContent `json:"content"`
}

// MultipleContent ...
type MultipleContent struct {
	MessageNotified int       `json:"messageNotified"`
	Messages        []Content `json:"messages"`
}

// SentResult ...
type SentResult struct {
	Failed    []interface{}
	MessageID string
	Timestamp int64
	Version   int
}

// MessageContent ...
type MessageContent struct {
	Content     Content  `json:"content"`
	From        string   `json:"from"`
	FromChannel int      `json:"fromChannel"`
	To          []string `json:"to"`
	ToChannel   int      `json:"toChannel"`
	EventType   string   `json:"eventType"`
	CreatedTime int      `json:"createdTime"`
	ID          string   `json:"id"`
}
<commit_msg>Fix struct<commit_after>package line

// ReceivedMessage ...
type ReceivedMessage struct {
	Result []Result `json:"result"`
}

// Result ...
type Result struct {
	ID          string   `json:"id"`
	From        string   `json:"from"`
	FromChannel int      `json:"fromChannel"`
	To          []string `json:"to"`
	ToChannel   int      `json:"toChannel"`
	EventType   string   `json:"eventType"`
	Content     Content  `json:"content"`
}

// SingleMessage ..
type SingleMessage struct {
	To        []string `json:"to"`
	ToChannel int      `json:"toChannel"`
	EventType string   `json:"eventType"`
	Content   Content  `json:"content"`
}

// Content ...
type Content struct {
	ID                 string          `json:"id"`
	ContentType        int             `json:"contentType"`
	From               string          `json:"from"`
	CreatedTime        int             `json:"createdTime"`
	To                 []string        `json:"to"`
	ToType             int             `json:"toType"`
	Text               string          `json:"text"`
	Location           Location        `json:"location"`
	ContentMetadata    ContentMetadata `json:"contentMetadata"`
	OriginalContentURL string          `json:"originalContentUrl"`
	PreviewImageURL    string          `json:"previewImageUrl"`
}

// Location ...
type Location struct {
	Title     string  `json:"title"`
	Address   string  `json:"address"`
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

// ContentMetadata ...
type ContentMetadata struct {
	STKID       string `json:"STKID"`
	STKPKGID    string `json:"STKPKGID"`
	STKVER      string `json:"STKVER"`
	STKTXT      string `json:"STKTXT"`
	MID         string `json:"mid"`
	DisplayName string `json:"displayName"`
	AUDLEN      string `json:"AUDLEN"`
	DOWNLOADURL string `json:"DOWNLOAD_URL"`
	SPECREV     string `json:"SPEC_REV"`
	ALTTEXT     string `json:"ALT_TEXT"`
	MARKUPJSON  string `json:"MARKUP_JSON"`
}

// UserProfiles ...
type UserProfiles struct {
	Contacts []Profile `json:"contacts"`
	Count    int       `json:"coudnt"`
	Display  int       `json:"display"`
	Start    int       `json:"start"`
	Total    int       `json:"total"`
}

// Profile ...
type Profile struct {
	DisplayName   string `json:"displayName"`
	MID           string `json:"mid"`
	PictureURL    string `json:"pictureUrl"`
	StatusMessage string `json:"statusMessage"`
}

// MultipleMessage ...
type MultipleMessage struct {
	To        []string        `json:"to"`
	ToChannel int             `json:"toChannel"`
	EventType string          `json:"eventType"`
	Content   MultipleContent `json:"content"`
}

// MultipleContent ...
type MultipleContent struct {
	MessageNotified int       `json:"messageNotified"`
	Messages        []Content `json:"messages"`
}

// SentResult ...
type SentResult struct {
	Failed    []interface{}
	MessageID string
	Timestamp int64
	Version   int
}

// MessageContent ...
type MessageContent struct {
	Result []ContentResult `json:"result"`
}

// ContentResult ...
type ContentResult struct {
	Content     Content  `json:"content"`
	From        string   `json:"from"`
	FromChannel int      `json:"fromChannel"`
	To          []string `json:"to"`
	ToChannel   int      `json:"toChannel"`
	EventType   string   `json:"eventType"`
	CreatedTime int      `json:"createdTime"`
	ID          string   `json:"id"`
}
<|endoftext|>


<commit_before>package usrv

import (
	"errors"
	"golang.org/x/net/context"
	"log"
	"os"
	"sync"
)

// Errors introduced by RPC server
var (
	ErrTimeout      = errors.New("Request timeout")
	ErrResponseSent = errors.New("Response already sent")
)

// Context keys
const (
	CtxCurEndpoint = "curEndpoint"
	CtxTraceId     = "traceId"
)

type Server struct {

	// The root server context
	ctx context.Context

	// A context-provided method for shutting down pending requests
	cancel context.CancelFunc

	// The list of registered endpoints
	endpoints []Endpoint

	// The logger for server messages
	Logger *log.Logger

	// The transport used for handling requests
	transport Transport

	// This waitgroup tracks ongoing requests so we can
	// properly drain them before terminating the server
	pending sync.WaitGroup
}

// Create a new server with default settings. One or more ServerOption
// may be specified to override defaults
func NewServer(transport Transport, options ...ServerOption) (*Server, error) {
	ctx, cancel := context.WithCancel(context.Background())

	// Create server with default settings
	server := &Server{
		ctx:       ctx,
		cancel:    cancel,
		endpoints: make([]Endpoint, 0),
		transport: transport,
		Logger:    log.New(os.Stderr, "", log.LstdFlags),
	}

	return server, server.SetOption(options...)
}

// Set one or more server options
func (srv *Server) SetOption(options ...ServerOption) error {
	// Apply any options
	for _, opt := range options {
		if err := opt(srv); err != nil {
			return err
		}
	}

	return nil
}

// Register a handler for requests to RPC endpoint identified by path. One
// or more EndpointOption may be specified to further customize the endpoint
func (srv *Server) Handle(path string, handler Handler, options ...EndpointOption) {
	ep := Endpoint{path, handler}

	// Apply any options
	for _, opt := range options {
		opt(&ep)
	}

	// Append to endpoint list
	srv.endpoints = append(srv.endpoints, ep)
}

// Dial the register transport srv.transport and then call Serve
// to start processing incoming RPC requests
func (srv *Server) ListenAndServe() error {
	var err error

	// Connect to transport
	err = srv.transport.Dial()
	if err != nil {
		return err
	}

	return srv.Serve()
}

// Bind each defined endpoint to srv.transport and process incoming connections
func (srv *Server) Serve() error {
	for _, ep := range srv.endpoints {

		binding, err := srv.transport.Bind(srv.ctx, ServerBinding, ep.Name)
		if err != nil {
			srv.Close()
			return err
		}

		srv.Logger.Printf("Bound to endpoint %s\n", ep.Name)
		go srv.serveEndpoint(binding.Messages, &ep)
	}

	// Block till our context is cancelled
	<-srv.ctx.Done()

	return nil
}

func (srv *Server) serveEndpoint(incoming <-chan TransportMessage, ep *Endpoint) {
	for {
		select {
		case trMsg, ok := <-incoming:
			if !ok {
				incoming = nil
				continue
			}
			srv.pending.Add(1)
			go func() {
				defer srv.pending.Done()

				// Create a new context with our endpoint name
				rctx := context.WithValue(srv.ctx, CtxCurEndpoint, ep.Name)

				// Serve the request and flush the response writer
				ep.Handler.Serve(rctx, trMsg.ResponseWriter, trMsg.Message)

				err := trMsg.ResponseWriter.Close()
				if err != nil {
					panic(err)
				}

			}()
		case <-srv.ctx.Done():
			return
		}
	}
}

func (srv *Server) Close() {

	srv.Logger.Printf("Server shutdown in progress; waiting for pending requests to drain\n")

	// Stop processing further requests and shutdown transport
	srv.cancel()

	// Drain pending requests
	srv.pending.Wait()
	srv.Logger.Printf("Server shutdown complete\n")
}
<commit_msg>Use a closure to spawn go-routines when iterating each defined endpoint<commit_after>package usrv

import (
	"errors"
	"golang.org/x/net/context"
	"log"
	"os"
	"sync"
)

// Errors introduced by RPC server
var (
	ErrTimeout      = errors.New("Request timeout")
	ErrResponseSent = errors.New("Response already sent")
)

// Context keys
const (
	CtxCurEndpoint = "curEndpoint"
	CtxTraceId     = "traceId"
)

type Server struct {

	// The root server context
	ctx context.Context

	// A context-provided method for shutting down pending requests
	cancel context.CancelFunc

	// The list of registered endpoints
	endpoints []Endpoint

	// The logger for server messages
	Logger *log.Logger

	// The transport used for handling requests
	transport Transport

	// This waitgroup tracks ongoing requests so we can
	// properly drain them before terminating the server
	pending sync.WaitGroup
}

// Create a new server with default settings. One or more ServerOption
// may be specified to override defaults
func NewServer(transport Transport, options ...ServerOption) (*Server, error) {
	ctx, cancel := context.WithCancel(context.Background())

	// Create server with default settings
	server := &Server{
		ctx:       ctx,
		cancel:    cancel,
		endpoints: make([]Endpoint, 0),
		transport: transport,
		Logger:    log.New(os.Stderr, "", log.LstdFlags),
	}

	return server, server.SetOption(options...)
}

// Set one or more server options
func (srv *Server) SetOption(options ...ServerOption) error {
	// Apply any options
	for _, opt := range options {
		if err := opt(srv); err != nil {
			return err
		}
	}

	return nil
}

// Register a handler for requests to RPC endpoint identified by path. One
// or more EndpointOption may be specified to further customize the endpoint
func (srv *Server) Handle(path string, handler Handler, options ...EndpointOption) {
	ep := Endpoint{path, handler}

	// Apply any options
	for _, opt := range options {
		opt(&ep)
	}

	// Append to endpoint list
	srv.endpoints = append(srv.endpoints, ep)
}

// Dial the register transport srv.transport and then call Serve
// to start processing incoming RPC requests
func (srv *Server) ListenAndServe() error {
	var err error

	// Connect to transport
	err = srv.transport.Dial()
	if err != nil {
		return err
	}

	return srv.Serve()
}

// Bind each defined endpoint to srv.transport and process incoming connections
func (srv *Server) Serve() error {
	for _, ep := range srv.endpoints {

		binding, err := srv.transport.Bind(srv.ctx, ServerBinding, ep.Name)
		if err != nil {
			srv.Close()
			return err
		}

		go func(queue <-chan TransportMessage, ep Endpoint){
			srv.serveEndpoint(queue, &ep)
		}(binding.Messages, ep)
	}

	// Block till our context is cancelled
	<-srv.ctx.Done()

	return nil
}

func (srv *Server) serveEndpoint(incoming <-chan TransportMessage, ep *Endpoint) {
	srv.Logger.Printf("Serving requests to endpoint %s\n", ep.Name)

	for {
		select {
		case trMsg, ok := <-incoming:
			if !ok {
				incoming = nil
				continue
			}
			srv.pending.Add(1)
			go func() {
				defer srv.pending.Done()

				// Create a new context with our endpoint name
				rctx := context.WithValue(srv.ctx, CtxCurEndpoint, ep.Name)

				// Serve the request and flush the response writer
				ep.Handler.Serve(rctx, trMsg.ResponseWriter, trMsg.Message)

				err := trMsg.ResponseWriter.Close()
				if err != nil {
					panic(err)
				}

			}()
		case <-srv.ctx.Done():
			return
		}
	}
}

func (srv *Server) Close() {

	srv.Logger.Printf("Server shutdown in progress; waiting for pending requests to drain\n")

	// Stop processing further requests and shutdown transport
	srv.cancel()

	// Drain pending requests
	srv.pending.Wait()
	srv.Logger.Printf("Server shutdown complete\n")
}
<|endoftext|>


<commit_before>package mass

// An Interface reprsenting a real-valued statistical model.
type Model interface {
	Eval(interface{}) float64
}

// Map a real-valued statistical model over a collection of input data.
func Map(m Model, inputs []interface{}) Slice {
	outputs := make(Slice, len(inputs))
	for i, x := range inputs {
		outputs.Set(i, x, m.Eval(x))
	}
	return outputs
}
<commit_msg>Add MapPair and tweak Map functions for StatModel.<commit_after>package mass

// An Model interface a real-valued statistical model.
type StatModel interface {
	Eval(interface{}) float64
}

// Map a real-valued statistical model over a collection of input data.
func MapPairs(m StatModel, inputs []interface{}) Slice {
	outputs := make(Slice, len(inputs))
	for i, x := range inputs {
		outputs.Set(i, x, m.Eval(x))
	}
	return outputs
}

func Map(m StatModel, inputs []interface{}) []float64 {
	outputs := make([]float64, len(inputs))
	for i, x := range inputs {
		outputs[i] = m.Eval(x)
	}
	return outputs
}
<|endoftext|>


<commit_before>package main

import (
	"bitbucket.org/bertimus9/systemstat"
	"flag"
	"fmt"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/fsouza/go-dockerclient"
	"github.com/go-martini/martini"
	"net/http"
	"strconv"
)

type MonitorSample struct {
	Name     string  `json:"name"`
	CpuPct   float64 `json:"cpu_percent"`
	MemUsed  uint64  `json:"mem_used"`
	MemTotal uint64  `json:"mem_total"`
}

func getSystemMonitorSample() MonitorSample {
	cpuSample := systemstat.GetCPUSample()
	idle := float64(cpuSample.Idle)
	total := float64(cpuSample.Total)

	memSample := systemstat.GetMemSample()

	var stat MonitorSample
	stat.Name = "System"
	stat.CpuPct = (total - idle) * 100.0 / total
	stat.MemTotal = memSample.MemTotal
	stat.MemUsed = memSample.MemUsed
	return stat
}

func getContainerMonitorSample(name string) (MonitorSample, error) {
	var stat MonitorSample
	dockerStats := make(chan *docker.Stats)
	errC := make(chan error, 1)
	go func() {
		errC <- client.Stats(docker.StatsOptions{name, dockerStats})
		close(errC)
	}()
	statsResult, ok := <-dockerStats
	if !ok {
		return stat, <-errC
	}
	fmt.Printf("%+v", statsResult)
	stat.Name = name
	stat.CpuPct = float64(statsResult.CPUStats.CPUUsage.TotalUsage)
	stat.MemTotal = statsResult.MemoryStats.Limit
	stat.MemUsed = statsResult.MemoryStats.Usage
	return stat, nil
}

var client *docker.Client

func main() {
	var port int
	flag.IntVar(&port, "port", 3001, "server port")
	flag.Parse()
	fmt.Println("Port: ", port)

	endpoint := "unix:///var/run/docker.sock"
	var err error
	client, err = docker.NewClient(endpoint)
	if err != nil {
		panic(err)
	}

	m := martini.Classic()
	m.Use(render.Renderer())

	m.Get("/", func(r render.Render) {
		r.JSON(http.StatusOK, getSystemMonitorSample())
	})

	m.Get("/:name", func(args martini.Params, r render.Render) {
		name := args["name"]
		sample, err := getContainerMonitorSample(name)
		if err == nil {
			r.JSON(http.StatusOK, sample)
		} else {
			r.JSON(http.StatusBadRequest, err)
		}
	})

	http.Handle("/", m)
	http.ListenAndServe(":"+strconv.Itoa(port), nil)
}
<commit_msg>remove not working cpu percent for apps<commit_after>package main

import (
	"bitbucket.org/bertimus9/systemstat"
	"flag"
	"fmt"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/fsouza/go-dockerclient"
	"github.com/go-martini/martini"
	"net/http"
	"strconv"
)

type MonitorSample struct {
	Name     string  `json:"name"`
	CpuPct   float64 `json:"cpu_percent,omitempty"`
	MemUsed  uint64  `json:"mem_used"`
	MemTotal uint64  `json:"mem_total"`
}

func getSystemMonitorSample() MonitorSample {
	cpuSample := systemstat.GetCPUSample()
	idle := float64(cpuSample.Idle)
	total := float64(cpuSample.Total)

	memSample := systemstat.GetMemSample()

	var stat MonitorSample
	stat.Name = "system"
	stat.CpuPct = (total - idle) * 100.0 / total
	stat.MemTotal = memSample.MemTotal
	stat.MemUsed = memSample.MemUsed
	return stat
}

func getContainerMonitorSample(name string) (MonitorSample, error) {
	var stat MonitorSample
	dockerStats := make(chan *docker.Stats)
	errC := make(chan error, 1)
	go func() {
		errC <- client.Stats(docker.StatsOptions{name, dockerStats})
		close(errC)
	}()

	statsResult, ok := <-dockerStats
	if !ok {
		return stat, <-errC
	}
	stat.Name = name
	stat.MemTotal = statsResult.MemoryStats.Limit
	stat.MemUsed = statsResult.MemoryStats.Usage
	return stat, nil
}

var client *docker.Client

func main() {
	var port int
	flag.IntVar(&port, "port", 3001, "server port")
	flag.Parse()
	fmt.Println("Port: ", port)

	endpoint := "unix:///var/run/docker.sock"
	var err error
	client, err = docker.NewClient(endpoint)
	if err != nil {
		panic(err)
	}

	m := martini.Classic()
	m.Use(render.Renderer())

	m.Get("/", func(r render.Render) {
		r.JSON(http.StatusOK, getSystemMonitorSample())
	})

	m.Get("/:name", func(args martini.Params, r render.Render) {
		name := args["name"]
		sample, err := getContainerMonitorSample(name)
		if err == nil {
			r.JSON(http.StatusOK, sample)
		} else {
			r.JSON(http.StatusBadRequest, err)
		}
	})

	http.Handle("/", m)
	http.ListenAndServe(":"+strconv.Itoa(port), nil)
}
<|endoftext|>


<commit_before>package auth551

import (
	"database/sql"
	"github.com/go51/model551"
	"time"
)

//--[ User Model ]--------
type UserModel struct {
	Id             int64 `db_table:"users"`
	CreatedAt      time.Time
	UpdatedAt      time.Time
	Locked         bool
	Enabled        bool
	Name           string
	Email          string
	EmailCanonical string
	PasswordSalt   string
	Password       string
	Thumbnail      string
	Serial         string
	DeletedAt      time.Time `db_delete:"true"`
}

func NewUserModel() interface{} {
	return UserModel{}
}

func NewUserModelPointer() interface{} {
	return &UserModel{}
}

func (m *UserModel) SetId(id int64) {
	m.Id = id
}

func (m *UserModel) GetId() int64 {
	return m.Id
}

func (m *UserModel) Scan(rows *sql.Rows) error {
	return rows.Scan(
		&m.Id,
		&m.CreatedAt,
		&m.UpdatedAt,
		&m.Locked,
		&m.Enabled,
		&m.Name,
		&m.Email,
		&m.EmailCanonical,
		&m.PasswordSalt,
		&m.Password,
		&m.Thumbnail,
		&m.Serial,
	)
}

func (m *UserModel) SqlValues(sqlType model551.SqlType) []interface{} {
	values := make([]interface{}, 0, 13)

	if sqlType == model551.SQL_LOGICAL_DELETE {
		values = append(values, m.Id)
	}
	if sqlType == model551.SQL_INSERT {
		m.CreatedAt = time.Now()
		m.UpdatedAt = m.CreatedAt
	}
	if sqlType == model551.SQL_UPDATE {
		m.UpdatedAt = time.Now()
	}
	values = append(values, m.CreatedAt)
	values = append(values, m.UpdatedAt)
	values = append(values, m.Locked)
	values = append(values, m.Enabled)
	values = append(values, m.Name)
	values = append(values, m.Email)
	values = append(values, m.EmailCanonical)
	values = append(values, m.PasswordSalt)
	values = append(values, m.PasswordSalt)
	values = append(values, m.Thumbnail)
	values = append(values, m.Serial)

	if sqlType == model551.SQL_UPDATE {
		values = append(values, m.Id)
	} else if sqlType == model551.SQL_LOGICAL_DELETE {
		m.DeletedAt = time.Now()
		values = append(values, m.DeletedAt)
	}

	return values

}

//--[/User Model ]--------

//--[ User Token Model ]--------
type UserTokenModel struct {
	Id           int64 `db_table:"user_tokens"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
	UserId       int64
	Vendor       string
	AccessToken  string
	TokenSecret  string
	Expiry       time.Time
	RefreshToken string
	TokenType    string
	AccountId    string
	Name         string
	Thumbnail    string
	DeletedAt    time.Time `db_delete:"true"`
}

func NewUserTokenModel() interface{} {
	return UserTokenModel{}
}

func NewUserTokenModelPointer() interface{} {
	return &UserTokenModel{}
}

func (m *UserTokenModel) SetId(id int64) {
	m.Id = id
}

func (m *UserTokenModel) GetId() int64 {
	return m.Id
}

func (m *UserTokenModel) Scan(rows *sql.Rows) error {
	return rows.Scan(
		&m.Id,
		&m.CreatedAt,
		&m.UpdatedAt,
		&m.UserId,
		&m.Vendor,
		&m.AccessToken,
		&m.TokenSecret,
		&m.Expiry,
		&m.RefreshToken,
		&m.TokenType,
		&m.AccountId,
		&m.Name,
		&m.Thumbnail,
	)
}

func (m *UserTokenModel) SqlValues(sqlType model551.SqlType) []interface{} {
	values := make([]interface{}, 0, 11)

	if sqlType == model551.SQL_LOGICAL_DELETE {
		values = append(values, m.Id)
	}
	if sqlType == model551.SQL_INSERT {
		m.CreatedAt = time.Now()
		m.UpdatedAt = m.CreatedAt
	}
	if sqlType == model551.SQL_UPDATE {
		m.UpdatedAt = time.Now()
	}
	values = append(values, m.CreatedAt)
	values = append(values, m.UpdatedAt)
	values = append(values, m.UserId)
	values = append(values, m.Vendor)
	values = append(values, m.AccessToken)
	values = append(values, m.TokenSecret)
	values = append(values, m.Expiry)
	values = append(values, m.RefreshToken)
	values = append(values, m.TokenType)
	values = append(values, m.AccountId)
	values = append(values, m.Name)
	values = append(values, m.Thumbnail)

	if sqlType == model551.SQL_UPDATE {
		values = append(values, m.Id)
	} else if sqlType == model551.SQL_LOGICAL_DELETE {
		m.DeletedAt = time.Now()
		values = append(values, m.DeletedAt)
	}

	return values
}

//--[/User Token Model ]--------

//--[ Access Token Model ]--------
type AccessToken struct {
	AccessToken  string
	TokenSecret  string
	TokenType    string
	RefreshToken string
	Expiry       time.Time
}

//--[/Access Token Model ]--------

//--[ Access Token Model ]--------
type AccountInformation struct {
	Id      string
	Name    string
	Email   string
	Picture string
}

//--[/Access Token Model ]--------
<commit_msg>refs #53 users テーブル登録時に password に password_salt が同じ内容で更新されている<commit_after>package auth551

import (
	"database/sql"
	"github.com/go51/model551"
	"time"
)

//--[ User Model ]--------
type UserModel struct {
	Id             int64 `db_table:"users"`
	CreatedAt      time.Time
	UpdatedAt      time.Time
	Locked         bool
	Enabled        bool
	Name           string
	Email          string
	EmailCanonical string
	PasswordSalt   string
	Password       string
	Thumbnail      string
	Serial         string
	DeletedAt      time.Time `db_delete:"true"`
}

func NewUserModel() interface{} {
	return UserModel{}
}

func NewUserModelPointer() interface{} {
	return &UserModel{}
}

func (m *UserModel) SetId(id int64) {
	m.Id = id
}

func (m *UserModel) GetId() int64 {
	return m.Id
}

func (m *UserModel) Scan(rows *sql.Rows) error {
	return rows.Scan(
		&m.Id,
		&m.CreatedAt,
		&m.UpdatedAt,
		&m.Locked,
		&m.Enabled,
		&m.Name,
		&m.Email,
		&m.EmailCanonical,
		&m.PasswordSalt,
		&m.Password,
		&m.Thumbnail,
		&m.Serial,
	)
}

func (m *UserModel) SqlValues(sqlType model551.SqlType) []interface{} {
	values := make([]interface{}, 0, 13)

	if sqlType == model551.SQL_LOGICAL_DELETE {
		values = append(values, m.Id)
	}
	if sqlType == model551.SQL_INSERT {
		m.CreatedAt = time.Now()
		m.UpdatedAt = m.CreatedAt
	}
	if sqlType == model551.SQL_UPDATE {
		m.UpdatedAt = time.Now()
	}
	values = append(values, m.CreatedAt)
	values = append(values, m.UpdatedAt)
	values = append(values, m.Locked)
	values = append(values, m.Enabled)
	values = append(values, m.Name)
	values = append(values, m.Email)
	values = append(values, m.EmailCanonical)
	values = append(values, m.PasswordSalt)
	values = append(values, m.Password)
	values = append(values, m.Thumbnail)
	values = append(values, m.Serial)

	if sqlType == model551.SQL_UPDATE {
		values = append(values, m.Id)
	} else if sqlType == model551.SQL_LOGICAL_DELETE {
		m.DeletedAt = time.Now()
		values = append(values, m.DeletedAt)
	}

	return values

}

//--[/User Model ]--------

//--[ User Token Model ]--------
type UserTokenModel struct {
	Id           int64 `db_table:"user_tokens"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
	UserId       int64
	Vendor       string
	AccessToken  string
	TokenSecret  string
	Expiry       time.Time
	RefreshToken string
	TokenType    string
	AccountId    string
	Name         string
	Thumbnail    string
	DeletedAt    time.Time `db_delete:"true"`
}

func NewUserTokenModel() interface{} {
	return UserTokenModel{}
}

func NewUserTokenModelPointer() interface{} {
	return &UserTokenModel{}
}

func (m *UserTokenModel) SetId(id int64) {
	m.Id = id
}

func (m *UserTokenModel) GetId() int64 {
	return m.Id
}

func (m *UserTokenModel) Scan(rows *sql.Rows) error {
	return rows.Scan(
		&m.Id,
		&m.CreatedAt,
		&m.UpdatedAt,
		&m.UserId,
		&m.Vendor,
		&m.AccessToken,
		&m.TokenSecret,
		&m.Expiry,
		&m.RefreshToken,
		&m.TokenType,
		&m.AccountId,
		&m.Name,
		&m.Thumbnail,
	)
}

func (m *UserTokenModel) SqlValues(sqlType model551.SqlType) []interface{} {
	values := make([]interface{}, 0, 11)

	if sqlType == model551.SQL_LOGICAL_DELETE {
		values = append(values, m.Id)
	}
	if sqlType == model551.SQL_INSERT {
		m.CreatedAt = time.Now()
		m.UpdatedAt = m.CreatedAt
	}
	if sqlType == model551.SQL_UPDATE {
		m.UpdatedAt = time.Now()
	}
	values = append(values, m.CreatedAt)
	values = append(values, m.UpdatedAt)
	values = append(values, m.UserId)
	values = append(values, m.Vendor)
	values = append(values, m.AccessToken)
	values = append(values, m.TokenSecret)
	values = append(values, m.Expiry)
	values = append(values, m.RefreshToken)
	values = append(values, m.TokenType)
	values = append(values, m.AccountId)
	values = append(values, m.Name)
	values = append(values, m.Thumbnail)

	if sqlType == model551.SQL_UPDATE {
		values = append(values, m.Id)
	} else if sqlType == model551.SQL_LOGICAL_DELETE {
		m.DeletedAt = time.Now()
		values = append(values, m.DeletedAt)
	}

	return values
}

//--[/User Token Model ]--------

//--[ Access Token Model ]--------
type AccessToken struct {
	AccessToken  string
	TokenSecret  string
	TokenType    string
	RefreshToken string
	Expiry       time.Time
}

//--[/Access Token Model ]--------

//--[ Access Token Model ]--------
type AccountInformation struct {
	Id      string
	Name    string
	Email   string
	Picture string
}

//--[/Access Token Model ]--------
<|endoftext|>


<commit_before>package copper

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/http"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type lowLevelServer interface {
	subscribe(settings SubscribeSettings) (int64, error)
	getEndpoints(targetID int64) ([]Endpoint, error)
	streamEndpoints(targetID int64) (EndpointChangesStream, error)
	unsubscribe(targetID int64) error
	publish(targetID int64, name string, settings PublishSettings) error
	unpublish(targetID int64) error
	setRoute(name string, routes ...Route) error
	listRoutes() ([]string, error)
	lookupRoute(name string) ([]Route, error)
	streamServices() (ServiceChangesStream, error)
}

type handleRequestStatus int

const (
	// Request was handled and the stream consumed
	handleRequestStatusDone handleRequestStatus = iota
	// There was an attempt to handle the request, but it was impossible, and
	// future requests are unlikely to succeed. While the stream was not
	// consumed this status implies that locks had been unlocked and
	// configuration has changed.
	handleRequestStatusImpossible
	// There was not enough capacity to handle the request
	handleRequestStatusOverCapacity
	// There was no route to send the request to
	handleRequestStatusNoRoute
)

type handleRequestCallback func(remote Stream) handleRequestStatus

type endpointReference interface {
	getEndpointsLocked() []Endpoint
	handleRequestLocked(callback handleRequestCallback) handleRequestStatus
}

type server struct {
	lock   sync.Mutex
	random *rand.Rand

	lastTargetID int64

	peers map[serverPeerKey]*serverPeer

	subsByName map[string]map[*serverSubscription]struct{}

	pubByTarget map[int64]*serverPublication
	pubsByName  map[string]map[uint32]*serverPublication
	pubWatchers map[*serverServiceChangesStream]struct{}

	routeByName map[string]*serverRoute

	failure    error
	closedchan chan struct{}
	finishchan chan struct{}
	listenwg   sync.WaitGroup
	clientwg   sync.WaitGroup
	listeners  []net.Listener

	clients map[*serverClient]struct{}
}

// NewServer returns a new local server
func NewServer() Server {
	s := &server{
		random: rand.New(rand.NewSource(time.Now().UnixNano())),

		peers: make(map[serverPeerKey]*serverPeer),

		subsByName: make(map[string]map[*serverSubscription]struct{}),

		pubByTarget: make(map[int64]*serverPublication),
		pubsByName:  make(map[string]map[uint32]*serverPublication),
		pubWatchers: make(map[*serverServiceChangesStream]struct{}),

		routeByName: make(map[string]*serverRoute),

		closedchan: make(chan struct{}),

		clients: make(map[*serverClient]struct{}),
	}
	return s
}

func (s *server) allocateTargetID() int64 {
	return atomic.AddInt64(&s.lastTargetID, 1)
}

func (s *server) closeWithError(err error) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if err == nil {
		err = ECONNCLOSED
	}
	preverror := s.failure
	if s.failure == nil {
		s.failure = err
		listeners := s.listeners
		s.listeners = nil
		for _, listener := range listeners {
			listener.Close()
		}
		for _, peer := range s.peers {
			peer.closeWithErrorLocked(err)
		}
		for client := range s.clients {
			client.closeWithErrorLocked(err)
		}
		for cs := range s.pubWatchers {
			cs.stopLocked()
		}
	}
	return preverror
}

func (s *server) addClient(conn net.Conn, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		conn.Close()
		return s.failure
	}
	client := newServerClient(s, conn, allowChanges)
	s.clients[client] = struct{}{}
	return nil
}

func (s *server) acceptor(listener net.Listener, allowChanges bool) {
	defer s.listenwg.Done()
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			s.closeWithError(err)
			return
		}
		err = s.addClient(conn, allowChanges)
		if err != nil {
			s.closeWithError(err)
			return
		}
	}
}

func (s *server) findEndpointLocked(name string, minDistance, maxDistance uint32) (endpoint endpointReference) {
	var minPriority uint32
	route := s.routeByName[name]
	if route != nil {
		return route
	}
	pubs := s.pubsByName[name]
	if len(pubs) > 0 {
		for _, pub := range pubs {
			if pub.settings.Distance < minDistance || pub.settings.Distance > maxDistance {
				continue
			}
			if endpoint == nil || pub.settings.Priority < minPriority {
				if pub.settings.Priority == 0 {
					return pub
				}
				endpoint = pub
				minPriority = pub.settings.Priority
			}
		}
		if endpoint != nil {
			return endpoint
		}
	}
	for _, peer := range s.peers {
		remotes := peer.remotesByName[name]
		if len(remotes) > 0 {
			for _, remote := range remotes {
				if remote.settings.Distance < minDistance || remote.settings.Distance > maxDistance {
					continue
				}
				if endpoint == nil || remote.settings.Priority < minPriority {
					if remote.settings.Priority == 0 {
						return remote
					}
					endpoint = remote
					minPriority = remote.settings.Priority
				}
			}
		}
	}
	return endpoint
}

func (s *server) findEndpointHTTPLocked(path string) (endpoint endpointReference) {
	if len(path) == 0 {
		path = "/"
	} else if path[0] != '/' {
		path = "/" + path
	}
	for len(path) > 0 {
		endpoint = s.findEndpointLocked("http:"+path, 0, 1)
		if endpoint != nil {
			return endpoint
		}
		endpoint = s.findEndpointLocked("http:"+path, 2, 2)
		if endpoint != nil {
			return endpoint
		}
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		}
		index := strings.LastIndex(path, "/")
		if index == -1 {
			break
		}
		path = path[:index+1]
	}
	return nil
}

// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

func copyHeaders(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func (s *server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	status := func() handleRequestStatus {
		s.lock.Lock()
		defer s.lock.Unlock()
		var endpoint endpointReference
		service := req.Header.Get("X-Copper-Service")
		if len(service) != 0 {
			endpoint = s.findEndpointLocked("http:"+service, 0, 1)
			if endpoint == nil {
				endpoint = s.findEndpointLocked("http:"+service, 2, 2)
			}
		} else {
			endpoint = s.findEndpointHTTPLocked(req.URL.Path)
		}
		if endpoint == nil {
			return handleRequestStatusNoRoute
		}
		return endpoint.handleRequestLocked(func(remote Stream) handleRequestStatus {
			outreq := new(http.Request)
			*outreq = *req
			modified := false
			for _, h := range hopHeaders {
				if len(outreq.Header[h]) > 0 {
					if !modified {
						outreq.Header = make(http.Header)
						copyHeaders(outreq.Header, req.Header)
					}
					delete(outreq.Header, h)
				}
			}
			go func() {
				err := outreq.Write(remote)
				if err != nil {
					remote.CloseWithError(err)
				}
			}()
			r := bufio.NewReader(remote)
			res, err := http.ReadResponse(r, outreq)
			if err == nil && res.StatusCode == 100 {
				// Skip 100-continue
				res, err = http.ReadResponse(r, outreq)
			}
			if err != nil {
				remote.CloseWithError(err)
				text := err.Error()
				rw.Header().Set("Content-Length", fmt.Sprintf("%d", len(text)))
				rw.WriteHeader(502)
				rw.Write([]byte(text))
			} else {
				defer res.Body.Close()
				copyHeaders(rw.Header(), res.Header)
				rw.WriteHeader(res.StatusCode)
				io.Copy(rw, res.Body)
			}
			return handleRequestStatusDone
		})
	}()
	if status != handleRequestStatusDone {
		rw.WriteHeader(404)
	}
}

func (s *server) httpacceptor(listener net.Listener) {
	defer s.listenwg.Done()
	defer listener.Close()
	httpserver := &http.Server{
		Handler: s,
	}
	err := httpserver.Serve(listener)
	if err != nil {
		s.closeWithError(err)
		return
	}
}

func (s *server) AddPeer(network, address string, distance uint32) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	return s.addPeerLocked(network, address, distance)
}

func (s *server) AddListener(listener net.Listener, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.acceptor(listener, allowChanges)
	return nil
}

func (s *server) AddHTTPListener(listener net.Listener) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.httpacceptor(listener)
	return nil
}

func (s *server) SetUpstream(upstream Client) error {
	return EUNSUPPORTED
}

func (s *server) Err() error {
	s.lock.Lock()
	defer s.lock.Unlock()
	return s.failure
}

func (s *server) Close() error {
	return s.closeWithError(ECONNSHUTDOWN)
}

func (s *server) Done() <-chan struct{} {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.finishchan == nil {
		s.finishchan = make(chan struct{})
		go func() {
			defer close(s.finishchan)
			s.listenwg.Wait()
			s.clientwg.Wait()
		}()
	}
	return s.finishchan
}

func (s *server) Closed() <-chan struct{} {
	return s.closedchan
}
<commit_msg>Use remote peers in case they have better priority<commit_after>package copper

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/http"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type lowLevelServer interface {
	subscribe(settings SubscribeSettings) (int64, error)
	getEndpoints(targetID int64) ([]Endpoint, error)
	streamEndpoints(targetID int64) (EndpointChangesStream, error)
	unsubscribe(targetID int64) error
	publish(targetID int64, name string, settings PublishSettings) error
	unpublish(targetID int64) error
	setRoute(name string, routes ...Route) error
	listRoutes() ([]string, error)
	lookupRoute(name string) ([]Route, error)
	streamServices() (ServiceChangesStream, error)
}

type handleRequestStatus int

const (
	// Request was handled and the stream consumed
	handleRequestStatusDone handleRequestStatus = iota
	// There was an attempt to handle the request, but it was impossible, and
	// future requests are unlikely to succeed. While the stream was not
	// consumed this status implies that locks had been unlocked and
	// configuration has changed.
	handleRequestStatusImpossible
	// There was not enough capacity to handle the request
	handleRequestStatusOverCapacity
	// There was no route to send the request to
	handleRequestStatusNoRoute
)

type handleRequestCallback func(remote Stream) handleRequestStatus

type endpointReference interface {
	getEndpointsLocked() []Endpoint
	handleRequestLocked(callback handleRequestCallback) handleRequestStatus
}

type server struct {
	lock   sync.Mutex
	random *rand.Rand

	lastTargetID int64

	peers map[serverPeerKey]*serverPeer

	subsByName map[string]map[*serverSubscription]struct{}

	pubByTarget map[int64]*serverPublication
	pubsByName  map[string]map[uint32]*serverPublication
	pubWatchers map[*serverServiceChangesStream]struct{}

	routeByName map[string]*serverRoute

	failure    error
	closedchan chan struct{}
	finishchan chan struct{}
	listenwg   sync.WaitGroup
	clientwg   sync.WaitGroup
	listeners  []net.Listener

	clients map[*serverClient]struct{}
}

// NewServer returns a new local server
func NewServer() Server {
	s := &server{
		random: rand.New(rand.NewSource(time.Now().UnixNano())),

		peers: make(map[serverPeerKey]*serverPeer),

		subsByName: make(map[string]map[*serverSubscription]struct{}),

		pubByTarget: make(map[int64]*serverPublication),
		pubsByName:  make(map[string]map[uint32]*serverPublication),
		pubWatchers: make(map[*serverServiceChangesStream]struct{}),

		routeByName: make(map[string]*serverRoute),

		closedchan: make(chan struct{}),

		clients: make(map[*serverClient]struct{}),
	}
	return s
}

func (s *server) allocateTargetID() int64 {
	return atomic.AddInt64(&s.lastTargetID, 1)
}

func (s *server) closeWithError(err error) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if err == nil {
		err = ECONNCLOSED
	}
	preverror := s.failure
	if s.failure == nil {
		s.failure = err
		listeners := s.listeners
		s.listeners = nil
		for _, listener := range listeners {
			listener.Close()
		}
		for _, peer := range s.peers {
			peer.closeWithErrorLocked(err)
		}
		for client := range s.clients {
			client.closeWithErrorLocked(err)
		}
		for cs := range s.pubWatchers {
			cs.stopLocked()
		}
	}
	return preverror
}

func (s *server) addClient(conn net.Conn, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		conn.Close()
		return s.failure
	}
	client := newServerClient(s, conn, allowChanges)
	s.clients[client] = struct{}{}
	return nil
}

func (s *server) acceptor(listener net.Listener, allowChanges bool) {
	defer s.listenwg.Done()
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			s.closeWithError(err)
			return
		}
		err = s.addClient(conn, allowChanges)
		if err != nil {
			s.closeWithError(err)
			return
		}
	}
}

func (s *server) findEndpointLocked(name string, minDistance, maxDistance uint32) (endpoint endpointReference) {
	var minPriority uint32
	route := s.routeByName[name]
	if route != nil {
		return route
	}
	pubs := s.pubsByName[name]
	if len(pubs) > 0 {
		for _, pub := range pubs {
			if pub.settings.Distance < minDistance || pub.settings.Distance > maxDistance {
				continue
			}
			if endpoint == nil || pub.settings.Priority < minPriority {
				if pub.settings.Priority == 0 {
					return pub
				}
				endpoint = pub
				minPriority = pub.settings.Priority
			}
		}
	}
	for _, peer := range s.peers {
		remotes := peer.remotesByName[name]
		if len(remotes) > 0 {
			for _, remote := range remotes {
				if remote.settings.Distance < minDistance || remote.settings.Distance > maxDistance {
					continue
				}
				if endpoint == nil || remote.settings.Priority < minPriority {
					if remote.settings.Priority == 0 {
						return remote
					}
					endpoint = remote
					minPriority = remote.settings.Priority
				}
			}
		}
	}
	return endpoint
}

func (s *server) findEndpointHTTPLocked(path string) (endpoint endpointReference) {
	if len(path) == 0 {
		path = "/"
	} else if path[0] != '/' {
		path = "/" + path
	}
	for len(path) > 0 {
		endpoint = s.findEndpointLocked("http:"+path, 0, 1)
		if endpoint != nil {
			return endpoint
		}
		endpoint = s.findEndpointLocked("http:"+path, 2, 2)
		if endpoint != nil {
			return endpoint
		}
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		}
		index := strings.LastIndex(path, "/")
		if index == -1 {
			break
		}
		path = path[:index+1]
	}
	return nil
}

// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

func copyHeaders(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func (s *server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	status := func() handleRequestStatus {
		s.lock.Lock()
		defer s.lock.Unlock()
		var endpoint endpointReference
		service := req.Header.Get("X-Copper-Service")
		if len(service) != 0 {
			endpoint = s.findEndpointLocked("http:"+service, 0, 1)
			if endpoint == nil {
				endpoint = s.findEndpointLocked("http:"+service, 2, 2)
			}
		} else {
			endpoint = s.findEndpointHTTPLocked(req.URL.Path)
		}
		if endpoint == nil {
			return handleRequestStatusNoRoute
		}
		return endpoint.handleRequestLocked(func(remote Stream) handleRequestStatus {
			outreq := new(http.Request)
			*outreq = *req
			modified := false
			for _, h := range hopHeaders {
				if len(outreq.Header[h]) > 0 {
					if !modified {
						outreq.Header = make(http.Header)
						copyHeaders(outreq.Header, req.Header)
					}
					delete(outreq.Header, h)
				}
			}
			go func() {
				err := outreq.Write(remote)
				if err != nil {
					remote.CloseWithError(err)
				}
			}()
			r := bufio.NewReader(remote)
			res, err := http.ReadResponse(r, outreq)
			if err == nil && res.StatusCode == 100 {
				// Skip 100-continue
				res, err = http.ReadResponse(r, outreq)
			}
			if err != nil {
				remote.CloseWithError(err)
				text := err.Error()
				rw.Header().Set("Content-Length", fmt.Sprintf("%d", len(text)))
				rw.WriteHeader(502)
				rw.Write([]byte(text))
			} else {
				defer res.Body.Close()
				copyHeaders(rw.Header(), res.Header)
				rw.WriteHeader(res.StatusCode)
				io.Copy(rw, res.Body)
			}
			return handleRequestStatusDone
		})
	}()
	if status != handleRequestStatusDone {
		rw.WriteHeader(404)
	}
}

func (s *server) httpacceptor(listener net.Listener) {
	defer s.listenwg.Done()
	defer listener.Close()
	httpserver := &http.Server{
		Handler: s,
	}
	err := httpserver.Serve(listener)
	if err != nil {
		s.closeWithError(err)
		return
	}
}

func (s *server) AddPeer(network, address string, distance uint32) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	return s.addPeerLocked(network, address, distance)
}

func (s *server) AddListener(listener net.Listener, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.acceptor(listener, allowChanges)
	return nil
}

func (s *server) AddHTTPListener(listener net.Listener) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.httpacceptor(listener)
	return nil
}

func (s *server) SetUpstream(upstream Client) error {
	return EUNSUPPORTED
}

func (s *server) Err() error {
	s.lock.Lock()
	defer s.lock.Unlock()
	return s.failure
}

func (s *server) Close() error {
	return s.closeWithError(ECONNSHUTDOWN)
}

func (s *server) Done() <-chan struct{} {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.finishchan == nil {
		s.finishchan = make(chan struct{})
		go func() {
			defer close(s.finishchan)
			s.listenwg.Wait()
			s.clientwg.Wait()
		}()
	}
	return s.finishchan
}

func (s *server) Closed() <-chan struct{} {
	return s.closedchan
}
<|endoftext|>


<commit_before>// spdy/server.go

package spdy

import (
	"bytes"
	"encoding/binary"
	"http"
	"io"
	"net"
	"os"
	"strconv"
	"sync"
)

type Server struct {
	Addr    string
	Handler http.Handler
}

func (srv *Server) ListenAndServe() os.Error {
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(l)
}

func (srv *Server) Serve(l net.Listener) os.Error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		s, err := newSession(c, handler)
		if err != nil {
			return err
		}
		go s.serve()
	}
	return nil
}

type session struct {
	c           net.Conn
	handler     http.Handler
	in, out     chan Frame
	streams     map[uint32]*serverStream
	streamsLock sync.RWMutex
}

func newSession(c net.Conn, h http.Handler) (s *session, err os.Error) {
	s = &session{
		c:       c,
		handler: h,
		in:      make(chan Frame),
		out:     make(chan Frame),
		streams: make(map[uint32]*serverStream),
	}
	return
}

func (sess *session) serve() {
	defer sess.c.Close()
	go sess.sendFrames()
	go sess.receiveFrames()

	for {
		select {
		case f := <-sess.in:
			switch frame := f.(type) {
			case ControlFrame:
				sess.handleControl(frame)
			case DataFrame:
				sess.handleData(frame)
			}
		}
	}
}

func (sess *session) handleControl(frame ControlFrame) {
	switch frame.Type {
	case TypeSynStream:
		sess.streamsLock.Lock()
		defer sess.streamsLock.Unlock()
		if stream, err := newServerStream(sess, frame); err == nil {
			if _, exists := sess.streams[stream.id]; !exists {
				sess.streams[stream.id] = stream
				go stream.bufferReads()
				go sess.handler.ServeHTTP(stream, stream.Request())
			}
		}
	}
}

func (sess *session) handleData(frame DataFrame) {
	sess.streamsLock.RLock()
	defer sess.streamsLock.RUnlock()

	st, found := sess.streams[frame.StreamID]
	if !found {
		// TODO: Error?
		return
	}
	if st.readChan != nil {
		st.readChan <- frame
		if frame.Flags&FlagFin != 0 {
			close(st.readChan)
		}
	}
}

func (sess *session) sendFrames() {
	for frame := range sess.out {
		// TODO: Check for errors
		frame.WriteTo(sess.c)
	}
}

func (sess *session) receiveFrames() {
	defer close(sess.in)
	for {
		frame, err := ReadFrame(sess.c)
		if err != nil {
			return
		}
		sess.in <- frame
	}
}

type serverStream struct {
	id      uint32
	session *session
	closed  bool

	headerReader   *HeaderReader
	requestHeaders http.Header

	headerWriter    *HeaderWriter
	responseHeaders http.Header
	wroteHeader     bool

	readChan   chan DataFrame
	readBuffer *bytes.Buffer
	readLock   sync.Mutex

	lastWrite Frame
}

func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err os.Error) {
	if frame.Type != TypeSynStream {
		err = os.NewError("Server stream must be created from a SynStream frame")
		return
	}
	st = &serverStream{
		session:         sess,
		headerReader:    NewHeaderReader(),
		headerWriter:    NewHeaderWriter(-1),
		responseHeaders: make(http.Header),
	}
	if frame.Flags&FlagFin == 0 {
		// Request body will follow
		st.readChan = make(chan DataFrame)
		st.readBuffer = new(bytes.Buffer)
	}
	// Read frame data
	data := bytes.NewBuffer(frame.Data)
	err = binary.Read(data, binary.BigEndian, &st.id)
	if err != nil {
		return
	}
	_, err = io.ReadFull(data, make([]byte, 6)) // skip associated stream ID and priority
	if err != nil {
		return
	}
	st.requestHeaders, err = st.headerReader.Decode(data.Bytes())
	return
}

func (st *serverStream) bufferReads() {
	for frame := range st.readChan {
		st.readLock.Lock()
		st.readBuffer.Write(frame.Data)
		st.readLock.Unlock()
	}
	st.readChan = nil
}

// Request returns the request data associated with the serverStream.
func (st *serverStream) Request() (req *http.Request) {
	// TODO
	req = &http.Request{
		Method:     st.requestHeaders.Get("method"),
		RawURL:     st.requestHeaders.Get("url"),
		Proto:      st.requestHeaders.Get("version"),
		Header:     st.requestHeaders,
		Body:       st,
		RemoteAddr: st.session.c.RemoteAddr().String(),
	}
	return
}

func (st *serverStream) Read(p []byte) (n int, err os.Error) {
	st.readLock.Lock()
	defer st.readLock.Unlock()
	if st.readBuffer.Len() == 0 {
		if st.readChan == nil {
			return 0, os.EOF
		}
		// TODO: Block for more data
	}
	return st.readBuffer.Read(p)
}

// Header returns the current response headers.
func (st *serverStream) Header() http.Header { return st.responseHeaders }

func (st *serverStream) Write(p []byte) (n int, err os.Error) {
	if st.closed {
		err = os.NewError("Write on closed serverStream")
		return
	}
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	for len(p) > 0 {
		frame := DataFrame{
			StreamID: st.id,
		}
		if len(p) <= MaxDataLength {
			frame.Data = p
			p = p[:0]
		} else {
			frame.Data = p[:MaxDataLength]
			p = p[MaxDataLength:]
		}
		st.writeFrame(frame)
	}
	return
}

func (st *serverStream) WriteHeader(code int) {
	if st.wroteHeader {
		return
	}
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, st.id&0x7fffffff)
	buf.Write([16]byte{}[:])
	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
	st.responseHeaders.Set("version", "HTTP/1.1")
	st.headerWriter.WriteHeader(buf, st.responseHeaders)
	st.writeFrame(ControlFrame{
		Type: TypeSynReply,
		Data: buf.Bytes(),
	})
}

func (st *serverStream) writeFrame(frame Frame) {
	if st.lastWrite != nil {
		st.session.out <- st.lastWrite
	}
	st.lastWrite = frame
}

func (st *serverStream) Flush() os.Error {
	if st.lastWrite != nil {
		st.session.out <- st.lastWrite
		st.lastWrite = nil
	}
	return nil
}

func (st *serverStream) Close() (err os.Error) {
	if st.lastWrite != nil {
		switch frame := st.lastWrite.(type) {
		case DataFrame:
			frame.Flags |= FlagFin
			st.session.out <- frame
		case ControlFrame:
			if frame.Type == TypeSynStream || frame.Type == TypeSynReply {
				frame.Flags |= FlagFin
				st.session.out <- frame
			} else {
				st.session.out <- st.lastWrite
				st.session.out <- DataFrame{
					StreamID: st.id,
					Flags:    FlagFin,
					Data:     []byte{},
				}
			}
		default:
			// Any other frame must be sent first, then followed by a close.
			st.session.out <- st.lastWrite
			st.session.out <- DataFrame{
				StreamID: st.id,
				Flags:    FlagFin,
				Data:     []byte{},
			}
		}
		st.lastWrite = nil
	} else {
		// Already flushed
		st.session.out <- DataFrame{
			StreamID: st.id,
			Flags:    FlagFin,
			Data:     []byte{},
		}
	}
	st.closed = true
	return nil
}
<commit_msg>Add ListenAndServe function and minimal docs<commit_after>// spdy/server.go

package spdy

import (
	"bytes"
	"encoding/binary"
	"http"
	"io"
	"net"
	"os"
	"strconv"
	"sync"
)

// ListenAndServe creates a new Server that serves on the given address.  If
// the handler is nil, then http.DefaultServeMux is used.
func ListenAndServe(addr string, handler http.Handler) os.Error {
	srv := &Server{addr, handler}
	return srv.ListenAndServe()
}

// A Server handles incoming SPDY connections with HTTP handlers.
type Server struct {
	Addr    string
	Handler http.Handler
}

func (srv *Server) ListenAndServe() os.Error {
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(l)
}

func (srv *Server) Serve(l net.Listener) os.Error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		s, err := newSession(c, handler)
		if err != nil {
			return err
		}
		go s.serve()
	}
	return nil
}

// A session manages a single TCP connection to a client.
type session struct {
	c           net.Conn
	handler     http.Handler
	in, out     chan Frame
	streams     map[uint32]*serverStream
	streamsLock sync.RWMutex
}

func newSession(c net.Conn, h http.Handler) (s *session, err os.Error) {
	s = &session{
		c:       c,
		handler: h,
		in:      make(chan Frame),
		out:     make(chan Frame),
		streams: make(map[uint32]*serverStream),
	}
	return
}

func (sess *session) serve() {
	defer sess.c.Close()
	go sess.sendFrames()
	go sess.receiveFrames()

	for {
		select {
		case f := <-sess.in:
			switch frame := f.(type) {
			case ControlFrame:
				sess.handleControl(frame)
			case DataFrame:
				sess.handleData(frame)
			}
		}
	}
}

func (sess *session) handleControl(frame ControlFrame) {
	switch frame.Type {
	case TypeSynStream:
		sess.streamsLock.Lock()
		defer sess.streamsLock.Unlock()
		if stream, err := newServerStream(sess, frame); err == nil {
			if _, exists := sess.streams[stream.id]; !exists {
				sess.streams[stream.id] = stream
				go stream.bufferReads()
				go sess.handler.ServeHTTP(stream, stream.Request())
			}
		}
	}
}

func (sess *session) handleData(frame DataFrame) {
	sess.streamsLock.RLock()
	defer sess.streamsLock.RUnlock()

	st, found := sess.streams[frame.StreamID]
	if !found {
		// TODO: Error?
		return
	}
	if st.readChan != nil {
		st.readChan <- frame
		if frame.Flags&FlagFin != 0 {
			close(st.readChan)
		}
	}
}

func (sess *session) sendFrames() {
	for frame := range sess.out {
		// TODO: Check for errors
		frame.WriteTo(sess.c)
	}
}

func (sess *session) receiveFrames() {
	defer close(sess.in)
	for {
		frame, err := ReadFrame(sess.c)
		if err != nil {
			return
		}
		sess.in <- frame
	}
}

// A serverStream is a logical data stream inside a session.  A serverStream
// services a single request.
type serverStream struct {
	id      uint32
	session *session
	closed  bool

	headerReader   *HeaderReader
	requestHeaders http.Header

	headerWriter    *HeaderWriter
	responseHeaders http.Header
	wroteHeader     bool

	readChan   chan DataFrame
	readBuffer *bytes.Buffer
	readLock   sync.Mutex

	lastWrite Frame
}

func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err os.Error) {
	if frame.Type != TypeSynStream {
		err = os.NewError("Server stream must be created from a SynStream frame")
		return
	}
	st = &serverStream{
		session:         sess,
		headerReader:    NewHeaderReader(),
		headerWriter:    NewHeaderWriter(-1),
		responseHeaders: make(http.Header),
	}
	if frame.Flags&FlagFin == 0 {
		// Request body will follow
		st.readChan = make(chan DataFrame)
		st.readBuffer = new(bytes.Buffer)
	}
	// Read frame data
	data := bytes.NewBuffer(frame.Data)
	err = binary.Read(data, binary.BigEndian, &st.id)
	if err != nil {
		return
	}
	_, err = io.ReadFull(data, make([]byte, 6)) // skip associated stream ID and priority
	if err != nil {
		return
	}
	st.requestHeaders, err = st.headerReader.Decode(data.Bytes())
	return
}

func (st *serverStream) bufferReads() {
	for frame := range st.readChan {
		st.readLock.Lock()
		st.readBuffer.Write(frame.Data)
		st.readLock.Unlock()
	}
	st.readChan = nil
}

// Request returns the request data associated with the serverStream.
func (st *serverStream) Request() (req *http.Request) {
	// TODO
	req = &http.Request{
		Method:     st.requestHeaders.Get("method"),
		RawURL:     st.requestHeaders.Get("url"),
		Proto:      st.requestHeaders.Get("version"),
		Header:     st.requestHeaders,
		Body:       st,
		RemoteAddr: st.session.c.RemoteAddr().String(),
	}
	return
}

func (st *serverStream) Read(p []byte) (n int, err os.Error) {
	st.readLock.Lock()
	defer st.readLock.Unlock()
	if st.readBuffer.Len() == 0 {
		if st.readChan == nil {
			return 0, os.EOF
		}
		// TODO: Block for more data
	}
	return st.readBuffer.Read(p)
}

// Header returns the current response headers.
func (st *serverStream) Header() http.Header { return st.responseHeaders }

func (st *serverStream) Write(p []byte) (n int, err os.Error) {
	if st.closed {
		err = os.NewError("Write on closed serverStream")
		return
	}
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	for len(p) > 0 {
		frame := DataFrame{
			StreamID: st.id,
		}
		if len(p) <= MaxDataLength {
			frame.Data = p
			p = p[:0]
		} else {
			frame.Data = p[:MaxDataLength]
			p = p[MaxDataLength:]
		}
		st.writeFrame(frame)
	}
	return
}

func (st *serverStream) WriteHeader(code int) {
	if st.wroteHeader {
		return
	}
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, st.id&0x7fffffff)
	buf.Write([16]byte{}[:])
	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
	st.responseHeaders.Set("version", "HTTP/1.1")
	st.headerWriter.WriteHeader(buf, st.responseHeaders)
	st.writeFrame(ControlFrame{
		Type: TypeSynReply,
		Data: buf.Bytes(),
	})
}

func (st *serverStream) writeFrame(frame Frame) {
	if st.lastWrite != nil {
		st.session.out <- st.lastWrite
	}
	st.lastWrite = frame
}

func (st *serverStream) Flush() os.Error {
	if st.lastWrite != nil {
		st.session.out <- st.lastWrite
		st.lastWrite = nil
	}
	return nil
}

func (st *serverStream) Close() (err os.Error) {
	if st.lastWrite != nil {
		switch frame := st.lastWrite.(type) {
		case DataFrame:
			frame.Flags |= FlagFin
			st.session.out <- frame
		case ControlFrame:
			if frame.Type == TypeSynStream || frame.Type == TypeSynReply {
				frame.Flags |= FlagFin
				st.session.out <- frame
			} else {
				st.session.out <- st.lastWrite
				st.session.out <- DataFrame{
					StreamID: st.id,
					Flags:    FlagFin,
					Data:     []byte{},
				}
			}
		default:
			// Any other frame must be sent first, then followed by a close.
			st.session.out <- st.lastWrite
			st.session.out <- DataFrame{
				StreamID: st.id,
				Flags:    FlagFin,
				Data:     []byte{},
			}
		}
		st.lastWrite = nil
	} else {
		// Already flushed
		st.session.out <- DataFrame{
			StreamID: st.id,
			Flags:    FlagFin,
			Data:     []byte{},
		}
	}
	st.closed = true
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	authlib "github.com/clawio/service.auth/lib"
	"github.com/clawio/service.localstore.data/lib"
	"github.com/rs/xlog"
	"golang.org/x/net/context"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"syscall"
)

const (
	dirPerm = 0755
)

type newServerParams struct {
	dataDir      string
	tmpDir       string
	sharedSecret string
}

func newServer(p *newServerParams) *server {
	return &server{p}
}

type server struct {
	p *newServerParams
}

func (s *server) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	log.SetField("trace", getTraceID(r))

	if strings.ToUpper(r.Method) == "PUT" {
		s.authHandler(ctx, w, r, s.upload)
	} else if strings.ToUpper(r.Method) == "GET" {
		s.authHandler(ctx, w, r, s.download)
	} else {
		w.WriteHeader(http.StatusNotFound)
		return
	}
}

func (s *server) upload(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	p := lib.MustFromContext(ctx)

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	tmpFn, tmpFile, err := s.tmpFile()
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("created tmp file %s", tmpFn)

	// TODO(labkode) Sometimes ContentLength = -1 because it is a binary
	// upload with TransferEncoding: chunked.
	// Instead using Copy we shoudl use a LimitedReader with a max file upload
	// configuration value.
	_, err = io.Copy(tmpFile, r.Body)
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("copied r.Body into tmp file %s", tmpFn)

	err = tmpFile.Close()
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("closed tmp file %s", tmpFn)

	if err = os.Rename(tmpFn, pp); err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("renamed tmp file %s to %s", tmpFn, pp)

	w.WriteHeader(http.StatusCreated)
}

func (s *server) download(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	p := lib.MustFromContext(ctx)

	pp := s.getPhysicalPath(p)

	log.Info("physical path is %s", pp)

	fd, err := os.Open(pp)
	if err == syscall.ENOENT {
		log.Error(err.Error())
		http.Error(w, "", http.StatusNotFound)
		return
	}

	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("opened %s", pp)

	info, err := fd.Stat()
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("stated %s got size %d", pp, info.Size())

	if info.IsDir() {
		log.Errorf("%s is a directory", pp)
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	defer fd.Close()

	_, err = io.Copy(w, fd)
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("copied %s to res.body", pp)

}

func (s *server) authHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
	next func(ctx context.Context, w http.ResponseWriter, r *http.Request)) {

	log := xlog.FromContext(ctx)

	idt, err := s.getIdentityFromReq(r)
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusUnauthorized)
		return
	}

	p := getPathFromReq(r) // already sanitized

	if !isUnderHome(p, idt) {
		// TODO use here share service
		log.Warn("access denied to %s accessing %s", *idt, p)
		http.Error(w, "", http.StatusForbidden)
		return
	}

	if p == getHome(idt) {
		http.Error(w, "", http.StatusMethodNotAllowed)
		return
	}

	log.Infof("path is %s", p)

	ctx = authlib.NewContext(ctx, idt)
	ctx = lib.NewContext(ctx, p)
	next(ctx, w, r)
}

func (s *server) tmpFile() (string, *os.File, error) {

	file, err := ioutil.TempFile(s.p.tmpDir, serviceID)
	if err != nil {
		return "", nil, err
	}

	fn := path.Join(path.Clean(file.Name()))

	return fn, file, nil
}

func (s *server) getPhysicalPath(p string) string {
	return path.Join(s.p.dataDir, path.Clean(p))
}

func (s *server) getIdentityFromReq(r *http.Request) (*authlib.Identity, error) {

	var token string

	// Look for an Authorization header
	if ah := r.Header.Get("Authorization"); ah != "" {
		// Should be a bearer token
		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
			token = ah[7:]
		}
	}

	if token == "" {
		// Look for "auth_token" parameter
		r.ParseMultipartForm(10e6)
		if tokStr := r.Form.Get("access_token"); tokStr != "" {
			token = tokStr
		}

	}

	return authlib.ParseToken(token, s.p.sharedSecret)
}
<commit_msg>Fix message<commit_after>package main

import (
	authlib "github.com/clawio/service.auth/lib"
	"github.com/clawio/service.localstore.data/lib"
	"github.com/rs/xlog"
	"golang.org/x/net/context"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"syscall"
)

const (
	dirPerm = 0755
)

type newServerParams struct {
	dataDir      string
	tmpDir       string
	sharedSecret string
}

func newServer(p *newServerParams) *server {
	return &server{p}
}

type server struct {
	p *newServerParams
}

func (s *server) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	log.SetField("trace", getTraceID(r))

	if strings.ToUpper(r.Method) == "PUT" {
		s.authHandler(ctx, w, r, s.upload)
	} else if strings.ToUpper(r.Method) == "GET" {
		s.authHandler(ctx, w, r, s.download)
	} else {
		w.WriteHeader(http.StatusNotFound)
		return
	}
}

func (s *server) upload(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	p := lib.MustFromContext(ctx)

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	tmpFn, tmpFile, err := s.tmpFile()
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("created tmp file %s", tmpFn)

	// TODO(labkode) Sometimes ContentLength = -1 because it is a binary
	// upload with TransferEncoding: chunked.
	// Instead using Copy we shoudl use a LimitedReader with a max file upload
	// configuration value.
	_, err = io.Copy(tmpFile, r.Body)
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("copied r.Body into tmp file %s", tmpFn)

	err = tmpFile.Close()
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("closed tmp file %s", tmpFn)

	if err = os.Rename(tmpFn, pp); err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("renamed tmp file %s to %s", tmpFn, pp)

	w.WriteHeader(http.StatusCreated)
}

func (s *server) download(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	p := lib.MustFromContext(ctx)

	pp := s.getPhysicalPath(p)

	log.Info("physical path is %s", pp)

	fd, err := os.Open(pp)
	if err == syscall.ENOENT {
		log.Error(err.Error())
		http.Error(w, "", http.StatusNotFound)
		return
	}

	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("opened %s", pp)

	info, err := fd.Stat()
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("stated %s got size %d", pp, info.Size())

	if info.IsDir() {
		log.Errorf("%s is a directory", pp)
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	defer fd.Close()

	_, err = io.Copy(w, fd)
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	log.Infof("copied %s to res.body", pp)

}

func (s *server) authHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
	next func(ctx context.Context, w http.ResponseWriter, r *http.Request)) {

	log := xlog.FromContext(ctx)

	idt, err := s.getIdentityFromReq(r)
	if err != nil {
		log.Error(err)
		http.Error(w, "", http.StatusUnauthorized)
		return
	}

	p := getPathFromReq(r) // already sanitized

	if !isUnderHome(p, idt) {
		// TODO use here share service
		log.Warnf("access denied to %s accessing %s", *idt, p)
		http.Error(w, "", http.StatusForbidden)
		return
	}

	if p == getHome(idt) {
		http.Error(w, "", http.StatusMethodNotAllowed)
		return
	}

	log.Infof("path is %s", p)

	ctx = authlib.NewContext(ctx, idt)
	ctx = lib.NewContext(ctx, p)
	next(ctx, w, r)
}

func (s *server) tmpFile() (string, *os.File, error) {

	file, err := ioutil.TempFile(s.p.tmpDir, serviceID)
	if err != nil {
		return "", nil, err
	}

	fn := path.Join(path.Clean(file.Name()))

	return fn, file, nil
}

func (s *server) getPhysicalPath(p string) string {
	return path.Join(s.p.dataDir, path.Clean(p))
}

func (s *server) getIdentityFromReq(r *http.Request) (*authlib.Identity, error) {

	var token string

	// Look for an Authorization header
	if ah := r.Header.Get("Authorization"); ah != "" {
		// Should be a bearer token
		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
			token = ah[7:]
		}
	}

	if token == "" {
		// Look for "auth_token" parameter
		r.ParseMultipartForm(10e6)
		if tokStr := r.Form.Get("access_token"); tokStr != "" {
			token = tokStr
		}

	}

	return authlib.ParseToken(token, s.p.sharedSecret)
}
<|endoftext|>