<commit_before>package app

import (
	"github.com/moncho/dry/ui"
	"github.com/nsf/termbox-go"
)

//KeyPressEvent maps a key to an app action
type eventHandler interface {
	handle(event termbox.Event) (refresh bool, focus bool)
}

type containersScreenEventHandler struct {
	dry                  *Dry
	screen               *ui.Screen
	keyboardQueueForView chan termbox.Event
	viewClosed           chan struct{}
}

func (h containersScreenEventHandler) handle(event termbox.Event) (refresh bool, focus bool) {
	focus = true
	dry := h.dry
	screen := h.screen
	if event.Key == termbox.KeyArrowUp { //cursor up
		screen.ScrollCursorUp()
		refresh = true
	} else if event.Key == termbox.KeyArrowDown { // cursor down
		screen.ScrollCursorDown()
		refresh = true
	} else if event.Key == termbox.KeyF1 { //sort
		dry.Sort()
	} else if event.Key == termbox.KeyF2 { //show all containers
		dry.ToggleShowAllContainers()
	} else if event.Key == termbox.KeyF5 { // refresh
		dry.Refresh()
	} else if event.Key == termbox.KeyF10 { // docker info
		dry.ShowInfo()
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '?' || event.Ch == 'h' || event.Ch == 'H' { //help
		focus = false
		dry.ShowHelp()
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '1' {
		screen.Cursor.Line = 0
		dry.ShowImages()
	} else if event.Ch == '2' {
		screen.Cursor.Line = 0
		dry.ShowNetworks()
	} else if event.Ch == 'e' || event.Ch == 'E' { //remove
		dry.Rm(screen.CursorPosition())
	} else if event.Key == termbox.KeyCtrlE { //remove all stopped
		dry.RemoveAllStoppedContainers()
	} else if event.Key == termbox.KeyCtrlK { //kill
		dry.Kill(screen.CursorPosition())
	} else if event.Ch == 'l' || event.Ch == 'L' { //logs
		if logs, err := dry.Logs(screen.CursorPosition()); err == nil {
			focus = false
			dry.ShowContainers()
			go stream(screen, logs, h.keyboardQueueForView, h.viewClosed)
		}
	} else if event.Ch == 'r' || event.Ch == 'R' { //start
		dry.StartContainer(screen.CursorPosition())
	} else if event.Ch == 's' || event.Ch == 'S' { //stats
		done, errC, err := dry.Stats(screen.CursorPosition())
		if err == nil {
			focus = false
			go autorefresh(dry, screen, h.keyboardQueueForView, h.viewClosed, done, errC)
		}
	} else if event.Key == termbox.KeyCtrlT { //stop
		dry.StopContainer(screen.CursorPosition())
	} else if event.Key == termbox.KeyEnter { //inspect
		dry.Inspect(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	}
	return (refresh || dry.Changed()), focus
}

type imagesScreenEventHandler struct {
	dry                  *Dry
	screen               *ui.Screen
	keyboardQueueForView chan termbox.Event
	viewClosed           chan struct{}
}

func (h imagesScreenEventHandler) handle(event termbox.Event) (refresh bool, focus bool) {
	focus = true
	dry := h.dry
	screen := h.screen
	if event.Key == termbox.KeyArrowUp { //cursor up
		screen.ScrollCursorUp()
		refresh = true
	} else if event.Key == termbox.KeyArrowDown { // cursor down
		screen.ScrollCursorDown()
		refresh = true
	} else if event.Key == termbox.KeyF1 { //sort
		dry.SortImages()
	} else if event.Key == termbox.KeyF5 { // refresh
		dry.Refresh()
	} else if event.Key == termbox.KeyF10 { // docker info
		dry.ShowInfo()
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '?' || event.Ch == 'h' || event.Ch == 'H' { //help
		focus = false
		dry.ShowHelp()
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '1' {
		screen.Cursor.Line = 0
		dry.ShowContainers()
	} else if event.Ch == '2' {
		screen.Cursor.Line = 0
		dry.ShowNetworks()
	} else if event.Ch == 'e' || event.Ch == 'E' { //remove
		dry.RemoveImage(screen.CursorPosition())
	} else if event.Ch == 'i' || event.Ch == 'I' { //remove
		dry.History(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Key == termbox.KeyEnter { //inspect
		dry.InspectImage(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	}
	return (refresh || dry.Changed()), focus
}

type networksScreenEventHandler struct {
	dry                  *Dry
	screen               *ui.Screen
	keyboardQueueForView chan termbox.Event
	viewClosed           chan struct{}
}

func (h networksScreenEventHandler) handle(event termbox.Event) (refresh bool, focus bool) {
	focus = true
	dry := h.dry
	screen := h.screen
	if event.Key == termbox.KeyArrowUp { //cursor up
		screen.ScrollCursorUp()
		refresh = true
	} else if event.Key == termbox.KeyArrowDown { // cursor down
		screen.ScrollCursorDown()
		refresh = true
	} else if event.Key == termbox.KeyF1 { //sort
		dry.SortNetworks()
	} else if event.Key == termbox.KeyF5 { // refresh
		dry.Refresh()
	} else if event.Key == termbox.KeyF10 { // docker info
		dry.ShowInfo()
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '?' || event.Ch == 'h' || event.Ch == 'H' { //help
		focus = false
		dry.ShowHelp()
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '1' {
		screen.Cursor.Line = 0
		dry.ShowContainers()
	} else if event.Ch == '2' {
		screen.Cursor.Line = 0
		dry.ShowImages()
	} else if event.Key == termbox.KeyEnter { //inspect
		dry.InspectNetwork(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	}
	return (refresh || dry.Changed()), focus
}

func eventHandlerFactory(dry *Dry, screen *ui.Screen,
	keyboardQueueForView chan termbox.Event,
	viewClosed chan struct{}) eventHandler {
	switch dry.viewMode() {
	case Images:
		return imagesScreenEventHandler{dry, screen, keyboardQueueForView, viewClosed}
	case Networks:
		return networksScreenEventHandler{dry, screen, keyboardQueueForView, viewClosed}
	default:
		return containersScreenEventHandler{dry, screen, keyboardQueueForView, viewClosed}
	}
}
<commit_msg>Change remove image keybind to ctrl+e<commit_after>package app

import (
	"github.com/moncho/dry/ui"
	"github.com/nsf/termbox-go"
)

//KeyPressEvent maps a key to an app action
type eventHandler interface {
	handle(event termbox.Event) (refresh bool, focus bool)
}

type containersScreenEventHandler struct {
	dry                  *Dry
	screen               *ui.Screen
	keyboardQueueForView chan termbox.Event
	viewClosed           chan struct{}
}

func (h containersScreenEventHandler) handle(event termbox.Event) (refresh bool, focus bool) {
	focus = true
	dry := h.dry
	screen := h.screen
	if event.Key == termbox.KeyArrowUp { //cursor up
		screen.ScrollCursorUp()
		refresh = true
	} else if event.Key == termbox.KeyArrowDown { // cursor down
		screen.ScrollCursorDown()
		refresh = true
	} else if event.Key == termbox.KeyF1 { //sort
		dry.Sort()
	} else if event.Key == termbox.KeyF2 { //show all containers
		dry.ToggleShowAllContainers()
	} else if event.Key == termbox.KeyF5 { // refresh
		dry.Refresh()
	} else if event.Key == termbox.KeyF10 { // docker info
		dry.ShowInfo()
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '?' || event.Ch == 'h' || event.Ch == 'H' { //help
		focus = false
		dry.ShowHelp()
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '1' {
		screen.Cursor.Line = 0
		dry.ShowImages()
	} else if event.Ch == '2' {
		screen.Cursor.Line = 0
		dry.ShowNetworks()
	} else if event.Ch == 'e' || event.Ch == 'E' { //remove
		dry.Rm(screen.CursorPosition())
	} else if event.Key == termbox.KeyCtrlE { //remove all stopped
		dry.RemoveAllStoppedContainers()
	} else if event.Key == termbox.KeyCtrlK { //kill
		dry.Kill(screen.CursorPosition())
	} else if event.Ch == 'l' || event.Ch == 'L' { //logs
		if logs, err := dry.Logs(screen.CursorPosition()); err == nil {
			focus = false
			dry.ShowContainers()
			go stream(screen, logs, h.keyboardQueueForView, h.viewClosed)
		}
	} else if event.Ch == 'r' || event.Ch == 'R' { //start
		dry.StartContainer(screen.CursorPosition())
	} else if event.Ch == 's' || event.Ch == 'S' { //stats
		done, errC, err := dry.Stats(screen.CursorPosition())
		if err == nil {
			focus = false
			go autorefresh(dry, screen, h.keyboardQueueForView, h.viewClosed, done, errC)
		}
	} else if event.Key == termbox.KeyCtrlT { //stop
		dry.StopContainer(screen.CursorPosition())
	} else if event.Key == termbox.KeyEnter { //inspect
		dry.Inspect(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	}
	return (refresh || dry.Changed()), focus
}

type imagesScreenEventHandler struct {
	dry                  *Dry
	screen               *ui.Screen
	keyboardQueueForView chan termbox.Event
	viewClosed           chan struct{}
}

func (h imagesScreenEventHandler) handle(event termbox.Event) (refresh bool, focus bool) {
	focus = true
	dry := h.dry
	screen := h.screen
	if event.Key == termbox.KeyArrowUp { //cursor up
		screen.ScrollCursorUp()
		refresh = true
	} else if event.Key == termbox.KeyArrowDown { // cursor down
		screen.ScrollCursorDown()
		refresh = true
	} else if event.Key == termbox.KeyF1 { //sort
		dry.SortImages()
	} else if event.Key == termbox.KeyF5 { // refresh
		dry.Refresh()
	} else if event.Key == termbox.KeyF10 { // docker info
		dry.ShowInfo()
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '?' || event.Ch == 'h' || event.Ch == 'H' { //help
		focus = false
		dry.ShowHelp()
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '1' {
		screen.Cursor.Line = 0
		dry.ShowContainers()
	} else if event.Ch == '2' {
		screen.Cursor.Line = 0
		dry.ShowNetworks()
	} else if event.Key == termbox.KeyCtrlE { //remove image
		dry.RemoveImage(screen.CursorPosition())
	} else if event.Ch == 'i' || event.Ch == 'I' { //image history
		dry.History(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Key == termbox.KeyEnter { //inspect image
		dry.InspectImage(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	}
	return (refresh || dry.Changed()), focus
}

type networksScreenEventHandler struct {
	dry                  *Dry
	screen               *ui.Screen
	keyboardQueueForView chan termbox.Event
	viewClosed           chan struct{}
}

func (h networksScreenEventHandler) handle(event termbox.Event) (refresh bool, focus bool) {
	focus = true
	dry := h.dry
	screen := h.screen
	if event.Key == termbox.KeyArrowUp { //cursor up
		screen.ScrollCursorUp()
		refresh = true
	} else if event.Key == termbox.KeyArrowDown { // cursor down
		screen.ScrollCursorDown()
		refresh = true
	} else if event.Key == termbox.KeyF1 { //sort
		dry.SortNetworks()
	} else if event.Key == termbox.KeyF5 { // refresh
		dry.Refresh()
	} else if event.Key == termbox.KeyF10 { // docker info
		dry.ShowInfo()
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '?' || event.Ch == 'h' || event.Ch == 'H' { //help
		focus = false
		dry.ShowHelp()
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	} else if event.Ch == '1' {
		screen.Cursor.Line = 0
		dry.ShowContainers()
	} else if event.Ch == '2' {
		screen.Cursor.Line = 0
		dry.ShowImages()
	} else if event.Key == termbox.KeyEnter { //inspect
		dry.InspectNetwork(screen.CursorPosition())
		focus = false
		go less(dry, screen, h.keyboardQueueForView, h.viewClosed)
	}
	return (refresh || dry.Changed()), focus
}

func eventHandlerFactory(dry *Dry, screen *ui.Screen,
	keyboardQueueForView chan termbox.Event,
	viewClosed chan struct{}) eventHandler {
	switch dry.viewMode() {
	case Images:
		return imagesScreenEventHandler{dry, screen, keyboardQueueForView, viewClosed}
	case Networks:
		return networksScreenEventHandler{dry, screen, keyboardQueueForView, viewClosed}
	default:
		return containersScreenEventHandler{dry, screen, keyboardQueueForView, viewClosed}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 the Velero contributors.

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 output

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)

var (
	backupStorageLocationColumns = []metav1.TableColumnDefinition{
		// name needs Type and Format defined for the decorator to identify it:
		// https://github.com/kubernetes/kubernetes/blob/v1.15.3/pkg/printers/tableprinter.go#L204
		{Name: "Name", Type: "string", Format: "name"},
		{Name: "Provider"},
		{Name: "Bucket/Prefix"},
		{Name: "Access Mode"},
	}
)

func printBackupStorageLocationList(list *v1.BackupStorageLocationList) []metav1.TableRow {
	rows := make([]metav1.TableRow, 0, len(list.Items))

	for i := range list.Items {
		rows = append(rows, printBackupStorageLocation(&list.Items[i])...)
	}
	return rows
}

func printBackupStorageLocation(location *v1.BackupStorageLocation) []metav1.TableRow {
	row := metav1.TableRow{
		Object: runtime.RawExtension{Object: location},
	}

	bucketAndPrefix := location.Spec.ObjectStorage.Bucket
	if location.Spec.ObjectStorage.Prefix != "" {
		bucketAndPrefix += "/" + location.Spec.ObjectStorage.Prefix
	}

	accessMode := location.Spec.AccessMode
	if accessMode == "" {
		accessMode = v1.BackupStorageLocationAccessModeReadWrite
	}

	row.Cells = append(row.Cells,
		location.Name,
		location.Spec.Provider,
		bucketAndPrefix,
		accessMode,
	)

	return []metav1.TableRow{row}
}
<commit_msg>Add status column to get BSL output (#2493)<commit_after>/*
Copyright 2018, 2020 the Velero contributors.

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 output

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)

var (
	backupStorageLocationColumns = []metav1.TableColumnDefinition{
		// name needs Type and Format defined for the decorator to identify it:
		// https://github.com/kubernetes/kubernetes/blob/v1.15.3/pkg/printers/tableprinter.go#L204
		{Name: "Name", Type: "string", Format: "name"},
		{Name: "Provider"},
		{Name: "Bucket/Prefix"},
		{Name: "Status"},
		{Name: "Access Mode"},
	}
)

func printBackupStorageLocationList(list *velerov1api.BackupStorageLocationList) []metav1.TableRow {
	rows := make([]metav1.TableRow, 0, len(list.Items))

	for i := range list.Items {
		rows = append(rows, printBackupStorageLocation(&list.Items[i])...)
	}
	return rows
}

func printBackupStorageLocation(location *velerov1api.BackupStorageLocation) []metav1.TableRow {
	row := metav1.TableRow{
		Object: runtime.RawExtension{Object: location},
	}

	bucketAndPrefix := location.Spec.ObjectStorage.Bucket
	if location.Spec.ObjectStorage.Prefix != "" {
		bucketAndPrefix += "/" + location.Spec.ObjectStorage.Prefix
	}

	accessMode := location.Spec.AccessMode
	if accessMode == "" {
		accessMode = velerov1api.BackupStorageLocationAccessModeReadWrite
	}

	status := location.Status.Phase
	if status == "" {
		status = "Unknown"
	}

	row.Cells = append(row.Cells,
		location.Name,
		location.Spec.Provider,
		bucketAndPrefix,
		status,
		accessMode,
	)

	return []metav1.TableRow{row}
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"os"
)

// Critical will print a message to os.Stderr unless DEBUG has been set, in
// which case panic will be called instead.
func Critical(v ...interface{}) {
	s := fmt.Sprintln(v...)
	os.Stderr.WriteString(s)
	if DEBUG {
		panic(s)
	}
}
<commit_msg>don't print error messages to stdout while testing<commit_after>package build

import (
	"fmt"
	"os"
)

// Critical will print a message to os.Stderr unless DEBUG has been set, in
// which case panic will be called instead.
func Critical(v ...interface{}) {
	s := fmt.Sprintln(v...)
	if Release != "testing" || !DEBUG {
		os.Stderr.WriteString(s)
	}
	if DEBUG {
		panic(s)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zapcore

import (
	"bytes"
	"fmt"
	"math"
	"reflect"
	"time"
)

// A FieldType indicates which member of the Field union struct should be used
// and how it should be serialized.
type FieldType uint8

const (
	// UnknownType is the default field type. Attempting to add it to an encoder will panic.
	UnknownType FieldType = iota
	// ArrayMarshalerType indicates that the field carries an ArrayMarshaler.
	ArrayMarshalerType
	// ObjectMarshalerType indicates that the field carries an ObjectMarshaler.
	ObjectMarshalerType
	// InlineMarshalerType indicates that the field carries an ObjectMarshaler
	// that should be inlined.
	InlineMarshalerType
	// BinaryType indicates that the field carries an opaque binary blob.
	BinaryType
	// BoolType indicates that the field carries a bool.
	BoolType
	// ByteStringType indicates that the field carries UTF-8 encoded bytes.
	ByteStringType
	// Complex128Type indicates that the field carries a complex128.
	Complex128Type
	// Complex64Type indicates that the field carries a complex128.
	Complex64Type
	// DurationType indicates that the field carries a time.Duration.
	DurationType
	// Float64Type indicates that the field carries a float64.
	Float64Type
	// Float32Type indicates that the field carries a float32.
	Float32Type
	// Int64Type indicates that the field carries an int64.
	Int64Type
	// Int32Type indicates that the field carries an int32.
	Int32Type
	// Int16Type indicates that the field carries an int16.
	Int16Type
	// Int8Type indicates that the field carries an int8.
	Int8Type
	// StringType indicates that the field carries a string.
	StringType
	// TimeType indicates that the field carries a time.Time that is
	// representable by a UnixNano() stored as an int64.
	TimeType
	// TimeFullType indicates that the field carries a time.Time stored as-is.
	TimeFullType
	// Uint64Type indicates that the field carries a uint64.
	Uint64Type
	// Uint32Type indicates that the field carries a uint32.
	Uint32Type
	// Uint16Type indicates that the field carries a uint16.
	Uint16Type
	// Uint8Type indicates that the field carries a uint8.
	Uint8Type
	// UintptrType indicates that the field carries a uintptr.
	UintptrType
	// ReflectType indicates that the field carries an interface{}, which should
	// be serialized using reflection.
	ReflectType
	// NamespaceType signals the beginning of an isolated namespace. All
	// subsequent fields should be added to the new namespace.
	NamespaceType
	// StringerType indicates that the field carries a fmt.Stringer.
	StringerType
	// ErrorType indicates that the field carries an error.
	ErrorType
	// SkipType indicates that the field is a no-op.
	SkipType
)

// A Field is a marshaling operation used to add a key-value pair to a logger's
// context. Most fields are lazily marshaled, so it's inexpensive to add fields
// to disabled debug-level log statements.
type Field struct {
	Key       string
	Type      FieldType
	Integer   int64
	String    string
	Interface interface{}
}

// AddTo exports a field through the ObjectEncoder interface. It's primarily
// useful to library authors, and shouldn't be necessary in most applications.
func (f Field) AddTo(enc ObjectEncoder) {
	var err error

	switch f.Type {
	case ArrayMarshalerType:
		err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
	case ObjectMarshalerType:
		err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
	case InlineMarshalerType:
		err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc)
	case BinaryType:
		enc.AddBinary(f.Key, f.Interface.([]byte))
	case BoolType:
		enc.AddBool(f.Key, f.Integer == 1)
	case ByteStringType:
		enc.AddByteString(f.Key, f.Interface.([]byte))
	case Complex128Type:
		enc.AddComplex128(f.Key, f.Interface.(complex128))
	case Complex64Type:
		enc.AddComplex64(f.Key, f.Interface.(complex64))
	case DurationType:
		enc.AddDuration(f.Key, time.Duration(f.Integer))
	case Float64Type:
		enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
	case Float32Type:
		enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
	case Int64Type:
		enc.AddInt64(f.Key, f.Integer)
	case Int32Type:
		enc.AddInt32(f.Key, int32(f.Integer))
	case Int16Type:
		enc.AddInt16(f.Key, int16(f.Integer))
	case Int8Type:
		enc.AddInt8(f.Key, int8(f.Integer))
	case StringType:
		enc.AddString(f.Key, f.String)
	case TimeType:
		if f.Interface != nil {
			enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
		} else {
			// Fall back to UTC if location is nil.
			enc.AddTime(f.Key, time.Unix(0, f.Integer))
		}
	case TimeFullType:
		enc.AddTime(f.Key, f.Interface.(time.Time))
	case Uint64Type:
		enc.AddUint64(f.Key, uint64(f.Integer))
	case Uint32Type:
		enc.AddUint32(f.Key, uint32(f.Integer))
	case Uint16Type:
		enc.AddUint16(f.Key, uint16(f.Integer))
	case Uint8Type:
		enc.AddUint8(f.Key, uint8(f.Integer))
	case UintptrType:
		enc.AddUintptr(f.Key, uintptr(f.Integer))
	case ReflectType:
		err = enc.AddReflected(f.Key, f.Interface)
	case NamespaceType:
		enc.OpenNamespace(f.Key)
	case StringerType:
		err = encodeStringer(f.Key, f.Interface, enc)
	case ErrorType:
		err = encodeError(f.Key, f.Interface.(error), enc)
	case SkipType:
		break
	default:
		panic(fmt.Sprintf("unknown field type: %v", f))
	}

	if err != nil {
		enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
	}
}

// Equals returns whether two fields are equal. For non-primitive types such as
// errors, marshalers, or reflect types, it uses reflect.DeepEqual.
func (f Field) Equals(other Field) bool {
	if f.Type != other.Type {
		return false
	}
	if f.Key != other.Key {
		return false
	}

	switch f.Type {
	case BinaryType, ByteStringType:
		return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte))
	case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType:
		return reflect.DeepEqual(f.Interface, other.Interface)
	default:
		return f == other
	}
}

func addFields(enc ObjectEncoder, fields []Field) {
	for i := range fields {
		fields[i].AddTo(enc)
	}
}

func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr error) {
	// Try to capture panics (from nil references or otherwise) when calling
	// the String() method, similar to https://golang.org/src/fmt/print.go#L540
	defer func() {
		if err := recover(); err != nil {
			// If it's a nil pointer, just say "<nil>". The likeliest causes are a
			// Stringer that fails to guard against nil or a nil pointer for a
			// value receiver, and in either case, "<nil>" is a nice result.
			if v := reflect.ValueOf(stringer); v.Kind() == reflect.Ptr && v.IsNil() {
				enc.AddString(key, "<nil>")
				return
			}

			retErr = fmt.Errorf("PANIC=%v", err)
		}
	}()

	enc.AddString(key, stringer.(fmt.Stringer).String())
	return nil
}
<commit_msg>zapcore/FieldType: Don't change enum values (#955)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zapcore

import (
	"bytes"
	"fmt"
	"math"
	"reflect"
	"time"
)

// A FieldType indicates which member of the Field union struct should be used
// and how it should be serialized.
type FieldType uint8

const (
	// UnknownType is the default field type. Attempting to add it to an encoder will panic.
	UnknownType FieldType = iota
	// ArrayMarshalerType indicates that the field carries an ArrayMarshaler.
	ArrayMarshalerType
	// ObjectMarshalerType indicates that the field carries an ObjectMarshaler.
	ObjectMarshalerType
	// BinaryType indicates that the field carries an opaque binary blob.
	BinaryType
	// BoolType indicates that the field carries a bool.
	BoolType
	// ByteStringType indicates that the field carries UTF-8 encoded bytes.
	ByteStringType
	// Complex128Type indicates that the field carries a complex128.
	Complex128Type
	// Complex64Type indicates that the field carries a complex128.
	Complex64Type
	// DurationType indicates that the field carries a time.Duration.
	DurationType
	// Float64Type indicates that the field carries a float64.
	Float64Type
	// Float32Type indicates that the field carries a float32.
	Float32Type
	// Int64Type indicates that the field carries an int64.
	Int64Type
	// Int32Type indicates that the field carries an int32.
	Int32Type
	// Int16Type indicates that the field carries an int16.
	Int16Type
	// Int8Type indicates that the field carries an int8.
	Int8Type
	// StringType indicates that the field carries a string.
	StringType
	// TimeType indicates that the field carries a time.Time that is
	// representable by a UnixNano() stored as an int64.
	TimeType
	// TimeFullType indicates that the field carries a time.Time stored as-is.
	TimeFullType
	// Uint64Type indicates that the field carries a uint64.
	Uint64Type
	// Uint32Type indicates that the field carries a uint32.
	Uint32Type
	// Uint16Type indicates that the field carries a uint16.
	Uint16Type
	// Uint8Type indicates that the field carries a uint8.
	Uint8Type
	// UintptrType indicates that the field carries a uintptr.
	UintptrType
	// ReflectType indicates that the field carries an interface{}, which should
	// be serialized using reflection.
	ReflectType
	// NamespaceType signals the beginning of an isolated namespace. All
	// subsequent fields should be added to the new namespace.
	NamespaceType
	// StringerType indicates that the field carries a fmt.Stringer.
	StringerType
	// ErrorType indicates that the field carries an error.
	ErrorType
	// SkipType indicates that the field is a no-op.
	SkipType

	// InlineMarshalerType indicates that the field carries an ObjectMarshaler
	// that should be inlined.
	InlineMarshalerType
)

// A Field is a marshaling operation used to add a key-value pair to a logger's
// context. Most fields are lazily marshaled, so it's inexpensive to add fields
// to disabled debug-level log statements.
type Field struct {
	Key       string
	Type      FieldType
	Integer   int64
	String    string
	Interface interface{}
}

// AddTo exports a field through the ObjectEncoder interface. It's primarily
// useful to library authors, and shouldn't be necessary in most applications.
func (f Field) AddTo(enc ObjectEncoder) {
	var err error

	switch f.Type {
	case ArrayMarshalerType:
		err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
	case ObjectMarshalerType:
		err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
	case InlineMarshalerType:
		err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc)
	case BinaryType:
		enc.AddBinary(f.Key, f.Interface.([]byte))
	case BoolType:
		enc.AddBool(f.Key, f.Integer == 1)
	case ByteStringType:
		enc.AddByteString(f.Key, f.Interface.([]byte))
	case Complex128Type:
		enc.AddComplex128(f.Key, f.Interface.(complex128))
	case Complex64Type:
		enc.AddComplex64(f.Key, f.Interface.(complex64))
	case DurationType:
		enc.AddDuration(f.Key, time.Duration(f.Integer))
	case Float64Type:
		enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
	case Float32Type:
		enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
	case Int64Type:
		enc.AddInt64(f.Key, f.Integer)
	case Int32Type:
		enc.AddInt32(f.Key, int32(f.Integer))
	case Int16Type:
		enc.AddInt16(f.Key, int16(f.Integer))
	case Int8Type:
		enc.AddInt8(f.Key, int8(f.Integer))
	case StringType:
		enc.AddString(f.Key, f.String)
	case TimeType:
		if f.Interface != nil {
			enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
		} else {
			// Fall back to UTC if location is nil.
			enc.AddTime(f.Key, time.Unix(0, f.Integer))
		}
	case TimeFullType:
		enc.AddTime(f.Key, f.Interface.(time.Time))
	case Uint64Type:
		enc.AddUint64(f.Key, uint64(f.Integer))
	case Uint32Type:
		enc.AddUint32(f.Key, uint32(f.Integer))
	case Uint16Type:
		enc.AddUint16(f.Key, uint16(f.Integer))
	case Uint8Type:
		enc.AddUint8(f.Key, uint8(f.Integer))
	case UintptrType:
		enc.AddUintptr(f.Key, uintptr(f.Integer))
	case ReflectType:
		err = enc.AddReflected(f.Key, f.Interface)
	case NamespaceType:
		enc.OpenNamespace(f.Key)
	case StringerType:
		err = encodeStringer(f.Key, f.Interface, enc)
	case ErrorType:
		err = encodeError(f.Key, f.Interface.(error), enc)
	case SkipType:
		break
	default:
		panic(fmt.Sprintf("unknown field type: %v", f))
	}

	if err != nil {
		enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
	}
}

// Equals returns whether two fields are equal. For non-primitive types such as
// errors, marshalers, or reflect types, it uses reflect.DeepEqual.
func (f Field) Equals(other Field) bool {
	if f.Type != other.Type {
		return false
	}
	if f.Key != other.Key {
		return false
	}

	switch f.Type {
	case BinaryType, ByteStringType:
		return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte))
	case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType:
		return reflect.DeepEqual(f.Interface, other.Interface)
	default:
		return f == other
	}
}

func addFields(enc ObjectEncoder, fields []Field) {
	for i := range fields {
		fields[i].AddTo(enc)
	}
}

func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr error) {
	// Try to capture panics (from nil references or otherwise) when calling
	// the String() method, similar to https://golang.org/src/fmt/print.go#L540
	defer func() {
		if err := recover(); err != nil {
			// If it's a nil pointer, just say "<nil>". The likeliest causes are a
			// Stringer that fails to guard against nil or a nil pointer for a
			// value receiver, and in either case, "<nil>" is a nice result.
			if v := reflect.ValueOf(stringer); v.Kind() == reflect.Ptr && v.IsNil() {
				enc.AddString(key, "<nil>")
				return
			}

			retErr = fmt.Errorf("PANIC=%v", err)
		}
	}()

	enc.AddString(key, stringer.(fmt.Stringer).String())
	return nil
}
<|endoftext|>


<commit_before>package indexer

import (
	"fmt"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/macarrie/flemzerd/downloadable"

	"github.com/macarrie/flemzerd/configuration"
	log "github.com/macarrie/flemzerd/logging"
	. "github.com/macarrie/flemzerd/objects"
	"github.com/macarrie/flemzerd/vidocq"

	"github.com/hashicorp/go-multierror"
)

var indexersCollection []Indexer

func AddIndexer(indexer Indexer) {
	indexersCollection = append(indexersCollection, indexer)
	log.WithFields(log.Fields{
		"indexer": indexer.GetName(),
	}).Debug("Indexer loaded")
}

func Status() ([]Module, error) {
	var modChan = make(chan Module, len(indexersCollection))
	var errorList *multierror.Error

	var wg sync.WaitGroup
	var errorListMutex sync.Mutex

	for _, indexer := range indexersCollection {
		wg.Add(1)
		go func() {
			defer wg.Done()

			mod, indexerAliveError := indexer.Status()
			modChan <- mod
			if indexerAliveError != nil {
				log.WithFields(log.Fields{
					"error": indexerAliveError,
				}).Warning("Indexer is not alive")

				errorListMutex.Lock()
				errorList = multierror.Append(errorList, indexerAliveError)
				errorListMutex.Unlock()
			}
		}()
	}

	wg.Wait()
	close(modChan)
	var modList []Module
	for mod := range modChan {
		modList = append(modList, mod)
	}

	return modList, errorList.ErrorOrNil()
}

func Reset() {
	indexersCollection = []Indexer{}
}

func GetTorrents(d downloadable.Downloadable) ([]Torrent, error) {
	var torrentList []Torrent
	var errorList *multierror.Error
	var totalError bool = true

	for _, indexer := range indexersCollection {
		indexerSearch, err := indexer.GetTorrents(d)
		if err != nil {
			d.GetLog().WithFields(log.Fields{
				"indexer": indexer.GetName(),
				"error":   err,
			}).Warning("Couldn't get torrents from indexer")
			errorList = multierror.Append(errorList, err)
			continue
		} else {
			totalError = false
		}

		if len(indexerSearch) != 0 {
			torrentList = append(torrentList, indexerSearch...)
			d.GetLog().WithFields(log.Fields{
				"indexer": indexer.GetName(),
				"nb":      len(indexerSearch),
			}).Info("Torrents found")
		} else {
			d.GetLog().WithFields(log.Fields{
				"indexer": indexer.GetName(),
			}).Info("No torrents found")
		}
	}

	sort.Slice(torrentList[:], func(i, j int) bool {
		return torrentList[i].Seeders > torrentList[j].Seeders
	})

	switch d.(type) {
	case *Movie:
		torrentList = FilterMovieTorrents(*d.(*Movie), torrentList)
	case *Episode:
		torrentList = FilterEpisodeTorrents(*d.(*Episode), torrentList)
	}

	if totalError {
		return torrentList, errorList.ErrorOrNil()
	}

	return torrentList, nil
}

func FilterEpisodeTorrents(episode Episode, torrentList []Torrent) []Torrent {
	torrentList = FilterTorrentEpisodeNumber(torrentList, episode)
	torrentList = FilterTorrentQuality(torrentList)
	torrentList = FilterTorrentReleaseType(torrentList)

	return torrentList
}

func FilterMovieTorrents(movie Movie, torrentList []Torrent) []Torrent {
	torrentList = FilterTorrentQuality(torrentList)
	if movie.Date.Year() != 1 {
		torrentList = FilterTorrentYear(torrentList, movie.Date.Year())
	}
	torrentList = FilterTorrentReleaseType(torrentList)

	return torrentList
}

func FilterTorrentEpisodeNumber(list []Torrent, episode Episode) []Torrent {
	log.WithFields(log.Fields{
		"strict_check": configuration.Config.System.StrictTorrentCheck,
	}).Debug("Checking torrent list for bad episodes")

	var returnList []Torrent
	var otherTorrents []Torrent

	for _, torrent := range list {
		if episode.TvShow.IsAnime {
			if episode.AbsoluteNumber != 0 {
				match, err := regexp.Match(fmt.Sprintf("%v", episode.AbsoluteNumber), []byte(torrent.Name))
				if match && err == nil {
					returnList = append(returnList, torrent)
				}
			} else {
				otherTorrents = append(otherTorrents, torrent)
			}
		} else {
			episodeInfo, err := vidocq.GetInfo(torrent.Name)
			if err != nil {
				log.WithFields(log.Fields{
					"torrent": torrent.Name,
				}).Warning("Error while getting media info for torrent: ", err)

				otherTorrents = append(otherTorrents, torrent)
				continue
			}

			if episodeInfo.Season != 0 && episodeInfo.Season == episode.Season && episodeInfo.Episode != 0 && episodeInfo.Episode == episode.Number {
				returnList = append(returnList, torrent)
			}
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return returnList
	}

	return append(returnList, otherTorrents...)
}

func FilterTorrentYear(list []Torrent, year int) []Torrent {
	log.WithFields(log.Fields{
		"strict_check": configuration.Config.System.StrictTorrentCheck,
	}).Debug("Checking torrent list for bad movie torrents (wrong year)")
	var returnList []Torrent
	var otherTorrents []Torrent

	for _, torrent := range list {
		movieInfo, err := vidocq.GetInfo(torrent.Name)
		if err != nil {
			log.WithFields(log.Fields{
				"torrent": torrent.Name,
			}).Warning("Error while getting media info for torrent: ", err)

			otherTorrents = append(otherTorrents, torrent)
			continue
		}

		if (movieInfo.Year != 0 && movieInfo.Year == year) || movieInfo.Year == 0 {
			returnList = append(returnList, torrent)
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return returnList
	}

	return append(returnList, otherTorrents...)
}

func FilterTorrentReleaseType(list []Torrent) []Torrent {
	log.WithFields(log.Fields{
		"excluded_release_types": configuration.Config.System.ExcludedReleaseTypes,
	}).Debug("Excluding release types from torrent list")

	var releaseFilteredList []Torrent
	var otherTorrents []Torrent
	var releaseTypeFilters []string

	releaseTypeFilters = strings.Split(configuration.Config.System.ExcludedReleaseTypes, ",")
	for i := range releaseTypeFilters {
		releaseTypeFilters[i] = strings.TrimSpace(releaseTypeFilters[i])
	}

	for _, torrent := range list {
		mediaInfo, err := vidocq.GetInfo(torrent.Name)
		if err != nil {
			log.Warning("An error occured during vidocq request: ", err.Error())
			otherTorrents = append(otherTorrents, torrent)

			continue
		}

		releaseTypeExcluded := false
		for _, excludedReleaseType := range releaseTypeFilters {
			if excludedReleaseType != "" && excludedReleaseType == mediaInfo.ReleaseType {
				releaseTypeExcluded = true
			}
		}

		if !releaseTypeExcluded {
			releaseFilteredList = append(releaseFilteredList, torrent)
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return releaseFilteredList
	}

	return append(releaseFilteredList, otherTorrents...)
}

func FilterTorrentQuality(list []Torrent) []Torrent {
	log.WithFields(log.Fields{
		"quality_filter": configuration.Config.System.PreferredMediaQuality,
		"strict_check":   configuration.Config.System.StrictTorrentCheck,
	}).Debug("Sorting list according to quality preferences")

	var qualityFilteredList []Torrent
	var otherTorrents []Torrent
	var qualityFilters []string

	qualityFilters = strings.Split(configuration.Config.System.PreferredMediaQuality, ",")
	for i := range qualityFilters {
		qualityFilters[i] = strings.TrimSpace(qualityFilters[i])
	}

	for _, torrent := range list {
		mediaInfo, err := vidocq.GetInfo(torrent.Name)
		if err != nil {
			log.Warning("An error occured during vidocq request: ", err.Error())
			otherTorrents = append(otherTorrents, torrent)

			continue
		}

		qualityMatches := false
		for _, quality := range qualityFilters {
			if quality == mediaInfo.Quality {
				qualityMatches = true
			}
		}

		if qualityMatches {
			qualityFilteredList = append(qualityFilteredList, torrent)
		} else {
			otherTorrents = append(otherTorrents, torrent)
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return qualityFilteredList
	}

	return append(qualityFilteredList, otherTorrents...)
}

// GetIndexer returns the registered indexer with name "name". An non-nil error is returned if no registered indexer are found with the required name
func GetIndexer(name string) (Indexer, error) {
	for _, ind := range indexersCollection {
		mod, _ := ind.Status()
		if mod.Name == name {
			return ind, nil
		}
	}

	return nil, fmt.Errorf("Indexer %s not found in configuration", name)
}
<commit_msg>Fixed wrong iteration over indexers in indexer status<commit_after>package indexer

import (
	"fmt"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/macarrie/flemzerd/downloadable"

	"github.com/macarrie/flemzerd/configuration"
	log "github.com/macarrie/flemzerd/logging"
	. "github.com/macarrie/flemzerd/objects"
	"github.com/macarrie/flemzerd/vidocq"

	"github.com/hashicorp/go-multierror"
)

var indexersCollection []Indexer

func AddIndexer(indexer Indexer) {
	indexersCollection = append(indexersCollection, indexer)
	log.WithFields(log.Fields{
		"indexer": indexer.GetName(),
	}).Debug("Indexer loaded")
}

func Status() ([]Module, error) {
	var modChan = make(chan Module, len(indexersCollection))
	var errorList *multierror.Error

	var wg sync.WaitGroup
	var errorListMutex sync.Mutex

	for i, _ := range indexersCollection {
		wg.Add(1)
		go func(indexer Indexer) {
			defer wg.Done()

			mod, indexerAliveError := indexer.Status()
			modChan <- mod
			if indexerAliveError != nil {
				log.WithFields(log.Fields{
					"error": indexerAliveError,
				}).Warning("Indexer is not alive")

				errorListMutex.Lock()
				errorList = multierror.Append(errorList, indexerAliveError)
				errorListMutex.Unlock()
			}
		}(indexersCollection[i])
	}

	wg.Wait()
	close(modChan)
	var modList []Module
	for mod := range modChan {
		modList = append(modList, mod)
	}

	return modList, errorList.ErrorOrNil()
}

func Reset() {
	indexersCollection = []Indexer{}
}

func GetTorrents(d downloadable.Downloadable) ([]Torrent, error) {
	var torrentList []Torrent
	var errorList *multierror.Error
	var totalError bool = true

	for _, indexer := range indexersCollection {
		indexerSearch, err := indexer.GetTorrents(d)
		if err != nil {
			d.GetLog().WithFields(log.Fields{
				"indexer": indexer.GetName(),
				"error":   err,
			}).Warning("Couldn't get torrents from indexer")
			errorList = multierror.Append(errorList, err)
			continue
		} else {
			totalError = false
		}

		if len(indexerSearch) != 0 {
			torrentList = append(torrentList, indexerSearch...)
			d.GetLog().WithFields(log.Fields{
				"indexer": indexer.GetName(),
				"nb":      len(indexerSearch),
			}).Info("Torrents found")
		} else {
			d.GetLog().WithFields(log.Fields{
				"indexer": indexer.GetName(),
			}).Info("No torrents found")
		}
	}

	sort.Slice(torrentList[:], func(i, j int) bool {
		return torrentList[i].Seeders > torrentList[j].Seeders
	})

	switch d.(type) {
	case *Movie:
		torrentList = FilterMovieTorrents(*d.(*Movie), torrentList)
	case *Episode:
		torrentList = FilterEpisodeTorrents(*d.(*Episode), torrentList)
	}

	if totalError {
		return torrentList, errorList.ErrorOrNil()
	}

	return torrentList, nil
}

func FilterEpisodeTorrents(episode Episode, torrentList []Torrent) []Torrent {
	torrentList = FilterTorrentEpisodeNumber(torrentList, episode)
	torrentList = FilterTorrentQuality(torrentList)
	torrentList = FilterTorrentReleaseType(torrentList)

	return torrentList
}

func FilterMovieTorrents(movie Movie, torrentList []Torrent) []Torrent {
	torrentList = FilterTorrentQuality(torrentList)
	if movie.Date.Year() != 1 {
		torrentList = FilterTorrentYear(torrentList, movie.Date.Year())
	}
	torrentList = FilterTorrentReleaseType(torrentList)

	return torrentList
}

func FilterTorrentEpisodeNumber(list []Torrent, episode Episode) []Torrent {
	log.WithFields(log.Fields{
		"strict_check": configuration.Config.System.StrictTorrentCheck,
	}).Debug("Checking torrent list for bad episodes")

	var returnList []Torrent
	var otherTorrents []Torrent

	for _, torrent := range list {
		if episode.TvShow.IsAnime {
			if episode.AbsoluteNumber != 0 {
				match, err := regexp.Match(fmt.Sprintf("%v", episode.AbsoluteNumber), []byte(torrent.Name))
				if match && err == nil {
					returnList = append(returnList, torrent)
				}
			} else {
				otherTorrents = append(otherTorrents, torrent)
			}
		} else {
			episodeInfo, err := vidocq.GetInfo(torrent.Name)
			if err != nil {
				log.WithFields(log.Fields{
					"torrent": torrent.Name,
				}).Warning("Error while getting media info for torrent: ", err)

				otherTorrents = append(otherTorrents, torrent)
				continue
			}

			if episodeInfo.Season != 0 && episodeInfo.Season == episode.Season && episodeInfo.Episode != 0 && episodeInfo.Episode == episode.Number {
				returnList = append(returnList, torrent)
			}
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return returnList
	}

	return append(returnList, otherTorrents...)
}

func FilterTorrentYear(list []Torrent, year int) []Torrent {
	log.WithFields(log.Fields{
		"strict_check": configuration.Config.System.StrictTorrentCheck,
	}).Debug("Checking torrent list for bad movie torrents (wrong year)")
	var returnList []Torrent
	var otherTorrents []Torrent

	for _, torrent := range list {
		movieInfo, err := vidocq.GetInfo(torrent.Name)
		if err != nil {
			log.WithFields(log.Fields{
				"torrent": torrent.Name,
			}).Warning("Error while getting media info for torrent: ", err)

			otherTorrents = append(otherTorrents, torrent)
			continue
		}

		if (movieInfo.Year != 0 && movieInfo.Year == year) || movieInfo.Year == 0 {
			returnList = append(returnList, torrent)
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return returnList
	}

	return append(returnList, otherTorrents...)
}

func FilterTorrentReleaseType(list []Torrent) []Torrent {
	log.WithFields(log.Fields{
		"excluded_release_types": configuration.Config.System.ExcludedReleaseTypes,
	}).Debug("Excluding release types from torrent list")

	var releaseFilteredList []Torrent
	var otherTorrents []Torrent
	var releaseTypeFilters []string

	releaseTypeFilters = strings.Split(configuration.Config.System.ExcludedReleaseTypes, ",")
	for i := range releaseTypeFilters {
		releaseTypeFilters[i] = strings.TrimSpace(releaseTypeFilters[i])
	}

	for _, torrent := range list {
		mediaInfo, err := vidocq.GetInfo(torrent.Name)
		if err != nil {
			log.Warning("An error occured during vidocq request: ", err.Error())
			otherTorrents = append(otherTorrents, torrent)

			continue
		}

		releaseTypeExcluded := false
		for _, excludedReleaseType := range releaseTypeFilters {
			if excludedReleaseType != "" && excludedReleaseType == mediaInfo.ReleaseType {
				releaseTypeExcluded = true
			}
		}

		if !releaseTypeExcluded {
			releaseFilteredList = append(releaseFilteredList, torrent)
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return releaseFilteredList
	}

	return append(releaseFilteredList, otherTorrents...)
}

func FilterTorrentQuality(list []Torrent) []Torrent {
	log.WithFields(log.Fields{
		"quality_filter": configuration.Config.System.PreferredMediaQuality,
		"strict_check":   configuration.Config.System.StrictTorrentCheck,
	}).Debug("Sorting list according to quality preferences")

	var qualityFilteredList []Torrent
	var otherTorrents []Torrent
	var qualityFilters []string

	qualityFilters = strings.Split(configuration.Config.System.PreferredMediaQuality, ",")
	for i := range qualityFilters {
		qualityFilters[i] = strings.TrimSpace(qualityFilters[i])
	}

	for _, torrent := range list {
		mediaInfo, err := vidocq.GetInfo(torrent.Name)
		if err != nil {
			log.Warning("An error occured during vidocq request: ", err.Error())
			otherTorrents = append(otherTorrents, torrent)

			continue
		}

		qualityMatches := false
		for _, quality := range qualityFilters {
			if quality == mediaInfo.Quality {
				qualityMatches = true
			}
		}

		if qualityMatches {
			qualityFilteredList = append(qualityFilteredList, torrent)
		} else {
			otherTorrents = append(otherTorrents, torrent)
		}
	}

	if configuration.Config.System.StrictTorrentCheck {
		return qualityFilteredList
	}

	return append(qualityFilteredList, otherTorrents...)
}

// GetIndexer returns the registered indexer with name "name". An non-nil error is returned if no registered indexer are found with the required name
func GetIndexer(name string) (Indexer, error) {
	for _, ind := range indexersCollection {
		mod, _ := ind.Status()
		if mod.Name == name {
			return ind, nil
		}
	}

	return nil, fmt.Errorf("Indexer %s not found in configuration", name)
}
<|endoftext|>


<commit_before>// Copyright 2013 The go-instagram 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 instagram provides a client for using the Instagram API.

Access different parts of the Instagram API using the various services on a Instagram
Client (second parameter is access token that likely you'll need to access most of
Instagram endpoints):

	client := instagram.NewClient(nil)

You can then optionally set ClientID, ClientSecret and AccessToken:

	client.ClientID = "8f2c0ad697ea4094beb2b1753b7cde9c"

With client object set, you can call Instagram endpoints:

	// Gets the most recent media published by a user with id "3"
	media, next, err := client.Users.RecentMedia("3", nil)

Set optional parameters for an API method by passing an Parameters object.

	// Gets user's feed.
	opt := &instagram.Parameters{Count: 3}
	media, next, err := client.Users.RecentMedia("3", opt)

The full Instagram API is documented at http://instagram.com/developer/endpoints/.
*/
package instagram

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

const (
	// LibraryVersion represents this library version
	LibraryVersion = "0.5"

	// BaseURL represents Instagram API base URL
	BaseURL = "https://api.instagram.com/v1/"

	// UserAgent represents this client User-Agent
	UserAgent = "github.com/carbocation/go-instagram v" + LibraryVersion
)

// A Client manages communication with the Instagram API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.
	BaseURL *url.URL

	// UserAgent agent used when communicating with Instagram API.
	UserAgent string

	// Application client_id
	ClientID string

	// Application client_secret
	ClientSecret string

	// Authenticated user's access_token
	AccessToken string

	// For Authenticated endpoints, using X-Forwarded-For
	// increases events per hour permitted by Instagram
	// This value should, if not nil, be the value of
	// a user's IP address. See
	// http://instagram.com/developer/restrict-api-requests/
	// for additional detail
	XInstaForwardedFor string

	// Services used for talking to different parts of the API.
	Users         *UsersService
	Relationships *RelationshipsService
	Media         *MediaService
	Comments      *CommentsService
	Likes         *LikesService
	Tags          *TagsService
	Locations     *LocationsService
	Geographies   *GeographiesService
	Realtime      *RealtimeService

	// Temporary Response
	Response *Response
}

// Parameters specifies the optional parameters to various service's methods.
type Parameters struct {
	Count        uint64
	Coursor      uint64
	MinID        string
	MaxID        string
	MinTimestamp int64
	MaxTimestamp int64
	Lat          float64
	Lng          float64
	Distance     float64
}

// Ratelimit specifies API calls limit found in HTTP headers.
type Ratelimit struct {
	// Total number of possible calls per hour
	Limit int

	// How many calls are left for this particular token or client ID
	Remaining int
}

// Response specifies Instagram's response structure.
//
// Instagram's envelope structure spec: http://instagram.com/developer/endpoints/#structure
type Response struct {
	Response   *http.Response      // HTTP response
	Meta       *ResponseMeta       `json:"meta,omitempty"`
	Data       interface{}         `json:"data,omitempty"`
	Pagination *ResponsePagination `json:"pagination,omitempty"`
}

// GetMeta gets extra information about the response. If all goes well,
// only Code key with value 200 is returned. If something goes wrong,
// ErrorType and ErrorMessage keys are present.
func (r *Response) GetMeta() *ResponseMeta {
	return r.Meta
}

// GetData gets the meat of the response.
func (r *Response) GetData() interface{} {
	return &r.Data
}

// GetError gets error from meta's response.
func (r *Response) GetError() error {
	if r.Meta.ErrorType != "" || r.Meta.ErrorMessage != "" {
		return fmt.Errorf(fmt.Sprintf("%s: %s", r.Meta.ErrorType, r.Meta.ErrorMessage))
	}
	return nil
}

// GetPagination gets pagination information.
func (r *Response) GetPagination() *ResponsePagination {
	return r.Pagination
}

// GetRatelimit returns parsed rate limit information from response headers.
func (r *Response) GetRatelimit() (Ratelimit, error) {
	var rl Ratelimit
	var err error
	const (
		Limit     = `X-Ratelimit-Limit`
		Remaining = `X-Ratelimit-Remaining`
	)

	rl.Limit, err = strconv.Atoi(r.Response.Header.Get(Limit))
	if err != nil {
		return rl, err
	}

	rl.Remaining, err = strconv.Atoi(r.Response.Header.Get(Remaining))
	return rl, err
}

// NextURL gets next url which represents URL for next set of data.
func (r *Response) NextURL() string {
	p := r.GetPagination()
	return p.NextURL
}

// NextMaxID gets MaxID parameter that can be passed for next request.
func (r *Response) NextMaxID() string {
	p := r.GetPagination()
	return p.NextMaxID
}

// ResponseMeta represents information about the response. If all goes well,
// only a Code key with value 200 will present. However, sometimes things
// go wrong, and in that case ErrorType and ErrorMessage are present.
type ResponseMeta struct {
	ErrorType    string `json:"error_type,omitempty"`
	Code         int    `json:"code,omitempty"`
	ErrorMessage string `json:"error_message,omitempty"`
}

// ResponsePagination represents information to get access to more data in
// any request for sequential data.
type ResponsePagination struct {
	NextURL   string `json:"next_url,omitempty"`
	NextMaxID string `json:"next_max_id,omitempty"`
}

// NewClient returns a new Instagram API client. if a nil httpClient is
// provided, http.DefaultClient will be used.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(BaseURL)

	c := &Client{
		client:    httpClient,
		BaseURL:   baseURL,
		UserAgent: UserAgent,
	}
	c.Users = &UsersService{client: c}
	c.Relationships = &RelationshipsService{client: c}
	c.Media = &MediaService{client: c}
	c.Comments = &CommentsService{client: c}
	c.Likes = &LikesService{client: c}
	c.Tags = &TagsService{client: c}
	c.Locations = &LocationsService{client: c}
	c.Geographies = &GeographiesService{client: c}
	c.Realtime = &RealtimeService{client: c}

	return c
}

// ComputeXInstaForwardedFor returns value for X-Insta-Forwarded-For header
func (c *Client) ComputeXInstaForwardedFor() string {
	if c.XInstaForwardedFor == "" {
		return ""
	}

	mac := hmac.New(sha256.New, []byte(c.ClientSecret))
	mac.Write([]byte(c.XInstaForwardedFor))

	return fmt.Sprintf("%s|%s", c.XInstaForwardedFor, hex.EncodeToString(mac.Sum(nil)))
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash. If
// specified
func (c *Client) NewRequest(method, urlStr string, body string) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)
	q := u.Query()
	if c.AccessToken != "" && q.Get("access_token") == "" {
		q.Set("access_token", c.AccessToken)
	}
	if c.ClientID != "" && q.Get("client_id") == "" {
		q.Set("client_id", c.ClientID)
	}
	if c.ClientSecret != "" && q.Get("client_secret") == "" {
		q.Set("client_secret", c.ClientSecret)
	}
	u.RawQuery = q.Encode()

	req, err := http.NewRequest(method, u.String(), bytes.NewBufferString(body))
	if err != nil {
		return nil, err
	}

	if method == "POST" {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	}

	if c.XInstaForwardedFor != "" {
		req.Header.Add("X-Insta-Forwarded-For", c.ComputeXInstaForwardedFor())
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// Do sends an API request and returns the API response. The API response is
// decoded and stored in the value pointed to by v, or returned as an error if
// an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	r := &Response{Response: resp}
	if v != nil {
		r.Data = v
		err = json.NewDecoder(resp.Body).Decode(r)
		c.Response = r
	}
	return resp, err
}

// Error represents an error recieved from instagram
type Error ResponseMeta

// Error makes the Error suitable for the error interface
func (err *Error) Error() string {
	return fmt.Sprintf("%s (%d): %s", err.ErrorType, err.Code, err.ErrorMessage)
}

// ErrorResponse represents a Response which contains an error
type ErrorResponse Response

func (r *ErrorResponse) Error() string {
	if r == nil {
		return fmt.Sprintf("A nil error response was returned")
	}

	if r.Response == nil || r.Response.Request == nil {
		return fmt.Sprintf("A nil error response was returned on %v", r)
	}

	if r.Response.Request.URL == nil {
		return fmt.Sprintf("A nil error response was returned on %v", r.Response.Request)
	}

	if r.Meta == nil {
		return fmt.Sprintf("%v %v: %d (no metadata)", r.Response.Request.Method, r.Response.Request.URL,
			r.Response.StatusCode)
	}

	return fmt.Sprintf("%v %v: %d %v %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Meta.ErrorType, r.Meta.ErrorMessage)
}

// CheckResponse checks the API response for error, and returns it
// if present. A response is considered an error if it has non StatusOK
// code.
func CheckResponse(r *http.Response) error {
	if r.StatusCode == http.StatusOK {
		return nil
	}

	data, readErr := ioutil.ReadAll(r.Body)
	if readErr != nil {
		return readErr
	}

	// Forbidden: see http://instagram.com/developer/restrict-api-requests/
	if r.StatusCode == http.StatusForbidden {
		err := &Error{}
		json.Unmarshal(data, &err)
		return err
	}

	// RateLimit: see http://instagram.com/developer/limits/
	if r.StatusCode == 429 {
		err := &Error{}
		json.Unmarshal(data, &err)
		return err
	}

	// Sometimes Instagram returns 500 with plain message
	// "Oops, an error occurred.".
	if r.StatusCode == http.StatusInternalServerError {
		err := &Error{
			ErrorType:    "Internal Server Error",
			Code:         http.StatusInternalServerError,
			ErrorMessage: "Oops, an error occurred.",
		}
		return err
	}

	if data != nil {
		// Unlike for successful (2XX) requests, unsuccessful
		// requests SOMETIMES have the {Meta: Error{}} format but
		// SOMETIMES they are just Error{}. From what I can tell, there is not
		// an obvious rationale behind what gets constructed in which way, so
		// we need to try both:
		err := &Error{}
		json.Unmarshal(data, err)
		if *err == *new(Error) {
			// Unmarshaling did nothing for us, so the format was not Error{}.
			// We will assume the format was {Meta: Error{}}:
			temp := make(map[string]Error)
			json.Unmarshal(data, &temp)

			meta := temp["meta"]

			delete(temp, "meta") // Probably uselesss
			return &meta
		}

		// Unmarshaling did something
		return err
	}

	return nil
}
<commit_msg>Fixing typo on Parameters, should be Cursor<commit_after>// Copyright 2013 The go-instagram 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 instagram provides a client for using the Instagram API.

Access different parts of the Instagram API using the various services on a Instagram
Client (second parameter is access token that likely you'll need to access most of
Instagram endpoints):

	client := instagram.NewClient(nil)

You can then optionally set ClientID, ClientSecret and AccessToken:

	client.ClientID = "8f2c0ad697ea4094beb2b1753b7cde9c"

With client object set, you can call Instagram endpoints:

	// Gets the most recent media published by a user with id "3"
	media, next, err := client.Users.RecentMedia("3", nil)

Set optional parameters for an API method by passing an Parameters object.

	// Gets user's feed.
	opt := &instagram.Parameters{Count: 3}
	media, next, err := client.Users.RecentMedia("3", opt)

The full Instagram API is documented at http://instagram.com/developer/endpoints/.
*/
package instagram

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

const (
	// LibraryVersion represents this library version
	LibraryVersion = "0.5"

	// BaseURL represents Instagram API base URL
	BaseURL = "https://api.instagram.com/v1/"

	// UserAgent represents this client User-Agent
	UserAgent = "github.com/carbocation/go-instagram v" + LibraryVersion
)

// A Client manages communication with the Instagram API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.
	BaseURL *url.URL

	// UserAgent agent used when communicating with Instagram API.
	UserAgent string

	// Application client_id
	ClientID string

	// Application client_secret
	ClientSecret string

	// Authenticated user's access_token
	AccessToken string

	// For Authenticated endpoints, using X-Forwarded-For
	// increases events per hour permitted by Instagram
	// This value should, if not nil, be the value of
	// a user's IP address. See
	// http://instagram.com/developer/restrict-api-requests/
	// for additional detail
	XInstaForwardedFor string

	// Services used for talking to different parts of the API.
	Users         *UsersService
	Relationships *RelationshipsService
	Media         *MediaService
	Comments      *CommentsService
	Likes         *LikesService
	Tags          *TagsService
	Locations     *LocationsService
	Geographies   *GeographiesService
	Realtime      *RealtimeService

	// Temporary Response
	Response *Response
}

// Parameters specifies the optional parameters to various service's methods.
type Parameters struct {
	Count        uint64
	Cursor       uint64
	MinID        string
	MaxID        string
	MinTimestamp int64
	MaxTimestamp int64
	Lat          float64
	Lng          float64
	Distance     float64
}

// Ratelimit specifies API calls limit found in HTTP headers.
type Ratelimit struct {
	// Total number of possible calls per hour
	Limit int

	// How many calls are left for this particular token or client ID
	Remaining int
}

// Response specifies Instagram's response structure.
//
// Instagram's envelope structure spec: http://instagram.com/developer/endpoints/#structure
type Response struct {
	Response   *http.Response      // HTTP response
	Meta       *ResponseMeta       `json:"meta,omitempty"`
	Data       interface{}         `json:"data,omitempty"`
	Pagination *ResponsePagination `json:"pagination,omitempty"`
}

// GetMeta gets extra information about the response. If all goes well,
// only Code key with value 200 is returned. If something goes wrong,
// ErrorType and ErrorMessage keys are present.
func (r *Response) GetMeta() *ResponseMeta {
	return r.Meta
}

// GetData gets the meat of the response.
func (r *Response) GetData() interface{} {
	return &r.Data
}

// GetError gets error from meta's response.
func (r *Response) GetError() error {
	if r.Meta.ErrorType != "" || r.Meta.ErrorMessage != "" {
		return fmt.Errorf(fmt.Sprintf("%s: %s", r.Meta.ErrorType, r.Meta.ErrorMessage))
	}
	return nil
}

// GetPagination gets pagination information.
func (r *Response) GetPagination() *ResponsePagination {
	return r.Pagination
}

// GetRatelimit returns parsed rate limit information from response headers.
func (r *Response) GetRatelimit() (Ratelimit, error) {
	var rl Ratelimit
	var err error
	const (
		Limit     = `X-Ratelimit-Limit`
		Remaining = `X-Ratelimit-Remaining`
	)

	rl.Limit, err = strconv.Atoi(r.Response.Header.Get(Limit))
	if err != nil {
		return rl, err
	}

	rl.Remaining, err = strconv.Atoi(r.Response.Header.Get(Remaining))
	return rl, err
}

// NextURL gets next url which represents URL for next set of data.
func (r *Response) NextURL() string {
	p := r.GetPagination()
	return p.NextURL
}

// NextMaxID gets MaxID parameter that can be passed for next request.
func (r *Response) NextMaxID() string {
	p := r.GetPagination()
	return p.NextMaxID
}

// ResponseMeta represents information about the response. If all goes well,
// only a Code key with value 200 will present. However, sometimes things
// go wrong, and in that case ErrorType and ErrorMessage are present.
type ResponseMeta struct {
	ErrorType    string `json:"error_type,omitempty"`
	Code         int    `json:"code,omitempty"`
	ErrorMessage string `json:"error_message,omitempty"`
}

// ResponsePagination represents information to get access to more data in
// any request for sequential data.
type ResponsePagination struct {
	NextURL   string `json:"next_url,omitempty"`
	NextMaxID string `json:"next_max_id,omitempty"`
}

// NewClient returns a new Instagram API client. if a nil httpClient is
// provided, http.DefaultClient will be used.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(BaseURL)

	c := &Client{
		client:    httpClient,
		BaseURL:   baseURL,
		UserAgent: UserAgent,
	}
	c.Users = &UsersService{client: c}
	c.Relationships = &RelationshipsService{client: c}
	c.Media = &MediaService{client: c}
	c.Comments = &CommentsService{client: c}
	c.Likes = &LikesService{client: c}
	c.Tags = &TagsService{client: c}
	c.Locations = &LocationsService{client: c}
	c.Geographies = &GeographiesService{client: c}
	c.Realtime = &RealtimeService{client: c}

	return c
}

// ComputeXInstaForwardedFor returns value for X-Insta-Forwarded-For header
func (c *Client) ComputeXInstaForwardedFor() string {
	if c.XInstaForwardedFor == "" {
		return ""
	}

	mac := hmac.New(sha256.New, []byte(c.ClientSecret))
	mac.Write([]byte(c.XInstaForwardedFor))

	return fmt.Sprintf("%s|%s", c.XInstaForwardedFor, hex.EncodeToString(mac.Sum(nil)))
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash. If
// specified
func (c *Client) NewRequest(method, urlStr string, body string) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)
	q := u.Query()
	if c.AccessToken != "" && q.Get("access_token") == "" {
		q.Set("access_token", c.AccessToken)
	}
	if c.ClientID != "" && q.Get("client_id") == "" {
		q.Set("client_id", c.ClientID)
	}
	if c.ClientSecret != "" && q.Get("client_secret") == "" {
		q.Set("client_secret", c.ClientSecret)
	}
	u.RawQuery = q.Encode()

	req, err := http.NewRequest(method, u.String(), bytes.NewBufferString(body))
	if err != nil {
		return nil, err
	}

	if method == "POST" {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	}

	if c.XInstaForwardedFor != "" {
		req.Header.Add("X-Insta-Forwarded-For", c.ComputeXInstaForwardedFor())
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// Do sends an API request and returns the API response. The API response is
// decoded and stored in the value pointed to by v, or returned as an error if
// an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	r := &Response{Response: resp}
	if v != nil {
		r.Data = v
		err = json.NewDecoder(resp.Body).Decode(r)
		c.Response = r
	}
	return resp, err
}

// Error represents an error recieved from instagram
type Error ResponseMeta

// Error makes the Error suitable for the error interface
func (err *Error) Error() string {
	return fmt.Sprintf("%s (%d): %s", err.ErrorType, err.Code, err.ErrorMessage)
}

// ErrorResponse represents a Response which contains an error
type ErrorResponse Response

func (r *ErrorResponse) Error() string {
	if r == nil {
		return fmt.Sprintf("A nil error response was returned")
	}

	if r.Response == nil || r.Response.Request == nil {
		return fmt.Sprintf("A nil error response was returned on %v", r)
	}

	if r.Response.Request.URL == nil {
		return fmt.Sprintf("A nil error response was returned on %v", r.Response.Request)
	}

	if r.Meta == nil {
		return fmt.Sprintf("%v %v: %d (no metadata)", r.Response.Request.Method, r.Response.Request.URL,
			r.Response.StatusCode)
	}

	return fmt.Sprintf("%v %v: %d %v %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Meta.ErrorType, r.Meta.ErrorMessage)
}

// CheckResponse checks the API response for error, and returns it
// if present. A response is considered an error if it has non StatusOK
// code.
func CheckResponse(r *http.Response) error {
	if r.StatusCode == http.StatusOK {
		return nil
	}

	data, readErr := ioutil.ReadAll(r.Body)
	if readErr != nil {
		return readErr
	}

	// Forbidden: see http://instagram.com/developer/restrict-api-requests/
	if r.StatusCode == http.StatusForbidden {
		err := &Error{}
		json.Unmarshal(data, &err)
		return err
	}

	// RateLimit: see http://instagram.com/developer/limits/
	if r.StatusCode == 429 {
		err := &Error{}
		json.Unmarshal(data, &err)
		return err
	}

	// Sometimes Instagram returns 500 with plain message
	// "Oops, an error occurred.".
	if r.StatusCode == http.StatusInternalServerError {
		err := &Error{
			ErrorType:    "Internal Server Error",
			Code:         http.StatusInternalServerError,
			ErrorMessage: "Oops, an error occurred.",
		}
		return err
	}

	if data != nil {
		// Unlike for successful (2XX) requests, unsuccessful
		// requests SOMETIMES have the {Meta: Error{}} format but
		// SOMETIMES they are just Error{}. From what I can tell, there is not
		// an obvious rationale behind what gets constructed in which way, so
		// we need to try both:
		err := &Error{}
		json.Unmarshal(data, err)
		if *err == *new(Error) {
			// Unmarshaling did nothing for us, so the format was not Error{}.
			// We will assume the format was {Meta: Error{}}:
			temp := make(map[string]Error)
			json.Unmarshal(data, &temp)

			meta := temp["meta"]

			delete(temp, "meta") // Probably uselesss
			return &meta
		}

		// Unmarshaling did something
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"log"
	"runtime"
	"strings"
)

func IdentifyPanic() string {
	var name, file string
	var line int
	var pc [16]uintptr

	n := runtime.Callers(3, pc[:])
	for _, pc := range pc[:n] {
		log.Printf("%d", pc)
		fn := runtime.FuncForPC(pc)
		if fn == nil {
			continue
		}
		file, line = fn.FileLine(pc)
		name = fn.Name()
		if !strings.HasPrefix(name, "runtime.") {
			break
		}
	}

	switch {
	case name != "":
		return fmt.Sprintf("%v:%v", name, line)
	case file != "":
		return fmt.Sprintf("%v:%v", file, line)
	}

	return fmt.Sprintf("pc:%x", pc)
}
<commit_msg>remove log of PC<commit_after>package core

import (
	"fmt"
	"log"
	"runtime"
	"strings"
)

func IdentifyPanic() string {
	var name, file string
	var line int
	var pc [16]uintptr

	n := runtime.Callers(3, pc[:])
	for _, pc := range pc[:n] {
		fn := runtime.FuncForPC(pc)
		if fn == nil {
			continue
		}
		file, line = fn.FileLine(pc)
		name = fn.Name()
		if !strings.HasPrefix(name, "runtime.") {
			break
		}
	}

	switch {
	case name != "":
		return fmt.Sprintf("%v:%v", name, line)
	case file != "":
		return fmt.Sprintf("%v:%v", file, line)
	}

	return fmt.Sprintf("pc:%x", pc)
}
<|endoftext|>


<commit_before>/* For license and copyright information please see LEGAL file in repository */

package captcha

import (
	"bytes"
	"container/list"
	"image"
	"image/draw"
	"image/jpeg"
	"image/png"
	"math/rand"
	"strconv"
	"unsafe"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font/gofont/gobolditalic"

	"time"

	"../uuid"
)

/*
Usage:
var phraseCaptchas = captcha.NewDefaultPhraseCaptchas()
var pc *captcha.PhraseCaptcha = phraseCaptchas.NewImage(req.Language, req.ImageFormat)

*/

// PhraseCaptchas store
type PhraseCaptchas struct {
	Len        uint8       // Number of captcha solution. can't be more than 16!
	Difficulty uint8       // 0:very-easy, 1:easy, 2:medium, 3:hard, 4:very-hard, 5:extreme-hard
	Type       uint8       // 0:Number(625896), 1:Word(A19Cat), 2:Math(+ - * /),
	Duration   int64       // The number of seconds indicate expiration time of captchas
	ImageSize  image.Point // Standard width & height of a captcha image.
	Pool       map[[16]byte]*PhraseCaptcha
	idByTime   *list.List
}

// PhraseCaptcha store
type PhraseCaptcha struct {
	ID       [16]byte
	Answer   string
	ExpireIn int64
	State    State
	Image    []byte // In requested lang & format
	Audio    []byte // In requested lang & format
}

// NewDefaultPhraseCaptchas use to make new captchas with defaults values!
func NewDefaultPhraseCaptchas() (pcs *PhraseCaptchas) {
	pcs = &PhraseCaptchas{
		Len:        6,
		Difficulty: 2,
		Type:       0,
		Duration:   2 * 60, // 2 Minute
		ImageSize:  image.Point{128, 64},
		Pool:       make(map[[16]byte]*PhraseCaptcha, 1024),
		idByTime:   list.New(),
	}
	// cleaner for expired captchas!
	go pcs.expirationProcessing()
	return
}

// NewImage make, store and return new captcha!
func (pcs *PhraseCaptchas) NewImage(lang Language, imageformat ImageFormat) (pc *PhraseCaptcha) {
	pc = &PhraseCaptcha{
		ID:       uuid.NewV4(),
		ExpireIn: time.Now().Unix() + pcs.Duration,
		State:    StateCreated,
	}
	switch pcs.Type {
	case 0:
		pc.Answer = pcs.randomDigits()
	case 1:
		pc.Answer = pcs.randomWord(lang)
	case 2:
		pc.Answer = pcs.randomMath()
	}
	pc.Image = pcs.createImage(pc.Answer, imageformat)

	pcs.Pool[pc.ID] = pc
	return
}

// GetAudio return exiting captcha with audio generated if exits otherwise returns nil!
func (pcs *PhraseCaptchas) GetAudio(captchaID [16]byte, lang Language, audioFormat AudioFormat) (pc *PhraseCaptcha) {
	pc = pcs.Pool[captchaID]
	if pc == nil {
		return nil
	}
	pc.Audio = pcs.createAudio(pc.Answer, audioFormat)
	return
}

// Get return exiting captcha if exits otherwise returns nil!
func (pcs *PhraseCaptchas) Get(captchaID [16]byte) (pc *PhraseCaptcha) {
	pc = pcs.Pool[captchaID]
	if pc.ExpireIn < time.Now().Unix() {
		delete(pcs.Pool, captchaID)
		return nil
	}
	return
}

// Solve check answer and return captcha state!
func (pcs *PhraseCaptchas) Solve(captchaID [16]byte, answer string) State {
	var c *PhraseCaptcha
	c = pcs.Pool[captchaID]
	if c == nil {
		return StateNotFound
	}
	if c.ExpireIn < time.Now().Unix() {
		delete(pcs.Pool, captchaID)
		return StateExpired
	}
	if c.Answer != answer {
		c.State = StateLastAnswerNotValid
		return StateLastAnswerNotValid
	}
	// Give more time to user to complete any proccess need captcha!
	c.ExpireIn += pcs.Duration
	c.State = StateSolved
	return StateSolved
}

func (pcs *PhraseCaptchas) randomDigits() string {
	var low, hi int64
	switch pcs.Len {
	case 6:
		low, hi = 100000, 999999
	case 7:
		low, hi = 1000000, 9999999
	case 8:
		low, hi = 10000000, 99999999
	case 9:
		low, hi = 100000000, 999999999
	case 10:
		low, hi = 1000000000, 9999999999
	default:
		low, hi = 1000000000, 9999999999
	}
	var rand = low + rand.Int63n(hi-low)
	return strconv.FormatInt(rand, 10)
}

var src = rand.NewSource(time.Now().UnixNano())

const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
)
const englishLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-"

func (pcs *PhraseCaptchas) randomWord(lang Language) string {
	var b = make([]byte, pcs.Len)
	var i uint8
	for i = 0; i < pcs.Len; i++ {
		var random = src.Int63()
		if idx := int(random & letterIdxMask); idx < len(englishLetters) {
			b[i] = englishLetters[idx]
		}
		random >>= letterIdxBits
	}
	return *(*string)(unsafe.Pointer(&b))
}

func (pcs *PhraseCaptchas) randomMath() string {
	// TODO:::
	return ""
}

var goBoldItalic *truetype.Font

func init() {
	var err error
	goBoldItalic, err = freetype.ParseFont(gobolditalic.TTF)
	if err != nil {
		// Almost never occur!
		panic(err)
	}
}

func (pcs *PhraseCaptchas) createImage(answer string, imageFormat ImageFormat) []byte {
	var img = image.NewRGBA(image.Rect(0, 0, pcs.ImageSize.X, pcs.ImageSize.Y))
	draw.Draw(img, img.Bounds(), image.White, image.ZP, draw.Src)

	// TODO::: Difficulty??!!
	var c = freetype.NewContext()
	var point = freetype.Pt(10, 10+int(c.PointToFixed(24)>>6))
	c.SetDst(img)
	c.SetSrc(image.Black) //(image.NewUniform(color.RGBA{200, 100, 0, 255}))
	c.SetFont(goBoldItalic)
	c.SetFontSize(24)
	c.SetDPI(72)
	c.SetClip(img.Bounds())
	c.DrawString(answer, point)

	var buf bytes.Buffer
	switch imageFormat {
	case ImageFormatPNG:
		png.Encode(&buf, img)
	case ImageFormatJPEG:
		jpeg.Encode(&buf, img, &jpeg.Options{Quality: jpeg.DefaultQuality})
	}
	return buf.Bytes()
}

func (pcs *PhraseCaptchas) createAudio(answer string, audioFormat AudioFormat) []byte {
	return []byte{}
}

func (pcs *PhraseCaptchas) expirationProcessing() {
	var timer = time.NewTimer(time.Duration(pcs.Duration) * time.Second)
	for {
		select {
		// case shutdownFeedback := <-pcs.shutdownSignal:
		// 	timer.Stop()
		// 	shutdownFeedback <- struct{}{}
		// 	return
		case <-timer.C:
			timer.Reset(time.Duration(pcs.Duration) * time.Second)

			if len(pcs.Pool) == 0 {
				continue
			}

			for _, captcha := range pcs.Pool {
				if captcha.ExpireIn < time.Now().Unix() {
					delete(pcs.Pool, captcha.ID)
				}
			}
		}
	}
}

// https://github.com/search?l=Go&q=captcha&type=Repositories
// https://github.com/dchest/captcha
// https://github.com/afocus/captcha
// https://github.com/steambap/captcha
// https://github.com/lifei6671/gocaptcha
// https://www.hcaptcha.com/
<commit_msg>A minor performance improvment and fix a panic bug in captcha<commit_after>/* For license and copyright information please see LEGAL file in repository */

package captcha

import (
	"bytes"
	"container/list"
	"image"
	"image/draw"
	"image/jpeg"
	"image/png"
	"math/rand"
	"strconv"
	"unsafe"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font/gofont/gobolditalic"

	"time"

	"../uuid"
)

/*
Usage:
var phraseCaptchas = captcha.NewDefaultPhraseCaptchas()
var pc *captcha.PhraseCaptcha = phraseCaptchas.NewImage(req.Language, req.ImageFormat)

*/

// PhraseCaptchas store
type PhraseCaptchas struct {
	Len        uint8       // Number of captcha solution. can't be more than 16!
	Difficulty uint8       // 0:very-easy, 1:easy, 2:medium, 3:hard, 4:very-hard, 5:extreme-hard
	Type       uint8       // 0:Number(625896), 1:Word(A19Cat), 2:Math(+ - * /),
	Duration   int64       // The number of seconds indicate expiration time of captchas
	ImageSize  image.Point // Standard width & height of a captcha image.
	Pool       map[[16]byte]*PhraseCaptcha
	idByTime   *list.List
}

// PhraseCaptcha store
type PhraseCaptcha struct {
	ID       [16]byte
	Answer   string
	ExpireIn int64
	State    State
	Image    []byte // In requested lang & format
	Audio    []byte // In requested lang & format
}

// NewDefaultPhraseCaptchas use to make new captchas with defaults values!
func NewDefaultPhraseCaptchas() (pcs *PhraseCaptchas) {
	pcs = &PhraseCaptchas{
		Len:        6,
		Difficulty: 2,
		Type:       0,
		Duration:   2 * 60, // 2 Minute
		ImageSize:  image.Point{128, 64},
		Pool:       make(map[[16]byte]*PhraseCaptcha, 1024),
		idByTime:   list.New(),
	}
	// cleaner for expired captchas!
	go pcs.expirationProcessing()
	return
}

// NewImage make, store and return new captcha!
func (pcs *PhraseCaptchas) NewImage(lang Language, imageformat ImageFormat) (pc *PhraseCaptcha) {
	pc = &PhraseCaptcha{
		ID:       uuid.NewV4(),
		ExpireIn: time.Now().Unix() + pcs.Duration,
		State:    StateCreated,
	}
	switch pcs.Type {
	case 0:
		pc.Answer = pcs.randomDigits()
	case 1:
		pc.Answer = pcs.randomWord(lang)
	case 2:
		pc.Answer = pcs.randomMath()
	}
	pc.Image = pcs.createImage(pc.Answer, imageformat)

	pcs.Pool[pc.ID] = pc
	return
}

// GetAudio return exiting captcha with audio generated if exits otherwise returns nil!
func (pcs *PhraseCaptchas) GetAudio(captchaID [16]byte, lang Language, audioFormat AudioFormat) (pc *PhraseCaptcha) {
	pc = pcs.Pool[captchaID]
	if pc == nil {
		return nil
	}
	pc.Audio = pcs.createAudio(pc.Answer, audioFormat)
	return
}

// Get return exiting captcha if exits otherwise returns nil!
func (pcs *PhraseCaptchas) Get(captchaID [16]byte) (pc *PhraseCaptcha) {
	pc = pcs.Pool[captchaID]
	if pc != nil && pc.ExpireIn < time.Now().Unix() {
		delete(pcs.Pool, captchaID)
		return nil
	}
	return
}

// Solve check answer and return captcha state!
func (pcs *PhraseCaptchas) Solve(captchaID [16]byte, answer string) State {
	var c *PhraseCaptcha
	c = pcs.Pool[captchaID]
	if c == nil {
		return StateNotFound
	}
	if c.ExpireIn < time.Now().Unix() {
		delete(pcs.Pool, captchaID)
		return StateExpired
	}
	if c.Answer != answer {
		c.State = StateLastAnswerNotValid
		return StateLastAnswerNotValid
	}
	// Give more time to user to complete any proccess need captcha!
	c.ExpireIn += pcs.Duration
	c.State = StateSolved
	return StateSolved
}

func (pcs *PhraseCaptchas) randomDigits() string {
	var low, hi int64
	switch pcs.Len {
	case 6:
		low, hi = 100000, 999999
	case 7:
		low, hi = 1000000, 9999999
	case 8:
		low, hi = 10000000, 99999999
	case 9:
		low, hi = 100000000, 999999999
	case 10:
		low, hi = 1000000000, 9999999999
	default:
		low, hi = 1000000000, 9999999999
	}
	var rand = low + rand.Int63n(hi-low)
	return strconv.FormatInt(rand, 10)
}

var src = rand.NewSource(time.Now().UnixNano())

const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
)
const englishLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-"

func (pcs *PhraseCaptchas) randomWord(lang Language) string {
	var b = make([]byte, pcs.Len)
	var i uint8
	for i = 0; i < pcs.Len; i++ {
		var random = src.Int63()
		if idx := int(random & letterIdxMask); idx < len(englishLetters) {
			b[i] = englishLetters[idx]
		}
		random >>= letterIdxBits
	}
	return *(*string)(unsafe.Pointer(&b))
}

func (pcs *PhraseCaptchas) randomMath() string {
	// TODO:::
	return ""
}

var goBoldItalic *truetype.Font

func init() {
	var err error
	goBoldItalic, err = freetype.ParseFont(gobolditalic.TTF)
	if err != nil {
		// Almost never occur!
		panic(err)
	}
}

func (pcs *PhraseCaptchas) createImage(answer string, imageFormat ImageFormat) []byte {
	var img = image.NewRGBA(image.Rect(0, 0, pcs.ImageSize.X, pcs.ImageSize.Y))
	draw.Draw(img, img.Bounds(), image.White, image.ZP, draw.Src)

	// TODO::: Difficulty??!!
	var c = freetype.NewContext()
	var point = freetype.Pt(10, 10+int(c.PointToFixed(24)>>6))
	c.SetDst(img)
	c.SetSrc(image.Black) //(image.NewUniform(color.RGBA{200, 100, 0, 255}))
	c.SetFont(goBoldItalic)
	c.SetFontSize(24)
	c.SetDPI(72)
	c.SetClip(img.Bounds())
	c.DrawString(answer, point)

	var buf bytes.Buffer
	switch imageFormat {
	case ImageFormatPNG:
		png.Encode(&buf, img)
	case ImageFormatJPEG:
		jpeg.Encode(&buf, img, &jpeg.Options{Quality: jpeg.DefaultQuality})
	}
	return buf.Bytes()
}

func (pcs *PhraseCaptchas) createAudio(answer string, audioFormat AudioFormat) []byte {
	return []byte{}
}

func (pcs *PhraseCaptchas) expirationProcessing() {
	var timer = time.NewTimer(time.Duration(pcs.Duration) * time.Second)
	for {
		select {
		// case shutdownFeedback := <-pcs.shutdownSignal:
		// 	timer.Stop()
		// 	shutdownFeedback <- struct{}{}
		// 	return
		case <-timer.C:
			timer.Reset(time.Duration(pcs.Duration) * time.Second)

			if len(pcs.Pool) == 0 {
				continue
			}

			// Usually this proccess is less than one second, so get time once for compare!
			var timeNow = time.Now().Unix()
			for _, captcha := range pcs.Pool {
				if captcha.ExpireIn < timeNow {
					delete(pcs.Pool, captcha.ID)
				}
			}
		}
	}
}

// https://github.com/search?l=Go&q=captcha&type=Repositories
// https://github.com/dchest/captcha
// https://github.com/afocus/captcha
// https://github.com/steambap/captcha
// https://github.com/lifei6671/gocaptcha
// https://www.hcaptcha.com/
<|endoftext|>


<commit_before>// Copyright 2014 The Cayley Authors. All rights reserved.
//
// 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 http

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

	"github.com/julienschmidt/httprouter"
	"golang.org/x/net/context"

	"github.com/cayleygraph/cayley/query"
	"io"
)

type SuccessQueryWrapper struct {
	Result interface{} `json:"result"`
}

type ErrorQueryWrapper struct {
	Error string `json:"error"`
}

func WriteError(w io.Writer, err error) error {
	enc := json.NewEncoder(w)
	//enc.SetIndent("", " ")
	return enc.Encode(ErrorQueryWrapper{err.Error()})
}

func WriteResult(w io.Writer, result interface{}) error {
	enc := json.NewEncoder(w)
	//enc.SetIndent("", " ")
	return enc.Encode(SuccessQueryWrapper{result})
}

func GetQueryShape(q string, ses query.HTTP) ([]byte, error) {
	s, err := ses.ShapeOf(q)
	if err != nil {
		return nil, err
	}
	return json.Marshal(s)
}

func (api *API) contextForRequest(r *http.Request) (context.Context, func()) {
	ctx := context.TODO() // TODO(dennwc): get from request
	cancel := func() {}
	if api.config.Timeout > 0 {
		ctx, cancel = context.WithTimeout(ctx, api.config.Timeout)
	}
	return ctx, cancel
}

func defaultErrorFunc(w query.ResponseWriter, err error) {
	data, _ := json.Marshal(err.Error())
	w.WriteHeader(http.StatusBadRequest)
	w.Write([]byte(`{"error" : `))
	w.Write(data)
	w.Write([]byte(`}`))
}

// TODO(barakmich): Turn this into proper middleware.
func (api *API) ServeV1Query(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	ctx, cancel := api.contextForRequest(r)
	defer cancel()
	l := query.GetLanguage(params.ByName("query_lang"))
	if l == nil {
		jsonResponse(w, http.StatusBadRequest, "Unknown query language.")
		return
	}
	errFunc := defaultErrorFunc
	if l.HTTPError != nil {
		errFunc = l.HTTPError
	}
	select {
	case <-ctx.Done():
		errFunc(w, ctx.Err())
		return
	default:
	}
	h, err := api.GetHandleForRequest(r)
	if err != nil {
		errFunc(w, err)
		return
	}
	if l.HTTPQuery != nil {
		defer r.Body.Close()
		l.HTTPQuery(ctx, h.QuadStore, w, r.Body)
		return
	}
	if l.HTTP == nil {
		errFunc(w, errors.New("HTTP interface is not supported for this query language."))
		return
	}
	ses := l.HTTP(h.QuadStore)
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		errFunc(w, err)
		return
	}
	code := string(bodyBytes)

	c := make(chan query.Result, 5)
	go ses.Execute(ctx, code, c, 100)

	for res := range c {
		if err := res.Err(); err != nil {
			if err == nil {
				continue // wait for results channel to close
			}
			errFunc(w, err)
			return
		}
		ses.Collate(res)
	}
	output, err := ses.Results()
	if err != nil {
		errFunc(w, err)
		return
	}
	_ = WriteResult(w, output)
}

func (api *API) ServeV1Shape(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	ctx, cancel := api.contextForRequest(r)
	defer cancel()
	select {
	case <-ctx.Done():
		jsonResponse(w, http.StatusBadRequest, "Cancelled")
		return
	default:
	}
	h, err := api.GetHandleForRequest(r)
	if err != nil {
		jsonResponse(w, http.StatusBadRequest, err)
		return
	}
	l := query.GetLanguage(params.ByName("query_lang"))
	if l == nil {
		jsonResponse(w, http.StatusBadRequest, "Unknown query language.")
		return
	} else if l.HTTP == nil {
		jsonResponse(w, http.StatusBadRequest, "HTTP interface is not supported for this query language.")
		return
	}
	ses := l.HTTP(h.QuadStore)
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		jsonResponse(w, http.StatusBadRequest, err)
		return
	}
	code := string(bodyBytes)

	output, err := GetQueryShape(code, ses)
	if err == query.ErrParseMore {
		jsonResponse(w, http.StatusBadRequest, "Incomplete data?")
		return
	} else if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		WriteError(w, err)
		return
	}
	w.Write(output)
}
<commit_msg>http: allow to specify query limit; fix #612<commit_after>// Copyright 2014 The Cayley Authors. All rights reserved.
//
// 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 http

import (
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"

	"github.com/julienschmidt/httprouter"
	"golang.org/x/net/context"

	"github.com/cayleygraph/cayley/query"
)

type SuccessQueryWrapper struct {
	Result interface{} `json:"result"`
}

type ErrorQueryWrapper struct {
	Error string `json:"error"`
}

func WriteError(w io.Writer, err error) error {
	enc := json.NewEncoder(w)
	//enc.SetIndent("", " ")
	return enc.Encode(ErrorQueryWrapper{err.Error()})
}

func WriteResult(w io.Writer, result interface{}) error {
	enc := json.NewEncoder(w)
	//enc.SetIndent("", " ")
	return enc.Encode(SuccessQueryWrapper{result})
}

func GetQueryShape(q string, ses query.HTTP) ([]byte, error) {
	s, err := ses.ShapeOf(q)
	if err != nil {
		return nil, err
	}
	return json.Marshal(s)
}

func (api *API) contextForRequest(r *http.Request) (context.Context, func()) {
	ctx := context.TODO() // TODO(dennwc): get from request
	cancel := func() {}
	if api.config.Timeout > 0 {
		ctx, cancel = context.WithTimeout(ctx, api.config.Timeout)
	}
	return ctx, cancel
}

func defaultErrorFunc(w query.ResponseWriter, err error) {
	data, _ := json.Marshal(err.Error())
	w.WriteHeader(http.StatusBadRequest)
	w.Write([]byte(`{"error" : `))
	w.Write(data)
	w.Write([]byte(`}`))
}

// TODO(barakmich): Turn this into proper middleware.
func (api *API) ServeV1Query(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	ctx, cancel := api.contextForRequest(r)
	defer cancel()
	l := query.GetLanguage(params.ByName("query_lang"))
	if l == nil {
		jsonResponse(w, http.StatusBadRequest, "Unknown query language.")
		return
	}
	errFunc := defaultErrorFunc
	if l.HTTPError != nil {
		errFunc = l.HTTPError
	}
	select {
	case <-ctx.Done():
		errFunc(w, ctx.Err())
		return
	default:
	}
	h, err := api.GetHandleForRequest(r)
	if err != nil {
		errFunc(w, err)
		return
	}
	if l.HTTPQuery != nil {
		defer r.Body.Close()
		l.HTTPQuery(ctx, h.QuadStore, w, r.Body)
		return
	}
	if l.HTTP == nil {
		errFunc(w, errors.New("HTTP interface is not supported for this query language."))
		return
	}

	par, _ := url.ParseQuery(r.URL.RawQuery)
	limit, _ := strconv.Atoi(par.Get("limit"))
	if limit == 0 {
		limit = 100
	}

	ses := l.HTTP(h.QuadStore)
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		errFunc(w, err)
		return
	}
	code := string(bodyBytes)

	c := make(chan query.Result, 5)
	go ses.Execute(ctx, code, c, limit)

	for res := range c {
		if err := res.Err(); err != nil {
			if err == nil {
				continue // wait for results channel to close
			}
			errFunc(w, err)
			return
		}
		ses.Collate(res)
	}
	output, err := ses.Results()
	if err != nil {
		errFunc(w, err)
		return
	}
	_ = WriteResult(w, output)
}

func (api *API) ServeV1Shape(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	ctx, cancel := api.contextForRequest(r)
	defer cancel()
	select {
	case <-ctx.Done():
		jsonResponse(w, http.StatusBadRequest, "Cancelled")
		return
	default:
	}
	h, err := api.GetHandleForRequest(r)
	if err != nil {
		jsonResponse(w, http.StatusBadRequest, err)
		return
	}
	l := query.GetLanguage(params.ByName("query_lang"))
	if l == nil {
		jsonResponse(w, http.StatusBadRequest, "Unknown query language.")
		return
	} else if l.HTTP == nil {
		jsonResponse(w, http.StatusBadRequest, "HTTP interface is not supported for this query language.")
		return
	}
	ses := l.HTTP(h.QuadStore)
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		jsonResponse(w, http.StatusBadRequest, err)
		return
	}
	code := string(bodyBytes)

	output, err := GetQueryShape(code, ses)
	if err == query.ErrParseMore {
		jsonResponse(w, http.StatusBadRequest, "Incomplete data?")
		return
	} else if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		WriteError(w, err)
		return
	}
	w.Write(output)
}
<|endoftext|>


<commit_before>package version

// IPCVersion represents a version of the IPC protocol.
type IPCVersion uint32

const (
	// UnknownIPCVersion is used for Min/MaxIPCVersion in an Endpoint when
	// we don't know the relevant version numbers.  In this case the IPC
	// implementation will have to guess the correct values.
	UnknownIPCVersion IPCVersion = iota
	// Deprecated versions
	ipcVersion2
	ipcVersion3
	ipcDummyVersion3 // So that the numeric value of IPCVersion4 is 4
	IPCVersion4

	// IPCVersion5 uses the new security model (Principal and Blessings objects),
	// and sends discharges for third-party caveats on the server's blessings
	// during authentication.
	IPCVersion5
)

// IPCVersionRange allows you to optionally specify a range of versions to
// use when calling FormatEndpoint
type IPCVersionRange struct {
	Min, Max IPCVersion
}

// EndpointOpt implents the EndpointOpt interface so an IPCVersionRange
// can be used as an option to FormatEndpoint.
func (IPCVersionRange) EndpointOpt() {}
<commit_msg>veyron/runtimes/google/ipc/stream: Implement control-channel encryption.<commit_after>package version

// IPCVersion represents a version of the IPC protocol.
type IPCVersion uint32

const (
	// UnknownIPCVersion is used for Min/MaxIPCVersion in an Endpoint when
	// we don't know the relevant version numbers.  In this case the IPC
	// implementation will have to guess the correct values.
	UnknownIPCVersion IPCVersion = iota
	// Deprecated versions
	ipcVersion2
	ipcVersion3
	ipcDummyVersion3 // So that the numeric value of IPCVersion4 is 4
	IPCVersion4

	// IPCVersion5 uses the new security model (Principal and Blessings objects),
	// and sends discharges for third-party caveats on the server's blessings
	// during authentication.
	IPCVersion5

	// IPCVersion6 adds control channel encryption to IPCVersion5.
	IPCVersion6
)

// IPCVersionRange allows you to optionally specify a range of versions to
// use when calling FormatEndpoint
type IPCVersionRange struct {
	Min, Max IPCVersion
}

// EndpointOpt implents the EndpointOpt interface so an IPCVersionRange
// can be used as an option to FormatEndpoint.
func (IPCVersionRange) EndpointOpt() {}
<|endoftext|>


<commit_before><commit_msg>gh-699: minor bugfix attempt<commit_after><|endoftext|>


<commit_before>package libvirt

import (
	"fmt"
	"subuk/vmango/util"
	"sync"

	"github.com/rs/zerolog"

	libvirt "github.com/libvirt/libvirt-go"
)

type ConnectionPool struct {
	uri    string
	mutex  *sync.Mutex
	logger zerolog.Logger
	cached *libvirt.Connect
}

func NewConnectionPool(uri string, logger zerolog.Logger) *ConnectionPool {
	return &ConnectionPool{
		uri:    uri,
		mutex:  &sync.Mutex{},
		logger: logger,
	}
}

func (p *ConnectionPool) Acquire() (*libvirt.Connect, error) {
	p.mutex.Lock()
	var conn *libvirt.Connect

	if p.cached != nil {
		conn = p.cached
	} else {
		p.logger.Debug().Msg("establishing new connection")
		newConn, err := libvirt.NewConnect(p.uri)
		if err != nil {
			return nil, util.NewError(err, "cannot open libvirt connection")
		}
		conn = newConn
		p.cached = conn
	}
	alive, err := conn.IsAlive()
	if err != nil {
		return nil, util.NewError(err, "libvirt connection is not alive")
	}
	if !alive {
		return nil, fmt.Errorf("libvirt connection is not alive")
	}
	return conn, nil
}

func (p *ConnectionPool) Release(conn *libvirt.Connect) {
	p.mutex.Unlock()
}
<commit_msg>Restore libvirt connection automatically<commit_after>package libvirt

import (
	"subuk/vmango/util"
	"sync"

	"github.com/rs/zerolog"

	libvirt "github.com/libvirt/libvirt-go"
)

type ConnectionPool struct {
	uri    string
	mutex  *sync.Mutex
	logger zerolog.Logger
	cached *libvirt.Connect
}

func NewConnectionPool(uri string, logger zerolog.Logger) *ConnectionPool {
	return &ConnectionPool{
		uri:    uri,
		mutex:  &sync.Mutex{},
		logger: logger,
	}
}

func (p *ConnectionPool) Acquire() (*libvirt.Connect, error) {
	p.mutex.Lock()
	var conn *libvirt.Connect

	if p.cached != nil {
		conn = p.cached
	}

	if conn == nil {
		p.logger.Debug().Msg("establishing new connection")
		newConn, err := libvirt.NewConnect(p.uri)
		if err != nil {
			p.mutex.Unlock()
			return nil, util.NewError(err, "cannot open libvirt connection")
		}
		p.cached = newConn
		return newConn, nil
	}
	alive, err := conn.IsAlive()
	if err != nil {
		newConn, err := libvirt.NewConnect(p.uri)
		if err != nil {
			p.mutex.Unlock()
			return nil, util.NewError(err, "cannot reopen libvirt connection")
		}
		p.cached = newConn
		return newConn, nil
	}
	if !alive {
		newConn, err := libvirt.NewConnect(p.uri)
		if err != nil {
			p.mutex.Unlock()
			return nil, util.NewError(err, "cannot reopen libvirt connection")
		}
		p.cached = newConn
		return newConn, nil
	}
	return conn, nil
}

func (p *ConnectionPool) Release(conn *libvirt.Connect) {
	p.mutex.Unlock()
}
<|endoftext|>