<commit_before>// Package sanitize provides functions for sanitizing text.
package sanitize

import (
	"bytes"
	"html"
	"html/template"
	"io"
	"path"
	"regexp"
	"strings"

	parser "golang.org/x/net/html"
)

var (
	ignoreTags = []string{"title", "script", "style", "iframe", "frame", "frameset", "noframes", "noembed", "embed", "applet", "object", "base"}

	defaultTags = []string{"h1", "h2", "h3", "h4", "h5", "h6", "div", "span", "hr", "p", "br", "b", "i", "strong", "em", "ol", "ul", "li", "a", "img", "pre", "code", "blockquote", "article", "section"}

	defaultAttributes = []string{"id", "class", "src", "href", "title", "alt", "name", "rel"}
)

// HTMLAllowing sanitizes html, allowing some tags.
// Arrays of allowed tags and allowed attributes may optionally be passed as the second and third arguments.
func HTMLAllowing(s string, args ...[]string) (string, error) {

	allowedTags := defaultTags
	if len(args) > 0 {
		allowedTags = args[0]
	}
	allowedAttributes := defaultAttributes
	if len(args) > 1 {
		allowedAttributes = args[1]
	}

	// Parse the html
	tokenizer := parser.NewTokenizer(strings.NewReader(s))

	buffer := bytes.NewBufferString("")
	ignore := ""

	for {
		tokenType := tokenizer.Next()
		token := tokenizer.Token()

		switch tokenType {

		case parser.ErrorToken:
			err := tokenizer.Err()
			if err == io.EOF {
				return buffer.String(), nil
			}
			return "", err

		case parser.StartTagToken:

			if len(ignore) == 0 && includes(allowedTags, token.Data) {
				token.Attr = cleanAttributes(token.Attr, allowedAttributes)
				buffer.WriteString(token.String())
			} else if includes(ignoreTags, token.Data) {
				ignore = token.Data
			}

		case parser.SelfClosingTagToken:

			if len(ignore) == 0 && includes(allowedTags, token.Data) {
				token.Attr = cleanAttributes(token.Attr, allowedAttributes)
				buffer.WriteString(token.String())
			} else if token.Data == ignore {
				ignore = ""
			}

		case parser.EndTagToken:
			if len(ignore) == 0 && includes(allowedTags, token.Data) {
				token.Attr = []parser.Attribute{}
				buffer.WriteString(token.String())
			} else if token.Data == ignore {
				ignore = ""
			}

		case parser.TextToken:
			// We allow text content through, unless ignoring this entire tag and its contents (including other tags)
			if ignore == "" {
				buffer.WriteString(token.String())
			}
		case parser.CommentToken:
			// We ignore comments by default
		case parser.DoctypeToken:
			// We ignore doctypes by default - html5 does not require them and this is intended for sanitizing snippets of text
		default:
			// We ignore unknown token types by default

		}

	}

}

// HTML strips html tags, replace common entities, and escapes <>&;'" in the result.
// Note the returned text may contain entities as it is escaped by HTMLEscapeString, and most entities are not translated.
func HTML(s string) (output string) {

	// Shortcut strings with no tags in them
	if !strings.ContainsAny(s, "<>") {
		output = s
	} else {

		// First remove line breaks etc as these have no meaning outside html tags (except pre)
		// this means pre sections will lose formatting... but will result in less unintentional paras.
		s = strings.Replace(s, "\n", "", -1)

		// Then replace line breaks with newlines, to preserve that formatting
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)

		// Walk through the string removing all tags
		b := bytes.NewBufferString("")
		inTag := false
		for _, r := range s {
			switch r {
			case '<':
				inTag = true
			case '>':
				inTag = false
			default:
				if !inTag {
					b.WriteRune(r)
				}
			}
		}
		output = b.String()
	}

	// Remove a few common harmless entities, to arrive at something more like plain text
	output = strings.Replace(output, "‘", "'", -1)
	output = strings.Replace(output, "’", "'", -1)
	output = strings.Replace(output, "“", "\"", -1)
	output = strings.Replace(output, "”", "\"", -1)
	output = strings.Replace(output, " ", " ", -1)
	output = strings.Replace(output, """, "\"", -1)
	output = strings.Replace(output, "'", "'", -1)

	// Translate some entities into their plain text equivalent (for example accents, if encoded as entities)
	output = html.UnescapeString(output)

	// In case we have missed any tags above, escape the text - removes <, >, &, ' and ".
	output = template.HTMLEscapeString(output)

	// After processing, remove some harmless entities &, ' and " which are encoded by HTMLEscapeString
	output = strings.Replace(output, """, "\"", -1)
	output = strings.Replace(output, "'", "'", -1)
	output = strings.Replace(output, "& ", "& ", -1)     // NB space after
	output = strings.Replace(output, "&amp; ", "& ", -1) // NB space after

	return output
}

// We are very restrictive as this is intended for ascii url slugs
var illegalPath = regexp.MustCompile(`[^[:alnum:]\~\-\./]`)

// Path makes a string safe to use as a URL path,
// removing accents and replacing separators with -.
// The path may still start at / and is not intended
// for use as a file system path without prefix.
func Path(s string) string {
	// Start with lowercase string
	filePath := strings.ToLower(s)
	filePath = strings.Replace(filePath, "..", "", -1)
	filePath = path.Clean(filePath)

	// Remove illegal characters for paths, flattening accents
	// and replacing some common separators with -
	filePath = cleanString(filePath, illegalPath)

	// NB this may be of length 0, caller must check
	return filePath
}

// Remove all other unrecognised characters apart from
var illegalName = regexp.MustCompile(`[^[:alnum:]-.]`)

// Name makes a string safe to use in a file name by first finding the path basename, then replacing non-ascii characters.
func Name(s string) string {
	// Start with lowercase string
	fileName := strings.ToLower(s)
	fileName = path.Clean(path.Base(fileName))

	// Remove illegal characters for names, replacing some common separators with -
	fileName = cleanString(fileName, illegalName)

	// NB this may be of length 0, caller must check
	return fileName
}

// Replace these separators with -
var baseNameSeparators = regexp.MustCompile(`[./]`)

// BaseName makes a string safe to use in a file name, producing a sanitized basename replacing . or / with -.
// No attempt is made to normalise a path or normalise case.
func BaseName(s string) string {

	// Replace certain joining characters with a dash
	baseName := baseNameSeparators.ReplaceAllString(s, "-")

	// Remove illegal characters for names, replacing some common separators with -
	baseName = cleanString(baseName, illegalName)

	// NB this may be of length 0, caller must check
	return baseName
}

// A very limited list of transliterations to catch common european names translated to urls.
// This set could be expanded with at least caps and many more characters.
var transliterations = map[rune]string{
	'À': "A",
	'Á': "A",
	'Â': "A",
	'Ã': "A",
	'Ä': "A",
	'Å': "AA",
	'Æ': "AE",
	'Ç': "C",
	'È': "E",
	'É': "E",
	'Ê': "E",
	'Ë': "E",
	'Ì': "I",
	'Í': "I",
	'Î': "I",
	'Ï': "I",
	'Ð': "D",
	'Ł': "L",
	'Ñ': "N",
	'Ò': "O",
	'Ó': "O",
	'Ô': "O",
	'Õ': "O",
	'Ö': "Oe",
	'Ø': "OE",
	'Ù': "U",
	'Ú': "U",
	'Ü': "Ue",
	'Û': "U",
	'Ý': "Y",
	'Þ': "Th",
	'ß': "ss",
	'à': "a",
	'á': "a",
	'â': "a",
	'ã': "a",
	'ä': "ae",
	'å': "aa",
	'æ': "ae",
	'ç': "c",
	'è': "e",
	'é': "e",
	'ê': "e",
	'ë': "e",
	'ì': "i",
	'í': "i",
	'î': "i",
	'ï': "i",
	'ð': "d",
	'ł': "l",
	'ñ': "n",
	'ń': "n",
	'ò': "o",
	'ó': "o",
	'ô': "o",
	'õ': "o",
	'ō': "o",
	'ö': "oe",
	'ø': "oe",
	'ś': "s",
	'ù': "u",
	'ú': "u",
	'û': "u",
	'ū': "u",
	'ü': "ue",
	'ý': "y",
	'þ': "th",
	'ÿ': "y",
	'ż': "z",
	'Œ': "OE",
	'œ': "oe",
}

// Accents replaces a set of accented characters with ascii equivalents.
func Accents(s string) string {
	// Replace some common accent characters
	b := bytes.NewBufferString("")
	for _, c := range s {
		// Check transliterations first
		if val, ok := transliterations[c]; ok {
			b.WriteString(val)
		} else {
			b.WriteRune(c)
		}
	}
	return b.String()
}

var (
	// If the attribute contains data: or javascript: anywhere, ignore it
	// we don't allow this in attributes as it is so frequently used for xss
	// NB we allow spaces in the value, and lowercase.
	illegalAttr = regexp.MustCompile(`(d\s*a\s*t\s*a|j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*)\s*:`)

	// We are far more restrictive with href attributes.
	legalHrefAttr = regexp.MustCompile(`\A[/#][^/\\]?|mailto:|http://|https://`)
)

// cleanAttributes returns an array of attributes after removing malicious ones.
func cleanAttributes(a []parser.Attribute, allowed []string) []parser.Attribute {
	if len(a) == 0 {
		return a
	}

	var cleaned []parser.Attribute
	for _, attr := range a {
		if includes(allowed, attr.Key) {

			val := strings.ToLower(attr.Val)

			// Check for illegal attribute values
			if illegalAttr.FindString(val) != "" {
				attr.Val = ""
			}

			// Check for legal href values - / mailto:// http:// or https://
			if attr.Key == "href" {
				if legalHrefAttr.FindString(val) == "" {
					attr.Val = ""
				}
			}

			// If we still have an attribute, append it to the array
			if attr.Val != "" {
				cleaned = append(cleaned, attr)
			}
		}
	}
	return cleaned
}

// A list of characters we consider separators in normal strings and replace with our canonical separator - rather than removing.
var (
	separators = regexp.MustCompile(`[ &_=+:]`)

	dashes = regexp.MustCompile(`[\-]+`)
)

// cleanString replaces separators with - and removes characters listed in the regexp provided from string.
// Accents, spaces, and all characters not in A-Za-z0-9 are replaced.
func cleanString(s string, r *regexp.Regexp) string {

	// Remove any trailing space to avoid ending on -
	s = strings.Trim(s, " ")

	// Flatten accents first so that if we remove non-ascii we still get a legible name
	s = Accents(s)

	// Replace certain joining characters with a dash
	s = separators.ReplaceAllString(s, "-")

	// Remove all other unrecognised characters - NB we do allow any printable characters
	s = r.ReplaceAllString(s, "")

	// Remove any multiple dashes caused by replacements above
	s = dashes.ReplaceAllString(s, "-")

	return s
}

// includes checks for inclusion of a string in a []string.
func includes(a []string, s string) bool {
	for _, as := range a {
		if as == s {
			return true
		}
	}
	return false
}
<commit_msg>Preserve case on transliterations, add some<commit_after>// Package sanitize provides functions for sanitizing text.
package sanitize

import (
	"bytes"
	"html"
	"html/template"
	"io"
	"path"
	"regexp"
	"strings"

	parser "golang.org/x/net/html"
)

var (
	ignoreTags = []string{"title", "script", "style", "iframe", "frame", "frameset", "noframes", "noembed", "embed", "applet", "object", "base"}

	defaultTags = []string{"h1", "h2", "h3", "h4", "h5", "h6", "div", "span", "hr", "p", "br", "b", "i", "strong", "em", "ol", "ul", "li", "a", "img", "pre", "code", "blockquote", "article", "section"}

	defaultAttributes = []string{"id", "class", "src", "href", "title", "alt", "name", "rel"}
)

// HTMLAllowing sanitizes html, allowing some tags.
// Arrays of allowed tags and allowed attributes may optionally be passed as the second and third arguments.
func HTMLAllowing(s string, args ...[]string) (string, error) {

	allowedTags := defaultTags
	if len(args) > 0 {
		allowedTags = args[0]
	}
	allowedAttributes := defaultAttributes
	if len(args) > 1 {
		allowedAttributes = args[1]
	}

	// Parse the html
	tokenizer := parser.NewTokenizer(strings.NewReader(s))

	buffer := bytes.NewBufferString("")
	ignore := ""

	for {
		tokenType := tokenizer.Next()
		token := tokenizer.Token()

		switch tokenType {

		case parser.ErrorToken:
			err := tokenizer.Err()
			if err == io.EOF {
				return buffer.String(), nil
			}
			return "", err

		case parser.StartTagToken:

			if len(ignore) == 0 && includes(allowedTags, token.Data) {
				token.Attr = cleanAttributes(token.Attr, allowedAttributes)
				buffer.WriteString(token.String())
			} else if includes(ignoreTags, token.Data) {
				ignore = token.Data
			}

		case parser.SelfClosingTagToken:

			if len(ignore) == 0 && includes(allowedTags, token.Data) {
				token.Attr = cleanAttributes(token.Attr, allowedAttributes)
				buffer.WriteString(token.String())
			} else if token.Data == ignore {
				ignore = ""
			}

		case parser.EndTagToken:
			if len(ignore) == 0 && includes(allowedTags, token.Data) {
				token.Attr = []parser.Attribute{}
				buffer.WriteString(token.String())
			} else if token.Data == ignore {
				ignore = ""
			}

		case parser.TextToken:
			// We allow text content through, unless ignoring this entire tag and its contents (including other tags)
			if ignore == "" {
				buffer.WriteString(token.String())
			}
		case parser.CommentToken:
			// We ignore comments by default
		case parser.DoctypeToken:
			// We ignore doctypes by default - html5 does not require them and this is intended for sanitizing snippets of text
		default:
			// We ignore unknown token types by default

		}

	}

}

// HTML strips html tags, replace common entities, and escapes <>&;'" in the result.
// Note the returned text may contain entities as it is escaped by HTMLEscapeString, and most entities are not translated.
func HTML(s string) (output string) {

	// Shortcut strings with no tags in them
	if !strings.ContainsAny(s, "<>") {
		output = s
	} else {

		// First remove line breaks etc as these have no meaning outside html tags (except pre)
		// this means pre sections will lose formatting... but will result in less unintentional paras.
		s = strings.Replace(s, "\n", "", -1)

		// Then replace line breaks with newlines, to preserve that formatting
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)
		s = strings.Replace(s, "
", "\n", -1)

		// Walk through the string removing all tags
		b := bytes.NewBufferString("")
		inTag := false
		for _, r := range s {
			switch r {
			case '<':
				inTag = true
			case '>':
				inTag = false
			default:
				if !inTag {
					b.WriteRune(r)
				}
			}
		}
		output = b.String()
	}

	// Remove a few common harmless entities, to arrive at something more like plain text
	output = strings.Replace(output, "‘", "'", -1)
	output = strings.Replace(output, "’", "'", -1)
	output = strings.Replace(output, "“", "\"", -1)
	output = strings.Replace(output, "”", "\"", -1)
	output = strings.Replace(output, " ", " ", -1)
	output = strings.Replace(output, """, "\"", -1)
	output = strings.Replace(output, "'", "'", -1)

	// Translate some entities into their plain text equivalent (for example accents, if encoded as entities)
	output = html.UnescapeString(output)

	// In case we have missed any tags above, escape the text - removes <, >, &, ' and ".
	output = template.HTMLEscapeString(output)

	// After processing, remove some harmless entities &, ' and " which are encoded by HTMLEscapeString
	output = strings.Replace(output, """, "\"", -1)
	output = strings.Replace(output, "'", "'", -1)
	output = strings.Replace(output, "& ", "& ", -1)     // NB space after
	output = strings.Replace(output, "&amp; ", "& ", -1) // NB space after

	return output
}

// We are very restrictive as this is intended for ascii url slugs
var illegalPath = regexp.MustCompile(`[^[:alnum:]\~\-\./]`)

// Path makes a string safe to use as a URL path,
// removing accents and replacing separators with -.
// The path may still start at / and is not intended
// for use as a file system path without prefix.
func Path(s string) string {
	// Start with lowercase string
	filePath := strings.ToLower(s)
	filePath = strings.Replace(filePath, "..", "", -1)
	filePath = path.Clean(filePath)

	// Remove illegal characters for paths, flattening accents
	// and replacing some common separators with -
	filePath = cleanString(filePath, illegalPath)

	// NB this may be of length 0, caller must check
	return filePath
}

// Remove all other unrecognised characters apart from
var illegalName = regexp.MustCompile(`[^[:alnum:]-.]`)

// Name makes a string safe to use in a file name by first finding the path basename, then replacing non-ascii characters.
func Name(s string) string {
	// Start with lowercase string
	fileName := strings.ToLower(s)
	fileName = path.Clean(path.Base(fileName))

	// Remove illegal characters for names, replacing some common separators with -
	fileName = cleanString(fileName, illegalName)

	// NB this may be of length 0, caller must check
	return fileName
}

// Replace these separators with -
var baseNameSeparators = regexp.MustCompile(`[./]`)

// BaseName makes a string safe to use in a file name, producing a sanitized basename replacing . or / with -.
// No attempt is made to normalise a path or normalise case.
func BaseName(s string) string {

	// Replace certain joining characters with a dash
	baseName := baseNameSeparators.ReplaceAllString(s, "-")

	// Remove illegal characters for names, replacing some common separators with -
	baseName = cleanString(baseName, illegalName)

	// NB this may be of length 0, caller must check
	return baseName
}

// A very limited list of transliterations to catch common european names translated to urls.
// This set could be expanded with at least caps and many more characters.
var transliterations = map[rune]string{
	'À': "A",
	'Á': "A",
	'Â': "A",
	'Ã': "A",
	'Ä': "A",
	'Å': "AA",
	'Æ': "AE",
	'Ç': "C",
	'È': "E",
	'É': "E",
	'Ê': "E",
	'Ë': "E",
	'Ì': "I",
	'Í': "I",
	'Î': "I",
	'Ï': "I",
	'Ð': "D",
	'Ł': "L",
	'Ñ': "N",
	'Ò': "O",
	'Ó': "O",
	'Ô': "O",
	'Õ': "O",
	'Ö': "OE",
	'Ø': "OE",
	'Œ': "OE",
	'Ù': "U",
	'Ú': "U",
	'Ü': "UE",
	'Û': "U",
	'Ý': "Y",
	'Þ': "TH",
	'ẞ': "SS",
	'à': "a",
	'á': "a",
	'â': "a",
	'ã': "a",
	'ä': "ae",
	'å': "aa",
	'æ': "ae",
	'ç': "c",
	'è': "e",
	'é': "e",
	'ê': "e",
	'ë': "e",
	'ì': "i",
	'í': "i",
	'î': "i",
	'ï': "i",
	'ð': "d",
	'ł': "l",
	'ñ': "n",
	'ń': "n",
	'ò': "o",
	'ó': "o",
	'ô': "o",
	'õ': "o",
	'ō': "o",
	'ö': "oe",
	'ø': "oe",
	'œ': "oe",
	'ś': "s",
	'ù': "u",
	'ú': "u",
	'û': "u",
	'ū': "u",
	'ü': "ue",
	'ý': "y",
	'ÿ': "y",
	'ż': "z",
	'þ': "th",
	'ß': "ss",
}

// Accents replaces a set of accented characters with ascii equivalents.
func Accents(s string) string {
	// Replace some common accent characters
	b := bytes.NewBufferString("")
	for _, c := range s {
		// Check transliterations first
		if val, ok := transliterations[c]; ok {
			b.WriteString(val)
		} else {
			b.WriteRune(c)
		}
	}
	return b.String()
}

var (
	// If the attribute contains data: or javascript: anywhere, ignore it
	// we don't allow this in attributes as it is so frequently used for xss
	// NB we allow spaces in the value, and lowercase.
	illegalAttr = regexp.MustCompile(`(d\s*a\s*t\s*a|j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*)\s*:`)

	// We are far more restrictive with href attributes.
	legalHrefAttr = regexp.MustCompile(`\A[/#][^/\\]?|mailto:|http://|https://`)
)

// cleanAttributes returns an array of attributes after removing malicious ones.
func cleanAttributes(a []parser.Attribute, allowed []string) []parser.Attribute {
	if len(a) == 0 {
		return a
	}

	var cleaned []parser.Attribute
	for _, attr := range a {
		if includes(allowed, attr.Key) {

			val := strings.ToLower(attr.Val)

			// Check for illegal attribute values
			if illegalAttr.FindString(val) != "" {
				attr.Val = ""
			}

			// Check for legal href values - / mailto:// http:// or https://
			if attr.Key == "href" {
				if legalHrefAttr.FindString(val) == "" {
					attr.Val = ""
				}
			}

			// If we still have an attribute, append it to the array
			if attr.Val != "" {
				cleaned = append(cleaned, attr)
			}
		}
	}
	return cleaned
}

// A list of characters we consider separators in normal strings and replace with our canonical separator - rather than removing.
var (
	separators = regexp.MustCompile(`[ &_=+:]`)

	dashes = regexp.MustCompile(`[\-]+`)
)

// cleanString replaces separators with - and removes characters listed in the regexp provided from string.
// Accents, spaces, and all characters not in A-Za-z0-9 are replaced.
func cleanString(s string, r *regexp.Regexp) string {

	// Remove any trailing space to avoid ending on -
	s = strings.Trim(s, " ")

	// Flatten accents first so that if we remove non-ascii we still get a legible name
	s = Accents(s)

	// Replace certain joining characters with a dash
	s = separators.ReplaceAllString(s, "-")

	// Remove all other unrecognised characters - NB we do allow any printable characters
	s = r.ReplaceAllString(s, "")

	// Remove any multiple dashes caused by replacements above
	s = dashes.ReplaceAllString(s, "-")

	return s
}

// includes checks for inclusion of a string in a []string.
func includes(a []string, s string) bool {
	for _, as := range a {
		if as == s {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// Package log provides functionality for configuring logging facilities.
package log

import (
	"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
)

// Event is used to group entries.  Each group can be toggled on or off.
type Event = log.Event

const (
	// EventRequest entries contain information about HTTP requests.
	// This includes information like the URL, query parameters, and headers.
	EventRequest = log.EventRequest

	// EventResponse entries contain information about HTTP responses.
	// This includes information like the HTTP status code, headers, and request URL.
	EventResponse = log.EventResponse

	// EventRetryPolicy entries contain information specific to the retry policy in use.
	EventRetryPolicy = log.EventRetryPolicy

	// EventLRO entries contain information specific to long-running operations.
	// This includes information like polling location, operation state and sleep intervals.
	EventLRO = log.EventLRO
)

// SetEvents is used to control which events are written to
// the log.  By default all log events are writen.
// NOTE: this is not goroutine safe and should be called before using SDK clients.
func SetEvents(cls ...Event) {
	log.SetEvents(cls...)
}

// SetListener will set the Logger to write to the specified Listener.
// NOTE: this is not goroutine safe and should be called before using SDK clients.
func SetListener(lst func(Event, string)) {
	log.SetListener(lst)
}

// for testing purposes
func resetEvents() {
	log.TestResetEvents()
}
<commit_msg>Define log constants in the log package (#17730)<commit_after>//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// Package log provides functionality for configuring logging facilities.
package log

import (
	"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
)

// Event is used to group entries.  Each group can be toggled on or off.
type Event = log.Event

const (
	// EventRequest entries contain information about HTTP requests.
	// This includes information like the URL, query parameters, and headers.
	EventRequest Event = "Request"

	// EventResponse entries contain information about HTTP responses.
	// This includes information like the HTTP status code, headers, and request URL.
	EventResponse Event = "Response"

	// EventRetryPolicy entries contain information specific to the retry policy in use.
	EventRetryPolicy Event = "Retry"

	// EventLRO entries contain information specific to long-running operations.
	// This includes information like polling location, operation state, and sleep intervals.
	EventLRO Event = "LongRunningOperation"
)

// SetEvents is used to control which events are written to
// the log.  By default all log events are writen.
// NOTE: this is not goroutine safe and should be called before using SDK clients.
func SetEvents(cls ...Event) {
	log.SetEvents(cls...)
}

// SetListener will set the Logger to write to the specified Listener.
// NOTE: this is not goroutine safe and should be called before using SDK clients.
func SetListener(lst func(Event, string)) {
	log.SetListener(lst)
}

// for testing purposes
func resetEvents() {
	log.TestResetEvents()
}
<|endoftext|>


<commit_before>package ackhandler

import (
	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/qerr"
	"github.com/lucas-clemente/quic-go/internal/utils"
	"github.com/lucas-clemente/quic-go/internal/wire"
)

// The receivedPacketHistory stores if a packet number has already been received.
// It generates ACK ranges which can be used to assemble an ACK frame.
// It does not store packet contents.
type receivedPacketHistory struct {
	ranges *utils.PacketIntervalList

	lowestInReceivedPacketNumbers protocol.PacketNumber
}

var errTooManyOutstandingReceivedAckRanges = qerr.Error(qerr.InternalError, "Too many outstanding received ACK ranges")

// newReceivedPacketHistory creates a new received packet history
func newReceivedPacketHistory() *receivedPacketHistory {
	return &receivedPacketHistory{
		ranges: utils.NewPacketIntervalList(),
	}
}

// ReceivedPacket registers a packet with PacketNumber p and updates the ranges
func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) error {
	if h.ranges.Len() >= protocol.MaxTrackedReceivedAckRanges {
		return errTooManyOutstandingReceivedAckRanges
	}

	if h.ranges.Len() == 0 {
		h.ranges.PushBack(utils.PacketInterval{Start: p, End: p})
		return nil
	}

	for el := h.ranges.Back(); el != nil; el = el.Prev() {
		// p already included in an existing range. Nothing to do here
		if p >= el.Value.Start && p <= el.Value.End {
			return nil
		}

		var rangeExtended bool
		if el.Value.End == p-1 { // extend a range at the end
			rangeExtended = true
			el.Value.End = p
		} else if el.Value.Start == p+1 { // extend a range at the beginning
			rangeExtended = true
			el.Value.Start = p
		}

		// if a range was extended (either at the beginning or at the end, maybe it is possible to merge two ranges into one)
		if rangeExtended {
			prev := el.Prev()
			if prev != nil && prev.Value.End+1 == el.Value.Start { // merge two ranges
				prev.Value.End = el.Value.End
				h.ranges.Remove(el)
				return nil
			}
			return nil // if the two ranges were not merge, we're done here
		}

		// create a new range at the end
		if p > el.Value.End {
			h.ranges.InsertAfter(utils.PacketInterval{Start: p, End: p}, el)
			return nil
		}
	}

	// create a new range at the beginning
	h.ranges.InsertBefore(utils.PacketInterval{Start: p, End: p}, h.ranges.Front())

	return nil
}

// DeleteBelow deletes all entries below (but not including) p
func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) {
	if p <= h.lowestInReceivedPacketNumbers {
		return
	}
	h.lowestInReceivedPacketNumbers = p

	nextEl := h.ranges.Front()
	for el := h.ranges.Front(); nextEl != nil; el = nextEl {
		nextEl = el.Next()

		if p > el.Value.Start && p <= el.Value.End {
			el.Value.Start = p
		} else if el.Value.End < p { // delete a whole range
			h.ranges.Remove(el)
		} else { // no ranges affected. Nothing to do
			return
		}
	}
}

// GetAckRanges gets a slice of all AckRanges that can be used in an AckFrame
func (h *receivedPacketHistory) GetAckRanges() []wire.AckRange {
	if h.ranges.Len() == 0 {
		return nil
	}

	ackRanges := make([]wire.AckRange, h.ranges.Len())
	i := 0
	for el := h.ranges.Back(); el != nil; el = el.Prev() {
		ackRanges[i] = wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End}
		i++
	}
	return ackRanges
}

func (h *receivedPacketHistory) GetHighestAckRange() wire.AckRange {
	ackRange := wire.AckRange{}
	if h.ranges.Len() > 0 {
		r := h.ranges.Back().Value
		ackRange.Smallest = r.Start
		ackRange.Largest = r.End
	}
	return ackRange
}
<commit_msg>optimize deleting of ACK ranges<commit_after>package ackhandler

import (
	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/qerr"
	"github.com/lucas-clemente/quic-go/internal/utils"
	"github.com/lucas-clemente/quic-go/internal/wire"
)

// The receivedPacketHistory stores if a packet number has already been received.
// It generates ACK ranges which can be used to assemble an ACK frame.
// It does not store packet contents.
type receivedPacketHistory struct {
	ranges *utils.PacketIntervalList

	lowestInReceivedPacketNumbers protocol.PacketNumber
}

var errTooManyOutstandingReceivedAckRanges = qerr.Error(qerr.InternalError, "Too many outstanding received ACK ranges")

// newReceivedPacketHistory creates a new received packet history
func newReceivedPacketHistory() *receivedPacketHistory {
	return &receivedPacketHistory{
		ranges: utils.NewPacketIntervalList(),
	}
}

// ReceivedPacket registers a packet with PacketNumber p and updates the ranges
func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) error {
	if h.ranges.Len() >= protocol.MaxTrackedReceivedAckRanges {
		return errTooManyOutstandingReceivedAckRanges
	}

	if h.ranges.Len() == 0 {
		h.ranges.PushBack(utils.PacketInterval{Start: p, End: p})
		return nil
	}

	for el := h.ranges.Back(); el != nil; el = el.Prev() {
		// p already included in an existing range. Nothing to do here
		if p >= el.Value.Start && p <= el.Value.End {
			return nil
		}

		var rangeExtended bool
		if el.Value.End == p-1 { // extend a range at the end
			rangeExtended = true
			el.Value.End = p
		} else if el.Value.Start == p+1 { // extend a range at the beginning
			rangeExtended = true
			el.Value.Start = p
		}

		// if a range was extended (either at the beginning or at the end, maybe it is possible to merge two ranges into one)
		if rangeExtended {
			prev := el.Prev()
			if prev != nil && prev.Value.End+1 == el.Value.Start { // merge two ranges
				prev.Value.End = el.Value.End
				h.ranges.Remove(el)
				return nil
			}
			return nil // if the two ranges were not merge, we're done here
		}

		// create a new range at the end
		if p > el.Value.End {
			h.ranges.InsertAfter(utils.PacketInterval{Start: p, End: p}, el)
			return nil
		}
	}

	// create a new range at the beginning
	h.ranges.InsertBefore(utils.PacketInterval{Start: p, End: p}, h.ranges.Front())

	return nil
}

// DeleteBelow deletes all entries below (but not including) p
func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) {
	if p <= h.lowestInReceivedPacketNumbers {
		return
	}
	h.lowestInReceivedPacketNumbers = p

	nextEl := h.ranges.Front()
	for el := h.ranges.Front(); nextEl != nil; el = nextEl {
		nextEl = el.Next()

		if el.Value.End < p { // delete a whole range
			h.ranges.Remove(el)
		} else if p > el.Value.Start && p <= el.Value.End {
			el.Value.Start = p
			return
		} else { // no ranges affected. Nothing to do
			return
		}
	}
}

// GetAckRanges gets a slice of all AckRanges that can be used in an AckFrame
func (h *receivedPacketHistory) GetAckRanges() []wire.AckRange {
	if h.ranges.Len() == 0 {
		return nil
	}

	ackRanges := make([]wire.AckRange, h.ranges.Len())
	i := 0
	for el := h.ranges.Back(); el != nil; el = el.Prev() {
		ackRanges[i] = wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End}
		i++
	}
	return ackRanges
}

func (h *receivedPacketHistory) GetHighestAckRange() wire.AckRange {
	ackRange := wire.AckRange{}
	if h.ranges.Len() > 0 {
		r := h.ranges.Back().Value
		ackRange.Smallest = r.Start
		ackRange.Largest = r.End
	}
	return ackRange
}
<|endoftext|>


<commit_before>package column

import (
	"fmt"
	"reflect"
	"time"

	"github.com/kshvakov/clickhouse/lib/binary"
)

type Nullable struct {
	base
	column Column
}

func (null *Nullable) ScanType() reflect.Type {
	return null.column.ScanType()
}

func (null *Nullable) Read(decoder *binary.Decoder) (interface{}, error) {
	return null.column.Read(decoder)
}

func (null *Nullable) Write(encoder *binary.Encoder, v interface{}) error {
	return nil
}

func (null *Nullable) ReadNull(decoder *binary.Decoder, rows int) (_ []interface{}, err error) {
	var (
		isNull byte
		value  interface{}
		nulls  = make([]byte, rows)
		values = make([]interface{}, rows)
	)
	for i := 0; i < rows; i++ {
		if isNull, err = decoder.ReadByte(); err != nil {
			return nil, err
		}
		nulls[i] = isNull
	}
	for i, isNull := range nulls {
		switch value, err = null.column.Read(decoder); true {
		case err != nil:
			return nil, err
		case isNull == 0:
			values[i] = value
		default:
			values[i] = nil
		}
	}
	return values, nil
}
func (null *Nullable) WriteNull(nulls, encoder *binary.Encoder, v interface{}) error {
	if v == nil {
		if _, err := nulls.Write([]byte{1}); err != nil {
			return err
		}
		return null.column.Write(encoder, null.column.defaultValue())
	}
	if _, err := nulls.Write([]byte{0}); err != nil {
		return err
	}
	return null.column.Write(encoder, v)
}

func parseNullable(name, chType string, timezone *time.Location) (*Nullable, error) {
	if len(chType) < 14 {
		return nil, fmt.Errorf("invalid Nullable column type: %s", chType)
	}
	column, err := Factory(name, chType[9:][:len(chType)-10], timezone)
	if err != nil {
		return nil, fmt.Errorf("Nullable(T): %v", err)
	}
	return &Nullable{
		base: base{
			name:   name,
			chType: chType,
		},
		column: column,
	}, nil
}
<commit_msg>use reflection to check for nil<commit_after>package column

import (
	"fmt"
	"reflect"
	"time"

	"github.com/kshvakov/clickhouse/lib/binary"
)

type Nullable struct {
	base
	column Column
}

func (null *Nullable) ScanType() reflect.Type {
	return null.column.ScanType()
}

func (null *Nullable) Read(decoder *binary.Decoder) (interface{}, error) {
	return null.column.Read(decoder)
}

func (null *Nullable) Write(encoder *binary.Encoder, v interface{}) error {
	return nil
}

func (null *Nullable) ReadNull(decoder *binary.Decoder, rows int) (_ []interface{}, err error) {
	var (
		isNull byte
		value  interface{}
		nulls  = make([]byte, rows)
		values = make([]interface{}, rows)
	)
	for i := 0; i < rows; i++ {
		if isNull, err = decoder.ReadByte(); err != nil {
			return nil, err
		}
		nulls[i] = isNull
	}
	for i, isNull := range nulls {
		switch value, err = null.column.Read(decoder); true {
		case err != nil:
			return nil, err
		case isNull == 0:
			values[i] = value
		default:
			values[i] = nil
		}
	}
	return values, nil
}
func (null *Nullable) WriteNull(nulls, encoder *binary.Encoder, v interface{}) error {
	if v == nil || reflect.ValueOf(v).IsNil() {
		if _, err := nulls.Write([]byte{1}); err != nil {
			return err
		}
		return null.column.Write(encoder, null.column.defaultValue())
	}
	if _, err := nulls.Write([]byte{0}); err != nil {
		return err
	}
	return null.column.Write(encoder, v)
}

func parseNullable(name, chType string, timezone *time.Location) (*Nullable, error) {
	if len(chType) < 14 {
		return nil, fmt.Errorf("invalid Nullable column type: %s", chType)
	}
	column, err := Factory(name, chType[9:][:len(chType)-10], timezone)
	if err != nil {
		return nil, fmt.Errorf("Nullable(T): %v", err)
	}
	return &Nullable{
		base: base{
			name:   name,
			chType: chType,
		},
		column: column,
	}, nil
}
<|endoftext|>


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

package src

import (
	"bytes"
	"errors"
	"testing"
)

func TestIgnoreWhitespaces(t *testing.T) {
	buf := bytes.NewBufferString("     x")
	scan := newScanner(buf)
	if err := scan.ignoreWhitespaces(); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if c := scan.buf[scan.pos:]; len(c) != 1 || c[0] != 'x' {
		t.Errorf("scan.ignoreWhitespace: found '%s', expected 'x'", c)
	}
}

func TestIsWhitespace(t *testing.T) {
	ws := []byte{' ', '\n', '\t', '\r'}
	for _, c := range ws {
		if !isWhitespace(c) {
			t.Errorf("'%s' should be considered as a whitespace", c)
		}
	}

	nows := []byte{'a', ',', ';', ':', '0', '\v'}
	for _, c := range nows {
		if isWhitespace(c) {
			t.Errorf("'%s' should not be considered as a whitespace", c)
		}
	}
}

func TestIsDigit(t *testing.T) {
	digits := []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
	for _, c := range digits {
		if !isDigit(c) {
			t.Errorf("'%s' should be considered as a digit", c)
		}
	}

	var c byte
	for c = 'a'; c <= 'z'; c++ {
		if isDigit(c) {
			t.Errorf("'%s' should not be considered as a digit", c)
		}
	}
}

func TestNextKey(t *testing.T) {
	validKeys := []string{
		`"foo":`,
		`"foo"  :`,
	}
	for _, keyInput := range validKeys {
		buf := bytes.NewBufferString(keyInput)
		scan := newScanner(buf)
		key, err := scan.nextKey()
		if err != nil {
			t.Error(err)
		}
		if key != "foo" {
			t.Errorf("nextKey: found '%s', expected 'foo'", key)
		}
	}

	invalidKeys := map[string]error{
		`"foo"`: errors.New("expected ':', found EOF"),
		`"foo`:  errors.New("expected key, found EOF"),
		`foo`:   errors.New("expected '\"', found 'f'"),
	}
	for keyInput, expectedErr := range invalidKeys {
		buf := bytes.NewBufferString(keyInput)
		scan := newScanner(buf)
		_, err := scan.nextKey()
		if err == nil {
			t.Error("nextKey: '%s' is expected to return the error '%v'", keyInput, expectedErr)
			continue
		}
		if err.Error() != expectedErr.Error() {
			t.Errorf("nextKey: found error \"%v\", expected error \"%v\"", err, expectedErr)
		}
	}
}
<commit_msg>src/scanner: add one more test case<commit_after>// Copyright 2014-2015 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package src

import (
	"bytes"
	"errors"
	"testing"
)

func TestIgnoreWhitespaces(t *testing.T) {
	buf := bytes.NewBufferString("     x")
	scan := newScanner(buf)
	if err := scan.ignoreWhitespaces(); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if c := scan.buf[scan.pos:]; len(c) != 1 || c[0] != 'x' {
		t.Errorf("scan.ignoreWhitespace: found '%s', expected 'x'", c)
	}
}

func TestIsWhitespace(t *testing.T) {
	ws := []byte{' ', '\n', '\t', '\r'}
	for _, c := range ws {
		if !isWhitespace(c) {
			t.Errorf("'%s' should be considered as a whitespace", c)
		}
	}

	nows := []byte{'a', ',', ';', ':', '0', '\v'}
	for _, c := range nows {
		if isWhitespace(c) {
			t.Errorf("'%s' should not be considered as a whitespace", c)
		}
	}
}

func TestIsDigit(t *testing.T) {
	digits := []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
	for _, c := range digits {
		if !isDigit(c) {
			t.Errorf("'%s' should be considered as a digit", c)
		}
	}

	var c byte
	for c = 'a'; c <= 'z'; c++ {
		if isDigit(c) {
			t.Errorf("'%s' should not be considered as a digit", c)
		}
	}
}

func TestNextKey(t *testing.T) {
	validKeys := []string{
		`"foo":`,
		`"foo"  :`,
		`"foo": "bar"`,
	}
	for _, keyInput := range validKeys {
		buf := bytes.NewBufferString(keyInput)
		scan := newScanner(buf)
		key, err := scan.nextKey()
		if err != nil {
			t.Error(err)
		}
		if key != "foo" {
			t.Errorf("nextKey: found '%s', expected 'foo'", key)
		}
	}

	invalidKeys := map[string]error{
		`"foo"`: errors.New("expected ':', found EOF"),
		`"foo`:  errors.New("expected key, found EOF"),
		`foo`:   errors.New("expected '\"', found 'f'"),
	}
	for keyInput, expectedErr := range invalidKeys {
		buf := bytes.NewBufferString(keyInput)
		scan := newScanner(buf)
		_, err := scan.nextKey()
		if err == nil {
			t.Error("nextKey: '%s' is expected to return the error '%v'", keyInput, expectedErr)
			continue
		}
		if err.Error() != expectedErr.Error() {
			t.Errorf("nextKey: found error \"%v\", expected error \"%v\"", err, expectedErr)
		}
	}
}
<|endoftext|>


<commit_before>package message

import (
	"GoOnchain/common"
	. "GoOnchain/net/protocol"
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"net"
	"strconv"
	"unsafe"
)

type addrReq struct {
	Hdr msgHdr
	// No payload
}

type addr struct {
	hdr       msgHdr
	nodeCnt   uint64
	nodeAddrs []NodeAddr
}

const (
	NODEADDRSIZE = 30
)

func newGetAddr() ([]byte, error) {
	var msg addrReq
	// Fixme the check is the []byte{0} instead of 0
	var sum []byte
	sum = []byte{0x5d, 0xf6, 0xe0, 0xe2}
	msg.Hdr.init("getaddr", sum, 0)

	buf, err := msg.Serialization()
	if err != nil {
		return nil, err
	}

	str := hex.EncodeToString(buf)
	fmt.Printf("The message get addr length is %d, %s\n", len(buf), str)

	return buf, err
}

func NewAddrs(nodeaddrs []NodeAddr, count uint64) ([]byte, error) {
	var msg addr
	msg.nodeAddrs = nodeaddrs
	msg.nodeCnt = count
	msg.hdr.Magic = NETMAGIC
	cmd := "addr"
	copy(msg.hdr.CMD[0:7], cmd)
	p := new(bytes.Buffer)
	err := binary.Write(p, binary.LittleEndian, msg.nodeCnt)
	if err != nil {
		fmt.Println("Binary Write failed at new Msg")
		return nil, err
	}

	err = binary.Write(p, binary.LittleEndian, msg.nodeAddrs)
	if err != nil {
		fmt.Println("Binary Write failed at new Msg")
		return nil, err
	}
	s := sha256.Sum256(p.Bytes())
	s2 := s[:]
	s = sha256.Sum256(s2)
	buf := bytes.NewBuffer(s[:4])
	binary.Read(buf, binary.LittleEndian, &(msg.hdr.Checksum))
	msg.hdr.Length = uint32(len(p.Bytes()))
	fmt.Printf("The message payload length is %d\n", msg.hdr.Length)

	m, err := msg.Serialization()
	if err != nil {
		fmt.Println("Error Convert net message ", err.Error())
		return nil, err
	}

	str := hex.EncodeToString(m)
	fmt.Printf("The message length is %d, %s\n", len(m), str)
	return m, nil
}

func (msg addrReq) Verify(buf []byte) error {
	// TODO Verify the message Content
	err := msg.Hdr.Verify(buf)
	return err
}

func (msg addrReq) Handle(node Noder) error {
	common.Trace()
	// lock
	var addrstr []NodeAddr
	var count uint64
	addrstr, count = node.LocalNode().GetNeighborAddrs()
	buf, _ := NewAddrs(addrstr, count)
	go node.Tx(buf)
	return nil
}

func (msg addrReq) Serialization() ([]byte, error) {
	var buf bytes.Buffer

	fmt.Printf("The size of messge is %d in serialization\n",
		uint32(unsafe.Sizeof(msg)))
	err := binary.Write(&buf, binary.LittleEndian, msg)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), err
}

func (msg *addrReq) Deserialization(p []byte) error {
	fmt.Printf("The size of messge is %d in deserialization\n",
		uint32(unsafe.Sizeof(*msg)))

	buf := bytes.NewBuffer(p)
	err := binary.Read(buf, binary.LittleEndian, msg)
	return err
}

func (msg addr) Serialization() ([]byte, error) {
	var buf bytes.Buffer
	err := binary.Write(&buf, binary.LittleEndian, msg.hdr)

	if err != nil {
		return nil, err
	}
	err = binary.Write(&buf, binary.LittleEndian, msg.nodeCnt)
	if err != nil {
		return nil, err
	}
	for _, v := range msg.nodeAddrs {
		//err = binary.Write(&buf, binary.LittleEndian, v.Serialization)
		err = binary.Write(&buf, binary.LittleEndian, v)
		if err != nil {
			return nil, err
		}
	}

	return buf.Bytes(), err
}

func (msg *addr) Deserialization(p []byte) error {
	fmt.Printf("The size of messge is %d in deserialization\n",
		uint32(unsafe.Sizeof(*msg)))

	buf := bytes.NewBuffer(p)
	err := binary.Read(buf, binary.LittleEndian, &(msg.hdr))
	//err := msg.hdr.Deserialization(p)
	err = binary.Read(buf, binary.LittleEndian, &(msg.nodeCnt))
	//err = binary.Read(p[MSGHDRLEN:p[MSGHDRLEN + 8], binary.LittleEndian, &cnt)
	fmt.Printf("The address count is %d \n", msg.nodeCnt)
	msg.nodeAddrs = make([]NodeAddr, msg.nodeCnt)
	for i := 0; i < int(msg.nodeCnt); i++ {
		err := binary.Read(buf, binary.LittleEndian, &(msg.nodeAddrs[i]))
		if err != nil {
			goto err
		}
	}
err:
	return err
}

func (msg addr) Verify(buf []byte) error {
	err := msg.hdr.Verify(buf)
	// TODO Verify the message Content, check the ipaddr number
	return err
}

func (msg addr) Handle(node Noder) error {
	common.Trace()
	for _, v := range msg.nodeAddrs {
		if v.Port != 0 {
			var ip net.IP
			ip = v.IpAddr[:]
			// Fixme consider the IPv6 case
			address := ip.To4().String() + ":" + strconv.Itoa(int(v.Port))
			fmt.Printf("The ip address is %s\n", address)
			go node.Connect(address)
		}
	}
	return nil
}
<commit_msg>Always trigger the connect from local node<commit_after>package message

import (
	"GoOnchain/common"
	. "GoOnchain/net/protocol"
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"net"
	"strconv"
	"unsafe"
)

type addrReq struct {
	Hdr msgHdr
	// No payload
}

type addr struct {
	hdr       msgHdr
	nodeCnt   uint64
	nodeAddrs []NodeAddr
}

const (
	NODEADDRSIZE = 30
)

func newGetAddr() ([]byte, error) {
	var msg addrReq
	// Fixme the check is the []byte{0} instead of 0
	var sum []byte
	sum = []byte{0x5d, 0xf6, 0xe0, 0xe2}
	msg.Hdr.init("getaddr", sum, 0)

	buf, err := msg.Serialization()
	if err != nil {
		return nil, err
	}

	str := hex.EncodeToString(buf)
	fmt.Printf("The message get addr length is %d, %s\n", len(buf), str)

	return buf, err
}

func NewAddrs(nodeaddrs []NodeAddr, count uint64) ([]byte, error) {
	var msg addr
	msg.nodeAddrs = nodeaddrs
	msg.nodeCnt = count
	msg.hdr.Magic = NETMAGIC
	cmd := "addr"
	copy(msg.hdr.CMD[0:7], cmd)
	p := new(bytes.Buffer)
	err := binary.Write(p, binary.LittleEndian, msg.nodeCnt)
	if err != nil {
		fmt.Println("Binary Write failed at new Msg")
		return nil, err
	}

	err = binary.Write(p, binary.LittleEndian, msg.nodeAddrs)
	if err != nil {
		fmt.Println("Binary Write failed at new Msg")
		return nil, err
	}
	s := sha256.Sum256(p.Bytes())
	s2 := s[:]
	s = sha256.Sum256(s2)
	buf := bytes.NewBuffer(s[:4])
	binary.Read(buf, binary.LittleEndian, &(msg.hdr.Checksum))
	msg.hdr.Length = uint32(len(p.Bytes()))
	fmt.Printf("The message payload length is %d\n", msg.hdr.Length)

	m, err := msg.Serialization()
	if err != nil {
		fmt.Println("Error Convert net message ", err.Error())
		return nil, err
	}

	str := hex.EncodeToString(m)
	fmt.Printf("The message length is %d, %s\n", len(m), str)
	return m, nil
}

func (msg addrReq) Verify(buf []byte) error {
	// TODO Verify the message Content
	err := msg.Hdr.Verify(buf)
	return err
}

func (msg addrReq) Handle(node Noder) error {
	common.Trace()
	// lock
	var addrstr []NodeAddr
	var count uint64
	addrstr, count = node.LocalNode().GetNeighborAddrs()
	buf, _ := NewAddrs(addrstr, count)
	go node.Tx(buf)
	return nil
}

func (msg addrReq) Serialization() ([]byte, error) {
	var buf bytes.Buffer

	fmt.Printf("The size of messge is %d in serialization\n",
		uint32(unsafe.Sizeof(msg)))
	err := binary.Write(&buf, binary.LittleEndian, msg)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), err
}

func (msg *addrReq) Deserialization(p []byte) error {
	fmt.Printf("The size of messge is %d in deserialization\n",
		uint32(unsafe.Sizeof(*msg)))

	buf := bytes.NewBuffer(p)
	err := binary.Read(buf, binary.LittleEndian, msg)
	return err
}

func (msg addr) Serialization() ([]byte, error) {
	var buf bytes.Buffer
	err := binary.Write(&buf, binary.LittleEndian, msg.hdr)

	if err != nil {
		return nil, err
	}
	err = binary.Write(&buf, binary.LittleEndian, msg.nodeCnt)
	if err != nil {
		return nil, err
	}
	for _, v := range msg.nodeAddrs {
		//err = binary.Write(&buf, binary.LittleEndian, v.Serialization)
		err = binary.Write(&buf, binary.LittleEndian, v)
		if err != nil {
			return nil, err
		}
	}

	return buf.Bytes(), err
}

func (msg *addr) Deserialization(p []byte) error {
	fmt.Printf("The size of messge is %d in deserialization\n",
		uint32(unsafe.Sizeof(*msg)))

	buf := bytes.NewBuffer(p)
	err := binary.Read(buf, binary.LittleEndian, &(msg.hdr))
	//err := msg.hdr.Deserialization(p)
	err = binary.Read(buf, binary.LittleEndian, &(msg.nodeCnt))
	//err = binary.Read(p[MSGHDRLEN:p[MSGHDRLEN + 8], binary.LittleEndian, &cnt)
	fmt.Printf("The address count is %d \n", msg.nodeCnt)
	msg.nodeAddrs = make([]NodeAddr, msg.nodeCnt)
	for i := 0; i < int(msg.nodeCnt); i++ {
		err := binary.Read(buf, binary.LittleEndian, &(msg.nodeAddrs[i]))
		if err != nil {
			goto err
		}
	}
err:
	return err
}

func (msg addr) Verify(buf []byte) error {
	err := msg.hdr.Verify(buf)
	// TODO Verify the message Content, check the ipaddr number
	return err
}

func (msg addr) Handle(node Noder) error {
	common.Trace()
	for _, v := range msg.nodeAddrs {
		if v.Port != 0 {
			var ip net.IP
			ip = v.IpAddr[:]
			// Fixme consider the IPv6 case
			address := ip.To4().String() + ":" + strconv.Itoa(int(v.Port))
			fmt.Printf("The ip address is %s\n", address)
			go node.LocalNode().Connect(address)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package tests

import (
  "github.com/lxfontes/roxter"
  "testing"
)

func Test_Proxy(t *testing.T) {
  p := roxter.NewProxy("127.0.0.1:11211")
  p.MaxIdle = 8
  p.ListenAndServe(":11212")
}
<commit_msg>useless test<commit_after>package tests

import (
  "github.com/lxfontes/roxter"
  "testing"
)

func Test_Proxy(t *testing.T) {
  roxter.NewProxy("127.0.0.1:11211")
}
<|endoftext|>


<commit_before>// sokoban solver, work in progress
package main

import (
	"fmt"
	"github.com/bertbaron/solve"
	"sort"
	"strings"
)

const (
	floor  byte = 0
	wall   byte = 1
	box    byte = 2
	goal   byte = 4
	player byte = 8
)

var chars = map[rune]byte{
	' ': floor,
	'#': wall,
	'$': box,
	'.': goal,
	'@': player,
	'+': player | goal,
	'*': box | goal}

var reverse = map[byte]rune{
	floor:         ' ',
	wall:          '#',
	box:           '$',
	goal:          '.',
	player:        '@',
	player | goal: '+',
	box | goal:    '*'}

type sokoban struct {
	// the static world, without player and boxes
	world []byte
	// sorted list of goal positions
	goals  []uint16
	width  int
	height int
}

type mainstate struct {
	// sorted list of box positions
	boxes    []uint16
	position int
	cost     int
}

func valueOf(s *sokoban, m *mainstate, position int) byte {
	boxidx := sort.Search(len(m.boxes), func(i int) bool { return m.boxes[i] >= uint16(position) })
	var additional byte = 0
	if m.position == position {
		additional |= player
	}
	if boxidx < len(m.boxes) && m.boxes[boxidx] == uint16(position) {
		additional |= box
	}
	return s.world[position] | additional
}

func print(s sokoban, m mainstate) {
	for position := range s.world {
		fmt.Print(string(reverse[valueOf(&s, &m, position)]))
		if position%s.width == s.width-1 {
			fmt.Println()
		}
	}
}

func (s mainstate) Cost(ctx solve.Context) float64 {
	return float64(s.cost)
}

func (s mainstate) Heuristic(ctx solve.Context) float64 {
	return 0
}

func (s mainstate) IsGoal(ctx solve.Context) bool {
	for i, value := range ctx.Custom.(sokoban).goals {
		if s.boxes[i] != value {
			return false
		}
	}
	return true
}

func (s mainstate) Expand(ctx solve.Context) []solve.State {
	var children []solve.State
	return children
}

// -------------- Sub problem for moving the player to all positions in which a box can be moved -----------

type walkcontext struct {
	// the static world, without player but with boxes because we don't move them here
	world []byte
	goalpositions []int
	width int
}

type walkstate struct {
	position int
	cost int
}

func (s walkstate) Cost(ctx solve.Context) float64 {
	return float64(s.cost)
}

func (s walkstate) Heuristic(ctx solve.Context) float64 {
	return 0
}

func (s walkstate) IsGoal(ctx solve.Context) bool {
	wc := ctx.Custom.(walkcontext)
	for _, goal := range wc.goalpositions {
		if s.position == goal {
			return true
		}
	}
	return false
}

func (s walkstate) Expand(ctx solve.Context) []solve.State {
	var children []solve.State
	wc := ctx.Custom.(walkcontext)
	children = s.addIfValid(children, s.position-1, wc)
	children = s.addIfValid(children, s.position+1, wc)
	children = s.addIfValid(children, s.position-wc.width, wc)
	children = s.addIfValid(children, s.position+wc.width, wc)
	return children
}

func (s walkstate) addIfValid(children []solve.State, newPosition int, wc walkcontext) []solve.State {
	if wc.world[newPosition] & (wall | box) == 0 {
		return append(children, walkstate{newPosition, s.cost + 1})
	}
	return children
}

func parse(level string) (sokoban, mainstate) {
	width := 0
	lines := strings.Split(level, "\n")
	height := len(lines)
	for _, line := range lines {
		if len(line) > width {
			width = len(line)
		}
	}
	var c sokoban
	var s mainstate
	c.width = width
	c.height = height

	c.world = make([]byte, width*height)
	c.goals = make([]uint16, 0)
	s.boxes = make([]uint16, 0)
	for y, row := range lines {
		for x, raw := range row {
			position := y*width + x
			if value, ok := chars[raw]; ok {
				c.world[position] = value &^ player &^ box
				if value&player != 0 {
					s.position = position
				}
				if value&goal != 0 {
					c.goals = append(c.goals, uint16(position))
				}
				if value&box != 0 {
					s.boxes = append(s.boxes, uint16(position))
				}
			} else {
				panic(fmt.Sprintf("Invalid level format, character %v is not valid", value))
			}
		}
	}
	return c, s
}

var level = `
   ####
####  ##
#   $  #
#  *** #
#  . . ##
## * *  #
 ##***  #
  # $ ###
  # @ #
  #####`

func main() {
	world, root := parse(level)
	print(world, root)
	result := solve.NewSolver(root).
		Context(world).
		Algorithm(solve.IDAstar).
		Solve()
	fmt.Printf("Result: %v\n ", result.Solution)
}
<commit_msg>Sokoban example<commit_after>// sokoban solver, work in progress
package main

import (
	"fmt"
	"github.com/bertbaron/solve"
	"sort"
	"strings"
)

const (
	floor  byte = 0
	wall   byte = 1
	box    byte = 2
	goal   byte = 4
	player byte = 8
)

var chars = map[rune]byte{
	' ': floor,
	'#': wall,
	'$': box,
	'.': goal,
	'@': player,
	'+': player | goal,
	'*': box | goal}

var reverse = map[byte]rune{
	floor:         ' ',
	wall:          '#',
	box:           '$',
	goal:          '.',
	player:        '@',
	player | goal: '+',
	box | goal:    '*'}

// -------- main problem. We only expose the states in which a block is pushed though to limit the search space
//          for the main search.
type sokoban struct {
	// the static world, without player and boxes
	world []byte
	// sorted list of goal positions
	goals  []uint16
	width  int
	height int
}

type mainstate struct {
	// sorted list of box positions
	boxes    []uint16
	position int
	cost     int
}

func valueOf(s *sokoban, m *mainstate, position int) byte {
	boxidx := sort.Search(len(m.boxes), func(i int) bool { return m.boxes[i] >= uint16(position) })
	var additional byte = 0
	if m.position == position {
		additional |= player
	}
	if boxidx < len(m.boxes) && m.boxes[boxidx] == uint16(position) {
		additional |= box
	}
	return s.world[position] | additional
}

func print(s sokoban, m mainstate) {
	for position := range s.world {
		fmt.Print(string(reverse[valueOf(&s, &m, position)]))
		if position%s.width == s.width-1 {
			fmt.Println()
		}
	}
}

func (s mainstate) Cost(ctx solve.Context) float64 {
	return float64(s.cost)
}

func (s mainstate) Heuristic(ctx solve.Context) float64 {
	return 0
}

func (s mainstate) IsGoal(ctx solve.Context) bool {
	for i, value := range ctx.Custom.(sokoban).goals {
		if s.boxes[i] != value {
			return false
		}
	}
	return true
}

func (s mainstate) Expand(ctx solve.Context) []solve.State {
	var children []solve.State
	return children
}

// -------------- Sub problem for moving the player to all positions in which a box can be moved -----------

type walkcontext struct {
	// the static world, without player but with boxes because we don't move them here
	world []byte
	goalpositions []int
	width int
}

type walkstate struct {
	position int
	cost int
}

func (s walkstate) Cost(ctx solve.Context) float64 {
	return float64(s.cost)
}

func (s walkstate) Heuristic(ctx solve.Context) float64 {
	return 0
}

func (s walkstate) IsGoal(ctx solve.Context) bool {
	wc := ctx.Custom.(walkcontext)
	for _, goal := range wc.goalpositions {
		if s.position == goal {
			return true
		}
	}
	return false
}

func (s walkstate) Expand(ctx solve.Context) []solve.State {
	var children []solve.State
	wc := ctx.Custom.(walkcontext)
	children = s.addIfValid(children, s.position-1, wc)
	children = s.addIfValid(children, s.position+1, wc)
	children = s.addIfValid(children, s.position-wc.width, wc)
	children = s.addIfValid(children, s.position+wc.width, wc)
	return children
}

func (s walkstate) addIfValid(children []solve.State, newPosition int, wc walkcontext) []solve.State {
	if wc.world[newPosition] & (wall | box) == 0 {
		return append(children, walkstate{newPosition, s.cost + 1})
	}
	return children
}

func parse(level string) (sokoban, mainstate) {
	width := 0
	lines := strings.Split(level, "\n")
	height := len(lines)
	for _, line := range lines {
		if len(line) > width {
			width = len(line)
		}
	}
	var c sokoban
	var s mainstate
	c.width = width
	c.height = height

	c.world = make([]byte, width*height)
	c.goals = make([]uint16, 0)
	s.boxes = make([]uint16, 0)
	for y, row := range lines {
		for x, raw := range row {
			position := y*width + x
			if value, ok := chars[raw]; ok {
				c.world[position] = value &^ player &^ box
				if value&player != 0 {
					s.position = position
				}
				if value&goal != 0 {
					c.goals = append(c.goals, uint16(position))
				}
				if value&box != 0 {
					s.boxes = append(s.boxes, uint16(position))
				}
			} else {
				panic(fmt.Sprintf("Invalid level format, character %v is not valid", value))
			}
		}
	}
	return c, s
}

var level = `
   ####
####  ##
#   $  #
#  *** #
#  . . ##
## * *  #
 ##***  #
  # $ ###
  # @ #
  #####`

func main() {
	world, root := parse(level)
	print(world, root)
	result := solve.NewSolver(root).
		Context(world).
		Algorithm(solve.IDAstar).
		Solve()
	fmt.Printf("Result: %v\n ", result.Solution)
}
<|endoftext|>


<commit_before>package slack

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"hash"
	"net/http"
)

// SecretsVerifier contains the information needed to verify that the request comes from Slack
type SecretsVerifier struct {
	slackSig  string
	timeStamp string
	hmac      hash.Hash
}

// NewSecretsVerifier returns a SecretsVerifier object in exchange for an http.Header object and signing secret
func NewSecretsVerifier(header http.Header, signingSecret string) (SecretsVerifier, error) {
	if header["X-Slack-Signature"][0] == "" || header["X-Slack-Request-Timestamp"][0] == "" {
		return SecretsVerifier{}, errors.New("headers are empty, cannot create SecretsVerifier")
	}

	hash := hmac.New(sha256.New, []byte(signingSecret))
	hash.Write([]byte(fmt.Sprintf("v0:%s:", header["X-Slack-Request-Timestamp"][0])))
	return SecretsVerifier{
		slackSig:  header["X-Slack-Signature"][0],
		timeStamp: header["X-Slack-Request-Timestamp"][0],
		hmac:      hash,
	}, nil
}

func (v *SecretsVerifier) Write(body []byte) (n int, err error) {
	return v.hmac.Write(body)
}

// Ensure compares the signature sent from Slack with the actual computed hash to judge validity
func (v SecretsVerifier) Ensure(signingSecret string) error {
	computed := "v0=" + string(hex.EncodeToString(v.hmac.Sum(nil)))
	if computed == v.slackSig {
		return nil
	}

	return fmt.Errorf("invalid request verification token %s, expected %s", v.slackSig, computed)
}
<commit_msg>remove unnecesary argument<commit_after>package slack

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"hash"
	"net/http"
)

// SecretsVerifier contains the information needed to verify that the request comes from Slack
type SecretsVerifier struct {
	slackSig  string
	timeStamp string
	hmac      hash.Hash
}

// NewSecretsVerifier returns a SecretsVerifier object in exchange for an http.Header object and signing secret
func NewSecretsVerifier(header http.Header, signingSecret string) (SecretsVerifier, error) {
	if header["X-Slack-Signature"][0] == "" || header["X-Slack-Request-Timestamp"][0] == "" {
		return SecretsVerifier{}, errors.New("headers are empty, cannot create SecretsVerifier")
	}

	hash := hmac.New(sha256.New, []byte(signingSecret))
	hash.Write([]byte(fmt.Sprintf("v0:%s:", header["X-Slack-Request-Timestamp"][0])))
	return SecretsVerifier{
		slackSig:  header["X-Slack-Signature"][0],
		timeStamp: header["X-Slack-Request-Timestamp"][0],
		hmac:      hash,
	}, nil
}

func (v *SecretsVerifier) Write(body []byte) (n int, err error) {
	return v.hmac.Write(body)
}

// Ensure compares the signature sent from Slack with the actual computed hash to judge validity
func (v SecretsVerifier) Ensure() error {
	computed := "v0=" + string(hex.EncodeToString(v.hmac.Sum(nil)))
	if computed == v.slackSig {
		return nil
	}

	return fmt.Errorf("invalid request verification token %s, expected %s", v.slackSig, computed)
}
<|endoftext|>


<commit_before>package mySort_test

import (
	"math/rand"
	"testing"
	"time"

	"github.com/mremond/algos/mySort"
)

// Testing InsertionSort

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

func TestInsertionSortBasic(t *testing.T) {
	// Test with fully reversed list
	list := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
	sortedList := mySort.InsertionSort(list)
	checkOrder(sortedList, t)
}

func benchmarkInsertionSort(i int, b *testing.B) {
	list := buildRandomIntList(i)
	for n := 0; n < b.N; n++ {
		mySort.InsertionSort(list)
	}
}

func BenchmarkInsertionSort10(b *testing.B)     { benchmarkInsertionSort(10, b) }
func BenchmarkInsertionSort100(b *testing.B)    { benchmarkInsertionSort(100, b) }
func BenchmarkInsertionSort1000(b *testing.B)   { benchmarkInsertionSort(1000, b) }
func BenchmarkInsertionSort10000(b *testing.B)  { benchmarkInsertionSort(10000, b) }
func BenchmarkInsertionSort100000(b *testing.B) { benchmarkInsertionSort(100000, b) }

// Helpers

func buildRandomIntList(size int) []int {
	myList := make([]int, size)
	for i := 0; i < size; i++ {
		myList[i] = rand.Int()
	}
	return myList
}

func checkOrder(sortedList []int, t *testing.T) {
	tmp := sortedList[0]
	for i := 1; i < len(sortedList)-2; i++ {
		if sortedList[i] < tmp {
			t.Error("List not sorted:", sortedList[i], "<", tmp)
			//			 break
		}
		tmp = sortedList[i]
	}
}
<commit_msg>Add test with random int list generation<commit_after>package mySort_test

import (
	"math/rand"
	"testing"
	"time"

	"github.com/mremond/algos/mySort"
)

// Testing InsertionSort

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

func TestInsertionSortBasic(t *testing.T) {
	// Test with fully reversed list
	list := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
	checkOrder(mySort.InsertionSort(list), t)
}

func TestInsertionSortRandom(t *testing.T) {
	list := buildRandomIntList(100)
	checkOrder(mySort.InsertionSort(list), t)
}

func benchmarkInsertionSort(i int, b *testing.B) {
	list := buildRandomIntList(i)
	for n := 0; n < b.N; n++ {
		mySort.InsertionSort(list)
	}
}

func BenchmarkInsertionSort10(b *testing.B)     { benchmarkInsertionSort(10, b) }
func BenchmarkInsertionSort100(b *testing.B)    { benchmarkInsertionSort(100, b) }
func BenchmarkInsertionSort1000(b *testing.B)   { benchmarkInsertionSort(1000, b) }
func BenchmarkInsertionSort10000(b *testing.B)  { benchmarkInsertionSort(10000, b) }
func BenchmarkInsertionSort100000(b *testing.B) { benchmarkInsertionSort(100000, b) }

// Helpers

func buildRandomIntList(size int) []int {
	myList := make([]int, size)
	for i := 0; i < size; i++ {
		myList[i] = rand.Int()
	}
	return myList
}

func checkOrder(sortedList []int, t *testing.T) {
	tmp := sortedList[0]
	for i := 1; i < len(sortedList)-2; i++ {
		if sortedList[i] < tmp {
			t.Error("List not sorted:", sortedList[i], "<", tmp)
			//			 break
		}
		tmp = sortedList[i]
	}
}
<|endoftext|>


<commit_before>// Copyright 2016-2020 The grok_exporter 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 exporter

import (
	configuration "github.com/fstab/grok_exporter/config/v3"
	"github.com/fstab/grok_exporter/oniguruma"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_model/go"
	"reflect"
	"testing"
)

func TestCounterVec(t *testing.T) {
	regex := initCounterRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name: "exim_rejected_rcpt_total",
		Labels: map[string]string{
			"error_message": "{{.message}}",
		},
	})
	counter := NewCounterMetric(counterCfg, regex, nil)
	counter.ProcessMatch("some unrelated line", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)
	counter.ProcessMatch("2016-04-26 12:31:39 H=(186-90-8-31.genericrev.cantv.net) [186.90.8.31] F=<Hans.Krause9@cantv.net> rejected RCPT <ug2seeng-admin@example.com>: Unrouteable address", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)

	switch c := counter.Collector().(type) {
	case *prometheus.CounterVec:
		m := io_prometheus_client.Metric{}
		c.WithLabelValues("relay not permitted").Write(&m)
		if *m.Counter.Value != float64(2) {
			t.Errorf("Expected 2 matches, but got %v matches.", *m.Counter.Value)
		}
		c.WithLabelValues("Unrouteable address").Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestCounter(t *testing.T) {
	regex := initCounterRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name: "exim_rejected_rcpt_total",
	})
	counter := NewCounterMetric(counterCfg, regex, nil)

	counter.ProcessMatch("some unrelated line", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)
	counter.ProcessMatch("2016-04-26 12:31:39 H=(186-90-8-31.genericrev.cantv.net) [186.90.8.31] F=<Hans.Krause9@cantv.net> rejected RCPT <ug2seeng-admin@example.com>: Unrouteable address", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)

	switch c := counter.Collector().(type) {
	case prometheus.Counter:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Counter.Value != float64(3) {
			t.Errorf("Expected 3 matches, but got %v matches.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestCounterValue(t *testing.T) {
	regex := initCumulativeRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:       "rainfall",
		Value:      "{{.rainfall}}",
	})
	counter := NewCounterMetric(counterCfg, regex, nil)

	counter.ProcessMatch("Rainfall in Berlin: 32", nil)
	counter.ProcessMatch("Rainfall in Berlin: 5", nil)

	switch c := counter.Collector().(type) {
	case prometheus.Counter:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Counter.Value != float64(37) {
			t.Errorf("Expected 37 as counter value, but got %v.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestLogfileLabel(t *testing.T) {
	regex := initCounterRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name: "exim_rejected_rcpt_total",
		Labels: map[string]string{
			"error_message": "{{.message}}",
			"logfile":       "{{.logfile}}",
		},
	})
	logfile1 := map[string]interface{}{
		"logfile": "/var/log/exim-1.log",
	}
	logfile2 := map[string]interface{}{
		"logfile": "/var/log/exim-2.log",
	}
	counter := NewCounterMetric(counterCfg, regex, nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", logfile1)
	counter.ProcessMatch("2016-04-26 12:31:39 H=(186-90-8-31.genericrev.cantv.net) [186.90.8.31] F=<Hans.Krause9@cantv.net> rejected RCPT <ug2seeng-admin@example.com>: Unrouteable address", logfile1)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", logfile2)

	switch c := counter.Collector().(type) {
	case *prometheus.CounterVec:
		m := io_prometheus_client.Metric{}
		c.With(map[string]string{
			"error_message": "relay not permitted",
			"logfile":       "/var/log/exim-1.log",
		}).Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
		c.With(map[string]string{
			"error_message": "Unrouteable address",
			"logfile":       "/var/log/exim-1.log",
		}).Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
		c.With(map[string]string{
			"error_message": "relay not permitted",
			"logfile":       "/var/log/exim-2.log",
		}).Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func initCounterRegex(t *testing.T) *oniguruma.Regex {
	patterns := loadPatternDir(t)
	err := patterns.AddPattern("EXIM_MESSAGE [a-zA-Z ]*")
	if err != nil {
		t.Error(err)
	}
	regex, err := Compile("%{EXIM_DATE} %{EXIM_REMOTE_HOST} F=<%{EMAILADDRESS}> rejected RCPT <%{EMAILADDRESS}>: %{EXIM_MESSAGE:message}", patterns)
	if err != nil {
		t.Error(err)
	}
	return regex
}

func TestGauge(t *testing.T) {
	regex := initGaugeRegex(t)
	gaugeCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:  "temperature",
		Value: "{{.temperature}}",
	})
	gauge := NewGaugeMetric(gaugeCfg, regex, nil)

	gauge.ProcessMatch("Temperature in Berlin: 32", nil)
	gauge.ProcessMatch("Temperature in Moscow: -5", nil)

	switch c := gauge.Collector().(type) {
	case prometheus.Gauge:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Gauge.Value != float64(-5) {
			t.Errorf("Expected -5 as last observed value, but got %v.", *m.Gauge.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestGaugeCumulative(t *testing.T) {
	regex := initCumulativeRegex(t)
	gaugeCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:       "rainfall",
		Value:      "{{.rainfall}}",
		Cumulative: true,
	})
	gauge := NewGaugeMetric(gaugeCfg, regex, nil)

	gauge.ProcessMatch("Rainfall in Berlin: 32", nil)
	gauge.ProcessMatch("Rainfall in Moscow: 5", nil)

	switch c := gauge.Collector().(type) {
	case prometheus.Gauge:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Gauge.Value != float64(37) {
			t.Errorf("Expected 37 as cumulative value, but got %v.", *m.Gauge.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestGaugeVec(t *testing.T) {
	regex := initGaugeRegex(t)
	gaugeCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:  "temperature",
		Value: "{{.temperature}}",
		Labels: map[string]string{
			"city": "{{.city}}",
		},
	})
	gauge := NewGaugeMetric(gaugeCfg, regex, nil)

	gauge.ProcessMatch("Temperature in Berlin: 32", nil)
	gauge.ProcessMatch("Temperature in Moscow: -5", nil)
	gauge.ProcessMatch("Temperature in Berlin: 31", nil)

	switch c := gauge.Collector().(type) {
	case *prometheus.GaugeVec:
		m := io_prometheus_client.Metric{}
		c.WithLabelValues("Berlin").Write(&m)
		if *m.Gauge.Value != float64(31) {
			t.Errorf("Expected 31 as last observed value in Berlin, but got %v.", *m.Gauge.Value)
		}
		c.WithLabelValues("Moscow").Write(&m)
		if *m.Gauge.Value != float64(-5) {
			t.Errorf("Expected -5 as last observed value in Moscow, but got %v.", *m.Gauge.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func initGaugeRegex(t *testing.T) *oniguruma.Regex {
	patterns := loadPatternDir(t)
	regex, err := Compile("Temperature in %{WORD:city}: %{INT:temperature}", patterns)
	if err != nil {
		t.Error(err)
	}
	return regex
}

func initCumulativeRegex(t *testing.T) *oniguruma.Regex {
	patterns := loadPatternDir(t)
	regex, err := Compile("Rainfall in %{WORD:city}: %{INT:rainfall}", patterns)
	if err != nil {
		t.Error(err)
	}
	return regex
}

func newMetricConfig(t *testing.T, cfg *configuration.MetricConfig) *configuration.MetricConfig {
	// Handle default for counter's value
	if cfg.Type == "counter" && len(cfg.Value) == 0 {
		cfg.Value = "1.0"
	}
	err := cfg.InitTemplates()
	if err != nil {
		t.Fatal(err)
	}
	return cfg
}
<commit_msg>Revert check due to missing configuration parameters<commit_after>// Copyright 2016-2020 The grok_exporter 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 exporter

import (
	configuration "github.com/fstab/grok_exporter/config/v3"
	"github.com/fstab/grok_exporter/oniguruma"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_model/go"
	"reflect"
	"testing"
)

func TestCounterVec(t *testing.T) {
	regex := initCounterRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name: "exim_rejected_rcpt_total",
		Labels: map[string]string{
			"error_message": "{{.message}}",
		},
	})
	counter := NewCounterMetric(counterCfg, regex, nil)
	counter.ProcessMatch("some unrelated line", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)
	counter.ProcessMatch("2016-04-26 12:31:39 H=(186-90-8-31.genericrev.cantv.net) [186.90.8.31] F=<Hans.Krause9@cantv.net> rejected RCPT <ug2seeng-admin@example.com>: Unrouteable address", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)

	switch c := counter.Collector().(type) {
	case *prometheus.CounterVec:
		m := io_prometheus_client.Metric{}
		c.WithLabelValues("relay not permitted").Write(&m)
		if *m.Counter.Value != float64(2) {
			t.Errorf("Expected 2 matches, but got %v matches.", *m.Counter.Value)
		}
		c.WithLabelValues("Unrouteable address").Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestCounter(t *testing.T) {
	regex := initCounterRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name: "exim_rejected_rcpt_total",
	})
	counter := NewCounterMetric(counterCfg, regex, nil)

	counter.ProcessMatch("some unrelated line", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)
	counter.ProcessMatch("2016-04-26 12:31:39 H=(186-90-8-31.genericrev.cantv.net) [186.90.8.31] F=<Hans.Krause9@cantv.net> rejected RCPT <ug2seeng-admin@example.com>: Unrouteable address", nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", nil)

	switch c := counter.Collector().(type) {
	case prometheus.Counter:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Counter.Value != float64(3) {
			t.Errorf("Expected 3 matches, but got %v matches.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestCounterValue(t *testing.T) {
	regex := initCumulativeRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:       "rainfall",
		Value:      "{{.rainfall}}",
	})
	counter := NewCounterMetric(counterCfg, regex, nil)

	counter.ProcessMatch("Rainfall in Berlin: 32", nil)
	counter.ProcessMatch("Rainfall in Berlin: 5", nil)

	switch c := counter.Collector().(type) {
	case prometheus.Counter:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Counter.Value != float64(37) {
			t.Errorf("Expected 37 as counter value, but got %v.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestLogfileLabel(t *testing.T) {
	regex := initCounterRegex(t)
	counterCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name: "exim_rejected_rcpt_total",
		Labels: map[string]string{
			"error_message": "{{.message}}",
			"logfile":       "{{.logfile}}",
		},
	})
	logfile1 := map[string]interface{}{
		"logfile": "/var/log/exim-1.log",
	}
	logfile2 := map[string]interface{}{
		"logfile": "/var/log/exim-2.log",
	}
	counter := NewCounterMetric(counterCfg, regex, nil)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", logfile1)
	counter.ProcessMatch("2016-04-26 12:31:39 H=(186-90-8-31.genericrev.cantv.net) [186.90.8.31] F=<Hans.Krause9@cantv.net> rejected RCPT <ug2seeng-admin@example.com>: Unrouteable address", logfile1)
	counter.ProcessMatch("2016-04-26 10:19:57 H=(85.214.241.101) [36.224.138.227] F=<z2007tw@yahoo.com.tw> rejected RCPT <alan.a168@msa.hinet.net>: relay not permitted", logfile2)

	switch c := counter.Collector().(type) {
	case *prometheus.CounterVec:
		m := io_prometheus_client.Metric{}
		c.With(map[string]string{
			"error_message": "relay not permitted",
			"logfile":       "/var/log/exim-1.log",
		}).Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
		c.With(map[string]string{
			"error_message": "Unrouteable address",
			"logfile":       "/var/log/exim-1.log",
		}).Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
		c.With(map[string]string{
			"error_message": "relay not permitted",
			"logfile":       "/var/log/exim-2.log",
		}).Write(&m)
		if *m.Counter.Value != float64(1) {
			t.Errorf("Expected 1 match, but got %v matches.", *m.Counter.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func initCounterRegex(t *testing.T) *oniguruma.Regex {
	patterns := loadPatternDir(t)
	err := patterns.AddPattern("EXIM_MESSAGE [a-zA-Z ]*")
	if err != nil {
		t.Error(err)
	}
	regex, err := Compile("%{EXIM_DATE} %{EXIM_REMOTE_HOST} F=<%{EMAILADDRESS}> rejected RCPT <%{EMAILADDRESS}>: %{EXIM_MESSAGE:message}", patterns)
	if err != nil {
		t.Error(err)
	}
	return regex
}

func TestGauge(t *testing.T) {
	regex := initGaugeRegex(t)
	gaugeCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:  "temperature",
		Value: "{{.temperature}}",
	})
	gauge := NewGaugeMetric(gaugeCfg, regex, nil)

	gauge.ProcessMatch("Temperature in Berlin: 32", nil)
	gauge.ProcessMatch("Temperature in Moscow: -5", nil)

	switch c := gauge.Collector().(type) {
	case prometheus.Gauge:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Gauge.Value != float64(-5) {
			t.Errorf("Expected -5 as last observed value, but got %v.", *m.Gauge.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestGaugeCumulative(t *testing.T) {
	regex := initCumulativeRegex(t)
	gaugeCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:       "rainfall",
		Value:      "{{.rainfall}}",
		Cumulative: true,
	})
	gauge := NewGaugeMetric(gaugeCfg, regex, nil)

	gauge.ProcessMatch("Rainfall in Berlin: 32", nil)
	gauge.ProcessMatch("Rainfall in Moscow: 5", nil)

	switch c := gauge.Collector().(type) {
	case prometheus.Gauge:
		m := io_prometheus_client.Metric{}
		c.Write(&m)
		if *m.Gauge.Value != float64(37) {
			t.Errorf("Expected 37 as cumulative value, but got %v.", *m.Gauge.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func TestGaugeVec(t *testing.T) {
	regex := initGaugeRegex(t)
	gaugeCfg := newMetricConfig(t, &configuration.MetricConfig{
		Name:  "temperature",
		Value: "{{.temperature}}",
		Labels: map[string]string{
			"city": "{{.city}}",
		},
	})
	gauge := NewGaugeMetric(gaugeCfg, regex, nil)

	gauge.ProcessMatch("Temperature in Berlin: 32", nil)
	gauge.ProcessMatch("Temperature in Moscow: -5", nil)
	gauge.ProcessMatch("Temperature in Berlin: 31", nil)

	switch c := gauge.Collector().(type) {
	case *prometheus.GaugeVec:
		m := io_prometheus_client.Metric{}
		c.WithLabelValues("Berlin").Write(&m)
		if *m.Gauge.Value != float64(31) {
			t.Errorf("Expected 31 as last observed value in Berlin, but got %v.", *m.Gauge.Value)
		}
		c.WithLabelValues("Moscow").Write(&m)
		if *m.Gauge.Value != float64(-5) {
			t.Errorf("Expected -5 as last observed value in Moscow, but got %v.", *m.Gauge.Value)
		}
	default:
		t.Errorf("Unexpected type of metric: %v", reflect.TypeOf(c))
	}
}

func initGaugeRegex(t *testing.T) *oniguruma.Regex {
	patterns := loadPatternDir(t)
	regex, err := Compile("Temperature in %{WORD:city}: %{INT:temperature}", patterns)
	if err != nil {
		t.Error(err)
	}
	return regex
}

func initCumulativeRegex(t *testing.T) *oniguruma.Regex {
	patterns := loadPatternDir(t)
	regex, err := Compile("Rainfall in %{WORD:city}: %{INT:rainfall}", patterns)
	if err != nil {
		t.Error(err)
	}
	return regex
}

func newMetricConfig(t *testing.T, cfg *configuration.MetricConfig) *configuration.MetricConfig {
	// Handle default for counter's value
	// Note: cfg.Type is not set here
	if len(cfg.Value) == 0 {
		cfg.Value = "1.0"
	}
	err := cfg.InitTemplates()
	if err != nil {
		t.Fatal(err)
	}
	return cfg
}
<|endoftext|>


<commit_before>package libvirt

import (
	"fmt"
	"log"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"gopkg.in/alexzorin/libvirt-go.v2"
)

const KeyLeftShift uint32 = 0xFFE1

type bootCommandTemplateData struct {
	HTTPIP   string
	HTTPPort uint
	Name     string
}

// This step "types" the boot command into the VM over VNC.
//
// Uses:
//   config *config
//   http_port int
//   ui     packer.Ui
//
// Produces:
//   <nothing>
type stepTypeBootCommand struct{}

func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	//	httpPort := state.Get("http_port").(uint)
	//	hostIp := state.Get("host_ip").(string)
	ui := state.Get("ui").(packer.Ui)

	var lvd libvirt.VirDomain
	lv, err := libvirt.NewVirConnection(config.LibvirtUrl)
	if err != nil {
		err := fmt.Errorf("Error connecting to libvirt: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer lv.CloseConnection()
	if lvd, err = lv.LookupDomainByName(config.VMName); err != nil {
		err := fmt.Errorf("Error lookup domain: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer lvd.Free()

	//	tplData := &bootCommandTemplateData{
	//		hostIp,
	//		httpPort,
	//		config.VMName,
	//	}

	ui.Say("Typing the boot command...")
	for _, command := range config.BootCommand {
		//		command, err := config.tpl.Process(command, tplData)
		//		if err != nil {
		//			err := fmt.Errorf("Error preparing boot command: %s", err)
		//			state.Put("error", err)
		//			ui.Error(err.Error())
		//			return multistep.ActionHalt
		//		}

		// Check for interrupts between typing things so we can cancel
		// since this isn't the fastest thing.
		if _, ok := state.GetOk(multistep.StateCancelled); ok {
			return multistep.ActionHalt
		}

		sendBootString(lvd, command)
	}

	return multistep.ActionContinue
}

func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {}

func sendBootString(d libvirt.VirDomain, original string) {
	var err error
	var key uint

	for len(original) > 0 {
		if strings.HasPrefix(original, "<wait>") {
			log.Printf("Special code '<wait>' found, sleeping one second")
			time.Sleep(1 * time.Second)
			original = original[len("<wait>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait5>") {
			log.Printf("Special code '<wait5>' found, sleeping 5 seconds")
			time.Sleep(5 * time.Second)
			original = original[len("<wait5>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait10>") {
			log.Printf("Special code '<wait10>' found, sleeping 10 seconds")
			time.Sleep(10 * time.Second)
			original = original[len("<wait10>"):]
			continue
		}

		if strings.HasPrefix(original, "<esc>") {
			d.SendKey(libvirt.VIR_KEYCODE_SET_RFB, 400, []uint{ecodes["<esc>"]}, 0)
			original = original[len("<esc>"):]
		}

		if strings.HasPrefix(original, "<enter>") {
			d.SendKey(libvirt.VIR_KEYCODE_SET_RFB, 400, []uint{ecodes["<enter>"]}, 0)
			original = original[len("<enter>"):]
		}

		log.Printf("command %s", original)
		r, size := utf8.DecodeRuneInString(original)
		original = original[size:]
		key = ecodes[string(r)]
		log.Printf("find code for char %s %d", string(r), key)
		//VIR_KEYCODE_SET_LINUX, VIR_KEYCODE_SET_USB, VIR_KEYCODE_SET_RFB, VIR_KEYCODE_SET_WIN32, VIR_KEYCODE_SET_XT_KBD
		if err = d.SendKey(libvirt.VIR_KEYCODE_SET_RFB, 400, []uint{key}, 0); err != nil {
			log.Printf("Sending code %d failed: %s", key, err.Error())
		}
	}

}
<commit_msg>fix<commit_after>package libvirt

import (
	"fmt"
	"log"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"gopkg.in/alexzorin/libvirt-go.v2"
)

const KeyLeftShift uint32 = 0xFFE1

type bootCommandTemplateData struct {
	HTTPIP   string
	HTTPPort uint
	Name     string
}

// This step "types" the boot command into the VM over VNC.
//
// Uses:
//   config *config
//   http_port int
//   ui     packer.Ui
//
// Produces:
//   <nothing>
type stepTypeBootCommand struct{}

func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	//	httpPort := state.Get("http_port").(uint)
	//	hostIp := state.Get("host_ip").(string)
	ui := state.Get("ui").(packer.Ui)

	var lvd libvirt.VirDomain
	lv, err := libvirt.NewVirConnection(config.LibvirtUrl)
	if err != nil {
		err := fmt.Errorf("Error connecting to libvirt: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer lv.CloseConnection()
	if lvd, err = lv.LookupDomainByName(config.VMName); err != nil {
		err := fmt.Errorf("Error lookup domain: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer lvd.Free()

	//	tplData := &bootCommandTemplateData{
	//		hostIp,
	//		httpPort,
	//		config.VMName,
	//	}

	ui.Say("Typing the boot command...")
	for _, command := range config.BootCommand {
		//		command, err := config.tpl.Process(command, tplData)
		//		if err != nil {
		//			err := fmt.Errorf("Error preparing boot command: %s", err)
		//			state.Put("error", err)
		//			ui.Error(err.Error())
		//			return multistep.ActionHalt
		//		}

		// Check for interrupts between typing things so we can cancel
		// since this isn't the fastest thing.
		if _, ok := state.GetOk(multistep.StateCancelled); ok {
			return multistep.ActionHalt
		}

		sendBootString(lvd, command)
	}

	return multistep.ActionContinue
}

func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {}

func sendBootString(d libvirt.VirDomain, original string) {
	var err error
	var key uint

	for len(original) > 0 {
		if strings.HasPrefix(original, "<wait>") {
			log.Printf("Special code '<wait>' found, sleeping one second")
			time.Sleep(1 * time.Second)
			original = original[len("<wait>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait5>") {
			log.Printf("Special code '<wait5>' found, sleeping 5 seconds")
			time.Sleep(5 * time.Second)
			original = original[len("<wait5>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait10>") {
			log.Printf("Special code '<wait10>' found, sleeping 10 seconds")
			time.Sleep(10 * time.Second)
			original = original[len("<wait10>"):]
			continue
		}

		if strings.HasPrefix(original, "<esc>") {
			d.SendKey(libvirt.VIR_KEYCODE_SET_RFB, 400, []uint{ecodes["<esc>"]}, 0)
			original = original[len("<esc>"):]
			continue
		}

		if strings.HasPrefix(original, "<enter>") {
			d.SendKey(libvirt.VIR_KEYCODE_SET_RFB, 400, []uint{ecodes["<enter>"]}, 0)
			original = original[len("<enter>"):]
			continue
		}

		log.Printf("command %s", original)
		r, size := utf8.DecodeRuneInString(original)
		original = original[size:]
		key = ecodes[string(r)]
		log.Printf("find code for char %s %d", string(r), key)
		//VIR_KEYCODE_SET_LINUX, VIR_KEYCODE_SET_USB, VIR_KEYCODE_SET_RFB, VIR_KEYCODE_SET_WIN32, VIR_KEYCODE_SET_XT_KBD
		if err = d.SendKey(libvirt.VIR_KEYCODE_SET_RFB, 400, []uint{key}, 0); err != nil {
			log.Printf("Sending code %d failed: %s", key, err.Error())
		}
	}

}
<|endoftext|>