<commit_before>// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

//go:generate -command counterfeiter go run github.com/maxbrunsfeld/counterfeiter/v6
//go:generate counterfeiter -o mocks/buffered_subscription.go --fake-name BufferedSubscription . BufferedSubscription

// Package events provides event subscription and polling functionality.
package events

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"runtime"
	"time"

	"github.com/thejerf/suture/v4"

	"github.com/syncthing/syncthing/lib/sync"
)

type EventType int64

const (
	Starting EventType = 1 << iota
	StartupComplete
	DeviceDiscovered
	DeviceConnected
	DeviceDisconnected
	DeviceRejected // DEPRECATED, superseded by PendingDevicesChanged
	PendingDevicesChanged
	DevicePaused
	DeviceResumed
	ClusterConfigReceived
	LocalChangeDetected
	RemoteChangeDetected
	LocalIndexUpdated
	RemoteIndexUpdated
	ItemStarted
	ItemFinished
	StateChanged
	FolderRejected // DEPRECATED, superseded by PendingFoldersChanged
	PendingFoldersChanged
	ConfigSaved
	DownloadProgress
	RemoteDownloadProgress
	FolderSummary
	FolderCompletion
	FolderErrors
	FolderScanProgress
	FolderPaused
	FolderResumed
	FolderWatchStateChanged
	ListenAddressesChanged
	LoginAttempt
	Failure

	AllEvents = (1 << iota) - 1
)

var (
	runningTests = false
	errNoop      = errors.New("method of a noop object called")
)

const eventLogTimeout = 15 * time.Millisecond

func (t EventType) String() string {
	switch t {
	case Starting:
		return "Starting"
	case StartupComplete:
		return "StartupComplete"
	case DeviceDiscovered:
		return "DeviceDiscovered"
	case DeviceConnected:
		return "DeviceConnected"
	case DeviceDisconnected:
		return "DeviceDisconnected"
	case DeviceRejected:
		return "DeviceRejected"
	case PendingDevicesChanged:
		return "PendingDevicesChanged"
	case LocalChangeDetected:
		return "LocalChangeDetected"
	case RemoteChangeDetected:
		return "RemoteChangeDetected"
	case LocalIndexUpdated:
		return "LocalIndexUpdated"
	case RemoteIndexUpdated:
		return "RemoteIndexUpdated"
	case ItemStarted:
		return "ItemStarted"
	case ItemFinished:
		return "ItemFinished"
	case StateChanged:
		return "StateChanged"
	case FolderRejected:
		return "FolderRejected"
	case PendingFoldersChanged:
		return "PendingFoldersChanged"
	case ConfigSaved:
		return "ConfigSaved"
	case DownloadProgress:
		return "DownloadProgress"
	case RemoteDownloadProgress:
		return "RemoteDownloadProgress"
	case FolderSummary:
		return "FolderSummary"
	case FolderCompletion:
		return "FolderCompletion"
	case FolderErrors:
		return "FolderErrors"
	case DevicePaused:
		return "DevicePaused"
	case DeviceResumed:
		return "DeviceResumed"
	case ClusterConfigReceived:
		return "ClusterConfigReceived"
	case FolderScanProgress:
		return "FolderScanProgress"
	case FolderPaused:
		return "FolderPaused"
	case FolderResumed:
		return "FolderResumed"
	case ListenAddressesChanged:
		return "ListenAddressesChanged"
	case LoginAttempt:
		return "LoginAttempt"
	case FolderWatchStateChanged:
		return "FolderWatchStateChanged"
	case Failure:
		return "Failure"
	default:
		return "Unknown"
	}
}

func (t EventType) MarshalText() ([]byte, error) {
	return []byte(t.String()), nil
}

func (t *EventType) UnmarshalJSON(b []byte) error {
	var s string

	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}

	*t = UnmarshalEventType(s)

	return nil
}

func UnmarshalEventType(s string) EventType {
	switch s {
	case "Starting":
		return Starting
	case "StartupComplete":
		return StartupComplete
	case "DeviceDiscovered":
		return DeviceDiscovered
	case "DeviceConnected":
		return DeviceConnected
	case "DeviceDisconnected":
		return DeviceDisconnected
	case "DeviceRejected":
		return DeviceRejected
	case "PendingDevicesChanged":
		return PendingDevicesChanged
	case "LocalChangeDetected":
		return LocalChangeDetected
	case "RemoteChangeDetected":
		return RemoteChangeDetected
	case "LocalIndexUpdated":
		return LocalIndexUpdated
	case "RemoteIndexUpdated":
		return RemoteIndexUpdated
	case "ItemStarted":
		return ItemStarted
	case "ItemFinished":
		return ItemFinished
	case "StateChanged":
		return StateChanged
	case "FolderRejected":
		return FolderRejected
	case "PendingFoldersChanged":
		return PendingFoldersChanged
	case "ConfigSaved":
		return ConfigSaved
	case "DownloadProgress":
		return DownloadProgress
	case "RemoteDownloadProgress":
		return RemoteDownloadProgress
	case "FolderSummary":
		return FolderSummary
	case "FolderCompletion":
		return FolderCompletion
	case "FolderErrors":
		return FolderErrors
	case "DevicePaused":
		return DevicePaused
	case "DeviceResumed":
		return DeviceResumed
	case "ClusterConfigReceived":
		return ClusterConfigReceived
	case "FolderScanProgress":
		return FolderScanProgress
	case "FolderPaused":
		return FolderPaused
	case "FolderResumed":
		return FolderResumed
	case "ListenAddressesChanged":
		return ListenAddressesChanged
	case "LoginAttempt":
		return LoginAttempt
	case "FolderWatchStateChanged":
		return FolderWatchStateChanged
	case "Failure":
		return Failure
	default:
		return 0
	}
}

const BufferSize = 64

type Logger interface {
	suture.Service
	Log(t EventType, data interface{})
	Subscribe(mask EventType) Subscription
}

type logger struct {
	subs                []*subscription
	nextSubscriptionIDs []int
	nextGlobalID        int
	timeout             *time.Timer
	events              chan Event
	funcs               chan func(context.Context)
	toUnsubscribe       chan *subscription
}

type Event struct {
	// Per-subscription sequential event ID. Named "id" for backwards compatibility with the REST API
	SubscriptionID int `json:"id"`
	// Global ID of the event across all subscriptions
	GlobalID int         `json:"globalID"`
	Time     time.Time   `json:"time"`
	Type     EventType   `json:"type"`
	Data     interface{} `json:"data"`
}

type Subscription interface {
	C() <-chan Event
	Poll(timeout time.Duration) (Event, error)
	Mask() EventType
	Unsubscribe()
}

type subscription struct {
	mask          EventType
	events        chan Event
	toUnsubscribe chan *subscription
	timeout       *time.Timer
	ctx           context.Context
}

var (
	ErrTimeout = errors.New("timeout")
	ErrClosed  = errors.New("closed")
)

func NewLogger() Logger {
	l := &logger{
		timeout:       time.NewTimer(time.Second),
		events:        make(chan Event, BufferSize),
		funcs:         make(chan func(context.Context)),
		toUnsubscribe: make(chan *subscription),
	}
	// Make sure the timer is in the stopped state and hasn't fired anything
	// into the channel.
	if !l.timeout.Stop() {
		<-l.timeout.C
	}
	return l
}

func (l *logger) Serve(ctx context.Context) error {
loop:
	for {
		select {
		case e := <-l.events:
			// Incoming events get sent
			l.sendEvent(e)

		case fn := <-l.funcs:
			// Subscriptions are handled here.
			fn(ctx)

		case s := <-l.toUnsubscribe:
			l.unsubscribe(s)

		case <-ctx.Done():
			break loop
		}
	}

	// Closing the event channels corresponds to what happens when a
	// subscription is unsubscribed; this stops any BufferedSubscription,
	// makes Poll() return ErrClosed, etc.
	for _, s := range l.subs {
		close(s.events)
	}

	return nil
}

func (l *logger) Log(t EventType, data interface{}) {
	l.events <- Event{
		Time: time.Now(), // intentionally high precision
		Type: t,
		Data: data,
		// SubscriptionID and GlobalID are set in sendEvent
	}
}

func (l *logger) sendEvent(e Event) {
	l.nextGlobalID++
	dl.Debugln("log", l.nextGlobalID, e.Type, e.Data)

	e.GlobalID = l.nextGlobalID

	for i, s := range l.subs {
		if s.mask&e.Type != 0 {
			e.SubscriptionID = l.nextSubscriptionIDs[i]
			l.nextSubscriptionIDs[i]++

			l.timeout.Reset(eventLogTimeout)
			timedOut := false

			select {
			case s.events <- e:
			case <-l.timeout.C:
				// if s.events is not ready, drop the event
				timedOut = true
			}

			// If stop returns false it already sent something to the
			// channel. If we didn't already read it above we must do so now
			// or we get a spurious timeout on the next loop.
			if !l.timeout.Stop() && !timedOut {
				<-l.timeout.C
			}
		}
	}
}

func (l *logger) Subscribe(mask EventType) Subscription {
	res := make(chan Subscription)
	l.funcs <- func(ctx context.Context) {
		dl.Debugln("subscribe", mask)

		s := &subscription{
			mask:          mask,
			events:        make(chan Event, BufferSize),
			toUnsubscribe: l.toUnsubscribe,
			timeout:       time.NewTimer(0),
			ctx:           ctx,
		}

		// We need to create the timeout timer in the stopped, non-fired state so
		// that Subscription.Poll() can safely reset it and select on the timeout
		// channel. This ensures the timer is stopped and the channel drained.
		if runningTests {
			// Make the behavior stable when running tests to avoid randomly
			// varying test coverage. This ensures, in practice if not in
			// theory, that the timer fires and we take the true branch of the
			// next if.
			runtime.Gosched()
		}
		if !s.timeout.Stop() {
			<-s.timeout.C
		}

		l.subs = append(l.subs, s)
		l.nextSubscriptionIDs = append(l.nextSubscriptionIDs, 1)
		res <- s
	}
	return <-res
}

func (l *logger) unsubscribe(s *subscription) {
	dl.Debugln("unsubscribe", s.mask)
	for i, ss := range l.subs {
		if s == ss {
			last := len(l.subs) - 1

			l.subs[i] = l.subs[last]
			l.subs[last] = nil
			l.subs = l.subs[:last]

			l.nextSubscriptionIDs[i] = l.nextSubscriptionIDs[last]
			l.nextSubscriptionIDs[last] = 0
			l.nextSubscriptionIDs = l.nextSubscriptionIDs[:last]

			break
		}
	}
	close(s.events)
}

func (l *logger) String() string {
	return fmt.Sprintf("events.Logger/@%p", l)
}

// Poll returns an event from the subscription or an error if the poll times
// out of the event channel is closed. Poll should not be called concurrently
// from multiple goroutines for a single subscription.
func (s *subscription) Poll(timeout time.Duration) (Event, error) {
	dl.Debugln("poll", timeout)

	s.timeout.Reset(timeout)

	select {
	case e, ok := <-s.events:
		if !ok {
			return e, ErrClosed
		}
		if runningTests {
			// Make the behavior stable when running tests to avoid randomly
			// varying test coverage. This ensures, in practice if not in
			// theory, that the timer fires and we take the true branch of
			// the next if.
			s.timeout.Reset(0)
			runtime.Gosched()
		}
		if !s.timeout.Stop() {
			// The timeout must be stopped and possibly drained to be ready
			// for reuse in the next call.
			<-s.timeout.C
		}
		return e, nil
	case <-s.timeout.C:
		return Event{}, ErrTimeout
	}
}

func (s *subscription) C() <-chan Event {
	return s.events
}

func (s *subscription) Mask() EventType {
	return s.mask
}

func (s *subscription) Unsubscribe() {
	select {
	case s.toUnsubscribe <- s:
	case <-s.ctx.Done():
	}
}

type bufferedSubscription struct {
	sub  Subscription
	buf  []Event
	next int
	cur  int // Current SubscriptionID
	mut  sync.Mutex
	cond *sync.TimeoutCond
}

type BufferedSubscription interface {
	Since(id int, into []Event, timeout time.Duration) []Event
	Mask() EventType
}

func NewBufferedSubscription(s Subscription, size int) BufferedSubscription {
	bs := &bufferedSubscription{
		sub: s,
		buf: make([]Event, size),
		mut: sync.NewMutex(),
	}
	bs.cond = sync.NewTimeoutCond(bs.mut)
	go bs.pollingLoop()
	return bs
}

func (s *bufferedSubscription) pollingLoop() {
	for ev := range s.sub.C() {
		s.mut.Lock()
		s.buf[s.next] = ev
		s.next = (s.next + 1) % len(s.buf)
		s.cur = ev.SubscriptionID
		s.cond.Broadcast()
		s.mut.Unlock()
	}
}

func (s *bufferedSubscription) Since(id int, into []Event, timeout time.Duration) []Event {
	s.mut.Lock()
	defer s.mut.Unlock()

	// Check once first before generating the TimeoutCondWaiter
	if id >= s.cur {
		waiter := s.cond.SetupWait(timeout)
		defer waiter.Stop()

		for id >= s.cur {
			if eventsAvailable := waiter.Wait(); !eventsAvailable {
				// Timed out
				return into
			}
		}
	}

	for i := s.next; i < len(s.buf); i++ {
		if s.buf[i].SubscriptionID > id {
			into = append(into, s.buf[i])
		}
	}
	for i := 0; i < s.next; i++ {
		if s.buf[i].SubscriptionID > id {
			into = append(into, s.buf[i])
		}
	}

	return into
}

func (s *bufferedSubscription) Mask() EventType {
	return s.sub.Mask()
}

// Error returns a string pointer suitable for JSON marshalling errors. It
// retains the "null on success" semantics, but ensures the error result is a
// string regardless of the underlying concrete error type.
func Error(err error) *string {
	if err == nil {
		return nil
	}
	str := err.Error()
	return &str
}

type noopLogger struct{}

var NoopLogger Logger = &noopLogger{}

func (*noopLogger) Serve(ctx context.Context) error { return nil }

func (*noopLogger) Stop() {}

func (*noopLogger) Log(t EventType, data interface{}) {}

func (*noopLogger) Subscribe(mask EventType) Subscription {
	return &noopSubscription{}
}

type noopSubscription struct{}

func (*noopSubscription) C() <-chan Event {
	return nil
}

func (*noopSubscription) Poll(timeout time.Duration) (Event, error) {
	return Event{}, errNoop
}

func (s *noopSubscription) Mask() EventType {
	return 0
}

func (*noopSubscription) Unsubscribe() {}
<commit_msg>lib/events: Remove unused method noopLogger.Stop (#8312)<commit_after>// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

//go:generate -command counterfeiter go run github.com/maxbrunsfeld/counterfeiter/v6
//go:generate counterfeiter -o mocks/buffered_subscription.go --fake-name BufferedSubscription . BufferedSubscription

// Package events provides event subscription and polling functionality.
package events

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"runtime"
	"time"

	"github.com/thejerf/suture/v4"

	"github.com/syncthing/syncthing/lib/sync"
)

type EventType int64

const (
	Starting EventType = 1 << iota
	StartupComplete
	DeviceDiscovered
	DeviceConnected
	DeviceDisconnected
	DeviceRejected // DEPRECATED, superseded by PendingDevicesChanged
	PendingDevicesChanged
	DevicePaused
	DeviceResumed
	ClusterConfigReceived
	LocalChangeDetected
	RemoteChangeDetected
	LocalIndexUpdated
	RemoteIndexUpdated
	ItemStarted
	ItemFinished
	StateChanged
	FolderRejected // DEPRECATED, superseded by PendingFoldersChanged
	PendingFoldersChanged
	ConfigSaved
	DownloadProgress
	RemoteDownloadProgress
	FolderSummary
	FolderCompletion
	FolderErrors
	FolderScanProgress
	FolderPaused
	FolderResumed
	FolderWatchStateChanged
	ListenAddressesChanged
	LoginAttempt
	Failure

	AllEvents = (1 << iota) - 1
)

var (
	runningTests = false
	errNoop      = errors.New("method of a noop object called")
)

const eventLogTimeout = 15 * time.Millisecond

func (t EventType) String() string {
	switch t {
	case Starting:
		return "Starting"
	case StartupComplete:
		return "StartupComplete"
	case DeviceDiscovered:
		return "DeviceDiscovered"
	case DeviceConnected:
		return "DeviceConnected"
	case DeviceDisconnected:
		return "DeviceDisconnected"
	case DeviceRejected:
		return "DeviceRejected"
	case PendingDevicesChanged:
		return "PendingDevicesChanged"
	case LocalChangeDetected:
		return "LocalChangeDetected"
	case RemoteChangeDetected:
		return "RemoteChangeDetected"
	case LocalIndexUpdated:
		return "LocalIndexUpdated"
	case RemoteIndexUpdated:
		return "RemoteIndexUpdated"
	case ItemStarted:
		return "ItemStarted"
	case ItemFinished:
		return "ItemFinished"
	case StateChanged:
		return "StateChanged"
	case FolderRejected:
		return "FolderRejected"
	case PendingFoldersChanged:
		return "PendingFoldersChanged"
	case ConfigSaved:
		return "ConfigSaved"
	case DownloadProgress:
		return "DownloadProgress"
	case RemoteDownloadProgress:
		return "RemoteDownloadProgress"
	case FolderSummary:
		return "FolderSummary"
	case FolderCompletion:
		return "FolderCompletion"
	case FolderErrors:
		return "FolderErrors"
	case DevicePaused:
		return "DevicePaused"
	case DeviceResumed:
		return "DeviceResumed"
	case ClusterConfigReceived:
		return "ClusterConfigReceived"
	case FolderScanProgress:
		return "FolderScanProgress"
	case FolderPaused:
		return "FolderPaused"
	case FolderResumed:
		return "FolderResumed"
	case ListenAddressesChanged:
		return "ListenAddressesChanged"
	case LoginAttempt:
		return "LoginAttempt"
	case FolderWatchStateChanged:
		return "FolderWatchStateChanged"
	case Failure:
		return "Failure"
	default:
		return "Unknown"
	}
}

func (t EventType) MarshalText() ([]byte, error) {
	return []byte(t.String()), nil
}

func (t *EventType) UnmarshalJSON(b []byte) error {
	var s string

	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}

	*t = UnmarshalEventType(s)

	return nil
}

func UnmarshalEventType(s string) EventType {
	switch s {
	case "Starting":
		return Starting
	case "StartupComplete":
		return StartupComplete
	case "DeviceDiscovered":
		return DeviceDiscovered
	case "DeviceConnected":
		return DeviceConnected
	case "DeviceDisconnected":
		return DeviceDisconnected
	case "DeviceRejected":
		return DeviceRejected
	case "PendingDevicesChanged":
		return PendingDevicesChanged
	case "LocalChangeDetected":
		return LocalChangeDetected
	case "RemoteChangeDetected":
		return RemoteChangeDetected
	case "LocalIndexUpdated":
		return LocalIndexUpdated
	case "RemoteIndexUpdated":
		return RemoteIndexUpdated
	case "ItemStarted":
		return ItemStarted
	case "ItemFinished":
		return ItemFinished
	case "StateChanged":
		return StateChanged
	case "FolderRejected":
		return FolderRejected
	case "PendingFoldersChanged":
		return PendingFoldersChanged
	case "ConfigSaved":
		return ConfigSaved
	case "DownloadProgress":
		return DownloadProgress
	case "RemoteDownloadProgress":
		return RemoteDownloadProgress
	case "FolderSummary":
		return FolderSummary
	case "FolderCompletion":
		return FolderCompletion
	case "FolderErrors":
		return FolderErrors
	case "DevicePaused":
		return DevicePaused
	case "DeviceResumed":
		return DeviceResumed
	case "ClusterConfigReceived":
		return ClusterConfigReceived
	case "FolderScanProgress":
		return FolderScanProgress
	case "FolderPaused":
		return FolderPaused
	case "FolderResumed":
		return FolderResumed
	case "ListenAddressesChanged":
		return ListenAddressesChanged
	case "LoginAttempt":
		return LoginAttempt
	case "FolderWatchStateChanged":
		return FolderWatchStateChanged
	case "Failure":
		return Failure
	default:
		return 0
	}
}

const BufferSize = 64

type Logger interface {
	suture.Service
	Log(t EventType, data interface{})
	Subscribe(mask EventType) Subscription
}

type logger struct {
	subs                []*subscription
	nextSubscriptionIDs []int
	nextGlobalID        int
	timeout             *time.Timer
	events              chan Event
	funcs               chan func(context.Context)
	toUnsubscribe       chan *subscription
}

type Event struct {
	// Per-subscription sequential event ID. Named "id" for backwards compatibility with the REST API
	SubscriptionID int `json:"id"`
	// Global ID of the event across all subscriptions
	GlobalID int         `json:"globalID"`
	Time     time.Time   `json:"time"`
	Type     EventType   `json:"type"`
	Data     interface{} `json:"data"`
}

type Subscription interface {
	C() <-chan Event
	Poll(timeout time.Duration) (Event, error)
	Mask() EventType
	Unsubscribe()
}

type subscription struct {
	mask          EventType
	events        chan Event
	toUnsubscribe chan *subscription
	timeout       *time.Timer
	ctx           context.Context
}

var (
	ErrTimeout = errors.New("timeout")
	ErrClosed  = errors.New("closed")
)

func NewLogger() Logger {
	l := &logger{
		timeout:       time.NewTimer(time.Second),
		events:        make(chan Event, BufferSize),
		funcs:         make(chan func(context.Context)),
		toUnsubscribe: make(chan *subscription),
	}
	// Make sure the timer is in the stopped state and hasn't fired anything
	// into the channel.
	if !l.timeout.Stop() {
		<-l.timeout.C
	}
	return l
}

func (l *logger) Serve(ctx context.Context) error {
loop:
	for {
		select {
		case e := <-l.events:
			// Incoming events get sent
			l.sendEvent(e)

		case fn := <-l.funcs:
			// Subscriptions are handled here.
			fn(ctx)

		case s := <-l.toUnsubscribe:
			l.unsubscribe(s)

		case <-ctx.Done():
			break loop
		}
	}

	// Closing the event channels corresponds to what happens when a
	// subscription is unsubscribed; this stops any BufferedSubscription,
	// makes Poll() return ErrClosed, etc.
	for _, s := range l.subs {
		close(s.events)
	}

	return nil
}

func (l *logger) Log(t EventType, data interface{}) {
	l.events <- Event{
		Time: time.Now(), // intentionally high precision
		Type: t,
		Data: data,
		// SubscriptionID and GlobalID are set in sendEvent
	}
}

func (l *logger) sendEvent(e Event) {
	l.nextGlobalID++
	dl.Debugln("log", l.nextGlobalID, e.Type, e.Data)

	e.GlobalID = l.nextGlobalID

	for i, s := range l.subs {
		if s.mask&e.Type != 0 {
			e.SubscriptionID = l.nextSubscriptionIDs[i]
			l.nextSubscriptionIDs[i]++

			l.timeout.Reset(eventLogTimeout)
			timedOut := false

			select {
			case s.events <- e:
			case <-l.timeout.C:
				// if s.events is not ready, drop the event
				timedOut = true
			}

			// If stop returns false it already sent something to the
			// channel. If we didn't already read it above we must do so now
			// or we get a spurious timeout on the next loop.
			if !l.timeout.Stop() && !timedOut {
				<-l.timeout.C
			}
		}
	}
}

func (l *logger) Subscribe(mask EventType) Subscription {
	res := make(chan Subscription)
	l.funcs <- func(ctx context.Context) {
		dl.Debugln("subscribe", mask)

		s := &subscription{
			mask:          mask,
			events:        make(chan Event, BufferSize),
			toUnsubscribe: l.toUnsubscribe,
			timeout:       time.NewTimer(0),
			ctx:           ctx,
		}

		// We need to create the timeout timer in the stopped, non-fired state so
		// that Subscription.Poll() can safely reset it and select on the timeout
		// channel. This ensures the timer is stopped and the channel drained.
		if runningTests {
			// Make the behavior stable when running tests to avoid randomly
			// varying test coverage. This ensures, in practice if not in
			// theory, that the timer fires and we take the true branch of the
			// next if.
			runtime.Gosched()
		}
		if !s.timeout.Stop() {
			<-s.timeout.C
		}

		l.subs = append(l.subs, s)
		l.nextSubscriptionIDs = append(l.nextSubscriptionIDs, 1)
		res <- s
	}
	return <-res
}

func (l *logger) unsubscribe(s *subscription) {
	dl.Debugln("unsubscribe", s.mask)
	for i, ss := range l.subs {
		if s == ss {
			last := len(l.subs) - 1

			l.subs[i] = l.subs[last]
			l.subs[last] = nil
			l.subs = l.subs[:last]

			l.nextSubscriptionIDs[i] = l.nextSubscriptionIDs[last]
			l.nextSubscriptionIDs[last] = 0
			l.nextSubscriptionIDs = l.nextSubscriptionIDs[:last]

			break
		}
	}
	close(s.events)
}

func (l *logger) String() string {
	return fmt.Sprintf("events.Logger/@%p", l)
}

// Poll returns an event from the subscription or an error if the poll times
// out of the event channel is closed. Poll should not be called concurrently
// from multiple goroutines for a single subscription.
func (s *subscription) Poll(timeout time.Duration) (Event, error) {
	dl.Debugln("poll", timeout)

	s.timeout.Reset(timeout)

	select {
	case e, ok := <-s.events:
		if !ok {
			return e, ErrClosed
		}
		if runningTests {
			// Make the behavior stable when running tests to avoid randomly
			// varying test coverage. This ensures, in practice if not in
			// theory, that the timer fires and we take the true branch of
			// the next if.
			s.timeout.Reset(0)
			runtime.Gosched()
		}
		if !s.timeout.Stop() {
			// The timeout must be stopped and possibly drained to be ready
			// for reuse in the next call.
			<-s.timeout.C
		}
		return e, nil
	case <-s.timeout.C:
		return Event{}, ErrTimeout
	}
}

func (s *subscription) C() <-chan Event {
	return s.events
}

func (s *subscription) Mask() EventType {
	return s.mask
}

func (s *subscription) Unsubscribe() {
	select {
	case s.toUnsubscribe <- s:
	case <-s.ctx.Done():
	}
}

type bufferedSubscription struct {
	sub  Subscription
	buf  []Event
	next int
	cur  int // Current SubscriptionID
	mut  sync.Mutex
	cond *sync.TimeoutCond
}

type BufferedSubscription interface {
	Since(id int, into []Event, timeout time.Duration) []Event
	Mask() EventType
}

func NewBufferedSubscription(s Subscription, size int) BufferedSubscription {
	bs := &bufferedSubscription{
		sub: s,
		buf: make([]Event, size),
		mut: sync.NewMutex(),
	}
	bs.cond = sync.NewTimeoutCond(bs.mut)
	go bs.pollingLoop()
	return bs
}

func (s *bufferedSubscription) pollingLoop() {
	for ev := range s.sub.C() {
		s.mut.Lock()
		s.buf[s.next] = ev
		s.next = (s.next + 1) % len(s.buf)
		s.cur = ev.SubscriptionID
		s.cond.Broadcast()
		s.mut.Unlock()
	}
}

func (s *bufferedSubscription) Since(id int, into []Event, timeout time.Duration) []Event {
	s.mut.Lock()
	defer s.mut.Unlock()

	// Check once first before generating the TimeoutCondWaiter
	if id >= s.cur {
		waiter := s.cond.SetupWait(timeout)
		defer waiter.Stop()

		for id >= s.cur {
			if eventsAvailable := waiter.Wait(); !eventsAvailable {
				// Timed out
				return into
			}
		}
	}

	for i := s.next; i < len(s.buf); i++ {
		if s.buf[i].SubscriptionID > id {
			into = append(into, s.buf[i])
		}
	}
	for i := 0; i < s.next; i++ {
		if s.buf[i].SubscriptionID > id {
			into = append(into, s.buf[i])
		}
	}

	return into
}

func (s *bufferedSubscription) Mask() EventType {
	return s.sub.Mask()
}

// Error returns a string pointer suitable for JSON marshalling errors. It
// retains the "null on success" semantics, but ensures the error result is a
// string regardless of the underlying concrete error type.
func Error(err error) *string {
	if err == nil {
		return nil
	}
	str := err.Error()
	return &str
}

type noopLogger struct{}

var NoopLogger Logger = &noopLogger{}

func (*noopLogger) Serve(ctx context.Context) error { return nil }

func (*noopLogger) Log(t EventType, data interface{}) {}

func (*noopLogger) Subscribe(mask EventType) Subscription {
	return &noopSubscription{}
}

type noopSubscription struct{}

func (*noopSubscription) C() <-chan Event {
	return nil
}

func (*noopSubscription) Poll(timeout time.Duration) (Event, error) {
	return Event{}, errNoop
}

func (s *noopSubscription) Mask() EventType {
	return 0
}

func (*noopSubscription) Unsubscribe() {}
<|endoftext|>


<commit_before>package jwt

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
)

type Parser struct {
	ValidMethods         []string // If populated, only these methods will be considered valid
	UseJSONNumber        bool     // Use JSON Number format in JSON decoder
	SkipClaimsValidation bool     // Skip claims validation during token parsing
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
}

func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) != 3 {
		return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
	}

	var err error
	token := &Token{Raw: tokenString}

	// parse Header
	var headerBytes []byte
	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
			return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
		}
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}
	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}

	// parse Claims
	var claimBytes []byte
	token.Claims = claims

	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}
	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
	if p.UseJSONNumber {
		dec.UseNumber()
	}
	// JSON Decode.  Special case for map type to avoid weird pointer behavior
	if c, ok := token.Claims.(MapClaims); ok {
		err = dec.Decode(&c)
	} else {
		err = dec.Decode(&claims)
	}
	// Handle decode error
	if err != nil {
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}

	// Lookup signature method
	if method, ok := token.Header["alg"].(string); ok {
		if token.Method = GetSigningMethod(method); token.Method == nil {
			return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
		}
	} else {
		return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
	}

	// Verify signing method is in the required set
	if p.ValidMethods != nil {
		var signingMethodValid = false
		var alg = token.Method.Alg()
		for _, m := range p.ValidMethods {
			if m == alg {
				signingMethodValid = true
				break
			}
		}
		if !signingMethodValid {
			// signing method is not in the listed set
			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
		}
	}

	// Lookup key
	var key interface{}
	if keyFunc == nil {
		// keyFunc was not provided.  short circuiting validation
		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
	}
	if key, err = keyFunc(token); err != nil {
		// keyFunc returned an error
		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
	}

	vErr := &ValidationError{}

	// Validate Claims
	if !p.SkipClaimsValidation {
		if err := token.Claims.Valid(); err != nil {

			// If the Claims Valid returned an error, check if it is a validation error,
			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
			if e, ok := err.(*ValidationError); !ok {
				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
			} else {
				vErr = e
			}
		}
	}

	// Perform validation
	token.Signature = parts[2]
	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
		vErr.Inner = err
		vErr.Errors |= ValidationErrorSignatureInvalid
	}

	if vErr.valid() {
		token.Valid = true
		return token, nil
	}

	return token, vErr
}
<commit_msg>Handle ValidationError returned by keyFunc in jwt.ParseWithClaims<commit_after>package jwt

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
)

type Parser struct {
	ValidMethods         []string // If populated, only these methods will be considered valid
	UseJSONNumber        bool     // Use JSON Number format in JSON decoder
	SkipClaimsValidation bool     // Skip claims validation during token parsing
}

// Parse, validate, and return a token.
// keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil
func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
}

func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) != 3 {
		return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
	}

	var err error
	token := &Token{Raw: tokenString}

	// parse Header
	var headerBytes []byte
	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
			return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
		}
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}
	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}

	// parse Claims
	var claimBytes []byte
	token.Claims = claims

	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}
	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
	if p.UseJSONNumber {
		dec.UseNumber()
	}
	// JSON Decode.  Special case for map type to avoid weird pointer behavior
	if c, ok := token.Claims.(MapClaims); ok {
		err = dec.Decode(&c)
	} else {
		err = dec.Decode(&claims)
	}
	// Handle decode error
	if err != nil {
		return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
	}

	// Lookup signature method
	if method, ok := token.Header["alg"].(string); ok {
		if token.Method = GetSigningMethod(method); token.Method == nil {
			return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
		}
	} else {
		return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
	}

	// Verify signing method is in the required set
	if p.ValidMethods != nil {
		var signingMethodValid = false
		var alg = token.Method.Alg()
		for _, m := range p.ValidMethods {
			if m == alg {
				signingMethodValid = true
				break
			}
		}
		if !signingMethodValid {
			// signing method is not in the listed set
			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
		}
	}

	// Lookup key
	var key interface{}
	if keyFunc == nil {
		// keyFunc was not provided.  short circuiting validation
		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
	}
	if key, err = keyFunc(token); err != nil {
		// keyFunc returned an error
		if ve, ok := err.(*ValidationError); ok {
			return token, ve
		}
		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
	}

	vErr := &ValidationError{}

	// Validate Claims
	if !p.SkipClaimsValidation {
		if err := token.Claims.Valid(); err != nil {

			// If the Claims Valid returned an error, check if it is a validation error,
			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
			if e, ok := err.(*ValidationError); !ok {
				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
			} else {
				vErr = e
			}
		}
	}

	// Perform validation
	token.Signature = parts[2]
	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
		vErr.Inner = err
		vErr.Errors |= ValidationErrorSignatureInvalid
	}

	if vErr.valid() {
		token.Valid = true
		return token, nil
	}

	return token, vErr
}
<|endoftext|>


<commit_before>package jsh

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

/*
ParseObject validates the HTTP request and returns a JSON object for a given
io.ReadCloser containing a raw JSON payload. Here's an example of how to use it
as part of your full flow.

	func Handler(w http.ResponseWriter, r *http.Request) {
		obj, error := jsh.ParseObject(r)
		if error != nil {
			// log your error
			err := jsh.Send(w, r, error)
			return
		}

		yourType := &YourType{}

		err := object.Unmarshal("yourtype", &yourType)
		if err != nil {
			err := jsh.Send(w, r, err)
			return
		}

		yourType.ID = obj.ID
		// do business logic

		err := object.Marshal(yourType)
		if err != nil {
			// log error
			err := jsh.Send(w, r, err)
			return
		}

		err := jsh.Send(w, r, object)
	}
*/
func ParseObject(r *http.Request) (*Object, *Error) {
	document, err := ParseDoc(r, ObjectMode)
	if err != nil {
		return nil, err
	}

	if !document.HasData() {
		return nil, TopLevelError("data")
	}

	object := document.First()
	if r.Method != "POST" && object.ID == "" {
		return nil, InputError("Missing mandatory object attribute", "id")
	}

	return object, nil
}

/*
ParseList validates the HTTP request and returns a resulting list of objects
parsed from the request Body. Use just like ParseObject.
*/
func ParseList(r *http.Request) (List, *Error) {
	document, err := ParseDoc(r, ListMode)
	if err != nil {
		return nil, err
	}

	return document.Data, nil
}

/*
ParseDoc parses and returns a top level jsh.Document. In most cases, using
"ParseList" or "ParseObject" is preferable.
*/
func ParseDoc(r *http.Request, mode DocumentMode) (*Document, *Error) {
	return NewParser(r).Document(r.Body, mode)
}

// Parser is an abstraction layer that helps to support parsing JSON payload from
// many types of sources, and allows other libraries to leverage this if desired.
type Parser struct {
	Method  string
	Headers http.Header
}

// NewParser creates a parser from an http.Request
func NewParser(request *http.Request) *Parser {
	return &Parser{
		Method:  request.Method,
		Headers: request.Header,
	}
}

/*
Document returns a single JSON data object from the parser. In the process it will
also validate any data objects against the JSON API.
*/
func (p *Parser) Document(payload io.ReadCloser, mode DocumentMode) (*Document, *Error) {
	defer closeReader(payload)

	err := validateHeaders(p.Headers)
	if err != nil {
		return nil, err
	}

	document := &Document{
		Data: List{},
		Mode: mode,
	}

	decodeErr := json.NewDecoder(payload).Decode(document)
	if decodeErr != nil {
		return nil, BadRequestError("Invalid JSON Document", decodeErr.Error())
	}

	// If the document has data, validate against specification
	if document.HasData() {
		for _, object := range document.Data {

			// TODO: currently this doesn't really do any user input
			// validation since it is validating against the jsh
			// "Object" type. Figure out how to options pass the
			// corressponding user object struct in to enable this
			// without making the API super clumsy.
			inputErr := validateInput(object)
			if inputErr != nil {
				return nil, inputErr[0]
			}

			// if we have a list, then all resource objects should have IDs, will
			// cross the bridge of bulk creation if and when there is a use case
			if len(document.Data) > 1 && object.ID == "" {
				return nil, InputError("Object without ID present in list", "id")
			}
		}
	}

	return document, nil
}

/*
closeReader is a deferal helper function for closing a reader and logging any errors that might occur after the fact.
*/
func closeReader(reader io.ReadCloser) {
	err := reader.Close()
	if err != nil {
		log.Println("Unable to close request Body")
	}
}

func validateHeaders(headers http.Header) *Error {

	reqContentType := headers.Get("Content-Type")
	if reqContentType != ContentType {
		return SpecificationError(fmt.Sprintf(
			"Expected Content-Type header to be %s, got: %s",
			ContentType,
			reqContentType,
		))
	}

	return nil
}
<commit_msg>Set empty object attributes to valid JSON to allow for valid unmarshalling<commit_after>package jsh

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

/*
ParseObject validates the HTTP request and returns a JSON object for a given
io.ReadCloser containing a raw JSON payload. Here's an example of how to use it
as part of your full flow.

	func Handler(w http.ResponseWriter, r *http.Request) {
		obj, error := jsh.ParseObject(r)
		if error != nil {
			// log your error
			err := jsh.Send(w, r, error)
			return
		}

		yourType := &YourType{}

		err := object.Unmarshal("yourtype", &yourType)
		if err != nil {
			err := jsh.Send(w, r, err)
			return
		}

		yourType.ID = obj.ID
		// do business logic

		err := object.Marshal(yourType)
		if err != nil {
			// log error
			err := jsh.Send(w, r, err)
			return
		}

		err := jsh.Send(w, r, object)
	}
*/
func ParseObject(r *http.Request) (*Object, *Error) {
	document, err := ParseDoc(r, ObjectMode)
	if err != nil {
		return nil, err
	}

	if !document.HasData() {
		return nil, TopLevelError("data")
	}

	object := document.First()
	if r.Method != "POST" && object.ID == "" {
		return nil, InputError("Missing mandatory object attribute", "id")
	}

	return object, nil
}

/*
ParseList validates the HTTP request and returns a resulting list of objects
parsed from the request Body. Use just like ParseObject.
*/
func ParseList(r *http.Request) (List, *Error) {
	document, err := ParseDoc(r, ListMode)
	if err != nil {
		return nil, err
	}

	return document.Data, nil
}

/*
ParseDoc parses and returns a top level jsh.Document. In most cases, using
"ParseList" or "ParseObject" is preferable.
*/
func ParseDoc(r *http.Request, mode DocumentMode) (*Document, *Error) {
	return NewParser(r).Document(r.Body, mode)
}

// Parser is an abstraction layer that helps to support parsing JSON payload from
// many types of sources, and allows other libraries to leverage this if desired.
type Parser struct {
	Method  string
	Headers http.Header
}

// NewParser creates a parser from an http.Request
func NewParser(request *http.Request) *Parser {
	return &Parser{
		Method:  request.Method,
		Headers: request.Header,
	}
}

/*
Document returns a single JSON data object from the parser. In the process it will
also validate any data objects against the JSON API.
*/
func (p *Parser) Document(payload io.ReadCloser, mode DocumentMode) (*Document, *Error) {
	defer closeReader(payload)

	err := validateHeaders(p.Headers)
	if err != nil {
		return nil, err
	}

	document := &Document{
		Data: List{},
		Mode: mode,
	}

	decodeErr := json.NewDecoder(payload).Decode(document)
	if decodeErr != nil {
		return nil, BadRequestError("Invalid JSON Document", decodeErr.Error())
	}

	// If the document has data, validate against specification
	if document.HasData() {
		for _, object := range document.Data {

			// TODO: currently this doesn't really do any user input
			// validation since it is validating against the jsh
			// "Object" type. Figure out how to options pass the
			// corressponding user object struct in to enable this
			// without making the API super clumsy.
			inputErr := validateInput(object)
			if inputErr != nil {
				return nil, inputErr[0]
			}

			// if we have a list, then all resource objects should have IDs, will
			// cross the bridge of bulk creation if and when there is a use case
			if len(document.Data) > 1 && object.ID == "" {
				return nil, InputError("Object without ID present in list", "id")
			}

			// If an object's attribute is empty, at least set it to valid JSON so that unmarshalling can succeed.
			if len(object.Attributes) == 0 {
				object.Attributes = json.RawMessage("{}")
			}
		}
	}

	return document, nil
}

/*
closeReader is a deferal helper function for closing a reader and logging any errors that might occur after the fact.
*/
func closeReader(reader io.ReadCloser) {
	err := reader.Close()
	if err != nil {
		log.Println("Unable to close request Body")
	}
}

func validateHeaders(headers http.Header) *Error {

	reqContentType := headers.Get("Content-Type")
	if reqContentType != ContentType {
		return SpecificationError(fmt.Sprintf(
			"Expected Content-Type header to be %s, got: %s",
			ContentType,
			reqContentType,
		))
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Markus Lindenberg, Stig Bakken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"strconv"
	"strings"
	"text/scanner"

	"github.com/prometheus/common/log"
)

type metric struct {
	Name  string
	Value float64
}

type labelset struct {
	Names  []string
	Values []string
}

func (l *labelset) Equals(labels []string) bool {
	if len(l.Names) != len(labels) {
		return false
	}
	for i := range l.Names {
		if l.Names[i] != labels[i] {
			return false
		}
	}
	return true
}

func parseMessage(src string, path_mappings []path_mappings) (metrics []metric, labels *labelset, err error) {
	metrics = make([]metric, 0)
	labels = &labelset{
		Names:  make([]string, 0),
		Values: make([]string, 0),
	}

	var s scanner.Scanner
	s.Init(strings.NewReader(src))
	var tok rune
	for {
		tok = s.Scan()
		if tok == scanner.EOF {
			return
		} else if tok != scanner.Ident {
			err = fmt.Errorf("Ident expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
			return
		}
		name := s.TokenText()

		tok = s.Scan()
		if tok == ':' {
			// Metric
			tok = s.Scan()
			if tok == scanner.Float || tok == scanner.Int {
				var value float64
				value, err = strconv.ParseFloat(s.TokenText(), 64)
				if err != nil {
					return
				}
				if (name == "time") {
					// varnishncsa's unit here is microseconds
					value = value / 1000000.0
				}
				metrics = append(metrics, metric{
					Name:  name,
					Value: value,
				})
			} else {
				err = fmt.Errorf("Float or Int expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
				return
			}

		} else if tok == '=' {
			// Label
			tok = s.Scan()
			var value string
			if tok == scanner.Ident || tok == scanner.Float || tok == scanner.Int {
				value = s.TokenText()
			} else if tok == scanner.String {
				value, err = strconv.Unquote(s.TokenText())
				if err != nil {
					return
				}
				// a bit nasty to hardcode this, but we do hardcode the field name when running varnishncsa..
				if name == "path" {
					for i := range path_mappings {
						mapping := path_mappings[i]
						log.Debugf("replacing '%v' with '%s' in '%s'\n", mapping.Pattern, mapping.Replacement, value)
						value = mapping.Pattern.ReplaceAllString(value, mapping.Replacement)
					}
				}
			} else {
				err = fmt.Errorf("Ident or String expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
			}

			labels.Names = append(labels.Names, name)
			labels.Values = append(labels.Values, value)
		} else {
			err = fmt.Errorf(": or = expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
			return
		}
	}
	return
}
<commit_msg>gofmt fix<commit_after>// Copyright 2016 Markus Lindenberg, Stig Bakken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"strconv"
	"strings"
	"text/scanner"

	"github.com/prometheus/common/log"
)

type metric struct {
	Name  string
	Value float64
}

type labelset struct {
	Names  []string
	Values []string
}

func (l *labelset) Equals(labels []string) bool {
	if len(l.Names) != len(labels) {
		return false
	}
	for i := range l.Names {
		if l.Names[i] != labels[i] {
			return false
		}
	}
	return true
}

func parseMessage(src string, path_mappings []path_mappings) (metrics []metric, labels *labelset, err error) {
	metrics = make([]metric, 0)
	labels = &labelset{
		Names:  make([]string, 0),
		Values: make([]string, 0),
	}

	var s scanner.Scanner
	s.Init(strings.NewReader(src))
	var tok rune
	for {
		tok = s.Scan()
		if tok == scanner.EOF {
			return
		} else if tok != scanner.Ident {
			err = fmt.Errorf("Ident expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
			return
		}
		name := s.TokenText()

		tok = s.Scan()
		if tok == ':' {
			// Metric
			tok = s.Scan()
			if tok == scanner.Float || tok == scanner.Int {
				var value float64
				value, err = strconv.ParseFloat(s.TokenText(), 64)
				if err != nil {
					return
				}
				if name == "time" {
					// varnishncsa's unit here is microseconds
					value = value / 1000000.0
				}
				metrics = append(metrics, metric{
					Name:  name,
					Value: value,
				})
			} else {
				err = fmt.Errorf("Float or Int expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
				return
			}

		} else if tok == '=' {
			// Label
			tok = s.Scan()
			var value string
			if tok == scanner.Ident || tok == scanner.Float || tok == scanner.Int {
				value = s.TokenText()
			} else if tok == scanner.String {
				value, err = strconv.Unquote(s.TokenText())
				if err != nil {
					return
				}
				// a bit nasty to hardcode this, but we do hardcode the field name when running varnishncsa..
				if name == "path" {
					for i := range path_mappings {
						mapping := path_mappings[i]
						log.Debugf("replacing '%v' with '%s' in '%s'\n", mapping.Pattern, mapping.Replacement, value)
						value = mapping.Pattern.ReplaceAllString(value, mapping.Replacement)
					}
				}
			} else {
				err = fmt.Errorf("Ident or String expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
			}

			labels.Names = append(labels.Names, name)
			labels.Values = append(labels.Values, value)
		} else {
			err = fmt.Errorf(": or = expected at %v, got %s", s.Pos(), scanner.TokenString(tok))
			return
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

func parse(grid *TokenGrid) (*Program, error) {
	// TODO: support more than one input and output per layer
	program := &Program{
		Size:  grid.Size,
		Cells: make(map[Index]*Cell),
	}

	// Build cells & the layer channels
	for idx, r := range grid.Tokens {
		cell := &Cell{
			Symbol: r,
		}
		switch r {
		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			n := Value(r - '0')
			cell.Type = &Constant{n}
			cell.Read = n
		case '@':
			cell.Type = &Forward{
				SourceDir: DirNone,
				SinkDir:   DirsPlane,
			}
		case '!':
			cell.Type = &Forward{
				SourceDir: DirsPlane,
				SinkDir:   DirNone,
			}
		case '^':
			cell.Type = &Forward{
				SourceDir: DirRight | DirLeft | DirDown,
				SinkDir:   DirUp,
			}
		case '<':
			cell.Type = &Forward{
				SourceDir: DirRight | DirUp | DirDown,
				SinkDir:   DirLeft,
			}
		case '>':
			cell.Type = &Forward{
				SourceDir: DirUp | DirLeft | DirDown,
				SinkDir:   DirRight,
			}
		case 'v':
			cell.Type = &Forward{
				SourceDir: DirRight | DirLeft | DirUp,
				SinkDir:   DirDown,
			}
		case 'C':
			cell.Type = &Oscillator{
				Period: 1,
				Function: func(i, p uint64) Value {
					return Value(i)
				},
			}
		case '+':
			cell.Type = &BinaryOp{
				Function: func(a, b Value) Value {
					return a + b
				},
			}
		case '*':
			cell.Type = &BinaryOp{
				Function: func(a, b Value) Value {
					return a * b
				},
			}
		case '-':
			cell.Type = &UnaryOp{
				Function: func(a Value) Value {
					return -a
				},
			}
		case 'P':
			cell.Type = &Pulse{
				Value: Value(1),
			}
		}

		program.Cells[idx] = cell
	}

	// Link cells
	// TODO: raise error if has no connection
	for idx, cell := range program.Cells {
		// Try to bind all the neighbours
		for _, dir := range Dirs(cell.Type.RequestDir()) {
			nidx, err := idx.Neighbour(dir)
			if err != nil {
				return nil, err
			}

			neighbour, ok := program.Cells[nidx]
			if !ok {
				continue
			}

			// Try to matching offer and request
			if InverseDir(dir)&neighbour.Type.OfferDir() == 0 {
				continue
			}

			if err := cell.Type.Bind(&neighbour.Read); err != nil {
				return nil, err
			}
		}

		switch cell.Symbol {
		case '@':
			cell.Type.Bind(&program.read)
			continue
		case '!':
			program.write = &cell.Read
		}
	}

	return program, nil
}
<commit_msg>Improve error msg on neighbourhood<commit_after>package main

import (
	"fmt"
)

func parse(grid *TokenGrid) (*Program, error) {
	// TODO: support more than one input and output per layer
	program := &Program{
		Size:  grid.Size,
		Cells: make(map[Index]*Cell),
	}

	// Build cells & the layer channels
	for idx, r := range grid.Tokens {
		cell := &Cell{
			Symbol: r,
		}
		switch r {
		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			n := Value(r - '0')
			cell.Type = &Constant{n}
			cell.Read = n
		case '@':
			cell.Type = &Forward{
				SourceDir: DirNone,
				SinkDir:   DirsPlane,
			}
		case '!':
			cell.Type = &Forward{
				SourceDir: DirsPlane,
				SinkDir:   DirNone,
			}
		case '^':
			cell.Type = &Forward{
				SourceDir: DirRight | DirLeft | DirDown,
				SinkDir:   DirUp,
			}
		case '<':
			cell.Type = &Forward{
				SourceDir: DirRight | DirUp | DirDown,
				SinkDir:   DirLeft,
			}
		case '>':
			cell.Type = &Forward{
				SourceDir: DirUp | DirLeft | DirDown,
				SinkDir:   DirRight,
			}
		case 'v':
			cell.Type = &Forward{
				SourceDir: DirRight | DirLeft | DirUp,
				SinkDir:   DirDown,
			}
		case 'C':
			cell.Type = &Oscillator{
				Period: 1,
				Function: func(i, p uint64) Value {
					return Value(i)
				},
			}
		case '+':
			cell.Type = &BinaryOp{
				Function: func(a, b Value) Value {
					return a + b
				},
			}
		case '*':
			cell.Type = &BinaryOp{
				Function: func(a, b Value) Value {
					return a * b
				},
			}
		case '-':
			cell.Type = &UnaryOp{
				Function: func(a Value) Value {
					return -a
				},
			}
		case 'P':
			cell.Type = &Pulse{
				Value: Value(1),
			}
		}

		program.Cells[idx] = cell
	}

	// Link cells
	// TODO: raise error if has no connection
	for idx, cell := range program.Cells {
		// Try to bind all the neighbours
		for _, dir := range Dirs(cell.Type.RequestDir()) {
			nidx, err := idx.Neighbour(dir)
			if err != nil {
				return nil, fmt.Errorf("Error in neighborhood: %v", err)
			}

			neighbour, ok := program.Cells[nidx]
			if !ok {
				continue
			}

			// Try to matching offer and request
			if InverseDir(dir)&neighbour.Type.OfferDir() == 0 {
				continue
			}

			if err := cell.Type.Bind(&neighbour.Read); err != nil {
				return nil, err
			}
		}

		switch cell.Symbol {
		case '@':
			cell.Type.Bind(&program.read)
			continue
		case '!':
			program.write = &cell.Read
		}
	}

	return program, nil
}
<|endoftext|>


<commit_before>package gofeed

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/mmcdole/gofeed/atom"
	"github.com/mmcdole/gofeed/json"
	"github.com/mmcdole/gofeed/rss"
)

// ErrFeedTypeNotDetected is returned when the detection system can not figure
// out the Feed format
var ErrFeedTypeNotDetected = errors.New("Failed to detect feed type")

// HTTPError represents an HTTP error returned by a server.
type HTTPError struct {
	StatusCode int
	Status     string
}

func (err HTTPError) Error() string {
	return fmt.Sprintf("http error: %s", err.Status)
}

// Parser is a universal feed parser that detects
// a given feed type, parsers it, and translates it
// to the universal feed type.
type Parser struct {
	AtomTranslator Translator
	RSSTranslator  Translator
	JSONTranslator Translator
	Client         *http.Client
	rp             *rss.Parser
	ap             *atom.Parser
	jp             *json.Parser
}

// NewParser creates a universal feed parser.
func NewParser() *Parser {
	fp := Parser{
		rp: &rss.Parser{},
		ap: &atom.Parser{},
		jp: &json.Parser{},
	}
	return &fp
}

// Parse parses a RSS or Atom or JSON feed into
// the universal gofeed.Feed.  It takes an
// io.Reader which should return the xml/json content.
func (f *Parser) Parse(feed io.Reader) (*Feed, error) {
	// Wrap the feed io.Reader in a io.TeeReader
	// so we can capture all the bytes read by the
	// DetectFeedType function and construct a new
	// reader with those bytes intact for when we
	// attempt to parse the feeds.
	var buf bytes.Buffer
	tee := io.TeeReader(feed, &buf)
	feedType := DetectFeedType(tee)

	// Glue the read bytes from the detect function
	// back into a new reader
	r := io.MultiReader(&buf, feed)

	switch feedType {
	case FeedTypeAtom:
		return f.parseAtomFeed(r)
	case FeedTypeRSS:
		return f.parseRSSFeed(r)
	case FeedTypeJSON:
		return f.parseJSONFeed(r)
	}

	return nil, ErrFeedTypeNotDetected
}

// ParseURL fetches the contents of a given url and
// attempts to parse the response into the universal feed type.
func (f *Parser) ParseURL(feedURL string) (feed *Feed, err error) {
	return f.ParseURLWithContext(feedURL, context.Background())
}

// ParseURLWithContext fetches contents of a given url and
// attempts to parse the response into the universal feed type.
// Request could be canceled or timeout via given context
func (f *Parser) ParseURLWithContext(feedURL string, ctx context.Context) (feed *Feed, err error) {
	client := f.httpClient()

	req, err := http.NewRequest("GET", feedURL, nil)
	if err != nil {
		return nil, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("User-Agent", "Gofeed/1.0")
	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	if resp != nil {
		defer func() {
			ce := resp.Body.Close()
			if ce != nil {
				err = ce
			}
		}()
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, HTTPError{
			StatusCode: resp.StatusCode,
			Status:     resp.Status,
		}
	}

	return f.Parse(resp.Body)
}

// ParseString parses a feed XML string and into the
// universal feed type.
func (f *Parser) ParseString(feed string) (*Feed, error) {
	return f.Parse(strings.NewReader(feed))
}

func (f *Parser) parseAtomFeed(feed io.Reader) (*Feed, error) {
	af, err := f.ap.Parse(feed)
	if err != nil {
		return nil, err
	}
	return f.atomTrans().Translate(af)
}

func (f *Parser) parseRSSFeed(feed io.Reader) (*Feed, error) {
	rf, err := f.rp.Parse(feed)
	if err != nil {
		return nil, err
	}

	return f.rssTrans().Translate(rf)
}

func (f *Parser) parseJSONFeed(feed io.Reader) (*Feed, error) {
	jf, err := f.jp.Parse(feed)
	if err != nil {
		return nil, err
	}
	return f.jsonTrans().Translate(jf)
}

func (f *Parser) atomTrans() Translator {
	if f.AtomTranslator != nil {
		return f.AtomTranslator
	}
	f.AtomTranslator = &DefaultAtomTranslator{}
	return f.AtomTranslator
}

func (f *Parser) rssTrans() Translator {
	if f.RSSTranslator != nil {
		return f.RSSTranslator
	}
	f.RSSTranslator = &DefaultRSSTranslator{}
	return f.RSSTranslator
}

func (f *Parser) jsonTrans() Translator {
	if f.JSONTranslator != nil {
		return f.JSONTranslator
	}
	f.JSONTranslator = &DefaultJSONTranslator{}
	return f.JSONTranslator
}

func (f *Parser) httpClient() *http.Client {
	if f.Client != nil {
		return f.Client
	}
	f.Client = &http.Client{}
	return f.Client
}
<commit_msg>Make userAgent changable (#172)<commit_after>package gofeed

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/mmcdole/gofeed/atom"
	"github.com/mmcdole/gofeed/json"
	"github.com/mmcdole/gofeed/rss"
)

// ErrFeedTypeNotDetected is returned when the detection system can not figure
// out the Feed format
var ErrFeedTypeNotDetected = errors.New("Failed to detect feed type")

// HTTPError represents an HTTP error returned by a server.
type HTTPError struct {
	StatusCode int
	Status     string
}

func (err HTTPError) Error() string {
	return fmt.Sprintf("http error: %s", err.Status)
}

// Parser is a universal feed parser that detects
// a given feed type, parsers it, and translates it
// to the universal feed type.
type Parser struct {
	AtomTranslator Translator
	RSSTranslator  Translator
	JSONTranslator Translator
	UserAgent      string
	Client         *http.Client
	rp             *rss.Parser
	ap             *atom.Parser
	jp             *json.Parser
}

// NewParser creates a universal feed parser.
func NewParser() *Parser {
	fp := Parser{
		rp:        &rss.Parser{},
		ap:        &atom.Parser{},
		jp:        &json.Parser{},
		UserAgent: "Gofeed/1.0",
	}
	return &fp
}

// Parse parses a RSS or Atom or JSON feed into
// the universal gofeed.Feed.  It takes an
// io.Reader which should return the xml/json content.
func (f *Parser) Parse(feed io.Reader) (*Feed, error) {
	// Wrap the feed io.Reader in a io.TeeReader
	// so we can capture all the bytes read by the
	// DetectFeedType function and construct a new
	// reader with those bytes intact for when we
	// attempt to parse the feeds.
	var buf bytes.Buffer
	tee := io.TeeReader(feed, &buf)
	feedType := DetectFeedType(tee)

	// Glue the read bytes from the detect function
	// back into a new reader
	r := io.MultiReader(&buf, feed)

	switch feedType {
	case FeedTypeAtom:
		return f.parseAtomFeed(r)
	case FeedTypeRSS:
		return f.parseRSSFeed(r)
	case FeedTypeJSON:
		return f.parseJSONFeed(r)
	}

	return nil, ErrFeedTypeNotDetected
}

// ParseURL fetches the contents of a given url and
// attempts to parse the response into the universal feed type.
func (f *Parser) ParseURL(feedURL string) (feed *Feed, err error) {
	return f.ParseURLWithContext(feedURL, context.Background())
}

// ParseURLWithContext fetches contents of a given url and
// attempts to parse the response into the universal feed type.
// Request could be canceled or timeout via given context
func (f *Parser) ParseURLWithContext(feedURL string, ctx context.Context) (feed *Feed, err error) {
	client := f.httpClient()

	req, err := http.NewRequest("GET", feedURL, nil)
	if err != nil {
		return nil, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("User-Agent", f.UserAgent)
	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	if resp != nil {
		defer func() {
			ce := resp.Body.Close()
			if ce != nil {
				err = ce
			}
		}()
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, HTTPError{
			StatusCode: resp.StatusCode,
			Status:     resp.Status,
		}
	}

	return f.Parse(resp.Body)
}

// ParseString parses a feed XML string and into the
// universal feed type.
func (f *Parser) ParseString(feed string) (*Feed, error) {
	return f.Parse(strings.NewReader(feed))
}

func (f *Parser) parseAtomFeed(feed io.Reader) (*Feed, error) {
	af, err := f.ap.Parse(feed)
	if err != nil {
		return nil, err
	}
	return f.atomTrans().Translate(af)
}

func (f *Parser) parseRSSFeed(feed io.Reader) (*Feed, error) {
	rf, err := f.rp.Parse(feed)
	if err != nil {
		return nil, err
	}

	return f.rssTrans().Translate(rf)
}

func (f *Parser) parseJSONFeed(feed io.Reader) (*Feed, error) {
	jf, err := f.jp.Parse(feed)
	if err != nil {
		return nil, err
	}
	return f.jsonTrans().Translate(jf)
}

func (f *Parser) atomTrans() Translator {
	if f.AtomTranslator != nil {
		return f.AtomTranslator
	}
	f.AtomTranslator = &DefaultAtomTranslator{}
	return f.AtomTranslator
}

func (f *Parser) rssTrans() Translator {
	if f.RSSTranslator != nil {
		return f.RSSTranslator
	}
	f.RSSTranslator = &DefaultRSSTranslator{}
	return f.RSSTranslator
}

func (f *Parser) jsonTrans() Translator {
	if f.JSONTranslator != nil {
		return f.JSONTranslator
	}
	f.JSONTranslator = &DefaultJSONTranslator{}
	return f.JSONTranslator
}

func (f *Parser) httpClient() *http.Client {
	if f.Client != nil {
		return f.Client
	}
	f.Client = &http.Client{}
	return f.Client
}
<|endoftext|>


<commit_before>package hbapi

import (
	"strconv"
	"time"

	rss "github.com/jteeuwen/go-pkg-rss"
)

// XML Namespace
const (
	xmlNSContent    = "http://purl.org/rss/1.0/modules/content/"
	xmlNSOpenSearch = "http://a9.com/-/spec/opensearchrss/1.0/"
	xmlNSDC         = "http://purl.org/dc/elements/1.1/"
	xmlNSHatena     = "http://www.hatena.ne.jp/info/xmlns#"
)

// XML Node
const (
	xmlNodeStartIndex    = "startIndex"
	xmlNodeItemsPerPage  = "itemsPerPage"
	xmlNodeTotalResults  = "totalResults"
	xmlNodeEncoded       = "encoded"
	xmlNodeCreator       = "creator"
	xmlNodeDate          = "date"
	xmlNodeBookmarkCount = "bookmarkcount"
	xmlNodeSubject       = "subject"
)

// HTTP timeout
const (
	timeout = 10
)

type parser struct{}

func newParser() parser {
	return parser{}
}

// Parse feed.
func (p parser) Parse(req string) (UnifiedFeed, error) {
	feed := rss.New(timeout, true, nil, nil)
	if err := feed.Fetch(req, nil); err != nil {
		return UnifiedFeed{}, err
	}

	channel := feed.Channels[0]
	opensearch := channel.Extensions[xmlNSOpenSearch]

	f := UnifiedFeed{}
	f.Title = channel.Title
	f.Link = channel.Links[0].Href
	f.Description = channel.Description
	if opensearch[xmlNodeStartIndex] != nil {
		startIndex, _ := strconv.Atoi(opensearch[xmlNodeStartIndex][0].Value)
		f.StartIndex = startIndex
	}
	if opensearch[xmlNodeItemsPerPage] != nil {
		itemsPerPage, _ := strconv.Atoi(opensearch[xmlNodeItemsPerPage][0].Value)
		f.ItemsPerPage = itemsPerPage
	}
	if opensearch[xmlNodeTotalResults] != nil {
		totalResults, _ := strconv.Atoi(opensearch[xmlNodeTotalResults][0].Value)
		f.TotalResults = totalResults
	}

	items := []UnifiedFeedItem{}
	for _, item := range channel.Items {
		content := item.Extensions[xmlNSContent]
		dc := item.Extensions[xmlNSDC]
		hatena := item.Extensions[xmlNSHatena]

		i := UnifiedFeedItem{}
		i.Title = item.Title
		i.Link = item.Links[0].Href
		i.Description = item.Description
		if content[xmlNodeEncoded] != nil {
			i.Content = content[xmlNodeEncoded][0].Value
		}
		if dc[xmlNodeCreator] != nil {
			i.Creator = dc[xmlNodeCreator][0].Value
		}
		if dc[xmlNodeDate] != nil {
			date, _ := time.Parse(time.RFC3339, dc[xmlNodeDate][0].Value)
			i.Date = date
		}
		if hatena[xmlNodeBookmarkCount] != nil {
			bookmarkCount, _ := strconv.Atoi(hatena[xmlNodeBookmarkCount][0].Value)
			i.BookmarkCount = bookmarkCount
		}
		if dc[xmlNodeSubject] != nil {
			for _, subject := range dc[xmlNodeSubject] {
				i.Subject = append(i.Subject, subject.Value)
			}
		}
		items = append(items, i)
	}
	f.Items = items

	return f, nil

}
<commit_msg>remove whitespace<commit_after>package hbapi

import (
	"strconv"
	"time"

	rss "github.com/jteeuwen/go-pkg-rss"
)

// XML Namespace
const (
	xmlNSContent    = "http://purl.org/rss/1.0/modules/content/"
	xmlNSOpenSearch = "http://a9.com/-/spec/opensearchrss/1.0/"
	xmlNSDC         = "http://purl.org/dc/elements/1.1/"
	xmlNSHatena     = "http://www.hatena.ne.jp/info/xmlns#"
)

// XML Node
const (
	xmlNodeStartIndex    = "startIndex"
	xmlNodeItemsPerPage  = "itemsPerPage"
	xmlNodeTotalResults  = "totalResults"
	xmlNodeEncoded       = "encoded"
	xmlNodeCreator       = "creator"
	xmlNodeDate          = "date"
	xmlNodeBookmarkCount = "bookmarkcount"
	xmlNodeSubject       = "subject"
)

// HTTP timeout
const (
	timeout = 10
)

type parser struct{}

func newParser() parser {
	return parser{}
}

// Parse feed.
func (p parser) Parse(req string) (UnifiedFeed, error) {
	feed := rss.New(timeout, true, nil, nil)
	if err := feed.Fetch(req, nil); err != nil {
		return UnifiedFeed{}, err
	}

	channel := feed.Channels[0]
	opensearch := channel.Extensions[xmlNSOpenSearch]

	f := UnifiedFeed{}
	f.Title = channel.Title
	f.Link = channel.Links[0].Href
	f.Description = channel.Description
	if opensearch[xmlNodeStartIndex] != nil {
		startIndex, _ := strconv.Atoi(opensearch[xmlNodeStartIndex][0].Value)
		f.StartIndex = startIndex
	}
	if opensearch[xmlNodeItemsPerPage] != nil {
		itemsPerPage, _ := strconv.Atoi(opensearch[xmlNodeItemsPerPage][0].Value)
		f.ItemsPerPage = itemsPerPage
	}
	if opensearch[xmlNodeTotalResults] != nil {
		totalResults, _ := strconv.Atoi(opensearch[xmlNodeTotalResults][0].Value)
		f.TotalResults = totalResults
	}

	items := []UnifiedFeedItem{}
	for _, item := range channel.Items {
		content := item.Extensions[xmlNSContent]
		dc := item.Extensions[xmlNSDC]
		hatena := item.Extensions[xmlNSHatena]

		i := UnifiedFeedItem{}
		i.Title = item.Title
		i.Link = item.Links[0].Href
		i.Description = item.Description
		if content[xmlNodeEncoded] != nil {
			i.Content = content[xmlNodeEncoded][0].Value
		}
		if dc[xmlNodeCreator] != nil {
			i.Creator = dc[xmlNodeCreator][0].Value
		}
		if dc[xmlNodeDate] != nil {
			date, _ := time.Parse(time.RFC3339, dc[xmlNodeDate][0].Value)
			i.Date = date
		}
		if hatena[xmlNodeBookmarkCount] != nil {
			bookmarkCount, _ := strconv.Atoi(hatena[xmlNodeBookmarkCount][0].Value)
			i.BookmarkCount = bookmarkCount
		}
		if dc[xmlNodeSubject] != nil {
			for _, subject := range dc[xmlNodeSubject] {
				i.Subject = append(i.Subject, subject.Value)
			}
		}
		items = append(items, i)
	}
	f.Items = items

	return f, nil
}
<|endoftext|>


<commit_before>// Copyright 2012, Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// This file contains some test helper functions.

package layers

import (
	"code.google.com/p/gopacket"
	"testing"
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func checkLayers(p gopacket.Packet, want []gopacket.LayerType, t *testing.T) {
	layers := p.Layers()
	t.Log("Checking packet layers, want", want)
	for _, l := range layers {
		t.Logf("  Got layer %v, %d bytes, payload of %d bytes", l.LayerType(), len(l.LayerContents()), len(l.LayerPayload()))
	}
	t.Log(p)
	if len(layers) != len(want) {
		t.Errorf("  Number of layers mismatch: got %d want %d", len(want), len(layers))
		return
	}
	for i, l := range layers {
		if l.LayerType() != want[i] {
			t.Errorf("  Layer %d mismatch: got %v want %v", i, l.LayerType(), want[i])
		}
	}
}
<commit_msg>Typo: fix want/got inversion<commit_after>// Copyright 2012, Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// This file contains some test helper functions.

package layers

import (
	"code.google.com/p/gopacket"
	"testing"
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func checkLayers(p gopacket.Packet, want []gopacket.LayerType, t *testing.T) {
	layers := p.Layers()
	t.Log("Checking packet layers, want", want)
	for _, l := range layers {
		t.Logf("  Got layer %v, %d bytes, payload of %d bytes", l.LayerType(),
			len(l.LayerContents()), len(l.LayerPayload()))
	}
	t.Log(p)
	if len(layers) != len(want) {
		t.Errorf("  Number of layers mismatch: got %d want %d", len(layers),
			len(want))
		return
	}
	for i, l := range layers {
		if l.LayerType() != want[i] {
			t.Errorf("  Layer %d mismatch: got %v want %v", i, l.LayerType(),
				want[i])
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	m2log "github.com/fclairamb/m2mp/go/m2mp-log"
	logging "github.com/op/go-logging"
)

var log *logging.Logger

func init() {
	log = m2log.GetLogger()
}
<commit_msg>Color doesn't work well on windows.<commit_after>package main

import (
	m2log "github.com/fclairamb/m2mp/go/m2mp-log"
	logging "github.com/op/go-logging"
)

var log *logging.Logger

func init() {
	m2log.NoColor = true
	log = m2log.GetLogger()
}
<|endoftext|>


<commit_before>package linux

import (
	"github.com/lunixbochs/struc"
	"io"
	"io/ioutil"
	"os"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

const UINT64_MAX = 0xFFFFFFFFFFFFFFFF

func (k *LinuxKernel) getdents(dirfd co.Fd, buf co.Obuf, count uint64, bits uint) uint64 {
	dir, ok := k.Files[dirfd]
	if !ok {
		return UINT64_MAX // FIXME
	}
	dents, err := ioutil.ReadDir(dir.Path)
	if err != nil {
		return UINT64_MAX // FIXME
	}
	if dir.Offset >= uint64(len(dents)) {
		return 0
	}
	dents = dents[dir.Offset:]
	written := 0
	offset := dir.Offset
	out := buf.Struc()
	for i, f := range dents {
		// TODO: syscall.Stat_t portability?
		inode := f.Sys().(*syscall.Stat_t).Ino
		// figure out file mode
		mode := f.Mode()
		fileType := DT_REG
		if f.IsDir() {
			fileType = DT_DIR
		} else if mode&os.ModeNamedPipe > 0 {
			fileType = DT_FIFO
		} else if mode&os.ModeSymlink > 0 {
			fileType = DT_LNK
		} else if mode&os.ModeDevice > 0 {
			if mode&os.ModeCharDevice > 0 {
				fileType = DT_CHR
			} else {
				fileType = DT_BLK
			}
		} else if mode&os.ModeSocket > 0 {
			fileType = DT_SOCK
		}
		// TODO: does inode get truncated? guess it depends on guest LFS support
		var ent interface{}
		if bits == 64 {
			ent = &Dirent64{inode, dir.Offset + uint64(i), 0, fileType, f.Name() + "\x00"}
		} else {
			ent = &Dirent{inode, dir.Offset + uint64(i), 0, f.Name() + "\x00", fileType}
		}
		size, _ := struc.Sizeof(ent)
		if uint64(written+size) > count {
			break
		}
		offset++
		if bits == 64 {
			ent.(*Dirent64).Len = size
		} else {
			ent.(*Dirent).Len = size
		}
		written += size
		if err := out.Pack(ent); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	dir.Offset = offset
	return uint64(written)
}

func (k *LinuxKernel) Getdents(dirfd co.Fd, buf co.Obuf, count uint64) uint64 {
	return k.getdents(dirfd, buf, count, 32)
}

func (k *LinuxKernel) Getdents64(dirfd co.Fd, buf co.Obuf, count uint64) uint64 {
	return k.getdents(dirfd, buf, count, 64)
}

func (k *LinuxKernel) Sendfile(out, in co.Fd, off co.Buf, count uint64) uint64 {
	// TODO: the in_fd argument must correspond to a file which supports mmap(2)-like operations (i.e., it cannot be a socket).
	outFile := out.File()
	inFile := in.File()
	var offset struc.Off_t
	if off.Addr != 0 {
		if err := off.Unpack(&offset); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	written, err := io.CopyN(outFile, inFile, int64(count))
	// TODO: is EOF handling correct here?
	if (err != nil && err != io.EOF) || written < 0 {
		return UINT64_MAX // FIXME
	}
	return uint64(written)
}

func (k *LinuxKernel) Fstat64(fd co.Fd, buf co.Obuf) uint64 {
	return k.Fstat(fd, buf)
}

func (k *LinuxKernel) Lstat64(path string, buf co.Obuf) uint64 {
	return k.Lstat(path, buf)
}
<commit_msg>include . and .. in getdents<commit_after>package linux

import (
	"github.com/lunixbochs/struc"
	"io"
	"io/ioutil"
	"os"
	"path"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

const UINT64_MAX = 0xFFFFFFFFFFFFFFFF

type fileInfoProxy struct {
	os.FileInfo
	name string
}

func (f fileInfoProxy) Name() string {
	return f.name
}

func (k *LinuxKernel) getdents(dirfd co.Fd, buf co.Obuf, count uint64, bits uint) uint64 {
	dir, ok := k.Files[dirfd]
	if !ok {
		return UINT64_MAX // FIXME
	}
	var dents []os.FileInfo
	dent, err := os.Lstat(path.Join(dir.Path, ".."))
	if err == nil {
		dents = append(dents, fileInfoProxy{dent, ".."})
	}
	dent, err = os.Lstat(dir.Path)
	if err == nil {
		dents = append(dents, fileInfoProxy{dent, "."})
	}
	contents, err := ioutil.ReadDir(dir.Path)
	if err != nil {
		return UINT64_MAX // FIXME
	}
	dents = append(dents, contents...)
	if dir.Offset >= uint64(len(dents)) {
		return 0
	}
	dents = dents[dir.Offset:]
	written := 0
	offset := dir.Offset
	out := buf.Struc()
	for i, f := range dents {
		// TODO: syscall.Stat_t portability?
		inode := f.Sys().(*syscall.Stat_t).Ino
		// figure out file mode
		mode := f.Mode()
		fileType := DT_REG
		if f.IsDir() {
			fileType = DT_DIR
		} else if mode&os.ModeNamedPipe > 0 {
			fileType = DT_FIFO
		} else if mode&os.ModeSymlink > 0 {
			fileType = DT_LNK
		} else if mode&os.ModeDevice > 0 {
			if mode&os.ModeCharDevice > 0 {
				fileType = DT_CHR
			} else {
				fileType = DT_BLK
			}
		} else if mode&os.ModeSocket > 0 {
			fileType = DT_SOCK
		}
		// TODO: does inode get truncated? guess it depends on guest LFS support
		var ent interface{}
		if bits == 64 {
			ent = &Dirent64{inode, dir.Offset + uint64(i), 0, fileType, f.Name() + "\x00"}
		} else {
			ent = &Dirent{inode, dir.Offset + uint64(i), 0, f.Name() + "\x00", fileType}
		}
		size, _ := struc.Sizeof(ent)
		if uint64(written+size) > count {
			break
		}
		offset++
		if bits == 64 {
			ent.(*Dirent64).Len = size
		} else {
			ent.(*Dirent).Len = size
		}
		written += size
		if err := out.Pack(ent); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	dir.Offset = offset
	return uint64(written)
}

func (k *LinuxKernel) Getdents(dirfd co.Fd, buf co.Obuf, count uint64) uint64 {
	return k.getdents(dirfd, buf, count, 32)
}

func (k *LinuxKernel) Getdents64(dirfd co.Fd, buf co.Obuf, count uint64) uint64 {
	return k.getdents(dirfd, buf, count, 64)
}

func (k *LinuxKernel) Sendfile(out, in co.Fd, off co.Buf, count uint64) uint64 {
	// TODO: the in_fd argument must correspond to a file which supports mmap(2)-like operations (i.e., it cannot be a socket).
	outFile := out.File()
	inFile := in.File()
	var offset struc.Off_t
	if off.Addr != 0 {
		if err := off.Unpack(&offset); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	written, err := io.CopyN(outFile, inFile, int64(count))
	// TODO: is EOF handling correct here?
	if (err != nil && err != io.EOF) || written < 0 {
		return UINT64_MAX // FIXME
	}
	return uint64(written)
}

func (k *LinuxKernel) Fstat64(fd co.Fd, buf co.Obuf) uint64 {
	return k.Fstat(fd, buf)
}

func (k *LinuxKernel) Lstat64(path string, buf co.Obuf) uint64 {
	return k.Lstat(path, buf)
}
<|endoftext|>