<commit_before>package mongo

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/ungerik/go-start/config"
	"github.com/ungerik/go-start/debug"
	"github.com/ungerik/go-start/errs"
	"github.com/ungerik/go-start/mgo"
	"github.com/ungerik/go-start/mgo/bson"
	"github.com/ungerik/go-start/model"
	"github.com/ungerik/go-start/reflection"
)

///////////////////////////////////////////////////////////////////////////////
// NewCollection

func NewCollection(name string, documentPrototype interface{}) *Collection {
	if _, ok := Collections[name]; ok {
		panic(fmt.Sprintf("Collection %s already created", name))
	}
	t := reflect.TypeOf(documentPrototype)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	collection := &Collection{Name: name, DocumentType: t}
	collection.Init()
	return collection
}

///////////////////////////////////////////////////////////////////////////////
// Collection

/*
Collection represents a MongoDB collection and implements mongo.Query for all
documents in the collection.

Example for creating, modifying and saving a document:

	user := models.Users.NewDocument().(*models.User)

	user.Name.First.Set("Erik")
	user.Name.Last.Set("Unger")

	err := user.Save()

*/
type Collection struct {
	queryBase
	Name         string
	DocumentType reflect.Type
	collection   *mgo.Collection
	// foreignRefs  []ForeignRef
}

func (self *Collection) Init() {
	self.thisQuery = self
	Collections[self.Name] = self
	if Database != nil {
		self.collection = Database.C(self.Name)
	}
	// self.foreignRefs = []ForeignRef{}
}

func (self *Collection) checkDBConnection() {
	if self == nil {
		panic("mongo.Collection is nil")
	}
	if self.collection == nil {
		panic("mongo.Collection.collection is nil")
	}
	if self.collection.Database == nil {
		panic("mongo.Collection.collection.Database is nil")
	}
	if self.collection.Database.Session == nil {
		panic("mongo.Collection.collection.Database.Session is nil")
	}
}

func (self *Collection) String() string {
	return fmt.Sprintf("mongo.Collection '%s' of type %s", self.Name, self.DocumentType)
}

func (self *Collection) Selector() string {
	return ""
}

func (self *Collection) bsonSelector() bson.M {
	return bson.M{}
}

func (self *Collection) mongoQuery() (q *mgo.Query, err error) {
	self.checkDBConnection()
	return self.collection.Find(nil), nil
}

func (self *Collection) subDocumentType(docType reflect.Type, fieldName string, subDocSelectors []string) (reflect.Type, error) {
	if fieldName == "" {
		return docType, errs.Format("Collection '%s', selector '%s': Empty field name", self.Name, strings.Join(subDocSelectors, "."))
	}

	switch docType.Kind() {
	case reflect.Struct:
		bsonName := strings.ToLower(fieldName)
		field := reflection.FindFlattenedStructField(docType, MatchBsonField(bsonName))
		if field != nil {
			return field.Type, nil
		}
		return nil, errs.Format("Collection '%s', selector '%s': Struct has no field '%s'", self.Name, strings.Join(subDocSelectors, "."), fieldName)

	case reflect.Array, reflect.Slice:
		_, numberErr := strconv.Atoi(fieldName)
		if numberErr == nil || fieldName == "$" {
			return docType, nil
		}
		return docType.Elem(), nil

	case reflect.Ptr, reflect.Interface:
		return self.subDocumentType(docType.Elem(), fieldName, subDocSelectors)
	}

	return nil, errs.Format("Collection '%s', selector '%s': Can't select sub-document '%s' of type '%s'", self.Name, strings.Join(subDocSelectors, "."), fieldName, docType.String())
}

func (self *Collection) ValidateSelector(subDocSelectors ...string) (err error) {
	return nil // todo remove

	if len(subDocSelectors) == 0 {
		return nil
	}
	docType := self.DocumentType
	for _, selector := range subDocSelectors {
		fields := strings.Split(selector, ".")
		if selector == "" || len(fields) == 0 {
			return errs.Format("Invalid empty selector in '%s'", strings.Join(subDocSelectors, "."))
		}
		for _, field := range fields {
			docType, err = self.subDocumentType(docType, field, subDocSelectors)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// return error?
func (self *Collection) NewDocument(subDocSelectors ...string) interface{} {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	docType := self.DocumentType
	for _, selector := range subDocSelectors {
		for _, field := range strings.Split(selector, ".") {
			var err error
			docType, err = self.subDocumentType(docType, field, subDocSelectors)
			errs.PanicOnError(err)
		}
	}
	doc := reflect.New(docType).Interface()
	self.InitDocument(doc)
	return doc
}

func (self *Collection) InitDocument(doc interface{}, subDocSelectors ...string) {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	switch s := doc.(type) {
	case Document:
		if len(subDocSelectors) > 0 {
			panic("Can't initialize mongo.Document with subDocSelectors")
		}
		s.Init(self, doc)

	case SubDocument:
		if len(subDocSelectors) == 0 {
			panic("Need subDocSelectors to initialize mongo.SubDocument")
		}
		selector := strings.Join(subDocSelectors, ".")
		s.Init(self, selector, doc)
	}
}

func (self *Collection) Ref(id bson.ObjectId) Ref {
	return Ref{id, self.Name}
}

// betterError returns a better error description
func (self *Collection) betterError(err error, context string) error {
	if err == mgo.NotFound {
		return fmt.Errorf("MongoDB document with id %s not found in collection %s", context, self.Collection().Name)
	}
	return err
}

func (self *Collection) logIdNotFoundError(id bson.ObjectId) {
	config.Logger.Printf("MongoDB document with id %s not found in collection %s", id.Hex(), self.Collection().Name)
	debug.LogCallStack()
}

func (self *Collection) documentWithID(id bson.ObjectId, subDocSelectors ...string) (document interface{}, err error) {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	if id == "" {
		return nil, errs.Format("mongo.Collection %s: Can't get document with empty id", self.Name)
	}
	if err = self.ValidateSelector(subDocSelectors...); err != nil {
		return nil, err
	}

	self.checkDBConnection()
	document = self.NewDocument(subDocSelectors...)
	q := self.collection.Find(bson.M{"_id": id})
	if len(subDocSelectors) == 0 {
		err = q.One(document)
	} else {
		err = q.Select(strings.Join(subDocSelectors, ".")).One(document)
	}
	if err != nil {
		return nil, err
	}
	// document has to be initialized again,
	// because mgo zeros the struct while unmarshalling.
	// Newly created slice elements need to be initialized too
	self.InitDocument(document)
	return document, nil
}

func (self *Collection) DocumentWithID(id bson.ObjectId, subDocSelectors ...string) (document interface{}, err error) {
	document, err = self.documentWithID(id, subDocSelectors...)
	if err == mgo.NotFound {
		self.logIdNotFoundError(id)
	}
	return document, err
}

func (self *Collection) TryDocumentWithID(id bson.ObjectId, subDocSelectors ...string) (document interface{}, found bool, err error) {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	if id == "" {
		return nil, false, nil
	}
	document, err = self.documentWithID(id, subDocSelectors...)
	if err == mgo.NotFound {
		return nil, false, nil
	}
	return document, err == nil, err
}

func (self *Collection) DocumentWithIDIterator(id bson.ObjectId, subDocSelectors ...string) model.Iterator {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	return model.NewObjectOrErrorOnlyIterator(self.DocumentWithID(id, subDocSelectors...))
}

func (self *Collection) TryDocumentWithIDIterator(id bson.ObjectId, subDocSelectors ...string) model.Iterator {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	document, ok, err := self.TryDocumentWithID(id, subDocSelectors...)
	if err != nil {
		return model.NewErrorOnlyIterator(err)
	}
	if !ok {
		return model.NewObjectIterator()
	}
	return model.NewObjectIterator(document)
}

func (self *Collection) FilterReferenced(refs ...Ref) Query {
	return self.FilterRef("_id", refs...)
}

func (self *Collection) Count() (n int, err error) {
	return self.collection.Count()
}

// Inserts document regardless if it's already in the collection
// If document has a DocumentBase, the ID will be updated to the
// newly created one
func (self *Collection) Insert(document interface{}) (id bson.ObjectId, err error) {
	self.checkDBConnection()
	// Need to set a valid ID, even if Upsert() returns another ID
	id = bson.NewObjectId()
	if doc, ok := document.(Document); ok {
		doc.SetObjectId(id)
	}
	newId, err := self.collection.Upsert(bson.M{"_id": id}, document)
	if err != nil {
		if err == mgo.NotFound {
			self.logIdNotFoundError(id)
		}
		return id, err
	}
	id = newId.(bson.ObjectId)
	if doc, ok := document.(Document); ok {
		doc.SetObjectId(id)
	}
	return id, nil
}

func (self *Collection) Update(id bson.ObjectId, document interface{}) (err error) {
	self.checkDBConnection()
	err = self.collection.Update(bson.M{"_id": id}, document)
	if err == mgo.NotFound {
		self.logIdNotFoundError(id)
	}
	return err
}

func (self *Collection) Remove(ids ...bson.ObjectId) (err error) {
	self.checkDBConnection()
	return self.collection.Remove(bson.M{"_id": bson.M{"$in": ids}})
}

func (self *Collection) RemoveAllNotIn(ids ...bson.ObjectId) error {
	self.checkDBConnection()
	return self.collection.Remove(bson.M{"_id": bson.M{"$nin": ids}})
}

// RemoveInvalidRefs removes invalid refs from all documents and saves
// the changes.
func (self *Collection) RemoveInvalidRefs() (invalidRefs []InvalidRefData, err error) {
	config.Logger.Println("RemoveInvalidRefs() @ " + self.String())
	// if !self.DocumentType.Implements(reflect.TypeOf((*Document)(nil)).Elem()) {
	// 	return nil, nil
	// }
	i := self.Iterator()
	for doc := i.Next(); doc != nil; doc = i.Next() {
		document := doc.(Document)
		refsData, err := document.RemoveInvalidRefs()
		if err != nil {
			return nil, err
		}
		if len(refsData) > 0 {
			config.Logger.Println("Found invalid refs in document " + document.ObjectId().Hex())
			for _, refData := range refsData {
				config.Logger.Println("Invalid ref from %s to ", refData.MetaData.Selector(), refData.Ref.DebugString())
			}
			// err = document.Save()
			// if err != nil {
			// 	config.Logger.Printf("mongo.Collection.RemoveInvalidRefs(): Error while saving document %#v", document)
			// 	return nil, err
			// }
			invalidRefs = append(invalidRefs, refsData...)
		}
	}
	if i.Err() != nil {
		config.Logger.Printf("mongo.Collection.RemoveInvalidRefs(): Error while iterating collection documents: '%s'", i.Err())
		return nil, i.Err()
	}
	return invalidRefs, nil
}

//func (self *Collection) EnsureIndex(unique bool, keyNodes ...oldmodel.Node) error {
//	keys := make([]string, len(keyNodes))
//	for i, keyNode := range keyNodes {
//		keys[i] = NodePath(keyNode)
//	}
//	index := mgo.Index{
//		Key:        keys,
//		Unique:     unique,
//		Background: true,
//	}
//	return self.collection.EnsureIndex(index)
//}

///////////////////////////////////////////////////////////////////////////////
// ForeignRef

type ForeignRef struct {
	Collection *Collection
	Selector   string
}
<commit_msg>better RemoveInvalidRef() logging<commit_after>package mongo

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/ungerik/go-start/config"
	"github.com/ungerik/go-start/debug"
	"github.com/ungerik/go-start/errs"
	"github.com/ungerik/go-start/mgo"
	"github.com/ungerik/go-start/mgo/bson"
	"github.com/ungerik/go-start/model"
	"github.com/ungerik/go-start/reflection"
)

///////////////////////////////////////////////////////////////////////////////
// NewCollection

func NewCollection(name string, documentPrototype interface{}) *Collection {
	if _, ok := Collections[name]; ok {
		panic(fmt.Sprintf("Collection %s already created", name))
	}
	t := reflect.TypeOf(documentPrototype)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	collection := &Collection{Name: name, DocumentType: t}
	collection.Init()
	return collection
}

///////////////////////////////////////////////////////////////////////////////
// Collection

/*
Collection represents a MongoDB collection and implements mongo.Query for all
documents in the collection.

Example for creating, modifying and saving a document:

	user := models.Users.NewDocument().(*models.User)

	user.Name.First.Set("Erik")
	user.Name.Last.Set("Unger")

	err := user.Save()

*/
type Collection struct {
	queryBase
	Name         string
	DocumentType reflect.Type
	collection   *mgo.Collection
	// foreignRefs  []ForeignRef
}

func (self *Collection) Init() {
	self.thisQuery = self
	Collections[self.Name] = self
	if Database != nil {
		self.collection = Database.C(self.Name)
	}
	// self.foreignRefs = []ForeignRef{}
}

func (self *Collection) checkDBConnection() {
	if self == nil {
		panic("mongo.Collection is nil")
	}
	if self.collection == nil {
		panic("mongo.Collection.collection is nil")
	}
	if self.collection.Database == nil {
		panic("mongo.Collection.collection.Database is nil")
	}
	if self.collection.Database.Session == nil {
		panic("mongo.Collection.collection.Database.Session is nil")
	}
}

func (self *Collection) String() string {
	return fmt.Sprintf("mongo.Collection '%s' of type %s", self.Name, self.DocumentType)
}

func (self *Collection) Selector() string {
	return ""
}

func (self *Collection) bsonSelector() bson.M {
	return bson.M{}
}

func (self *Collection) mongoQuery() (q *mgo.Query, err error) {
	self.checkDBConnection()
	return self.collection.Find(nil), nil
}

func (self *Collection) subDocumentType(docType reflect.Type, fieldName string, subDocSelectors []string) (reflect.Type, error) {
	if fieldName == "" {
		return docType, errs.Format("Collection '%s', selector '%s': Empty field name", self.Name, strings.Join(subDocSelectors, "."))
	}

	switch docType.Kind() {
	case reflect.Struct:
		bsonName := strings.ToLower(fieldName)
		field := reflection.FindFlattenedStructField(docType, MatchBsonField(bsonName))
		if field != nil {
			return field.Type, nil
		}
		return nil, errs.Format("Collection '%s', selector '%s': Struct has no field '%s'", self.Name, strings.Join(subDocSelectors, "."), fieldName)

	case reflect.Array, reflect.Slice:
		_, numberErr := strconv.Atoi(fieldName)
		if numberErr == nil || fieldName == "$" {
			return docType, nil
		}
		return docType.Elem(), nil

	case reflect.Ptr, reflect.Interface:
		return self.subDocumentType(docType.Elem(), fieldName, subDocSelectors)
	}

	return nil, errs.Format("Collection '%s', selector '%s': Can't select sub-document '%s' of type '%s'", self.Name, strings.Join(subDocSelectors, "."), fieldName, docType.String())
}

func (self *Collection) ValidateSelector(subDocSelectors ...string) (err error) {
	return nil // todo remove

	if len(subDocSelectors) == 0 {
		return nil
	}
	docType := self.DocumentType
	for _, selector := range subDocSelectors {
		fields := strings.Split(selector, ".")
		if selector == "" || len(fields) == 0 {
			return errs.Format("Invalid empty selector in '%s'", strings.Join(subDocSelectors, "."))
		}
		for _, field := range fields {
			docType, err = self.subDocumentType(docType, field, subDocSelectors)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// return error?
func (self *Collection) NewDocument(subDocSelectors ...string) interface{} {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	docType := self.DocumentType
	for _, selector := range subDocSelectors {
		for _, field := range strings.Split(selector, ".") {
			var err error
			docType, err = self.subDocumentType(docType, field, subDocSelectors)
			errs.PanicOnError(err)
		}
	}
	doc := reflect.New(docType).Interface()
	self.InitDocument(doc)
	return doc
}

func (self *Collection) InitDocument(doc interface{}, subDocSelectors ...string) {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	switch s := doc.(type) {
	case Document:
		if len(subDocSelectors) > 0 {
			panic("Can't initialize mongo.Document with subDocSelectors")
		}
		s.Init(self, doc)

	case SubDocument:
		if len(subDocSelectors) == 0 {
			panic("Need subDocSelectors to initialize mongo.SubDocument")
		}
		selector := strings.Join(subDocSelectors, ".")
		s.Init(self, selector, doc)
	}
}

func (self *Collection) Ref(id bson.ObjectId) Ref {
	return Ref{id, self.Name}
}

// betterError returns a better error description
func (self *Collection) betterError(err error, context string) error {
	if err == mgo.NotFound {
		return fmt.Errorf("MongoDB document with id %s not found in collection %s", context, self.Collection().Name)
	}
	return err
}

func (self *Collection) logIdNotFoundError(id bson.ObjectId) {
	config.Logger.Printf("MongoDB document with id %s not found in collection %s", id.Hex(), self.Collection().Name)
	debug.LogCallStack()
}

func (self *Collection) documentWithID(id bson.ObjectId, subDocSelectors ...string) (document interface{}, err error) {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	if id == "" {
		return nil, errs.Format("mongo.Collection %s: Can't get document with empty id", self.Name)
	}
	if err = self.ValidateSelector(subDocSelectors...); err != nil {
		return nil, err
	}

	self.checkDBConnection()
	document = self.NewDocument(subDocSelectors...)
	q := self.collection.Find(bson.M{"_id": id})
	if len(subDocSelectors) == 0 {
		err = q.One(document)
	} else {
		err = q.Select(strings.Join(subDocSelectors, ".")).One(document)
	}
	if err != nil {
		return nil, err
	}
	// document has to be initialized again,
	// because mgo zeros the struct while unmarshalling.
	// Newly created slice elements need to be initialized too
	self.InitDocument(document)
	return document, nil
}

func (self *Collection) DocumentWithID(id bson.ObjectId, subDocSelectors ...string) (document interface{}, err error) {
	document, err = self.documentWithID(id, subDocSelectors...)
	if err == mgo.NotFound {
		self.logIdNotFoundError(id)
	}
	return document, err
}

func (self *Collection) TryDocumentWithID(id bson.ObjectId, subDocSelectors ...string) (document interface{}, found bool, err error) {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	if id == "" {
		return nil, false, nil
	}
	document, err = self.documentWithID(id, subDocSelectors...)
	if err == mgo.NotFound {
		return nil, false, nil
	}
	return document, err == nil, err
}

func (self *Collection) DocumentWithIDIterator(id bson.ObjectId, subDocSelectors ...string) model.Iterator {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	return model.NewObjectOrErrorOnlyIterator(self.DocumentWithID(id, subDocSelectors...))
}

func (self *Collection) TryDocumentWithIDIterator(id bson.ObjectId, subDocSelectors ...string) model.Iterator {
	if len(subDocSelectors) > 0 {
		panic("Sub document selectors are not implemented")
	}
	document, ok, err := self.TryDocumentWithID(id, subDocSelectors...)
	if err != nil {
		return model.NewErrorOnlyIterator(err)
	}
	if !ok {
		return model.NewObjectIterator()
	}
	return model.NewObjectIterator(document)
}

func (self *Collection) FilterReferenced(refs ...Ref) Query {
	return self.FilterRef("_id", refs...)
}

func (self *Collection) Count() (n int, err error) {
	return self.collection.Count()
}

// Inserts document regardless if it's already in the collection
// If document has a DocumentBase, the ID will be updated to the
// newly created one
func (self *Collection) Insert(document interface{}) (id bson.ObjectId, err error) {
	self.checkDBConnection()
	// Need to set a valid ID, even if Upsert() returns another ID
	id = bson.NewObjectId()
	if doc, ok := document.(Document); ok {
		doc.SetObjectId(id)
	}
	newId, err := self.collection.Upsert(bson.M{"_id": id}, document)
	if err != nil {
		if err == mgo.NotFound {
			self.logIdNotFoundError(id)
		}
		return id, err
	}
	id = newId.(bson.ObjectId)
	if doc, ok := document.(Document); ok {
		doc.SetObjectId(id)
	}
	return id, nil
}

func (self *Collection) Update(id bson.ObjectId, document interface{}) (err error) {
	self.checkDBConnection()
	err = self.collection.Update(bson.M{"_id": id}, document)
	if err == mgo.NotFound {
		self.logIdNotFoundError(id)
	}
	return err
}

func (self *Collection) Remove(ids ...bson.ObjectId) (err error) {
	self.checkDBConnection()
	return self.collection.Remove(bson.M{"_id": bson.M{"$in": ids}})
}

func (self *Collection) RemoveAllNotIn(ids ...bson.ObjectId) error {
	self.checkDBConnection()
	return self.collection.Remove(bson.M{"_id": bson.M{"$nin": ids}})
}

// RemoveInvalidRefs removes invalid refs from all documents and saves
// the changes.
func (self *Collection) RemoveInvalidRefs() (invalidRefs []InvalidRefData, err error) {
	config.Logger.Println("RemoveInvalidRefs() @ " + self.String())
	// if !self.DocumentType.Implements(reflect.TypeOf((*Document)(nil)).Elem()) {
	// 	return nil, nil
	// }
	i := self.Iterator()
	for doc := i.Next(); doc != nil; doc = i.Next() {
		document := doc.(Document)
		refsData, err := document.RemoveInvalidRefs()
		if err != nil {
			return nil, err
		}
		if len(refsData) > 0 {
			config.Logger.Println("Found invalid refs in document " + document.ObjectId().Hex())
			for _, refData := range refsData {
				config.Logger.Printf("Invalid ref from %s to ", refData.MetaData.Selector(), refData.Ref.DebugString())
			}
			// err = document.Save()
			// if err != nil {
			// 	config.Logger.Printf("mongo.Collection.RemoveInvalidRefs(): Error while saving document %#v", document)
			// 	return nil, err
			// }
			invalidRefs = append(invalidRefs, refsData...)
		}
	}
	if i.Err() != nil {
		config.Logger.Printf("mongo.Collection.RemoveInvalidRefs(): Error while iterating collection documents: '%s'", i.Err())
		return nil, i.Err()
	}
	return invalidRefs, nil
}

//func (self *Collection) EnsureIndex(unique bool, keyNodes ...oldmodel.Node) error {
//	keys := make([]string, len(keyNodes))
//	for i, keyNode := range keyNodes {
//		keys[i] = NodePath(keyNode)
//	}
//	index := mgo.Index{
//		Key:        keys,
//		Unique:     unique,
//		Background: true,
//	}
//	return self.collection.EnsureIndex(index)
//}

///////////////////////////////////////////////////////////////////////////////
// ForeignRef

type ForeignRef struct {
	Collection *Collection
	Selector   string
}
<|endoftext|>


<commit_before>package mapgen

import (
	"buildblast/lib/coords"
	"buildblast/lib/mapgen/noise"
)

type SimplexHills struct {
	simplexNoise *noise.SimplexNoise
	simplexHoles *noise.SimplexNoise
}

func NewSimplexHills(seed int64) *SimplexHills {
	sh := new(SimplexHills)
	sh.simplexNoise = noise.NewSimplexNoise(1024, 0.4, seed)
	sh.simplexHoles = noise.NewSimplexNoise(1024, 0.8, seed)
	return sh
}

func (sh *SimplexHills) heightAt(x, z float64) float64 {
	height := sh.simplexNoise.Noise2(x, z)
	return height*50 + float64(coords.ChunkHeight)/2
}

func (sh *SimplexHills) holeAt(x, y, z float64) bool {
	val := sh.simplexNoise.Noise3(x, y, z)
	return val < -0.2
}

func (sh *SimplexHills) Block(bc coords.Block) Block {
	if bc.X == 0 && bc.Y == 16 && bc.Z == 0 {
		return BLOCK_SPAWN
	}
	if sh.holeAt(float64(bc.X), float64(bc.Y), float64(bc.Z)) {
		return BLOCK_AIR
	}

	height := int(sh.heightAt(float64(bc.X), float64(bc.Z)))
	if bc.Y == height {
		return BLOCK_GRASS
	}
	if bc.Y < height-3 {
		return BLOCK_STONE
	}
	if height > bc.Y {
		return BLOCK_DIRT
	}
	return BLOCK_AIR
}

func (sh *SimplexHills) Chunk(cc coords.Chunk) *Chunk {
	return generateChunk(sh, cc)
}
<commit_msg>Optimize the SimplexHills chunk generation<commit_after>package mapgen

import (
	"log"
	"buildblast/lib/coords"
	"buildblast/lib/mapgen/noise"
)

type SimplexHills struct {
	simplexNoise *noise.SimplexNoise
	simplexHoles *noise.SimplexNoise
}

func NewSimplexHills(seed int64) *SimplexHills {
	sh := new(SimplexHills)
	sh.simplexNoise = noise.NewSimplexNoise(1024, 0.4, seed)
	sh.simplexHoles = noise.NewSimplexNoise(1024, 0.8, seed)
	return sh
}

func (sh *SimplexHills) heightAt(x, z float64) float64 {
	height := sh.simplexNoise.Noise2(x, z)
	return height*50 + float64(coords.ChunkHeight)/2
}

func (sh *SimplexHills) holeAt(x, y, z float64) bool {
	val := sh.simplexNoise.Noise3(x, y, z)
	return val < -0.2
}

func (sh *SimplexHills) Chunk(cc coords.Chunk) *Chunk {
	chunk := &Chunk{}
	// Build the height map
	hMap := make([][]int, coords.ChunkWidth)
	for x := range hMap {
		hMap[x] = make([]int, coords.ChunkDepth)
		for z := range hMap[x] {
			oc := coords.Offset{X: x, Y: 0, Z: z}
			bc := oc.Block(cc)
			hMap[x][z] = int(sh.heightAt(float64(bc.X), float64(bc.Z)))
		}
	}
	for ocX := 0; ocX < coords.ChunkWidth; ocX++ {
		for ocY := 0; ocY < coords.ChunkHeight; ocY++ {
			for ocZ := 0; ocZ < coords.ChunkDepth; ocZ++ {
				oc := coords.Offset{X: ocX, Y: ocY, Z: ocZ}
				bc := oc.Block(cc)
				block := sh.block(bc, hMap[oc.X][oc.Z])
				chunk.SetBlock(oc, block)
			}
		}
	}
	return chunk
}

func (sh *SimplexHills) Block(bc coords.Block) Block {
	log.Println("I shouldn't be called")
	return sh.block(bc, int(sh.heightAt(float64(bc.X), float64(bc.Z))))
}

func (sh *SimplexHills) block(bc coords.Block, height int) Block {
	if bc.X == 0 && bc.Y == 16 && bc.Z == 0 {
		return BLOCK_SPAWN
	}
	if sh.holeAt(float64(bc.X), float64(bc.Y), float64(bc.Z)) {
		return BLOCK_AIR
	}

	if bc.Y == height {
		return BLOCK_GRASS
	}
	if bc.Y < height-3 {
		return BLOCK_STONE
	}
	if height > bc.Y {
		return BLOCK_DIRT
	}
	return BLOCK_AIR
}
<|endoftext|>


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

// Package logging implements log library for other applications. It provides
// functions Debug, Info, Warning, Error, Critical, and formatting version
// Logf.
//
// Example:
//
//	logger := logging.SimpleLogger("main")
//	logger.SetLevel(logging.WARNING)
//	logger.Error("test for error")
//	logger.Warning("test for warning", "second parameter")
//	logger.Debug("test for debug")
//
package logging

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

// Pre-defined formats
const (
	DefaultFileName       = "logging.log"                   // default logging filename
	DefaultConfigFileName = "logging.conf"                  // default configuration filename
	DefaultTimeFormat     = "2006-01-02 15:04:05.999999999" // defaulttime format
	bufSize               = 1000                            // buffer size for writer
	queueSize             = 1e6                             // chan queue size in async logging
)

// Logger is the logging struct.
type Logger struct {

	// Be careful of the alignment issue of the variable seqid because it
	// uses the sync/atomic.AddUint64() operation. If the alignment is
	// wrong, it will cause a panic. To solve the alignment issue in an
	// easy way, we put seqid to the beginning of the structure.
	// seqid is only visiable internally.
	seqid uint64 // last used sequence number in record

	// These variables can be configured by users.
	name       string    // logger name
	level      Level     // record level higher than this will be printed
	format     string    // format of the record
	fargs      []string  // arguments to be used in the format
	out        io.Writer // writer
	startTime  time.Time // start time of the logger
	sync       bool      // use sync or async way to record logs
	timeFormat string    // format for time

	// Internal used variables, which don't have get and set functions.
	lock    sync.Mutex   // writer lock
	queue   chan string  // queue used in async logging
	request chan request // queue used in async logging
	flush   chan bool    // flush signal for the watcher to write
	quit    chan bool    // quit signal for the watcher to quit
	fd      *os.File     // file handler, used to close the file on destroy
	runtime bool         // with runtime operation or not
}

// request struct stores the logger request
type request struct {
	level  Level
	format string
	v      []interface{}
}

// SimpleLogger creates a new logger with simple configuration.
func SimpleLogger(name string) (*Logger, error) {
	return createLogger(name, WARNING, BasicFormat, os.Stdout, false)
}

// BasicLogger creates a new logger with basic configuration.
func BasicLogger(name string) (*Logger, error) {
	return FileLogger(name, WARNING, BasicFormat, DefaultFileName, false)
}

// RichLogger creates a new logger with simple configuration.
func RichLogger(name string) (*Logger, error) {
	return FileLogger(name, NOTSET, RichFormat, DefaultFileName, false)
}

// FileLogger creates a new logger with file output.
func FileLogger(name string, level Level, format string, file string, sync bool) (*Logger, error) {
	out, err := os.Create(file)
	if err != nil {
		return new(Logger), err
	}
	logger, err := createLogger(name, level, format, out, sync)
	if err == nil {
		logger.fd = out
	}
	return logger, err
}

func WriterLogger(name string, level Level, format string, out io.Writer, sync bool) (*Logger, error) {
	return createLogger(name, level, format, out, sync)
}

// createLogger create a new logger
func createLogger(name string, level Level, format string, out io.Writer, sync bool) (*Logger, error) {
	logger := new(Logger)

	err := logger.parseFormat(format)
	if err != nil {
		return logger, err
	}

	// asign values to logger
	logger.name = name
	logger.level = level
	logger.out = out
	logger.seqid = 0
	logger.sync = sync
	logger.queue = make(chan string, queueSize)
	logger.request = make(chan request, queueSize)
	logger.flush = make(chan bool)
	logger.quit = make(chan bool)
	logger.startTime = time.Now()
	logger.fd = nil
	logger.timeFormat = DefaultTimeFormat

	// start watcher to write logs if it is async or no runtime field
	if logger.sync == false || logger.runtime == false {
		go logger.watcher()
	}

	return logger, nil
}

// Destroy sends quit signal to watcher and releases all the resources.
func (logger *Logger) Destroy() {
	logger.quitWatcher()
	// clean up
	if logger.fd != nil {
		logger.fd.Close()
	}
}

func (logger *Logger) quitWatcher() {
	if logger.sync == false || logger.runtime == false {
		// quit watcher
		logger.quit <- true
		// wait for watcher quit
		<-logger.quit
	}
}

// Flush the writer
func (logger *Logger) Flush() {
	if logger.sync == false || logger.runtime == false {
		logger.flush <- true
	}
}

// Get and set the configuration of the logger

func (logger *Logger) Name() string {
	return logger.name
}

func (logger *Logger) SetName(name string) {
	logger.name = name
}

func (logger *Logger) TimeFormat() string {
	return logger.timeFormat
}

func (logger *Logger) SetTimeFormat(format string) {
	logger.timeFormat = format
}

func (logger *Logger) Level() Level {
	return Level(atomic.LoadInt32((*int32)(&logger.level)))
}

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreInt32((*int32)(&logger.level), int32(level))
}

func (logger *Logger) Format() string {
	return logger.format
}

func (logger *Logger) Fargs() []string {
	return logger.fargs
}

func (logger *Logger) SetFormat(format string) error {
	return logger.parseFormat(format)
}

func (logger *Logger) Writer() io.Writer {
	return logger.out
}

func (logger *Logger) AddWriter(out io.Writer) {
	logger.out = io.MultiWriter(logger.out, out)
}

func (logger *Logger) AddWriters(out ...io.Writer) {
	logger.out = io.MultiWriter(append(out, logger.out)...)
}

func (logger *Logger) SetWriter(out io.Writer) {
	logger.out = out
}

func (logger *Logger) SetWriters(out ...io.Writer) {
	logger.out = io.MultiWriter(out...)
}

func (logger *Logger) Sync() bool {
	return logger.sync
}

func (logger *Logger) SetSync(sync bool) {
	if sync == logger.sync {
		return
	}
	logger.quitWatcher()
	logger.sync = sync
	if logger.sync == false || logger.runtime == false {
		go logger.watcher()
	}
}
<commit_msg>use different size for request and queue<commit_after>// Copyright 2013, Cong Ding. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: Cong Ding <dinggnu@gmail.com>

// Package logging implements log library for other applications. It provides
// functions Debug, Info, Warning, Error, Critical, and formatting version
// Logf.
//
// Example:
//
//	logger := logging.SimpleLogger("main")
//	logger.SetLevel(logging.WARNING)
//	logger.Error("test for error")
//	logger.Warning("test for warning", "second parameter")
//	logger.Debug("test for debug")
//
package logging

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

// Pre-defined formats
const (
	DefaultFileName       = "logging.log"                   // default logging filename
	DefaultConfigFileName = "logging.conf"                  // default configuration filename
	DefaultTimeFormat     = "2006-01-02 15:04:05.999999999" // defaulttime format
	bufSize               = 1000                            // buffer size for writer
	queueSize             = 10000                           // chan queue size in async logging
	reqSize               = 10000                           // chan queue size in async logging
)

// Logger is the logging struct.
type Logger struct {

	// Be careful of the alignment issue of the variable seqid because it
	// uses the sync/atomic.AddUint64() operation. If the alignment is
	// wrong, it will cause a panic. To solve the alignment issue in an
	// easy way, we put seqid to the beginning of the structure.
	// seqid is only visiable internally.
	seqid uint64 // last used sequence number in record

	// These variables can be configured by users.
	name       string    // logger name
	level      Level     // record level higher than this will be printed
	format     string    // format of the record
	fargs      []string  // arguments to be used in the format
	out        io.Writer // writer
	startTime  time.Time // start time of the logger
	sync       bool      // use sync or async way to record logs
	timeFormat string    // format for time

	// Internal used variables, which don't have get and set functions.
	lock    sync.Mutex   // writer lock
	queue   chan string  // queue used in async logging
	request chan request // queue used in async logging
	flush   chan bool    // flush signal for the watcher to write
	quit    chan bool    // quit signal for the watcher to quit
	fd      *os.File     // file handler, used to close the file on destroy
	runtime bool         // with runtime operation or not
}

// request struct stores the logger request
type request struct {
	level  Level
	format string
	v      []interface{}
}

// SimpleLogger creates a new logger with simple configuration.
func SimpleLogger(name string) (*Logger, error) {
	return createLogger(name, WARNING, BasicFormat, os.Stdout, false)
}

// BasicLogger creates a new logger with basic configuration.
func BasicLogger(name string) (*Logger, error) {
	return FileLogger(name, WARNING, BasicFormat, DefaultFileName, false)
}

// RichLogger creates a new logger with simple configuration.
func RichLogger(name string) (*Logger, error) {
	return FileLogger(name, NOTSET, RichFormat, DefaultFileName, false)
}

// FileLogger creates a new logger with file output.
func FileLogger(name string, level Level, format string, file string, sync bool) (*Logger, error) {
	out, err := os.Create(file)
	if err != nil {
		return new(Logger), err
	}
	logger, err := createLogger(name, level, format, out, sync)
	if err == nil {
		logger.fd = out
	}
	return logger, err
}

func WriterLogger(name string, level Level, format string, out io.Writer, sync bool) (*Logger, error) {
	return createLogger(name, level, format, out, sync)
}

// createLogger create a new logger
func createLogger(name string, level Level, format string, out io.Writer, sync bool) (*Logger, error) {
	logger := new(Logger)

	err := logger.parseFormat(format)
	if err != nil {
		return logger, err
	}

	// asign values to logger
	logger.name = name
	logger.level = level
	logger.out = out
	logger.seqid = 0
	logger.sync = sync
	logger.queue = make(chan string, queueSize)
	logger.request = make(chan request, reqSize)
	logger.flush = make(chan bool)
	logger.quit = make(chan bool)
	logger.startTime = time.Now()
	logger.fd = nil
	logger.timeFormat = DefaultTimeFormat

	// start watcher to write logs if it is async or no runtime field
	if logger.sync == false || logger.runtime == false {
		go logger.watcher()
	}

	return logger, nil
}

// Destroy sends quit signal to watcher and releases all the resources.
func (logger *Logger) Destroy() {
	logger.quitWatcher()
	// clean up
	if logger.fd != nil {
		logger.fd.Close()
	}
}

func (logger *Logger) quitWatcher() {
	if logger.sync == false || logger.runtime == false {
		// quit watcher
		logger.quit <- true
		// wait for watcher quit
		<-logger.quit
	}
}

// Flush the writer
func (logger *Logger) Flush() {
	if logger.sync == false || logger.runtime == false {
		logger.flush <- true
	}
}

// Get and set the configuration of the logger

func (logger *Logger) Name() string {
	return logger.name
}

func (logger *Logger) SetName(name string) {
	logger.name = name
}

func (logger *Logger) TimeFormat() string {
	return logger.timeFormat
}

func (logger *Logger) SetTimeFormat(format string) {
	logger.timeFormat = format
}

func (logger *Logger) Level() Level {
	return Level(atomic.LoadInt32((*int32)(&logger.level)))
}

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreInt32((*int32)(&logger.level), int32(level))
}

func (logger *Logger) Format() string {
	return logger.format
}

func (logger *Logger) Fargs() []string {
	return logger.fargs
}

func (logger *Logger) SetFormat(format string) error {
	return logger.parseFormat(format)
}

func (logger *Logger) Writer() io.Writer {
	return logger.out
}

func (logger *Logger) AddWriter(out io.Writer) {
	logger.out = io.MultiWriter(logger.out, out)
}

func (logger *Logger) AddWriters(out ...io.Writer) {
	logger.out = io.MultiWriter(append(out, logger.out)...)
}

func (logger *Logger) SetWriter(out io.Writer) {
	logger.out = out
}

func (logger *Logger) SetWriters(out ...io.Writer) {
	logger.out = io.MultiWriter(out...)
}

func (logger *Logger) Sync() bool {
	return logger.sync
}

func (logger *Logger) SetSync(sync bool) {
	if sync == logger.sync {
		return
	}
	logger.quitWatcher()
	logger.sync = sync
	if logger.sync == false || logger.runtime == false {
		go logger.watcher()
	}
}
<|endoftext|>


<commit_before>package i18n

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/resources"
	go_i18n "github.com/nicksnyder/go-i18n/i18n"
	"github.com/nicksnyder/go-i18n/i18n/language"
)

const DEFAULT_LOCALE = "en_US"

var T go_i18n.TranslateFunc

func Init(config core_config.Reader) go_i18n.TranslateFunc {
	sources := []string{
		config.Locale(),
		os.Getenv("LC_ALL"),
		os.Getenv("LANG"),
		DEFAULT_LOCALE,
	}

	assetNames := resources.AssetNames()

	for _, source := range sources {
		if source == "" {
			continue
		}

		for _, l := range language.Parse(source) {
			if l.Tag == "zh-tw" || l.Tag == "zh-hk" {
				l.Tag = "zh-hant"
			}

			for _, assetName := range assetNames {
				assetLocale := strings.ToLower(strings.Replace(path.Base(assetName), "_", "-", -1))
				if strings.HasPrefix(assetLocale, l.Tag) {
					assetBytes, err := resources.Asset(assetName)
					if err != nil {
						panic(fmt.Sprintf("Could not load asset '%s': %s", assetName, err.Error()))
					}

					err = go_i18n.ParseTranslationFileBytes(assetName, assetBytes)
					if err != nil {
						panic(fmt.Sprintf("Could not load translations '%s': %s", assetName, err.Error()))
					}

					T, err := go_i18n.Tfunc(source)
					if err == nil {
						return T
					}
				}
			}
		}
	}

	panic("Unable to find suitable translation")
}

func SupportedLocales() []string {
	assetNames := resources.AssetNames()
	locales := make([]string, len(assetNames))

	for i := range assetNames {
		locales[i] = strings.TrimSuffix(path.Base(assetNames[i]), ".all.json")
	}

	return locales
}

func NormalizedSupportedLocales() []string {
	supportedLocales := SupportedLocales()
	locales := make([]string, len(supportedLocales))

	for i := range supportedLocales {
		locales[i] = language.NormalizeTag(supportedLocales[i])
	}

	return locales
}

func IsSupportedLocale(locale string) bool {
	for _, supportedLocale := range NormalizedSupportedLocales() {
		for _, l := range language.Parse(locale) {
			if supportedLocale == l.String() {
				return true
			}
		}
	}

	return false
}
<commit_msg>Remove magic from i18n.go<commit_after>package i18n

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/resources"
	go_i18n "github.com/nicksnyder/go-i18n/i18n"
	"github.com/nicksnyder/go-i18n/i18n/language"
)

const (
	defaultLocale  = "en_US"
	lang           = "LANG"
	lcAll          = "LC_ALL"
	resourceSuffix = ".all.json"
	zhTW           = "zh-tw"
	zhHK           = "zh-hk"
	zhHant         = "zhHant"
	hyphen         = "-"
	underscore     = "_"
)

var T go_i18n.TranslateFunc

func Init(config core_config.Reader) go_i18n.TranslateFunc {
	sources := []string{
		config.Locale(),
		os.Getenv(lcAll),
		os.Getenv(lang),
		defaultLocale,
	}

	assetNames := resources.AssetNames()

	for _, source := range sources {
		if source == "" {
			continue
		}

		for _, l := range language.Parse(source) {
			if l.Tag == zhTW || l.Tag == zhHK {
				l.Tag = zhHant
			}

			for _, assetName := range assetNames {
				assetLocale := strings.ToLower(strings.Replace(path.Base(assetName), underscore, hyphen, -1))
				if strings.HasPrefix(assetLocale, l.Tag) {
					assetBytes, err := resources.Asset(assetName)
					if err != nil {
						panic(fmt.Sprintf("Could not load asset '%s': %s", assetName, err.Error()))
					}

					err = go_i18n.ParseTranslationFileBytes(assetName, assetBytes)
					if err != nil {
						panic(fmt.Sprintf("Could not load translations '%s': %s", assetName, err.Error()))
					}

					T, err := go_i18n.Tfunc(source)
					if err == nil {
						return T
					}
				}
			}
		}
	}

	panic("Unable to find suitable translation")
}

func SupportedLocales() []string {
	assetNames := resources.AssetNames()
	locales := make([]string, len(assetNames))

	for i := range assetNames {
		locales[i] = strings.TrimSuffix(path.Base(assetNames[i]), resourceSuffix)
	}

	return locales
}

func NormalizedSupportedLocales() []string {
	supportedLocales := SupportedLocales()
	locales := make([]string, len(supportedLocales))

	for i := range supportedLocales {
		locales[i] = language.NormalizeTag(supportedLocales[i])
	}

	return locales
}

func IsSupportedLocale(locale string) bool {
	for _, supportedLocale := range NormalizedSupportedLocales() {
		for _, l := range language.Parse(locale) {
			if supportedLocale == l.String() {
				return true
			}
		}
	}

	return false
}
<|endoftext|>


<commit_before>package other

import (
	"errors"
	"fmt"
	"os"
)

// MakeServiceFile creates the contents of a .service file and logs it plus tips to install it
func MakeServiceFile() error {
	wotnlclansBinary := Ask("Where is the wotnlclans script? (Full path to binary)")

	devAgree := Ask("Is this used for devlopment? (Y) to agree")
	dev := devAgree == "Y" || devAgree == "y"
	if _, err := os.Stat(wotnlclansBinary); os.IsNotExist(err) {
		return errors.New("Wrong location to binary, " + wotnlclansBinary)
	}
	if dev {
		wotnlclansBinary = wotnlclansBinary + " -dev"
	}

	webServer := Ask("What is the webserver location? (if empty it uses the default: " + defaultWebServerLocation + ")")
	if len(webServer) > 0 {
		wotnlclansBinary = wotnlclansBinary + " -webserverLocation " + webServer
	} else {
		wotnlclansBinary = wotnlclansBinary + " -webserverLocation " + defaultWebServerLocation
	}

	wgKey := Ask("What is your wargaming key?")
	if len(wgKey) == 0 {
		return errors.New("No wargaming key given")
	}

	wotnlclansBinary = wotnlclansBinary + "-wgkey " + wgKey

	service := `
[Unit]
Description=Wot nl/be clans server
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]
Environment=CADDYPATH=/etc/ssl/caddy
ExecStart=` + wotnlclansBinary + `
ExecReload=/bin/kill -USR1 $MAINPID
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5s

[Install]
WantedBy=multi-user.target
	`

	serviceName := "wotnlclans"
	if dev {
		serviceName = "wotnlclans-dev"
	}

	fmt.Println("----------------------\n" + service + "\n----------------------")
	fmt.Println("Copy the contents from above between the ---- into /etc/systemd/system/" + serviceName + ".service")
	fmt.Println("Start it after that using `sudo systemctl start " + serviceName + "`")
	fmt.Println("You can also directly start it after startup using `sudo systemctl enable " + serviceName + "`")
	return nil
}

// Ask aks something to the user and returns the answer
func Ask(what string) string {
	fmt.Print(what + "\n> ")
	var input string
	fmt.Scanln(&input)
	return input
}
<commit_msg>Fixed a view small service file issues<commit_after>package other

import (
	"errors"
	"fmt"
	"os"
)

// MakeServiceFile creates the contents of a .service file and logs it plus tips to install it
func MakeServiceFile() error {
	wotnlclansBinary := Ask("Where is the wotnlclans script? (Full path to binary)")

	devAgree := Ask("Is this used for devlopment? (Y) to agree")
	dev := devAgree == "Y" || devAgree == "y"
	if _, err := os.Stat(wotnlclansBinary); os.IsNotExist(err) {
		return errors.New("Wrong location to binary, " + wotnlclansBinary)
	}
	if dev {
		wotnlclansBinary = wotnlclansBinary + " -dev"
	}

	webServer := Ask("What is the webserver location? (if empty it uses the default: " + defaultWebServerLocation + ")")
	if len(webServer) > 0 {
		wotnlclansBinary = wotnlclansBinary + " -webserverLocation " + webServer
	} else {
		wotnlclansBinary = wotnlclansBinary + " -webserverLocation " + defaultWebServerLocation
	}

	wgKey := Ask("What is your wargaming key?")
	if len(wgKey) == 0 {
		return errors.New("No wargaming key given")
	}

	wotnlclansBinary = wotnlclansBinary + " -wgkey " + wgKey

	service := `
[Unit]
Description=Wot nl/be clans server
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]
ExecStart=` + wotnlclansBinary + `
ExecReload=/bin/kill -USR1 $MAINPID
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5s

[Install]
WantedBy=multi-user.target
	`

	serviceName := "wotnlclans"
	if dev {
		serviceName = "wotnlclans-dev"
	}

	fmt.Println("----------------------\n" + service + "\n----------------------")
	fmt.Println("Copy the contents from above between the ---- into /etc/systemd/system/" + serviceName + ".service")
	fmt.Println("Start it after that using `sudo systemctl start " + serviceName + "`")
	fmt.Println("You can also directly start it after startup using `sudo systemctl enable " + serviceName + "`")
	return nil
}

// Ask aks something to the user and returns the answer
func Ask(what string) string {
	fmt.Print(what + "\n> ")
	var input string
	fmt.Scanln(&input)
	return input
}
<|endoftext|>


<commit_before>// Copyright 2019 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.

//go:build libfuzzer

package runtime

import "unsafe"

func libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
func libfuzzerCallTraceIntCmp(fn *byte, arg0, arg1, fakePC uintptr)
func libfuzzerCall4(fn *byte, fakePC uintptr, s1, s2 unsafe.Pointer, result uintptr)

// Keep in sync with the definition of ret_sled in src/runtime/libfuzzer_amd64.s
const retSledSize = 512

// In libFuzzer mode, the compiler inserts calls to libfuzzerTraceCmpN and libfuzzerTraceConstCmpN
// (where N can be 1, 2, 4, or 8) for encountered integer comparisons in the code to be instrumented.
// This may result in these functions having callers that are nosplit. That is why they must be nosplit.
//
//go:nosplit
func libfuzzerTraceCmp1(arg0, arg1 uint8, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp1, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceCmp2(arg0, arg1 uint16, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp2, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceCmp4(arg0, arg1 uint32, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp4, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceCmp8(arg0, arg1 uint64, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp8, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp1(arg0, arg1 uint8, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp1, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp2(arg0, arg1 uint16, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp2, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp4(arg0, arg1 uint32, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp4, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp8(arg0, arg1 uint64, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp8, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

var pcTables []byte

func init() {
	libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_8bit_counters_init, &__start___sancov_cntrs, &__stop___sancov_cntrs)
	start := unsafe.Pointer(&__start___sancov_cntrs)
	end := unsafe.Pointer(&__stop___sancov_cntrs)

	// PC tables are arrays of ptr-sized integers representing pairs [PC,PCFlags] for every instrumented block.
	// The number of PCs and PCFlags is the same as the number of 8-bit counters. Each PC table entry has
	// the size of two ptr-sized integers. We allocate one more byte than what we actually need so that we can
	// get a pointer representing the end of the PC table array.
	size := (uintptr(end)-uintptr(start))*unsafe.Sizeof(uintptr(0))*2 + 1
	pcTables = make([]byte, size)
	libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_pcs_init, &pcTables[0], &pcTables[size-1])
}

// We call libFuzzer's __sanitizer_weak_hook_strcmp function which takes the
// following four arguments:
//
//  1. caller_pc: location of string comparison call site
//  2. s1: first string used in the comparison
//  3. s2: second string used in the comparison
//  4. result: an integer representing the comparison result. 0 indicates
//     equality (comparison will ignored by libfuzzer), non-zero indicates a
//     difference (comparison will be taken into consideration).
func libfuzzerHookStrCmp(s1, s2 string, fakePC int) {
	if s1 != s2 {
		libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
	}
	// if s1 == s2 we could call the hook with a last argument of 0 but this is unnecessary since this case will be then
	// ignored by libfuzzer
}

// This function has now the same implementation as libfuzzerHookStrCmp because we lack better checks
// for case-insensitive string equality in the runtime package.
func libfuzzerHookEqualFold(s1, s2 string, fakePC int) {
	if s1 != s2 {
		libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
	}
}

//go:linkname __sanitizer_cov_trace_cmp1 __sanitizer_cov_trace_cmp1
//go:cgo_import_static __sanitizer_cov_trace_cmp1
var __sanitizer_cov_trace_cmp1 byte

//go:linkname __sanitizer_cov_trace_cmp2 __sanitizer_cov_trace_cmp2
//go:cgo_import_static __sanitizer_cov_trace_cmp2
var __sanitizer_cov_trace_cmp2 byte

//go:linkname __sanitizer_cov_trace_cmp4 __sanitizer_cov_trace_cmp4
//go:cgo_import_static __sanitizer_cov_trace_cmp4
var __sanitizer_cov_trace_cmp4 byte

//go:linkname __sanitizer_cov_trace_cmp8 __sanitizer_cov_trace_cmp8
//go:cgo_import_static __sanitizer_cov_trace_cmp8
var __sanitizer_cov_trace_cmp8 byte

//go:linkname __sanitizer_cov_trace_const_cmp1 __sanitizer_cov_trace_const_cmp1
//go:cgo_import_static __sanitizer_cov_trace_const_cmp1
var __sanitizer_cov_trace_const_cmp1 byte

//go:linkname __sanitizer_cov_trace_const_cmp2 __sanitizer_cov_trace_const_cmp2
//go:cgo_import_static __sanitizer_cov_trace_const_cmp2
var __sanitizer_cov_trace_const_cmp2 byte

//go:linkname __sanitizer_cov_trace_const_cmp4 __sanitizer_cov_trace_const_cmp4
//go:cgo_import_static __sanitizer_cov_trace_const_cmp4
var __sanitizer_cov_trace_const_cmp4 byte

//go:linkname __sanitizer_cov_trace_const_cmp8 __sanitizer_cov_trace_const_cmp8
//go:cgo_import_static __sanitizer_cov_trace_const_cmp8
var __sanitizer_cov_trace_const_cmp8 byte

//go:linkname __sanitizer_cov_8bit_counters_init __sanitizer_cov_8bit_counters_init
//go:cgo_import_static __sanitizer_cov_8bit_counters_init
var __sanitizer_cov_8bit_counters_init byte

//go:linkname __start___sancov_cntrs __start___sancov_cntrs
//go:cgo_import_static __start___sancov_cntrs
var __start___sancov_cntrs byte

//go:linkname __stop___sancov_cntrs __stop___sancov_cntrs
//go:cgo_import_static __stop___sancov_cntrs
var __stop___sancov_cntrs byte

//go:linkname __sanitizer_cov_pcs_init __sanitizer_cov_pcs_init
//go:cgo_import_static __sanitizer_cov_pcs_init
var __sanitizer_cov_pcs_init byte

//go:linkname __sanitizer_weak_hook_strcmp __sanitizer_weak_hook_strcmp
//go:cgo_import_static __sanitizer_weak_hook_strcmp
var __sanitizer_weak_hook_strcmp byte
<commit_msg>runtime: mark string comparison hooks as no split<commit_after>// Copyright 2019 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.

//go:build libfuzzer

package runtime

import "unsafe"

func libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
func libfuzzerCallTraceIntCmp(fn *byte, arg0, arg1, fakePC uintptr)
func libfuzzerCall4(fn *byte, fakePC uintptr, s1, s2 unsafe.Pointer, result uintptr)

// Keep in sync with the definition of ret_sled in src/runtime/libfuzzer_amd64.s
const retSledSize = 512

// In libFuzzer mode, the compiler inserts calls to libfuzzerTraceCmpN and libfuzzerTraceConstCmpN
// (where N can be 1, 2, 4, or 8) for encountered integer comparisons in the code to be instrumented.
// This may result in these functions having callers that are nosplit. That is why they must be nosplit.
//
//go:nosplit
func libfuzzerTraceCmp1(arg0, arg1 uint8, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp1, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceCmp2(arg0, arg1 uint16, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp2, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceCmp4(arg0, arg1 uint32, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp4, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceCmp8(arg0, arg1 uint64, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp8, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp1(arg0, arg1 uint8, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp1, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp2(arg0, arg1 uint16, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp2, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp4(arg0, arg1 uint32, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp4, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

//go:nosplit
func libfuzzerTraceConstCmp8(arg0, arg1 uint64, fakePC int) {
	fakePC = fakePC % retSledSize
	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp8, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
}

var pcTables []byte

func init() {
	libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_8bit_counters_init, &__start___sancov_cntrs, &__stop___sancov_cntrs)
	start := unsafe.Pointer(&__start___sancov_cntrs)
	end := unsafe.Pointer(&__stop___sancov_cntrs)

	// PC tables are arrays of ptr-sized integers representing pairs [PC,PCFlags] for every instrumented block.
	// The number of PCs and PCFlags is the same as the number of 8-bit counters. Each PC table entry has
	// the size of two ptr-sized integers. We allocate one more byte than what we actually need so that we can
	// get a pointer representing the end of the PC table array.
	size := (uintptr(end)-uintptr(start))*unsafe.Sizeof(uintptr(0))*2 + 1
	pcTables = make([]byte, size)
	libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_pcs_init, &pcTables[0], &pcTables[size-1])
}

// We call libFuzzer's __sanitizer_weak_hook_strcmp function which takes the
// following four arguments:
//
//  1. caller_pc: location of string comparison call site
//  2. s1: first string used in the comparison
//  3. s2: second string used in the comparison
//  4. result: an integer representing the comparison result. 0 indicates
//     equality (comparison will ignored by libfuzzer), non-zero indicates a
//     difference (comparison will be taken into consideration).
//
//go:nosplit
func libfuzzerHookStrCmp(s1, s2 string, fakePC int) {
	if s1 != s2 {
		libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
	}
	// if s1 == s2 we could call the hook with a last argument of 0 but this is unnecessary since this case will be then
	// ignored by libfuzzer
}

// This function has now the same implementation as libfuzzerHookStrCmp because we lack better checks
// for case-insensitive string equality in the runtime package.
//
//go:nosplit
func libfuzzerHookEqualFold(s1, s2 string, fakePC int) {
	if s1 != s2 {
		libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
	}
}

//go:linkname __sanitizer_cov_trace_cmp1 __sanitizer_cov_trace_cmp1
//go:cgo_import_static __sanitizer_cov_trace_cmp1
var __sanitizer_cov_trace_cmp1 byte

//go:linkname __sanitizer_cov_trace_cmp2 __sanitizer_cov_trace_cmp2
//go:cgo_import_static __sanitizer_cov_trace_cmp2
var __sanitizer_cov_trace_cmp2 byte

//go:linkname __sanitizer_cov_trace_cmp4 __sanitizer_cov_trace_cmp4
//go:cgo_import_static __sanitizer_cov_trace_cmp4
var __sanitizer_cov_trace_cmp4 byte

//go:linkname __sanitizer_cov_trace_cmp8 __sanitizer_cov_trace_cmp8
//go:cgo_import_static __sanitizer_cov_trace_cmp8
var __sanitizer_cov_trace_cmp8 byte

//go:linkname __sanitizer_cov_trace_const_cmp1 __sanitizer_cov_trace_const_cmp1
//go:cgo_import_static __sanitizer_cov_trace_const_cmp1
var __sanitizer_cov_trace_const_cmp1 byte

//go:linkname __sanitizer_cov_trace_const_cmp2 __sanitizer_cov_trace_const_cmp2
//go:cgo_import_static __sanitizer_cov_trace_const_cmp2
var __sanitizer_cov_trace_const_cmp2 byte

//go:linkname __sanitizer_cov_trace_const_cmp4 __sanitizer_cov_trace_const_cmp4
//go:cgo_import_static __sanitizer_cov_trace_const_cmp4
var __sanitizer_cov_trace_const_cmp4 byte

//go:linkname __sanitizer_cov_trace_const_cmp8 __sanitizer_cov_trace_const_cmp8
//go:cgo_import_static __sanitizer_cov_trace_const_cmp8
var __sanitizer_cov_trace_const_cmp8 byte

//go:linkname __sanitizer_cov_8bit_counters_init __sanitizer_cov_8bit_counters_init
//go:cgo_import_static __sanitizer_cov_8bit_counters_init
var __sanitizer_cov_8bit_counters_init byte

//go:linkname __start___sancov_cntrs __start___sancov_cntrs
//go:cgo_import_static __start___sancov_cntrs
var __start___sancov_cntrs byte

//go:linkname __stop___sancov_cntrs __stop___sancov_cntrs
//go:cgo_import_static __stop___sancov_cntrs
var __stop___sancov_cntrs byte

//go:linkname __sanitizer_cov_pcs_init __sanitizer_cov_pcs_init
//go:cgo_import_static __sanitizer_cov_pcs_init
var __sanitizer_cov_pcs_init byte

//go:linkname __sanitizer_weak_hook_strcmp __sanitizer_weak_hook_strcmp
//go:cgo_import_static __sanitizer_weak_hook_strcmp
var __sanitizer_weak_hook_strcmp byte
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package x509

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"fmt"
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apiserver/pkg/authentication/authenticator"
	"k8s.io/apiserver/pkg/authentication/user"
)

var clientCertificateExpirationHistogram = prometheus.NewHistogram(
	prometheus.HistogramOpts{
		Namespace: "apiserver",
		Subsystem: "client",
		Name:      "certificate_expiration_seconds",
		Help:      "Distribution of the remaining lifetime on the certificate used to authenticate a request.",
		Buckets: []float64{
			0,
			(6 * time.Hour).Seconds(),
			(12 * time.Hour).Seconds(),
			(24 * time.Hour).Seconds(),
			(2 * 24 * time.Hour).Seconds(),
			(4 * 24 * time.Hour).Seconds(),
			(7 * 24 * time.Hour).Seconds(),
			(30 * 24 * time.Hour).Seconds(),
			(3 * 30 * 24 * time.Hour).Seconds(),
			(6 * 30 * 24 * time.Hour).Seconds(),
			(12 * 30 * 24 * time.Hour).Seconds(),
		},
	},
)

func init() {
	prometheus.MustRegister(clientCertificateExpirationHistogram)
}

// UserConversion defines an interface for extracting user info from a client certificate chain
type UserConversion interface {
	User(chain []*x509.Certificate) (*authenticator.Response, bool, error)
}

// UserConversionFunc is a function that implements the UserConversion interface.
type UserConversionFunc func(chain []*x509.Certificate) (*authenticator.Response, bool, error)

// User implements x509.UserConversion
func (f UserConversionFunc) User(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
	return f(chain)
}

// Authenticator implements request.Authenticator by extracting user info from verified client certificates
type Authenticator struct {
	opts x509.VerifyOptions
	user UserConversion
}

// New returns a request.Authenticator that verifies client certificates using the provided
// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
	return &Authenticator{opts, user}
}

// AuthenticateRequest authenticates the request using presented client certificates
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	remaining := req.TLS.PeerCertificates[0].NotAfter.Sub(time.Now())
	clientCertificateExpirationHistogram.Observe(remaining.Seconds())
	chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy)
	if err != nil {
		return nil, false, err
	}

	var errlist []error
	for _, chain := range chains {
		user, ok, err := a.user.User(chain)
		if err != nil {
			errlist = append(errlist, err)
			continue
		}

		if ok {
			return user, ok, err
		}
	}
	return nil, false, utilerrors.NewAggregate(errlist)
}

// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
type Verifier struct {
	opts x509.VerifyOptions
	auth authenticator.Request

	// allowedCommonNames contains the common names which a verified certificate is allowed to have.
	// If empty, all verified certificates are allowed.
	allowedCommonNames sets.String
}

// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
	return &Verifier{opts, auth, allowedCommonNames}
}

// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	if _, err := req.TLS.PeerCertificates[0].Verify(optsCopy); err != nil {
		return nil, false, err
	}
	if err := a.verifySubject(req.TLS.PeerCertificates[0].Subject); err != nil {
		return nil, false, err
	}
	return a.auth.AuthenticateRequest(req)
}

func (a *Verifier) verifySubject(subject pkix.Name) error {
	// No CN restrictions
	if len(a.allowedCommonNames) == 0 {
		return nil
	}
	// Enforce CN restrictions
	if a.allowedCommonNames.Has(subject.CommonName) {
		return nil
	}
	return fmt.Errorf("x509: subject with cn=%s is not in the allowed list", subject.CommonName)
}

// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
func DefaultVerifyOptions() x509.VerifyOptions {
	return x509.VerifyOptions{
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}
}

// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
	if len(chain[0].Subject.CommonName) == 0 {
		return nil, false, nil
	}
	return &authenticator.Response{
		User: &user.DefaultInfo{
			Name:   chain[0].Subject.CommonName,
			Groups: chain[0].Subject.Organization,
		},
	}, true, nil
})
<commit_msg>src/k8s.io/apiserver: Increase cert expiration histogram resolution<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package x509

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"fmt"
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apiserver/pkg/authentication/authenticator"
	"k8s.io/apiserver/pkg/authentication/user"
)

var clientCertificateExpirationHistogram = prometheus.NewHistogram(
	prometheus.HistogramOpts{
		Namespace: "apiserver",
		Subsystem: "client",
		Name:      "certificate_expiration_seconds",
		Help:      "Distribution of the remaining lifetime on the certificate used to authenticate a request.",
		Buckets: []float64{
			0,
			(30 * time.Minute).Seconds(),
			(1 * time.Hour).Seconds(),
			(2 * time.Hour).Seconds(),
			(6 * time.Hour).Seconds(),
			(12 * time.Hour).Seconds(),
			(24 * time.Hour).Seconds(),
			(2 * 24 * time.Hour).Seconds(),
			(4 * 24 * time.Hour).Seconds(),
			(7 * 24 * time.Hour).Seconds(),
			(30 * 24 * time.Hour).Seconds(),
			(3 * 30 * 24 * time.Hour).Seconds(),
			(6 * 30 * 24 * time.Hour).Seconds(),
			(12 * 30 * 24 * time.Hour).Seconds(),
		},
	},
)

func init() {
	prometheus.MustRegister(clientCertificateExpirationHistogram)
}

// UserConversion defines an interface for extracting user info from a client certificate chain
type UserConversion interface {
	User(chain []*x509.Certificate) (*authenticator.Response, bool, error)
}

// UserConversionFunc is a function that implements the UserConversion interface.
type UserConversionFunc func(chain []*x509.Certificate) (*authenticator.Response, bool, error)

// User implements x509.UserConversion
func (f UserConversionFunc) User(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
	return f(chain)
}

// Authenticator implements request.Authenticator by extracting user info from verified client certificates
type Authenticator struct {
	opts x509.VerifyOptions
	user UserConversion
}

// New returns a request.Authenticator that verifies client certificates using the provided
// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
	return &Authenticator{opts, user}
}

// AuthenticateRequest authenticates the request using presented client certificates
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	remaining := req.TLS.PeerCertificates[0].NotAfter.Sub(time.Now())
	clientCertificateExpirationHistogram.Observe(remaining.Seconds())
	chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy)
	if err != nil {
		return nil, false, err
	}

	var errlist []error
	for _, chain := range chains {
		user, ok, err := a.user.User(chain)
		if err != nil {
			errlist = append(errlist, err)
			continue
		}

		if ok {
			return user, ok, err
		}
	}
	return nil, false, utilerrors.NewAggregate(errlist)
}

// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
type Verifier struct {
	opts x509.VerifyOptions
	auth authenticator.Request

	// allowedCommonNames contains the common names which a verified certificate is allowed to have.
	// If empty, all verified certificates are allowed.
	allowedCommonNames sets.String
}

// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
	return &Verifier{opts, auth, allowedCommonNames}
}

// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
		return nil, false, nil
	}

	// Use intermediates, if provided
	optsCopy := a.opts
	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
		optsCopy.Intermediates = x509.NewCertPool()
		for _, intermediate := range req.TLS.PeerCertificates[1:] {
			optsCopy.Intermediates.AddCert(intermediate)
		}
	}

	if _, err := req.TLS.PeerCertificates[0].Verify(optsCopy); err != nil {
		return nil, false, err
	}
	if err := a.verifySubject(req.TLS.PeerCertificates[0].Subject); err != nil {
		return nil, false, err
	}
	return a.auth.AuthenticateRequest(req)
}

func (a *Verifier) verifySubject(subject pkix.Name) error {
	// No CN restrictions
	if len(a.allowedCommonNames) == 0 {
		return nil
	}
	// Enforce CN restrictions
	if a.allowedCommonNames.Has(subject.CommonName) {
		return nil
	}
	return fmt.Errorf("x509: subject with cn=%s is not in the allowed list", subject.CommonName)
}

// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
func DefaultVerifyOptions() x509.VerifyOptions {
	return x509.VerifyOptions{
		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}
}

// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
	if len(chain[0].Subject.CommonName) == 0 {
		return nil, false, nil
	}
	return &authenticator.Response{
		User: &user.DefaultInfo{
			Name:   chain[0].Subject.CommonName,
			Groups: chain[0].Subject.Organization,
		},
	}, true, nil
})
<|endoftext|>


<commit_before>// Packege pidctrl implements a PID controller.
//
// see http://en.wikipedia.org/wiki/PID_controller
package pidctrl

import (
	"time"
)

// NewPIDController returns a new PIDController using the given gain values.
func NewPIDController(p, i, d float64) *PIDController {
	return &PIDController{p: p, i: i, d: d}
}

// PIDController implements a PID controller.
type PIDController struct {
	p          float64   // proportional gain
	i          float64   // integral gain
	d          float64   // derrivate gain
	setpoint   float64   // current setpoint
	prevValue  float64   // last process value
	integral   float64   // integral sum
	lastUpdate time.Time // time of last update
}

// Set changes the setpoint of the controller.
func (c *PIDController) Set(setpoint float64) {
	c.setpoint = setpoint
}

// Get returns the setpoint of the controller.
func (c *PIDController) Get() float64 {
	return c.setpoint
}

// SetPID changes the P, I, and D constants
func (c *PIDController) SetPID(p, i, d float64) {
	c.p = p
	c.i = i
	c.d = d
}

// GetPID returns the P, I, and D constants
func (c *PIDController) GetPID() (p, i, d float64) {
	return c.p, c.i, c.d
}

// Update is identical to UpdateDuration, but automatically keeps track of the
// durations between updates.
func (c *PIDController) Update(value float64) float64 {
	var duration time.Duration
	if !c.lastUpdate.IsZero() {
		duration = time.Since(c.lastUpdate)
	}
	c.lastUpdate = time.Now()
	return c.UpdateDuration(value, duration)
}

// UpdateDuration updates the controller with the given value and duration since
// the last update. It returns the new output.
//
// see http://en.wikipedia.org/wiki/PID_controller#Pseudocode
func (c *PIDController) UpdateDuration(value float64, duration time.Duration) float64 {
	var (
		dt  = duration.Seconds()
		err = c.setpoint - value
		d   float64
	)
	c.integral += err * dt * c.i
	if dt > 0 {
		d = -((value - c.prevValue) / dt)
	}
	c.prevValue = value
	return (c.p * err) + c.integral + (c.d * d)
}
<commit_msg>Change GetPID() to just PID()<commit_after>// Packege pidctrl implements a PID controller.
//
// see http://en.wikipedia.org/wiki/PID_controller
package pidctrl

import (
	"time"
)

// NewPIDController returns a new PIDController using the given gain values.
func NewPIDController(p, i, d float64) *PIDController {
	return &PIDController{p: p, i: i, d: d}
}

// PIDController implements a PID controller.
type PIDController struct {
	p          float64   // proportional gain
	i          float64   // integral gain
	d          float64   // derrivate gain
	setpoint   float64   // current setpoint
	prevValue  float64   // last process value
	integral   float64   // integral sum
	lastUpdate time.Time // time of last update
}

// Set changes the setpoint of the controller.
func (c *PIDController) Set(setpoint float64) {
	c.setpoint = setpoint
}

// Get returns the setpoint of the controller.
func (c *PIDController) Get() float64 {
	return c.setpoint
}

// SetPID changes the P, I, and D constants
func (c *PIDController) SetPID(p, i, d float64) {
	c.p = p
	c.i = i
	c.d = d
}

// PID returns the P, I, and D constants
func (c *PIDController) PID() (p, i, d float64) {
	return c.p, c.i, c.d
}

// Update is identical to UpdateDuration, but automatically keeps track of the
// durations between updates.
func (c *PIDController) Update(value float64) float64 {
	var duration time.Duration
	if !c.lastUpdate.IsZero() {
		duration = time.Since(c.lastUpdate)
	}
	c.lastUpdate = time.Now()
	return c.UpdateDuration(value, duration)
}

// UpdateDuration updates the controller with the given value and duration since
// the last update. It returns the new output.
//
// see http://en.wikipedia.org/wiki/PID_controller#Pseudocode
func (c *PIDController) UpdateDuration(value float64, duration time.Duration) float64 {
	var (
		dt  = duration.Seconds()
		err = c.setpoint - value
		d   float64
	)
	c.integral += err * dt * c.i
	if dt > 0 {
		d = -((value - c.prevValue) / dt)
	}
	c.prevValue = value
	return (c.p * err) + c.integral + (c.d * d)
}
<|endoftext|>