<commit_before>// Copyright 2016 Adam H. Leventhal. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0

package main

import (
	"flag"
	"fmt"
	"os"
	"sort"

	// "github.com/zabawaba99/firego"

	"github.com/attic-labs/noms/go/spec"
	"github.com/attic-labs/noms/go/types"
)

// Map<number, Struct Story {
//	id Number
//	time Number XXX there's at least one with no time; I'll try to find it
//
//	// Optional
//	deleted, dead Bool
//	descendants, score Number
//	text, url, title, by String
//
//	comments List<Struct Comment {
//		id Number
//		time Number
//
//		// Optional
//		deleted, dead Bool
//		text, by String
//
//		comments List<Cycle<0>>
//	}>
// }>

var nothing types.Value
var nothingType *types.Type

func init() {
	nothing = types.NewStruct("Nothing", types.StructData{})
	nothingType = nothing.Type()
}

var commentType *StructType

func main() {
	flag.Usage = func() {
		fmt.Printf("Usage: %s <src-dataset-spec> <dst-dataset-spec>\n", os.Args[0])
	}
	flag.Parse()
	if flag.NArg() != 2 {
		flag.Usage()
		return
	}

	source, err := spec.GetDataset(os.Args[1])
	if err != nil {
		fmt.Println(err)
		return
	}
	defer source.Database().Close()

	ds, err := spec.GetDataset(os.Args[2])
	if err != nil {
		fmt.Println(err)
		return
	}
	defer ds.Database().Close()

	fmt.Println("starting")

	optionString := types.MakeUnionType(types.StringType, nothingType)
	optionNumber := types.MakeUnionType(types.NumberType, nothingType)
	optionBool := types.MakeUnionType(types.BoolType, nothingType)

	commentType = MakeStructType("Comment", []FieldType{
		{"id", types.NumberType},
		{"time", types.NumberType},

		{"deleted", optionBool},
		{"dead", optionBool},

		{"text", optionString},
		{"by", optionString},

		{"comments", types.MakeListType(types.MakeCycleType(0))},
	})

	storyType := MakeStructType("Story", []FieldType{
		{"id", types.NumberType},
		{"time", types.NumberType},

		{"deleted", optionBool},
		{"dead", optionBool},

		{"descendants", optionNumber},
		{"score", optionNumber},

		{"text", optionString},
		{"url", optionString},
		{"by", optionString},

		{"comments", types.MakeListType(commentType.t)},
	})

	mm := source.HeadValue().(types.Map)

	start, ok := ds.MaybeHeadValue()
	if !ok {
		start = types.Number(1)
	}

	newItem := make(chan types.Struct, 100)
	newStory := make(chan types.Value, 100)

	go func() {
		mm.IterFrom(start, func(id, value types.Value) bool {
			item := value.(types.Struct)

			if item.Type().Desc.(types.StructDesc).Name == "story" {
				newItem <- item
			}

			return false
		})
		close(newItem)
	}()

	for i := 0; i < 100; i += 1 {
		go func() {
			for item := range newItem {
				id := item.Get("id")

				// Known stubs with just id and type
				if fields := item.ChildValues(); len(fields) == 2 {
					item.Get("type") // or panic
					continue
				}

				newStory <- NewStructWithType(storyType, types.ValueSlice{
					id,
					item.Get("time"),
					OptionGet(item, "deleted"),
					OptionGet(item, "dead"),
					OptionGet(item, "descendants"),
					OptionGet(item, "score"),
					OptionGet(item, "text"),
					OptionGet(item, "url"),
					OptionGet(item, "by"),
					comments(item, mm),
				})
			}
		}()
	}

	for story := range newStory {
		id := story.(types.Struct).Get("id")
		//fmt.Println(types.EncodedIndexValue(id))
		fmt.Println(types.EncodedIndexValue(story))

		nds, err := ds.CommitValue(id)
		if err != nil {
			panic(err)
		}
		ds = nds
	}
}

func OptionGet(st types.Struct, field string) types.Value {
	value, ok := st.MaybeGet(field)
	if ok {
		return value
	} else {
		return nothing
	}
}

// |item| could be a story or a comment
func comments(item types.Value, all types.Map) types.Value {
	ret := types.NewList()

	c, ok := item.(types.Struct).MaybeGet("kids")
	if ok {
		c.(types.List).IterAll(func(id types.Value, _ uint64) {
			value, ok := all.MaybeGet(id)
			if !ok {
				panic(fmt.Sprintf("unable to look up %d", int(id.(types.Number))))
			}

			subitem := value.(types.Struct)

			// Ignore stubs and zombies
			_, ok = subitem.MaybeGet("time")
			if !ok {
				return
			}

			comm := NewStructWithType(commentType, types.ValueSlice{
				id,
				subitem.Get("time"),
				OptionGet(subitem, "deleted"),
				OptionGet(subitem, "dead"),
				OptionGet(subitem, "text"),
				OptionGet(subitem, "by"),
				comments(subitem, all),
			})
			ret = ret.Append(comm)
		})
	}

	return ret
}

type StructType struct {
	t     *types.Type
	xform []int
}

type FieldType struct {
	name string
	t    *types.Type
}

type SortableFields struct {
	xform  []int
	fields []FieldType
}

func (s SortableFields) Len() int      { return len(s.xform) }
func (s SortableFields) Swap(i, j int) { s.xform[i], s.xform[j] = s.xform[j], s.xform[i] }
func (s SortableFields) Less(i, j int) bool {
	return s.fields[s.xform[i]].name < s.fields[s.xform[j]].name
}

func MakeStructType(name string, fields []FieldType) *StructType {
	xform := make([]int, len(fields))

	for idx, _ := range xform {
		xform[idx] = idx
	}

	sort.Sort(SortableFields{xform: xform, fields: fields})

	ns := make([]string, len(fields))
	ts := make([]*types.Type, len(fields))

	for to, from := range xform {
		ns[to] = fields[from].name
		ts[to] = fields[from].t
	}

	t := types.MakeStructType(name, ns, ts)

	return &StructType{t, xform}
}

func NewStructWithType(t *StructType, values types.ValueSlice) types.Value {
	v := make(types.ValueSlice, len(values))

	for to, from := range t.xform {
		v[to] = values[from]
	}

	return types.NewStructWithType(t.t, v)
}
<commit_msg>am I done?<commit_after>// Copyright 2016 Adam H. Leventhal. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0

package main

import (
	"flag"
	"fmt"
	"os"
	"sort"

	// "github.com/zabawaba99/firego"

	"github.com/attic-labs/noms/go/spec"
	"github.com/attic-labs/noms/go/types"
)

// Map<number, Struct Story {
//	id Number
//	time Number XXX there's at least one with no time; I'll try to find it
//
//	// Optional
//	deleted, dead Bool
//	descendants, score Number
//	text, url, title, by String
//
//	comments List<Struct Comment {
//		id Number
//		time Number
//
//		// Optional
//		deleted, dead Bool
//		text, by String
//
//		comments List<Cycle<0>>
//	}>
// }>

var nothing types.Value
var nothingType *types.Type

func init() {
	nothing = types.NewStruct("Nothing", types.StructData{})
	nothingType = nothing.Type()
}

var commentType *StructType

func main() {
	flag.Usage = func() {
		fmt.Printf("Usage: %s <src-dataset-spec> <dst-dataset-spec>\n", os.Args[0])
	}
	flag.Parse()
	if flag.NArg() != 2 {
		flag.Usage()
		return
	}

	source, err := spec.GetDataset(os.Args[1])
	if err != nil {
		fmt.Println(err)
		return
	}
	defer source.Database().Close()

	ds, err := spec.GetDataset(os.Args[2])
	if err != nil {
		fmt.Println(err)
		return
	}
	defer ds.Database().Close()

	fmt.Println("starting")

	optionString := types.MakeUnionType(types.StringType, nothingType)
	optionNumber := types.MakeUnionType(types.NumberType, nothingType)
	optionBool := types.MakeUnionType(types.BoolType, nothingType)

	commentType = MakeStructType("Comment", []FieldType{
		{"id", types.NumberType},
		{"time", types.NumberType},

		{"deleted", optionBool},
		{"dead", optionBool},

		{"text", optionString},
		{"by", optionString},

		{"comments", types.MakeListType(types.MakeCycleType(0))},
	})

	storyType := MakeStructType("Story", []FieldType{
		{"id", types.NumberType},
		{"time", types.NumberType},

		{"deleted", optionBool},
		{"dead", optionBool},

		{"descendants", optionNumber},
		{"score", optionNumber},

		{"text", optionString},
		{"url", optionString},
		{"by", optionString},

		{"comments", types.MakeListType(commentType.t)},
	})

	mm := source.HeadValue().(types.Map)

	start, ok := ds.MaybeHeadValue()
	if !ok {
		start = types.Number(1)
	}

	newItem := make(chan types.Struct, 100)
	newStory := make(chan types.Value, 100)

	go func() {
		mm.IterFrom(start, func(id, value types.Value) bool {
			item := value.(types.Struct)

			if item.Type().Desc.(types.StructDesc).Name == "story" {
				newItem <- item
			}

			return false
		})
		close(newItem)
	}()

	for i := 0; i < 100; i += 1 {
		go func() {
			for item := range newItem {
				id := item.Get("id")

				// Known stubs with just id and type
				if fields := item.ChildValues(); len(fields) == 2 {
					item.Get("type") // or panic
					continue
				}

				newStory <- NewStructWithType(storyType, types.ValueSlice{
					id,
					item.Get("time"),
					OptionGet(item, "deleted"),
					OptionGet(item, "dead"),
					OptionGet(item, "descendants"),
					OptionGet(item, "score"),
					OptionGet(item, "text"),
					OptionGet(item, "url"),
					OptionGet(item, "by"),
					comments(item, mm),
				})
			}
		}()
	}

	for story := range newStory {
		id := story.(types.Struct).Get("id")
		//fmt.Println(types.EncodedIndexValue(id))
		fmt.Println(types.EncodedIndexValue(story))

		nds, err := ds.CommitValue(id)
		if err != nil {
			panic(err)
		}
		ds = nds
	}

	fmt.Println("done")
}

func OptionGet(st types.Struct, field string) types.Value {
	value, ok := st.MaybeGet(field)
	if ok {
		return value
	} else {
		return nothing
	}
}

// |item| could be a story or a comment
func comments(item types.Value, all types.Map) types.Value {
	ret := types.NewList()

	c, ok := item.(types.Struct).MaybeGet("kids")
	if ok {
		c.(types.List).IterAll(func(id types.Value, _ uint64) {
			value, ok := all.MaybeGet(id)
			if !ok {
				panic(fmt.Sprintf("unable to look up %d", int(id.(types.Number))))
			}

			subitem := value.(types.Struct)

			// Ignore stubs and zombies
			_, ok = subitem.MaybeGet("time")
			if !ok {
				return
			}

			comm := NewStructWithType(commentType, types.ValueSlice{
				id,
				subitem.Get("time"),
				OptionGet(subitem, "deleted"),
				OptionGet(subitem, "dead"),
				OptionGet(subitem, "text"),
				OptionGet(subitem, "by"),
				comments(subitem, all),
			})
			ret = ret.Append(comm)
		})
	}

	return ret
}

type StructType struct {
	t     *types.Type
	xform []int
}

type FieldType struct {
	name string
	t    *types.Type
}

type SortableFields struct {
	xform  []int
	fields []FieldType
}

func (s SortableFields) Len() int      { return len(s.xform) }
func (s SortableFields) Swap(i, j int) { s.xform[i], s.xform[j] = s.xform[j], s.xform[i] }
func (s SortableFields) Less(i, j int) bool {
	return s.fields[s.xform[i]].name < s.fields[s.xform[j]].name
}

func MakeStructType(name string, fields []FieldType) *StructType {
	xform := make([]int, len(fields))

	for idx, _ := range xform {
		xform[idx] = idx
	}

	sort.Sort(SortableFields{xform: xform, fields: fields})

	ns := make([]string, len(fields))
	ts := make([]*types.Type, len(fields))

	for to, from := range xform {
		ns[to] = fields[from].name
		ts[to] = fields[from].t
	}

	t := types.MakeStructType(name, ns, ts)

	return &StructType{t, xform}
}

func NewStructWithType(t *StructType, values types.ValueSlice) types.Value {
	v := make(types.ValueSlice, len(values))

	for to, from := range t.xform {
		v[to] = values[from]
	}

	return types.NewStructWithType(t.t, v)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/spf13/viper"
	"gopkg.in/yaml.v2"
	"path/filepath"
	"io/ioutil"
)

type Config struct {
	HoverflyHost      string `yaml:"hoverfly.host"`
	HoverflyAdminPort string `yaml:"hoverfly.admin.port"`
	HoverflyProxyPort string `yaml:"hoverfly.proxy.port"`
	SpectoLabHost     string `yaml:"specto.lab.host"`
	SpectoLabPort     string `yaml:"specto.lab.port"`
	SpectoLabApiKey   string `yaml:"specto.lab.api.key"`
}

func GetConfig(hoverflyHostOverride, hoverflyAdminPortOverride, hoverflyProxyPortOverride string) Config {
	SetConfigurationDefaults()
	viper.ReadInConfig()

	config := Config{
		HoverflyHost: viper.GetString("hoverfly.host"),
		HoverflyAdminPort: viper.GetString("hoverfly.admin.port"),
		HoverflyProxyPort: viper.GetString("hoverfly.proxy.port"),
		SpectoLabHost: viper.GetString("specto.lab.host"),
		SpectoLabPort: viper.GetString("specto.lab.port"),
		SpectoLabApiKey: "",
	}

	if len(hoverflyHostOverride) > 0 {
		config.HoverflyHost = hoverflyHostOverride
	}

	if len(hoverflyAdminPortOverride) > 0 {
		config.HoverflyAdminPort = hoverflyAdminPortOverride
	}

	if len(hoverflyProxyPortOverride) > 0 {
		config.HoverflyProxyPort = hoverflyProxyPortOverride
	}

	return config
}

func (c *Config) GetFilepath() (string) {
	return viper.ConfigFileUsed()
}

func (c *Config) WriteToFile(path string) (error) {
	data, err := yaml.Marshal(c)

	if err != nil {
		return err
	}

	filepath := filepath.Join(path, "config.yaml")

	err = ioutil.WriteFile(filepath, data, 0644)

	if err != nil {
		return err
	}

	return nil
}

func SetConfigurationDefaults() {
	viper.AddConfigPath("./.hoverfly")
	viper.AddConfigPath("$HOME/.hoverfly")
	viper.SetDefault("hoverfly.host", "localhost")
	viper.SetDefault("hoverfly.admin.port", "8888")
	viper.SetDefault("hoverfly.proxy.port", "8500")
	viper.SetDefault("specto.lab.host", "localhost")
	viper.SetDefault("specto.lab.port", "81")
}<commit_msg>Didn't use the api.key from the config file<commit_after>package main

import (
	"github.com/spf13/viper"
	"gopkg.in/yaml.v2"
	"path/filepath"
	"io/ioutil"
)

type Config struct {
	HoverflyHost      string `yaml:"hoverfly.host"`
	HoverflyAdminPort string `yaml:"hoverfly.admin.port"`
	HoverflyProxyPort string `yaml:"hoverfly.proxy.port"`
	SpectoLabHost     string `yaml:"specto.lab.host"`
	SpectoLabPort     string `yaml:"specto.lab.port"`
	SpectoLabApiKey   string `yaml:"specto.lab.api.key"`
}

func GetConfig(hoverflyHostOverride, hoverflyAdminPortOverride, hoverflyProxyPortOverride string) Config {
	SetConfigurationDefaults()
	viper.ReadInConfig()

	config := Config{
		HoverflyHost: viper.GetString("hoverfly.host"),
		HoverflyAdminPort: viper.GetString("hoverfly.admin.port"),
		HoverflyProxyPort: viper.GetString("hoverfly.proxy.port"),
		SpectoLabHost: viper.GetString("specto.lab.host"),
		SpectoLabPort: viper.GetString("specto.lab.port"),
		SpectoLabApiKey: viper.GetString("specto.lab.api.key"),
	}

	if len(hoverflyHostOverride) > 0 {
		config.HoverflyHost = hoverflyHostOverride
	}

	if len(hoverflyAdminPortOverride) > 0 {
		config.HoverflyAdminPort = hoverflyAdminPortOverride
	}

	if len(hoverflyProxyPortOverride) > 0 {
		config.HoverflyProxyPort = hoverflyProxyPortOverride
	}

	return config
}

func (c *Config) GetFilepath() (string) {
	return viper.ConfigFileUsed()
}

func (c *Config) WriteToFile(path string) (error) {
	data, err := yaml.Marshal(c)

	if err != nil {
		return err
	}

	filepath := filepath.Join(path, "config.yaml")

	err = ioutil.WriteFile(filepath, data, 0644)

	if err != nil {
		return err
	}

	return nil
}

func SetConfigurationDefaults() {
	viper.AddConfigPath("./.hoverfly")
	viper.AddConfigPath("$HOME/.hoverfly")
	viper.SetDefault("hoverfly.host", "localhost")
	viper.SetDefault("hoverfly.admin.port", "8888")
	viper.SetDefault("hoverfly.proxy.port", "8500")
	viper.SetDefault("specto.lab.host", "localhost")
	viper.SetDefault("specto.lab.port", "81")
	viper.SetDefault("specto.lab.api.key", "")
}<|endoftext|>


<commit_before>package bullet
<commit_msg>Remove a needless file.<commit_after><|endoftext|>


<commit_before>package dogo

type dogoConfig struct {
	// 运行端口
	Port string
	// 运行级别
	RunLevel runLevel
	// 使用session
	UserSession bool
	// session 名称
	SessionName string
	// log 日志缓存大小(谨慎操作。默认值为0，如果 > 0 ，日志记录将是无序的，不能保证写入顺序)
	LogDataChanSize int
}

var RunTimeConfig dogoConfig

func (c dogoConfig) IsDebug() bool {
	return c.RunLevel == RUN_DEBUG
}

func init() {
	RunTimeConfig.RunLevel = RUN_DEBUG
	RunTimeConfig.Port = "8080"
	// 默认开启Session
	RunTimeConfig.UserSession = true
	// session 名称
	RunTimeConfig.SessionName = "DogoSessionID"
	//
	RunTimeConfig.LogDataChanSize = 10

}
<commit_msg>添加日志缓存数量设置<commit_after>package dogo

type dogoConfig struct {
	// 运行端口
	Port string
	// 运行级别
	RunLevel runLevel
	// 使用session
	UserSession bool
	// session 名称
	SessionName string
	// log 日志缓存大小(谨慎操作。默认值为0，如果 > 0 ，日志记录将是无序的，不能保证写入顺序)
	LogDataChanSize int
}

var RunTimeConfig dogoConfig

func (c dogoConfig) IsDebug() bool {
	return c.RunLevel == RUN_DEBUG
}

func init() {
	RunTimeConfig.RunLevel = RUN_DEBUG
	RunTimeConfig.Port = "8080"
	// 默认开启Session
	RunTimeConfig.UserSession = true
	// session 名称
	RunTimeConfig.SessionName = "DogoSessionID"
	//
	RunTimeConfig.LogDataChanSize = 0

}

// I don’t understand the start means
<|endoftext|>


<commit_before>package config

import (
	"flag"
	"fmt"
	"os"
	"os/user"
	"path"
	"reflect"
	"unsafe"

	"pault.ag/go/debian/control"
)

func LoadFlags(name string, data interface{}) (*flag.FlagSet, error) {
	if err := Load(name, data); err != nil {
		return nil, err
	}
	return Flag(data)
}

//
func Load(name string, data interface{}) error {
	localUser, err := user.Current()
	if err != nil {
		return err
	}
	rcPath := path.Join(localUser.HomeDir, fmt.Sprintf(".%src", name))
	fd, err := os.Open(rcPath)
	if err != nil {
		return err
	}
	defer fd.Close()
	err = control.Unmarshal(data, fd)
	return err
}

func flagPointer(incoming reflect.Value, data *flag.FlagSet) error {
	if incoming.Type().Kind() == reflect.Ptr {
		return flagPointer(incoming.Elem(), data)
	}

	for i := 0; i < incoming.NumField(); i++ {
		field := incoming.Field(i)
		fieldType := incoming.Type().Field(i)

		if it := fieldType.Tag.Get("flag"); it != "" {
			/* Register the flag */
			switch field.Type().Kind() {
			case reflect.Int:
				data.IntVar(
					(*int)(unsafe.Pointer(field.Addr().Pointer())),
					it,
					int(field.Int()),
					fieldType.Tag.Get("description"),
				)
				continue
			case reflect.String:
				data.StringVar(
					(*string)(unsafe.Pointer(field.Addr().Pointer())),
					it,
					field.String(),
					fieldType.Tag.Get("description"),
				)
				continue
			default:
				return fmt.Errorf("Unknown type: %s", field.Type().Kind())
			}
		}
	}
	return nil
}

func Flag(data interface{}) (*flag.FlagSet, error) {
	dataValue := reflect.ValueOf(data)
	name := dataValue.Elem().Type().Name()
	flagSet := flag.NewFlagSet(name, flag.ExitOnError)
	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		flagSet.PrintDefaults()
	}

	err := flagPointer(dataValue, flagSet)
	if err != nil {
		return nil, err
	}
	return flagSet, nil
}
<commit_msg>to lower<commit_after>package config

import (
	"flag"
	"fmt"
	"os"
	"os/user"
	"path"
	"reflect"
	"strings"
	"unsafe"

	"pault.ag/go/debian/control"
)

func LoadFlags(name string, data interface{}) (*flag.FlagSet, error) {
	if err := Load(name, data); err != nil {
		return nil, err
	}
	return Flag(data)
}

//
func Load(name string, data interface{}) error {
	localUser, err := user.Current()
	if err != nil {
		return err
	}
	rcPath := path.Join(localUser.HomeDir, fmt.Sprintf(".%src", name))
	fd, err := os.Open(rcPath)
	if err != nil {
		return err
	}
	defer fd.Close()
	err = control.Unmarshal(data, fd)
	return err
}

func flagPointer(incoming reflect.Value, data *flag.FlagSet) error {
	if incoming.Type().Kind() == reflect.Ptr {
		return flagPointer(incoming.Elem(), data)
	}

	for i := 0; i < incoming.NumField(); i++ {
		field := incoming.Field(i)
		fieldType := incoming.Type().Field(i)

		if it := fieldType.Tag.Get("flag"); it != "" {
			/* Register the flag */
			switch field.Type().Kind() {
			case reflect.Int:
				data.IntVar(
					(*int)(unsafe.Pointer(field.Addr().Pointer())),
					it,
					int(field.Int()),
					fieldType.Tag.Get("description"),
				)
				continue
			case reflect.String:
				data.StringVar(
					(*string)(unsafe.Pointer(field.Addr().Pointer())),
					it,
					field.String(),
					fieldType.Tag.Get("description"),
				)
				continue
			default:
				return fmt.Errorf("Unknown type: %s", field.Type().Kind())
			}
		}
	}
	return nil
}

func Flag(data interface{}) (*flag.FlagSet, error) {
	dataValue := reflect.ValueOf(data)
	name := strings.ToLower(dataValue.Elem().Type().Name())
	flagSet := flag.NewFlagSet(name, flag.ExitOnError)
	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		flagSet.PrintDefaults()
	}

	err := flagPointer(dataValue, flagSet)
	if err != nil {
		return nil, err
	}
	return flagSet, nil
}
<|endoftext|>


<commit_before>/*
 *  zanproxy: a proxy detector for Zandronum
 *  Copyright (C) 2016  Alex Mayfield <alexmax2742@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package main

import (
	"errors"

	"github.com/BurntSushi/toml"
)

// Config contains the configuration for the program.
type Config struct {
	Banlist    string
	Email      string
	Logfiles   []string
	MinScore   float64
	BanMessage string
}

// NewConfig creates a new instance of Config from a configuration file.
func NewConfig(filename string) (*Config, error) {
	// Load configuration file
	config := &Config{}
	meta, err := toml.DecodeFile(filename, config)
	if err != nil {
		return nil, err
	}

	// Ensure Banlist exists
	if !meta.IsDefined("Banlist") {
		return nil, errors.New("Config: must define Banlist")
	}

	// Ensure Email exists
	if !meta.IsDefined("Email") {
		return nil, errors.New("Config: must define Email")
	}

	// Ensure Logfiles exists
	if !meta.IsDefined("Logfiles") {
		return nil, errors.New("Config: must define Logfiles")
	}

	// Ensure MinScore exists
	if !meta.IsDefined("MinScore") {
		return nil, errors.New("Config: must define MinScore")
	}

	// Ensure BanMessage exists
	if !meta.IsDefined("BanMessage") {
		return nil, errors.New("Config: must define BanMessage")
	}

	return config, nil
}
<commit_msg>Make BanMessage configurable.<commit_after>/*
 *  zanproxy: a proxy detector for Zandronum
 *  Copyright (C) 2016  Alex Mayfield <alexmax2742@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package main

import (
	"errors"

	"github.com/BurntSushi/toml"
)

// Config contains the configuration for the program.
type Config struct {
	Banlist    string
	Email      string
	Logfiles   []string
	MinScore   float64
	BanMessage string
}

// NewConfig creates a new instance of Config from a configuration file.
func NewConfig(filename string) (*Config, error) {
	// Load configuration file
	config := &Config{}
	meta, err := toml.DecodeFile(filename, config)
	if err != nil {
		return nil, err
	}

	// Ensure Banlist exists
	if !meta.IsDefined("Banlist") {
		return nil, errors.New("Config: must define Banlist")
	}

	// Ensure Email exists
	if !meta.IsDefined("Email") {
		return nil, errors.New("Config: must define Email")
	}

	// Ensure Logfiles exists
	if !meta.IsDefined("Logfiles") {
		return nil, errors.New("Config: must define Logfiles")
	}

	// Ensure MinScore exists
	if !meta.IsDefined("MinScore") {
		return nil, errors.New("Config: must define MinScore")
	}

	// Ensure BanMessage exists, else use a sane default
	if !meta.IsDefined("BanMessage") {
		config.BanMessage = "You have been banned on suspicion of proxy use.  If you believe this is in error, please contact the administrators."
	}

	return config, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"appengine"
	"appengine/user"
	"bytes"
	"code.google.com/p/rsc/blog/atom"
	"encoding/xml"
	"fmt"
	mpg "github.com/mjibson/MiniProfiler/go/miniprofiler_gae"
	"github.com/mjibson/goon"
	"github.com/mjibson/rssgo"
	"html/template"
	"net/http"
	"net/url"
	"time"
)

func serveError(w http.ResponseWriter, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

type Includes struct {
	Angular      string
	BootstrapCss string
	BootstrapJs  string
	Jquery       string
	MiniProfiler template.HTML
	User         *User
}

var (
	Angular      string
	BootstrapCss string
	BootstrapJs  string
	Jquery       string
)

func init() {
	angular_ver := "1.0.5"
	bootstrap_ver := "2.3.1"
	jquery_ver := "1.9.1"

	if appengine.IsDevAppServer() {
		Angular = fmt.Sprintf("/static/js/angular-%v.js", angular_ver)
		BootstrapCss = fmt.Sprintf("/static/css/bootstrap-%v.css", bootstrap_ver)
		BootstrapJs = fmt.Sprintf("/static/js/bootstrap-%v.js", bootstrap_ver)
		Jquery = fmt.Sprintf("/static/js/jquery-%v.js", jquery_ver)
	} else {
		Angular = fmt.Sprintf("//ajax.googleapis.com/ajax/libs/angularjs/%v/angular.min.js", angular_ver)
		BootstrapCss = fmt.Sprintf("//netdna.bootstrapcdn.com/twitter-bootstrap/%v/css/bootstrap-combined.min.css", bootstrap_ver)
		BootstrapJs = fmt.Sprintf("//netdna.bootstrapcdn.com/twitter-bootstrap/%v/js/bootstrap.min.js", bootstrap_ver)
		Jquery = fmt.Sprintf("//ajax.googleapis.com/ajax/libs/jquery/%v/jquery.min.js", jquery_ver)
	}
}

func includes(c mpg.Context) *Includes {
	i := &Includes{
		Angular:      Angular,
		BootstrapCss: BootstrapCss,
		BootstrapJs:  BootstrapJs,
		Jquery:       Jquery,
		MiniProfiler: c.P.Includes(),
	}

	if u := user.Current(c); u != nil {
		gn := goon.FromContext(c)
		user := new(User)
		if e, err := gn.GetById(user, u.ID, 0, nil); err == nil && !e.NotFound {
			i.User = user
		}
	}

	return i
}

const atomDateFormat = "2006-01-02T15:04:05-07:00"

func ParseAtomDate(d atom.TimeStr) time.Time {
	t, err := time.Parse(atomDateFormat, string(d))
	if err != nil {
		return time.Time{}
	}
	return t
}

func ParseFeed(c appengine.Context, b []byte) (*Feed, []*Story) {
	f := Feed{}
	var s []*Story

	a := atom.Feed{}
	var atomerr, err error
	d := xml.NewDecoder(bytes.NewReader(b))
	d.CharsetReader = CharsetReader
	if atomerr = d.Decode(&a); atomerr == nil {
		f.Title = a.Title
		if a.Updated != "" {
			f.Updated = ParseAtomDate(a.Updated)
		}
		for _, l := range a.Link {
			if l.Rel != "self" {
				f.Link = l.Href
				break
			}
		}

		for _, i := range a.Entry {
			st := Story{
				Id:        i.ID,
				Title:     i.Title,
				Published: ParseAtomDate(i.Published),
				Updated:   ParseAtomDate(i.Updated),
			}
			if len(i.Link) > 0 {
				st.Link = i.Link[0].Href
			}
			if i.Author != nil {
				st.Author = i.Author.Name
			}
			if i.Summary != nil {
				st.Summary = i.Summary.Body
			}
			if i.Content != nil {
				st.content = Sanitize(i.Content.Body)
			}
			st.Date = st.Updated.Unix()
			s = append(s, &st)
		}

		return parseFix(&f, s)
	}

	r := rssgo.Rss{}
	d = xml.NewDecoder(bytes.NewReader(b))
	d.CharsetReader = CharsetReader
	if err = d.Decode(&r); err == nil {
		f.Title = r.Title
		f.Link = r.Link
		if t, err := rssgo.ParseRssDate(r.LastBuildDate); err == nil {
			f.Updated = t
		} else {
			if t, err = rssgo.ParseRssDate(r.PubDate); err == nil {
				f.Updated = t
			}
		}

		for _, i := range r.Items {
			st := Story{
				Link:   i.Link,
				Author: i.Author,
			}
			if i.Title != "" {
				st.Title = i.Title
				if i.Description != "" {
					st.Summary = i.Description
				}
			} else if i.Description != "" {
				i.Title = i.Description
			} else {
				c.Errorf("rss feed requires title or description")
				return nil, nil
			}
			if i.Content != "" {
				st.content = Sanitize(i.Content)
			}
			if i.Guid != nil {
				st.Id = i.Guid.Guid
			} else {
				st.Id = i.Title
			}
			var t time.Time
			if t, err = rssgo.ParseRssDate(i.PubDate); err == nil {
			} else if t, err = rssgo.ParseRssDate(i.Date); err == nil {
			} else if t, err = rssgo.ParseRssDate(i.Published); err == nil {
			} else {
				c.Errorf("could not parse date: %v, %v, %v", i.PubDate, i.Date, i.Published)
				t = time.Now()
			}
			st.Published = t
			st.Updated = t
			st.Date = t.Unix()

			s = append(s, &st)
		}

		return parseFix(&f, s)
	}

	c.Errorf("atom parse error: %s", atomerr.Error())
	c.Errorf("xml parse error: %s", err.Error())
	return nil, nil
}

func parseFix(f *Feed, ss []*Story) (*Feed, []*Story) {
	for _, s := range ss {
		if s.Link == "" {
			if u, err := url.Parse(s.Id); err == nil {
				s.Link = u.String()
			}
		}
	}

	return f, ss
}
<commit_msg>Comment this function<commit_after>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"appengine"
	"appengine/user"
	"bytes"
	"code.google.com/p/rsc/blog/atom"
	"encoding/xml"
	"fmt"
	mpg "github.com/mjibson/MiniProfiler/go/miniprofiler_gae"
	"github.com/mjibson/goon"
	"github.com/mjibson/rssgo"
	"html/template"
	"net/http"
	"net/url"
	"time"
)

func serveError(w http.ResponseWriter, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

type Includes struct {
	Angular      string
	BootstrapCss string
	BootstrapJs  string
	Jquery       string
	MiniProfiler template.HTML
	User         *User
}

var (
	Angular      string
	BootstrapCss string
	BootstrapJs  string
	Jquery       string
)

func init() {
	angular_ver := "1.0.5"
	bootstrap_ver := "2.3.1"
	jquery_ver := "1.9.1"

	if appengine.IsDevAppServer() {
		Angular = fmt.Sprintf("/static/js/angular-%v.js", angular_ver)
		BootstrapCss = fmt.Sprintf("/static/css/bootstrap-%v.css", bootstrap_ver)
		BootstrapJs = fmt.Sprintf("/static/js/bootstrap-%v.js", bootstrap_ver)
		Jquery = fmt.Sprintf("/static/js/jquery-%v.js", jquery_ver)
	} else {
		Angular = fmt.Sprintf("//ajax.googleapis.com/ajax/libs/angularjs/%v/angular.min.js", angular_ver)
		BootstrapCss = fmt.Sprintf("//netdna.bootstrapcdn.com/twitter-bootstrap/%v/css/bootstrap-combined.min.css", bootstrap_ver)
		BootstrapJs = fmt.Sprintf("//netdna.bootstrapcdn.com/twitter-bootstrap/%v/js/bootstrap.min.js", bootstrap_ver)
		Jquery = fmt.Sprintf("//ajax.googleapis.com/ajax/libs/jquery/%v/jquery.min.js", jquery_ver)
	}
}

func includes(c mpg.Context) *Includes {
	i := &Includes{
		Angular:      Angular,
		BootstrapCss: BootstrapCss,
		BootstrapJs:  BootstrapJs,
		Jquery:       Jquery,
		MiniProfiler: c.P.Includes(),
	}

	if u := user.Current(c); u != nil {
		gn := goon.FromContext(c)
		user := new(User)
		if e, err := gn.GetById(user, u.ID, 0, nil); err == nil && !e.NotFound {
			i.User = user
		}
	}

	return i
}

const atomDateFormat = "2006-01-02T15:04:05-07:00"

func ParseAtomDate(d atom.TimeStr) time.Time {
	t, err := time.Parse(atomDateFormat, string(d))
	if err != nil {
		return time.Time{}
	}
	return t
}

func ParseFeed(c appengine.Context, b []byte) (*Feed, []*Story) {
	f := Feed{}
	var s []*Story

	a := atom.Feed{}
	var atomerr, err error
	d := xml.NewDecoder(bytes.NewReader(b))
	d.CharsetReader = CharsetReader
	if atomerr = d.Decode(&a); atomerr == nil {
		f.Title = a.Title
		if a.Updated != "" {
			f.Updated = ParseAtomDate(a.Updated)
		}
		for _, l := range a.Link {
			if l.Rel != "self" {
				f.Link = l.Href
				break
			}
		}

		for _, i := range a.Entry {
			st := Story{
				Id:        i.ID,
				Title:     i.Title,
				Published: ParseAtomDate(i.Published),
				Updated:   ParseAtomDate(i.Updated),
			}
			if len(i.Link) > 0 {
				st.Link = i.Link[0].Href
			}
			if i.Author != nil {
				st.Author = i.Author.Name
			}
			if i.Summary != nil {
				st.Summary = i.Summary.Body
			}
			if i.Content != nil {
				st.content = Sanitize(i.Content.Body)
			}
			st.Date = st.Updated.Unix()
			s = append(s, &st)
		}

		return parseFix(&f, s)
	}

	r := rssgo.Rss{}
	d = xml.NewDecoder(bytes.NewReader(b))
	d.CharsetReader = CharsetReader
	if err = d.Decode(&r); err == nil {
		f.Title = r.Title
		f.Link = r.Link
		if t, err := rssgo.ParseRssDate(r.LastBuildDate); err == nil {
			f.Updated = t
		} else {
			if t, err = rssgo.ParseRssDate(r.PubDate); err == nil {
				f.Updated = t
			}
		}

		for _, i := range r.Items {
			st := Story{
				Link:   i.Link,
				Author: i.Author,
			}
			if i.Title != "" {
				st.Title = i.Title
				if i.Description != "" {
					st.Summary = i.Description
				}
			} else if i.Description != "" {
				i.Title = i.Description
			} else {
				c.Errorf("rss feed requires title or description")
				return nil, nil
			}
			if i.Content != "" {
				st.content = Sanitize(i.Content)
			}
			if i.Guid != nil {
				st.Id = i.Guid.Guid
			} else {
				st.Id = i.Title
			}
			var t time.Time
			if t, err = rssgo.ParseRssDate(i.PubDate); err == nil {
			} else if t, err = rssgo.ParseRssDate(i.Date); err == nil {
			} else if t, err = rssgo.ParseRssDate(i.Published); err == nil {
			} else {
				c.Errorf("could not parse date: %v, %v, %v", i.PubDate, i.Date, i.Published)
				t = time.Now()
			}
			st.Published = t
			st.Updated = t
			st.Date = t.Unix()

			s = append(s, &st)
		}

		return parseFix(&f, s)
	}

	c.Errorf("atom parse error: %s", atomerr.Error())
	c.Errorf("xml parse error: %s", err.Error())
	return nil, nil
}

func parseFix(f *Feed, ss []*Story) (*Feed, []*Story) {
	for _, s := range ss {
		// if a story doesn't have a link, see if its id is a URL
		if s.Link == "" {
			if u, err := url.Parse(s.Id); err == nil {
				s.Link = u.String()
			}
		}
	}

	return f, ss
}
<|endoftext|>


<commit_before>package jwt

import (
	"fmt"
	"reflect"
	"strings"
	"time"
	"unicode"
)

// JSON является синонимом для быстрого создания map в формате JSON.
type JSON = map[string]interface{}

// Config описывает шаблон для генерации токена. Поля, указанные в нем,
// будут автоматически добавляться при генерации токена. Любые общие
// дополнительные поля для токена можно указать в Private. Если задана функция
// Nonce, то в каждый токен будет добавляться уникальная строка, возвращаемая
// этой функцией.
//
// Для автоматической подписи токена необходимо указать ключ. В зависимости от
// его типа будут использоваться разные алгоритмы для генерации подписи.
// Для *rsa.PrivateKey будет создаваться токен с алгоритмом подписи RS256.
// Для *ecdsa.PrivateKey - ES256, ES384 или ES512, в зависимости от параметров
// созданного ключа. Для string, []byte или любого другого объекта, который
// поддерживает строковое представление (fmt.Stringer) - HS256.
//
// Чтобы указать в заголовке токена идентификатор ключа, используемого для
// подписи, нужно чтобы функция ключа возвращала два значения: первым будет
// KeyID, а вторым - сам ключ для подписи.
type Config struct {
	Issuer    string        // iss - идентификатор выпускающего
	Created   bool          // iat - добавлять время создания
	Expires   time.Duration // exp - добавлять время жизни
	NotBefore time.Duration // nbf - добавлять время начала действия
	Type      string        // typ - тип токена
	UniqueID  func() string // nonce - генератор случайной строки
	Private   JSON          // дополнительные именованные поля

	Key interface{} // ключ для подписи токена или функция его возвращающая
}

// Token возвращает сгенерированный токен на основании шаблона и
// предоставленных данных. В качестве payload можно указать
// map[string]interface{} или собственный объект. Так же принимается строка:
// в этом случае считается, что она задает единственное значение "sub".
//
// Есть несколько отличий от стандартной сериализации в формат JSON, которые
// заложены в этой функции. Во-первых, все поля, представленные в виде
// time.Time кодируются в числовом виде, а не строками, как это стандартно
// происходит в Go. А не заданные значение time.Time автоматически игнорируются.
// Во-вторых, в структурах для именования полей могут использоваться теги "json"
// и "jwt". Последний имеет чуть больший приоритет, поэтому вы можете специально
// для токенов указывать другие имена. Если имя поля не определено в теге, то
// используется само имя поля, но первая его буква при этом становится строчной,
// что больше соответствует формату JSON токена.
func (c *Config) Token(claimset interface{}) (string, error) {
	// формируем содержимое токена
	result := make(JSON)

	// добавляем дополнительные поля из шаблона
	for key, value := range c.Private {
		if vt, ok := value.(time.Time); ok {
			if vt.IsZero() {
				continue // игнорируем пустые даты
			}
			value = vt.Unix() // преобразуем в числовой вид
		}
		result[key] = value
	}

	// генерируем поля на основе данных шаблона
	if c.Issuer != "" {
		result["iss"] = c.Issuer
	}

	// добавляем данные с временем
	now := time.Now()
	if c.Created {
		result["iat"] = now.Add(-10 * time.Second).Unix()
	}
	if c.Expires > 0 {
		result["exp"] = now.Add(c.Expires).Unix()
	}
	if c.NotBefore != 0 {
		result["nbf"] = now.Add(c.NotBefore).Unix()
	}
	if c.Type != "" {
		result["typ"] = c.Type
	}
	if c.UniqueID != nil {
		result["jti"] = c.UniqueID()
	}

	// добавляем данные из объекта
	switch claimset := claimset.(type) {
	case string:
		result["sub"] = claimset

	case fmt.Stringer:
		result["sub"] = claimset.String()

	case map[string]string: // только строковые значения
		for key, value := range claimset {
			result[key] = value
		}

	case JSON: // словарь в формате JSON
		for key, value := range claimset {
			// отдельно обрабатываем поля с датой и временем
			if vt, ok := value.(time.Time); ok {
				if vt.IsZero() {
					continue // игнорируем пустые даты
				}
				value = vt.Unix() // преобразуем в числовой вид
			}
			result[key] = value
		}

	default: // поддержка структур
		v := reflect.ValueOf(claimset)
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}

		// проверяем, что данный тип данных мы поддерживаем
		if k := v.Kind(); k == reflect.Invalid || k != reflect.Struct {
			return "", fmt.Errorf("unsupported claimset type %T", claimset)
		}

		typ := v.Type()
		// перебираем все поля структуры
		for i := 0; i < v.NumField(); i++ {
			field := typ.Field(i)
			if field.PkgPath != "" {
				continue // игнорируем приватные поля
			}

			// подбираем имя элемента токена
			tag, ok := field.Tag.Lookup("jwt")
			if !ok {
				tag, ok = field.Tag.Lookup("json")
				if !ok && !strings.Contains(string(field.Tag), ":") {
					tag = string(field.Tag)
				}
			}
			if tag == "-" {
				continue // явно указано игнорирование
			}

			value := v.Field(i)
			// пропускаем пустые значения, которые указано игнорировать
			if idx := strings.IndexByte(tag, ','); idx >= 0 {
				if strings.Contains(tag[idx+1:], "omitempty") && value.IsZero() {
					continue
				}
				tag = tag[:idx]
			}

			// если имя не определено в теге элемента, то берем имя поля
			if tag == "" {
				// первую букву в имени приводим к нижнему регистру
				runes := []rune(field.Name)
				runes[0] = unicode.ToLower(runes[0])
				tag = string(runes)
			}

			val := value.Interface()
			// подмена данных для времени
			if vt, ok := val.(time.Time); ok {
				if vt.IsZero() {
					continue // игнорируем пустые даты
				}
				val = vt.Unix() // подменяем на число
			}
			// добавляем значение поля в наш результирующий словарь
			result[tag] = val
		}
	}

	// кодируем и возвращаем токен
	return Encode(result, c.Key)
}
<commit_msg>fix pointer<commit_after>package jwt

import (
	"fmt"
	"reflect"
	"strings"
	"time"
	"unicode"
)

// JSON является синонимом для быстрого создания map в формате JSON.
type JSON = map[string]interface{}

// Config описывает шаблон для генерации токена. Поля, указанные в нем,
// будут автоматически добавляться при генерации токена. Любые общие
// дополнительные поля для токена можно указать в Private. Если задана функция
// Nonce, то в каждый токен будет добавляться уникальная строка, возвращаемая
// этой функцией.
//
// Для автоматической подписи токена необходимо указать ключ. В зависимости от
// его типа будут использоваться разные алгоритмы для генерации подписи.
// Для *rsa.PrivateKey будет создаваться токен с алгоритмом подписи RS256.
// Для *ecdsa.PrivateKey - ES256, ES384 или ES512, в зависимости от параметров
// созданного ключа. Для string, []byte или любого другого объекта, который
// поддерживает строковое представление (fmt.Stringer) - HS256.
//
// Чтобы указать в заголовке токена идентификатор ключа, используемого для
// подписи, нужно чтобы функция ключа возвращала два значения: первым будет
// KeyID, а вторым - сам ключ для подписи.
type Config struct {
	Issuer    string        // iss - идентификатор выпускающего
	Created   bool          // iat - добавлять время создания
	Expires   time.Duration // exp - добавлять время жизни
	NotBefore time.Duration // nbf - добавлять время начала действия
	Type      string        // typ - тип токена
	UniqueID  func() string // nonce - генератор случайной строки
	Private   JSON          // дополнительные именованные поля

	Key interface{} // ключ для подписи токена или функция его возвращающая
}

// Token возвращает сгенерированный токен на основании шаблона и
// предоставленных данных. В качестве payload можно указать
// map[string]interface{} или собственный объект. Так же принимается строка:
// в этом случае считается, что она задает единственное значение "sub".
//
// Есть несколько отличий от стандартной сериализации в формат JSON, которые
// заложены в этой функции. Во-первых, все поля, представленные в виде
// time.Time кодируются в числовом виде, а не строками, как это стандартно
// происходит в Go. А не заданные значение time.Time автоматически игнорируются.
// Во-вторых, в структурах для именования полей могут использоваться теги "json"
// и "jwt". Последний имеет чуть больший приоритет, поэтому вы можете специально
// для токенов указывать другие имена. Если имя поля не определено в теге, то
// используется само имя поля, но первая его буква при этом становится строчной,
// что больше соответствует формату JSON токена.
func (c Config) Token(claimset interface{}) (string, error) {
	// формируем содержимое токена
	result := make(JSON)

	// добавляем дополнительные поля из шаблона
	for key, value := range c.Private {
		if vt, ok := value.(time.Time); ok {
			if vt.IsZero() {
				continue // игнорируем пустые даты
			}
			value = vt.Unix() // преобразуем в числовой вид
		}
		result[key] = value
	}

	// генерируем поля на основе данных шаблона
	if c.Issuer != "" {
		result["iss"] = c.Issuer
	}

	// добавляем данные с временем
	now := time.Now()
	if c.Created {
		result["iat"] = now.Add(-10 * time.Second).Unix()
	}
	if c.Expires > 0 {
		result["exp"] = now.Add(c.Expires).Unix()
	}
	if c.NotBefore != 0 {
		result["nbf"] = now.Add(c.NotBefore).Unix()
	}
	if c.Type != "" {
		result["typ"] = c.Type
	}
	if c.UniqueID != nil {
		result["jti"] = c.UniqueID()
	}

	// добавляем данные из объекта
	switch claimset := claimset.(type) {
	case string:
		result["sub"] = claimset

	case fmt.Stringer:
		result["sub"] = claimset.String()

	case map[string]string: // только строковые значения
		for key, value := range claimset {
			result[key] = value
		}

	case JSON: // словарь в формате JSON
		for key, value := range claimset {
			// отдельно обрабатываем поля с датой и временем
			if vt, ok := value.(time.Time); ok {
				if vt.IsZero() {
					continue // игнорируем пустые даты
				}
				value = vt.Unix() // преобразуем в числовой вид
			}
			result[key] = value
		}

	default: // поддержка структур
		v := reflect.ValueOf(claimset)
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}

		// проверяем, что данный тип данных мы поддерживаем
		if k := v.Kind(); k == reflect.Invalid || k != reflect.Struct {
			return "", fmt.Errorf("unsupported claimset type %T", claimset)
		}

		typ := v.Type()
		// перебираем все поля структуры
		for i := 0; i < v.NumField(); i++ {
			field := typ.Field(i)
			if field.PkgPath != "" {
				continue // игнорируем приватные поля
			}

			// подбираем имя элемента токена
			tag, ok := field.Tag.Lookup("jwt")
			if !ok {
				tag, ok = field.Tag.Lookup("json")
				if !ok && !strings.Contains(string(field.Tag), ":") {
					tag = string(field.Tag)
				}
			}
			if tag == "-" {
				continue // явно указано игнорирование
			}

			value := v.Field(i)
			// пропускаем пустые значения, которые указано игнорировать
			if idx := strings.IndexByte(tag, ','); idx >= 0 {
				if strings.Contains(tag[idx+1:], "omitempty") && value.IsZero() {
					continue
				}
				tag = tag[:idx]
			}

			// если имя не определено в теге элемента, то берем имя поля
			if tag == "" {
				// первую букву в имени приводим к нижнему регистру
				runes := []rune(field.Name)
				runes[0] = unicode.ToLower(runes[0])
				tag = string(runes)
			}

			val := value.Interface()
			// подмена данных для времени
			if vt, ok := val.(time.Time); ok {
				if vt.IsZero() {
					continue // игнорируем пустые даты
				}
				val = vt.Unix() // подменяем на число
			}
			// добавляем значение поля в наш результирующий словарь
			result[tag] = val
		}
	}

	// кодируем и возвращаем токен
	return Encode(result, c.Key)
}
<|endoftext|>


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

package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/jessevdk/go-flags"
	"github.com/osrg/gobgp/config"
	ops "github.com/osrg/gobgp/openswitch"
	"github.com/osrg/gobgp/packet"
	"github.com/osrg/gobgp/server"
	"io/ioutil"
	"log/syslog"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
)

func main() {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM)

	var opts struct {
		ConfigFile    string `short:"f" long:"config-file" description:"specifying a config file"`
		LogLevel      string `short:"l" long:"log-level" description:"specifying log level"`
		LogPlain      bool   `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
		UseSyslog     string `short:"s" long:"syslog" description:"use syslogd"`
		Facility      string `long:"syslog-facility" description:"specify syslog facility"`
		DisableStdlog bool   `long:"disable-stdlog" description:"disable standard logging"`
		CPUs          int    `long:"cpus" description:"specify the number of CPUs to be used"`
		Ops           bool   `long:"openswitch" description:"openswitch mode"`
	}
	_, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	if opts.CPUs == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		if runtime.NumCPU() < opts.CPUs {
			log.Errorf("Only %d CPUs are available but %d is specified", runtime.NumCPU(), opts.CPUs)
			os.Exit(1)
		}
		runtime.GOMAXPROCS(opts.CPUs)
	}

	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	switch opts.LogLevel {
	case "debug":
		log.SetLevel(log.DebugLevel)
	case "info":
		log.SetLevel(log.InfoLevel)
	default:
		log.SetLevel(log.InfoLevel)
	}

	if opts.DisableStdlog == true {
		log.SetOutput(ioutil.Discard)
	} else {
		log.SetOutput(os.Stdout)
	}

	if opts.UseSyslog != "" {
		dst := strings.SplitN(opts.UseSyslog, ":", 2)
		network := ""
		addr := ""
		if len(dst) == 2 {
			network = dst[0]
			addr = dst[1]
		}

		facility := syslog.Priority(0)
		switch opts.Facility {
		case "kern":
			facility = syslog.LOG_KERN
		case "user":
			facility = syslog.LOG_USER
		case "mail":
			facility = syslog.LOG_MAIL
		case "daemon":
			facility = syslog.LOG_DAEMON
		case "auth":
			facility = syslog.LOG_AUTH
		case "syslog":
			facility = syslog.LOG_SYSLOG
		case "lpr":
			facility = syslog.LOG_LPR
		case "news":
			facility = syslog.LOG_NEWS
		case "uucp":
			facility = syslog.LOG_UUCP
		case "cron":
			facility = syslog.LOG_CRON
		case "authpriv":
			facility = syslog.LOG_AUTHPRIV
		case "ftp":
			facility = syslog.LOG_FTP
		case "local0":
			facility = syslog.LOG_LOCAL0
		case "local1":
			facility = syslog.LOG_LOCAL1
		case "local2":
			facility = syslog.LOG_LOCAL2
		case "local3":
			facility = syslog.LOG_LOCAL3
		case "local4":
			facility = syslog.LOG_LOCAL4
		case "local5":
			facility = syslog.LOG_LOCAL5
		case "local6":
			facility = syslog.LOG_LOCAL6
		case "local7":
			facility = syslog.LOG_LOCAL7
		}

		hook, err := logrus_syslog.NewSyslogHook(network, addr, syslog.LOG_INFO|facility, "bgpd")
		if err != nil {
			log.Error("Unable to connect to syslog daemon, ", opts.UseSyslog)
			os.Exit(1)
		} else {
			log.AddHook(hook)
		}
	}

	if opts.LogPlain == false {
		log.SetFormatter(&log.JSONFormatter{})
	}

	log.Info("gobgpd started")

	configCh := make(chan config.BgpConfigSet)
	reloadCh := make(chan bool)
	bgpServer := server.NewBgpServer(bgp.BGP_PORT)
	if opts.Ops {
		m, err := ops.NewOpsConfigManager(bgpServer.GrpcReqCh)
		if err != nil {
			log.Errorf("Failed to start ops config manager: %s", err)
			os.Exit(1)
		}
		go m.Serve()
	} else if opts.ConfigFile != "" {
		go config.ReadConfigfileServe(opts.ConfigFile, configCh, reloadCh)
		reloadCh <- true
	}
	go bgpServer.Serve()

	// start grpc Server
	grpcServer := server.NewGrpcServer(server.GRPC_PORT, bgpServer.GrpcReqCh)
	go grpcServer.Serve()

	var bgpConfig *config.Bgp = nil
	var policyConfig *config.RoutingPolicy = nil
	for {
		select {
		case newConfig := <-configCh:
			var added, deleted, updated []config.Neighbor

			if bgpConfig == nil {
				bgpServer.SetGlobalType(newConfig.Bgp.Global)
				bgpConfig = &newConfig.Bgp
				bgpServer.SetRpkiConfig(newConfig.Bgp.RpkiServers)
				bgpServer.SetBmpConfig(newConfig.Bgp.BmpServers)
				added = newConfig.Bgp.Neighbors.NeighborList
				deleted = []config.Neighbor{}
				updated = []config.Neighbor{}
			} else {
				bgpConfig, added, deleted, updated = config.UpdateConfig(bgpConfig, &newConfig.Bgp)
			}

			if policyConfig == nil {
				policyConfig = &newConfig.Policy
				// FIXME: Currently the following code
				// is safe because the above
				// SetRpkiConfig will be blocked
				// because the length of rpkiConfigCh
				// is zero. So server.GlobalRib is
				// allocated before the above
				// SetPolicy. But this should be
				// handled more cleanly.
				if err := bgpServer.SetPolicy(newConfig.Policy); err != nil {
					log.Fatal(err)
				}
			} else {
				if config.CheckPolicyDifference(policyConfig, &newConfig.Policy) {
					log.Info("Policy config is updated")
					bgpServer.UpdatePolicy(newConfig.Policy)
				}
			}

			for _, p := range added {
				log.Infof("Peer %v is added", p.NeighborConfig.NeighborAddress)
				bgpServer.PeerAdd(p)
			}
			for _, p := range deleted {
				log.Infof("Peer %v is deleted", p.NeighborConfig.NeighborAddress)
				bgpServer.PeerDelete(p)
			}
			for _, p := range updated {
				log.Infof("Peer %v is updated", p.NeighborConfig.NeighborAddress)
				bgpServer.PeerUpdate(p)
			}
		case sig := <-sigCh:
			switch sig {
			case syscall.SIGHUP:
				log.Info("reload the config file")
				reloadCh <- true
			case syscall.SIGKILL, syscall.SIGTERM:
				bgpServer.Shutdown()
			}
		}
	}
}
<commit_msg>gobgpd: make blank bmpconfig when no config file<commit_after>// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/jessevdk/go-flags"
	"github.com/osrg/gobgp/config"
	ops "github.com/osrg/gobgp/openswitch"
	"github.com/osrg/gobgp/packet"
	"github.com/osrg/gobgp/server"
	"io/ioutil"
	"log/syslog"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
)

func main() {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM)

	var opts struct {
		ConfigFile    string `short:"f" long:"config-file" description:"specifying a config file"`
		LogLevel      string `short:"l" long:"log-level" description:"specifying log level"`
		LogPlain      bool   `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
		UseSyslog     string `short:"s" long:"syslog" description:"use syslogd"`
		Facility      string `long:"syslog-facility" description:"specify syslog facility"`
		DisableStdlog bool   `long:"disable-stdlog" description:"disable standard logging"`
		CPUs          int    `long:"cpus" description:"specify the number of CPUs to be used"`
		Ops           bool   `long:"openswitch" description:"openswitch mode"`
	}
	_, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	if opts.CPUs == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		if runtime.NumCPU() < opts.CPUs {
			log.Errorf("Only %d CPUs are available but %d is specified", runtime.NumCPU(), opts.CPUs)
			os.Exit(1)
		}
		runtime.GOMAXPROCS(opts.CPUs)
	}

	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	switch opts.LogLevel {
	case "debug":
		log.SetLevel(log.DebugLevel)
	case "info":
		log.SetLevel(log.InfoLevel)
	default:
		log.SetLevel(log.InfoLevel)
	}

	if opts.DisableStdlog == true {
		log.SetOutput(ioutil.Discard)
	} else {
		log.SetOutput(os.Stdout)
	}

	if opts.UseSyslog != "" {
		dst := strings.SplitN(opts.UseSyslog, ":", 2)
		network := ""
		addr := ""
		if len(dst) == 2 {
			network = dst[0]
			addr = dst[1]
		}

		facility := syslog.Priority(0)
		switch opts.Facility {
		case "kern":
			facility = syslog.LOG_KERN
		case "user":
			facility = syslog.LOG_USER
		case "mail":
			facility = syslog.LOG_MAIL
		case "daemon":
			facility = syslog.LOG_DAEMON
		case "auth":
			facility = syslog.LOG_AUTH
		case "syslog":
			facility = syslog.LOG_SYSLOG
		case "lpr":
			facility = syslog.LOG_LPR
		case "news":
			facility = syslog.LOG_NEWS
		case "uucp":
			facility = syslog.LOG_UUCP
		case "cron":
			facility = syslog.LOG_CRON
		case "authpriv":
			facility = syslog.LOG_AUTHPRIV
		case "ftp":
			facility = syslog.LOG_FTP
		case "local0":
			facility = syslog.LOG_LOCAL0
		case "local1":
			facility = syslog.LOG_LOCAL1
		case "local2":
			facility = syslog.LOG_LOCAL2
		case "local3":
			facility = syslog.LOG_LOCAL3
		case "local4":
			facility = syslog.LOG_LOCAL4
		case "local5":
			facility = syslog.LOG_LOCAL5
		case "local6":
			facility = syslog.LOG_LOCAL6
		case "local7":
			facility = syslog.LOG_LOCAL7
		}

		hook, err := logrus_syslog.NewSyslogHook(network, addr, syslog.LOG_INFO|facility, "bgpd")
		if err != nil {
			log.Error("Unable to connect to syslog daemon, ", opts.UseSyslog)
			os.Exit(1)
		} else {
			log.AddHook(hook)
		}
	}

	if opts.LogPlain == false {
		log.SetFormatter(&log.JSONFormatter{})
	}

	log.Info("gobgpd started")

	configCh := make(chan config.BgpConfigSet)
	reloadCh := make(chan bool)
	bgpServer := server.NewBgpServer(bgp.BGP_PORT)
	if opts.Ops {
		m, err := ops.NewOpsConfigManager(bgpServer.GrpcReqCh)
		if err != nil {
			log.Errorf("Failed to start ops config manager: %s", err)
			os.Exit(1)
		}
		go m.Serve()
	} else if opts.ConfigFile != "" {
		go config.ReadConfigfileServe(opts.ConfigFile, configCh, reloadCh)
		reloadCh <- true
	}
	go bgpServer.Serve()

	// start grpc Server
	grpcServer := server.NewGrpcServer(server.GRPC_PORT, bgpServer.GrpcReqCh)
	go grpcServer.Serve()

	if opts.ConfigFile == "" {
		bgpServer.SetBmpConfig(config.BmpServers{
			BmpServerList: []config.BmpServer{},
		})
	}
	var bgpConfig *config.Bgp = nil
	var policyConfig *config.RoutingPolicy = nil
	for {
		select {
		case newConfig := <-configCh:
			var added, deleted, updated []config.Neighbor

			if bgpConfig == nil {
				bgpServer.SetGlobalType(newConfig.Bgp.Global)
				bgpConfig = &newConfig.Bgp
				bgpServer.SetRpkiConfig(newConfig.Bgp.RpkiServers)
				bgpServer.SetBmpConfig(newConfig.Bgp.BmpServers)
				added = newConfig.Bgp.Neighbors.NeighborList
				deleted = []config.Neighbor{}
				updated = []config.Neighbor{}
			} else {
				bgpConfig, added, deleted, updated = config.UpdateConfig(bgpConfig, &newConfig.Bgp)
			}

			if policyConfig == nil {
				policyConfig = &newConfig.Policy
				// FIXME: Currently the following code
				// is safe because the above
				// SetRpkiConfig will be blocked
				// because the length of rpkiConfigCh
				// is zero. So server.GlobalRib is
				// allocated before the above
				// SetPolicy. But this should be
				// handled more cleanly.
				if err := bgpServer.SetPolicy(newConfig.Policy); err != nil {
					log.Fatal(err)
				}
			} else {
				if config.CheckPolicyDifference(policyConfig, &newConfig.Policy) {
					log.Info("Policy config is updated")
					bgpServer.UpdatePolicy(newConfig.Policy)
				}
			}

			for _, p := range added {
				log.Infof("Peer %v is added", p.NeighborConfig.NeighborAddress)
				bgpServer.PeerAdd(p)
			}
			for _, p := range deleted {
				log.Infof("Peer %v is deleted", p.NeighborConfig.NeighborAddress)
				bgpServer.PeerDelete(p)
			}
			for _, p := range updated {
				log.Infof("Peer %v is updated", p.NeighborConfig.NeighborAddress)
				bgpServer.PeerUpdate(p)
			}
		case sig := <-sigCh:
			switch sig {
			case syscall.SIGHUP:
				log.Info("reload the config file")
				reloadCh <- true
			case syscall.SIGKILL, syscall.SIGTERM:
				bgpServer.Shutdown()
			}
		}
	}
}
<|endoftext|>


<commit_before>package controlapi

import (
	"errors"
	"reflect"
	"strconv"

	"github.com/docker/engine-api/types/reference"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/identity"
	"github.com/docker/swarmkit/manager/scheduler"
	"github.com/docker/swarmkit/manager/state/store"
	"github.com/docker/swarmkit/protobuf/ptypes"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

var (
	errNetworkUpdateNotSupported = errors.New("changing network in service is not supported")
	errModeChangeNotAllowed      = errors.New("service mode change is not allowed")
)

func validateResources(r *api.Resources) error {
	if r == nil {
		return nil
	}

	if r.NanoCPUs != 0 && r.NanoCPUs < 1e6 {
		return grpc.Errorf(codes.InvalidArgument, "invalid cpu value %g: Must be at least %g", float64(r.NanoCPUs)/1e9, 1e6/1e9)
	}

	if r.MemoryBytes != 0 && r.MemoryBytes < 4*1024*1024 {
		return grpc.Errorf(codes.InvalidArgument, "invalid memory value %d: Must be at least 4MiB", r.MemoryBytes)
	}
	return nil
}

func validateResourceRequirements(r *api.ResourceRequirements) error {
	if r == nil {
		return nil
	}
	if err := validateResources(r.Limits); err != nil {
		return err
	}
	if err := validateResources(r.Reservations); err != nil {
		return err
	}
	return nil
}

func validateRestartPolicy(rp *api.RestartPolicy) error {
	if rp == nil {
		return nil
	}

	if rp.Delay != nil {
		delay, err := ptypes.Duration(rp.Delay)
		if err != nil {
			return err
		}
		if delay < 0 {
			return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-delay cannot be negative")
		}
	}

	if rp.Window != nil {
		win, err := ptypes.Duration(rp.Window)
		if err != nil {
			return err
		}
		if win < 0 {
			return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-window cannot be negative")
		}
	}

	return nil
}

func validatePlacement(placement *api.Placement) error {
	if placement == nil {
		return nil
	}
	_, err := scheduler.ParseExprs(placement.Constraints)
	return err
}

func validateUpdate(uc *api.UpdateConfig) error {
	if uc == nil {
		return nil
	}

	delay, err := ptypes.Duration(&uc.Delay)
	if err != nil {
		return err
	}

	if delay < 0 {
		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: update-delay cannot be negative")
	}

	return nil
}

func validateTask(taskSpec api.TaskSpec) error {
	if err := validateResourceRequirements(taskSpec.Resources); err != nil {
		return err
	}

	if err := validateRestartPolicy(taskSpec.Restart); err != nil {
		return err
	}

	if err := validatePlacement(taskSpec.Placement); err != nil {
		return err
	}

	if taskSpec.GetRuntime() == nil {
		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
	}

	_, ok := taskSpec.GetRuntime().(*api.TaskSpec_Container)
	if !ok {
		return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec")
	}

	container := taskSpec.GetContainer()
	if container == nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec")
	}

	if container.Image == "" {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided")
	}

	if _, _, err := reference.Parse(container.Image); err != nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image)
	}
	return nil
}

func validateEndpointSpec(epSpec *api.EndpointSpec) error {
	// Endpoint spec is optional
	if epSpec == nil {
		return nil
	}

	if len(epSpec.Ports) > 0 && epSpec.Mode == api.ResolutionModeDNSRoundRobin {
		return grpc.Errorf(codes.InvalidArgument, "EndpointSpec: ports can't be used with dnsrr mode")
	}

	portSet := make(map[api.PortConfig]struct{})
	for _, port := range epSpec.Ports {
		if _, ok := portSet[*port]; ok {
			return grpc.Errorf(codes.InvalidArgument, "EndpointSpec: duplicate ports provided")
		}

		portSet[*port] = struct{}{}
	}

	return nil
}

func validateServiceSpec(spec *api.ServiceSpec) error {
	if spec == nil {
		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateAnnotations(spec.Annotations); err != nil {
		return err
	}
	if err := validateTask(spec.Task); err != nil {
		return err
	}
	if err := validateUpdate(spec.Update); err != nil {
		return err
	}
	if err := validateEndpointSpec(spec.Endpoint); err != nil {
		return err
	}
	return nil
}

// checkPortConflicts does a best effort to find if the passed in spec has port
// conflicts with existing services.
func (s *Server) checkPortConflicts(spec *api.ServiceSpec) error {
	if spec.Endpoint == nil {
		return nil
	}

	pcToString := func(pc *api.PortConfig) string {
		port := strconv.FormatUint(uint64(pc.PublishedPort), 10)
		return port + "/" + pc.Protocol.String()
	}

	reqPorts := make(map[string]bool)
	for _, pc := range spec.Endpoint.Ports {
		if pc.PublishedPort > 0 {
			reqPorts[pcToString(pc)] = true
		}
	}
	if len(reqPorts) == 0 {
		return nil
	}

	var (
		services []*api.Service
		err      error
	)

	s.store.View(func(tx store.ReadTx) {
		services, err = store.FindServices(tx, store.All)
	})
	if err != nil {
		return err
	}

	for _, service := range services {
		if service.Spec.Endpoint != nil {
			for _, pc := range service.Spec.Endpoint.Ports {
				if reqPorts[pcToString(pc)] {
					return grpc.Errorf(codes.InvalidArgument, "port '%d' is already in use by service %s", pc.PublishedPort, service.ID)
				}
			}
		}
		if service.Endpoint != nil {
			for _, pc := range service.Endpoint.Ports {
				if reqPorts[pcToString(pc)] {
					return grpc.Errorf(codes.InvalidArgument, "port '%d' is already in use by service %s", pc.PublishedPort, service.ID)
				}
			}
		}
	}
	return nil
}

// CreateService creates and return a Service based on the provided ServiceSpec.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns `AlreadyExists` if the ServiceID conflicts.
// - Returns an error if the creation fails.
func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRequest) (*api.CreateServiceResponse, error) {
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	if err := s.checkPortConflicts(request.Spec); err != nil {
		return nil, err
	}

	// TODO(aluzzardi): Consider using `Name` as a primary key to handle
	// duplicate creations. See #65
	service := &api.Service{
		ID:   identity.NewID(),
		Spec: *request.Spec,
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.CreateService(tx, service)
	})
	if err != nil {
		return nil, err
	}

	return &api.CreateServiceResponse{
		Service: service,
	}, nil
}

// GetService returns a Service given a ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
func (s *Server) GetService(ctx context.Context, request *api.GetServiceRequest) (*api.GetServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	var service *api.Service
	s.store.View(func(tx store.ReadTx) {
		service = store.GetService(tx, request.ServiceID)
	})
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}

	return &api.GetServiceResponse{
		Service: service,
	}, nil
}

// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
	if request.ServiceID == "" || request.ServiceVersion == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	var service *api.Service
	s.store.View(func(tx store.ReadTx) {
		service = store.GetService(tx, request.ServiceID)
	})
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}

	if request.Spec.Endpoint != nil && !reflect.DeepEqual(request.Spec.Endpoint, service.Spec.Endpoint) {
		if err := s.checkPortConflicts(request.Spec); err != nil {
			return nil, err
		}
	}

	err := s.store.Update(func(tx store.Tx) error {
		service = store.GetService(tx, request.ServiceID)
		if service == nil {
			return nil
		}
		// temporary disable network update
		if request.Spec != nil && !reflect.DeepEqual(request.Spec.Networks, service.Spec.Networks) {
			return errNetworkUpdateNotSupported
		}

		// orchestrator is designed to be stateless, so it should not deal
		// with service mode change (comparing current config with previous config).
		// proper way to change service mode is to delete and re-add.
		if request.Spec != nil && reflect.TypeOf(service.Spec.Mode) != reflect.TypeOf(request.Spec.Mode) {
			return errModeChangeNotAllowed
		}
		service.Meta.Version = *request.ServiceVersion
		service.Spec = *request.Spec.Copy()

		// Reset update status
		service.UpdateStatus = nil

		return store.UpdateService(tx, service)
	})
	if err != nil {
		return nil, err
	}
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}
	return &api.UpdateServiceResponse{
		Service: service,
	}, nil
}

// RemoveService removes a Service referenced by ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
// - Returns an error if the deletion fails.
func (s *Server) RemoveService(ctx context.Context, request *api.RemoveServiceRequest) (*api.RemoveServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.DeleteService(tx, request.ServiceID)
	})
	if err != nil {
		if err == store.ErrNotExist {
			return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
		}
		return nil, err
	}
	return &api.RemoveServiceResponse{}, nil
}

func filterServices(candidates []*api.Service, filters ...func(*api.Service) bool) []*api.Service {
	result := []*api.Service{}

	for _, c := range candidates {
		match := true
		for _, f := range filters {
			if !f(c) {
				match = false
				break
			}
		}
		if match {
			result = append(result, c)
		}
	}

	return result
}

// ListServices returns a list of all services.
func (s *Server) ListServices(ctx context.Context, request *api.ListServicesRequest) (*api.ListServicesResponse, error) {
	var (
		services []*api.Service
		err      error
	)

	s.store.View(func(tx store.ReadTx) {
		switch {
		case request.Filters != nil && len(request.Filters.Names) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByName, request.Filters.Names))
		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
		default:
			services, err = store.FindServices(tx, store.All)
		}
	})
	if err != nil {
		return nil, err
	}

	if request.Filters != nil {
		services = filterServices(services,
			func(e *api.Service) bool {
				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
			},
			func(e *api.Service) bool {
				return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
			},
			func(e *api.Service) bool {
				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
			},
			func(e *api.Service) bool {
				return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
			},
		)
	}

	return &api.ListServicesResponse{
		Services: services,
	}, nil
}
<commit_msg>Improve the error message for port collision<commit_after>package controlapi

import (
	"errors"
	"reflect"
	"strconv"

	"github.com/docker/engine-api/types/reference"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/identity"
	"github.com/docker/swarmkit/manager/scheduler"
	"github.com/docker/swarmkit/manager/state/store"
	"github.com/docker/swarmkit/protobuf/ptypes"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

var (
	errNetworkUpdateNotSupported = errors.New("changing network in service is not supported")
	errModeChangeNotAllowed      = errors.New("service mode change is not allowed")
)

func validateResources(r *api.Resources) error {
	if r == nil {
		return nil
	}

	if r.NanoCPUs != 0 && r.NanoCPUs < 1e6 {
		return grpc.Errorf(codes.InvalidArgument, "invalid cpu value %g: Must be at least %g", float64(r.NanoCPUs)/1e9, 1e6/1e9)
	}

	if r.MemoryBytes != 0 && r.MemoryBytes < 4*1024*1024 {
		return grpc.Errorf(codes.InvalidArgument, "invalid memory value %d: Must be at least 4MiB", r.MemoryBytes)
	}
	return nil
}

func validateResourceRequirements(r *api.ResourceRequirements) error {
	if r == nil {
		return nil
	}
	if err := validateResources(r.Limits); err != nil {
		return err
	}
	if err := validateResources(r.Reservations); err != nil {
		return err
	}
	return nil
}

func validateRestartPolicy(rp *api.RestartPolicy) error {
	if rp == nil {
		return nil
	}

	if rp.Delay != nil {
		delay, err := ptypes.Duration(rp.Delay)
		if err != nil {
			return err
		}
		if delay < 0 {
			return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-delay cannot be negative")
		}
	}

	if rp.Window != nil {
		win, err := ptypes.Duration(rp.Window)
		if err != nil {
			return err
		}
		if win < 0 {
			return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-window cannot be negative")
		}
	}

	return nil
}

func validatePlacement(placement *api.Placement) error {
	if placement == nil {
		return nil
	}
	_, err := scheduler.ParseExprs(placement.Constraints)
	return err
}

func validateUpdate(uc *api.UpdateConfig) error {
	if uc == nil {
		return nil
	}

	delay, err := ptypes.Duration(&uc.Delay)
	if err != nil {
		return err
	}

	if delay < 0 {
		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: update-delay cannot be negative")
	}

	return nil
}

func validateTask(taskSpec api.TaskSpec) error {
	if err := validateResourceRequirements(taskSpec.Resources); err != nil {
		return err
	}

	if err := validateRestartPolicy(taskSpec.Restart); err != nil {
		return err
	}

	if err := validatePlacement(taskSpec.Placement); err != nil {
		return err
	}

	if taskSpec.GetRuntime() == nil {
		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
	}

	_, ok := taskSpec.GetRuntime().(*api.TaskSpec_Container)
	if !ok {
		return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec")
	}

	container := taskSpec.GetContainer()
	if container == nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec")
	}

	if container.Image == "" {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided")
	}

	if _, _, err := reference.Parse(container.Image); err != nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image)
	}
	return nil
}

func validateEndpointSpec(epSpec *api.EndpointSpec) error {
	// Endpoint spec is optional
	if epSpec == nil {
		return nil
	}

	if len(epSpec.Ports) > 0 && epSpec.Mode == api.ResolutionModeDNSRoundRobin {
		return grpc.Errorf(codes.InvalidArgument, "EndpointSpec: ports can't be used with dnsrr mode")
	}

	portSet := make(map[api.PortConfig]struct{})
	for _, port := range epSpec.Ports {
		if _, ok := portSet[*port]; ok {
			return grpc.Errorf(codes.InvalidArgument, "EndpointSpec: duplicate ports provided")
		}

		portSet[*port] = struct{}{}
	}

	return nil
}

func validateServiceSpec(spec *api.ServiceSpec) error {
	if spec == nil {
		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateAnnotations(spec.Annotations); err != nil {
		return err
	}
	if err := validateTask(spec.Task); err != nil {
		return err
	}
	if err := validateUpdate(spec.Update); err != nil {
		return err
	}
	if err := validateEndpointSpec(spec.Endpoint); err != nil {
		return err
	}
	return nil
}

// checkPortConflicts does a best effort to find if the passed in spec has port
// conflicts with existing services.
func (s *Server) checkPortConflicts(spec *api.ServiceSpec) error {
	if spec.Endpoint == nil {
		return nil
	}

	pcToString := func(pc *api.PortConfig) string {
		port := strconv.FormatUint(uint64(pc.PublishedPort), 10)
		return port + "/" + pc.Protocol.String()
	}

	reqPorts := make(map[string]bool)
	for _, pc := range spec.Endpoint.Ports {
		if pc.PublishedPort > 0 {
			reqPorts[pcToString(pc)] = true
		}
	}
	if len(reqPorts) == 0 {
		return nil
	}

	var (
		services []*api.Service
		err      error
	)

	s.store.View(func(tx store.ReadTx) {
		services, err = store.FindServices(tx, store.All)
	})
	if err != nil {
		return err
	}

	for _, service := range services {
		if service.Spec.Endpoint != nil {
			for _, pc := range service.Spec.Endpoint.Ports {
				if reqPorts[pcToString(pc)] {
					return grpc.Errorf(codes.InvalidArgument, "port '%d' is already in use by service '%s' (%s)", pc.PublishedPort, service.Spec.Annotations.Name, service.ID)
				}
			}
		}
		if service.Endpoint != nil {
			for _, pc := range service.Endpoint.Ports {
				if reqPorts[pcToString(pc)] {
					return grpc.Errorf(codes.InvalidArgument, "port '%d' is already in use by service '%s' (%s)", pc.PublishedPort, service.Spec.Annotations.Name, service.ID)
				}
			}
		}
	}
	return nil
}

// CreateService creates and return a Service based on the provided ServiceSpec.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns `AlreadyExists` if the ServiceID conflicts.
// - Returns an error if the creation fails.
func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRequest) (*api.CreateServiceResponse, error) {
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	if err := s.checkPortConflicts(request.Spec); err != nil {
		return nil, err
	}

	// TODO(aluzzardi): Consider using `Name` as a primary key to handle
	// duplicate creations. See #65
	service := &api.Service{
		ID:   identity.NewID(),
		Spec: *request.Spec,
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.CreateService(tx, service)
	})
	if err != nil {
		return nil, err
	}

	return &api.CreateServiceResponse{
		Service: service,
	}, nil
}

// GetService returns a Service given a ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
func (s *Server) GetService(ctx context.Context, request *api.GetServiceRequest) (*api.GetServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	var service *api.Service
	s.store.View(func(tx store.ReadTx) {
		service = store.GetService(tx, request.ServiceID)
	})
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}

	return &api.GetServiceResponse{
		Service: service,
	}, nil
}

// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
	if request.ServiceID == "" || request.ServiceVersion == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	var service *api.Service
	s.store.View(func(tx store.ReadTx) {
		service = store.GetService(tx, request.ServiceID)
	})
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}

	if request.Spec.Endpoint != nil && !reflect.DeepEqual(request.Spec.Endpoint, service.Spec.Endpoint) {
		if err := s.checkPortConflicts(request.Spec); err != nil {
			return nil, err
		}
	}

	err := s.store.Update(func(tx store.Tx) error {
		service = store.GetService(tx, request.ServiceID)
		if service == nil {
			return nil
		}
		// temporary disable network update
		if request.Spec != nil && !reflect.DeepEqual(request.Spec.Networks, service.Spec.Networks) {
			return errNetworkUpdateNotSupported
		}

		// orchestrator is designed to be stateless, so it should not deal
		// with service mode change (comparing current config with previous config).
		// proper way to change service mode is to delete and re-add.
		if request.Spec != nil && reflect.TypeOf(service.Spec.Mode) != reflect.TypeOf(request.Spec.Mode) {
			return errModeChangeNotAllowed
		}
		service.Meta.Version = *request.ServiceVersion
		service.Spec = *request.Spec.Copy()

		// Reset update status
		service.UpdateStatus = nil

		return store.UpdateService(tx, service)
	})
	if err != nil {
		return nil, err
	}
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}
	return &api.UpdateServiceResponse{
		Service: service,
	}, nil
}

// RemoveService removes a Service referenced by ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
// - Returns an error if the deletion fails.
func (s *Server) RemoveService(ctx context.Context, request *api.RemoveServiceRequest) (*api.RemoveServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.DeleteService(tx, request.ServiceID)
	})
	if err != nil {
		if err == store.ErrNotExist {
			return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
		}
		return nil, err
	}
	return &api.RemoveServiceResponse{}, nil
}

func filterServices(candidates []*api.Service, filters ...func(*api.Service) bool) []*api.Service {
	result := []*api.Service{}

	for _, c := range candidates {
		match := true
		for _, f := range filters {
			if !f(c) {
				match = false
				break
			}
		}
		if match {
			result = append(result, c)
		}
	}

	return result
}

// ListServices returns a list of all services.
func (s *Server) ListServices(ctx context.Context, request *api.ListServicesRequest) (*api.ListServicesResponse, error) {
	var (
		services []*api.Service
		err      error
	)

	s.store.View(func(tx store.ReadTx) {
		switch {
		case request.Filters != nil && len(request.Filters.Names) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByName, request.Filters.Names))
		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
		default:
			services, err = store.FindServices(tx, store.All)
		}
	})
	if err != nil {
		return nil, err
	}

	if request.Filters != nil {
		services = filterServices(services,
			func(e *api.Service) bool {
				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
			},
			func(e *api.Service) bool {
				return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
			},
			func(e *api.Service) bool {
				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
			},
			func(e *api.Service) bool {
				return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
			},
		)
	}

	return &api.ListServicesResponse{
		Services: services,
	}, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go 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 main

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"code.google.com/p/go.talks/pkg/present"
)

func init() {
	present.PlayEnabled = true
}

var tourContent []byte

// initTour loads tour.article and the relevant HTML templates from the given
// tour root, and renders the template to the tourContent global variable.
func initTour(root string) error {
	// Open and parse source file.
	source := filepath.Join(root, "tour.article")
	f, err := os.Open(source)
	if err != nil {
		return err
	}
	defer f.Close()
	doc, err := present.Parse(prepContent(f), source, 0)
	if err != nil {
		return err
	}

	// Set up templates.
	action := filepath.Join(root, "template", "action.tmpl")
	tour := filepath.Join(root, "template", "tour.tmpl")
	t := present.Template().Funcs(template.FuncMap{"nocode": nocode, "socketAddr": socketAddr})
	_, err = t.ParseFiles(action, tour)
	if err != nil {
		return err
	}

	// Render.
	buf := new(bytes.Buffer)
	if err := doc.Render(buf, t); err != nil {
		return err
	}
	tourContent = buf.Bytes()
	return nil
}

// renderTour writes the tour content to the provided Writer.
func renderTour(w io.Writer) error {
	if tourContent == nil {
		panic("renderTour called before successful initTour")
	}
	_, err := w.Write(tourContent)
	return err
}

// nocode returns true if the provided Section contains
// no Code elements with Play enabled.
func nocode(s present.Section) bool {
	for _, e := range s.Elem {
		if c, ok := e.(present.Code); ok && c.Play {
			return false
		}
	}
	return true
}

var commonScripts = []string{
	"jquery.js",
	"codemirror/lib/codemirror.js",
	"codemirror/lib/go.js",
	"lang.js",
}

// serveScripts registers an HTTP handler at /script.js that serves a
// concatenated set of all the scripts specified by path relative to root.
func serveScripts(root string, path ...string) error {
	modTime := time.Now()
	var buf bytes.Buffer
	scripts := append(commonScripts, path...)
	scripts = append(scripts, "tour.js")
	for _, p := range scripts {
		fn := filepath.Join(root, p)
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			return err
		}
		fmt.Fprintf(&buf, "\n\n// **** %s ****\n\n", filepath.Base(fn))
		buf.Write(b)
	}
	b := buf.Bytes()
	http.HandleFunc("/script.js", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-type", "application/javascript")
		http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
	})
	return nil
}
<commit_msg>go-tour: set PlayEnabled flag before parsing<commit_after>// Copyright 2013 The Go 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 main

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"code.google.com/p/go.talks/pkg/present"
)

var tourContent []byte

// initTour loads tour.article and the relevant HTML templates from the given
// tour root, and renders the template to the tourContent global variable.
func initTour(root string) error {
	// Make sure playground is enabled before rendering.
	present.PlayEnabled = true

	// Open and parse source file.
	source := filepath.Join(root, "tour.article")
	f, err := os.Open(source)
	if err != nil {
		return err
	}
	defer f.Close()
	doc, err := present.Parse(prepContent(f), source, 0)
	if err != nil {
		return err
	}

	// Set up templates.
	action := filepath.Join(root, "template", "action.tmpl")
	tour := filepath.Join(root, "template", "tour.tmpl")
	t := present.Template().Funcs(template.FuncMap{"nocode": nocode, "socketAddr": socketAddr})
	_, err = t.ParseFiles(action, tour)
	if err != nil {
		return err
	}

	// Render.
	buf := new(bytes.Buffer)
	if err := doc.Render(buf, t); err != nil {
		return err
	}
	tourContent = buf.Bytes()
	return nil
}

// renderTour writes the tour content to the provided Writer.
func renderTour(w io.Writer) error {
	if tourContent == nil {
		panic("renderTour called before successful initTour")
	}
	_, err := w.Write(tourContent)
	return err
}

// nocode returns true if the provided Section contains
// no Code elements with Play enabled.
func nocode(s present.Section) bool {
	for _, e := range s.Elem {
		if c, ok := e.(present.Code); ok && c.Play {
			return false
		}
	}
	return true
}

var commonScripts = []string{
	"jquery.js",
	"codemirror/lib/codemirror.js",
	"codemirror/lib/go.js",
	"lang.js",
}

// serveScripts registers an HTTP handler at /script.js that serves a
// concatenated set of all the scripts specified by path relative to root.
func serveScripts(root string, path ...string) error {
	modTime := time.Now()
	var buf bytes.Buffer
	scripts := append(commonScripts, path...)
	scripts = append(scripts, "tour.js")
	for _, p := range scripts {
		fn := filepath.Join(root, p)
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			return err
		}
		fmt.Fprintf(&buf, "\n\n// **** %s ****\n\n", filepath.Base(fn))
		buf.Write(b)
	}
	b := buf.Bytes()
	http.HandleFunc("/script.js", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-type", "application/javascript")
		http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
	})
	return nil
}
<|endoftext|>


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

// The list package implements a doubly linked list.
package list

// Element is an element in the linked list.
type Element struct {
	// Next and previous pointers in the doubly-linked list of elements.
	// The front of the list has prev = nil, and the back has next = nil.
	next, prev *Element

	// Thie list to which this element belongs.
	list *List

	// The contents of this list element.
	Value interface{}
}

// Next returns the next list element or nil.
func (e *Element) Next() *Element { return e.next }

// Prev returns the previous list element or nil.
func (e *Element) Prev() *Element { return e.prev }

// List represents a doubly linked list.
// The zero value for List is an empty list ready to use.
type List struct {
	front, back *Element
	len         int
}

// Init initializes or clears a List.
func (l *List) Init() *List {
	l.front = nil
	l.back = nil
	l.len = 0
	return l
}

// New returns an initialized list.
func New() *List { return new(List).Init() }

// Front returns the first element in the list.
func (l *List) Front() *Element { return l.front }

// Back returns the last element in the list.
func (l *List) Back() *Element { return l.back }

// Remove removes the element from the list.
func (l *List) Remove(e *Element) {
	l.remove(e)
	e.list = nil // do what remove does not
}

// remove the element from the list, but do not clear the Element's list field.
// This is so that other List methods may use remove when relocating Elements
// without needing to restore the list field.
func (l *List) remove(e *Element) {
	if e.list != l {
		return
	}
	if e.prev == nil {
		l.front = e.next
	} else {
		e.prev.next = e.next
	}
	if e.next == nil {
		l.back = e.prev
	} else {
		e.next.prev = e.prev
	}

	e.prev = nil
	e.next = nil
	l.len--
}

func (l *List) insertBefore(e *Element, mark *Element) {
	if mark.prev == nil {
		// new front of the list
		l.front = e
	} else {
		mark.prev.next = e
	}
	e.prev = mark.prev
	mark.prev = e
	e.next = mark
	l.len++
}

func (l *List) insertAfter(e *Element, mark *Element) {
	if mark.next == nil {
		// new back of the list
		l.back = e
	} else {
		mark.next.prev = e
	}
	e.next = mark.next
	mark.next = e
	e.prev = mark
	l.len++
}

func (l *List) insertFront(e *Element) {
	if l.front == nil {
		// empty list
		l.front, l.back = e, e
		e.prev, e.next = nil, nil
		l.len = 1
		return
	}
	l.insertBefore(e, l.front)
}

func (l *List) insertBack(e *Element) {
	if l.back == nil {
		// empty list
		l.front, l.back = e, e
		e.prev, e.next = nil, nil
		l.len = 1
		return
	}
	l.insertAfter(e, l.back)
}

// PushFront inserts the value at the front of the list and returns a new Element containing the value.
func (l *List) PushFront(value interface{}) *Element {
	if l == nil {
		l.Init()
	}
	e := &Element{nil, nil, l, value}
	l.insertFront(e)
	return e
}

// PushBack inserts the value at the back of the list and returns a new Element containing the value.
func (l *List) PushBack(value interface{}) *Element {
	if l == nil {
		l.Init()
	}
	e := &Element{nil, nil, l, value}
	l.insertBack(e)
	return e
}

// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
	if mark.list != l {
		return nil
	}
	e := &Element{nil, nil, l, value}
	l.insertBefore(e, mark)
	return e
}

// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
	if mark.list != l {
		return nil
	}
	e := &Element{nil, nil, l, value}
	l.insertAfter(e, mark)
	return e
}

// MoveToFront moves the element to the front of the list.
func (l *List) MoveToFront(e *Element) {
	if e.list != l || l.front == e {
		return
	}
	l.remove(e)
	l.insertFront(e)
}

// MoveToBack moves the element to the back of the list.
func (l *List) MoveToBack(e *Element) {
	if e.list != l || l.back == e {
		return
	}
	l.remove(e)
	l.insertBack(e)
}

// Len returns the number of elements in the list.
func (l *List) Len() int { return l.len }

// PushBackList inserts each element of ol at the back of the list.
func (l *List) PushBackList(ol *List) {
	last := ol.Back()
	for e := ol.Front(); e != nil; e = e.Next() {
		l.PushBack(e.Value)
		if e == last {
			break
		}
	}
}

// PushFrontList inserts each element of ol at the front of the list. The ordering of the passed list is preserved.
func (l *List) PushFrontList(ol *List) {
	first := ol.Front()
	for e := ol.Back(); e != nil; e = e.Prev() {
		l.PushFront(e.Value)
		if e == first {
			break
		}
	}
}
<commit_msg>container/list: elide redundant tests and fix comment typo<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The list package implements a doubly linked list.
package list

// Element is an element in the linked list.
type Element struct {
	// Next and previous pointers in the doubly-linked list of elements.
	// The front of the list has prev = nil, and the back has next = nil.
	next, prev *Element

	// The list to which this element belongs.
	list *List

	// The contents of this list element.
	Value interface{}
}

// Next returns the next list element or nil.
func (e *Element) Next() *Element { return e.next }

// Prev returns the previous list element or nil.
func (e *Element) Prev() *Element { return e.prev }

// List represents a doubly linked list.
// The zero value for List is an empty list ready to use.
type List struct {
	front, back *Element
	len         int
}

// Init initializes or clears a List.
func (l *List) Init() *List {
	l.front = nil
	l.back = nil
	l.len = 0
	return l
}

// New returns an initialized list.
func New() *List { return new(List) }

// Front returns the first element in the list.
func (l *List) Front() *Element { return l.front }

// Back returns the last element in the list.
func (l *List) Back() *Element { return l.back }

// Remove removes the element from the list.
func (l *List) Remove(e *Element) {
	l.remove(e)
	e.list = nil // do what remove does not
}

// remove the element from the list, but do not clear the Element's list field.
// This is so that other List methods may use remove when relocating Elements
// without needing to restore the list field.
func (l *List) remove(e *Element) {
	if e.list != l {
		return
	}
	if e.prev == nil {
		l.front = e.next
	} else {
		e.prev.next = e.next
	}
	if e.next == nil {
		l.back = e.prev
	} else {
		e.next.prev = e.prev
	}

	e.prev = nil
	e.next = nil
	l.len--
}

func (l *List) insertBefore(e *Element, mark *Element) {
	if mark.prev == nil {
		// new front of the list
		l.front = e
	} else {
		mark.prev.next = e
	}
	e.prev = mark.prev
	mark.prev = e
	e.next = mark
	l.len++
}

func (l *List) insertAfter(e *Element, mark *Element) {
	if mark.next == nil {
		// new back of the list
		l.back = e
	} else {
		mark.next.prev = e
	}
	e.next = mark.next
	mark.next = e
	e.prev = mark
	l.len++
}

func (l *List) insertFront(e *Element) {
	if l.front == nil {
		// empty list
		l.front, l.back = e, e
		e.prev, e.next = nil, nil
		l.len = 1
		return
	}
	l.insertBefore(e, l.front)
}

func (l *List) insertBack(e *Element) {
	if l.back == nil {
		// empty list
		l.front, l.back = e, e
		e.prev, e.next = nil, nil
		l.len = 1
		return
	}
	l.insertAfter(e, l.back)
}

// PushFront inserts the value at the front of the list and returns a new Element containing the value.
func (l *List) PushFront(value interface{}) *Element {
	e := &Element{nil, nil, l, value}
	l.insertFront(e)
	return e
}

// PushBack inserts the value at the back of the list and returns a new Element containing the value.
func (l *List) PushBack(value interface{}) *Element {
	e := &Element{nil, nil, l, value}
	l.insertBack(e)
	return e
}

// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
	if mark.list != l {
		return nil
	}
	e := &Element{nil, nil, l, value}
	l.insertBefore(e, mark)
	return e
}

// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
	if mark.list != l {
		return nil
	}
	e := &Element{nil, nil, l, value}
	l.insertAfter(e, mark)
	return e
}

// MoveToFront moves the element to the front of the list.
func (l *List) MoveToFront(e *Element) {
	if e.list != l || l.front == e {
		return
	}
	l.remove(e)
	l.insertFront(e)
}

// MoveToBack moves the element to the back of the list.
func (l *List) MoveToBack(e *Element) {
	if e.list != l || l.back == e {
		return
	}
	l.remove(e)
	l.insertBack(e)
}

// Len returns the number of elements in the list.
func (l *List) Len() int { return l.len }

// PushBackList inserts each element of ol at the back of the list.
func (l *List) PushBackList(ol *List) {
	last := ol.Back()
	for e := ol.Front(); e != nil; e = e.Next() {
		l.PushBack(e.Value)
		if e == last {
			break
		}
	}
}

// PushFrontList inserts each element of ol at the front of the list. The ordering of the passed list is preserved.
func (l *List) PushFrontList(ol *List) {
	first := ol.Front()
	for e := ol.Back(); e != nil; e = e.Prev() {
		l.PushFront(e.Value)
		if e == first {
			break
		}
	}
}
<|endoftext|>