<commit_before>package kvs

import (
	"fmt"
	"reflect"
	"sync"
)

var (
	storageType        = reflect.TypeOf((*Storage)(nil)).Elem()
	emptyInterfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
)

// KVS is a thread safe implementation of the
// Storage interface. Its empty value is safe
// to use.
type KVS struct {
	mu     sync.RWMutex
	values map[interface{}]interface{}
}

// Get implements Storage.Get
func (k *KVS) Get(key interface{}) interface{} {
	k.mu.RLock()
	value := k.values[key]
	k.mu.RUnlock()
	return value
}

// Set implements Storage.Set
func (k *KVS) Set(key interface{}, value interface{}) {
	k.mu.Lock()
	if k.values == nil {
		k.values = make(map[interface{}]interface{})
	}
	k.values[key] = value
	k.mu.Unlock()
}

// Clear removes all stored values
func (k *KVS) Clear() {
	k.mu.Lock()
	k.values = nil
	k.mu.Unlock()
}

// Copy returns a shallow copy of the KVS
func (k *KVS) Copy() *KVS {
	cpy := new(KVS)
	k.mu.RLock()
	if len(k.values) > 0 {
		cpy.values = make(map[interface{}]interface{})
		for k, v := range k.values {
			cpy.values[k] = v
		}
	}
	k.mu.RUnlock()
	return cpy
}

// Storage is an interface which declares two methods for
// storing arbitrary values. The lifetime of the values as well of
// the thread safety of the storage is dependent on the implementation.
type Storage interface {
	Get(key interface{}) interface{}
	Set(key interface{}, value interface{})
}

func keyValueGet(kv Storage, key interface{}, typ reflect.Type) []reflect.Value {
	v := kv.Get(key)
	var rv reflect.Value
	if v == nil {
		// We've got an untyped nil, so we need to
		// create a typed one with the return value
		// of the function.
		rv = reflect.Zero(typ)
	} else {
		rv = reflect.ValueOf(v)
	}
	return []reflect.Value{rv}
}

func storageGet(key interface{}, typ reflect.Type) func([]reflect.Value) []reflect.Value {
	return func(in []reflect.Value) []reflect.Value {
		kv := in[0].Interface().(Storage)
		return keyValueGet(kv, key, typ)
	}
}

func storageGetKey(typ reflect.Type) func([]reflect.Value) []reflect.Value {
	return func(in []reflect.Value) []reflect.Value {
		kv := in[0].Interface().(Storage)
		key := in[1].Interface()
		return keyValueGet(kv, key, typ)
	}
}

func storageSet(key interface{}) func([]reflect.Value) []reflect.Value {
	return func(in []reflect.Value) []reflect.Value {
		kv := in[0].Interface().(Storage)
		kv.Set(key, in[1].Interface())
		return nil
	}
}

func storageSetKey(in []reflect.Value) []reflect.Value {
	kv := in[0].Interface().(Storage)
	kv.Set(in[1].Interface(), in[2].Interface())
	return nil
}

func isStorageType(typ reflect.Type) bool {
	return typ == storageType || typ.AssignableTo(storageType)
}

// Funcs allows creating functions for easily setting and retrieving
// values associated with a key from an Storage in a type safe manner.
//
// Getter functions must conform to the following specification:
//
//  func(storage S, key interface{}) V or func(storage S, key interface{}) (V, bool)
//
// Where S is kvs.Storage or implements kvs.Storage and V is any type.
//
// Setter functions must conform to the following specification:
//
//  func(storage S, key interface{}, value V)
//
// Where V is any type. Note that when generating a getter/setter function pair,
// V must be exactly the same type in the getter and in the setter.
//
// See the examples for more information.
//
// Note that this function will panic if the prototypes of the functions don't,
// match the expected ones.
//
// Alternatively, if you're only going to store once value per type, use
// TypeFuncs instead.
func Funcs(getter interface{}, setter interface{}) {
	gptr := reflect.ValueOf(getter)
	if gptr.Kind() != reflect.Ptr || gptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("getter must be a pointer to a function, not %v",
			gptr.Type()))
	}
	gval := gptr.Elem()
	gvalType := gval.Type()
	if gvalType.NumIn() != 2 {
		panic(fmt.Errorf("getter must accept two arguments, not %d",
			gvalType.NumIn()))
	}
	if !isStorageType(gvalType.In(0)) {
		panic(fmt.Errorf("getter 1st argument must be of type %v or assignable to it, not %v",
			storageType, gvalType.In(0)))
	}
	if gvalType.In(1) != emptyInterfaceType {
		panic(fmt.Errorf("getter 2nd argument must be of type %v, not %v",
			emptyInterfaceType, gvalType.In(1)))
	}
	if gvalType.NumOut() != 1 {
		panic(fmt.Errorf("getter must return only one value, not %d",
			gvalType.NumOut()))
	}
	ttype := gvalType.Out(0)
	gval.Set(reflect.MakeFunc(gvalType, storageGetKey(ttype)))

	sptr := reflect.ValueOf(setter)
	if sptr.Kind() != reflect.Ptr || sptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("setter must be a pointer to a function, not %v",
			sptr.Type()))
	}
	sval := sptr.Elem()
	svalType := sval.Type()
	if svalType.NumIn() != 3 {
		panic(fmt.Errorf("setter must accept three arguments, not %d",
			svalType.NumIn()))
	}
	if !isStorageType(svalType.In(0)) {
		panic(fmt.Errorf("setter's 1st argument must be of type %v or assignable to it, not %v",
			storageType, svalType.In(0)))
	}
	if svalType.In(1) != emptyInterfaceType {
		panic(fmt.Errorf("setter's 2nd argument must be of type %v, not %v",
			emptyInterfaceType, svalType.In(1)))
	}
	if svalType.In(2) != ttype {
		panic(fmt.Errorf("setter's 3rd argument must be of type %v (to match getter), not %v",
			ttype, svalType.In(2)))
	}
	if svalType.NumOut() != 0 {
		panic(fmt.Errorf("setter not return any values, not %d",
			svalType.NumOut()))
	}
	sval.Set(reflect.MakeFunc(svalType, storageSetKey))
}

// TypeFuncs allows creating functions for easily setting and retrieving
// a value associated with a type from an Storage in a type safe manner.
//
// Getter functions must conform to the following specification:
//
//  func(storage S) V or func(storage S) (V, bool)
//
// Where S is kvs.Storage or implements kvs.Storage and V is any type.
//
// Setter functions must conform to the following specification:
//
//  func(storage S, value V)
//
// Where V is any type. Note that when generating a getter/setter function pair,
// V must be exactly the same type in the getter and in the setter.
//
// See the examples for more information.
//
// Alternatively, if you need to get/set multiple values of the same type, use
// Funcs instead.
func TypeFuncs(getter interface{}, setter interface{}) {
	gptr := reflect.ValueOf(getter)
	if gptr.Kind() != reflect.Ptr || gptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("getter must be a pointer to a function, not %v",
			gptr.Type()))
	}
	gval := gptr.Elem()
	gvalType := gval.Type()
	if gvalType.NumIn() != 1 {
		panic(fmt.Errorf("getter must accept only one argument, not %d",
			gvalType.NumIn()))
	}
	if !isStorageType(gvalType.In(0)) {
		panic(fmt.Errorf("getter 1st argument must be of type %v or assignable to it, not %v",
			storageType, gvalType.In(0)))
	}
	if gvalType.NumOut() != 1 {
		panic(fmt.Errorf("getter must return only one value, not %d",
			gvalType.NumOut()))
	}
	ttype := gvalType.Out(0)
	key := gval
	gval.Set(reflect.MakeFunc(gvalType, storageGet(key, ttype)))

	sptr := reflect.ValueOf(setter)
	if sptr.Kind() != reflect.Ptr || sptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("setter must be a pointer to a function, not %v",
			sptr.Type()))
	}
	sval := sptr.Elem()
	svalType := sval.Type()
	if svalType.NumIn() != 2 {
		panic(fmt.Errorf("setter must accept two arguments, not %d",
			svalType.NumIn()))
	}
	if !isStorageType(svalType.In(0)) {
		panic(fmt.Errorf("setter's 1st argument must be of type %v or assignable to it, not %v",
			storageType, svalType.In(0)))
	}
	if svalType.In(1) != ttype {
		panic(fmt.Errorf("setter's 2nd argument must be of type %v (to match getter), not %v",
			ttype, svalType.In(1)))
	}
	if svalType.NumOut() != 0 {
		panic(fmt.Errorf("setter not return any values, not %d",
			svalType.NumOut()))
	}
	sval.Set(reflect.MakeFunc(svalType, storageSet(key)))
}
<commit_msg>Add doc comments to Storage.Get and Storage.Set<commit_after>package kvs

import (
	"fmt"
	"reflect"
	"sync"
)

var (
	storageType        = reflect.TypeOf((*Storage)(nil)).Elem()
	emptyInterfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
)

// KVS is a thread safe implementation of the
// Storage interface. Its empty value is safe
// to use.
type KVS struct {
	mu     sync.RWMutex
	values map[interface{}]interface{}
}

// Get implements Storage.Get
func (k *KVS) Get(key interface{}) interface{} {
	k.mu.RLock()
	value := k.values[key]
	k.mu.RUnlock()
	return value
}

// Set implements Storage.Set
func (k *KVS) Set(key interface{}, value interface{}) {
	k.mu.Lock()
	if k.values == nil {
		k.values = make(map[interface{}]interface{})
	}
	k.values[key] = value
	k.mu.Unlock()
}

// Clear removes all stored values
func (k *KVS) Clear() {
	k.mu.Lock()
	k.values = nil
	k.mu.Unlock()
}

// Copy returns a shallow copy of the KVS
func (k *KVS) Copy() *KVS {
	cpy := new(KVS)
	k.mu.RLock()
	if len(k.values) > 0 {
		cpy.values = make(map[interface{}]interface{})
		for k, v := range k.values {
			cpy.values[k] = v
		}
	}
	k.mu.RUnlock()
	return cpy
}

// Storage is an interface which declares two methods for
// storing arbitrary values. The lifetime of the values as well of
// the thread safety of the storage is dependent on the implementation.
type Storage interface {
	// Get returns the value assocciated with key
	Get(key interface{}) interface{}
	// Set sets the value assocciated with key to value
	Set(key interface{}, value interface{})
}

func keyValueGet(kv Storage, key interface{}, typ reflect.Type) []reflect.Value {
	v := kv.Get(key)
	var rv reflect.Value
	if v == nil {
		// We've got an untyped nil, so we need to
		// create a typed one with the return value
		// of the function.
		rv = reflect.Zero(typ)
	} else {
		rv = reflect.ValueOf(v)
	}
	return []reflect.Value{rv}
}

func storageGet(key interface{}, typ reflect.Type) func([]reflect.Value) []reflect.Value {
	return func(in []reflect.Value) []reflect.Value {
		kv := in[0].Interface().(Storage)
		return keyValueGet(kv, key, typ)
	}
}

func storageGetKey(typ reflect.Type) func([]reflect.Value) []reflect.Value {
	return func(in []reflect.Value) []reflect.Value {
		kv := in[0].Interface().(Storage)
		key := in[1].Interface()
		return keyValueGet(kv, key, typ)
	}
}

func storageSet(key interface{}) func([]reflect.Value) []reflect.Value {
	return func(in []reflect.Value) []reflect.Value {
		kv := in[0].Interface().(Storage)
		kv.Set(key, in[1].Interface())
		return nil
	}
}

func storageSetKey(in []reflect.Value) []reflect.Value {
	kv := in[0].Interface().(Storage)
	kv.Set(in[1].Interface(), in[2].Interface())
	return nil
}

func isStorageType(typ reflect.Type) bool {
	return typ == storageType || typ.AssignableTo(storageType)
}

// Funcs allows creating functions for easily setting and retrieving
// values associated with a key from an Storage in a type safe manner.
//
// Getter functions must conform to the following specification:
//
//  func(storage S, key interface{}) V or func(storage S, key interface{}) (V, bool)
//
// Where S is kvs.Storage or implements kvs.Storage and V is any type.
//
// Setter functions must conform to the following specification:
//
//  func(storage S, key interface{}, value V)
//
// Where V is any type. Note that when generating a getter/setter function pair,
// V must be exactly the same type in the getter and in the setter.
//
// See the examples for more information.
//
// Note that this function will panic if the prototypes of the functions don't,
// match the expected ones.
//
// Alternatively, if you're only going to store once value per type, use
// TypeFuncs instead.
func Funcs(getter interface{}, setter interface{}) {
	gptr := reflect.ValueOf(getter)
	if gptr.Kind() != reflect.Ptr || gptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("getter must be a pointer to a function, not %v",
			gptr.Type()))
	}
	gval := gptr.Elem()
	gvalType := gval.Type()
	if gvalType.NumIn() != 2 {
		panic(fmt.Errorf("getter must accept two arguments, not %d",
			gvalType.NumIn()))
	}
	if !isStorageType(gvalType.In(0)) {
		panic(fmt.Errorf("getter 1st argument must be of type %v or assignable to it, not %v",
			storageType, gvalType.In(0)))
	}
	if gvalType.In(1) != emptyInterfaceType {
		panic(fmt.Errorf("getter 2nd argument must be of type %v, not %v",
			emptyInterfaceType, gvalType.In(1)))
	}
	if gvalType.NumOut() != 1 {
		panic(fmt.Errorf("getter must return only one value, not %d",
			gvalType.NumOut()))
	}
	ttype := gvalType.Out(0)
	gval.Set(reflect.MakeFunc(gvalType, storageGetKey(ttype)))

	sptr := reflect.ValueOf(setter)
	if sptr.Kind() != reflect.Ptr || sptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("setter must be a pointer to a function, not %v",
			sptr.Type()))
	}
	sval := sptr.Elem()
	svalType := sval.Type()
	if svalType.NumIn() != 3 {
		panic(fmt.Errorf("setter must accept three arguments, not %d",
			svalType.NumIn()))
	}
	if !isStorageType(svalType.In(0)) {
		panic(fmt.Errorf("setter's 1st argument must be of type %v or assignable to it, not %v",
			storageType, svalType.In(0)))
	}
	if svalType.In(1) != emptyInterfaceType {
		panic(fmt.Errorf("setter's 2nd argument must be of type %v, not %v",
			emptyInterfaceType, svalType.In(1)))
	}
	if svalType.In(2) != ttype {
		panic(fmt.Errorf("setter's 3rd argument must be of type %v (to match getter), not %v",
			ttype, svalType.In(2)))
	}
	if svalType.NumOut() != 0 {
		panic(fmt.Errorf("setter not return any values, not %d",
			svalType.NumOut()))
	}
	sval.Set(reflect.MakeFunc(svalType, storageSetKey))
}

// TypeFuncs allows creating functions for easily setting and retrieving
// a value associated with a type from an Storage in a type safe manner.
//
// Getter functions must conform to the following specification:
//
//  func(storage S) V or func(storage S) (V, bool)
//
// Where S is kvs.Storage or implements kvs.Storage and V is any type.
//
// Setter functions must conform to the following specification:
//
//  func(storage S, value V)
//
// Where V is any type. Note that when generating a getter/setter function pair,
// V must be exactly the same type in the getter and in the setter.
//
// See the examples for more information.
//
// Alternatively, if you need to get/set multiple values of the same type, use
// Funcs instead.
func TypeFuncs(getter interface{}, setter interface{}) {
	gptr := reflect.ValueOf(getter)
	if gptr.Kind() != reflect.Ptr || gptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("getter must be a pointer to a function, not %v",
			gptr.Type()))
	}
	gval := gptr.Elem()
	gvalType := gval.Type()
	if gvalType.NumIn() != 1 {
		panic(fmt.Errorf("getter must accept only one argument, not %d",
			gvalType.NumIn()))
	}
	if !isStorageType(gvalType.In(0)) {
		panic(fmt.Errorf("getter 1st argument must be of type %v or assignable to it, not %v",
			storageType, gvalType.In(0)))
	}
	if gvalType.NumOut() != 1 {
		panic(fmt.Errorf("getter must return only one value, not %d",
			gvalType.NumOut()))
	}
	ttype := gvalType.Out(0)
	key := gval
	gval.Set(reflect.MakeFunc(gvalType, storageGet(key, ttype)))

	sptr := reflect.ValueOf(setter)
	if sptr.Kind() != reflect.Ptr || sptr.Elem().Kind() != reflect.Func {
		panic(fmt.Errorf("setter must be a pointer to a function, not %v",
			sptr.Type()))
	}
	sval := sptr.Elem()
	svalType := sval.Type()
	if svalType.NumIn() != 2 {
		panic(fmt.Errorf("setter must accept two arguments, not %d",
			svalType.NumIn()))
	}
	if !isStorageType(svalType.In(0)) {
		panic(fmt.Errorf("setter's 1st argument must be of type %v or assignable to it, not %v",
			storageType, svalType.In(0)))
	}
	if svalType.In(1) != ttype {
		panic(fmt.Errorf("setter's 2nd argument must be of type %v (to match getter), not %v",
			ttype, svalType.In(1)))
	}
	if svalType.NumOut() != 0 {
		panic(fmt.Errorf("setter not return any values, not %d",
			svalType.NumOut()))
	}
	sval.Set(reflect.MakeFunc(svalType, storageSet(key)))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/the42/ogdat"
	htmltpl "html/template"
	"io"
	"log"
	"os"
	texttpl "text/template"
)

var inputfile = flag.String("if", "", "Eingabe mit OGD-Spezifikation (Standard: stdin)")
var outputfile = flag.String("of", "", "Ausgabe der Spezifikation nach (Standard: stdout)")
var templateset = flag.String("ts", "render.html.tpl", "(Satz von) Template-Dateien, die die Transformation der Spezifikation ins Ausgabeformat beschreibt")
var html = flag.Bool("html", true, "Anwendung von HTML-Escaping in der Ausgabe")
var help = flag.Bool("help", false, "Hilfe zur Verwendung")

type Templater interface {
	Execute(io.Writer, interface{}) error
}

func main() {
	flag.Parse()
	if *help {
		flag.PrintDefaults()
		return
	}

	if *inputfile == "" {
		*inputfile = os.Stdin.Name()
	}
	spec, err := ogdat.Loadogdatspec("unknown", *inputfile)
	if err != nil {
		log.Panicf("Could not load specification file %s, the error was %s\n", *inputfile, err)
	}

	var ofile *os.File
	if *outputfile == "" {
		ofile = os.Stdout
	} else {
		var err error
		ofile, err = os.OpenFile(*outputfile, os.O_RDWR|os.O_CREATE|os.O_EXCL, os.FileMode(0666))
		if err != nil {
			log.Panicf("Can't open file %s for writing, the error was: %s\n", inputfile, err)
		}
		defer ofile.Close()
	}

	var tpl Templater
	if *html {
		tpl = htmltpl.Must(htmltpl.ParseFiles(*templateset))
	} else {
		tpl = texttpl.Must(texttpl.ParseFiles(*templateset))
	}
	tpl.Execute(ofile, spec)
}
<commit_msg>first open input file, then template, then output file<commit_after>package main

import (
	"flag"
	"github.com/the42/ogdat"
	htmltpl "html/template"
	"io"
	"log"
	"os"
	texttpl "text/template"
)

var inputfile = flag.String("if", "", "Eingabe mit OGD-Spezifikation (Standard: stdin)")
var outputfile = flag.String("of", "", "Ausgabe der Spezifikation nach (Standard: stdout)")
var templateset = flag.String("ts", "render.html.tpl", "(Satz von) Template-Dateien, die die Transformation der Spezifikation ins Ausgabeformat beschreibt")
var html = flag.Bool("html", true, "Anwendung von HTML-Escaping in der Ausgabe")
var help = flag.Bool("help", false, "Hilfe zur Verwendung")

type Templater interface {
	Execute(io.Writer, interface{}) error
}

func main() {
	flag.Parse()
	if *help {
		flag.PrintDefaults()
		return
	}

	if *inputfile == "" {
		*inputfile = os.Stdin.Name()
	}
	spec, err := ogdat.Loadogdatspec("unknown", *inputfile)
	if err != nil {
		log.Panicf("Could not load specification file %s, the error was %s\n", *inputfile, err)
	}

	var tpl Templater
	if *html {
		tpl = htmltpl.Must(htmltpl.ParseFiles(*templateset))
	} else {
		tpl = texttpl.Must(texttpl.ParseFiles(*templateset))
	}

	var ofile *os.File
	if *outputfile == "" {
		ofile = os.Stdout
	} else {
		var err error
		ofile, err = os.OpenFile(*outputfile, os.O_RDWR|os.O_CREATE|os.O_EXCL, os.FileMode(0666))
		if err != nil {
			log.Panicf("Can't open file %s for writing, the error was: %s\n", inputfile, err)
		}
		defer ofile.Close()
	}

	tpl.Execute(ofile, spec)
}
<|endoftext|>


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

//go:build go1.18
// +build go1.18

package main

// This example will create the keyspace
// "gocql_integration_example" and a single table
// with the following schema:
// gocql_integration_example.book
//   id UUID
//   title text
//   author_first_name text
//   author_last_name text
//   PRIMARY KEY(id)
// The example will insert fictional books into the database and
// then truncate the table.

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"time"

	"github.com/gocql/gocql"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"go.opentelemetry.io/otel"
	otelprom "go.opentelemetry.io/otel/exporters/prometheus"
	"go.opentelemetry.io/otel/exporters/zipkin"
	"go.opentelemetry.io/otel/metric/global"
	"go.opentelemetry.io/otel/sdk/metric"
	"go.opentelemetry.io/otel/sdk/metric/aggregation"
	"go.opentelemetry.io/otel/sdk/metric/view"
	"go.opentelemetry.io/otel/sdk/trace"

	"go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql"
)

const keyspace = "gocql_integration_example"

var wg sync.WaitGroup

func main() {
	if err := initMetrics(); err != nil {
		log.Fatalf("failed to install metric exporter, %v", err)
	}
	tp, err := initTracer()
	if err != nil {
		log.Fatalf("failed to create zipkin exporter: %s", err)
	}
	defer func() { tp.Shutdown(context.Background()) }() //nolint:revive,errcheck
	if err := initDb(); err != nil {
		log.Fatal(err)
	}

	ctx, span := otel.Tracer(
		"go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/example",
	).Start(context.Background(), "begin example")

	cluster := getCluster()
	// Create a session to begin making queries
	session, err := otelgocql.NewSessionWithTracing(
		ctx,
		cluster,
	)
	if err != nil {
		log.Fatalf("failed to create a session, %v", err)
	}
	defer session.Close()

	batch := session.NewBatch(gocql.LoggedBatch)
	for i := 0; i < 500; i++ {
		batch.Query(
			"INSERT INTO book (id, title, author_first_name, author_last_name) VALUES (?, ?, ?, ?)",
			gocql.TimeUUID(),
			fmt.Sprintf("Example Book %d", i),
			"firstName",
			"lastName",
		)
	}
	if err := session.ExecuteBatch(batch.WithContext(ctx)); err != nil {
		log.Printf("failed to batch insert, %v", err)
	}

	res := session.Query(
		"SELECT title, author_first_name, author_last_name from book WHERE author_last_name = ?",
		"lastName",
	).WithContext(ctx).PageSize(100).Iter()

	var (
		title     string
		firstName string
		lastName  string
	)

	for res.Scan(&title, &firstName, &lastName) {
		res.Scan(&title, &firstName, &lastName)
	}

	res.Close()

	if err = session.Query("truncate table book").WithContext(ctx).Exec(); err != nil {
		log.Printf("failed to delete data, %v", err)
	}

	span.End()

	wg.Wait()
}

func views() ([]view.View, error) {
	var vs []view.View
	// TODO: Remove renames when the Prometheus exporter natively supports
	// metric instrument name sanitation
	// (https://github.com/open-telemetry/opentelemetry-go/issues/3183).
	v, err := view.New(
		view.MatchInstrumentName("db.cassandra.queries"),
		view.WithRename("db_cassandra_queries"),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	v, err = view.New(
		view.MatchInstrumentName("db.cassandra.rows"),
		view.WithRename("db_cassandra_rows"),
		view.WithSetAggregation(aggregation.ExplicitBucketHistogram{
			Boundaries: []float64{0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10},
		}),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	v, err = view.New(
		view.MatchInstrumentName("db.cassandra.batch.queries"),
		view.WithRename("db_cassandra_batch_queries"),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	v, err = view.New(
		view.MatchInstrumentName("db.cassandra.connections"),
		view.WithRename("db_cassandra_connections"),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	v, err = view.New(
		view.MatchInstrumentName("db.cassandra.latency"),
		view.WithRename("db_cassandra_latency"),
		view.WithSetAggregation(aggregation.ExplicitBucketHistogram{
			Boundaries: []float64{0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10},
		}),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	return vs, nil
}

func initMetrics() error {
	vs, err := views()
	if err != nil {
		return err
	}

	exporter, err := otelprom.New()
	if err != nil {
		return err
	}
	provider := metric.NewMeterProvider(metric.WithReader(exporter, vs...))
	global.SetMeterProvider(provider)

	http.Handle("/", promhttp.Handler())
	log.Print("Serving metrics at :2222/")
	go func() {
		err := http.ListenAndServe(":2222", nil)
		if err != nil {
			log.Print(err)
		}
	}()

	ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
	wg.Add(1)
	go func() {
		defer wg.Done()
		<-ctx.Done()
		err := provider.Shutdown(context.Background())
		if err != nil {
			log.Printf("error stopping MeterProvider: %s", err)
		}
	}()
	return nil
}

func initTracer() (*trace.TracerProvider, error) {
	exporter, err := zipkin.New("http://localhost:9411/api/v2/spans")
	if err != nil {
		return nil, err
	}

	tp := trace.NewTracerProvider(trace.WithBatcher(exporter))
	otel.SetTracerProvider(tp)

	return tp, nil
}

func initDb() error {
	cluster := gocql.NewCluster("127.0.0.1")
	cluster.Keyspace = "system"
	cluster.Consistency = gocql.LocalQuorum
	cluster.Timeout = time.Second * 2
	session, err := cluster.CreateSession()
	if err != nil {
		return err
	}
	stmt := fmt.Sprintf(
		"create keyspace if not exists %s with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
		keyspace,
	)
	if err := session.Query(stmt).Exec(); err != nil {
		return err
	}

	cluster.Keyspace = keyspace
	session, err = cluster.CreateSession()
	if err != nil {
		return err
	}

	stmt = "create table if not exists book(id UUID, title text, author_first_name text, author_last_name text, PRIMARY KEY(id))"
	if err = session.Query(stmt).Exec(); err != nil {
		return err
	}

	return session.Query("create index if not exists on book(author_last_name)").Exec()
}

func getCluster() *gocql.ClusterConfig {
	cluster := gocql.NewCluster("127.0.0.1")
	cluster.Keyspace = keyspace
	cluster.Consistency = gocql.LocalQuorum
	cluster.ProtoVersion = 3
	cluster.Timeout = 2 * time.Second
	return cluster
}
<commit_msg>Remove unneeded inst rename views for otelgocql (#2960)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build go1.18
// +build go1.18

package main

// This example will create the keyspace
// "gocql_integration_example" and a single table
// with the following schema:
// gocql_integration_example.book
//   id UUID
//   title text
//   author_first_name text
//   author_last_name text
//   PRIMARY KEY(id)
// The example will insert fictional books into the database and
// then truncate the table.

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"time"

	"github.com/gocql/gocql"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"go.opentelemetry.io/otel"
	otelprom "go.opentelemetry.io/otel/exporters/prometheus"
	"go.opentelemetry.io/otel/exporters/zipkin"
	"go.opentelemetry.io/otel/metric/global"
	"go.opentelemetry.io/otel/sdk/metric"
	"go.opentelemetry.io/otel/sdk/metric/aggregation"
	"go.opentelemetry.io/otel/sdk/metric/view"
	"go.opentelemetry.io/otel/sdk/trace"

	"go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql"
)

const keyspace = "gocql_integration_example"

var wg sync.WaitGroup

func main() {
	if err := initMetrics(); err != nil {
		log.Fatalf("failed to install metric exporter, %v", err)
	}
	tp, err := initTracer()
	if err != nil {
		log.Fatalf("failed to create zipkin exporter: %s", err)
	}
	defer func() { tp.Shutdown(context.Background()) }() //nolint:revive,errcheck
	if err := initDb(); err != nil {
		log.Fatal(err)
	}

	ctx, span := otel.Tracer(
		"go.opentelemetry.io/contrib/instrumentation/github.com/gocql/gocql/otelgocql/example",
	).Start(context.Background(), "begin example")

	cluster := getCluster()
	// Create a session to begin making queries
	session, err := otelgocql.NewSessionWithTracing(
		ctx,
		cluster,
	)
	if err != nil {
		log.Fatalf("failed to create a session, %v", err)
	}
	defer session.Close()

	batch := session.NewBatch(gocql.LoggedBatch)
	for i := 0; i < 500; i++ {
		batch.Query(
			"INSERT INTO book (id, title, author_first_name, author_last_name) VALUES (?, ?, ?, ?)",
			gocql.TimeUUID(),
			fmt.Sprintf("Example Book %d", i),
			"firstName",
			"lastName",
		)
	}
	if err := session.ExecuteBatch(batch.WithContext(ctx)); err != nil {
		log.Printf("failed to batch insert, %v", err)
	}

	res := session.Query(
		"SELECT title, author_first_name, author_last_name from book WHERE author_last_name = ?",
		"lastName",
	).WithContext(ctx).PageSize(100).Iter()

	var (
		title     string
		firstName string
		lastName  string
	)

	for res.Scan(&title, &firstName, &lastName) {
		res.Scan(&title, &firstName, &lastName)
	}

	res.Close()

	if err = session.Query("truncate table book").WithContext(ctx).Exec(); err != nil {
		log.Printf("failed to delete data, %v", err)
	}

	span.End()

	wg.Wait()
}

func views() ([]view.View, error) {
	var vs []view.View
	v, err := view.New(
		view.MatchInstrumentName("db.cassandra.rows"),
		view.WithSetAggregation(aggregation.ExplicitBucketHistogram{
			Boundaries: []float64{0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10},
		}),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	v, err = view.New(
		view.MatchInstrumentName("db.cassandra.latency"),
		view.WithSetAggregation(aggregation.ExplicitBucketHistogram{
			Boundaries: []float64{0.001, 0.01, 0.1, 0.5, 1, 2, 5, 10},
		}),
	)
	if err != nil {
		return nil, err
	}
	vs = append(vs, v)

	return vs, nil
}

func initMetrics() error {
	vs, err := views()
	if err != nil {
		return err
	}

	exporter, err := otelprom.New()
	if err != nil {
		return err
	}
	provider := metric.NewMeterProvider(metric.WithReader(exporter, vs...))
	global.SetMeterProvider(provider)

	http.Handle("/", promhttp.Handler())
	log.Print("Serving metrics at :2222/")
	go func() {
		err := http.ListenAndServe(":2222", nil)
		if err != nil {
			log.Print(err)
		}
	}()

	ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
	wg.Add(1)
	go func() {
		defer wg.Done()
		<-ctx.Done()
		err := provider.Shutdown(context.Background())
		if err != nil {
			log.Printf("error stopping MeterProvider: %s", err)
		}
	}()
	return nil
}

func initTracer() (*trace.TracerProvider, error) {
	exporter, err := zipkin.New("http://localhost:9411/api/v2/spans")
	if err != nil {
		return nil, err
	}

	tp := trace.NewTracerProvider(trace.WithBatcher(exporter))
	otel.SetTracerProvider(tp)

	return tp, nil
}

func initDb() error {
	cluster := gocql.NewCluster("127.0.0.1")
	cluster.Keyspace = "system"
	cluster.Consistency = gocql.LocalQuorum
	cluster.Timeout = time.Second * 2
	session, err := cluster.CreateSession()
	if err != nil {
		return err
	}
	stmt := fmt.Sprintf(
		"create keyspace if not exists %s with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }",
		keyspace,
	)
	if err := session.Query(stmt).Exec(); err != nil {
		return err
	}

	cluster.Keyspace = keyspace
	session, err = cluster.CreateSession()
	if err != nil {
		return err
	}

	stmt = "create table if not exists book(id UUID, title text, author_first_name text, author_last_name text, PRIMARY KEY(id))"
	if err = session.Query(stmt).Exec(); err != nil {
		return err
	}

	return session.Query("create index if not exists on book(author_last_name)").Exec()
}

func getCluster() *gocql.ClusterConfig {
	cluster := gocql.NewCluster("127.0.0.1")
	cluster.Keyspace = keyspace
	cluster.Consistency = gocql.LocalQuorum
	cluster.ProtoVersion = 3
	cluster.Timeout = 2 * time.Second
	return cluster
}
<|endoftext|>


<commit_before>package main

import "github.com/dizzyd/gogotelehash"
import "crypto/rand"
import "crypto/rsa"

func main() {
	key, _ := rsa.GenerateKey(rand.Reader, 1024)
	s, _ := telehash.NewSwitch("0.0.0.0:0", key)
}
<commit_msg>Interstitial commit<commit_after>package main

import "crypto/rand"
import "crypto/rsa"
import "fmt"
import "github.com/GeertJohan/go.linenoise"
import "github.com/dizzyd/gogotelehash"
import "log"
import "os"
import "path"

func main() {
	// Initialize data dir, if it doesn't already exist
	configDir := path.Join(os.ExpandEnv("$HOME"), ".thconsole")
	os.Mkdir(configDir, 0700)

	// Setup logging subsystem
	logFilename := path.Join(configDir, "log")
	logFile, err := os.OpenFile(logFilename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Printf("Could not open %s: %s\n", logFilename, err)
		os.Exit(1)
	}
	defer logFile.Close()

	// Direct all logging output to the log file
	log.SetOutput(logFile)
	log.Println("Started thconsole!")

	key, _ := rsa.GenerateKey(rand.Reader, 1024)
	telehash.NewSwitch("0.0.0.0:0", key)

	// Load command line history
	historyFilename := path.Join(configDir, "history")
	linenoise.LoadHistory(historyFilename)
	defer linenoise.SaveHistory(historyFilename)

	defer log.Println("Shutting down...")

	// Start processing commands
	for {
		str, err := linenoise.Line("th> ")
		if err != nil {
			if err == linenoise.KillSignalError {
				return
			}
			fmt.Println("Unexpected error: %s", err)
			return
		}

		switch str {
		case "quit":
			return
		}

		linenoise.AddHistory(str)
		fmt.Printf("Got: %s\n", str)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/gif"
	_ "image/jpeg"
	_ "image/png"
	"os"
	"sort"
)

var (
	frameLimit = flag.Uint("framelimit", 0, "max number of frames. 0 = unlimited")
	backfill   = flag.Bool("backfill", true, "backfill still missing pixels with closest color")
	popsort    = flag.Bool("sort", true, "sort colors by popularity")
)

func init() {
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
		fmt.Println("requires one image as input")
		os.Exit(1)
	}
}

type coord struct {
	X, Y int
}

type colorCount struct {
	C      color.Color
	Coords []coord
}

type colorCountList []colorCount

func (p colorCountList) Len() int           { return len(p) }
func (p colorCountList) Less(i, j int) bool { return len(p[i].Coords) < len(p[j].Coords) }
func (p colorCountList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

func main() {
	file, err := os.Open(flag.Arg(0))
	if err != nil {
		panic(err)
	}

	img, _, err := image.Decode(file)
	if err != nil {
		panic(err)
	}

	b := img.Bounds()
	g := &gif.GIF{}

	colormap := make(map[color.Color][]coord)

	for y := 0; y <= b.Max.Y; y++ {
		for x := 0; x <= b.Max.X; x++ {
			c := img.At(x, y)
			colormap[c] = append(colormap[c], coord{x, y})
		}
	}

	colorhisto := make(colorCountList, 0)
	for c, e := range colormap {
		colorhisto = append(colorhisto, colorCount{c, e})
	}

	if *popsort {
		sort.Sort(sort.Reverse(colorhisto))
	}

	seglen := (len(colorhisto) / 254) + 1
	segments := make([]colorCountList, seglen)

	x := 0
	for _, xxx := range colorhisto {
		n := x / 254 //integer division
		segments[n] = append(segments[n], xxx)

		x++
	}

	limitSeglen := seglen
	if *frameLimit != 0 && int(*frameLimit) < limitSeglen {
		limitSeglen = int(*frameLimit)
	}

	for i := 0; i < limitSeglen; i++ {
		pimg := image.NewPaletted(b, color.Palette{})
		pimg.Palette = append(pimg.Palette, color.Transparent)
		g.Image = append(g.Image, pimg)

		for _, ch := range segments[i] {
			pimg.Palette = append(pimg.Palette, ch.C)
			ind := pimg.Palette.Index(ch.C)

			for _, ccoord := range ch.Coords {
				pimg.SetColorIndex(ccoord.X, ccoord.Y, uint8(ind))
			}
		}

		if *backfill {
			for j := i + 1; j < seglen; j++ {
				for _, ch := range segments[j] {
					ind := pimg.Palette.Index(ch.C)

					for _, ccoord := range ch.Coords {
						pimg.SetColorIndex(ccoord.X, ccoord.Y, uint8(ind))
					}
				}
			}
		}
	}

	g.Delay = make([]int, len(g.Image))
	for i, _ := range g.Delay {
		g.Delay[i] = 0
	}

	out, err := os.Create("out.gif")
	if err != nil {
		panic(err)
	}

	err = gif.EncodeAll(out, g)
	if err != nil {
		panic(err)
	}

	fmt.Println("Output to: out.gif")
	fmt.Printf("Conatins %d frames.\n", len(g.Image))
}
<commit_msg>Removes panics<commit_after>package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/gif"
	_ "image/jpeg"
	_ "image/png"
	"log"
	"os"
	"sort"
)

var (
	frameLimit = flag.Uint("framelimit", 0, "max number of frames. 0 = unlimited")
	backfill   = flag.Bool("backfill", true, "backfill still missing pixels with closest color")
	popsort    = flag.Bool("sort", true, "sort colors by popularity")
)

func init() {
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
		fmt.Println("requires one image as input")
		os.Exit(1)
	}
}

type coord struct {
	X, Y int
}

type colorCount struct {
	C      color.Color
	Coords []coord
}

type colorCountList []colorCount

func (p colorCountList) Len() int           { return len(p) }
func (p colorCountList) Less(i, j int) bool { return len(p[i].Coords) < len(p[j].Coords) }
func (p colorCountList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

func main() {
	file, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}

	img, _, err := image.Decode(file)
	if err != nil {
		log.Fatal(err)
	}

	b := img.Bounds()
	g := &gif.GIF{}

	colormap := make(map[color.Color][]coord)

	for y := 0; y <= b.Max.Y; y++ {
		for x := 0; x <= b.Max.X; x++ {
			c := img.At(x, y)
			colormap[c] = append(colormap[c], coord{x, y})
		}
	}

	colorhisto := make(colorCountList, 0)
	for c, e := range colormap {
		colorhisto = append(colorhisto, colorCount{c, e})
	}

	if *popsort {
		sort.Sort(sort.Reverse(colorhisto))
	}

	seglen := (len(colorhisto) / 254) + 1
	segments := make([]colorCountList, seglen)

	x := 0
	for _, xxx := range colorhisto {
		n := x / 254 //integer division
		segments[n] = append(segments[n], xxx)

		x++
	}

	limitSeglen := seglen
	if *frameLimit != 0 && int(*frameLimit) < limitSeglen {
		limitSeglen = int(*frameLimit)
	}

	for i := 0; i < limitSeglen; i++ {
		pimg := image.NewPaletted(b, color.Palette{})
		pimg.Palette = append(pimg.Palette, color.Transparent)
		g.Image = append(g.Image, pimg)

		for _, ch := range segments[i] {
			pimg.Palette = append(pimg.Palette, ch.C)
			ind := pimg.Palette.Index(ch.C)

			for _, ccoord := range ch.Coords {
				pimg.SetColorIndex(ccoord.X, ccoord.Y, uint8(ind))
			}
		}

		if *backfill {
			for j := i + 1; j < seglen; j++ {
				for _, ch := range segments[j] {
					ind := pimg.Palette.Index(ch.C)

					for _, ccoord := range ch.Coords {
						pimg.SetColorIndex(ccoord.X, ccoord.Y, uint8(ind))
					}
				}
			}
		}
	}

	g.Delay = make([]int, len(g.Image))
	for i, _ := range g.Delay {
		g.Delay[i] = 0
	}

	out, err := os.Create("out.gif")
	if err != nil {
		log.Fatal(err)
	}

	err = gif.EncodeAll(out, g)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Output to: out.gif")
	fmt.Printf("Conatins %d frames.\n", len(g.Image))
}
<|endoftext|>


<commit_before>package webgo

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"time"
	//"sync"
)

type App struct {
	router        Router
	definitions   Definitions
	templates     *template.Template
	staticDir     string
	modules       Modules
	workDir       string
	tmpDir        string
	maxBodyLength int64
}

const (
	CT_JSON      = "application/json"
	CT_FORM      = "application/x-www-form-urlencoded"
	CT_MULTIPART = "multipart/form-data"
)

var app App
var LOGGER *Logger

func init() {

	// Init LOGGER
	LOGGER = NewLogger()

	cp := consoleProvider{}
	ep := emailProvider{}

	LOGGER.RegisterProvider(cp)
	LOGGER.RegisterProvider(ep)

	LOGGER.AddLogProvider(PROVIDER_CONSOLE)
	LOGGER.AddErrorProvider(PROVIDER_CONSOLE, PROVIDER_EMAIL)
	LOGGER.AddFatalProvider(PROVIDER_CONSOLE, PROVIDER_EMAIL)
	LOGGER.AddDebugProvider(PROVIDER_CONSOLE)

	// Init App
	templates := template.New("template")
	filepath.Walk("templates", func(path string, info os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".html") {
			templates.ParseFiles(path)
		}
		return nil
	})
	app = App{}
	app.router = Router{make(Routes)}
	app.definitions = Definitions{}
	app.templates = templates
	app.staticDir = "public"
	app.modules = Modules{}

	app.workDir, _ = os.Getwd()
	app.tmpDir = app.workDir + "/tmp"
	app.maxBodyLength = 131072

	//TODO: Проверить папку tmp, создать если необходимо
}

func parseRequest(ctx *Context, limit int64) (errorCode int, err error) {
	var body []byte

	defer func() {
		r := recover()
		if r != nil {
			errorCode = 400
			err = errors.New("Bad Request")
		}
	}()
	ctx.Request.Body = http.MaxBytesReader(ctx.Response, ctx.Request.Body, limit)

	if ctx.Request.Method == "GET" {
		err = ctx.Request.ParseForm()
		if err != nil {
			errorCode = 400
			return
		}

		// Копируем данные
		for i := range ctx.Request.Form {
			ctx.Query[i] = ctx.Request.Form[i]
		}

		return
	}

	switch ctx.ContentType {
	case CT_JSON:
		body, err = ioutil.ReadAll(ctx.Request.Body)
		if err != nil {
			errorCode = 400
			return
		}

		var data interface{}
		err = json.Unmarshal(body, &data)
		if err != nil {
			errorCode = 400
			return
		}
		ctx._Body = body
		ctx.Body = data.(map[string]interface{})

		return
	case CT_FORM:
		err = ctx.Request.ParseForm()
		if err != nil {
			errorCode = 400
			return
		}

	case CT_MULTIPART:
		err = ctx.Request.ParseMultipartForm(limit)
		if err != nil {
			//TODO: 400 or 413
			errorCode = 400
			return
		}

		for _, fheaders := range ctx.Request.MultipartForm.File {
			for _, hdr := range fheaders {
				var infile multipart.File
				if infile, err = hdr.Open(); nil != err {
					errorCode = 500
					return
				}

				var outfile *os.File
				if outfile, err = os.Create(app.tmpDir + "/" + hdr.Filename); nil != err {
					errorCode = 500
					return
				}
				// 32K buffer copy
				var written int64
				if written, err = io.Copy(outfile, infile); nil != err {
					errorCode = 500
					return
				}

				ctx.Files = append(ctx.Files, File{FileName: hdr.Filename, Size: int64(written)})
			}
		}

	default:
		err = errors.New("Bad Request")
		errorCode = 400
		return
	}

	for i := range ctx.Request.Form {
		ctx.Body[i] = ctx.Request.Form[i]
	}

	return
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//cn, ok := w.(http.CloseNotifier)
	//if !ok {
	//	LOGGER.Fatal("don't support CloseNotifier")
	//}

	var vc reflect.Value
	var Action reflect.Value
	var middlewareGroup string

	method := r.Method
	path := r.URL.Path

	// TODO как отдавать статику?
	/*// Отдаем статику если был запрошен файл
	ext := filepath.Ext(path)
	if ext != "" {
		http.ServeFile(w, r, app.staticDir+filepath.Clean(path))
		return
	}*/

	if len(path) > 1 && path[len(path)-1:] == "/" {
		http.Redirect(w, r, path[:len(path)-1], 301)
		return
	}

	route := a.router.Match(method, path)
	if route == nil {
		http.Error(w, "", 404)
		return
	}

	if route.Options.Timeout == 0 {
		route.Options.Timeout = 2
	}
	//timeout := time.After(route.Options.Timeout * time.Second)
	//done := make(chan bool)

	vc = reflect.New(route.ControllerType)
	Action = vc.MethodByName(route.Options.Action)
	middlewareGroup = route.Options.MiddlewareGroup

	var err error
	ctx := Context{Action: route.Options.Action, Response: w, Request: r, Query: make(map[string]interface{}), Body: make(map[string]interface{}), Params: route.Params, Method: method}
	ctx.ContentType = ctx.Request.Header.Get("Content-Type")
	ctx.ContentType, _, err = mime.ParseMediaType(ctx.ContentType)

	if err != nil && method != "GET" {
		http.Error(w, "", 400)
		return
	}

	if route.Options.ContentType != "" && (method == "POST" || method == "PUT") {
		if route.Options.ContentType != ctx.ContentType {
			http.Error(w, "", 400)
			return
		}
	}

	Controller, ok := vc.Interface().(ControllerInterface)
	if !ok {
		LOGGER.Error(errors.New("controller is not ControllerInterface"))
		http.Error(w, "", 500)
		return
	}

	// Парсим запрос
	var maxBodyLength int64 = app.maxBodyLength
	if route.Options.BodyLength > 0 {
		maxBodyLength = route.Options.BodyLength
	}

	code, err := parseRequest(&ctx, maxBodyLength)
	if err != nil {
		http.Error(w, "", code)
		return
	}

	// Инициализация контекста
	Controller.Init(&ctx)

	// Запуск предобработчика
	if !Controller.Prepare() {
		Controller.exec()
		return
	}

	// Запуск цепочки middleware
	if middlewareGroup != "" {
		isNext := app.definitions.Run(middlewareGroup, &ctx)
		if !isNext {
			return
		}
	}

	in := make([]reflect.Value, 0)
	Action.Call(in)
	//go func () {
	//	in := make([]reflect.Value, 0)
	//	Action.Call(in)
	//	done <- true
	//}()

	// Запуск постобработчика

	Controller.Finish()

	if ctx.ContentType == "multipart/form-data" {
		err = ctx.Files.RemoveAll()
		if err != nil {
			LOGGER.Error(err)
		}

		err = ctx.Request.MultipartForm.RemoveAll()
		if err != nil {
			LOGGER.Error(err)
		}
	}

	Controller.exec()

	//select {
	//case <-timeout:
	//	ctx.close = true
	//	w.WriteHeader(503)
	//	w.Write([]byte(""))
	//	return
	//case <-cn.CloseNotify():
	//	//TODO: НИХРЕНА НЕПОНЯТНО!!!
	//	ctx.close = true
	//	w.WriteHeader(503)
	//	w.Write([]byte(""))
	//	return
	//case <-done:
	//	// TODO: Обработать ошибки
	//	if ctx.error != nil {
	//		if ctx.code == 0 {
	//			ctx.code = 500
	//		}
	//		ctx.Response.WriteHeader(ctx.code)
	//		ctx.Response.Write(ctx.output)
	//		return
	//	}
	//
	//	// Проверяем редирект
	//	if ctx.IsRedirect(){
	//		ctx.Response.WriteHeader(ctx.code)
	//		return
	//	}
	//
	//	// Выводим данные
	//	if ctx.code == 0 {
	//		ctx.code = 200
	//	}
	//	ctx.Response.WriteHeader(ctx.code)
	//	ctx.Response.Write(ctx.output)
	//	return
	//}

}

func RegisterMiddleware(name string, plugins ...MiddlewareInterface) {
	for _, plugin := range plugins {
		app.definitions.Register(name, plugin)
	}
}
func RegisterModule(name string, module ModuleInterface) {
	app.modules.RegisterModule(name, module)
}
func Get(url string, opts RouteOptions) {
	app.router.addRoute("GET", url, &opts)
}
func Post(url string, opts RouteOptions) {
	app.router.addRoute("POST", url, &opts)
}
func Put(url string, opts RouteOptions) {
	app.router.addRoute("PUT", url, &opts)
}
func Delete(url string, opts RouteOptions) {
	app.router.addRoute("DELETE", url, &opts)
}
func Options(url string, opts RouteOptions) {
	app.router.addRoute("OPTIONS", url, &opts)
}

func GetModule(str string) ModuleInterface {
	return app.modules[str]
}

func Run() {
	var r *int = flag.Int("r", 0, "read timeout")
	var w *int = flag.Int("w", 0, "write timeout")

	port := CFG.Int("port")

	if port == 0 {
		port = 80
	}

	host := CFG.Str("host")
	if host == "" {
		host = "127.0.0.1"
	}

	address := fmt.Sprintf("%s:%d", host, port)
	fmt.Println("WebGO start ", address)

	server := http.Server{
		Addr:         address,
		ReadTimeout:  time.Duration(*r) * time.Second,
		WriteTimeout: time.Duration(*w) * time.Second,
		Handler:      &app,
	}

	//server.SetKeepAlivesEnabled(false)

	err := server.ListenAndServe()
	if err != nil {
		LOGGER.Fatal(err)
	}

}
<commit_msg>Add GetRoutes()<commit_after>package webgo

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"time"
	//"sync"
)

type App struct {
	router        Router
	definitions   Definitions
	templates     *template.Template
	staticDir     string
	modules       Modules
	workDir       string
	tmpDir        string
	maxBodyLength int64
}

const (
	CT_JSON      = "application/json"
	CT_FORM      = "application/x-www-form-urlencoded"
	CT_MULTIPART = "multipart/form-data"
)

var app App
var LOGGER *Logger

func init() {

	// Init LOGGER
	LOGGER = NewLogger()

	cp := consoleProvider{}
	ep := emailProvider{}

	LOGGER.RegisterProvider(cp)
	LOGGER.RegisterProvider(ep)

	LOGGER.AddLogProvider(PROVIDER_CONSOLE)
	LOGGER.AddErrorProvider(PROVIDER_CONSOLE, PROVIDER_EMAIL)
	LOGGER.AddFatalProvider(PROVIDER_CONSOLE, PROVIDER_EMAIL)
	LOGGER.AddDebugProvider(PROVIDER_CONSOLE)

	// Init App
	templates := template.New("template")
	filepath.Walk("templates", func(path string, info os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".html") {
			templates.ParseFiles(path)
		}
		return nil
	})
	app = App{}
	app.router = Router{make(Routes)}
	app.definitions = Definitions{}
	app.templates = templates
	app.staticDir = "public"
	app.modules = Modules{}

	app.workDir, _ = os.Getwd()
	app.tmpDir = app.workDir + "/tmp"
	app.maxBodyLength = 131072

	//TODO: Проверить папку tmp, создать если необходимо
}

func parseRequest(ctx *Context, limit int64) (errorCode int, err error) {
	var body []byte

	defer func() {
		r := recover()
		if r != nil {
			errorCode = 400
			err = errors.New("Bad Request")
		}
	}()
	ctx.Request.Body = http.MaxBytesReader(ctx.Response, ctx.Request.Body, limit)

	if ctx.Request.Method == "GET" {
		err = ctx.Request.ParseForm()
		if err != nil {
			errorCode = 400
			return
		}

		// Копируем данные
		for i := range ctx.Request.Form {
			ctx.Query[i] = ctx.Request.Form[i]
		}

		return
	}

	switch ctx.ContentType {
	case CT_JSON:
		body, err = ioutil.ReadAll(ctx.Request.Body)
		if err != nil {
			errorCode = 400
			return
		}

		var data interface{}
		err = json.Unmarshal(body, &data)
		if err != nil {
			errorCode = 400
			return
		}
		ctx._Body = body
		ctx.Body = data.(map[string]interface{})

		return
	case CT_FORM:
		err = ctx.Request.ParseForm()
		if err != nil {
			errorCode = 400
			return
		}

	case CT_MULTIPART:
		err = ctx.Request.ParseMultipartForm(limit)
		if err != nil {
			//TODO: 400 or 413
			errorCode = 400
			return
		}

		for _, fheaders := range ctx.Request.MultipartForm.File {
			for _, hdr := range fheaders {
				var infile multipart.File
				if infile, err = hdr.Open(); nil != err {
					errorCode = 500
					return
				}

				var outfile *os.File
				if outfile, err = os.Create(app.tmpDir + "/" + hdr.Filename); nil != err {
					errorCode = 500
					return
				}
				// 32K buffer copy
				var written int64
				if written, err = io.Copy(outfile, infile); nil != err {
					errorCode = 500
					return
				}

				ctx.Files = append(ctx.Files, File{FileName: hdr.Filename, Size: int64(written)})
			}
		}

	default:
		err = errors.New("Bad Request")
		errorCode = 400
		return
	}

	for i := range ctx.Request.Form {
		ctx.Body[i] = ctx.Request.Form[i]
	}

	return
}

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//cn, ok := w.(http.CloseNotifier)
	//if !ok {
	//	LOGGER.Fatal("don't support CloseNotifier")
	//}

	var vc reflect.Value
	var Action reflect.Value
	var middlewareGroup string

	method := r.Method
	path := r.URL.Path

	// TODO как отдавать статику?
	/*// Отдаем статику если был запрошен файл
	ext := filepath.Ext(path)
	if ext != "" {
		http.ServeFile(w, r, app.staticDir+filepath.Clean(path))
		return
	}*/

	if len(path) > 1 && path[len(path)-1:] == "/" {
		http.Redirect(w, r, path[:len(path)-1], 301)
		return
	}

	route := a.router.Match(method, path)
	if route == nil {
		http.Error(w, "", 404)
		return
	}

	if route.Options.Timeout == 0 {
		route.Options.Timeout = 2
	}
	//timeout := time.After(route.Options.Timeout * time.Second)
	//done := make(chan bool)

	vc = reflect.New(route.ControllerType)
	Action = vc.MethodByName(route.Options.Action)
	middlewareGroup = route.Options.MiddlewareGroup

	var err error
	ctx := Context{Action: route.Options.Action, Response: w, Request: r, Query: make(map[string]interface{}), Body: make(map[string]interface{}), Params: route.Params, Method: method}
	ctx.ContentType = ctx.Request.Header.Get("Content-Type")
	ctx.ContentType, _, err = mime.ParseMediaType(ctx.ContentType)

	if err != nil && method != "GET" {
		http.Error(w, "", 400)
		return
	}

	if route.Options.ContentType != "" && (method == "POST" || method == "PUT") {
		if route.Options.ContentType != ctx.ContentType {
			http.Error(w, "", 400)
			return
		}
	}

	Controller, ok := vc.Interface().(ControllerInterface)
	if !ok {
		LOGGER.Error(errors.New("controller is not ControllerInterface"))
		http.Error(w, "", 500)
		return
	}

	// Парсим запрос
	var maxBodyLength int64 = app.maxBodyLength
	if route.Options.BodyLength > 0 {
		maxBodyLength = route.Options.BodyLength
	}

	code, err := parseRequest(&ctx, maxBodyLength)
	if err != nil {
		http.Error(w, "", code)
		return
	}

	// Инициализация контекста
	Controller.Init(&ctx)

	// Запуск предобработчика
	if !Controller.Prepare() {
		Controller.exec()
		return
	}

	// Запуск цепочки middleware
	if middlewareGroup != "" {
		isNext := app.definitions.Run(middlewareGroup, &ctx)
		if !isNext {
			return
		}
	}

	in := make([]reflect.Value, 0)
	Action.Call(in)
	//go func () {
	//	in := make([]reflect.Value, 0)
	//	Action.Call(in)
	//	done <- true
	//}()

	// Запуск постобработчика

	Controller.Finish()

	if ctx.ContentType == "multipart/form-data" {
		err = ctx.Files.RemoveAll()
		if err != nil {
			LOGGER.Error(err)
		}

		err = ctx.Request.MultipartForm.RemoveAll()
		if err != nil {
			LOGGER.Error(err)
		}
	}

	Controller.exec()

	//select {
	//case <-timeout:
	//	ctx.close = true
	//	w.WriteHeader(503)
	//	w.Write([]byte(""))
	//	return
	//case <-cn.CloseNotify():
	//	//TODO: НИХРЕНА НЕПОНЯТНО!!!
	//	ctx.close = true
	//	w.WriteHeader(503)
	//	w.Write([]byte(""))
	//	return
	//case <-done:
	//	// TODO: Обработать ошибки
	//	if ctx.error != nil {
	//		if ctx.code == 0 {
	//			ctx.code = 500
	//		}
	//		ctx.Response.WriteHeader(ctx.code)
	//		ctx.Response.Write(ctx.output)
	//		return
	//	}
	//
	//	// Проверяем редирект
	//	if ctx.IsRedirect(){
	//		ctx.Response.WriteHeader(ctx.code)
	//		return
	//	}
	//
	//	// Выводим данные
	//	if ctx.code == 0 {
	//		ctx.code = 200
	//	}
	//	ctx.Response.WriteHeader(ctx.code)
	//	ctx.Response.Write(ctx.output)
	//	return
	//}

}

func RegisterMiddleware(name string, plugins ...MiddlewareInterface) {
	for _, plugin := range plugins {
		app.definitions.Register(name, plugin)
	}
}
func RegisterModule(name string, module ModuleInterface) {
	app.modules.RegisterModule(name, module)
}
func Get(url string, opts RouteOptions) {
	app.router.addRoute("GET", url, &opts)
}
func Post(url string, opts RouteOptions) {
	app.router.addRoute("POST", url, &opts)
}
func Put(url string, opts RouteOptions) {
	app.router.addRoute("PUT", url, &opts)
}
func Delete(url string, opts RouteOptions) {
	app.router.addRoute("DELETE", url, &opts)
}
func Options(url string, opts RouteOptions) {
	app.router.addRoute("OPTIONS", url, &opts)
}

func GetModule(str string) ModuleInterface {
	return app.modules[str]
}

func GetRoutes() (routes map[string][]string) {

	routes = make(map[string][]string)

	for key, val := range app.router.routes {
		if routes[key] == nil {
			routes[key] = make([]string, 0)
		}

		for _, route := range val {
			routes[key] = append(routes[key], route.Options.Action)
		}
	}

	return
}

func Run() {
	var r *int = flag.Int("r", 0, "read timeout")
	var w *int = flag.Int("w", 0, "write timeout")

	port := CFG.Int("port")

	if port == 0 {
		port = 80
	}

	host := CFG.Str("host")
	if host == "" {
		host = "127.0.0.1"
	}

	address := fmt.Sprintf("%s:%d", host, port)
	fmt.Println("WebGO start ", address)

	server := http.Server{
		Addr:         address,
		ReadTimeout:  time.Duration(*r) * time.Second,
		WriteTimeout: time.Duration(*w) * time.Second,
		Handler:      &app,
	}

	//server.SetKeepAlivesEnabled(false)

	err := server.ListenAndServe()
	if err != nil {
		LOGGER.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package apiserver

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	log "github.com/Sirupsen/logrus"
	types "github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/volume"
)

const (
	// VolumeDriver is the string returned in the handshake protocol.
	VolumeDriver = "VolumeDriver"
)

// Implementation of the Docker volumes plugin specification.
type driver struct {
	restBase
}

type handshakeResp struct {
	Implements []string
}

type volumeRequest struct {
	Name string
}

type volumeResponse struct {
	Err error
}
type volumePathResponse struct {
	Mountpoint string
	Err        error
}

type volumeInfo struct {
	vol *types.Volume
}

func newVolumePlugin(name string) restServer {
	return &driver{restBase{name: name, version: "0.3"}}
}

func (d *driver) String() string {
	return d.name
}

func volDriverPath(method string) string {
	return fmt.Sprintf("/%s.%s", VolumeDriver, method)
}

func (d *driver) Routes() []*Route {
	return []*Route{
		&Route{verb: "POST", path: volDriverPath("Create"), fn: d.create},
		&Route{verb: "POST", path: volDriverPath("Remove"), fn: d.remove},
		&Route{verb: "POST", path: volDriverPath("Mount"), fn: d.mount},
		&Route{verb: "POST", path: volDriverPath("Path"), fn: d.path},
		&Route{verb: "POST", path: volDriverPath("Unmount"), fn: d.unmount},
		&Route{verb: "POST", path: "/Plugin.Activate", fn: d.handshake},
		&Route{verb: "GET", path: "/status", fn: d.status},
	}
}

func (d *driver) emptyResponse(w http.ResponseWriter) {
	json.NewEncoder(w).Encode(&volumeResponse{})
}

func (d *driver) volFromName(name string) (*volumeInfo, error) {
	v, err := volume.Get(d.name)
	if err != nil {
		log.Warn("Cannot locate volume driver for %s", d.name)
		return nil, err
	}
	volumes, err := v.Inspect([]types.VolumeID{types.VolumeID(name)})
	if err != nil || len(volumes) == 0 {
		log.Warn("Cannot locate volume %s", name)
		return nil, err
	}
	return &volumeInfo{vol: &volumes[0]}, nil
}

func (d *driver) decode(method string, w http.ResponseWriter, r *http.Request) (*volumeRequest, error) {
	var request volumeRequest
	err := json.NewDecoder(r.Body).Decode(&request)
	if err != nil {
		log.Warn("Cannot decode request.", err)
		e := fmt.Errorf("Unable to decode JSON payload")
		d.sendError(method, "", w, e.Error()+":"+err.Error(), http.StatusBadRequest)
		return nil, e
	}
	d.logReq(method, request.Name).Debug()
	return &request, nil
}

func (d *driver) handshake(w http.ResponseWriter, r *http.Request) {
	err := json.NewEncoder(w).Encode(&handshakeResp{
		[]string{VolumeDriver},
	})
	if err != nil {
		d.sendError("handshake", "", w, "encode error", http.StatusInternalServerError)
		return
	}
	d.logReq("handshake", "").Info("Handshake completed")
}

func (d *driver) status(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, fmt.Sprintln("osd plugin", d.version))
}

func (d *driver) create(w http.ResponseWriter, r *http.Request) {
	method := "create"

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	log.Info("Plugin instructed to create volume ", request.Name)

	// It is an error if the volume doesn't already exist.
	_, err = d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumeResponse{Err: e})
		return
	}

	json.NewEncoder(w).Encode(&volumeResponse{})
}

func (d *driver) remove(w http.ResponseWriter, r *http.Request) {
	method := "remove"

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	log.Info("Plugin instructed to remove volume ", request.Name)

	// It is an error if the volume doesn't exist.
	_, err = d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumeResponse{Err: e})
		return
	}

	json.NewEncoder(w).Encode(&volumeResponse{})
}

func (d *driver) mount(w http.ResponseWriter, r *http.Request) {
	var response volumePathResponse
	method := "mount"

	v, err := volume.Get(d.name)
	if err != nil {
		log.Warnf("Cannot locate volume driver for %+v", d.name)
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	request, err := d.decode(method, w, r)
	if err != nil {
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	log.Info("Plugin instructed to mount volume ", request.Name)

	volInfo, err := d.volFromName(request.Name)
	if err != nil {
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	// If this is a block driver, first attach the volume.
	if v.Type() == volume.Block {
		_, err = v.Attach(volInfo.vol.ID)
		if err != nil {
			log.Warnf("Cannot attach volume %+v, %+v", volInfo.vol.ID, err)
			json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
			return
		}
		log.Infof("Volume %+v attached", volInfo.vol.ID)
	}

	// Now mount it.
	response.Mountpoint = fmt.Sprintf("/mnt/%s", request.Name)
	os.MkdirAll(response.Mountpoint, 0755)

	err = v.Mount(volInfo.vol.ID, response.Mountpoint)
	if err != nil {
		log.Warnf("Cannot mount volume %+v at %+v, %+v", volInfo.vol.ID, response.Mountpoint, err)
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	log.Infof("Volume %+v mounted at %+v", volInfo.vol.ID, response.Mountpoint)

	d.logReq(method, request.Name).Debugf("response %v", response.Mountpoint)
	json.NewEncoder(w).Encode(&response)
}

func (d *driver) path(w http.ResponseWriter, r *http.Request) {
	method := "path"
	var response volumePathResponse

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	volInfo, err := d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumePathResponse{Err: e})
		return
	}

	log.Info("Plugin requested to resolve the path for volume ", request.Name)

	response.Mountpoint = volInfo.vol.AttachPath
	d.logReq(method, request.Name).Debugf("response %v", response.Mountpoint)
	json.NewEncoder(w).Encode(&response)
}

func (d *driver) unmount(w http.ResponseWriter, r *http.Request) {
	method := "unmount"

	v, err := volume.Get(d.name)
	if err != nil {
		log.Warn("Cannot locate volume driver for %s", d.name)
		json.NewEncoder(w).Encode(&volumeResponse{Err: err})
		return
	}

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	log.Info("Plugin instructed to unmount volume ", request.Name)

	volInfo, err := d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumeResponse{Err: e})
		return
	}

	if v.Type() == volume.Block {
		err = v.Detach(volInfo.vol.ID)
		if err != nil {
			log.Warnf("Cannot detach volume %+v, %+v", volInfo.vol.ID, err)
			d.logReq(request.Name, method).Warnf("%s", err.Error())
			json.NewEncoder(w).Encode(&volumeResponse{Err: err})
			return
		}
	}

	// XXX TODO unmount
	// log.Infof("Volume %+v mounted at %+v", volInfo, response.Mountpoint)

	d.emptyResponse(w)
}
<commit_msg>Fix log statements<commit_after>package apiserver

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	log "github.com/Sirupsen/logrus"
	types "github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/volume"
)

const (
	// VolumeDriver is the string returned in the handshake protocol.
	VolumeDriver = "VolumeDriver"
)

// Implementation of the Docker volumes plugin specification.
type driver struct {
	restBase
}

type handshakeResp struct {
	Implements []string
}

type volumeRequest struct {
	Name string
}

type volumeResponse struct {
	Err error
}
type volumePathResponse struct {
	Mountpoint string
	Err        error
}

type volumeInfo struct {
	vol *types.Volume
}

func newVolumePlugin(name string) restServer {
	return &driver{restBase{name: name, version: "0.3"}}
}

func (d *driver) String() string {
	return d.name
}

func volDriverPath(method string) string {
	return fmt.Sprintf("/%s.%s", VolumeDriver, method)
}

func (d *driver) Routes() []*Route {
	return []*Route{
		&Route{verb: "POST", path: volDriverPath("Create"), fn: d.create},
		&Route{verb: "POST", path: volDriverPath("Remove"), fn: d.remove},
		&Route{verb: "POST", path: volDriverPath("Mount"), fn: d.mount},
		&Route{verb: "POST", path: volDriverPath("Path"), fn: d.path},
		&Route{verb: "POST", path: volDriverPath("Unmount"), fn: d.unmount},
		&Route{verb: "POST", path: "/Plugin.Activate", fn: d.handshake},
		&Route{verb: "GET", path: "/status", fn: d.status},
	}
}

func (d *driver) emptyResponse(w http.ResponseWriter) {
	json.NewEncoder(w).Encode(&volumeResponse{})
}

func (d *driver) volFromName(name string) (*volumeInfo, error) {
	v, err := volume.Get(d.name)
	if err != nil {
		log.Warn("Cannot locate volume driver for %s", d.name)
		return nil, err
	}
	volumes, err := v.Inspect([]types.VolumeID{types.VolumeID(name)})
	if err != nil || len(volumes) == 0 {
		log.Warn("Cannot locate volume %s", name)
		return nil, err
	}
	return &volumeInfo{vol: &volumes[0]}, nil
}

func (d *driver) decode(method string, w http.ResponseWriter, r *http.Request) (*volumeRequest, error) {
	var request volumeRequest
	err := json.NewDecoder(r.Body).Decode(&request)
	if err != nil {
		log.Warn("Cannot decode request.", err)
		e := fmt.Errorf("Unable to decode JSON payload")
		d.sendError(method, "", w, e.Error()+":"+err.Error(), http.StatusBadRequest)
		return nil, e
	}
	d.logReq(method, request.Name).Debug()
	return &request, nil
}

func (d *driver) handshake(w http.ResponseWriter, r *http.Request) {
	err := json.NewEncoder(w).Encode(&handshakeResp{
		[]string{VolumeDriver},
	})
	if err != nil {
		d.sendError("handshake", "", w, "encode error", http.StatusInternalServerError)
		return
	}
	d.logReq("handshake", "").Info("Handshake completed")
}

func (d *driver) status(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, fmt.Sprintln("osd plugin", d.version))
}

func (d *driver) create(w http.ResponseWriter, r *http.Request) {
	method := "create"

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	d.logReq(method, request.Name).Info("")

	// It is an error if the volume doesn't already exist.
	_, err = d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumeResponse{Err: e})
		return
	}

	json.NewEncoder(w).Encode(&volumeResponse{})
}

func (d *driver) remove(w http.ResponseWriter, r *http.Request) {
	method := "remove"

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	d.logReq(method, request.Name).Info("")

	// It is an error if the volume doesn't exist.
	_, err = d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumeResponse{Err: e})
		return
	}

	json.NewEncoder(w).Encode(&volumeResponse{})
}

func (d *driver) mount(w http.ResponseWriter, r *http.Request) {
	var response volumePathResponse
	method := "mount"

	v, err := volume.Get(d.name)
	if err != nil {
		log.Warnf("Cannot locate volume driver for %+v", d.name)
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	request, err := d.decode(method, w, r)
	if err != nil {
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	d.logReq(method, request.Name).Info("")

	volInfo, err := d.volFromName(request.Name)
	if err != nil {
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	// If this is a block driver, first attach the volume.
	if v.Type() == volume.Block {
		_, err = v.Attach(volInfo.vol.ID)
		if err != nil {
			log.Warnf("Cannot attach volume %+v, %+v", volInfo.vol.ID, err)
			json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
			return
		}
		log.Infof("Volume %+v attached", volInfo.vol.ID)
	}

	// Now mount it.
	response.Mountpoint = fmt.Sprintf("/mnt/%s", request.Name)
	os.MkdirAll(response.Mountpoint, 0755)

	err = v.Mount(volInfo.vol.ID, response.Mountpoint)
	if err != nil {
		log.Warnf("Cannot mount volume %+v at %+v, %+v", volInfo.vol.ID, response.Mountpoint, err)
		json.NewEncoder(w).Encode(&volumePathResponse{Err: err})
		return
	}

	log.Infof("Volume %+v mounted at %+v", volInfo.vol.ID, response.Mountpoint)

	d.logReq(method, request.Name).Debugf("response %v", response.Mountpoint)
	json.NewEncoder(w).Encode(&response)
}

func (d *driver) path(w http.ResponseWriter, r *http.Request) {
	method := "path"
	var response volumePathResponse

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	volInfo, err := d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumePathResponse{Err: e})
		return
	}

	d.logReq(method, request.Name).Info("")

	response.Mountpoint = volInfo.vol.AttachPath
	d.logReq(method, request.Name).Debugf("response %v", response.Mountpoint)
	json.NewEncoder(w).Encode(&response)
}

func (d *driver) unmount(w http.ResponseWriter, r *http.Request) {
	method := "unmount"

	v, err := volume.Get(d.name)
	if err != nil {
		log.Warn("Cannot locate volume driver for %s", d.name)
		json.NewEncoder(w).Encode(&volumeResponse{Err: err})
		return
	}

	request, err := d.decode(method, w, r)
	if err != nil {
		return
	}

	d.logReq(method, request.Name).Info("")

	volInfo, err := d.volFromName(request.Name)
	if err != nil {
		e := d.volNotFound(method, request.Name, err, w)
		json.NewEncoder(w).Encode(&volumeResponse{Err: e})
		return
	}

	if v.Type() == volume.Block {
		err = v.Detach(volInfo.vol.ID)
		if err != nil {
			log.Warnf("Cannot detach volume %+v, %+v", volInfo.vol.ID, err)
			d.logReq(request.Name, method).Warnf("%s", err.Error())
			json.NewEncoder(w).Encode(&volumeResponse{Err: err})
			return
		}
	}

	// XXX TODO unmount
	// log.Infof("Volume %+v mounted at %+v", volInfo, response.Mountpoint)

	d.emptyResponse(w)
}
<|endoftext|>


<commit_before>package torrent

import (
	"sync"

	"github.com/anacrolix/missinggo/bitmap"

	"github.com/anacrolix/torrent/metainfo"
	pp "github.com/anacrolix/torrent/peer_protocol"
	"github.com/anacrolix/torrent/storage"
)

// Piece priority describes the importance of obtaining a particular piece.

type piecePriority byte

func (pp *piecePriority) Raise(maybe piecePriority) {
	if maybe > *pp {
		*pp = maybe
	}
}

const (
	PiecePriorityNone      piecePriority = iota // Not wanted.
	PiecePriorityNormal                         // Wanted.
	PiecePriorityReadahead                      // May be required soon.
	PiecePriorityNext                           // Succeeds a piece where a read occurred.
	PiecePriorityNow                            // A Reader is reading in this piece.
)

type piece struct {
	// The completed piece SHA1 hash, from the metainfo "pieces" field.
	Hash  metainfo.Hash
	t     *Torrent
	index int
	// Chunks we've written to since the last check. The chunk offset and
	// length can be determined by the request chunkSize in use.
	DirtyChunks      bitmap.Bitmap
	Hashing          bool
	QueuedForHash    bool
	EverHashed       bool
	PublicPieceState PieceState
	priority         piecePriority

	pendingWritesMutex sync.Mutex
	pendingWrites      int
	noPendingWrites    sync.Cond
}

func (p *piece) Info() metainfo.Piece {
	return p.t.info.Piece(p.index)
}

func (p *piece) Storage() storage.Piece {
	return p.t.storage.Piece(p.Info())
}

func (p *piece) pendingChunkIndex(chunkIndex int) bool {
	return !p.DirtyChunks.Contains(chunkIndex)
}

func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
	return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
}

func (p *piece) hasDirtyChunks() bool {
	return p.DirtyChunks.Len() != 0
}

func (p *piece) numDirtyChunks() (ret int) {
	return p.DirtyChunks.Len()
}

func (p *piece) unpendChunkIndex(i int) {
	p.DirtyChunks.Add(i)
}

func (p *piece) pendChunkIndex(i int) {
	p.DirtyChunks.Remove(i)
}

func (p *piece) numChunks() int {
	return p.t.pieceNumChunks(p.index)
}

func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
	ret = p.DirtyChunks.Copy()
	ret.FlipRange(0, p.numChunks())
	return
}

func (p *piece) incrementPendingWrites() {
	p.pendingWritesMutex.Lock()
	p.pendingWrites++
	p.pendingWritesMutex.Unlock()
}

func (p *piece) decrementPendingWrites() {
	p.pendingWritesMutex.Lock()
	if p.pendingWrites == 0 {
		panic("assertion")
	}
	p.pendingWrites--
	if p.pendingWrites == 0 {
		p.noPendingWrites.Broadcast()
	}
	p.pendingWritesMutex.Unlock()
}

func (p *piece) waitNoPendingWrites() {
	p.pendingWritesMutex.Lock()
	for p.pendingWrites != 0 {
		p.noPendingWrites.Wait()
	}
	p.pendingWritesMutex.Unlock()
}

func (p *piece) chunkIndexDirty(chunk int) bool {
	return p.DirtyChunks.Contains(chunk)
}

func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
	return chunkIndexSpec(chunk, p.length(), p.chunkSize())
}

func (p *piece) numDirtyBytes() (ret pp.Integer) {
	defer func() {
		if ret > p.length() {
			panic("too many dirty bytes")
		}
	}()
	numRegularDirtyChunks := p.numDirtyChunks()
	if p.chunkIndexDirty(p.numChunks() - 1) {
		numRegularDirtyChunks--
		ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
	}
	ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
	return
}

func (p *piece) length() pp.Integer {
	return p.t.pieceLength(p.index)
}

func (p *piece) chunkSize() pp.Integer {
	return p.t.chunkSize
}

func (p *piece) lastChunkIndex() int {
	return p.numChunks() - 1
}

func (p *piece) bytesLeft() (ret pp.Integer) {
	if p.t.pieceComplete(p.index) {
		return 0
	}
	return p.length() - p.numDirtyBytes()
}
<commit_msg>Comment on PiecePriorityNext<commit_after>package torrent

import (
	"sync"

	"github.com/anacrolix/missinggo/bitmap"

	"github.com/anacrolix/torrent/metainfo"
	pp "github.com/anacrolix/torrent/peer_protocol"
	"github.com/anacrolix/torrent/storage"
)

// Piece priority describes the importance of obtaining a particular piece.

type piecePriority byte

func (pp *piecePriority) Raise(maybe piecePriority) {
	if maybe > *pp {
		*pp = maybe
	}
}

const (
	PiecePriorityNone      piecePriority = iota // Not wanted.
	PiecePriorityNormal                         // Wanted.
	PiecePriorityReadahead                      // May be required soon.
	// Succeeds a piece where a read occurred. Currently the same as Now, apparently due to issues with caching.
	PiecePriorityNext
	PiecePriorityNow // A Reader is reading in this piece.
)

type piece struct {
	// The completed piece SHA1 hash, from the metainfo "pieces" field.
	Hash  metainfo.Hash
	t     *Torrent
	index int
	// Chunks we've written to since the last check. The chunk offset and
	// length can be determined by the request chunkSize in use.
	DirtyChunks      bitmap.Bitmap
	Hashing          bool
	QueuedForHash    bool
	EverHashed       bool
	PublicPieceState PieceState
	priority         piecePriority

	pendingWritesMutex sync.Mutex
	pendingWrites      int
	noPendingWrites    sync.Cond
}

func (p *piece) Info() metainfo.Piece {
	return p.t.info.Piece(p.index)
}

func (p *piece) Storage() storage.Piece {
	return p.t.storage.Piece(p.Info())
}

func (p *piece) pendingChunkIndex(chunkIndex int) bool {
	return !p.DirtyChunks.Contains(chunkIndex)
}

func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
	return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
}

func (p *piece) hasDirtyChunks() bool {
	return p.DirtyChunks.Len() != 0
}

func (p *piece) numDirtyChunks() (ret int) {
	return p.DirtyChunks.Len()
}

func (p *piece) unpendChunkIndex(i int) {
	p.DirtyChunks.Add(i)
}

func (p *piece) pendChunkIndex(i int) {
	p.DirtyChunks.Remove(i)
}

func (p *piece) numChunks() int {
	return p.t.pieceNumChunks(p.index)
}

func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
	ret = p.DirtyChunks.Copy()
	ret.FlipRange(0, p.numChunks())
	return
}

func (p *piece) incrementPendingWrites() {
	p.pendingWritesMutex.Lock()
	p.pendingWrites++
	p.pendingWritesMutex.Unlock()
}

func (p *piece) decrementPendingWrites() {
	p.pendingWritesMutex.Lock()
	if p.pendingWrites == 0 {
		panic("assertion")
	}
	p.pendingWrites--
	if p.pendingWrites == 0 {
		p.noPendingWrites.Broadcast()
	}
	p.pendingWritesMutex.Unlock()
}

func (p *piece) waitNoPendingWrites() {
	p.pendingWritesMutex.Lock()
	for p.pendingWrites != 0 {
		p.noPendingWrites.Wait()
	}
	p.pendingWritesMutex.Unlock()
}

func (p *piece) chunkIndexDirty(chunk int) bool {
	return p.DirtyChunks.Contains(chunk)
}

func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
	return chunkIndexSpec(chunk, p.length(), p.chunkSize())
}

func (p *piece) numDirtyBytes() (ret pp.Integer) {
	defer func() {
		if ret > p.length() {
			panic("too many dirty bytes")
		}
	}()
	numRegularDirtyChunks := p.numDirtyChunks()
	if p.chunkIndexDirty(p.numChunks() - 1) {
		numRegularDirtyChunks--
		ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
	}
	ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
	return
}

func (p *piece) length() pp.Integer {
	return p.t.pieceLength(p.index)
}

func (p *piece) chunkSize() pp.Integer {
	return p.t.chunkSize
}

func (p *piece) lastChunkIndex() int {
	return p.numChunks() - 1
}

func (p *piece) bytesLeft() (ret pp.Integer) {
	if p.t.pieceComplete(p.index) {
		return 0
	}
	return p.length() - p.numDirtyBytes()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"login"
	"os/signal"
	"syscall"
)

func main()  {
	var port = flag.Int("port", 8090, "Port to bind to on the localhost interface")
	flag.Parse()

	router := login.NewRouter()
	log.Printf("Starting a server on localhost:%d", *port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), router))
}

func init()  {
	login.LoadKey()

	sc := make(chan os.Signal, 1)

	signal.Notify(sc, syscall.SIGHUP)

	go func ()  {
		for {
			<-sc
			login.LoadKey()
		}
	}()
}<commit_msg>Fixed the package pointer in login/main<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"login"
	"os/signal"
	"syscall"
	"authn"
)

func main()  {
	var port = flag.Int("port", 8090, "Port to bind to on the localhost interface")
	flag.Parse()

	router := login.NewRouter()
	log.Printf("Starting a server on localhost:%d", *port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), router))
}

func init()  {
	authn.LoadKey()

	sc := make(chan os.Signal, 1)

	signal.Notify(sc, syscall.SIGHUP)

	go func ()  {
		for {
			<-sc
			authn.LoadKey()
		}
	}()
}<|endoftext|>


<commit_before>package articles

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

const (
	TimeFormat = "January 2, 2006"
	readMore   = "<!--readmore-->"
)

type Articles []*Article
type Article struct {
	Date     time.Time
	Edit     time.Time
	Title    string
	Slug     string
	Body     string
	Tags     Tags
	Enabled  bool
	Author   string
	Comments Comments
}

type YearMap map[int]Articles
type MonthMap map[int]Articles

func (a *Article) makeSlug() {
	r := strings.NewReplacer(" ", "-")
	a.Slug = r.Replace(strings.TrimSpace(a.Title))
}

func (a *Article) Publish() {
	a.Date = time.Now()
	a.Enabled = true
}

func (a *Article) Suppress() {
	a.Enabled = false
}

func (a *Article) AddComment(c *Comment) {
	a.Comments.Add(c)
}

func (a Articles) Len() int           { return len(a) }
func (a Articles) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a Articles) Less(i, j int) bool { return a[i].Date.Before(a[j].Date) }

func (a *Articles) Add(article *Article) error {
	article.Date = time.Now()
	if article.Slug == "" {
		article.makeSlug()
	}
	_, err := a.Find(article.Slug)
	if err == nil {
		return errors.New("duplicate slug " + article.Slug)
	}
	*a = append(*a, article)
	return nil
}

func (a *Articles) Update(article *Article) error {
	article.Edit = time.Now()
	if article.Slug == "" {
		article.makeSlug()
	}
	i, err := a.locate(article.Slug)
	if err != nil {
		return a.Add(article)
	}
	article.Date = (*a)[i].Date
	(*a)[i] = article
	return nil
}

func (a Articles) locate(slug string) (int, error) {
	for i, ar := range a {
		if ar.Slug == slug {
			return i, nil
		}
	}
	return 0, errors.New("not found " + slug)
}

func (a Articles) Find(slug string) (*Article, error) {
	i, err := a.locate(slug)
	if err != nil {
		return nil, err
	}
	return a[i], nil
}

func (a Articles) Page(page, app int) (Articles, int, int) {
	var next, prev int

	lastpage := len(a)/app + 1

	if page <= 1 {
		page = 1
	} else {
		prev = page - 1
	}

	if page >= lastpage {
		page = lastpage
	} else {
		next = page + 1
	}

	from := (page - 1) * app
	to := from + app - 1
	if to > len(a) {
		to = len(a)
	}

	return a[from:to], next, prev
}

func (a Article) PostDate() string {
	return a.Date.Local().Format(TimeFormat)
}

func (a Article) Edited() bool {
	return !a.Edit.IsZero()
}
func (a Article) EditDate() string {
	return a.Edit.Local().Format(TimeFormat)
}

func (a Article) RssDate() string {
	return a.Date.Local().Format(time.RFC1123Z)
}

func (a Article) Spoiler() string {
	if i := strings.Index(a.Body, readMore); i > 0 {
		return a.Body[:i]
	}
	return a.Body
}

func (a Article) HasMore() bool {
	return strings.Contains(a.Body, readMore)
}

func (a Article) Year() int {
	return a.Date.Year()
}

func (a Article) Month() time.Month {
	return a.Date.Month()
}

func (a Articles) Year(year int) (A Articles) {
	if year == 0 {
		year = time.Now().Year()
	}
	for _, v := range a {
		if v.Date.Year() == year {
			A = append(A, v)
		}
	}
	return A
}

func (a Articles) Month(month time.Month) (A Articles) {
	if month == 0 {
		month = time.Now().Month()
	}
	for _, v := range a {
		if v.Date.Month() == month {
			A = append(A, v)
		}
	}
	return A
}

func (a Articles) Enabled() (A Articles) {
	for _, v := range a {
		if v.Enabled {
			A = append(A, v)
		}
	}
	return A
}

func (a Articles) Limit(n int) Articles {
	if n > len(a) {
		n = len(a)
	}
	return a[:n]
}

func (a Articles) Head() Article {
	return *a[0]
}

func (a Articles) Tail() Article {
	return *a[len(a)-1]
}

func (a Articles) YearMap() YearMap {
	ym := make(YearMap)
	for _, v := range a {
		y := v.Date.Year()
		ym[y] = append(ym[y], v)
	}
	return ym
}

func (a Articles) MonthMap() MonthMap {
	mm := make(MonthMap)
	for _, v := range a {
		m := int(v.Date.Month())
		mm[m] = append(mm[m], v)
	}
	return mm
}

func (a Article) FullPath() string {
	return fmt.Sprintf("/%.4d/%.2d/%s", a.Date.Year(), a.Date.Month(), a.Slug)
}
<commit_msg>add Skip<commit_after>package articles

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

const (
	TimeFormat = "January 2, 2006"
	readMore   = "<!--readmore-->"
)

type Articles []*Article
type Article struct {
	Date     time.Time
	Edit     time.Time
	Title    string
	Slug     string
	Body     string
	Tags     Tags
	Enabled  bool
	Author   string
	Comments Comments
}

type YearMap map[int]Articles
type MonthMap map[int]Articles

func (a *Article) makeSlug() {
	r := strings.NewReplacer(" ", "-")
	a.Slug = r.Replace(strings.TrimSpace(a.Title))
}

func (a *Article) Publish() {
	a.Date = time.Now()
	a.Enabled = true
}

func (a *Article) Suppress() {
	a.Enabled = false
}

func (a *Article) AddComment(c *Comment) {
	a.Comments.Add(c)
}

func (a Articles) Len() int           { return len(a) }
func (a Articles) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a Articles) Less(i, j int) bool { return a[i].Date.Before(a[j].Date) }

func (a *Articles) Add(article *Article) error {
	article.Date = time.Now()
	if article.Slug == "" {
		article.makeSlug()
	}
	_, err := a.Find(article.Slug)
	if err == nil {
		return errors.New("duplicate slug " + article.Slug)
	}
	*a = append(*a, article)
	return nil
}

func (a *Articles) Update(article *Article) error {
	article.Edit = time.Now()
	if article.Slug == "" {
		article.makeSlug()
	}
	i, err := a.locate(article.Slug)
	if err != nil {
		return a.Add(article)
	}
	article.Date = (*a)[i].Date
	(*a)[i] = article
	return nil
}

func (a Articles) locate(slug string) (int, error) {
	for i, ar := range a {
		if ar.Slug == slug {
			return i, nil
		}
	}
	return 0, errors.New("not found " + slug)
}

func (a Articles) Find(slug string) (*Article, error) {
	i, err := a.locate(slug)
	if err != nil {
		return nil, err
	}
	return a[i], nil
}

func (a Articles) Page(page, app int) (Articles, int, int) {
	var next, prev int

	lastpage := len(a)/app + 1

	if page <= 1 {
		page = 1
	} else {
		prev = page - 1
	}

	if page >= lastpage {
		page = lastpage
	} else {
		next = page + 1
	}

	from := (page - 1) * app
	to := from + app - 1
	if to > len(a) {
		to = len(a)
	}

	return a[from:to], next, prev
}

func (a Article) PostDate() string {
	return a.Date.Local().Format(TimeFormat)
}

func (a Article) Edited() bool {
	return !a.Edit.IsZero()
}
func (a Article) EditDate() string {
	return a.Edit.Local().Format(TimeFormat)
}

func (a Article) RssDate() string {
	return a.Date.Local().Format(time.RFC1123Z)
}

func (a Article) Spoiler() string {
	if i := strings.Index(a.Body, readMore); i > 0 {
		return a.Body[:i]
	}
	return a.Body
}

func (a Article) HasMore() bool {
	return strings.Contains(a.Body, readMore)
}

func (a Article) Year() int {
	return a.Date.Year()
}

func (a Article) Month() time.Month {
	return a.Date.Month()
}

func (a Articles) Year(year int) (A Articles) {
	if year == 0 {
		year = time.Now().Year()
	}
	for _, v := range a {
		if v.Date.Year() == year {
			A = append(A, v)
		}
	}
	return A
}

func (a Articles) Month(month time.Month) (A Articles) {
	if month == 0 {
		month = time.Now().Month()
	}
	for _, v := range a {
		if v.Date.Month() == month {
			A = append(A, v)
		}
	}
	return A
}

func (a Articles) Enabled() (A Articles) {
	for _, v := range a {
		if v.Enabled {
			A = append(A, v)
		}
	}
	return A
}

func (a Articles) Skip(n int) Articles {
	if n > len(a) {
		return nil
	}
	return a[n:]
}

func (a Articles) Limit(n int) Articles {
	if n > len(a) {
		n = len(a)
	}
	return a[:n]
}

func (a Articles) Head() Article {
	return *a[0]
}

func (a Articles) Tail() Article {
	return *a[len(a)-1]
}

func (a Articles) YearMap() YearMap {
	ym := make(YearMap)
	for _, v := range a {
		y := v.Date.Year()
		ym[y] = append(ym[y], v)
	}
	return ym
}

func (a Articles) MonthMap() MonthMap {
	mm := make(MonthMap)
	for _, v := range a {
		m := int(v.Date.Month())
		mm[m] = append(mm[m], v)
	}
	return mm
}

func (a Article) FullPath() string {
	return fmt.Sprintf("/%.4d/%.2d/%s", a.Date.Year(), a.Date.Month(), a.Slug)
}
<|endoftext|>