<commit_before>// Package aphjsonapi provides additional interfaces, wrapper and helper functions for original
// jsonapi package("github.com/manyminds/api2go/jsonapi")
package aphjsonapi

import (
	"fmt"
	"math"
	"reflect"
	"strings"

	"github.com/dictyBase/go-middlewares/middlewares/pagination"
	"github.com/manyminds/api2go/jsonapi"
)

// Container type for having information about relationship links
type RelationShipLink struct {
	Name string
	// To override the default links, it will be appended to
	// the base url.
	SuffixFragment string
}

// Interface to implement for creating self relationship links
type MarshalSelfRelations interface {
	GetSelfLinksInfo() []RelationShipLink
}

// Interface to implement for creating related relationship links
type MarshalRelatedRelations interface {
	GetRelatedLinksInfo() []RelationShipLink
}

// MarshalWithPagination adds pagination information for collection resource
func MarshalWithPagination(data interface{}, ep jsonapi.ServerInformation, opt *pagination.Props) (*jsonapi.Document, error) {
	var jst *jsonapi.Document
	if reflect.TypeOf(data).Kind() != reflect.Slice {
		return jst, fmt.Errorf("%s\n", "Only slice type is allowed for pagination")
	}
	jst, err := MarshalToStructWrapper(data, ep)
	if err != nil {
		return jst, err
	}
	baseLink := jst.Links.Self
	pageLink := &jsonapi.Links{}
	pageLink.Self = generatePaginatedResourceLink(baseLink, opt.Current, opt.Entries)
	pageLink.First = generatePaginatedResourceLink(baseLink, 1, opt.Entries)
	if opt.Current != 1 {
		pageLink.Previous = generatePaginatedResourceLink(baseLink, opt.Current-1, opt.Entries)
	}
	lastPage := int(math.Floor(float64(opt.Records) / float64(opt.Entries)))
	pageLink.Last = generatePaginatedResourceLink(baseLink, lastPage, opt.Entries)
	if opt.Current != lastPage {
		pageLink.Next = generatePaginatedResourceLink(baseLink, opt.Current+1, opt.Entries)
	}
	jst.Links = pageLink
	jst.Meta = map[string]interface{}{
		"pagination": map[string]int{
			"records": opt.Records,
			"total":   lastPage,
			"size":    opt.Entries,
			"number":  opt.Current,
		},
	}
	return jst, nil
}

// MarshalToStructWrapper adds relationship information and returns a
// jsonapi.Document structure for further json encoding
func MarshalToStructWrapper(data interface{}, ep jsonapi.ServerInformation) (*jsonapi.Document, error) {
	jst, err := jsonapi.MarshalToStruct(data, ep)
	if err != nil {
		return jst, err
	}
	if len(jst.Data.DataArray) > 0 { //array resource objects
		// picking first element both from the generated and given typed structures
		elem := jst.Data.DataArray[0]
		value := reflect.ValueOf(data).Index(0).Interface()
		// link for the array resource itself
		jst.Links = &jsonapi.Links{Self: generateMultiResourceLink(&elem, ep)}
		for i, d := range jst.Data.DataArray {
			// link for individual resource
			jst.Data.DataArray[i].Links = &jsonapi.Links{Self: generateSingleResourceLink(&d, ep)}
			// Add relationships to every member
			r := generateRelationshipLinks(value, &d, ep)
			jst.Data.DataArray[i].Relationships = r
		}
	} else {
		jst.Links = &jsonapi.Links{Self: generateSingleResourceLink(jst.Data.DataObject, ep)}
		relationships := generateRelationshipLinks(data, jst.Data.DataObject, ep)
		if len(relationships) > 0 {
			jst.Data.DataObject.Relationships = relationships
		}
	}
	return jst, nil
}

func generateBaseLink(ep jsonapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		strings.Trim(ep.GetBaseURL(), "/"),
		strings.Trim(ep.GetPrefix(), "/"),
	)
}

func generatePaginatedResourceLink(baseurl string, pagenum, pagesize int) string {
	return fmt.Sprintf(
		"%s?page[number]=%d&page[size]=%d",
		baseurl,
		pagenum,
		pagesize,
	)
}

func generateSingleResourceLink(jdata *jsonapi.Data, ep jsonapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s/%s",
		generateBaseLink(ep),
		jdata.Type,
		jdata.ID,
	)
}

func generateMultiResourceLink(jdata *jsonapi.Data, ep jsonapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		generateBaseLink(ep),
		jdata.Type,
	)
}

func generateRelationshipLinks(data interface{}, jdata *jsonapi.Data, ep jsonapi.ServerInformation) map[string]jsonapi.Relationship {
	relationships := make(map[string]jsonapi.Relationship)
	baselink := generateBaseLink(ep)
	self, ok := data.(MarshalSelfRelations)
	if ok {
		for _, rel := range self.GetSelfLinksInfo() {
			links := &jsonapi.Links{}
			if len(rel.SuffixFragment) > 0 {
				links.Self = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				links.Self = fmt.Sprintf("%s/%s/%s/relationships/%s",
					baselink,
					jdata.Type,
					jdata.ID,
					rel.Name,
				)
			}
			relationships[rel.Name] = jsonapi.Relationship{Links: links}
		}
	}
	related, ok := data.(MarshalRelatedRelations)
	if ok {
		for _, rel := range related.GetRelatedLinksInfo() {
			var rlink string
			if len(rel.SuffixFragment) > 0 {
				rlink = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				rlink = fmt.Sprintf("%s/%s/%s/%s",
					baselink,
					jdata.Type,
					jdata.ID, rel.Name,
				)
			}
			if _, ok := relationships[rel.Name]; ok {
				relationships[rel.Name].Links.Related = rlink
			} else {
				relationships[rel.Name] = jsonapi.Relationship{Links: &jsonapi.Links{Related: rlink}}
			}
		}
	}
	return relationships
}

// MapFieldsToDbRow maps JSONAPI attributes to database row names
func MapFieldsToDbRow(data interface{}) map[string]string {
	frow := make(map[string]string)
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag
		v, ok := tag.Lookup("json")
		if ok && v != "-" {
			r, dbok := tag.Lookup("db")
			if dbok && r != "-" {
				frow[v] = r
			}
		}
	}
	return frow
}
<commit_msg>Check for interface implementation for the mapping before using dynamic reflection<commit_after>// Package aphjsonapi provides additional interfaces, wrapper and helper functions for original
// jsonapi package("github.com/manyminds/api2go/jsonapi")
package aphjsonapi

import (
	"fmt"
	"math"
	"reflect"
	"strings"

	"github.com/dictyBase/go-middlewares/middlewares/pagination"
	"github.com/manyminds/api2go/jsonapi"
)

// RelationshipLink is a container type for having information about
// relationship links
type RelationShipLink struct {
	Name string
	// To override the default links, it will be appended to
	// the base url.
	SuffixFragment string
}

// MarshalSelfRelations is an interface  for creating self relationship links
type MarshalSelfRelations interface {
	GetSelfLinksInfo() []RelationShipLink
}

// MarshalRelatedRelations is an interface  for creating related relationship
// links
type MarshalRelatedRelations interface {
	GetRelatedLinksInfo() []RelationShipLink
}

// AttributeToDbRowMapper is an interface to provide mapping between JSONAPI
// attribute and database row names
type AttributeToDbRowMapper interface {
	GetMap() map[string]string
}

// MarshalWithPagination adds pagination information for collection resource
func MarshalWithPagination(data interface{}, ep jsonapi.ServerInformation, opt *pagination.Props) (*jsonapi.Document, error) {
	var jst *jsonapi.Document
	if reflect.TypeOf(data).Kind() != reflect.Slice {
		return jst, fmt.Errorf("%s\n", "Only slice type is allowed for pagination")
	}
	jst, err := MarshalToStructWrapper(data, ep)
	if err != nil {
		return jst, err
	}
	baseLink := jst.Links.Self
	pageLink := &jsonapi.Links{}
	pageLink.Self = generatePaginatedResourceLink(baseLink, opt.Current, opt.Entries)
	pageLink.First = generatePaginatedResourceLink(baseLink, 1, opt.Entries)
	if opt.Current != 1 {
		pageLink.Previous = generatePaginatedResourceLink(baseLink, opt.Current-1, opt.Entries)
	}
	lastPage := int(math.Floor(float64(opt.Records) / float64(opt.Entries)))
	pageLink.Last = generatePaginatedResourceLink(baseLink, lastPage, opt.Entries)
	if opt.Current != lastPage {
		pageLink.Next = generatePaginatedResourceLink(baseLink, opt.Current+1, opt.Entries)
	}
	jst.Links = pageLink
	jst.Meta = map[string]interface{}{
		"pagination": map[string]int{
			"records": opt.Records,
			"total":   lastPage,
			"size":    opt.Entries,
			"number":  opt.Current,
		},
	}
	return jst, nil
}

// MarshalToStructWrapper adds relationship information and returns a
// jsonapi.Document structure for further json encoding
func MarshalToStructWrapper(data interface{}, ep jsonapi.ServerInformation) (*jsonapi.Document, error) {
	jst, err := jsonapi.MarshalToStruct(data, ep)
	if err != nil {
		return jst, err
	}
	if len(jst.Data.DataArray) > 0 { //array resource objects
		// picking first element both from the generated and given typed structures
		elem := jst.Data.DataArray[0]
		value := reflect.ValueOf(data).Index(0).Interface()
		// link for the array resource itself
		jst.Links = &jsonapi.Links{Self: generateMultiResourceLink(&elem, ep)}
		for i, d := range jst.Data.DataArray {
			// link for individual resource
			jst.Data.DataArray[i].Links = &jsonapi.Links{Self: generateSingleResourceLink(&d, ep)}
			// Add relationships to every member
			r := generateRelationshipLinks(value, &d, ep)
			jst.Data.DataArray[i].Relationships = r
		}
	} else {
		jst.Links = &jsonapi.Links{Self: generateSingleResourceLink(jst.Data.DataObject, ep)}
		relationships := generateRelationshipLinks(data, jst.Data.DataObject, ep)
		if len(relationships) > 0 {
			jst.Data.DataObject.Relationships = relationships
		}
	}
	return jst, nil
}

func generateBaseLink(ep jsonapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		strings.Trim(ep.GetBaseURL(), "/"),
		strings.Trim(ep.GetPrefix(), "/"),
	)
}

func generatePaginatedResourceLink(baseurl string, pagenum, pagesize int) string {
	return fmt.Sprintf(
		"%s?page[number]=%d&page[size]=%d",
		baseurl,
		pagenum,
		pagesize,
	)
}

func generateSingleResourceLink(jdata *jsonapi.Data, ep jsonapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s/%s",
		generateBaseLink(ep),
		jdata.Type,
		jdata.ID,
	)
}

func generateMultiResourceLink(jdata *jsonapi.Data, ep jsonapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		generateBaseLink(ep),
		jdata.Type,
	)
}

func generateRelationshipLinks(data interface{}, jdata *jsonapi.Data, ep jsonapi.ServerInformation) map[string]jsonapi.Relationship {
	relationships := make(map[string]jsonapi.Relationship)
	baselink := generateBaseLink(ep)
	self, ok := data.(MarshalSelfRelations)
	if ok {
		for _, rel := range self.GetSelfLinksInfo() {
			links := &jsonapi.Links{}
			if len(rel.SuffixFragment) > 0 {
				links.Self = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				links.Self = fmt.Sprintf("%s/%s/%s/relationships/%s",
					baselink,
					jdata.Type,
					jdata.ID,
					rel.Name,
				)
			}
			relationships[rel.Name] = jsonapi.Relationship{Links: links}
		}
	}
	related, ok := data.(MarshalRelatedRelations)
	if ok {
		for _, rel := range related.GetRelatedLinksInfo() {
			var rlink string
			if len(rel.SuffixFragment) > 0 {
				rlink = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				rlink = fmt.Sprintf("%s/%s/%s/%s",
					baselink,
					jdata.Type,
					jdata.ID, rel.Name,
				)
			}
			if _, ok := relationships[rel.Name]; ok {
				relationships[rel.Name].Links.Related = rlink
			} else {
				relationships[rel.Name] = jsonapi.Relationship{Links: &jsonapi.Links{Related: rlink}}
			}
		}
	}
	return relationships
}

// MapFieldsToDbRow maps JSONAPI attributes to database row names
func MapFieldsToDbRow(data interface{}) map[string]string {
	m, ok := data.(AttributeToDbRowMapper)
	if ok {
		return m.GetMap()
	}
	frow := make(map[string]string)
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag
		v, ok := tag.Lookup("json")
		if ok && v != "-" {
			r, dbok := tag.Lookup("db")
			if dbok && r != "-" {
				frow[v] = r
			}
		}
	}
	return frow
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

var (
	output             Output
	slack              Slack
	config             Config
	ip                 string
	endpointErrorState map[string]int
)

func TestSeeders(name string, seeders []string) []DNSSeeder {
	log.Printf("Testing %s seeders..\n", name)
	tm := time.Now()
	errCounter := 0
	var dnsList []DNSSeeder
	for _, x := range seeders {
		seeder := DNSSeeder{Name: x, Type: name}
		tm2 := time.Now()
		result, err := net.LookupHost(x)
		if err != nil {
			errCounter++
			seeder.Status = GetOnlineOffline(false)
			seeder.Error = err.Error()
			log.Printf("%s FAIL.\t\t Test took %s. Error: %s\n", x, time.Since(tm2).String(), err)
		} else {
			seeder.Status = GetOnlineOffline(true)
			seeder.NodeCount = len(result)
			log.Printf("%s OK\t\t %d hosts returned. Test took %s\n", x, len(result), time.Since(tm2).String())
		}
		dnsList = append(dnsList, seeder)
	}
	log.Printf("%d/%d %s DNS seeders online. Total test duration took %s\n", len(seeders)-errCounter, len(seeders), name, time.Since(tm).String())
	return dnsList
}

func IsSiteExluded(host, protocol string) bool {
	for _, x := range config.Websites {
		if host == x.Host && strings.Contains(protocol, x.Exclusions) && x.Exclusions != "" {
			return true
		}
	}
	return false
}

func CheckContentMatch(endpoint, content string) bool {
	for _, x := range config.Websites {
		for _, y := range x.ContentMatch {
			ep := y.Subdomains + "." + x.Host
			if (ep == endpoint && y.StringCheck != "" && strings.Contains(content, y.StringCheck)) || y.StringCheck == "" {
				return true
			}
		}
	}
	return false
}

func TestSites(name string, subdomains []string) []Site {
	log.Printf("Testing %s site..\n", name)
	tm := time.Now()
	errCounter := 0
	var siteList []Site
	httpPrefixes := []string{"http://", "https://"}

	for _, x := range subdomains {
		var site Site
		for _, y := range httpPrefixes {
			url := fmt.Sprintf("%s%s.%s", y, x, name)
			site.Name = StripHTTPPrefix(url)
			var result SiteProtocol

			if IsSiteExluded(name, y) {
				result.Status = "NA"
				result.Error = ""
			} else {
				tm2 := time.Now()
				content, contentSize, httpCode, err := SendHTTPGetRequest(url, false)
				result.ContentSize = contentSize
				result.HTTPCode = httpCode
				result.RespTime = time.Since(tm2).String()
				result.Status = GetOnlineOffline(true) // default to online

				var contentMatch bool
				if content == nil {
					contentMatch = CheckContentMatch(site.Name, "")
				} else {
					contentMatch = CheckContentMatch(site.Name, content.(string))
				}

				if err != nil || !contentMatch {
					result.Status = GetOnlineOffline(false)

					if !contentMatch {
						err = fmt.Errorf("%s content match failed", url)
					}

					result.Error = err.Error()
					site.NeedsAttention = true
					log.Printf("%s FAIL.\t\t Test took %s. Error: %s\n", url, time.Since(tm2).String(), err)
				} else {
					log.Println(url, "content match PASSED!")
					log.Printf("%s OK.\t\t Test took %s\n", url, time.Since(tm2).String())
				}
			}

			if y == "http://" {
				site.Protocol.HTTP = result
			} else {
				site.Protocol.HTTPS = result
			}
		}
		siteList = append(siteList, site)
	}

	log.Printf("%d/%d %s site components online. Total test duration took %s\n", len(subdomains)-errCounter, len(subdomains), name, time.Since(tm).String())
	return siteList
}

func GetOverallStatus(result *Output) string {
	health := "OK"
	for _, x := range result.DNSSeeders {
		if x.Error != "" {
			endpointErrorState[x.Name]++
			CheckExistingErrorState(x.Name, x.Error)
			log.Printf("DNS seeder %s needs attention. Error: %s Failure counter: %d", x.Name, x.Error,
				endpointErrorState[x.Name])
			health = "Needs attention."
		}
	}

	for _, x := range result.Websites {
		if x.Protocol.HTTP.Error != "" {
			endpointName := "http://" + x.Name
			endpointErrorState[endpointName]++
			CheckExistingErrorState(endpointName, x.Protocol.HTTP.Error)
			log.Printf("Website %s needs attention. Error: %s Failure counter: %d", x.Name, x.Protocol.HTTP.Error,
				endpointErrorState[endpointName])
			health = "Needs attention."
		}
		if x.Protocol.HTTPS.Error != "" {
			endpointName := "https://" + x.Name
			endpointErrorState[endpointName]++
			CheckExistingErrorState(endpointName, x.Protocol.HTTPS.Error)
			log.Printf("Website %s needs attention. Error: %s Failure counter: %d", x.Name, x.Protocol.HTTPS.Error,
				endpointErrorState[endpointName])
			health = "Needs attention."
		}
	}
	return health
}

func (o *Output) Update(seeders []DNSSeeder, sites []Site) {
	o.mux.Lock()
	o.DNSSeeders = seeders
	o.Websites = sites
	o.LastUpdated = time.Now().Unix()
	o.Status = GetOverallStatus(o)
	o.mux.Unlock()
}

func (o *Output) UpdateBlockInfo(bi BlockInfo) {
	o.mux.Lock()
	o.Block = bi
	o.mux.Unlock()
}

func (o *Output) UpdateBlockTime() {
	o.mux.Lock()
	o.Block.TimeElapsed = GetSecondsElapsed(o.Block.BlockTime)
	o.Block.Status = TimeSinceLastBlock(o.Block.BlockTime)
	o.mux.Unlock()
}

func (o Output) Get() Output {
	o.mux.Lock()
	defer o.mux.Unlock()
	return o
}

func CheckState(oldOuput, newOutput Output) {
	for x := range oldOuput.DNSSeeders {
		if oldOuput.DNSSeeders[x].Error != newOutput.DNSSeeders[x].Error {
			if oldOuput.DNSSeeders[x].Error == "" && newOutput.DNSSeeders[x].Error != "" {
				ReportStateChange(oldOuput.DNSSeeders[x].Name, false, newOutput.DNSSeeders[x].Error)
			} else if oldOuput.DNSSeeders[x].Error != "" && newOutput.DNSSeeders[x].Error == "" {
				ReportStateChange(oldOuput.DNSSeeders[x].Name, true, "")
			}
		}
	}

	for x := range oldOuput.Websites {
		if oldOuput.Websites[x].NeedsAttention != newOutput.Websites[x].NeedsAttention {
			if oldOuput.Websites[x].Protocol.HTTP.Error == "" && newOutput.Websites[x].Protocol.HTTP.Error != "" {
				ReportStateChange("http://"+oldOuput.Websites[x].Name, false, newOutput.Websites[x].Protocol.HTTP.Error)
			} else if oldOuput.Websites[x].Protocol.HTTP.Error != "" && newOutput.Websites[x].Protocol.HTTP.Error == "" {
				ReportStateChange("http://"+oldOuput.Websites[x].Name, true, "")
			}

			if oldOuput.Websites[x].Protocol.HTTPS.Error == "" && newOutput.Websites[x].Protocol.HTTPS.Error != "" {
				ReportStateChange("https://"+oldOuput.Websites[x].Name, false, newOutput.Websites[x].Protocol.HTTPS.Error)
			} else if oldOuput.Websites[x].Protocol.HTTPS.Error != "" && newOutput.Websites[x].Protocol.HTTPS.Error == "" {
				ReportStateChange("https://"+oldOuput.Websites[x].Name, true, "")
			}
		}
	}
}

func CheckExistingErrorState(endpoint, err string) {
	var result string
	if endpointErrorState[endpoint] == config.ErrorTransitionThreshold {
		result = fmt.Sprintf("%s has transitioned from ONLINE to OFFLINE. Error %s", endpoint, err)
		if slack.Connected {
			slack.SendMessage(slack.Channel, result)
		}
	}
}

func ReportStateChange(endpoint string, nowOnline bool, err string) {
	if nowOnline {
		endpointErrorState[endpoint] = 0
		result := fmt.Sprintf("%s has transitioned from OFFLINE to ONLINE.", endpoint)
		if slack.Connected {
			slack.SendMessage(slack.Channel, result)
		}
	}
}

func main() {
	//ready := make(chan bool)
	var err error
	config, err = LoadConfig()
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Loaded config.")
	config.CheckDelay = time.Minute * config.CheckDelay
	log.Println("Check delay set to", config.CheckDelay.Minutes(), "minute(s).")

	go SlackConnect(config.Slack.Token, config.Slack.Channel)

	go BlockMonitor()

	endpointErrorState = make(map[string]int)

	go func() {
		for {
			var seeders []DNSSeeder
			var sites []Site

			for _, x := range config.DNSSeeders {
				result := TestSeeders(x.Type, strings.Split(x.Hosts, ","))
				seeders = append(seeders, result...)
			}

			for _, x := range config.Websites {
				result := TestSites(x.Host, strings.Split(x.Subdomains, ","))
				sites = append(sites, result...)
			}

			oldOutput := output
			output.Update(seeders, sites)
			newOutput := output.Get()
			CheckState(oldOutput, newOutput)
			//	ready <- true
			time.Sleep(config.CheckDelay)
		}
	}()
	//<-ready

	ip, err = GetExternalIP()
	if err != nil {
		log.Printf("Unable to get IP. Error %s", err)
	} else {
		log.Println("External IP: ", ip)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		output.UpdateBlockTime()
		data, err := json.MarshalIndent(output.Get(), "", "\t")
		if err != nil {
			panic(err)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(data)
	})

	log.Printf("Starting HTTP server on port %s\n", config.HTTPServer)
	log.Fatal(http.ListenAndServe(config.HTTPServer, nil))
}
<commit_msg>Only reporting transition after threshold is reached<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

var (
	output             Output
	slack              Slack
	config             Config
	ip                 string
	endpointErrorState map[string]int
)

func TestSeeders(name string, seeders []string) []DNSSeeder {
	log.Printf("Testing %s seeders..\n", name)
	tm := time.Now()
	errCounter := 0
	var dnsList []DNSSeeder
	for _, x := range seeders {
		seeder := DNSSeeder{Name: x, Type: name}
		tm2 := time.Now()
		result, err := net.LookupHost(x)
		if err != nil {
			errCounter++
			seeder.Status = GetOnlineOffline(false)
			seeder.Error = err.Error()
			log.Printf("%s FAIL.\t\t Test took %s. Error: %s\n", x, time.Since(tm2).String(), err)
		} else {
			seeder.Status = GetOnlineOffline(true)
			seeder.NodeCount = len(result)
			log.Printf("%s OK\t\t %d hosts returned. Test took %s\n", x, len(result), time.Since(tm2).String())
		}
		dnsList = append(dnsList, seeder)
	}
	log.Printf("%d/%d %s DNS seeders online. Total test duration took %s\n", len(seeders)-errCounter, len(seeders), name, time.Since(tm).String())
	return dnsList
}

func IsSiteExluded(host, protocol string) bool {
	for _, x := range config.Websites {
		if host == x.Host && strings.Contains(protocol, x.Exclusions) && x.Exclusions != "" {
			return true
		}
	}
	return false
}

func CheckContentMatch(endpoint, content string) bool {
	for _, x := range config.Websites {
		for _, y := range x.ContentMatch {
			ep := y.Subdomains + "." + x.Host
			if (ep == endpoint && y.StringCheck != "" && strings.Contains(content, y.StringCheck)) || y.StringCheck == "" {
				return true
			}
		}
	}
	return false
}

func TestSites(name string, subdomains []string) []Site {
	log.Printf("Testing %s site..\n", name)
	tm := time.Now()
	errCounter := 0
	var siteList []Site
	httpPrefixes := []string{"http://", "https://"}

	for _, x := range subdomains {
		var site Site
		for _, y := range httpPrefixes {
			url := fmt.Sprintf("%s%s.%s", y, x, name)
			site.Name = StripHTTPPrefix(url)
			var result SiteProtocol

			if IsSiteExluded(name, y) {
				result.Status = "NA"
				result.Error = ""
			} else {
				tm2 := time.Now()
				content, contentSize, httpCode, err := SendHTTPGetRequest(url, false)
				result.ContentSize = contentSize
				result.HTTPCode = httpCode
				result.RespTime = time.Since(tm2).String()
				result.Status = GetOnlineOffline(true) // default to online

				var contentMatch bool
				if content == nil {
					contentMatch = CheckContentMatch(site.Name, "")
				} else {
					contentMatch = CheckContentMatch(site.Name, content.(string))
				}

				if err != nil || !contentMatch {
					result.Status = GetOnlineOffline(false)

					if !contentMatch {
						err = fmt.Errorf("%s content match failed", url)
					}

					result.Error = err.Error()
					site.NeedsAttention = true
					log.Printf("%s FAIL.\t\t Test took %s. Error: %s\n", url, time.Since(tm2).String(), err)
				} else {
					log.Println(url, "content match PASSED!")
					log.Printf("%s OK.\t\t Test took %s\n", url, time.Since(tm2).String())
				}
			}

			if y == "http://" {
				site.Protocol.HTTP = result
			} else {
				site.Protocol.HTTPS = result
			}
		}
		siteList = append(siteList, site)
	}

	log.Printf("%d/%d %s site components online. Total test duration took %s\n", len(subdomains)-errCounter, len(subdomains), name, time.Since(tm).String())
	return siteList
}

func GetOverallStatus(result *Output) string {
	health := "OK"
	for _, x := range result.DNSSeeders {
		if x.Error != "" {
			endpointErrorState[x.Name]++
			CheckExistingErrorState(x.Name, x.Error)
			log.Printf("DNS seeder %s needs attention. Error: %s Failure counter: %d", x.Name, x.Error,
				endpointErrorState[x.Name])
			health = "Needs attention."
		}
	}

	for _, x := range result.Websites {
		if x.Protocol.HTTP.Error != "" {
			endpointName := "http://" + x.Name
			endpointErrorState[endpointName]++
			CheckExistingErrorState(endpointName, x.Protocol.HTTP.Error)
			log.Printf("Website %s needs attention. Error: %s Failure counter: %d", x.Name, x.Protocol.HTTP.Error,
				endpointErrorState[endpointName])
			health = "Needs attention."
		}
		if x.Protocol.HTTPS.Error != "" {
			endpointName := "https://" + x.Name
			endpointErrorState[endpointName]++
			CheckExistingErrorState(endpointName, x.Protocol.HTTPS.Error)
			log.Printf("Website %s needs attention. Error: %s Failure counter: %d", x.Name, x.Protocol.HTTPS.Error,
				endpointErrorState[endpointName])
			health = "Needs attention."
		}
	}
	return health
}

func (o *Output) Update(seeders []DNSSeeder, sites []Site) {
	o.mux.Lock()
	o.DNSSeeders = seeders
	o.Websites = sites
	o.LastUpdated = time.Now().Unix()
	o.Status = GetOverallStatus(o)
	o.mux.Unlock()
}

func (o *Output) UpdateBlockInfo(bi BlockInfo) {
	o.mux.Lock()
	o.Block = bi
	o.mux.Unlock()
}

func (o *Output) UpdateBlockTime() {
	o.mux.Lock()
	o.Block.TimeElapsed = GetSecondsElapsed(o.Block.BlockTime)
	o.Block.Status = TimeSinceLastBlock(o.Block.BlockTime)
	o.mux.Unlock()
}

func (o Output) Get() Output {
	o.mux.Lock()
	defer o.mux.Unlock()
	return o
}

func CheckState(oldOuput, newOutput Output) {
	for x := range oldOuput.DNSSeeders {
		if oldOuput.DNSSeeders[x].Error != newOutput.DNSSeeders[x].Error {
			if oldOuput.DNSSeeders[x].Error == "" && newOutput.DNSSeeders[x].Error != "" {
				ReportStateChange(oldOuput.DNSSeeders[x].Name, false, newOutput.DNSSeeders[x].Error)
			} else if oldOuput.DNSSeeders[x].Error != "" && newOutput.DNSSeeders[x].Error == "" {
				ReportStateChange(oldOuput.DNSSeeders[x].Name, true, "")
			}
		}
	}

	for x := range oldOuput.Websites {
		if oldOuput.Websites[x].NeedsAttention != newOutput.Websites[x].NeedsAttention {
			if oldOuput.Websites[x].Protocol.HTTP.Error == "" && newOutput.Websites[x].Protocol.HTTP.Error != "" {
				ReportStateChange("http://"+oldOuput.Websites[x].Name, false, newOutput.Websites[x].Protocol.HTTP.Error)
			} else if oldOuput.Websites[x].Protocol.HTTP.Error != "" && newOutput.Websites[x].Protocol.HTTP.Error == "" {
				ReportStateChange("http://"+oldOuput.Websites[x].Name, true, "")
			}

			if oldOuput.Websites[x].Protocol.HTTPS.Error == "" && newOutput.Websites[x].Protocol.HTTPS.Error != "" {
				ReportStateChange("https://"+oldOuput.Websites[x].Name, false, newOutput.Websites[x].Protocol.HTTPS.Error)
			} else if oldOuput.Websites[x].Protocol.HTTPS.Error != "" && newOutput.Websites[x].Protocol.HTTPS.Error == "" {
				ReportStateChange("https://"+oldOuput.Websites[x].Name, true, "")
			}
		}
	}
}

func CheckExistingErrorState(endpoint, err string) {
	var result string
	if endpointErrorState[endpoint] == config.ErrorTransitionThreshold {
		result = fmt.Sprintf("%s has transitioned from ONLINE to OFFLINE. Error %s", endpoint, err)
		if slack.Connected {
			slack.SendMessage(slack.Channel, result)
		}
	}
}

func ReportStateChange(endpoint string, nowOnline bool, err string) {
	if nowOnline && endpointErrorState[endpoint] >= config.ErrorTransitionThreshold {
		endpointErrorState[endpoint] = 0
		result := fmt.Sprintf("%s has transitioned from OFFLINE to ONLINE.", endpoint)
		if slack.Connected {
			slack.SendMessage(slack.Channel, result)
		}
	}
}

func main() {
	//ready := make(chan bool)
	var err error
	config, err = LoadConfig()
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Loaded config.")
	config.CheckDelay = time.Minute * config.CheckDelay
	log.Println("Check delay set to", config.CheckDelay.Minutes(), "minute(s).")

	go SlackConnect(config.Slack.Token, config.Slack.Channel)

	go BlockMonitor()

	endpointErrorState = make(map[string]int)

	go func() {
		for {
			var seeders []DNSSeeder
			var sites []Site

			for _, x := range config.DNSSeeders {
				result := TestSeeders(x.Type, strings.Split(x.Hosts, ","))
				seeders = append(seeders, result...)
			}

			for _, x := range config.Websites {
				result := TestSites(x.Host, strings.Split(x.Subdomains, ","))
				sites = append(sites, result...)
			}

			oldOutput := output
			output.Update(seeders, sites)
			newOutput := output.Get()
			CheckState(oldOutput, newOutput)
			//	ready <- true
			time.Sleep(config.CheckDelay)
		}
	}()
	//<-ready

	ip, err = GetExternalIP()
	if err != nil {
		log.Printf("Unable to get IP. Error %s", err)
	} else {
		log.Println("External IP: ", ip)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		output.UpdateBlockTime()
		data, err := json.MarshalIndent(output.Get(), "", "\t")
		if err != nil {
			panic(err)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(data)
	})

	log.Printf("Starting HTTP server on port %s\n", config.HTTPServer)
	log.Fatal(http.ListenAndServe(config.HTTPServer, nil))
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package api

import (
	"github.com/mattermost/platform/einterfaces"
	"github.com/mattermost/platform/model"
	"github.com/mattermost/platform/utils"

	"net/http"
)

func checkPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
	if err := checkUserPassword(user, password); err != nil {
		return err
	}

	if err := checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
		return err
	}

	return nil
}

func checkUserPassword(user *model.User, password string) *model.AppError {
	if !model.ComparePassword(user.Password, password) {
		if result := <-Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); result.Err != nil {
			return result.Err
		}

		return model.NewLocAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id)
	} else {
		if result := <-Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, 0); result.Err != nil {
			return result.Err
		}

		return nil
	}
}

func checkLdapUserPasswordAndAllCriteria(ldapId *string, password string, mfaToken string) (*model.User, *model.AppError) {
	ldapInterface := einterfaces.GetLdapInterface()

	if ldapInterface == nil || ldapId == nil {
		err := model.NewLocAppError("doLdapAuthentication", "api.user.login_ldap.not_available.app_error", nil, "")
		err.StatusCode = http.StatusNotImplemented
		return nil, err
	}

	var user *model.User
	if ldapUser, err := ldapInterface.DoLogin(*ldapId, password); err != nil {
		err.StatusCode = http.StatusUnauthorized
		return nil, err
	} else {
		user = ldapUser
	}

	if err := checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
		err.StatusCode = http.StatusUnauthorized
		return user, err
	}

	// user successfully authenticated
	return user, nil
}

func checkUserAdditionalAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
	if err := checkUserMfa(user, mfaToken); err != nil {
		return err
	}

	if err := checkEmailVerified(user); err != nil {
		return err
	}

	if err := checkUserNotDisabled(user); err != nil {
		return err
	}

	if err := checkUserLoginAttempts(user); err != nil {
		return err
	}

	return nil
}

func checkUserMfa(user *model.User, token string) *model.AppError {
	if !user.MfaActive || !utils.IsLicensed || !*utils.License.Features.MFA || !*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication {
		return nil
	}

	mfaInterface := einterfaces.GetMfaInterface()
	if mfaInterface == nil {
		return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.not_available.app_error", nil, "")
	}

	if ok, err := mfaInterface.ValidateToken(user.MfaSecret, token); err != nil {
		return err
	} else if !ok {
		return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "")
	}

	return nil
}

func checkUserLoginAttempts(user *model.User) *model.AppError {
	if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
		return model.NewLocAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id)
	}

	return nil
}

func checkEmailVerified(user *model.User) *model.AppError {
	if !user.EmailVerified && utils.Cfg.EmailSettings.RequireEmailVerification {
		return model.NewLocAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id)
	}
	return nil
}

func checkUserNotDisabled(user *model.User) *model.AppError {
	if user.DeleteAt > 0 {
		return model.NewLocAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id)
	}
	return nil
}

func authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) {
	ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil && utils.IsLicensed && *utils.License.Features.LDAP

	if user.AuthService == model.USER_AUTH_SERVICE_LDAP {
		if !ldapAvailable {
			err := model.NewLocAppError("login", "api.user.login_ldap.not_available.app_error", nil, "")
			err.StatusCode = http.StatusNotImplemented
			return user, err
		} else if ldapUser, err := checkLdapUserPasswordAndAllCriteria(user.AuthData, password, mfaToken); err != nil {
			err.StatusCode = http.StatusUnauthorized
			return user, err
		} else {
			// slightly redundant to get the user again, but we need to get it from the LDAP server
			return ldapUser, nil
		}
	} else if user.AuthService != "" {
		err := model.NewLocAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": user.AuthService}, "")
		err.StatusCode = http.StatusBadRequest
		return user, err
	} else {
		if err := checkPasswordAndAllCriteria(user, password, mfaToken); err != nil {
			err.StatusCode = http.StatusUnauthorized
			return user, err
		} else {
			return user, nil
		}
	}
}
<commit_msg>LDAP users should not be subject to password guess limits or email verification (#3245)<commit_after>// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package api

import (
	"github.com/mattermost/platform/einterfaces"
	"github.com/mattermost/platform/model"
	"github.com/mattermost/platform/utils"

	"net/http"
)

func checkPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
	if err := checkUserPassword(user, password); err != nil {
		return err
	}

	if err := checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
		return err
	}

	return nil
}

func checkUserPassword(user *model.User, password string) *model.AppError {
	if !model.ComparePassword(user.Password, password) {
		if result := <-Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); result.Err != nil {
			return result.Err
		}

		return model.NewLocAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id)
	} else {
		if result := <-Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, 0); result.Err != nil {
			return result.Err
		}

		return nil
	}
}

func checkLdapUserPasswordAndAllCriteria(ldapId *string, password string, mfaToken string) (*model.User, *model.AppError) {
	ldapInterface := einterfaces.GetLdapInterface()

	if ldapInterface == nil || ldapId == nil {
		err := model.NewLocAppError("doLdapAuthentication", "api.user.login_ldap.not_available.app_error", nil, "")
		err.StatusCode = http.StatusNotImplemented
		return nil, err
	}

	var user *model.User
	if ldapUser, err := ldapInterface.DoLogin(*ldapId, password); err != nil {
		err.StatusCode = http.StatusUnauthorized
		return nil, err
	} else {
		user = ldapUser
	}

	if err := checkUserMfa(user, mfaToken); err != nil {
		return nil, err
	}

	if err := checkUserNotDisabled(user); err != nil {
		return nil, err
	}

	// user successfully authenticated
	return user, nil
}

func checkUserAdditionalAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
	if err := checkUserMfa(user, mfaToken); err != nil {
		return err
	}

	if err := checkEmailVerified(user); err != nil {
		return err
	}

	if err := checkUserNotDisabled(user); err != nil {
		return err
	}

	if err := checkUserLoginAttempts(user); err != nil {
		return err
	}

	return nil
}

func checkUserMfa(user *model.User, token string) *model.AppError {
	if !user.MfaActive || !utils.IsLicensed || !*utils.License.Features.MFA || !*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication {
		return nil
	}

	mfaInterface := einterfaces.GetMfaInterface()
	if mfaInterface == nil {
		return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.not_available.app_error", nil, "")
	}

	if ok, err := mfaInterface.ValidateToken(user.MfaSecret, token); err != nil {
		return err
	} else if !ok {
		return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "")
	}

	return nil
}

func checkUserLoginAttempts(user *model.User) *model.AppError {
	if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
		return model.NewLocAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id)
	}

	return nil
}

func checkEmailVerified(user *model.User) *model.AppError {
	if !user.EmailVerified && utils.Cfg.EmailSettings.RequireEmailVerification {
		return model.NewLocAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id)
	}
	return nil
}

func checkUserNotDisabled(user *model.User) *model.AppError {
	if user.DeleteAt > 0 {
		return model.NewLocAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id)
	}
	return nil
}

func authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) {
	ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil && utils.IsLicensed && *utils.License.Features.LDAP

	if user.AuthService == model.USER_AUTH_SERVICE_LDAP {
		if !ldapAvailable {
			err := model.NewLocAppError("login", "api.user.login_ldap.not_available.app_error", nil, "")
			err.StatusCode = http.StatusNotImplemented
			return user, err
		} else if ldapUser, err := checkLdapUserPasswordAndAllCriteria(user.AuthData, password, mfaToken); err != nil {
			err.StatusCode = http.StatusUnauthorized
			return user, err
		} else {
			// slightly redundant to get the user again, but we need to get it from the LDAP server
			return ldapUser, nil
		}
	} else if user.AuthService != "" {
		err := model.NewLocAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": user.AuthService}, "")
		err.StatusCode = http.StatusBadRequest
		return user, err
	} else {
		if err := checkPasswordAndAllCriteria(user, password, mfaToken); err != nil {
			err.StatusCode = http.StatusUnauthorized
			return user, err
		} else {
			return user, nil
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package backups

import (
	"io"
	"time"

	"github.com/juju/errors"

	"github.com/juju/juju/utils/ssh"
)

var sshCopyReader = func(host, filename string, archive io.Reader) error {
	return ssh.CopyReader(host, filename, archive, nil)
}

// Upload sends the backup archive to the server when it is stored.
// The ID by which the stored archive can be found is returned.
func (c *Client) Upload(archive io.Reader) (string, error) {
	// TODO(ericsnow) sshCopyReader assumes the proper SSH keys are
	// already in place (which they will be when the client is
	// initiated from the CLI).  However, this SSH-based implementation
	// is a temporary solution that will be replaced by an HTTP-based
	// one (which won't have any problem with keys).
	filename := time.Now().UTC().Format("/tmp/juju-backup-20060102-150405.tgz")
	host := "ubuntu@" + c.publicAddress
	err := sshCopyReader(host, filename, archive)
	return "file://" + filename, errors.Trace(err)
}
<commit_msg>Upload the file to the SSH user's home directory.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package backups

import (
	"io"
	"time"

	"github.com/juju/errors"

	"github.com/juju/juju/utils/ssh"
)

const sshUser = "ubuntu"

var sshCopyReader = func(host, filename string, archive io.Reader) error {
	return ssh.CopyReader(host, filename, archive, nil)
}

// Upload sends the backup archive to the server when it is stored.
// The ID by which the stored archive can be found is returned.
func (c *Client) Upload(archive io.Reader) (string, error) {
	// TODO(ericsnow) sshCopyReader assumes the proper SSH keys are
	// already in place (which they will be when the client is
	// initiated from the CLI).  However, this SSH-based implementation
	// is a temporary solution that will be replaced by an HTTP-based
	// one (which won't have any problem with keys).

	// We upload the file to the user's home directory.
	filename := time.Now().UTC().Format("juju-backup-20060102-150405.tgz")
	host := sshUser + "@" + c.publicAddress
	err := sshCopyReader(host, filename, archive)
	return "file://" + filename, errors.Trace(err)
}
<|endoftext|>


<commit_before>package framework

import (
	"gost/config"
	"gost/util"
	"log"
)

const frameworkRoutes = `
[
    {
        "id": "AuthorizationRoute",
        "endpoint": "/auth",
        "actions": {
            "CreateSession": {
              "type": "POST",
              "allowAnonymous": true
            },
            "GetAllSessions": {
              "type": "GET",
              "allowAnonymous": false,
            },
            "KillSession": {
              "type": "POST",
              "allowAnonymous": false,
            },
            "ActivateAccount": {
              "type": "POST",
              "allowAnonymous": true
            },
            "ResendAccountActivationEmail": {
                "type": "GET",
                "allowAnonymous": true
            },
            "RequestResetPassword": {
              "type": "POST",
              "allowAnonymous": true
            },
            "ResetPassword": {
              "type": "POST",
              "allowAnonymous": true
            }
        }
    },
    {
        "id": "ValuesRoute",
        "endpoint": "/values",
        "actions": {
            "Get": {
              "type": "GET",
              "allowAnonymous": false,
            },
            "GetAnonymous": {
              "type": "GET",
              "allowAnonymous": true
            }
        }
    }
]`

// InitFrameworkRoutes initializes the routes used by the framework itself
func InitFrameworkRoutes() {
	var routes []config.Route

	var err = util.DeserializeJSON([]byte(frameworkRoutes), &routes)
	if err != nil {
		log.Fatalf("[InitFrameworkRoutes] %v\n", err)
	}

	err = config.AddRoutes(false, routes...)
	if err != nil {
		log.Fatalf("[InitFrameworkRoutes] %v\n", err)
	}
}
<commit_msg>Fixed bad configuration json that prevented startup of the server<commit_after>package framework

import (
	"gost/config"
	"gost/util"
	"log"
)

const frameworkRoutes = `
[
    {
        "id": "AuthorizationRoute",
        "endpoint": "/auth",
        "actions": {
            "CreateSession": {
              "type": "POST",
              "allowAnonymous": true
            },
            "GetAllSessions": {
              "type": "GET",
              "allowAnonymous": false
            },
            "KillSession": {
              "type": "POST",
              "allowAnonymous": false
            },
            "ActivateAccount": {
              "type": "POST",
              "allowAnonymous": true
            },
            "ResendAccountActivationEmail": {
                "type": "GET",
                "allowAnonymous": true
            },
            "RequestResetPassword": {
              "type": "POST",
              "allowAnonymous": true
            },
            "ResetPassword": {
              "type": "POST",
              "allowAnonymous": true
            }
        }
    },
    {
        "id": "ValuesRoute",
        "endpoint": "/values",
        "actions": {
            "Get": {
              "type": "GET",
              "allowAnonymous": false
            },
            "GetAnonymous": {
              "type": "GET",
              "allowAnonymous": true
            }
        }
    }
]`

// InitFrameworkRoutes initializes the routes used by the framework itself
func InitFrameworkRoutes() {
	var routes []config.Route

	var err = util.DeserializeJSON([]byte(frameworkRoutes), &routes)
	if err != nil {
		log.Fatalf("[InitFrameworkRoutes] %v\n", err)
	}

	err = config.AddRoutes(false, routes...)
	if err != nil {
		log.Fatalf("[InitFrameworkRoutes] %v\n", err)
	}
}
<|endoftext|>


<commit_before>package msgpack_test

import (
	"bufio"
	"bytes"
	"math"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	. "gopkg.in/check.v1"

	"github.com/vmihailenco/msgpack/v5"
)

type nameStruct struct {
	Name string
}

func TestGocheck(t *testing.T) { TestingT(t) }

type MsgpackTest struct {
	buf *bytes.Buffer
	enc *msgpack.Encoder
	dec *msgpack.Decoder
}

var _ = Suite(&MsgpackTest{})

func (t *MsgpackTest) SetUpTest(c *C) {
	t.buf = &bytes.Buffer{}
	t.enc = msgpack.NewEncoder(t.buf)
	t.dec = msgpack.NewDecoder(bufio.NewReader(t.buf))
}

func (t *MsgpackTest) TestDecodeNil(c *C) {
	c.Assert(t.dec.Decode(nil), NotNil)
}

func (t *MsgpackTest) TestTime(c *C) {
	in := time.Now()
	var out time.Time
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Equal(in), Equals, true)

	var zero time.Time
	c.Assert(t.enc.Encode(zero), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Equal(zero), Equals, true)
	c.Assert(out.IsZero(), Equals, true)
}

func (t *MsgpackTest) TestLargeBytes(c *C) {
	N := int(1e6)

	src := bytes.Repeat([]byte{'1'}, N)
	c.Assert(t.enc.Encode(src), IsNil)
	var dst []byte
	c.Assert(t.dec.Decode(&dst), IsNil)
	c.Assert(dst, DeepEquals, src)
}

func (t *MsgpackTest) TestLargeString(c *C) {
	N := int(1e6)

	src := string(bytes.Repeat([]byte{'1'}, N))
	c.Assert(t.enc.Encode(src), IsNil)
	var dst string
	c.Assert(t.dec.Decode(&dst), IsNil)
	c.Assert(dst, Equals, src)
}

func (t *MsgpackTest) TestSliceOfStructs(c *C) {
	in := []*nameStruct{&nameStruct{"hello"}}
	var out []*nameStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out, DeepEquals, in)
}

func (t *MsgpackTest) TestMap(c *C) {
	for _, i := range []struct {
		m map[string]string
		b []byte
	}{
		{map[string]string{}, []byte{0x80}},
		{map[string]string{"hello": "world"}, []byte{0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xa5, 0x77, 0x6f, 0x72, 0x6c, 0x64}},
	} {
		c.Assert(t.enc.Encode(i.m), IsNil)
		c.Assert(t.buf.Bytes(), DeepEquals, i.b, Commentf("err encoding %v", i.m))
		var m map[string]string
		c.Assert(t.dec.Decode(&m), IsNil)
		c.Assert(m, DeepEquals, i.m)
	}
}

func (t *MsgpackTest) TestStructNil(c *C) {
	var dst *nameStruct

	c.Assert(t.enc.Encode(nameStruct{Name: "foo"}), IsNil)
	c.Assert(t.dec.Decode(&dst), IsNil)
	c.Assert(dst, Not(IsNil))
	c.Assert(dst.Name, Equals, "foo")
}

func (t *MsgpackTest) TestStructUnknownField(c *C) {
	in := struct {
		Field1 string
		Field2 string
		Field3 string
	}{
		Field1: "value1",
		Field2: "value2",
		Field3: "value3",
	}
	c.Assert(t.enc.Encode(in), IsNil)

	out := struct {
		Field2 string
	}{}
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Field2, Equals, "value2")
}

//------------------------------------------------------------------------------

type coderStruct struct {
	name string
}

type wrapperStruct struct {
	coderStruct
}

var (
	_ msgpack.CustomEncoder = (*coderStruct)(nil)
	_ msgpack.CustomDecoder = (*coderStruct)(nil)
)

func (s *coderStruct) Name() string {
	return s.name
}

func (s *coderStruct) EncodeMsgpack(enc *msgpack.Encoder) error {
	return enc.Encode(s.name)
}

func (s *coderStruct) DecodeMsgpack(dec *msgpack.Decoder) error {
	return dec.Decode(&s.name)
}

func (t *MsgpackTest) TestCoder(c *C) {
	in := &coderStruct{name: "hello"}
	var out coderStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestNilCoder(c *C) {
	in := &coderStruct{name: "hello"}
	var out *coderStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestNilCoderValue(c *C) {
	in := &coderStruct{name: "hello"}
	var out *coderStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.DecodeValue(reflect.ValueOf(&out)), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestPtrToCoder(c *C) {
	in := &coderStruct{name: "hello"}
	var out coderStruct
	out2 := &out
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out2), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestWrappedCoder(c *C) {
	in := &wrapperStruct{coderStruct: coderStruct{name: "hello"}}
	var out wrapperStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

//------------------------------------------------------------------------------

type struct2 struct {
	Name string
}

type struct1 struct {
	Name    string
	Struct2 struct2
}

func (t *MsgpackTest) TestNestedStructs(c *C) {
	in := &struct1{Name: "hello", Struct2: struct2{Name: "world"}}
	var out struct1
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name, Equals, in.Name)
	c.Assert(out.Struct2.Name, Equals, in.Struct2.Name)
}

type Struct4 struct {
	Name2 string
}

type Struct3 struct {
	Struct4
	Name1 string
}

func TestEmbedding(t *testing.T) {
	in := &Struct3{
		Name1: "hello",
		Struct4: Struct4{
			Name2: "world",
		},
	}
	var out Struct3

	b, err := msgpack.Marshal(in)
	if err != nil {
		t.Fatal(err)
	}

	err = msgpack.Unmarshal(b, &out)
	if err != nil {
		t.Fatal(err)
	}
	if out.Name1 != in.Name1 {
		t.Fatalf("")
	}
	if out.Name2 != in.Name2 {
		t.Fatalf("")
	}
}

func (t *MsgpackTest) TestSliceNil(c *C) {
	in := [][]*int{nil}
	var out [][]*int

	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out, DeepEquals, in)
}

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

func TestNoPanicOnUnsupportedKey(t *testing.T) {
	data := []byte{0x81, 0x81, 0xa1, 0x78, 0xc3, 0xc3}

	_, err := msgpack.NewDecoder(bytes.NewReader(data)).DecodeTypedMap()
	require.EqualError(t, err, "msgpack: unsupported map key: map[string]interface {}")
}

func TestMapDefault(t *testing.T) {
	in := map[string]interface{}{
		"foo": "bar",
		"hello": map[string]interface{}{
			"foo": "bar",
		},
	}
	b, err := msgpack.Marshal(in)
	require.Nil(t, err)

	var out map[string]interface{}
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)
	require.Equal(t, in, out)
}

func TestRawMessage(t *testing.T) {
	type In struct {
		Foo map[string]interface{}
	}

	type Out struct {
		Foo msgpack.RawMessage
	}

	type Out2 struct {
		Foo interface{}
	}

	b, err := msgpack.Marshal(&In{
		Foo: map[string]interface{}{
			"hello": "world",
		},
	})
	require.Nil(t, err)

	var out Out
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)

	var m map[string]string
	err = msgpack.Unmarshal(out.Foo, &m)
	require.Nil(t, err)
	require.Equal(t, map[string]string{
		"hello": "world",
	}, m)

	msg := new(msgpack.RawMessage)
	out2 := Out2{
		Foo: msg,
	}
	err = msgpack.Unmarshal(b, &out2)
	require.Nil(t, err)
	require.Equal(t, out.Foo, *msg)
}

func TestInterface(t *testing.T) {
	type Interface struct {
		Foo interface{}
	}

	in := Interface{Foo: "foo"}
	b, err := msgpack.Marshal(in)
	require.Nil(t, err)

	var str string
	out := Interface{Foo: &str}
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)
	require.Equal(t, "foo", str)
}

func TestNaN(t *testing.T) {
	in := float64(math.NaN())
	b, err := msgpack.Marshal(in)
	require.Nil(t, err)

	var out float64
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)
	require.True(t, math.IsNaN(out))
}
<commit_msg>Add sorted maps test<commit_after>package msgpack_test

import (
	"bufio"
	"bytes"
	"math"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	. "gopkg.in/check.v1"

	"github.com/vmihailenco/msgpack/v5"
)

type nameStruct struct {
	Name string
}

func TestGocheck(t *testing.T) { TestingT(t) }

type MsgpackTest struct {
	buf *bytes.Buffer
	enc *msgpack.Encoder
	dec *msgpack.Decoder
}

var _ = Suite(&MsgpackTest{})

func (t *MsgpackTest) SetUpTest(c *C) {
	t.buf = &bytes.Buffer{}
	t.enc = msgpack.NewEncoder(t.buf)
	t.dec = msgpack.NewDecoder(bufio.NewReader(t.buf))
}

func (t *MsgpackTest) TestDecodeNil(c *C) {
	c.Assert(t.dec.Decode(nil), NotNil)
}

func (t *MsgpackTest) TestTime(c *C) {
	in := time.Now()
	var out time.Time
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Equal(in), Equals, true)

	var zero time.Time
	c.Assert(t.enc.Encode(zero), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Equal(zero), Equals, true)
	c.Assert(out.IsZero(), Equals, true)
}

func (t *MsgpackTest) TestLargeBytes(c *C) {
	N := int(1e6)

	src := bytes.Repeat([]byte{'1'}, N)
	c.Assert(t.enc.Encode(src), IsNil)
	var dst []byte
	c.Assert(t.dec.Decode(&dst), IsNil)
	c.Assert(dst, DeepEquals, src)
}

func (t *MsgpackTest) TestLargeString(c *C) {
	N := int(1e6)

	src := string(bytes.Repeat([]byte{'1'}, N))
	c.Assert(t.enc.Encode(src), IsNil)
	var dst string
	c.Assert(t.dec.Decode(&dst), IsNil)
	c.Assert(dst, Equals, src)
}

func (t *MsgpackTest) TestSliceOfStructs(c *C) {
	in := []*nameStruct{&nameStruct{"hello"}}
	var out []*nameStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out, DeepEquals, in)
}

func (t *MsgpackTest) TestMap(c *C) {
	for _, i := range []struct {
		m map[string]string
		b []byte
	}{
		{map[string]string{}, []byte{0x80}},
		{map[string]string{"hello": "world"}, []byte{0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xa5, 0x77, 0x6f, 0x72, 0x6c, 0x64}},
	} {
		c.Assert(t.enc.Encode(i.m), IsNil)
		c.Assert(t.buf.Bytes(), DeepEquals, i.b, Commentf("err encoding %v", i.m))
		var m map[string]string
		c.Assert(t.dec.Decode(&m), IsNil)
		c.Assert(m, DeepEquals, i.m)
	}
}

func (t *MsgpackTest) TestStructNil(c *C) {
	var dst *nameStruct

	c.Assert(t.enc.Encode(nameStruct{Name: "foo"}), IsNil)
	c.Assert(t.dec.Decode(&dst), IsNil)
	c.Assert(dst, Not(IsNil))
	c.Assert(dst.Name, Equals, "foo")
}

func (t *MsgpackTest) TestStructUnknownField(c *C) {
	in := struct {
		Field1 string
		Field2 string
		Field3 string
	}{
		Field1: "value1",
		Field2: "value2",
		Field3: "value3",
	}
	c.Assert(t.enc.Encode(in), IsNil)

	out := struct {
		Field2 string
	}{}
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Field2, Equals, "value2")
}

//------------------------------------------------------------------------------

type coderStruct struct {
	name string
}

type wrapperStruct struct {
	coderStruct
}

var (
	_ msgpack.CustomEncoder = (*coderStruct)(nil)
	_ msgpack.CustomDecoder = (*coderStruct)(nil)
)

func (s *coderStruct) Name() string {
	return s.name
}

func (s *coderStruct) EncodeMsgpack(enc *msgpack.Encoder) error {
	return enc.Encode(s.name)
}

func (s *coderStruct) DecodeMsgpack(dec *msgpack.Decoder) error {
	return dec.Decode(&s.name)
}

func (t *MsgpackTest) TestCoder(c *C) {
	in := &coderStruct{name: "hello"}
	var out coderStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestNilCoder(c *C) {
	in := &coderStruct{name: "hello"}
	var out *coderStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestNilCoderValue(c *C) {
	in := &coderStruct{name: "hello"}
	var out *coderStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.DecodeValue(reflect.ValueOf(&out)), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestPtrToCoder(c *C) {
	in := &coderStruct{name: "hello"}
	var out coderStruct
	out2 := &out
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out2), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

func (t *MsgpackTest) TestWrappedCoder(c *C) {
	in := &wrapperStruct{coderStruct: coderStruct{name: "hello"}}
	var out wrapperStruct
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name(), Equals, "hello")
}

//------------------------------------------------------------------------------

type struct2 struct {
	Name string
}

type struct1 struct {
	Name    string
	Struct2 struct2
}

func (t *MsgpackTest) TestNestedStructs(c *C) {
	in := &struct1{Name: "hello", Struct2: struct2{Name: "world"}}
	var out struct1
	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out.Name, Equals, in.Name)
	c.Assert(out.Struct2.Name, Equals, in.Struct2.Name)
}

type Struct4 struct {
	Name2 string
}

type Struct3 struct {
	Struct4
	Name1 string
}

func TestEmbedding(t *testing.T) {
	in := &Struct3{
		Name1: "hello",
		Struct4: Struct4{
			Name2: "world",
		},
	}
	var out Struct3

	b, err := msgpack.Marshal(in)
	if err != nil {
		t.Fatal(err)
	}

	err = msgpack.Unmarshal(b, &out)
	if err != nil {
		t.Fatal(err)
	}
	if out.Name1 != in.Name1 {
		t.Fatalf("")
	}
	if out.Name2 != in.Name2 {
		t.Fatalf("")
	}
}

func (t *MsgpackTest) TestSliceNil(c *C) {
	in := [][]*int{nil}
	var out [][]*int

	c.Assert(t.enc.Encode(in), IsNil)
	c.Assert(t.dec.Decode(&out), IsNil)
	c.Assert(out, DeepEquals, in)
}

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

func TestNoPanicOnUnsupportedKey(t *testing.T) {
	data := []byte{0x81, 0x81, 0xa1, 0x78, 0xc3, 0xc3}

	_, err := msgpack.NewDecoder(bytes.NewReader(data)).DecodeTypedMap()
	require.EqualError(t, err, "msgpack: unsupported map key: map[string]interface {}")
}

func TestMapDefault(t *testing.T) {
	in := map[string]interface{}{
		"foo": "bar",
		"hello": map[string]interface{}{
			"foo": "bar",
		},
	}
	b, err := msgpack.Marshal(in)
	require.Nil(t, err)

	var out map[string]interface{}
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)
	require.Equal(t, in, out)
}

func TestRawMessage(t *testing.T) {
	type In struct {
		Foo map[string]interface{}
	}

	type Out struct {
		Foo msgpack.RawMessage
	}

	type Out2 struct {
		Foo interface{}
	}

	b, err := msgpack.Marshal(&In{
		Foo: map[string]interface{}{
			"hello": "world",
		},
	})
	require.Nil(t, err)

	var out Out
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)

	var m map[string]string
	err = msgpack.Unmarshal(out.Foo, &m)
	require.Nil(t, err)
	require.Equal(t, map[string]string{
		"hello": "world",
	}, m)

	msg := new(msgpack.RawMessage)
	out2 := Out2{
		Foo: msg,
	}
	err = msgpack.Unmarshal(b, &out2)
	require.Nil(t, err)
	require.Equal(t, out.Foo, *msg)
}

func TestInterface(t *testing.T) {
	type Interface struct {
		Foo interface{}
	}

	in := Interface{Foo: "foo"}
	b, err := msgpack.Marshal(in)
	require.Nil(t, err)

	var str string
	out := Interface{Foo: &str}
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)
	require.Equal(t, "foo", str)
}

func TestNaN(t *testing.T) {
	in := float64(math.NaN())
	b, err := msgpack.Marshal(in)
	require.Nil(t, err)

	var out float64
	err = msgpack.Unmarshal(b, &out)
	require.Nil(t, err)
	require.True(t, math.IsNaN(out))
}

func TestUseSortedMaps(t *testing.T) {
	in := map[string]interface{}{
		"a": "a",
		"b": "b",
		"c": "c",
		"d": "d",
	}

	var buf bytes.Buffer
	enc := msgpack.NewEncoder(&buf)
	enc.UseSortedMaps(true)
	dec := msgpack.NewDecoder(&buf)

	err := enc.Encode(in)
	require.Nil(t, err)

	wanted := make([]byte, buf.Len())
	copy(wanted, buf.Bytes())
	buf.Reset()

	for i := 0; i < 100; i++ {
		err := enc.Encode(in)
		require.Nil(t, err)
		require.Equal(t, wanted, buf.Bytes())

		out, err := dec.DecodeMap()
		require.Nil(t, err)
		require.Equal(t, in, out)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"time"

	"github.com/simulatedsimian/flotilla/dock"
	"github.com/tarm/serial"
)

func exitOnError(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

type LifeBoard [8]byte

func (l *LifeBoard) Set(x, y, v int) {
	x = x & 7
	y = y & 7

	if v == 0 {
		l[x] = l[x] & (0xfe << uint(y))
	} else {
		l[x] = l[x] | (1 << uint(y))
	}
}

func (l *LifeBoard) Get(x, y int) int {
	x = x & 7
	y = y & 7

	if l[x]>>uint(y)&1 != 0 {
		return 1
	}
	return 0
}

func (l *LifeBoard) writeBoard(port int, d *dock.Dock) error {
	return d.SetModuleData(port, dock.Matrix, int(l[0]), int(l[1]), int(l[2]), int(l[3]),
		int(l[4]), int(l[5]), int(l[6]), int(l[7]), 128)
}

func (l *LifeBoard) randomPopulation(rng *rand.Rand) {
	for i := range l {
		l[i] = byte(rng.Uint32())
	}
}

func (l *LifeBoard) generation() {
	var dest LifeBoard
	for y := 0; y < 8; y++ {
		for x := 0; x < 8; x++ {
			cnt := l.Get(x+1, y+1) + l.Get(x, y+1) + l.Get(x-1, y+1) +
				l.Get(x+1, y-1) + l.Get(x, y-1) + l.Get(x-1, y-1) +
				l.Get(x+1, y) + l.Get(x-1, y)

			if l.Get(x, y) == 1 {
				if cnt < 2 || cnt > 3 {
					dest.Set(x, y, 0)
				} else {
					dest.Set(x, y, 1)
				}
			} else {
				if cnt == 3 {
					dest.Set(x, y, 1)
				}
			}
		}
	}
	*l = dest
}

func main() {
	var board LifeBoard

	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	board.randomPopulation(rng)

	serialcfg := serial.Config{Name: "/dev/ttyACM0", Baud: 9600}
	port, err := serial.OpenPort(&serialcfg)

	exitOnError(err)

	log.Println("connecting to dock")
	d := dock.ConnectDock(port)

	time.Sleep(200 * time.Millisecond)
	d.SendDockCommand('e')

	matrixIdx := -1

	for {
		select {
		case ev := <-d.Events:
			if ev.ModuleType == dock.Matrix {
				if ev.EventType == dock.Connected {
					matrixIdx = ev.Port
				}
				if ev.EventType == dock.Disconnected {
					matrixIdx = -1
				}
			}
			if ev.ModuleType == dock.Touch && ev.EventType == dock.Update {
				if ev.Params[0] == 1 {
					board.randomPopulation(rng)
				}
			}

			fmt.Println(ev)
			exitOnError(ev.Error)

		case <-time.After(50 * time.Millisecond):
			if matrixIdx != -1 {
				err := board.writeBoard(matrixIdx, d)
				exitOnError(err)
				board.generation()
			}
		}
	}
}
<commit_msg>fixed bugs in life demo<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"time"

	"github.com/simulatedsimian/flotilla/dock"
	"github.com/tarm/serial"
)

func exitOnError(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

type LifeBoard [8]byte

func (l *LifeBoard) Set(x, y, v int) {
	x = x & 7
	y = y & 7

	if v == 0 {
		l[x] = l[x] & ^(1 << uint(y))
	} else {
		l[x] = l[x] | (1 << uint(y))
	}
}

func (l *LifeBoard) Get(x, y int) int {
	x = x & 7
	y = y & 7

	if l[x]&(1<<uint(y)) != 0 {
		return 1
	}
	return 0
}

func (l *LifeBoard) writeBoard(port int, d *dock.Dock) error {
	return d.SetModuleData(port, dock.Matrix, int(l[0]), int(l[1]), int(l[2]), int(l[3]),
		int(l[4]), int(l[5]), int(l[6]), int(l[7]), 32)
}

func (l *LifeBoard) randomPopulation(rng *rand.Rand) {
	for i := range l {
		l[i] = byte(rng.Uint32())
	}
}

func (l *LifeBoard) clear() {
	for i := range l {
		l[i] = 0
	}
}

func (l *LifeBoard) fill() {
	for i := range l {
		l[i] = 255
	}
}

func (l *LifeBoard) makeGlider() {
	l.clear()
	l.Set(3, 3, 1)
	l.Set(4, 4, 1)
	l.Set(4, 5, 1)
	l.Set(3, 5, 1)
	l.Set(2, 5, 1)
}

func (l *LifeBoard) countNeighbours(xx, yy int) int {
	cnt := 0
	for y := -1; y <= 1; y++ {
		for x := -1; x <= 1; x++ {
			if x != 0 || y != 0 {
				cnt += l.Get(x+xx, y+yy)
			}
		}
	}
	return cnt
}

func (l *LifeBoard) generation() {
	var dest LifeBoard
	for y := 0; y < 8; y++ {
		for x := 0; x < 8; x++ {
			cnt := l.countNeighbours(x, y)

			if l.Get(x, y) == 1 {
				if cnt < 2 || cnt > 3 {
					dest.Set(x, y, 0)
				} else {
					dest.Set(x, y, 1)
				}
			} else {
				if cnt == 3 {
					dest.Set(x, y, 1)
				}
			}
		}
	}
	*l = dest
}

func main() {
	var board LifeBoard

	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	board.randomPopulation(rng)

	serialcfg := serial.Config{Name: "/dev/ttyACM0", Baud: 9600}
	port, err := serial.OpenPort(&serialcfg)

	exitOnError(err)

	log.Println("connecting to dock")
	d := dock.ConnectDock(port)

	time.Sleep(200 * time.Millisecond)
	d.SendDockCommand('e')

	matrixIdx := -1

	for {
		select {
		case ev := <-d.Events:
			if ev.ModuleType == dock.Matrix {
				if ev.EventType == dock.Connected {
					matrixIdx = ev.Port
				}
				if ev.EventType == dock.Disconnected {
					matrixIdx = -1
				}
			}
			if ev.ModuleType == dock.Touch && ev.EventType == dock.Update {
				if ev.Params[0] == 1 {
					board.randomPopulation(rng)
					board.writeBoard(matrixIdx, d)
				}
				if ev.Params[1] == 1 {
					board.makeGlider()
					board.writeBoard(matrixIdx, d)
				}
			}

			fmt.Println(ev)
			exitOnError(ev.Error)

		case <-time.After(100 * time.Millisecond):
			if matrixIdx != -1 {
				err := board.writeBoard(matrixIdx, d)
				exitOnError(err)
				board.generation()
			}
		}
	}
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.1.22"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<commit_msg>functions: 0.1.23 release [skip ci]<commit_after>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.1.23"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<|endoftext|>


<commit_before>package deleteconnection

import (
  "seeme/db"

  "net/http"
)

func DeleteConnectionController(w http.ResponseWriter, r *http.Request) {
  _, err := db.GetUser(r.FormValue("username"))
  if err != nil {
    w.Write([]byte(err.Error()))
    return
  }
  affect, err := db.DeleteConnection(r.FormValue("username"), r.FormValue("password"));
  if err != nil || affect < 1 {
    w.Write([]byte(err.Error()))
    return
  }

  w.Write([]byte("Connection Deleted!"))

}

<commit_msg>used long if syntax in delete connection<commit_after>package deleteconnection

import (
  "seeme/db"

  "net/http"
)

func DeleteConnectionController(w http.ResponseWriter, r *http.Request) {
  if _, err := db.GetUser(r.FormValue("username")); err != nil {
    w.Write([]byte(err.Error()))
    return
  }
  affect, err := db.DeleteConnection(r.FormValue("username"), r.FormValue("password"));
  if err != nil || affect < 1 {
    w.Write([]byte(err.Error()))
    return
  }

  w.Write([]byte("Connection Deleted!"))

}

<|endoftext|>


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

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"cuelang.org/go/cue"
	"cuelang.org/go/encoding/openapi"
	"cuelang.org/go/encoding/yaml"
	"github.com/emicklei/proto"
	"github.com/kr/pretty"
)

// A Config defines the OpenAPI to generate and their properties.
type Config struct {
	// Module is the Go or CUE modules for which to generated OpenAPI
	// definitions.
	Module string

	cwd     string // the current working directory
	modRoot string // the module root

	// The generator configuration.
	Openapi *openapi.Generator

	// Directories is a list of files to generate per directory.
	Directories map[string][]Grouping

	// Information about the output of an aggregate OpenAPI file.
	All *Grouping
}

const (
	perFile  = "perFile"
	allFiles = "all"
)

// Grouping defines the source and settings for a single file.
//
// See doc.cue for more information on these fields.
type Grouping struct {
	dir string

	OapiFilename string // empty indicates the default name

	// Mode defines the set of files to include by default:
	//   manual   user defines ProtoFiles
	//   all      all proto files in this directory are automatically added
	//   perFile  a single file is generated for each proto file in the directory
	Mode string

	// ProtoFiles defines the list of proto files to include as the bases
	// of the generated file. The paths are relative the the directory.
	ProtoFiles []string

	// derived automatically if unspecified.
	Title   string
	Version string
}

func loadConfig(filename string) (c *Config, err error) {
	r := &cue.Runtime{}

	f, err := assets.Open("/")
	if err != nil {
		return nil, err
	}
	inst, err := r.Compile("doc.cue", f)
	if err != nil {
		log.Fatal(err)
	}

	var cfg *cue.Instance

	switch filepath.Ext(filename) {
	case ".cue", ".json":
		cfg, err = r.Compile(filename, nil)
	case ".yaml", ".yml":
		cfg, err = yaml.Decode(r, filename, nil)
	}
	if err != nil {
		return nil, err
	}

	v := inst.Value().Unify(cfg.Value())
	if err := v.Err(); err != nil {
		return nil, err
	}

	c = &Config{}
	if err = v.Decode(c); err != nil {
		return nil, err
	}
	return c, nil
}

// fileFromDir computes the openapi json filename from the directory name.
// If filename is not "", it is assumed to be the proto filename in perFile
// mode.
func fileFromDir(dir, filename string) string {
	comps := strings.Split(dir, "/")
	if len(comps) == 0 {
		return "istio.json"
	}

	comps = append([]string{"istio"}, comps...)

	if filename == "" {
		return strings.Join(append(comps, "json"), ".")
	}

	filename = filename[:len(filename)-len(".proto")]
	version := len(comps) - 1
	return strings.Join(append(comps[:version], filename, comps[version], "json"), ".")
}

func (c *Config) completeBuildPlan() error {
	root := c.cwd

	buildPlan := c.Directories

	// Walk over all .proto files in the root and add them to groupin entries
	// that requested all files in the directory to be added.
	err := filepath.Walk(root, func(path string, f os.FileInfo, _ error) (err error) {
		if !strings.HasSuffix(path, ".proto") {
			return nil
		}

		rel, _ := filepath.Rel(root, path)
		dir, file := filepath.Split(rel)
		dir = filepath.Clean(dir)
		switch {
		case len(buildPlan[dir]) == 0:
			return nil
		case buildPlan[dir][0].Mode == perFile:
			if len(buildPlan[dir][0].ProtoFiles) > 0 {
				buildPlan[dir] = append(buildPlan[dir], Grouping{
					ProtoFiles: []string{file},
					Mode:       perFile,
				})
				break
			}
			fallthrough
		case buildPlan[dir][0].Mode == allFiles:
			buildPlan[dir][0].ProtoFiles = append(buildPlan[dir][0].ProtoFiles, file)
		}

		return nil
	})
	if err != nil {
		return err
	}

	// Complete version, titles, and file names
	for dir, all := range buildPlan {
		for i := range all {
			(&all[i]).update(root, dir)
		}
	}

	if *verbose {
		pretty.Print(buildPlan)
		fmt.Println()
	}

	// Validate
	for dir, all := range buildPlan {
		for _, g := range all {
			if g.Title == "" {
				g.Title = "NO TITLE"
				fmt.Printf("No $description set for package %q in any .proto file\n", dir)
			}
		}
	}

	return nil
}

func (g *Grouping) update(root, dir string) {
	g.dir = dir

	if g.OapiFilename == "" {
		filename := ""
		if g.Mode == perFile && len(g.ProtoFiles) > 0 {
			filename = g.ProtoFiles[0]
		}
		g.OapiFilename = fileFromDir(dir, filename)
	}

	g.Version = filepath.Base(dir)

	if g.Title == "" {
		for _, file := range g.ProtoFiles {
			if title, ok := findTitle(filepath.Join(root, dir, file)); ok {
				if g.Title != "" && g.Title != title {
					fmt.Printf("found two incompatible titles for %s:\n\t%q, and\n\t%q\n", g.OapiFilename, g.Title, title)
				}
				g.Title = title
			}
		}
	}
}

var descRe = regexp.MustCompile(`\$description: (.*)`)

func findTitle(filename string) (title string, ok bool) {
	for _, d := range protoElems(filename) {
		switch x := d.(type) {
		case *proto.Comment:
			for _, str := range x.Lines {
				m := descRe.FindStringSubmatch(str)
				if m != nil {
					return m[1], true
				}
			}
		case *proto.Package:
			return "", false
		}
	}
	return "", false
}

func protoElems(filename string) []proto.Visitee {
	reader, err := os.Open(filename)
	if err != nil {
		log.Fatal("Could not find proto file:", err)
	}
	defer reader.Close()

	parser := proto.NewParser(reader)
	def, err := parser.Parse()
	if err != nil {
		log.Fatal("Error parsing proto:", err)
	}
	return def.Elements
}
<commit_msg>Fix cue openapi generator per-file generation filename (#219)<commit_after>// Copyright 2019 Istio 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 main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"cuelang.org/go/cue"
	"cuelang.org/go/encoding/openapi"
	"cuelang.org/go/encoding/yaml"
	"github.com/emicklei/proto"
	"github.com/kr/pretty"
)

// A Config defines the OpenAPI to generate and their properties.
type Config struct {
	// Module is the Go or CUE modules for which to generated OpenAPI
	// definitions.
	Module string

	cwd     string // the current working directory
	modRoot string // the module root

	// The generator configuration.
	Openapi *openapi.Generator

	// Directories is a list of files to generate per directory.
	Directories map[string][]Grouping

	// Information about the output of an aggregate OpenAPI file.
	All *Grouping
}

const (
	perFile  = "perFile"
	allFiles = "all"
)

// Grouping defines the source and settings for a single file.
//
// See doc.cue for more information on these fields.
type Grouping struct {
	dir string

	OapiFilename string // empty indicates the default name

	// Mode defines the set of files to include by default:
	//   manual   user defines ProtoFiles
	//   all      all proto files in this directory are automatically added
	//   perFile  a single file is generated for each proto file in the directory
	Mode string

	// ProtoFiles defines the list of proto files to include as the bases
	// of the generated file. The paths are relative the the directory.
	ProtoFiles []string

	// derived automatically if unspecified.
	Title   string
	Version string
}

func loadConfig(filename string) (c *Config, err error) {
	r := &cue.Runtime{}

	f, err := assets.Open("/")
	if err != nil {
		return nil, err
	}
	inst, err := r.Compile("doc.cue", f)
	if err != nil {
		log.Fatal(err)
	}

	var cfg *cue.Instance

	switch filepath.Ext(filename) {
	case ".cue", ".json":
		cfg, err = r.Compile(filename, nil)
	case ".yaml", ".yml":
		cfg, err = yaml.Decode(r, filename, nil)
	}
	if err != nil {
		return nil, err
	}

	v := inst.Value().Unify(cfg.Value())
	if err := v.Err(); err != nil {
		return nil, err
	}

	c = &Config{}
	if err = v.Decode(c); err != nil {
		return nil, err
	}
	return c, nil
}

// fileFromDir computes the openapi json filename from the directory name.
// If filename is not "", it is assumed to be the proto filename in perFile
// mode.
func fileFromDir(dir, filename string) string {
	if filename != "" {
		filename = filename[:len(filename)-len(".proto")]
		return filename + ".json"
	}
	comps := strings.Split(dir, "/")
	if len(comps) == 0 {
		return "istio.json"
	}

	comps = append([]string{"istio"}, comps...)

	return strings.Join(append(comps, "json"), ".")
}

func (c *Config) completeBuildPlan() error {
	root := c.cwd

	buildPlan := c.Directories

	// Walk over all .proto files in the root and add them to groupin entries
	// that requested all files in the directory to be added.
	err := filepath.Walk(root, func(path string, f os.FileInfo, _ error) (err error) {
		if !strings.HasSuffix(path, ".proto") {
			return nil
		}

		rel, _ := filepath.Rel(root, path)
		dir, file := filepath.Split(rel)
		dir = filepath.Clean(dir)
		switch {
		case len(buildPlan[dir]) == 0:
			return nil
		case buildPlan[dir][0].Mode == perFile:
			if len(buildPlan[dir][0].ProtoFiles) > 0 {
				buildPlan[dir] = append(buildPlan[dir], Grouping{
					ProtoFiles: []string{file},
					Mode:       perFile,
				})
				break
			}
			fallthrough
		case buildPlan[dir][0].Mode == allFiles:
			buildPlan[dir][0].ProtoFiles = append(buildPlan[dir][0].ProtoFiles, file)
		}

		return nil
	})
	if err != nil {
		return err
	}

	// Complete version, titles, and file names
	for dir, all := range buildPlan {
		for i := range all {
			(&all[i]).update(root, dir)
		}
	}

	if *verbose {
		pretty.Print(buildPlan)
		fmt.Println()
	}

	// Validate
	for dir, all := range buildPlan {
		for _, g := range all {
			if g.Title == "" {
				g.Title = "NO TITLE"
				fmt.Printf("No $description set for package %q in any .proto file\n", dir)
			}
		}
	}

	return nil
}

func (g *Grouping) update(root, dir string) {
	g.dir = dir

	if g.OapiFilename == "" {
		filename := ""
		if g.Mode == perFile && len(g.ProtoFiles) > 0 {
			filename = g.ProtoFiles[0]
		}
		g.OapiFilename = fileFromDir(dir, filename)
	}

	g.Version = filepath.Base(dir)

	if g.Title == "" {
		for _, file := range g.ProtoFiles {
			if title, ok := findTitle(filepath.Join(root, dir, file)); ok {
				if g.Title != "" && g.Title != title {
					fmt.Printf("found two incompatible titles for %s:\n\t%q, and\n\t%q\n", g.OapiFilename, g.Title, title)
				}
				g.Title = title
			}
		}
	}
}

var descRe = regexp.MustCompile(`\$description: (.*)`)

func findTitle(filename string) (title string, ok bool) {
	for _, d := range protoElems(filename) {
		switch x := d.(type) {
		case *proto.Comment:
			for _, str := range x.Lines {
				m := descRe.FindStringSubmatch(str)
				if m != nil {
					return m[1], true
				}
			}
		case *proto.Package:
			return "", false
		}
	}
	return "", false
}

func protoElems(filename string) []proto.Visitee {
	reader, err := os.Open(filename)
	if err != nil {
		log.Fatal("Could not find proto file:", err)
	}
	defer reader.Close()

	parser := proto.NewParser(reader)
	def, err := parser.Parse()
	if err != nil {
		log.Fatal("Error parsing proto:", err)
	}
	return def.Elements
}
<|endoftext|>


<commit_before>package distribution

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
	"syscall"
	"time"

	"github.com/docker/distribution"
	"github.com/docker/distribution/registry/api/errcode"
	"github.com/docker/distribution/registry/client"
	"github.com/docker/distribution/registry/client/auth"
	"github.com/docker/distribution/registry/client/transport"
	"github.com/docker/docker/distribution/xfer"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/registry"
	"github.com/docker/engine-api/types"
	"golang.org/x/net/context"
)

// fallbackError wraps an error that can possibly allow fallback to a different
// endpoint.
type fallbackError struct {
	// err is the error being wrapped.
	err error
	// confirmedV2 is set to true if it was confirmed that the registry
	// supports the v2 protocol. This is used to limit fallbacks to the v1
	// protocol.
	confirmedV2 bool
}

// Error renders the FallbackError as a string.
func (f fallbackError) Error() string {
	return f.err.Error()
}

type dumbCredentialStore struct {
	auth *types.AuthConfig
}

func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
	return dcs.auth.Username, dcs.auth.Password
}

// conn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type conn struct {
	net.Conn
	readTimeout  time.Duration
	writeTimeout time.Duration
}

func (c *conn) Read(b []byte) (int, error) {
	err := c.Conn.SetReadDeadline(time.Now().Add(c.readTimeout))
	if err != nil {
		return 0, err
	}
	return c.Conn.Read(b)
}

func (c *conn) Write(b []byte) (int, error) {
	err := c.Conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
	if err != nil {
		return 0, err
	}
	return c.Conn.Write(b)
}

// NewV2Repository returns a repository (v2 only). It creates a HTTP transport
// providing timeout settings and authentication support, and also verifies the
// remote API version.
func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) {
	repoName := repoInfo.FullName()
	// If endpoint does not support CanonicalName, use the RemoteName instead
	if endpoint.TrimHostname {
		repoName = repoInfo.RemoteName()
	}

	// TODO(dmcgowan): Call close idle connections when complete, use keep alive
	base := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: func(network, address string) (net.Conn, error) {
			dialer := &net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
				DualStack: true,
			}
			netConn, err := dialer.Dial(network, address)
			if err != nil {
				return netConn, err
			}
			return &conn{
				Conn:         netConn,
				readTimeout:  time.Minute,
				writeTimeout: time.Minute,
			}, nil
		},
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     endpoint.TLSConfig,
		// TODO(dmcgowan): Call close idle connections when complete and use keep alive
		DisableKeepAlives: true,
	}

	modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(), metaHeaders)
	authTransport := transport.NewTransport(base, modifiers...)
	pingClient := &http.Client{
		Transport: authTransport,
		Timeout:   15 * time.Second,
	}
	endpointStr := strings.TrimRight(endpoint.URL, "/") + "/v2/"
	req, err := http.NewRequest("GET", endpointStr, nil)
	if err != nil {
		return nil, false, err
	}
	resp, err := pingClient.Do(req)
	if err != nil {
		return nil, false, err
	}
	defer resp.Body.Close()

	v2Version := auth.APIVersion{
		Type:    "registry",
		Version: "2.0",
	}

	versions := auth.APIVersions(resp, registry.DefaultRegistryVersionHeader)
	for _, pingVersion := range versions {
		if pingVersion == v2Version {
			// The version header indicates we're definitely
			// talking to a v2 registry. So don't allow future
			// fallbacks to the v1 protocol.

			foundVersion = true
			break
		}
	}

	challengeManager := auth.NewSimpleChallengeManager()
	if err := challengeManager.AddResponse(resp); err != nil {
		return nil, foundVersion, err
	}

	if authConfig.RegistryToken != "" {
		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
	} else {
		creds := dumbCredentialStore{auth: authConfig}
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
		basicHandler := auth.NewBasicHandler(creds)
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
	}
	tr := transport.NewTransport(base, modifiers...)

	repo, err = client.NewRepository(ctx, repoName, endpoint.URL, tr)
	return repo, foundVersion, err
}

type existingTokenHandler struct {
	token string
}

func (th *existingTokenHandler) Scheme() string {
	return "bearer"
}

func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
	return nil
}

// retryOnError wraps the error in xfer.DoNotRetry if we should not retry the
// operation after this error.
func retryOnError(err error) error {
	switch v := err.(type) {
	case errcode.Errors:
		return retryOnError(v[0])
	case errcode.Error:
		switch v.Code {
		case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied:
			return xfer.DoNotRetry{Err: err}
		}
	case *url.Error:
		return retryOnError(v.Err)
	case *client.UnexpectedHTTPResponseError:
		return xfer.DoNotRetry{Err: err}
	case error:
		if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) {
			return xfer.DoNotRetry{Err: err}
		}
	}
	// let's be nice and fallback if the error is a completely
	// unexpected one.
	// If new errors have to be handled in some way, please
	// add them to the switch above.
	return err
}
<commit_msg>Revert "Set idle timeouts for HTTP reads and writes in communications with the registry"<commit_after>package distribution

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
	"syscall"
	"time"

	"github.com/docker/distribution"
	"github.com/docker/distribution/registry/api/errcode"
	"github.com/docker/distribution/registry/client"
	"github.com/docker/distribution/registry/client/auth"
	"github.com/docker/distribution/registry/client/transport"
	"github.com/docker/docker/distribution/xfer"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/registry"
	"github.com/docker/engine-api/types"
	"golang.org/x/net/context"
)

// fallbackError wraps an error that can possibly allow fallback to a different
// endpoint.
type fallbackError struct {
	// err is the error being wrapped.
	err error
	// confirmedV2 is set to true if it was confirmed that the registry
	// supports the v2 protocol. This is used to limit fallbacks to the v1
	// protocol.
	confirmedV2 bool
}

// Error renders the FallbackError as a string.
func (f fallbackError) Error() string {
	return f.err.Error()
}

type dumbCredentialStore struct {
	auth *types.AuthConfig
}

func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
	return dcs.auth.Username, dcs.auth.Password
}

// NewV2Repository returns a repository (v2 only). It creates a HTTP transport
// providing timeout settings and authentication support, and also verifies the
// remote API version.
func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) {
	repoName := repoInfo.FullName()
	// If endpoint does not support CanonicalName, use the RemoteName instead
	if endpoint.TrimHostname {
		repoName = repoInfo.RemoteName()
	}

	// TODO(dmcgowan): Call close idle connections when complete, use keep alive
	base := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     endpoint.TLSConfig,
		// TODO(dmcgowan): Call close idle connections when complete and use keep alive
		DisableKeepAlives: true,
	}

	modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(), metaHeaders)
	authTransport := transport.NewTransport(base, modifiers...)
	pingClient := &http.Client{
		Transport: authTransport,
		Timeout:   15 * time.Second,
	}
	endpointStr := strings.TrimRight(endpoint.URL, "/") + "/v2/"
	req, err := http.NewRequest("GET", endpointStr, nil)
	if err != nil {
		return nil, false, err
	}
	resp, err := pingClient.Do(req)
	if err != nil {
		return nil, false, err
	}
	defer resp.Body.Close()

	v2Version := auth.APIVersion{
		Type:    "registry",
		Version: "2.0",
	}

	versions := auth.APIVersions(resp, registry.DefaultRegistryVersionHeader)
	for _, pingVersion := range versions {
		if pingVersion == v2Version {
			// The version header indicates we're definitely
			// talking to a v2 registry. So don't allow future
			// fallbacks to the v1 protocol.

			foundVersion = true
			break
		}
	}

	challengeManager := auth.NewSimpleChallengeManager()
	if err := challengeManager.AddResponse(resp); err != nil {
		return nil, foundVersion, err
	}

	if authConfig.RegistryToken != "" {
		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
	} else {
		creds := dumbCredentialStore{auth: authConfig}
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
		basicHandler := auth.NewBasicHandler(creds)
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
	}
	tr := transport.NewTransport(base, modifiers...)

	repo, err = client.NewRepository(ctx, repoName, endpoint.URL, tr)
	return repo, foundVersion, err
}

type existingTokenHandler struct {
	token string
}

func (th *existingTokenHandler) Scheme() string {
	return "bearer"
}

func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
	return nil
}

// retryOnError wraps the error in xfer.DoNotRetry if we should not retry the
// operation after this error.
func retryOnError(err error) error {
	switch v := err.(type) {
	case errcode.Errors:
		return retryOnError(v[0])
	case errcode.Error:
		switch v.Code {
		case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied:
			return xfer.DoNotRetry{Err: err}
		}
	case *url.Error:
		return retryOnError(v.Err)
	case *client.UnexpectedHTTPResponseError:
		return xfer.DoNotRetry{Err: err}
	case error:
		if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) {
			return xfer.DoNotRetry{Err: err}
		}
	}
	// let's be nice and fallback if the error is a completely
	// unexpected one.
	// If new errors have to be handled in some way, please
	// add them to the switch above.
	return err
}
<|endoftext|>