<commit_before>// Copyright 2018 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.

package logger

import (
	"bytes"
	"testing"

	"github.com/stretchr/testify/assert"
)

func readBuf(buf *bytes.Buffer) string {
	str := buf.String()
	buf.Reset()
	return str
}

func TestLogger(t *testing.T) {
	buf := new(bytes.Buffer)
	SetOutput(buf)

	Debug("debug log, should ignore by default")
	assert.Empty(t, readBuf(buf))

	Info("info log, should visable")
	assert.Contains(t, readBuf(buf), "info log, should visable")

	Info("format [%d]", 111)
	assert.Contains(t, readBuf(buf), "format [111]")

	SetLevelByString("debug")
	Debug("debug log, now it becomes visible")
	assert.Contains(t, readBuf(buf), "debug log, now it becomes visible")

	logger = NewLogger()
	logger.SetPrefix("(prefix)").SetSuffix("(suffix)").SetOutput(buf)

	logger.Warn("log_content")
	assert.Contains(t, readBuf(buf), " -WARNING- (prefix)log_content (testing.go:777)(suffix)")
}
<commit_msg>Fix ci error<commit_after>// Copyright 2018 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.

package logger

import (
	"bytes"
	"testing"

	"github.com/stretchr/testify/assert"
)

func readBuf(buf *bytes.Buffer) string {
	str := buf.String()
	buf.Reset()
	return str
}

func TestLogger(t *testing.T) {
	buf := new(bytes.Buffer)
	SetOutput(buf)

	Debug("debug log, should ignore by default")
	assert.Empty(t, readBuf(buf))

	Info("info log, should visable")
	assert.Contains(t, readBuf(buf), "info log, should visable")

	Info("format [%d]", 111)
	assert.Contains(t, readBuf(buf), "format [111]")

	SetLevelByString("debug")
	Debug("debug log, now it becomes visible")
	assert.Contains(t, readBuf(buf), "debug log, now it becomes visible")

	logger = NewLogger()
	logger.SetPrefix("(prefix)").SetSuffix("(suffix)").SetOutput(buf)

	logger.Warn("log_content")
	assert.Regexp(t, " -WARNING- \\(prefix\\)log_content \\(testing.go:\\d+\\)\\(suffix\\)", readBuf(buf))
}
<|endoftext|>


<commit_before>package basic

import (
	"errors"

	"github.com/hellofresh/janus/pkg/plugin"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
)

var (
	repo        Repository
	adminRouter router.Router
)

func init() {
	plugin.RegisterEventHook(plugin.StartupEvent, onStartup)
	plugin.RegisterEventHook(plugin.AdminAPIStartupEvent, onAdminAPIStartup)

	plugin.RegisterPlugin("basic_auth", plugin.Plugin{
		Action: setupBasicAuth,
	})
}

func setupBasicAuth(def *proxy.RouterDefinition, rawConfig plugin.Config) error {
	if repo == nil {
		return errors.New("the repository was not set by onStartup event")
	}

	def.AddMiddleware(NewBasicAuth(repo))
	return nil
}

func onAdminAPIStartup(event interface{}) error {
	e, ok := event.(plugin.OnAdminAPIStartup)
	if !ok {
		return errors.New("could not convert event to admin startup type")
	}

	adminRouter = e.Router
	return nil
}

func onStartup(event interface{}) error {
	var err error

	e, ok := event.(plugin.OnStartup)
	if !ok {
		return errors.New("could not convert event to startup type")
	}

	if e.MongoSession == nil {
		return ErrInvalidMongoDBSession
	}

	if adminRouter == nil {
		return ErrInvalidAdminRouter
	}

	repo, err = NewMongoRepository(e.MongoSession)
	if err != nil {
		return err
	}

	handlers := NewHandler(repo)
	group := adminRouter.Group("/credentials/basic_auth")
	{
		group.GET("/", handlers.Index())
		group.POST("/", handlers.Create())
		group.GET("/{username}", handlers.Show())
		group.PUT("/{username}", handlers.Update())
		group.DELETE("/{username}", handlers.Delete())
	}

	return nil
}
<commit_msg>Use memory repository when no mongo connection for basic auth pligin<commit_after>package basic

import (
	"errors"

	"github.com/hellofresh/janus/pkg/plugin"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
	log "github.com/sirupsen/logrus"
)

var (
	repo        Repository
	adminRouter router.Router
)

func init() {
	plugin.RegisterEventHook(plugin.StartupEvent, onStartup)
	plugin.RegisterEventHook(plugin.AdminAPIStartupEvent, onAdminAPIStartup)

	plugin.RegisterPlugin("basic_auth", plugin.Plugin{
		Action: setupBasicAuth,
	})
}

func setupBasicAuth(def *proxy.RouterDefinition, rawConfig plugin.Config) error {
	if repo == nil {
		return errors.New("the repository was not set by onStartup event")
	}

	def.AddMiddleware(NewBasicAuth(repo))
	return nil
}

func onAdminAPIStartup(event interface{}) error {
	e, ok := event.(plugin.OnAdminAPIStartup)
	if !ok {
		return errors.New("could not convert event to admin startup type")
	}

	adminRouter = e.Router
	return nil
}

func onStartup(event interface{}) error {
	var err error

	e, ok := event.(plugin.OnStartup)
	if !ok {
		return errors.New("could not convert event to startup type")
	}

	var repo Repository
	if e.MongoSession == nil {
		log.Debug("Mongo session is not set, using memory repository for basic auth plugin")

		repo = NewInMemoryRepository()
	} else {
		log.Debug("Mongo session is set, using mongo repository for basic auth plugin")

		repo, err = NewMongoRepository(e.MongoSession)
		if err != nil {
			return err
		}
	}

	if adminRouter == nil {
		return ErrInvalidAdminRouter
	}

	handlers := NewHandler(repo)
	group := adminRouter.Group("/credentials/basic_auth")
	{
		group.GET("/", handlers.Index())
		group.POST("/", handlers.Create())
		group.GET("/{username}", handlers.Show())
		group.PUT("/{username}", handlers.Update())
		group.DELETE("/{username}", handlers.Delete())
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 trivago GmbH
//
// 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 core

import (
	"github.com/sirupsen/logrus"
	"hash/fnv"
	"sync"
)

var (
	// GeneratedRouterPrefix is prepended to all generated routers
	GeneratedRouterPrefix = "_GENERATED_"
)

// streamRegistry holds routers mapped by their MessageStreamID as well as a
// reverse lookup of MessageStreamID to stream name.
type streamRegistry struct {
	routers     map[MessageStreamID]Router
	name        map[MessageStreamID]string
	nameGuard   *sync.RWMutex
	streamGuard *sync.RWMutex
	wildcard    []Producer
}

// StreamRegistry is the global instance of streamRegistry used to store the
// all registered routers.
var StreamRegistry = streamRegistry{
	routers:     make(map[MessageStreamID]Router),
	streamGuard: new(sync.RWMutex),
	name:        make(map[MessageStreamID]string),
	nameGuard:   new(sync.RWMutex),
}

// GetStreamID is deprecated
func GetStreamID(stream string) MessageStreamID {
	return StreamRegistry.GetStreamID(stream)
}

// GetStreamID returns the integer representation of a given stream name.
func (registry *streamRegistry) GetStreamID(stream string) MessageStreamID {
	hash := fnv.New64a()
	hash.Write([]byte(stream))
	streamID := MessageStreamID(hash.Sum64())

	registry.nameGuard.Lock()
	registry.name[streamID] = stream
	registry.nameGuard.Unlock()

	return streamID
}

// GetStreamName does a reverse lookup for a given MessageStreamID and returns
// the corresponding name. If the MessageStreamID is not registered, an empty
// string is returned.
func (registry streamRegistry) GetStreamName(streamID MessageStreamID) string {
	switch streamID {
	case LogInternalStreamID:
		return LogInternalStream

	case WildcardStreamID:
		return WildcardStream

	case InvalidStreamID:
		return InvalidStream

	default:
		registry.nameGuard.RLock()
		name, exists := registry.name[streamID]
		registry.nameGuard.RUnlock()

		if exists {
			return name // ### return, found ###
		}
	}
	return ""
}

// GetRouterByStreamName returns a registered stream by name. See GetRouter.
func (registry streamRegistry) GetRouterByStreamName(name string) Router {
	streamID := registry.GetStreamID(name)
	return registry.GetRouter(streamID)
}

// GetRouter returns a registered stream or nil
func (registry streamRegistry) GetRouter(id MessageStreamID) Router {
	registry.streamGuard.RLock()
	stream, exists := registry.routers[id]
	registry.streamGuard.RUnlock()

	if exists {
		return stream
	}
	return nil
}

// IsStreamRegistered returns true if the stream for the given id is registered.
func (registry streamRegistry) IsStreamRegistered(id MessageStreamID) bool {
	registry.streamGuard.RLock()
	_, exists := registry.routers[id]
	registry.streamGuard.RUnlock()

	return exists
}

// ForEachStream loops over all registered routers and calls the given function.
func (registry streamRegistry) ForEachStream(callback func(streamID MessageStreamID, stream Router)) {
	registry.streamGuard.RLock()
	defer registry.streamGuard.RUnlock()

	for streamID, router := range registry.routers {
		callback(streamID, router)
	}
}

// WildcardProducersExist returns true if any producer is listening to the
// wildcard stream.
func (registry *streamRegistry) WildcardProducersExist() bool {
	return len(registry.wildcard) > 0
}

// RegisterWildcardProducer adds a new producer to the list of known wildcard
// prodcuers. This list has to be added to new routers upon creation to send
// messages to producers listening to *.
// Duplicates will be filtered.
// This state of this list is undefined during the configuration phase.
func (registry *streamRegistry) RegisterWildcardProducer(producers ...Producer) {
nextProd:
	for _, prod := range producers {
		for _, existing := range registry.wildcard {
			if existing == prod {
				continue nextProd
			}
		}
		registry.wildcard = append(registry.wildcard, prod)
	}
}

// AddWildcardProducersToRouter adds all known wildcard producers to a given
// router. The state of the wildcard list is undefined during the configuration
// phase.
func (registry streamRegistry) AddWildcardProducersToRouter(router Router) {
	streamID := router.GetStreamID()
	if streamID != LogInternalStreamID {
		router.AddProducer(registry.wildcard...)
	}
}

// AddAllWildcardProducersToAllRouters executes AddWildcardProducersToRouter on
// all currently registered routers
func (registry *streamRegistry) AddAllWildcardProducersToAllRouters() {
	registry.ForEachStream(
		func(streamID MessageStreamID, router Router) {
			registry.AddWildcardProducersToRouter(router)
		})
}

// Register registers a router plugin to a given stream id
func (registry *streamRegistry) Register(router Router, streamID MessageStreamID) {
	registry.streamGuard.RLock()
	_, exists := registry.routers[streamID]
	registry.streamGuard.RUnlock()

	if exists {
		logrus.Warningf("%T attaches to an already occupied router (%s)", router, registry.GetStreamName(streamID))
		return // ### return, double registration ###
	}

	registry.streamGuard.Lock()
	defer registry.streamGuard.Unlock()

	// Test again inside critical section to avoid races
	if _, exists := registry.routers[streamID]; !exists {
		registry.routers[streamID] = router
		CountRouters()
	}
}

// GetRouterOrFallback returns the router for the given streamID if it is registered.
// If no router is registered for the given streamID the default router is used.
// The default router is equivalent to an unconfigured router.Broadcast with
// all wildcard producers already added.
func (registry *streamRegistry) GetRouterOrFallback(streamID MessageStreamID) Router {
	if streamID == InvalidStreamID {
		return nil // ### return, invalid stream does not have a router ###
	}

	registry.streamGuard.RLock()
	router, exists := registry.routers[streamID]
	registry.streamGuard.RUnlock()
	if exists {
		return router // ### return, already registered ###
	}

	registry.streamGuard.Lock()
	defer registry.streamGuard.Unlock()

	// Create router, avoid race conditions by check again in ciritical section
	if router, exists = registry.routers[streamID]; exists {
		return router // ### return, lost the race ###
	}

	defaultRouter := registry.createFallback(streamID)
	registry.AddWildcardProducersToRouter(defaultRouter)
	registry.routers[streamID] = defaultRouter

	CountRouters()
	CountFallbackRouters()

	return defaultRouter
}

func (registry *streamRegistry) createFallback(streamID MessageStreamID) Router {
	streamName := registry.GetStreamName(streamID)
	logrus.Debug("Creating fallback stream for ", streamName)

	config := NewPluginConfig(GeneratedRouterPrefix+streamName, "router.Broadcast")
	config.Override("stream", streamName)

	plugin, err := NewPluginWithConfig(config)
	if err != nil {
		panic(err) // this has to always work, otherwise: panic
	}

	stream := plugin.(Router) // panic if not!
	return stream
}
<commit_msg>added missing TraceInternalStreamID<commit_after>// Copyright 2015-2016 trivago GmbH
//
// 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 core

import (
	"github.com/sirupsen/logrus"
	"hash/fnv"
	"sync"
)

var (
	// GeneratedRouterPrefix is prepended to all generated routers
	GeneratedRouterPrefix = "_GENERATED_"
)

// streamRegistry holds routers mapped by their MessageStreamID as well as a
// reverse lookup of MessageStreamID to stream name.
type streamRegistry struct {
	routers     map[MessageStreamID]Router
	name        map[MessageStreamID]string
	nameGuard   *sync.RWMutex
	streamGuard *sync.RWMutex
	wildcard    []Producer
}

// StreamRegistry is the global instance of streamRegistry used to store the
// all registered routers.
var StreamRegistry = streamRegistry{
	routers:     make(map[MessageStreamID]Router),
	streamGuard: new(sync.RWMutex),
	name:        make(map[MessageStreamID]string),
	nameGuard:   new(sync.RWMutex),
}

// GetStreamID is deprecated
func GetStreamID(stream string) MessageStreamID {
	return StreamRegistry.GetStreamID(stream)
}

// GetStreamID returns the integer representation of a given stream name.
func (registry *streamRegistry) GetStreamID(stream string) MessageStreamID {
	hash := fnv.New64a()
	hash.Write([]byte(stream))
	streamID := MessageStreamID(hash.Sum64())

	registry.nameGuard.Lock()
	registry.name[streamID] = stream
	registry.nameGuard.Unlock()

	return streamID
}

// GetStreamName does a reverse lookup for a given MessageStreamID and returns
// the corresponding name. If the MessageStreamID is not registered, an empty
// string is returned.
func (registry streamRegistry) GetStreamName(streamID MessageStreamID) string {
	switch streamID {
	case LogInternalStreamID:
		return LogInternalStream

	case WildcardStreamID:
		return WildcardStream

	case InvalidStreamID:
		return InvalidStream

	case TraceInternalStreamID:
		return TraceInternalStream

	default:
		registry.nameGuard.RLock()
		name, exists := registry.name[streamID]
		registry.nameGuard.RUnlock()

		if exists {
			return name // ### return, found ###
		}
	}
	return ""
}

// GetRouterByStreamName returns a registered stream by name. See GetRouter.
func (registry streamRegistry) GetRouterByStreamName(name string) Router {
	streamID := registry.GetStreamID(name)
	return registry.GetRouter(streamID)
}

// GetRouter returns a registered stream or nil
func (registry streamRegistry) GetRouter(id MessageStreamID) Router {
	registry.streamGuard.RLock()
	stream, exists := registry.routers[id]
	registry.streamGuard.RUnlock()

	if exists {
		return stream
	}
	return nil
}

// IsStreamRegistered returns true if the stream for the given id is registered.
func (registry streamRegistry) IsStreamRegistered(id MessageStreamID) bool {
	registry.streamGuard.RLock()
	_, exists := registry.routers[id]
	registry.streamGuard.RUnlock()

	return exists
}

// ForEachStream loops over all registered routers and calls the given function.
func (registry streamRegistry) ForEachStream(callback func(streamID MessageStreamID, stream Router)) {
	registry.streamGuard.RLock()
	defer registry.streamGuard.RUnlock()

	for streamID, router := range registry.routers {
		callback(streamID, router)
	}
}

// WildcardProducersExist returns true if any producer is listening to the
// wildcard stream.
func (registry *streamRegistry) WildcardProducersExist() bool {
	return len(registry.wildcard) > 0
}

// RegisterWildcardProducer adds a new producer to the list of known wildcard
// prodcuers. This list has to be added to new routers upon creation to send
// messages to producers listening to *.
// Duplicates will be filtered.
// This state of this list is undefined during the configuration phase.
func (registry *streamRegistry) RegisterWildcardProducer(producers ...Producer) {
nextProd:
	for _, prod := range producers {
		for _, existing := range registry.wildcard {
			if existing == prod {
				continue nextProd
			}
		}
		registry.wildcard = append(registry.wildcard, prod)
	}
}

// AddWildcardProducersToRouter adds all known wildcard producers to a given
// router. The state of the wildcard list is undefined during the configuration
// phase.
func (registry streamRegistry) AddWildcardProducersToRouter(router Router) {
	streamID := router.GetStreamID()
	if streamID != LogInternalStreamID {
		router.AddProducer(registry.wildcard...)
	}
}

// AddAllWildcardProducersToAllRouters executes AddWildcardProducersToRouter on
// all currently registered routers
func (registry *streamRegistry) AddAllWildcardProducersToAllRouters() {
	registry.ForEachStream(
		func(streamID MessageStreamID, router Router) {
			registry.AddWildcardProducersToRouter(router)
		})
}

// Register registers a router plugin to a given stream id
func (registry *streamRegistry) Register(router Router, streamID MessageStreamID) {
	registry.streamGuard.RLock()
	_, exists := registry.routers[streamID]
	registry.streamGuard.RUnlock()

	if exists {
		logrus.Warningf("%T attaches to an already occupied router (%s)", router, registry.GetStreamName(streamID))
		return // ### return, double registration ###
	}

	registry.streamGuard.Lock()
	defer registry.streamGuard.Unlock()

	// Test again inside critical section to avoid races
	if _, exists := registry.routers[streamID]; !exists {
		registry.routers[streamID] = router
		CountRouters()
	}
}

// GetRouterOrFallback returns the router for the given streamID if it is registered.
// If no router is registered for the given streamID the default router is used.
// The default router is equivalent to an unconfigured router.Broadcast with
// all wildcard producers already added.
func (registry *streamRegistry) GetRouterOrFallback(streamID MessageStreamID) Router {
	if streamID == InvalidStreamID {
		return nil // ### return, invalid stream does not have a router ###
	}

	registry.streamGuard.RLock()
	router, exists := registry.routers[streamID]
	registry.streamGuard.RUnlock()
	if exists {
		return router // ### return, already registered ###
	}

	registry.streamGuard.Lock()
	defer registry.streamGuard.Unlock()

	// Create router, avoid race conditions by check again in ciritical section
	if router, exists = registry.routers[streamID]; exists {
		return router // ### return, lost the race ###
	}

	defaultRouter := registry.createFallback(streamID)
	registry.AddWildcardProducersToRouter(defaultRouter)
	registry.routers[streamID] = defaultRouter

	CountRouters()
	CountFallbackRouters()

	return defaultRouter
}

func (registry *streamRegistry) createFallback(streamID MessageStreamID) Router {
	streamName := registry.GetStreamName(streamID)
	logrus.Debug("Creating fallback stream for ", streamName)

	config := NewPluginConfig(GeneratedRouterPrefix+streamName, "router.Broadcast")
	config.Override("stream", streamName)

	plugin, err := NewPluginWithConfig(config)
	if err != nil {
		panic(err) // this has to always work, otherwise: panic
	}

	stream := plugin.(Router) // panic if not!
	return stream
}
<|endoftext|>


<commit_before>package geojson

import (
	"encoding/json"
	"github.com/foobaz/geom"
	"reflect"
)

func ToGeoJSON(t geom.T) (interface{}, error) {
	switch g := t.(type) {
	case geom.Point:
		return &Geometry{
			Type:        "Point",
			Coordinates: g,
		}, nil
	case geom.LineString:
		return Geometry{
			Type:        "LineString",
			Coordinates: g,
		}, nil
	case geom.Polygon:
		return Geometry{
			Type:        "Polygon",
			Coordinates: g,
		}, nil
	case geom.MultiPolygon:
		return Geometry{
			Type:        "MultiPolygon",
			Coordinates: g,
		}, nil
	case geom.Feature:
		serializable, err := ToGeoJSON(g.T)
		if err != nil {
			return nil, err
		}

		geometry, ok := serializable.(Geometry)
		if !ok {
			return nil, &UnsupportedGeometryError{reflect.TypeOf(geometry).String()}
		}

		return Feature{
			Type:       "Feature",
			Geometry:   geometry,
			Properties: g.Properties,
		}, nil
	case geom.FeatureCollection:
		features := make([]Feature, 0, len(g.Features))
		for _, geomFeature := range g.Features {
			serializable, err := ToGeoJSON(geomFeature)
			if err != nil {
				continue
			}

			jsonFeature, ok := serializable.(Feature)
			if !ok {
				continue
			}

			features = append(features, jsonFeature)
		}
		return FeatureCollection{
			Type:       "FeatureCollection",
			Features:   features,
			Properties: g.Properties,
		}, nil
	default:
		return nil, &UnsupportedGeometryError{reflect.TypeOf(g).String()}
	}
}

func Encode(g geom.T) ([]byte, error) {
	if object, err := ToGeoJSON(g); err == nil {
		return json.Marshal(object)
	} else {
		return nil, err
	}
}
<commit_msg>validate geojson more, return errors for invalid geometry<commit_after>package geojson

import (
	"encoding/json"
	"reflect"

	"github.com/foobaz/geom"
)

func ToGeoJSON(t geom.T) (interface{}, error) {
	switch g := t.(type) {
	case geom.Point:
		return &Geometry{
			Type:        "Point",
			Coordinates: g,
		}, nil
	case geom.LineString:
		err := validateLineString(g)
		if err != nil {
			return nil, err
		}

		return Geometry{
			Type:        "LineString",
			Coordinates: g,
		}, nil
	case geom.MultiLineString:
		err := validateMultiLineString(g)
		if err != nil {
			return nil, err
		}

		return Geometry{
			Type:        "MultiLineString",
			Coordinates: g,
		}, nil
	case geom.Polygon:
		err := validatePolygon(g)
		if err != nil {
			return nil, err
		}

		return Geometry{
			Type:        "Polygon",
			Coordinates: g,
		}, nil
	case geom.MultiPolygon:
		err := validateMultiPolygon(g)
		if err != nil {
			return nil, err
		}

		return Geometry{
			Type:        "MultiPolygon",
			Coordinates: g,
		}, nil
	case geom.Feature:
		serializable, err := ToGeoJSON(g.T)
		if err != nil {
			return nil, err
		}

		geometry, ok := serializable.(Geometry)
		if !ok {
			return nil, &UnsupportedGeometryError{reflect.TypeOf(geometry).String()}
		}

		return Feature{
			Type:       "Feature",
			Geometry:   geometry,
			Properties: g.Properties,
		}, nil
	case geom.FeatureCollection:
		features := make([]Feature, 0, len(g.Features))
		for _, geomFeature := range g.Features {
			serializable, err := ToGeoJSON(geomFeature)
			if err != nil {
				continue
			}

			jsonFeature, ok := serializable.(Feature)
			if !ok {
				continue
			}

			features = append(features, jsonFeature)
		}
		return FeatureCollection{
			Type:       "FeatureCollection",
			Features:   features,
			Properties: g.Properties,
		}, nil
	default:
		return nil, &UnsupportedGeometryError{reflect.TypeOf(g).String()}
	}
}

func Encode(g geom.T) ([]byte, error) {
	if object, err := ToGeoJSON(g); err == nil {
		return json.Marshal(object)
	} else {
		return nil, err
	}
}

func validateLineString(l geom.LineString) error {
	pointCount := len(l)
	if pointCount < 2 {
		return InsufficientPointsError{pointCount}
	}

	return nil
}

func validateMultiLineString(m geom.MultiLineString) error {
	for _, l := range m {
		err := validateLineString(l)
		if err != nil {
			return err
		}
	}

	return nil
}

func validatePolygon(p geom.Polygon) error {
	if len(p) == 0 {
		return InsufficientPointsError{0}
	}

	for _, r := range p {
		pointCount := len(r)
		if pointCount < 4 {
			return InsufficientPointsError{pointCount}
		}
	}

	return nil
}

func validateMultiPolygon(m geom.MultiPolygon) error {
	for _, p := range m {
		err := validatePolygon(p)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package realtime

import (
	"encoding/json"

	"github.com/cozy/cozy-stack/pkg/logger"
	redis "github.com/go-redis/redis"
)

const eventsRedisKey = "realtime:events"

type redisHub struct {
	c     *redis.Client
	mem   *memHub
	local *topic
}

func newRedisHub(c *redis.Client) *redisHub {
	local := newTopic("*")
	mem := newMemHub()
	hub := &redisHub{c, mem, local}
	go hub.start()
	return hub
}

type jsonDoc struct {
	M    map[string]interface{}
	Type string
}

func (j jsonDoc) ID() string      { id, _ := j.M["_id"].(string); return id }
func (j jsonDoc) DocType() string { return j.Type }
func (j *jsonDoc) MarshalJSON() ([]byte, error) {
	j.M["_type"] = j.Type
	defer delete(j.M, "_type")
	return json.Marshal(j.M)
}

func toJSONDoc(d map[string]interface{}) *jsonDoc {
	if d == nil {
		return nil
	}
	doctype, _ := d["_type"].(string)
	delete(d, "_type")
	return &jsonDoc{d, doctype}
}

type jsonEvent struct {
	Domain string
	Verb   string
	Doc    *jsonDoc
	Old    *jsonDoc
}

func (j *jsonEvent) UnmarshalJSON(buf []byte) error {
	var m map[string]interface{}
	if err := json.Unmarshal(buf, &m); err != nil {
		return err
	}
	j.Domain, _ = m["domain"].(string)
	j.Verb, _ = m["verb"].(string)
	if doc, ok := m["doc"].(map[string]interface{}); ok {
		j.Doc = toJSONDoc(doc)
	}
	if old, ok := m["old"].(map[string]interface{}); ok {
		j.Old = toJSONDoc(old)
	}
	return nil
}

func (h *redisHub) start() {
	sub := h.c.Subscribe(eventsRedisKey)
	log := logger.WithNamespace("realtime-redis")
	for msg := range sub.Channel() {
		je := jsonEvent{}
		buf := []byte(msg.Payload)
		if err := json.Unmarshal(buf, &je); err != nil {
			log.Warnf("Error on start: %s", err)
			continue
		}
		e := &Event{
			Domain: je.Domain,
			Verb:   je.Verb,
			Doc:    je.Doc,
			OldDoc: je.Old,
		}
		h.mem.Publish(e)
	}
}

func (h *redisHub) GetTopic(domain, doctype string) *topic {
	return nil
}

func (h *redisHub) Publish(e *Event) {
	h.local.broadcast <- e
	buf, err := json.Marshal(e)
	if err != nil {
		log := logger.WithNamespace("realtime-redis")
		log.Warnf("Error on publish: %s", err)
		return
	}
	h.c.Publish(eventsRedisKey, string(buf))
}

func (h *redisHub) Subscriber(domain string) *DynamicSubscriber {
	return h.mem.Subscriber(domain)
}

func (h *redisHub) SubscribeLocalAll() *DynamicSubscriber {
	ds := newDynamicSubscriber(nil, "")
	ds.addTopic(h.local, "")
	return ds
}
<commit_msg>Preserve doctype when transfering docs in redis for realtime<commit_after>package realtime

import (
	"encoding/json"
	"strings"

	"github.com/cozy/cozy-stack/pkg/logger"
	redis "github.com/go-redis/redis"
)

const eventsRedisKey = "realtime:events"

type redisHub struct {
	c     *redis.Client
	mem   *memHub
	local *topic
}

func newRedisHub(c *redis.Client) *redisHub {
	local := newTopic("*")
	mem := newMemHub()
	hub := &redisHub{c, mem, local}
	go hub.start()
	return hub
}

type jsonDoc struct {
	M    map[string]interface{}
	Type string
}

func (j jsonDoc) ID() string      { id, _ := j.M["_id"].(string); return id }
func (j jsonDoc) DocType() string { return j.Type }
func (j *jsonDoc) MarshalJSON() ([]byte, error) {
	j.M["_type"] = j.Type
	defer delete(j.M, "_type")
	return json.Marshal(j.M)
}

func toJSONDoc(d map[string]interface{}) *jsonDoc {
	if d == nil {
		return nil
	}
	doctype, _ := d["_type"].(string)
	delete(d, "_type")
	return &jsonDoc{d, doctype}
}

type jsonEvent struct {
	Domain string
	Verb   string
	Doc    *jsonDoc
	Old    *jsonDoc
}

func (j *jsonEvent) UnmarshalJSON(buf []byte) error {
	var m map[string]interface{}
	if err := json.Unmarshal(buf, &m); err != nil {
		return err
	}
	j.Domain, _ = m["domain"].(string)
	j.Verb, _ = m["verb"].(string)
	if doc, ok := m["doc"].(map[string]interface{}); ok {
		j.Doc = toJSONDoc(doc)
	}
	if old, ok := m["old"].(map[string]interface{}); ok {
		j.Old = toJSONDoc(old)
	}
	return nil
}

func (h *redisHub) start() {
	sub := h.c.Subscribe(eventsRedisKey)
	log := logger.WithNamespace("realtime-redis")
	for msg := range sub.Channel() {
		je := jsonEvent{}
		parts := strings.SplitN(msg.Payload, ",", 2)
		if len(parts) < 2 {
			log.Warnf("Invalid payload: %s", msg.Payload)
			continue
		}
		doctype := parts[0]
		buf := []byte(parts[1])
		if err := json.Unmarshal(buf, &je); err != nil {
			log.Warnf("Error on start: %s", err)
			continue
		}
		if je.Doc != nil {
			je.Doc.Type = doctype
		}
		if je.Old != nil {
			je.Old.Type = doctype
		}
		e := &Event{
			Domain: je.Domain,
			Verb:   je.Verb,
			Doc:    je.Doc,
			OldDoc: je.Old,
		}
		h.mem.Publish(e)
	}
}

func (h *redisHub) GetTopic(domain, doctype string) *topic {
	return nil
}

func (h *redisHub) Publish(e *Event) {
	h.local.broadcast <- e
	buf, err := json.Marshal(e)
	if err != nil {
		log := logger.WithNamespace("realtime-redis")
		log.Warnf("Error on publish: %s", err)
		return
	}
	h.c.Publish(eventsRedisKey, e.Doc.DocType()+","+string(buf))
}

func (h *redisHub) Subscriber(domain string) *DynamicSubscriber {
	return h.mem.Subscriber(domain)
}

func (h *redisHub) SubscribeLocalAll() *DynamicSubscriber {
	ds := newDynamicSubscriber(nil, "")
	ds.addTopic(h.local, "")
	return ds
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Skaffold Authors

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 sync

import (
	"fmt"
	"path"
	"path/filepath"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"
	"github.com/pkg/errors"
)

type Syncer interface {
	Sync(s *Item) error
}

type Item struct {
	Image  string
	Copy   map[string]string
	Delete map[string]string
}

func NewItem(a *latest.Artifact, e watch.Events, builds []build.Artifact) (*Item, error) {
	// If there are no changes, short circuit and don't sync anything
	if !e.HasChanged() || a.Sync == nil || len(a.Sync) == 0 {
		return nil, nil
	}

	toCopy, err := intersect(a.Workspace, a.Sync, append(e.Added, e.Modified...))
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and added, modified files")
	}

	toDelete, err := intersect(a.Workspace, a.Sync, e.Deleted)
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and added, modified files")
	}

	if toCopy == nil || toDelete == nil {
		return nil, nil
	}

	tag := latestTag(a.ImageName, builds)
	if tag == "" {
		return nil, fmt.Errorf("Could not find latest tag for image %s in builds: %s", a.ImageName, builds)
	}

	return &Item{
		Image:  tag,
		Copy:   toCopy,
		Delete: toDelete,
	}, nil
}

func latestTag(image string, builds []build.Artifact) string {
	for _, build := range builds {
		if build.ImageName == image {
			return build.Tag
		}
	}
	return ""
}

func intersect(context string, syncMap map[string]string, files []string) (map[string]string, error) {
	ret := map[string]string{}
	for _, f := range files {
		relPath, err := filepath.Rel(context, f)
		if err != nil {
			return nil, errors.Wrapf(err, "changed file %s can't be found relative to context %s", f, context)
		}
		for p, dst := range syncMap {
			match, err := filepath.Match(p, relPath)
			if err != nil {
				return nil, errors.Wrapf(err, "pattern error for %s", relPath)
			}
			if !match {
				return nil, nil
			}
			// If the source has special match characters,
			// the destination must be a directory
			// The path package must be used here, since the destination is always
			// a linux filesystem.
			if util.HasMeta(p) {
				dst = path.Join(dst, filepath.Base(relPath))
			}
			ret[f] = dst
		}
	}
	return ret, nil
}
<commit_msg>Fix errors<commit_after>/*
Copyright 2018 The Skaffold Authors

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 sync

import (
	"fmt"
	"path"
	"path/filepath"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"
	"github.com/pkg/errors"
)

type Syncer interface {
	Sync(s *Item) error
}

type Item struct {
	Image  string
	Copy   map[string]string
	Delete map[string]string
}

func NewItem(a *latest.Artifact, e watch.Events, builds []build.Artifact) (*Item, error) {
	// If there are no changes, short circuit and don't sync anything
	if !e.HasChanged() || a.Sync == nil || len(a.Sync) == 0 {
		return nil, nil
	}

	toCopy, err := intersect(a.Workspace, a.Sync, append(e.Added, e.Modified...))
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and added, modified files")
	}

	toDelete, err := intersect(a.Workspace, a.Sync, e.Deleted)
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and deleted files")
	}

	if toCopy == nil || toDelete == nil {
		return nil, nil
	}

	tag := latestTag(a.ImageName, builds)
	if tag == "" {
		return nil, fmt.Errorf("could not find latest tag for image %s in builds: %v", a.ImageName, builds)
	}

	return &Item{
		Image:  tag,
		Copy:   toCopy,
		Delete: toDelete,
	}, nil
}

func latestTag(image string, builds []build.Artifact) string {
	for _, build := range builds {
		if build.ImageName == image {
			return build.Tag
		}
	}
	return ""
}

func intersect(context string, syncMap map[string]string, files []string) (map[string]string, error) {
	ret := map[string]string{}
	for _, f := range files {
		relPath, err := filepath.Rel(context, f)
		if err != nil {
			return nil, errors.Wrapf(err, "changed file %s can't be found relative to context %s", f, context)
		}
		for p, dst := range syncMap {
			match, err := filepath.Match(p, relPath)
			if err != nil {
				return nil, errors.Wrapf(err, "pattern error for %s", relPath)
			}
			if !match {
				return nil, nil
			}
			// If the source has special match characters,
			// the destination must be a directory
			// The path package must be used here, since the destination is always
			// a linux filesystem.
			if util.HasMeta(p) {
				dst = path.Join(dst, filepath.Base(relPath))
			}
			ret[f] = dst
		}
	}
	return ret, nil
}
<|endoftext|>


<commit_before>//  Copyright 2013 Walter Schulze
//
//  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 funcs

import (
	"fmt"
	"reflect"
	"strings"
)

func reverse(uniq string) (name string) {
	for n, us := range funcsMap.nameToUniq {
		for _, u := range us {
			if uniq == u {
				return n
			}
		}
	}
	return ""
}

type stringer interface {
	String() string
}

func isVarConst(p1, p2 interface{}) (string, bool) {
	switch p1.(type) {
	case *varBool, *varBytes, *varDouble, *varInt, *varString, *varUint:
		switch p2.(type) {
		case *constBool, *constBytes, *constDouble, *constInt, *constString, *constUint:
			return Sprint(p2), true
		}
	}
	switch p2.(type) {
	case *varBool, *varBytes, *varDouble, *varInt, *varString, *varUint:
		switch p1.(type) {
		case *constBool, *constBytes, *constDouble, *constInt, *constString, *constUint:
			return Sprint(p1), true
		}
	}
	return "", false
}

func Sprint(i interface{}) string {
	e := reflect.ValueOf(i).Elem()
	uniqName := e.Type().Name()
	name := reverse(uniqName)
	numFields := e.NumField()
	if numFields == 2 {
		p1 := e.Field(0).Interface()
		p2 := e.Field(1).Interface()
		v, ok := isVarConst(p1, p2)
		if ok {
			if name == "eq" {
				return "== " + v
			}
			if name == "ne" {
				return "!= " + v
			}
			if name == "gt" {
				return "> " + v
			}
			if name == "lt" {
				return "< " + v
			}
			if name == "ge" {
				return ">= " + v
			}
			if name == "le" {
				return "<= " + v
			}
		}
	}
	return sprint(i)
}

func sprint(i interface{}) string {
	e := reflect.ValueOf(i).Elem()
	uniqName := e.Type().Name()
	name := reverse(uniqName)
	if len(name) == 0 {
		strer, ok := i.(stringer)
		if !ok {
			panic("unknown function without String() string method")
		}
		name = strer.String()
	}
	if _, ok := i.(Const); ok {
		return name
	}
	if _, ok := i.(Decoder); ok {
		return name
	}
	numFields := e.NumField()
	ss := make([]string, 0, numFields)
	for i := 0; i < numFields; i++ {
		if _, ok := e.Field(i).Type().MethodByName("Eval"); !ok {
			continue
		}
		ss = append(ss, sprint(e.Field(i).Interface()))
	}
	return name + "(" + strings.Join(ss, ",") + ")"
}

func Equal(l, r interface{}) bool {
	le := reflect.ValueOf(l).Elem()
	lUniqName := le.Type().Name()
	re := reflect.ValueOf(r).Elem()
	rUniqName := re.Type().Name()
	if lUniqName != rUniqName {
		return false
	}
	if len(reverse(lUniqName)) == 0 {
		//TODO maybe this could be done better or we could just always convert functions to strings to compare
		return Sprint(l) == Sprint(r)
	}
	numFields := le.NumField()
	for i := 0; i < numFields; i++ {
		if _, ok := le.Field(i).Type().MethodByName("Eval"); !ok {
			continue
		}
		if !Equal(le.Field(i).Interface(), re.Field(i).Interface()) {
			return false
		}
	}
	if Sprint(l) != Sprint(r) {
		fmt.Printf("wtf %v == %v\n", Sprint(l), Sprint(r))
		panic("two non equal functions are equal")
	}
	return true
}

func Simplify(f Bool) Bool {
	if ff, ok := f.(*and); ok {
		v1 := Simplify(ff.V1)
		v2 := Simplify(ff.V2)
		if l, ok := v1.(*constBool); ok {
			if l.v == false {
				return BoolConst(false)
			} else {
				return v2
			}
		}
		if r, ok := v2.(*constBool); ok {
			if r.v == false {
				return BoolConst(false)
			} else {
				return v1
			}
		}
		if Equal(v1, v2) {
			return v1
		}
		if l, ok := v1.(*not); ok {
			if Equal(l.V1, v2) {
				return BoolConst(false)
			}
		}
		if r, ok := v2.(*not); ok {
			if Equal(v1, r.V1) {
				return BoolConst(false)
			}
		}
		switch vv1 := v1.(type) {
		case *stringEq:
			if vv2, ok := v2.(*stringEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return BoolConst(false)
						}
					}
				}
			}
			if vv2, ok := v2.(*stringNe); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v1
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		case *stringNe:
			if vv2, ok := v2.(*stringEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v2
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		case *intEq:
			if vv2, ok := v2.(*intEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return BoolConst(false)
						}
					}
				}
			}
			if vv2, ok := v2.(*intNe); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v1
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		case *intNe:
			if vv2, ok := v2.(*intEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v2
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		}
		return And(v1, v2)
	}
	if ff, ok := f.(*or); ok {
		v1 := Simplify(ff.V1)
		v2 := Simplify(ff.V2)
		if l, ok := v1.(*constBool); ok {
			if l.v == true {
				return BoolConst(true)
			} else {
				return v2
			}
		}
		if r, ok := v2.(*constBool); ok {
			if r.v == true {
				return BoolConst(true)
			} else {
				return v1
			}
		}
		if Equal(v1, v2) {
			return v1
		}
		if l, ok := v1.(*not); ok {
			if Equal(l.V1, v2) {
				return BoolConst(true)
			}
		}
		if r, ok := v2.(*not); ok {
			if Equal(v1, r.V1) {
				return BoolConst(true)
			}
		}
		return Or(v1, v2)
	}
	if ff, ok := f.(*not); ok {
		v1 := Simplify(ff.V1)
		if vv, ok := v1.(*not); ok {
			return vv.V1
		}
		if vv, ok := v1.(*constBool); ok {
			return BoolConst(!vv.v)
		}
		if vv, ok := v1.(*and); ok {
			return Simplify(Or(Not(vv.V1), Not(vv.V2)))
		}
		if vv, ok := v1.(*or); ok {
			return Simplify(And(Not(vv.V1), Not(vv.V2)))
		}
		switch vv := v1.(type) {
		case *boolEq:
			return BoolNe(vv.V1, vv.V2)
		case *bytesEq:
			return BytesNe(vv.V1, vv.V2)
		case *doubleEq:
			return DoubleNe(vv.V1, vv.V2)
		case *intEq:
			return IntNe(vv.V1, vv.V2)
		case *stringEq:
			return StringNe(vv.V1, vv.V2)
		case *uintEq:
			return UintNe(vv.V1, vv.V2)
		case *boolNe:
			return BoolEq(vv.V1, vv.V2)
		case *bytesNe:
			return BytesEq(vv.V1, vv.V2)
		case *doubleNe:
			return DoubleEq(vv.V1, vv.V2)
		case *intNe:
			return IntEq(vv.V1, vv.V2)
		case *stringNe:
			return StringEq(vv.V1, vv.V2)
		case *uintNe:
			return UintEq(vv.V1, vv.V2)
		}
		return Not(v1)
	}
	return f
}
<commit_msg>fixed sprint better<commit_after>//  Copyright 2013 Walter Schulze
//
//  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 funcs

import (
	"fmt"
	"reflect"
	"strings"
)

func reverse(uniq string) (name string) {
	for n, us := range funcsMap.nameToUniq {
		for _, u := range us {
			if uniq == u {
				return n
			}
		}
	}
	return ""
}

type stringer interface {
	String() string
}

func isVarConst(p1, p2 interface{}) (string, bool) {
	switch p1.(type) {
	case *varBool, *varBytes, *varDouble, *varInt, *varString, *varUint:
		switch p2.(type) {
		case *constBool, *constBytes, *constDouble, *constInt, *constString, *constUint:
			return Sprint(p2), true
		}
	}
	switch p2.(type) {
	case *varBool, *varBytes, *varDouble, *varInt, *varString, *varUint:
		switch p1.(type) {
		case *constBool, *constBytes, *constDouble, *constInt, *constString, *constUint:
			return Sprint(p1), true
		}
	}
	return "", false
}

func Sprint(i interface{}) string {
	e := reflect.ValueOf(i).Elem()
	uniqName := e.Type().Name()
	name := reverse(uniqName)
	numFields := e.NumField()
	if numFields == 2 {
		p1 := e.Field(0).Interface()
		p2 := e.Field(1).Interface()
		v, ok := isVarConst(p1, p2)
		if ok {
			if name == "eq" {
				return "== " + v
			}
			if name == "ne" {
				return "!= " + v
			}
			if name == "gt" {
				return "> " + v
			}
			if name == "lt" {
				return "< " + v
			}
			if name == "ge" {
				return ">= " + v
			}
			if name == "le" {
				return "<= " + v
			}
		}
	}
	return sprint(i)
}

func sprint(i interface{}) string {
	e := reflect.ValueOf(i).Elem()
	uniqName := e.Type().Name()
	name := reverse(uniqName)
	if len(name) == 0 {
		strer, ok := i.(stringer)
		if !ok {
			panic("unknown function without String() string method")
		}
		name = strer.String()
	}
	switch i.(type) {
	case Const:
		return name
	case Decoder:
		return name
	case ListOf:
		return name
	}
	numFields := e.NumField()
	ss := make([]string, 0, numFields)
	for i := 0; i < numFields; i++ {
		if _, ok := e.Field(i).Type().MethodByName("Eval"); !ok {
			continue
		}
		ss = append(ss, sprint(e.Field(i).Interface()))
	}
	return name + "(" + strings.Join(ss, ",") + ")"
}

func Equal(l, r interface{}) bool {
	le := reflect.ValueOf(l).Elem()
	lUniqName := le.Type().Name()
	re := reflect.ValueOf(r).Elem()
	rUniqName := re.Type().Name()
	if lUniqName != rUniqName {
		return false
	}
	if len(reverse(lUniqName)) == 0 {
		//TODO maybe this could be done better or we could just always convert functions to strings to compare
		return Sprint(l) == Sprint(r)
	}
	numFields := le.NumField()
	for i := 0; i < numFields; i++ {
		if _, ok := le.Field(i).Type().MethodByName("Eval"); !ok {
			continue
		}
		if !Equal(le.Field(i).Interface(), re.Field(i).Interface()) {
			return false
		}
	}
	if Sprint(l) != Sprint(r) {
		fmt.Printf("wtf %v == %v\n", Sprint(l), Sprint(r))
		panic("two non equal functions are equal")
	}
	return true
}

func Simplify(f Bool) Bool {
	if ff, ok := f.(*and); ok {
		v1 := Simplify(ff.V1)
		v2 := Simplify(ff.V2)
		if l, ok := v1.(*constBool); ok {
			if l.v == false {
				return BoolConst(false)
			} else {
				return v2
			}
		}
		if r, ok := v2.(*constBool); ok {
			if r.v == false {
				return BoolConst(false)
			} else {
				return v1
			}
		}
		if Equal(v1, v2) {
			return v1
		}
		if l, ok := v1.(*not); ok {
			if Equal(l.V1, v2) {
				return BoolConst(false)
			}
		}
		if r, ok := v2.(*not); ok {
			if Equal(v1, r.V1) {
				return BoolConst(false)
			}
		}
		switch vv1 := v1.(type) {
		case *stringEq:
			if vv2, ok := v2.(*stringEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return BoolConst(false)
						}
					}
				}
			}
			if vv2, ok := v2.(*stringNe); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v1
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		case *stringNe:
			if vv2, ok := v2.(*stringEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v2
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		case *intEq:
			if vv2, ok := v2.(*intEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return BoolConst(false)
						}
					}
				}
			}
			if vv2, ok := v2.(*intNe); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v1
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		case *intNe:
			if vv2, ok := v2.(*intEq); ok {
				if vvv1, ok1 := isVarConst(vv1.V1, vv1.V2); ok1 {
					if vvv2, ok2 := isVarConst(vv2.V1, vv2.V2); ok2 {
						if vvv1 != vvv2 {
							return v2
						} else {
							return BoolConst(false)
						}
					}
				}
			}
		}
		return And(v1, v2)
	}
	if ff, ok := f.(*or); ok {
		v1 := Simplify(ff.V1)
		v2 := Simplify(ff.V2)
		if l, ok := v1.(*constBool); ok {
			if l.v == true {
				return BoolConst(true)
			} else {
				return v2
			}
		}
		if r, ok := v2.(*constBool); ok {
			if r.v == true {
				return BoolConst(true)
			} else {
				return v1
			}
		}
		if Equal(v1, v2) {
			return v1
		}
		if l, ok := v1.(*not); ok {
			if Equal(l.V1, v2) {
				return BoolConst(true)
			}
		}
		if r, ok := v2.(*not); ok {
			if Equal(v1, r.V1) {
				return BoolConst(true)
			}
		}
		return Or(v1, v2)
	}
	if ff, ok := f.(*not); ok {
		v1 := Simplify(ff.V1)
		if vv, ok := v1.(*not); ok {
			return vv.V1
		}
		if vv, ok := v1.(*constBool); ok {
			return BoolConst(!vv.v)
		}
		if vv, ok := v1.(*and); ok {
			return Simplify(Or(Not(vv.V1), Not(vv.V2)))
		}
		if vv, ok := v1.(*or); ok {
			return Simplify(And(Not(vv.V1), Not(vv.V2)))
		}
		switch vv := v1.(type) {
		case *boolEq:
			return BoolNe(vv.V1, vv.V2)
		case *bytesEq:
			return BytesNe(vv.V1, vv.V2)
		case *doubleEq:
			return DoubleNe(vv.V1, vv.V2)
		case *intEq:
			return IntNe(vv.V1, vv.V2)
		case *stringEq:
			return StringNe(vv.V1, vv.V2)
		case *uintEq:
			return UintNe(vv.V1, vv.V2)
		case *boolNe:
			return BoolEq(vv.V1, vv.V2)
		case *bytesNe:
			return BytesEq(vv.V1, vv.V2)
		case *doubleNe:
			return DoubleEq(vv.V1, vv.V2)
		case *intNe:
			return IntEq(vv.V1, vv.V2)
		case *stringNe:
			return StringEq(vv.V1, vv.V2)
		case *uintNe:
			return UintEq(vv.V1, vv.V2)
		}
		return Not(v1)
	}
	return f
}
<|endoftext|>


<commit_before>// Copyright 2013-2017 Aerospike, Inc.
//
// 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 aerospike

import "math"

const (
	// TTLServerDefault will default to namespace configuration variable "default-ttl" on the server.
	TTLServerDefault = 0
	// TTLDontExpire will never expire for Aerospike 2 server versions >= 2.7.2 and Aerospike 3 server.
	TTLDontExpire = math.MaxUint32
	// TTLDontUpdate will not change the record's ttl when record is written. Supported by Aerospike server versions >= 3.10.1
	TTLDontUpdate = math.MaxUint32 - 1
)

// WritePolicy encapsulates parameters for policy attributes used in write operations.
// This object is passed into methods where database writes can occur.
type WritePolicy struct {
	BasePolicy

	// RecordExistsAction qualifies how to handle writes where the record already exists.
	RecordExistsAction RecordExistsAction //= RecordExistsAction.UPDATE;

	// GenerationPolicy qualifies how to handle record writes based on record generation. The default (NONE)
	// indicates that the generation is not used to restrict writes.
	GenerationPolicy GenerationPolicy //= GenerationPolicy.NONE;

	// Desired consistency guarantee when committing a transaction on the server. The default
	// (COMMIT_ALL) indicates that the server should wait for master and all replica commits to
	// be successful before returning success to the client.
	CommitLevel CommitLevel //= COMMIT_ALL

	// Generation determines expected generation.
	// Generation is the number of times a record has been
	// modified (including creation) on the server.
	// If a write operation is creating a record, the expected generation would be 0.
	Generation uint32

	// Expiration determines record expiration in seconds. Also known as TTL (Time-To-Live).
	// Seconds record will live before being removed by the server.
	// Expiration values:
	// TTLServerDefault (0): Default to namespace configuration variable "default-ttl" on the server.
	// TTLDontExpire (MaxUint32): Never expire for Aerospike 2 server versions >= 2.7.2 and Aerospike 3 server
	// TTLDontUpdate (MaxUint32 - 1): Do not change ttl when record is written. Supported by Aerospike server versions >= 3.10.1
	// > 0: Actual expiration in seconds.
	Expiration uint32

	// RespondPerEachOp defines for client.Operate() method, return a result for every operation.
	// Some list operations do not return results by default (ListClearOp() for example).
	// This can sometimes make it difficult to determine the desired result offset in the returned
	// bin's result list.
	//
	// Setting RespondPerEachOp to true makes it easier to identify the desired result offset
	// (result offset equals bin's operate sequence). This only makes sense when multiple list
	// operations are used in one operate call and some of those operations do not return results
	// by default.
	RespondPerEachOp bool

	// DurableDelete leaves a tombstone for the record if the transaction results in a record deletion.
	// This prevents deleted records from reappearing after node failures.
	// Valid for Aerospike Server Enterprise Edition 4+ only.
	DurableDelete bool
}

// NewWritePolicy initializes a new WritePolicy instance with default parameters.
func NewWritePolicy(generation, expiration uint32) *WritePolicy {
	res := &WritePolicy{
		BasePolicy:         *NewPolicy(),
		RecordExistsAction: UPDATE,
		GenerationPolicy:   NONE,
		CommitLevel:        COMMIT_ALL,
		Generation:         generation,
		Expiration:         expiration,
	}

	// Writes may not be idempotent.
	// do not allow retries on writes by default.
	res.MaxRetries = 0

	return res
}
<commit_msg>Minor doc fix<commit_after>// Copyright 2013-2017 Aerospike, Inc.
//
// 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 aerospike

import "math"

const (
	// TTLServerDefault will default to namespace configuration variable "default-ttl" on the server.
	TTLServerDefault = 0
	// TTLDontExpire will never expire for Aerospike 2 server versions >= 2.7.2 and Aerospike 3 server.
	TTLDontExpire = math.MaxUint32
	// TTLDontUpdate will not change the record's ttl when record is written. Supported by Aerospike server versions >= 3.10.1
	TTLDontUpdate = math.MaxUint32 - 1
)

// WritePolicy encapsulates parameters for policy attributes used in write operations.
// This object is passed into methods where database writes can occur.
type WritePolicy struct {
	BasePolicy

	// RecordExistsAction qualifies how to handle writes where the record already exists.
	RecordExistsAction RecordExistsAction //= RecordExistsAction.UPDATE;

	// GenerationPolicy qualifies how to handle record writes based on record generation. The default (NONE)
	// indicates that the generation is not used to restrict writes.
	GenerationPolicy GenerationPolicy //= GenerationPolicy.NONE;

	// Desired consistency guarantee when committing a transaction on the server. The default
	// (COMMIT_ALL) indicates that the server should wait for master and all replica commits to
	// be successful before returning success to the client.
	CommitLevel CommitLevel //= COMMIT_ALL

	// Generation determines expected generation.
	// Generation is the number of times a record has been
	// modified (including creation) on the server.
	// If a write operation is creating a record, the expected generation would be 0.
	Generation uint32

	// Expiration determines record expiration in seconds. Also known as TTL (Time-To-Live).
	// Seconds record will live before being removed by the server.
	// Expiration values:
	// TTLServerDefault (0): Default to namespace configuration variable "default-ttl" on the server.
	// TTLDontExpire (MaxUint32): Never expire for Aerospike 2 server versions >= 2.7.2 and Aerospike 3 server
	// TTLDontUpdate (MaxUint32 - 1): Do not change ttl when record is written. Supported by Aerospike server versions >= 3.10.1
	// > 0: Actual expiration in seconds.
	Expiration uint32

	// RespondPerEachOp defines for client.Operate() method, return a result for every operation.
	// Some list operations do not return results by default (ListClearOp() for example).
	// This can sometimes make it difficult to determine the desired result offset in the returned
	// bin's result list.
	//
	// Setting RespondPerEachOp to true makes it easier to identify the desired result offset
	// (result offset equals bin's operate sequence). This only makes sense when multiple list
	// operations are used in one operate call and some of those operations do not return results
	// by default.
	RespondPerEachOp bool

	// DurableDelete leaves a tombstone for the record if the transaction results in a record deletion.
	// This prevents deleted records from reappearing after node failures.
	// Valid for Aerospike Server Enterprise Edition 3.10+ only.
	DurableDelete bool
}

// NewWritePolicy initializes a new WritePolicy instance with default parameters.
func NewWritePolicy(generation, expiration uint32) *WritePolicy {
	res := &WritePolicy{
		BasePolicy:         *NewPolicy(),
		RecordExistsAction: UPDATE,
		GenerationPolicy:   NONE,
		CommitLevel:        COMMIT_ALL,
		Generation:         generation,
		Expiration:         expiration,
	}

	// Writes may not be idempotent.
	// do not allow retries on writes by default.
	res.MaxRetries = 0

	return res
}
<|endoftext|>


<commit_before>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// execprog executes a single program passed via a flag
// and prints information about execution.
package main

import (
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/google/syzkaller/cover"
	"github.com/google/syzkaller/ipc"
	"github.com/google/syzkaller/prog"
)

var (
	flagExecutor = flag.String("executor", "", "path to executor binary")
	flagProg     = flag.String("prog", "", "file with a program to execute")
	flagThreaded = flag.Bool("threaded", false, "use threaded mode in executor")
	flagDebug    = flag.Bool("debug", true, "debug output from executor")
	flagStrace   = flag.Bool("strace", false, "run executor under strace")
	flagCover    = flag.String("cover", "", "collect coverage and write to the file")
	flagDedup    = flag.Bool("dedup", false, "deduplicate coverage in executor")
)

func main() {
	flag.Parse()
	data, err := ioutil.ReadFile(*flagProg)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
		os.Exit(1)
	}
	p, err := prog.Deserialize(data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
		os.Exit(1)
	}
	var flags uint64
	if *flagThreaded {
		flags |= ipc.FlagThreaded
	}
	if *flagDebug {
		flags |= ipc.FlagDebug
	}
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	if *flagCover != "" {
		flags |= ipc.FlagCover
	}
	if *flagDedup {
		flags |= ipc.FlagDedupCover
	}
	env, err := ipc.MakeEnv(*flagExecutor, 3*time.Second, flags)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create execution environment: %v\n", err)
		os.Exit(1)
	}
	output, strace, cov, failed, hanged, err := env.Exec(p)
	fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
	if *flagStrace {
		fmt.Printf("strace output:\n%s", strace)
	}
	// Coverage is dumped in sanitizer format.
	// github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
	// then they can be piped via addr2line to symbolize.
	for i, c := range cov {
		fmt.Printf("call #%v: coverage %v\n", i, len(c))
		if len(c) == 0 {
			continue
		}
		buf := new(bytes.Buffer)
		binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
		for _, pc := range c {
			binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc))
		}
		err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCover, i), buf.Bytes(), 0660)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to write coverage file: %v\n", err)
			os.Exit(1)
		}
	}
}
<commit_msg>clean up temp files in tools/execprog<commit_after>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// execprog executes a single program passed via a flag
// and prints information about execution.
package main

import (
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/google/syzkaller/cover"
	"github.com/google/syzkaller/ipc"
	"github.com/google/syzkaller/prog"
)

var (
	flagExecutor = flag.String("executor", "", "path to executor binary")
	flagProg     = flag.String("prog", "", "file with a program to execute")
	flagThreaded = flag.Bool("threaded", false, "use threaded mode in executor")
	flagDebug    = flag.Bool("debug", true, "debug output from executor")
	flagStrace   = flag.Bool("strace", false, "run executor under strace")
	flagCover    = flag.String("cover", "", "collect coverage and write to the file")
	flagDedup    = flag.Bool("dedup", false, "deduplicate coverage in executor")
)

func main() {
	flag.Parse()
	data, err := ioutil.ReadFile(*flagProg)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
		os.Exit(1)
	}
	p, err := prog.Deserialize(data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
		os.Exit(1)
	}
	var flags uint64
	if *flagThreaded {
		flags |= ipc.FlagThreaded
	}
	if *flagDebug {
		flags |= ipc.FlagDebug
	}
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	if *flagCover != "" {
		flags |= ipc.FlagCover
	}
	if *flagDedup {
		flags |= ipc.FlagDedupCover
	}
	env, err := ipc.MakeEnv(*flagExecutor, 3*time.Second, flags)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create execution environment: %v\n", err)
		os.Exit(1)
	}
	defer env.Close()
	output, strace, cov, failed, hanged, err := env.Exec(p)
	fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
	if *flagStrace {
		fmt.Printf("strace output:\n%s", strace)
	}
	// Coverage is dumped in sanitizer format.
	// github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
	// then they can be piped via addr2line to symbolize.
	for i, c := range cov {
		fmt.Printf("call #%v: coverage %v\n", i, len(c))
		if len(c) == 0 {
			continue
		}
		buf := new(bytes.Buffer)
		binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
		for _, pc := range c {
			binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc))
		}
		err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCover, i), buf.Bytes(), 0660)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to write coverage file: %v\n", err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package tfdiags

import (
	"github.com/hashicorp/hcl2/hcl"
)

// hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
type hclDiagnostic struct {
	diag *hcl.Diagnostic
}

var _ Diagnostic = hclDiagnostic{}

func (d hclDiagnostic) Severity() Severity {
	switch d.diag.Severity {
	case hcl.DiagWarning:
		return Warning
	default:
		return Error
	}
}

func (d hclDiagnostic) Description() Description {
	return Description{
		Summary: d.diag.Summary,
		Detail:  d.diag.Detail,
	}
}

func (d hclDiagnostic) Source() Source {
	var ret Source
	if d.diag.Subject != nil {
		ret.Subject = &SourceRange{
			Filename: d.diag.Subject.Filename,
			Start: SourcePos{
				Line:   d.diag.Subject.Start.Line,
				Column: d.diag.Subject.Start.Column,
				Byte:   d.diag.Subject.Start.Byte,
			},
			End: SourcePos{
				Line:   d.diag.Subject.End.Line,
				Column: d.diag.Subject.End.Column,
				Byte:   d.diag.Subject.End.Byte,
			},
		}
	}
	if d.diag.Context != nil {
		ret.Context = &SourceRange{
			Filename: d.diag.Context.Filename,
			Start: SourcePos{
				Line:   d.diag.Context.Start.Line,
				Column: d.diag.Context.Start.Column,
				Byte:   d.diag.Context.Start.Byte,
			},
			End: SourcePos{
				Line:   d.diag.Context.End.Line,
				Column: d.diag.Context.End.Column,
				Byte:   d.diag.Context.End.Byte,
			},
		}
	}
	return ret
}
<commit_msg>tfdiags: Helper to construct SourceRange from hcl.Range<commit_after>package tfdiags

import (
	"github.com/hashicorp/hcl2/hcl"
)

// hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
type hclDiagnostic struct {
	diag *hcl.Diagnostic
}

var _ Diagnostic = hclDiagnostic{}

func (d hclDiagnostic) Severity() Severity {
	switch d.diag.Severity {
	case hcl.DiagWarning:
		return Warning
	default:
		return Error
	}
}

func (d hclDiagnostic) Description() Description {
	return Description{
		Summary: d.diag.Summary,
		Detail:  d.diag.Detail,
	}
}

func (d hclDiagnostic) Source() Source {
	var ret Source
	if d.diag.Subject != nil {
		rng := SourceRangeFromHCL(*d.diag.Subject)
		ret.Subject = &rng
	}
	if d.diag.Context != nil {
		rng := SourceRangeFromHCL(*d.diag.Context)
		ret.Context = &rng
	}
	return ret
}

// SourceRangeFromHCL constructs a SourceRange from the corresponding range
// type within the HCL package.
func SourceRangeFromHCL(hclRange hcl.Range) SourceRange {
	return SourceRange{
		Filename: hclRange.Filename,
		Start: SourcePos{
			Line:   hclRange.Start.Line,
			Column: hclRange.Start.Column,
			Byte:   hclRange.Start.Byte,
		},
		End: SourcePos{
			Line:   hclRange.End.Line,
			Column: hclRange.End.Column,
			Byte:   hclRange.End.Byte,
		},
	}
}

// ToHCL constructs a HCL Range from the receiving SourceRange. This is the
// opposite of SourceRangeFromHCL.
func (r SourceRange) ToHCL() hcl.Range {
	return hcl.Range{
		Filename: r.Filename,
		Start: hcl.Pos{
			Line:   r.Start.Line,
			Column: r.Start.Column,
			Byte:   r.Start.Byte,
		},
		End: hcl.Pos{
			Line:   r.End.Line,
			Column: r.End.Column,
			Byte:   r.End.Byte,
		},
	}
}
<|endoftext|>


<commit_before>package nodefs

import (
	"log"
	"sync"
	"unsafe"

	"github.com/hanwen/go-fuse/fuse"
)

// openedFile stores either an open dir or an open file.
type openedFile struct {
	handled

	WithFlags

	dir *connectorDir
}

type fileSystemMount struct {
	// Node that we were mounted on.
	mountInode *Inode

	// Parent to the mountInode.
	parentInode *Inode

	// Options for the mount.
	options *Options

	// Protects Children hashmaps within the mount.  treeLock
	// should be acquired before openFilesLock.
	//
	// If multiple treeLocks must be acquired, the treeLocks
	// closer to the root must be acquired first.
	treeLock sync.RWMutex

	// Manage filehandles of open files.
	openFiles handleMap

	Debug bool

	connector *FileSystemConnector
}

// Must called with lock for parent held.
func (m *fileSystemMount) mountName() string {
	for k, v := range m.parentInode.children {
		if m.mountInode == v {
			return k
		}
	}
	panic("not found")
	return ""
}

func (m *fileSystemMount) setOwner(attr *fuse.Attr) {
	if m.options.Owner != nil {
		attr.Owner = *(*fuse.Owner)(m.options.Owner)
	}
}

func (m *fileSystemMount) fillEntry(out *fuse.EntryOut) {
	splitDuration(m.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
	splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
	m.setOwner(&out.Attr)
	if out.Mode&fuse.S_IFDIR == 0 && out.Nlink == 0 {
		out.Nlink = 1
	}
}

func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) {
	splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
	m.setOwner(&out.Attr)
	out.Ino = nodeId
}

func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile {
	var b *openedFile
	if h != 0 {
		b = (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h)))
	}

	if b != nil && m.connector.debug && b.WithFlags.Description != "" {
		log.Printf("File %d = %q", h, b.WithFlags.Description)
	}
	return b
}

func (m *fileSystemMount) unregisterFileHandle(handle uint64, node *Inode) *openedFile {
	_, obj := m.openFiles.Forget(handle, 1)
	opened := (*openedFile)(unsafe.Pointer(obj))
	node.openFilesMutex.Lock()
	idx := -1
	for i, v := range node.openFiles {
		if v == opened {
			idx = i
			break
		}
	}

	l := len(node.openFiles)
	node.openFiles[idx] = node.openFiles[l-1]
	node.openFiles = node.openFiles[:l-1]
	node.openFilesMutex.Unlock()

	return opened
}

func (m *fileSystemMount) registerFileHandle(node *Inode, dir *connectorDir, f File, flags uint32) (uint64, *openedFile) {
	node.openFilesMutex.Lock()
	b := &openedFile{
		dir: dir,
		WithFlags: WithFlags{
			File:      f,
			OpenFlags: flags,
		},
	}

	for {
		withFlags, ok := f.(*WithFlags)
		if !ok {
			break
		}

		b.WithFlags.File = withFlags.File
		b.WithFlags.FuseFlags |= withFlags.FuseFlags
		b.WithFlags.Description += withFlags.Description
		f = withFlags.File
	}

	if b.WithFlags.File != nil {
		b.WithFlags.File.SetInode(node)
	}
	node.openFiles = append(node.openFiles, b)
	handle := m.openFiles.Register(&b.handled)
	node.openFilesMutex.Unlock()
	return handle, b
}

// Creates a return entry for a non-existent path.
func (m *fileSystemMount) negativeEntry(out *fuse.EntryOut) bool {
	if m.options.NegativeTimeout > 0.0 {
		out.NodeId = 0
		splitDuration(m.options.NegativeTimeout, &out.EntryValid, &out.EntryValidNsec)
		return true
	}
	return false
}
<commit_msg>Fix memory leak when unregistering most recently opened file handle.<commit_after>package nodefs

import (
	"log"
	"sync"
	"unsafe"

	"github.com/hanwen/go-fuse/fuse"
)

// openedFile stores either an open dir or an open file.
type openedFile struct {
	handled

	WithFlags

	dir *connectorDir
}

type fileSystemMount struct {
	// Node that we were mounted on.
	mountInode *Inode

	// Parent to the mountInode.
	parentInode *Inode

	// Options for the mount.
	options *Options

	// Protects Children hashmaps within the mount.  treeLock
	// should be acquired before openFilesLock.
	//
	// If multiple treeLocks must be acquired, the treeLocks
	// closer to the root must be acquired first.
	treeLock sync.RWMutex

	// Manage filehandles of open files.
	openFiles handleMap

	Debug bool

	connector *FileSystemConnector
}

// Must called with lock for parent held.
func (m *fileSystemMount) mountName() string {
	for k, v := range m.parentInode.children {
		if m.mountInode == v {
			return k
		}
	}
	panic("not found")
	return ""
}

func (m *fileSystemMount) setOwner(attr *fuse.Attr) {
	if m.options.Owner != nil {
		attr.Owner = *(*fuse.Owner)(m.options.Owner)
	}
}

func (m *fileSystemMount) fillEntry(out *fuse.EntryOut) {
	splitDuration(m.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
	splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
	m.setOwner(&out.Attr)
	if out.Mode&fuse.S_IFDIR == 0 && out.Nlink == 0 {
		out.Nlink = 1
	}
}

func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) {
	splitDuration(m.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
	m.setOwner(&out.Attr)
	out.Ino = nodeId
}

func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile {
	var b *openedFile
	if h != 0 {
		b = (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h)))
	}

	if b != nil && m.connector.debug && b.WithFlags.Description != "" {
		log.Printf("File %d = %q", h, b.WithFlags.Description)
	}
	return b
}

func (m *fileSystemMount) unregisterFileHandle(handle uint64, node *Inode) *openedFile {
	_, obj := m.openFiles.Forget(handle, 1)
	opened := (*openedFile)(unsafe.Pointer(obj))
	node.openFilesMutex.Lock()
	idx := -1
	for i, v := range node.openFiles {
		if v == opened {
			idx = i
			break
		}
	}

	l := len(node.openFiles)
	if idx == l-1 {
		node.openFiles[idx] = nil
	} else {
		node.openFiles[idx] = node.openFiles[l-1]
	}
	node.openFiles = node.openFiles[:l-1]
	node.openFilesMutex.Unlock()

	return opened
}

func (m *fileSystemMount) registerFileHandle(node *Inode, dir *connectorDir, f File, flags uint32) (uint64, *openedFile) {
	node.openFilesMutex.Lock()
	b := &openedFile{
		dir: dir,
		WithFlags: WithFlags{
			File:      f,
			OpenFlags: flags,
		},
	}

	for {
		withFlags, ok := f.(*WithFlags)
		if !ok {
			break
		}

		b.WithFlags.File = withFlags.File
		b.WithFlags.FuseFlags |= withFlags.FuseFlags
		b.WithFlags.Description += withFlags.Description
		f = withFlags.File
	}

	if b.WithFlags.File != nil {
		b.WithFlags.File.SetInode(node)
	}
	node.openFiles = append(node.openFiles, b)
	handle := m.openFiles.Register(&b.handled)
	node.openFilesMutex.Unlock()
	return handle, b
}

// Creates a return entry for a non-existent path.
func (m *fileSystemMount) negativeEntry(out *fuse.EntryOut) bool {
	if m.options.NegativeTimeout > 0.0 {
		out.NodeId = 0
		splitDuration(m.options.NegativeTimeout, &out.EntryValid, &out.EntryValidNsec)
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package websocket

import (
	"time"

	jsonrpc2websocket "github.com/asuleymanov/jsonrpc2/websocket"
	"github.com/asuleymanov/websocket"
)

// ObjectStream implements jsonrpc2.ObjectStream that uses a WebSocket.
// It extends jsonrpc2/websocket.ObjectStream with read/write timeouts.
type ObjectStream struct {
	conn   *websocket.Conn
	stream jsonrpc2websocket.ObjectStream

	writeTimeout time.Duration
	readTimeout  time.Duration
}

//NewObjectStream initialised ObjectStream
func NewObjectStream(conn *websocket.Conn, writeTimeout, readTimeout time.Duration) *ObjectStream {
	return &ObjectStream{conn, jsonrpc2websocket.NewObjectStream(conn), writeTimeout, readTimeout}
}

//WriteObject data record in ObjectStream
func (stream *ObjectStream) WriteObject(v interface{}) error {
	stream.conn.SetWriteDeadline(time.Now().Add(stream.writeTimeout))
	return stream.stream.WriteObject(v)
}

//ReadObject reading data from ObjectStream
func (stream *ObjectStream) ReadObject(v interface{}) error {
	stream.conn.SetReadDeadline(time.Now().Add(stream.readTimeout))
	return stream.stream.ReadObject(v)
}

//Close closing the ObjectStream
func (stream *ObjectStream) Close() error {
	return stream.stream.Close()
}
<commit_msg>Update object_stream.go<commit_after>package websocket

import (
	"time"

	jsonrpc2websocket "github.com/asuleymanov/jsonrpc2/websocket"
	"github.com/asuleymanov/websocket"
)

// ObjectStream implements jsonrpc2.ObjectStream that uses a WebSocket.
// It extends jsonrpc2/websocket.ObjectStream with read/write timeouts.
type ObjectStream struct {
	conn   *websocket.Conn
	stream jsonrpc2websocket.ObjectStream

	writeTimeout time.Duration
	readTimeout  time.Duration
}

//NewObjectStream initialised ObjectStream
func NewObjectStream(conn *websocket.Conn, writeTimeout, readTimeout time.Duration) *ObjectStream {
	return &ObjectStream{conn, jsonrpc2websocket.NewObjectStream(conn), writeTimeout, readTimeout}
}

//WriteObject data record in ObjectStream
func (stream *ObjectStream) WriteObject(v interface{}) error {
	err:=stream.conn.SetWriteDeadline(time.Now().Add(stream.writeTimeout))
	if err!=nil {
		return err
	}
	return stream.stream.WriteObject(v)
}

//ReadObject reading data from ObjectStream
func (stream *ObjectStream) ReadObject(v interface{}) error {
	err:=stream.conn.SetReadDeadline(time.Now().Add(stream.readTimeout))
	if err!=nil {
		return err
	}
	return stream.stream.ReadObject(v)
}

//Close closing the ObjectStream
func (stream *ObjectStream) Close() error {
	return stream.stream.Close()
}
<|endoftext|>


<commit_before>package gatherrun

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var (
	abuseInterval     = time.Minute * 5
	analyticsInterval = time.Hour * 24
	envVarName        = "GATHER"
)

type GatherRun struct {
	DestFolder string
	Exporter   Exporter
	Fetcher    Fetcher
	Env        string
	Username   string
	ScriptType string
}

func Run(env, username string) {
	fetcher := &S3Fetcher{
		BucketName: "koding-gather",
		FileName:   "koding-kernel.tar",
		Region:     "us-east-1",
	}

	exporter := NewKodingExporter()

	go func() {
		New(fetcher, exporter, env, username, "abuse").Run()
		New(fetcher, exporter, env, username, "analytics").Run()
	}()

	abuseTimer := time.NewTimer(abuseInterval)
	analyticsTimer := time.NewTimer(analyticsInterval)

	for {
		select {
		case <-abuseTimer.C:
			New(fetcher, exporter, env, username, "abuse").Run()
		case <-analyticsTimer.C:
			New(fetcher, exporter, env, username, "analytics").Run()
		}
	}
}

func New(fetcher Fetcher, exporter Exporter, env, username, scriptType string) *GatherRun {
	tmpDir, err := ioutil.TempDir("/tmp", "koding-kernel")
	if err != nil {
		// TODO: how to deal with errs
	}

	return &GatherRun{
		Fetcher:    fetcher,
		Exporter:   exporter,
		DestFolder: tmpDir,
		Env:        env,
		Username:   username,
		ScriptType: scriptType,
	}
}

func (c *GatherRun) Run() (err error) {
	defer func() { err = c.Cleanup() }()

	binary, err := c.GetGatherBinary()
	if err != nil {
		return err
	}

	if err = c.Export(binary.Run()); err != nil {
		return err
	}

	return nil
}

func (c *GatherRun) GetGatherBinary() (*GatherBinary, error) {
	if err := os.MkdirAll(c.DestFolder, 0777); err != nil {
		return nil, err
	}

	if err := c.DownloadScripts(c.DestFolder); err != nil {
		return nil, err
	}

	tarFile := filepath.Join(c.DestFolder, c.Fetcher.GetFileName())
	if err := untar(tarFile, c.DestFolder); err != nil {
		return nil, err
	}

	binaryPath := strings.TrimSuffix(tarFile, tarSuffix)
	return &GatherBinary{Path: binaryPath, ScriptType: c.ScriptType}, nil
}

func (c *GatherRun) DownloadScripts(folderName string) error {
	return c.Fetcher.Download(folderName)
}

func (c *GatherRun) Export(raw []interface{}, err error) error {
	if err != nil {
		return c.sendErrors(err)
	}

	var stats = []GatherSingleStat{}
	var errors = []error{}

	for _, r := range raw {
		buf := new(bytes.Buffer)
		if err := json.NewEncoder(buf).Encode(r); err != nil {
			errors = append(errors, err)
			continue
		}

		var stat GatherSingleStat
		if err := json.NewDecoder(buf).Decode(&stat); err != nil {
			errors = append(errors, err)
			continue
		}

		stats = append(stats, stat)
	}

	if len(errors) > 0 {
		c.sendErrors(errors...)
	}

	if len(stats) > 0 {
		gStat := &GatherStat{
			Env: c.Env, Username: c.Username, Stats: stats, Type: c.ScriptType,
		}
		return c.Exporter.SendStats(gStat)
	}

	return nil
}

func (c *GatherRun) Cleanup() error {
	return os.RemoveAll(c.DestFolder)
}

func (c *GatherRun) sendErrors(errs ...error) error {
	gErr := &GatherError{
		Env: c.Env, Username: c.Username, Errors: errs,
	}

	return c.Exporter.SendError(gErr)
}
<commit_msg>gather: increase abuse checking to every 15 mins<commit_after>package gatherrun

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var (
	abuseInterval     = time.Minute * 15
	analyticsInterval = time.Hour * 24
	envVarName        = "GATHER"
)

type GatherRun struct {
	DestFolder string
	Exporter   Exporter
	Fetcher    Fetcher
	Env        string
	Username   string
	ScriptType string
}

func Run(env, username string) {
	fetcher := &S3Fetcher{
		BucketName: "koding-gather",
		FileName:   "koding-kernel.tar",
		Region:     "us-east-1",
	}

	exporter := NewKodingExporter()

	go func() {
		New(fetcher, exporter, env, username, "abuse").Run()
		New(fetcher, exporter, env, username, "analytics").Run()
	}()

	abuseTimer := time.NewTimer(abuseInterval)
	analyticsTimer := time.NewTimer(analyticsInterval)

	for {
		select {
		case <-abuseTimer.C:
			New(fetcher, exporter, env, username, "abuse").Run()
		case <-analyticsTimer.C:
			New(fetcher, exporter, env, username, "analytics").Run()
		}
	}
}

func New(fetcher Fetcher, exporter Exporter, env, username, scriptType string) *GatherRun {
	tmpDir, err := ioutil.TempDir("/tmp", "koding-kernel")
	if err != nil {
		// TODO: how to deal with errs
	}

	return &GatherRun{
		Fetcher:    fetcher,
		Exporter:   exporter,
		DestFolder: tmpDir,
		Env:        env,
		Username:   username,
		ScriptType: scriptType,
	}
}

func (c *GatherRun) Run() (err error) {
	defer func() { err = c.Cleanup() }()

	binary, err := c.GetGatherBinary()
	if err != nil {
		return err
	}

	if err = c.Export(binary.Run()); err != nil {
		return err
	}

	return nil
}

func (c *GatherRun) GetGatherBinary() (*GatherBinary, error) {
	if err := os.MkdirAll(c.DestFolder, 0777); err != nil {
		return nil, err
	}

	if err := c.DownloadScripts(c.DestFolder); err != nil {
		return nil, err
	}

	tarFile := filepath.Join(c.DestFolder, c.Fetcher.GetFileName())
	if err := untar(tarFile, c.DestFolder); err != nil {
		return nil, err
	}

	binaryPath := strings.TrimSuffix(tarFile, tarSuffix)
	return &GatherBinary{Path: binaryPath, ScriptType: c.ScriptType}, nil
}

func (c *GatherRun) DownloadScripts(folderName string) error {
	return c.Fetcher.Download(folderName)
}

func (c *GatherRun) Export(raw []interface{}, err error) error {
	if err != nil {
		return c.sendErrors(err)
	}

	var stats = []GatherSingleStat{}
	var errors = []error{}

	for _, r := range raw {
		buf := new(bytes.Buffer)
		if err := json.NewEncoder(buf).Encode(r); err != nil {
			errors = append(errors, err)
			continue
		}

		var stat GatherSingleStat
		if err := json.NewDecoder(buf).Decode(&stat); err != nil {
			errors = append(errors, err)
			continue
		}

		stats = append(stats, stat)
	}

	if len(errors) > 0 {
		c.sendErrors(errors...)
	}

	if len(stats) > 0 {
		gStat := &GatherStat{
			Env: c.Env, Username: c.Username, Stats: stats, Type: c.ScriptType,
		}
		return c.Exporter.SendStats(gStat)
	}

	return nil
}

func (c *GatherRun) Cleanup() error {
	return os.RemoveAll(c.DestFolder)
}

func (c *GatherRun) sendErrors(errs ...error) error {
	gErr := &GatherError{
		Env: c.Env, Username: c.Username, Errors: errs,
	}

	return c.Exporter.SendError(gErr)
}
<|endoftext|>


<commit_before>// Copyright 2018 Crisp IM SARL All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package crisp

import (
  "fmt"
)

// WebsiteBatchConversationsOperation mapping
type WebsiteBatchConversationsOperation struct {
  Sessions  *[]string  `json:"sessions,omitempty"`
}

// WebsiteBatchPeopleOperation mapping
type WebsiteBatchPeopleOperation struct {
  People  *WebsiteBatchPeopleOperationInner  `json:"people,omitempty"`
}

// WebsiteBatchPeopleOperationInner mapping
type WebsiteBatchPeopleOperationInner struct {
  Profiles  *[]string                                `json:"profiles,omitempty"`
  Search    *WebsiteBatchPeopleOperationInnerSearch  `json:"search,omitempty"`
}

// WebsiteBatchPeopleOperationInnerSearch mapping
type WebsiteBatchPeopleOperationInnerSearch struct {
  Filter    []WebsiteFilter  `json:"filter,omitempty"`
  Operator  string           `json:"operator,omitempty"`
}

// BatchResolveConversations resolves given (or all) items in website (conversation variant).
func (service *WebsiteService) BatchResolveConversations(websiteID string, sessions []string) (*Response, error) {
  url := fmt.Sprintf("website/%s/batch/resolve", websiteID)
  req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchConversationsOperation{Sessions: &sessions})

  return service.client.Do(req, nil)
}

// BatchReadConversations marks given (or all) items as read in website (conversation variant).
func (service *WebsiteService) BatchReadConversations(websiteID string, sessions []string) (*Response, error) {
  url := fmt.Sprintf("website/%s/batch/read", websiteID)
  req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchConversationsOperation{Sessions: &sessions})

  return service.client.Do(req, nil)
}

// BatchRemoveConversations removes given items in website (conversation variant).
func (service *WebsiteService) BatchRemoveConversations(websiteID string, sessions []string) (*Response, error) {
  url := fmt.Sprintf("website/%s/batch/remove", websiteID)
  req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchConversationsOperation{Sessions: &sessions})

  return service.client.Do(req, nil)
}

// BatchRemovePeople removes given items in website (people variant).
func (service *WebsiteService) BatchRemovePeople(websiteID string, people WebsiteBatchPeopleOperationInner) (*Response, error) {
  url := fmt.Sprintf("website/%s/batch/remove", websiteID)
  req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchPeopleOperation{People: &people})

  return service.client.Do(req, nil)
}
<commit_msg>Fix Website Batch operations for all sessions<commit_after>// Copyright 2018 Crisp IM SARL All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package crisp

import (
	"fmt"
)

// WebsiteBatchConversationsOperation mapping
type WebsiteBatchConversationsOperation struct {
	Sessions []string `json:"sessions,omitempty"`
}

// WebsiteBatchPeopleOperation mapping
type WebsiteBatchPeopleOperation struct {
	People *WebsiteBatchPeopleOperationInner `json:"people,omitempty"`
}

// WebsiteBatchPeopleOperationInner mapping
type WebsiteBatchPeopleOperationInner struct {
	Profiles *[]string                               `json:"profiles,omitempty"`
	Search   *WebsiteBatchPeopleOperationInnerSearch `json:"search,omitempty"`
}

// WebsiteBatchPeopleOperationInnerSearch mapping
type WebsiteBatchPeopleOperationInnerSearch struct {
	Filter   []WebsiteFilter `json:"filter,omitempty"`
	Operator string          `json:"operator,omitempty"`
}

// BatchResolveConversations resolves given (or all) items in website (conversation variant).
func (service *WebsiteService) BatchResolveConversations(websiteID string, sessions []string) (*Response, error) {
	url := fmt.Sprintf("website/%s/batch/resolve", websiteID)
	req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchConversationsOperation{Sessions: sessions})

	return service.client.Do(req, nil)
}

// BatchReadConversations marks given (or all) items as read in website (conversation variant).
func (service *WebsiteService) BatchReadConversations(websiteID string, sessions []string) (*Response, error) {
	url := fmt.Sprintf("website/%s/batch/read", websiteID)
	req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchConversationsOperation{Sessions: sessions})

	return service.client.Do(req, nil)
}

// BatchRemoveConversations removes given items in website (conversation variant).
func (service *WebsiteService) BatchRemoveConversations(websiteID string, sessions []string) (*Response, error) {
	url := fmt.Sprintf("website/%s/batch/remove", websiteID)
	req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchConversationsOperation{Sessions: sessions})

	return service.client.Do(req, nil)
}

// BatchRemovePeople removes given items in website (people variant).
func (service *WebsiteService) BatchRemovePeople(websiteID string, people WebsiteBatchPeopleOperationInner) (*Response, error) {
	url := fmt.Sprintf("website/%s/batch/remove", websiteID)
	req, _ := service.client.NewRequest("PATCH", url, WebsiteBatchPeopleOperation{People: &people})

	return service.client.Do(req, nil)
}
<|endoftext|>


<commit_before>// Copyright 2013 The go-toggl AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package toggl

import (
	"errors"
	"fmt"
	"time"
)

// TasksService handles communication with the tasks related
// methods of the Toggl API.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md
type TasksService struct {
	client *Client
}

// Task represents a task.
type Task struct {
	ID               int        `json:"id,omitempty"`
	Name             string     `json:"name,omitempty"`
	ProjectID        int        `json:"pid,omitempty"`
	UserID           int        `json:"uid,omitempty"`
	WorkspaceID      int        `json:"wid,omitempty"`
	EstimatedSeconds int        `json:"estimated_seconds,omitempty"`
	Active           bool       `json:"active,omitempty"`
	At               *time.Time `json:"time,omitempty"`
}

// TaskResponse acts as a response wrapper where response returns
// in format of "data": Tasks's object.
type TaskResponse struct {
	Data *Task `json:"data,omitempty"`
}

// TaskMassResponse acts as a response wrapper where response returns
// in format of "data": [ ... ].
type TaskMaskResponse struct {
	Data []Task `json:"data,omitempty"`
}

// TaskCreate represents posted data to be sent to task endpoint.
type TaskCreate struct {
	Task *Task `json:"task,omitempty"`
}

// Create a task.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#actions-for-single-project-user
func (s *TasksService) Create(t *Task) (*Task, error) {
	u := "tasks"
	tc := &TaskCreate{t}
	req, err := s.client.NewRequest("POST", u, tc)
	if err != nil {
		return nil, err
	}

	data := new(TaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// Get task details by task_id.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#get-task-details
func (s *TasksService) Get(id int) (*Task, error) {
	u := fmt.Sprintf("tasks/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	data := new(TaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// Update a task.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#update-a-task
func (s *TasksService) Update(t *Task) (*Task, error) {
	if t == nil {
		return nil, errors.New("Task cannot be nil")
	}
	if t.ID <= 0 {
		return nil, errors.New("Invalid Task.ID")
	}

	u := fmt.Sprintf("tasks/%v", t.ID)

	tc := &TaskCreate{t}
	req, err := s.client.NewRequest("PUT", u, tc)
	if err != nil {
		return nil, err
	}

	data := new(TaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// MassUpdate mass update tasks.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#update-multiple-tasks
func (s *TasksService) MassUpdate(ids string, t *Task) ([]Task, error) {
	u := fmt.Sprintf("tasks/%v", ids)

	tc := &TaskCreate{t}
	req, err := s.client.NewRequest("PUT", u, tc)
	if err != nil {
		return nil, err
	}

	data := new(TaskMaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// Delete a task.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#delete-a-task
func (s *TasksService) Delete(id int) error {
	u := fmt.Sprintf("tasks/%v", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}

// MassDelete mass delete tasks.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#delete-multiple-tasks
func (s *TasksService) MassDelete(ids string) error {
	u := fmt.Sprintf("tasks/%v", ids)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}
<commit_msg>Fixed invalid 'at' key's name.<commit_after>// Copyright 2013 The go-toggl AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package toggl

import (
	"errors"
	"fmt"
	"time"
)

// TasksService handles communication with the tasks related
// methods of the Toggl API.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md
type TasksService struct {
	client *Client
}

// Task represents a task.
type Task struct {
	ID               int        `json:"id,omitempty"`
	Name             string     `json:"name,omitempty"`
	ProjectID        int        `json:"pid,omitempty"`
	UserID           int        `json:"uid,omitempty"`
	WorkspaceID      int        `json:"wid,omitempty"`
	EstimatedSeconds int        `json:"estimated_seconds,omitempty"`
	Active           bool       `json:"active,omitempty"`
	At               *time.Time `json:"at,omitempty"`
}

// TaskResponse acts as a response wrapper where response returns
// in format of "data": Tasks's object.
type TaskResponse struct {
	Data *Task `json:"data,omitempty"`
}

// TaskMassResponse acts as a response wrapper where response returns
// in format of "data": [ ... ].
type TaskMaskResponse struct {
	Data []Task `json:"data,omitempty"`
}

// TaskCreate represents posted data to be sent to task endpoint.
type TaskCreate struct {
	Task *Task `json:"task,omitempty"`
}

// Create a task.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#actions-for-single-project-user
func (s *TasksService) Create(t *Task) (*Task, error) {
	u := "tasks"
	tc := &TaskCreate{t}
	req, err := s.client.NewRequest("POST", u, tc)
	if err != nil {
		return nil, err
	}

	data := new(TaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// Get task details by task_id.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#get-task-details
func (s *TasksService) Get(id int) (*Task, error) {
	u := fmt.Sprintf("tasks/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	data := new(TaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// Update a task.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#update-a-task
func (s *TasksService) Update(t *Task) (*Task, error) {
	if t == nil {
		return nil, errors.New("Task cannot be nil")
	}
	if t.ID <= 0 {
		return nil, errors.New("Invalid Task.ID")
	}

	u := fmt.Sprintf("tasks/%v", t.ID)

	tc := &TaskCreate{t}
	req, err := s.client.NewRequest("PUT", u, tc)
	if err != nil {
		return nil, err
	}

	data := new(TaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// MassUpdate mass update tasks.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#update-multiple-tasks
func (s *TasksService) MassUpdate(ids string, t *Task) ([]Task, error) {
	u := fmt.Sprintf("tasks/%v", ids)

	tc := &TaskCreate{t}
	req, err := s.client.NewRequest("PUT", u, tc)
	if err != nil {
		return nil, err
	}

	data := new(TaskMaskResponse)
	_, err = s.client.Do(req, data)

	return data.Data, err
}

// Delete a task.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#delete-a-task
func (s *TasksService) Delete(id int) error {
	u := fmt.Sprintf("tasks/%v", id)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}

// MassDelete mass delete tasks.
//
// Toggl API docs: https://github.com/toggl/toggl_api_docs/blob/master/chapters/tasks.md#delete-multiple-tasks
func (s *TasksService) MassDelete(ids string) error {
	u := fmt.Sprintf("tasks/%v", ids)
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}
<|endoftext|>