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

// This file contains the printf-checker.

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/token"
	"strings"
	"unicode/utf8"
)

var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")

// printfList records the formatted-print functions. The value is the location
// of the format parameter. Names are lower-cased so the lookup is
// case insensitive.
var printfList = map[string]int{
	"errorf":  0,
	"fatalf":  0,
	"fprintf": 1,
	"panicf":  0,
	"printf":  0,
	"sprintf": 0,
}

// printList records the unformatted-print functions. The value is the location
// of the first parameter to be printed.  Names are lower-cased so the lookup is
// case insensitive.
var printList = map[string]int{
	"error":  0,
	"fatal":  0,
	"fprint": 1, "fprintln": 1,
	"panic": 0, "panicln": 0,
	"print": 0, "println": 0,
	"sprint": 0, "sprintln": 0,
}

// checkCall triggers the print-specific checks if the call invokes a print function.
func (f *File) checkFmtPrintfCall(call *ast.CallExpr, Name string) {
	if !*vetPrintf && !*vetAll {
		return
	}
	name := strings.ToLower(Name)
	if skip, ok := printfList[name]; ok {
		f.checkPrintf(call, Name, skip)
		return
	}
	if skip, ok := printList[name]; ok {
		f.checkPrint(call, Name, skip)
		return
	}
}

// literal returns the literal value represented by the expression, or nil if it is not a literal.
func (f *File) literal(value ast.Expr) *ast.BasicLit {
	switch v := value.(type) {
	case *ast.BasicLit:
		return v
	case *ast.Ident:
		// See if it's a constant or initial value (we can't tell the difference).
		if v.Obj == nil || v.Obj.Decl == nil {
			return nil
		}
		valueSpec, ok := v.Obj.Decl.(*ast.ValueSpec)
		if ok && len(valueSpec.Names) == len(valueSpec.Values) {
			// Find the index in the list of names
			var i int
			for i = 0; i < len(valueSpec.Names); i++ {
				if valueSpec.Names[i].Name == v.Name {
					if lit, ok := valueSpec.Values[i].(*ast.BasicLit); ok {
						return lit
					}
					return nil
				}
			}
		}
	}
	return nil
}

// checkPrintf checks a call to a formatted print routine such as Printf.
// The skip argument records how many arguments to ignore; that is,
// call.Args[skip] is (well, should be) the format argument.
func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
	if len(call.Args) <= skip {
		return
	}
	lit := f.literal(call.Args[skip])
	if lit == nil {
		if *verbose {
			f.Warn(call.Pos(), "can't check non-literal format in call to", name)
		}
		return
	}
	if lit.Kind != token.STRING {
		f.Badf(call.Pos(), "literal %v not a string in call to", lit.Value, name)
	}
	format := lit.Value
	if !strings.Contains(format, "%") {
		if len(call.Args) > skip+1 {
			f.Badf(call.Pos(), "no formatting directive in %s call", name)
		}
		return
	}
	// Hard part: check formats against args.
	// Trivial but useful test: count.
	numArgs := 0
	for i, w := 0, 0; i < len(format); i += w {
		w = 1
		if format[i] == '%' {
			nbytes, nargs := f.parsePrintfVerb(call, format[i:])
			w = nbytes
			numArgs += nargs
		}
	}
	expect := len(call.Args) - (skip + 1)
	if numArgs != expect {
		f.Badf(call.Pos(), "wrong number of args in %s call: %d needed but %d args", name, numArgs, expect)
	}
}

// parsePrintfVerb returns the number of bytes and number of arguments
// consumed by the Printf directive that begins s, including its percent sign
// and verb.
func (f *File) parsePrintfVerb(call *ast.CallExpr, s string) (nbytes, nargs int) {
	// There's guaranteed a percent sign.
	flags := make([]byte, 0, 5)
	nbytes = 1
	end := len(s)
	// There may be flags.
FlagLoop:
	for nbytes < end {
		switch s[nbytes] {
		case '#', '0', '+', '-', ' ':
			flags = append(flags, s[nbytes])
			nbytes++
		default:
			break FlagLoop
		}
	}
	getNum := func() {
		if nbytes < end && s[nbytes] == '*' {
			nbytes++
			nargs++
		} else {
			for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
				nbytes++
			}
		}
	}
	// There may be a width.
	getNum()
	// If there's a period, there may be a precision.
	if nbytes < end && s[nbytes] == '.' {
		flags = append(flags, '.') // Treat precision as a flag.
		nbytes++
		getNum()
	}
	// Now a verb.
	c, w := utf8.DecodeRuneInString(s[nbytes:])
	nbytes += w
	if c != '%' {
		nargs++
		f.checkPrintfVerb(call, c, flags)
	}
	return
}

type printVerb struct {
	verb  rune
	flags string // known flags are all ASCII
}

// Common flag sets for printf verbs.
const (
	numFlag      = " -+.0"
	sharpNumFlag = " -+.0#"
	allFlags     = " -+.0#"
)

// printVerbs identifies which flags are known to printf for each verb.
// TODO: A type that implements Formatter may do what it wants, and vet
// will complain incorrectly.
var printVerbs = []printVerb{
	// '-' is a width modifier, always valid.
	// '.' is a precision for float, max width for strings.
	// '+' is required sign for numbers, Go format for %v.
	// '#' is alternate format for several verbs.
	// ' ' is spacer for numbers
	{'b', numFlag},
	{'c', "-"},
	{'d', numFlag},
	{'e', numFlag},
	{'E', numFlag},
	{'f', numFlag},
	{'F', numFlag},
	{'g', numFlag},
	{'G', numFlag},
	{'o', sharpNumFlag},
	{'p', "-#"},
	{'q', "-+#."},
	{'s', "-."},
	{'t', "-"},
	{'T', "-"},
	{'U', "-#"},
	{'v', allFlags},
	{'x', sharpNumFlag},
	{'X', sharpNumFlag},
}

const printfVerbs = "bcdeEfFgGopqstTvxUX"

func (f *File) checkPrintfVerb(call *ast.CallExpr, verb rune, flags []byte) {
	// Linear scan is fast enough for a small list.
	for _, v := range printVerbs {
		if v.verb == verb {
			for _, flag := range flags {
				if !strings.ContainsRune(v.flags, rune(flag)) {
					f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", verb, flag)
				}
			}
			return
		}
	}
	f.Badf(call.Pos(), "unrecognized printf verb %q", verb)
}

// checkPrint checks a call to an unformatted print routine such as Println.
// The skip argument records how many arguments to ignore; that is,
// call.Args[skip] is the first argument to be printed.
func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
	isLn := strings.HasSuffix(name, "ln")
	isF := strings.HasPrefix(name, "F")
	args := call.Args
	// check for Println(os.Stderr, ...)
	if skip == 0 && !isF && len(args) > 0 {
		if sel, ok := args[0].(*ast.SelectorExpr); ok {
			if x, ok := sel.X.(*ast.Ident); ok {
				if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
					f.Warnf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
				}
			}
		}
	}
	if len(args) <= skip {
		if *verbose && !isLn {
			f.Badf(call.Pos(), "no args in %s call", name)
		}
		return
	}
	arg := args[skip]
	if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
		if strings.Contains(lit.Value, "%") {
			f.Badf(call.Pos(), "possible formatting directive in %s call", name)
		}
	}
	if isLn {
		// The last item, if a string, should not have a newline.
		arg = args[len(call.Args)-1]
		if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
			if strings.HasSuffix(lit.Value, `\n"`) {
				f.Badf(call.Pos(), "%s call ends with newline", name)
			}
		}
	}
}

// This function never executes, but it serves as a simple test for the program.
// Test with make test.
func BadFunctionUsedInTests() {
	fmt.Println()                      // not an error
	fmt.Println("%s", "hi")            // ERROR "possible formatting directive in Println call"
	fmt.Printf("%s", "hi", 3)          // ERROR "wrong number of args in Printf call"
	fmt.Printf("%s%%%d", "hi", 3)      // correct
	fmt.Printf("%.*d", 3, 3)           // correct
	fmt.Printf("%.*d", 3, 3, 3)        // ERROR "wrong number of args in Printf call"
	printf("now is the time", "buddy") // ERROR "no formatting directive"
	Printf("now is the time", "buddy") // ERROR "no formatting directive"
	Printf("hi")                       // ok
	const format = "%s %s\n"
	Printf(format, "hi", "there")
	Printf(format, "hi") // ERROR "wrong number of args in Printf call"
	f := new(File)
	f.Warn(0, "%s", "hello", 3)  // ERROR "possible formatting directive in Warn call"
	f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
	f.Warnf(0, "%r", "hello")    // ERROR "unrecognized printf verb"
	f.Warnf(0, "%#s", "hello")   // ERROR "unrecognized printf flag"
}

// printf is used by the test.
func printf(format string, args ...interface{}) {
	panic("don't call - testing only")
}
<commit_msg>vet: be less strict about number of arguments when a ... is present.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains the printf-checker.

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/token"
	"strings"
	"unicode/utf8"
)

var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")

// printfList records the formatted-print functions. The value is the location
// of the format parameter. Names are lower-cased so the lookup is
// case insensitive.
var printfList = map[string]int{
	"errorf":  0,
	"fatalf":  0,
	"fprintf": 1,
	"panicf":  0,
	"printf":  0,
	"sprintf": 0,
}

// printList records the unformatted-print functions. The value is the location
// of the first parameter to be printed.  Names are lower-cased so the lookup is
// case insensitive.
var printList = map[string]int{
	"error":  0,
	"fatal":  0,
	"fprint": 1, "fprintln": 1,
	"panic": 0, "panicln": 0,
	"print": 0, "println": 0,
	"sprint": 0, "sprintln": 0,
}

// checkCall triggers the print-specific checks if the call invokes a print function.
func (f *File) checkFmtPrintfCall(call *ast.CallExpr, Name string) {
	if !*vetPrintf && !*vetAll {
		return
	}
	name := strings.ToLower(Name)
	if skip, ok := printfList[name]; ok {
		f.checkPrintf(call, Name, skip)
		return
	}
	if skip, ok := printList[name]; ok {
		f.checkPrint(call, Name, skip)
		return
	}
}

// literal returns the literal value represented by the expression, or nil if it is not a literal.
func (f *File) literal(value ast.Expr) *ast.BasicLit {
	switch v := value.(type) {
	case *ast.BasicLit:
		return v
	case *ast.Ident:
		// See if it's a constant or initial value (we can't tell the difference).
		if v.Obj == nil || v.Obj.Decl == nil {
			return nil
		}
		valueSpec, ok := v.Obj.Decl.(*ast.ValueSpec)
		if ok && len(valueSpec.Names) == len(valueSpec.Values) {
			// Find the index in the list of names
			var i int
			for i = 0; i < len(valueSpec.Names); i++ {
				if valueSpec.Names[i].Name == v.Name {
					if lit, ok := valueSpec.Values[i].(*ast.BasicLit); ok {
						return lit
					}
					return nil
				}
			}
		}
	}
	return nil
}

// checkPrintf checks a call to a formatted print routine such as Printf.
// The skip argument records how many arguments to ignore; that is,
// call.Args[skip] is (well, should be) the format argument.
func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
	if len(call.Args) <= skip {
		return
	}
	lit := f.literal(call.Args[skip])
	if lit == nil {
		if *verbose {
			f.Warn(call.Pos(), "can't check non-literal format in call to", name)
		}
		return
	}
	if lit.Kind != token.STRING {
		f.Badf(call.Pos(), "literal %v not a string in call to", lit.Value, name)
	}
	format := lit.Value
	if !strings.Contains(format, "%") {
		if len(call.Args) > skip+1 {
			f.Badf(call.Pos(), "no formatting directive in %s call", name)
		}
		return
	}
	// Hard part: check formats against args.
	// Trivial but useful test: count.
	numArgs := 0
	for i, w := 0, 0; i < len(format); i += w {
		w = 1
		if format[i] == '%' {
			nbytes, nargs := f.parsePrintfVerb(call, format[i:])
			w = nbytes
			numArgs += nargs
		}
	}
	expect := len(call.Args) - (skip + 1)
	// Don't be too strict on dotdotdot.
	if call.Ellipsis.IsValid() && numArgs >= expect {
		return
	}
	if numArgs != expect {
		f.Badf(call.Pos(), "wrong number of args in %s call: %d needed but %d args", name, numArgs, expect)
	}
}

// parsePrintfVerb returns the number of bytes and number of arguments
// consumed by the Printf directive that begins s, including its percent sign
// and verb.
func (f *File) parsePrintfVerb(call *ast.CallExpr, s string) (nbytes, nargs int) {
	// There's guaranteed a percent sign.
	flags := make([]byte, 0, 5)
	nbytes = 1
	end := len(s)
	// There may be flags.
FlagLoop:
	for nbytes < end {
		switch s[nbytes] {
		case '#', '0', '+', '-', ' ':
			flags = append(flags, s[nbytes])
			nbytes++
		default:
			break FlagLoop
		}
	}
	getNum := func() {
		if nbytes < end && s[nbytes] == '*' {
			nbytes++
			nargs++
		} else {
			for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
				nbytes++
			}
		}
	}
	// There may be a width.
	getNum()
	// If there's a period, there may be a precision.
	if nbytes < end && s[nbytes] == '.' {
		flags = append(flags, '.') // Treat precision as a flag.
		nbytes++
		getNum()
	}
	// Now a verb.
	c, w := utf8.DecodeRuneInString(s[nbytes:])
	nbytes += w
	if c != '%' {
		nargs++
		f.checkPrintfVerb(call, c, flags)
	}
	return
}

type printVerb struct {
	verb  rune
	flags string // known flags are all ASCII
}

// Common flag sets for printf verbs.
const (
	numFlag      = " -+.0"
	sharpNumFlag = " -+.0#"
	allFlags     = " -+.0#"
)

// printVerbs identifies which flags are known to printf for each verb.
// TODO: A type that implements Formatter may do what it wants, and vet
// will complain incorrectly.
var printVerbs = []printVerb{
	// '-' is a width modifier, always valid.
	// '.' is a precision for float, max width for strings.
	// '+' is required sign for numbers, Go format for %v.
	// '#' is alternate format for several verbs.
	// ' ' is spacer for numbers
	{'b', numFlag},
	{'c', "-"},
	{'d', numFlag},
	{'e', numFlag},
	{'E', numFlag},
	{'f', numFlag},
	{'F', numFlag},
	{'g', numFlag},
	{'G', numFlag},
	{'o', sharpNumFlag},
	{'p', "-#"},
	{'q', "-+#."},
	{'s', "-."},
	{'t', "-"},
	{'T', "-"},
	{'U', "-#"},
	{'v', allFlags},
	{'x', sharpNumFlag},
	{'X', sharpNumFlag},
}

const printfVerbs = "bcdeEfFgGopqstTvxUX"

func (f *File) checkPrintfVerb(call *ast.CallExpr, verb rune, flags []byte) {
	// Linear scan is fast enough for a small list.
	for _, v := range printVerbs {
		if v.verb == verb {
			for _, flag := range flags {
				if !strings.ContainsRune(v.flags, rune(flag)) {
					f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", verb, flag)
				}
			}
			return
		}
	}
	f.Badf(call.Pos(), "unrecognized printf verb %q", verb)
}

// checkPrint checks a call to an unformatted print routine such as Println.
// The skip argument records how many arguments to ignore; that is,
// call.Args[skip] is the first argument to be printed.
func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
	isLn := strings.HasSuffix(name, "ln")
	isF := strings.HasPrefix(name, "F")
	args := call.Args
	// check for Println(os.Stderr, ...)
	if skip == 0 && !isF && len(args) > 0 {
		if sel, ok := args[0].(*ast.SelectorExpr); ok {
			if x, ok := sel.X.(*ast.Ident); ok {
				if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
					f.Warnf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
				}
			}
		}
	}
	if len(args) <= skip {
		if *verbose && !isLn {
			f.Badf(call.Pos(), "no args in %s call", name)
		}
		return
	}
	arg := args[skip]
	if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
		if strings.Contains(lit.Value, "%") {
			f.Badf(call.Pos(), "possible formatting directive in %s call", name)
		}
	}
	if isLn {
		// The last item, if a string, should not have a newline.
		arg = args[len(call.Args)-1]
		if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
			if strings.HasSuffix(lit.Value, `\n"`) {
				f.Badf(call.Pos(), "%s call ends with newline", name)
			}
		}
	}
}

// This function never executes, but it serves as a simple test for the program.
// Test with make test.
func BadFunctionUsedInTests() {
	fmt.Println()                      // not an error
	fmt.Println("%s", "hi")            // ERROR "possible formatting directive in Println call"
	fmt.Printf("%s", "hi", 3)          // ERROR "wrong number of args in Printf call"
	fmt.Printf("%s%%%d", "hi", 3)      // correct
	fmt.Printf("%.*d", 3, 3)           // correct
	fmt.Printf("%.*d", 3, 3, 3)        // ERROR "wrong number of args in Printf call"
	fmt.Printf("%q %q", multi()...)    // ok
	printf("now is the time", "buddy") // ERROR "no formatting directive"
	Printf("now is the time", "buddy") // ERROR "no formatting directive"
	Printf("hi")                       // ok
	const format = "%s %s\n"
	Printf(format, "hi", "there")
	Printf(format, "hi") // ERROR "wrong number of args in Printf call"
	f := new(File)
	f.Warn(0, "%s", "hello", 3)  // ERROR "possible formatting directive in Warn call"
	f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
	f.Warnf(0, "%r", "hello")    // ERROR "unrecognized printf verb"
	f.Warnf(0, "%#s", "hello")   // ERROR "unrecognized printf flag"
}

// printf is used by the test.
func printf(format string, args ...interface{}) {
	panic("don't call - testing only")
}

// multi is used by the test.
func multi() []interface{} {
	panic("don't call - testing only")
}
<|endoftext|>


<commit_before>package fakegit

import (
	"fmt"
	"os"
	"regexp"
	"strings"
)

func MakeC(argx []string) []string {
	for i := range argx {
		if strings.Count(argx[i], " ") > 0 {
			argx[i] = fmt.Sprintf("%#v", argx[i])
		}
	}
	return argx
}

func ProcUser(argx []string) ([]string, string, string, bool) {
	var name, email string
	if IsIn("--user", argx) {
		ind := IndexOf("--user", argx)
		Pop(ind, &argx)
		if ind >= len(argx) {
			Fatal(ARGUMENT_ERROR_INVALID)
		}
		info := Pop(ind, &argx)
		re, _ := regexp.Compile(`([\w -]+)(<.*@.*>|<>)?`)
		res := re.FindStringSubmatch(info)
		name = strings.TrimSpace(res[1])
		email = res[2]
		if name == "" {
			Fatal(ARGUMENT_ERROR_USERNAME)
		}
		if email == "" {
			fmt.Printf("Finding user %s...\n", name)
			fake := NewGithubUser(name)
			name, email = fake.GetIdentity()
			fmt.Printf("User found: %s <%s>\n", name, email)
		} else {
			email = email[1 : len(email)-1]
		}
	}
	return MakeC(argx), name, email, IsIn("change", argx)
}

func ShowHelp() {
	fmt.Print(HELP_DOCS)
	os.Exit(0)
}

func ProcArgs() ([]string, string, string, bool) {
	if len(os.Args) < 2 {
		ShowHelp()
	}
	cliArgs := os.Args[1:]
	if IsIn("--help", cliArgs) || IsIn("-h", cliArgs) {
		ShowHelp()
	}
	if IsIn("recover", cliArgs) {
		NewGitConf(".git/config").Recover()
		fmt.Println("Config file reset.")
		os.Exit(0)
	}
	return ProcUser(cliArgs)
}
<commit_msg>No need for Makec<commit_after>package fakegit

import (
	"fmt"
	"os"
	"regexp"
	"strings"
)

func ProcUser(argx []string) ([]string, string, string, bool) {
	var name, email string
	if IsIn("--user", argx) {
		ind := IndexOf("--user", argx)
		Pop(ind, &argx)
		if ind >= len(argx) {
			Fatal(ARGUMENT_ERROR_INVALID)
		}
		info := Pop(ind, &argx)
		re, _ := regexp.Compile(`([\w -]+)(<.*@.*>|<>)?`)
		res := re.FindStringSubmatch(info)
		name = strings.TrimSpace(res[1])
		email = res[2]
		if name == "" {
			Fatal(ARGUMENT_ERROR_USERNAME)
		}
		if email == "" {
			fmt.Printf("Finding user %s...\n", name)
			fake := NewGithubUser(name)
			name, email = fake.GetIdentity()
			fmt.Printf("User found: %s <%s>\n", name, email)
		} else {
			email = email[1 : len(email)-1]
		}
	}
	return argx, name, email, IsIn("change", argx)
}

func ShowHelp() {
	fmt.Print(HELP_DOCS)
	os.Exit(0)
}

func ProcArgs() ([]string, string, string, bool) {
	if len(os.Args) < 2 {
		ShowHelp()
	}
	cliArgs := os.Args[1:]
	if IsIn("--help", cliArgs) || IsIn("-h", cliArgs) {
		ShowHelp()
	}
	if IsIn("recover", cliArgs) {
		NewGitConf(".git/config").Recover()
		fmt.Println("Config file reset.")
		os.Exit(0)
	}
	return ProcUser(cliArgs)
}
<|endoftext|>


<commit_before>/*
Package giantbomb implements a wrapper for Giant Bomb API.

Giant Bomb is a video game website and wiki. Wiki contains a ton of information
about video games and things related to them. This information is collected by
volunteers, video game fans.

API provides interface to access all this information. You will need to get an
API key to be able to use it. Information about getting your API key, terms of
use and other useful info is available at https://www.giantbomb.com/api/.

Now go build something, duder!

This library is meant to simplify interactons with Giant Bomb API. After you
get your API key, make sure to set Key variable to match it:

	giantbomb.Key = "YOUR_API_KEY"

There's a lot of data for you to get. It is usually a good idea to set a list
of fields that you need:

	giantbomb.FieldList = []string{
		"name",
		"platforms",
	}
*/
package giantbomb

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

const (
	ResourceTypeGame      = "game"
	ResourceTypeFranchise = "franchise"
	ResourceTypeCharacter = "character"
	ResourceTypeConcept   = "concept"
	ResourceTypeObject    = "object"
	ResourceTypeLocation  = "location"
	ResourceTypePerson    = "person"
	ResourceTypeCompany   = "company"
	ResourceTypeVideo     = "video"
)

var (
	Host      = "https://www.giantbomb.com/api/"
	Key       string   // Your API key. Make sure to set this variable to match your key.
	FieldList []string // List of fields that determines data that you get in responses.
)

type Response struct {
	Error                string
	Limit                int
	Offset               int
	NumberOfPageResults  int
	NumberOfTotalResults int
	Results              []Result
}

type Result struct{}

// Pass empty string to resourceID if you don't need to specify it.
func getBaseURL(resourceType string, resourceID string) string {
	url := Host + resourceType + "/"
	if resourceID != "" {
		url += resourceID + "/"
	}
	url += "?format=json&api_key=" + Key
	if len(FieldList) > 0 {
		url += "&field_list=" + strings.Join(FieldList, ",")
	}
	return url
}

func Search(query string, limit int, page int, resources []string) ([]byte, error) {
	url := getBaseURL("search", "") +
		"&query=\"" + query + "\"" +
		"&limit=" + strconv.Itoa(limit) +
		"&page=" + strconv.Itoa(page) +
		"&resources=" + strings.Join(resources, ",")
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Request to %s failed (%s)!", url, resp.Status))
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}

	// TODO: Implement JSON parsing.
	return body, nil
}
<commit_msg>Added a way to get a list of platforms.<commit_after>/*
Package giantbomb implements a wrapper for Giant Bomb API.

Giant Bomb is a video game website and wiki. Wiki contains a ton of information
about video games and things related to them. This information is collected by
volunteers, video game fans.

API provides interface to access all this information. You will need to get an
API key to be able to use it. Information about getting your API key, terms of
use and other useful info is available at https://www.giantbomb.com/api/.

Now go build something, duder!

This library is meant to simplify interactons with Giant Bomb API. After you
get your API key, make sure to set Key variable to match it:

	giantbomb.Key = "YOUR_API_KEY"

There's a lot of data for you to get. It is usually a good idea to set a list
of fields that you need:

	giantbomb.FieldList = []string{
		"name",
		"platforms",
	}
*/
package giantbomb

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

const (
	ResourceTypeGame      = "game"
	ResourceTypeFranchise = "franchise"
	ResourceTypeCharacter = "character"
	ResourceTypeConcept   = "concept"
	ResourceTypeObject    = "object"
	ResourceTypeLocation  = "location"
	ResourceTypePerson    = "person"
	ResourceTypeCompany   = "company"
	ResourceTypeVideo     = "video"
)

var (
	Host      = "https://www.giantbomb.com/api/"
	Key       string   // Your API key. Make sure to set this variable to match your key.
	FieldList []string // List of fields that determines data that you get in responses.
)

type Response struct {
	Error                string
	Limit                int
	Offset               int
	NumberOfPageResults  int
	NumberOfTotalResults int
	Results              []Result
}

type Result struct{}

// Pass empty string to resourceID if you don't need to specify it.
func getBaseURL(resourceType string, resourceID string) string {
	url := Host + resourceType + "/"
	if resourceID != "" {
		url += resourceID + "/"
	}
	url += "?format=json&api_key=" + Key
	if len(FieldList) > 0 {
		url += "&field_list=" + strings.Join(FieldList, ",")
	}
	return url
}

func Search(query string, limit int, page int, resources []string) ([]byte, error) {
	url := getBaseURL("search", "") +
		"&query=\"" + query + "\"" +
		"&limit=" + strconv.Itoa(limit) +
		"&page=" + strconv.Itoa(page) +
		"&resources=" + strings.Join(resources, ",")
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Request to %s failed (%s)!", url, resp.Status))
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}

	// TODO: Implement JSON parsing.
	return body, nil
}

// Platforms returns list of existing gaming platforms.
func Platforms(limit int, offset int) ([]byte, error) {
	url := getBaseURL("platforms", "") +
		"&limit=" + strconv.Itoa(limit) +
		"&offset=" + strconv.Itoa(offset)
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Request to %s failed (%s)!", url, resp.Status))
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}

	// TODO: Implement JSON parsing.
	return body, nil
}
<|endoftext|>


<commit_before>package stripe

import (
	"net/url"
	"strconv"
	"strings"
)

// Credit Card Types accepted by the Stripe API.
const (
	AmericanExpress = "American Express"
	DinersClub      = "Diners Club"
	Discover        = "Discover"
	JCB             = "JCB"
	MasterCard      = "MasterCard"
	Visa            = "Visa"
	UnknownCard     = "Unknown"
)

// Card represents details about a Credit Card entered into Stripe.
type Card struct {
	Id                string `json:"id"`
	Name              String `json:"name,omitempty"`
	Type              string `json:"type"`
	ExpMonth          int    `json:"exp_month"`
	ExpYear           int    `json:"exp_year"`
	Last4             string `json:"last4"`
	Fingerprint       string `json:"fingerprint"`
	Country           String `json:"country,omitempty"`
	Address1          String `json:"address_line1,omitempty"`
	Address2          String `json:"address_line2,omitempty"`
	AddressCountry    String `json:"address_country,omitempty"`
	AddressState      String `json:"address_state,omitempty"`
	AddressZip        String `json:"address_zip,omitempty"`
	AddressCity       String `json:"address_city"`
	AddressLine1Check String `json:"address_line1_check,omitempty"`
	AddressZipCheck   String `json:"address_zip_check,omitempty"`
	CVCCheck          String `json:"cvc_check,omitempty"`
}

// CardParams encapsulates options for Creating or Updating Credit Cards.
type CardParams struct {
	// (Optional) Cardholder's full name.
	Name string

	// The card number, as a string without any separators.
	Number string

	// Two digit number representing the card's expiration month.
	ExpMonth int

	// Four digit number representing the card's expiration year.
	ExpYear int

	// Card security code
	CVC string

	// (Optional) Billing address line 1
	Address1 string

	// (Optional) Billing address line 2
	Address2 string

	// (Optional) Billing address country
	AddressCountry string

	// (Optional) Billing address state
	AddressState string

	// (Optional) Billing address zip code
	AddressZip string
}

// CardClient encapsulates operations for creating, updating, deleting and
// querying cards using the Stripe REST API.
type CardClient struct{}

func (self *CardClient) Create(c *CardParams, customerId string) (*Card, error) {
	card := Card{}
	values := url.Values{}
	appendCardParamsToValues(c, &values)

	err := query("POST", "/v1/customers/"+customerId+"/cards", values, &card)
	return &card, err
}

// IsLuhnValid uses the Luhn Algorithm (also known as the Mod 10 algorithm) to
// verify a credit cards checksum, which helps flag accidental data entry
// errors.
//
// see http://en.wikipedia.org/wiki/Luhn_algorithm
func IsLuhnValid(card string) (bool, error) {

	var sum = 0
	var digits = strings.Split(card, "")

	// iterate through the digits in reverse order
	for i, even := len(digits)-1, false; i >= 0; i, even = i-1, !even {

		// convert the digit to an integer
		digit, err := strconv.Atoi(digits[i])
		if err != nil {
			return false, err
		}

		// we multiply every other digit by 2, adding the product to the sum.
		// note: if the product is double digits (i.e. 14) we add the two digits
		//       to the sum (14 -> 1+4 = 5). A simple shortcut is to subtract 9
		//       from a double digit product (14 -> 14 - 9 = 5).
		switch {
		case even && digit > 4:
			sum += (digit * 2) - 9
		case even:
			sum += digit * 2
		case !even:
			sum += digit
		}
	}

	// if the sum is divisible by 10, it passes the check
	return sum%10 == 0, nil
}

// GetCardType is a simple algorithm to determine the Card Type (ie Visa,
// Discover) based on the Credit Card Number. If the Number is not recognized, a
// value of "Unknown" will be returned.
func GetCardType(card string) string {

	switch card[0:1] {
	case "4":
		return Visa
	case "2", "1":
		switch card[0:4] {
		case "2131", "1800":
			return JCB
		}
	case "6":
		switch card[0:4] {
		case "6011":
			return Discover
		}
	case "5":
		switch card[0:2] {
		case "51", "52", "53", "54", "55":
			return MasterCard
		}
	case "3":
		switch card[0:2] {
		case "34", "37":
			return AmericanExpress
		case "36":
			return DinersClub
		case "30":
			switch card[0:3] {
			case "300", "301", "302", "303", "304", "305":
				return DinersClub
			}
		default:
			return JCB
		}
	}

	return UnknownCard
}
<commit_msg>added card creation<commit_after>package stripe

import (
	"net/url"
	"strconv"
	"strings"
)

// Credit Card Types accepted by the Stripe API.
const (
	AmericanExpress = "American Express"
	DinersClub      = "Diners Club"
	Discover        = "Discover"
	JCB             = "JCB"
	MasterCard      = "MasterCard"
	Visa            = "Visa"
	UnknownCard     = "Unknown"
)

// Card represents details about a Credit Card entered into Stripe.
type Card struct {
	Id                string `json:"id"`
	Name              String `json:"name,omitempty"`
	Type              string `json:"type"`
	ExpMonth          int    `json:"exp_month"`
	ExpYear           int    `json:"exp_year"`
	Last4             string `json:"last4"`
	Fingerprint       string `json:"fingerprint"`
	Country           String `json:"country,omitempty"`
	Address1          String `json:"address_line1,omitempty"`
	Address2          String `json:"address_line2,omitempty"`
	AddressCountry    String `json:"address_country,omitempty"`
	AddressState      String `json:"address_state,omitempty"`
	AddressZip        String `json:"address_zip,omitempty"`
	AddressCity       String `json:"address_city"`
	AddressLine1Check String `json:"address_line1_check,omitempty"`
	AddressZipCheck   String `json:"address_zip_check,omitempty"`
	CVCCheck          String `json:"cvc_check,omitempty"`
}

// CardParams encapsulates options for Creating or Updating Credit Cards.
type CardParams struct {
	// (Optional) Cardholder's full name.
	Name string

	// The card number, as a string without any separators.
	Number string

	// Two digit number representing the card's expiration month.
	ExpMonth int

	// Four digit number representing the card's expiration year.
	ExpYear int

	// Card security code
	CVC string

	// (Optional) Billing address line 1
	Address1 string

	// (Optional) Billing address line 2
	Address2 string

	// (Optional) Billing address country
	AddressCountry string

	// (Optional) Billing address state
	AddressState string

	// (Optional) Billing address zip code
	AddressZip string
}

// CardClient encapsulates operations for creating, updating, deleting and
// querying cards using the Stripe REST API.
type CardClient struct{}

func (self *CardClient) Create(c *CardParams, customerId string) (*Card, error) {
	card := Card{}
	values := url.Values{}
	appendCardParamsToValues(c, &values)

	err := query("POST", "/v1/customers/"+customerId+"/cards", values, &card)
	return &card, err
}

func (self *CardClient) Delete(cardId string, customerId string) (*DeleteResp, error) {
	delResponse := DeleteResp{}
	values := url.Values{}

	err := query("DELETE", "/v1/customers/"+customerId+"/cards/"+cardId, values, &delResponse)
	return &delResponse, err
}

// IsLuhnValid uses the Luhn Algorithm (also known as the Mod 10 algorithm) to
// verify a credit cards checksum, which helps flag accidental data entry
// errors.
//
// see http://en.wikipedia.org/wiki/Luhn_algorithm
func IsLuhnValid(card string) (bool, error) {

	var sum = 0
	var digits = strings.Split(card, "")

	// iterate through the digits in reverse order
	for i, even := len(digits)-1, false; i >= 0; i, even = i-1, !even {

		// convert the digit to an integer
		digit, err := strconv.Atoi(digits[i])
		if err != nil {
			return false, err
		}

		// we multiply every other digit by 2, adding the product to the sum.
		// note: if the product is double digits (i.e. 14) we add the two digits
		//       to the sum (14 -> 1+4 = 5). A simple shortcut is to subtract 9
		//       from a double digit product (14 -> 14 - 9 = 5).
		switch {
		case even && digit > 4:
			sum += (digit * 2) - 9
		case even:
			sum += digit * 2
		case !even:
			sum += digit
		}
	}

	// if the sum is divisible by 10, it passes the check
	return sum%10 == 0, nil
}

// GetCardType is a simple algorithm to determine the Card Type (ie Visa,
// Discover) based on the Credit Card Number. If the Number is not recognized, a
// value of "Unknown" will be returned.
func GetCardType(card string) string {

	switch card[0:1] {
	case "4":
		return Visa
	case "2", "1":
		switch card[0:4] {
		case "2131", "1800":
			return JCB
		}
	case "6":
		switch card[0:4] {
		case "6011":
			return Discover
		}
	case "5":
		switch card[0:2] {
		case "51", "52", "53", "54", "55":
			return MasterCard
		}
	case "3":
		switch card[0:2] {
		case "34", "37":
			return AmericanExpress
		case "36":
			return DinersClub
		case "30":
			switch card[0:3] {
			case "300", "301", "302", "303", "304", "305":
				return DinersClub
			}
		default:
			return JCB
		}
	}

	return UnknownCard
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"io"
	"sync"
	"time"
)

var (
	// Serial connection Mutex
	pm = &sync.Mutex{}
)

func WaitTimeout(wait <-chan bool, timeout *time.Timer) (success bool, err error) {
	select {
	case result := <-wait:
		// Operation succeeded
		return result, nil
	case <-timeout.C:
		// Time out the transaction
		return false, errTimeout
	}
}

// ScanTimeout advances the given scanner until the timer expires.
// All output found on the way is returned.
func ScanTimeout(scanner *bufio.Scanner, timer *time.Timer) (out []byte, err error) {

	done := make(chan bool)

	// Advance the scanner past one delimiter
	go func() { done <- scanner.Scan() }()

	// Wait for delimiter to appear, or time out
	if _, err := WaitTimeout(done, timer); err != nil {
		return out, err
	}

	// Return all characters found on the way to the delimiter
	out = scanner.Bytes()

	return
}

func ReadPacket(conn io.Reader, timer *time.Timer, expect bool) (out Packet, err error) {

	// Read the first byte in the stream
	scanner := bufio.NewScanner(conn)

	// Split function with configurable
	splitFunc := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		for i := 0; i < len(data); i++ {
			// Look for escape characters
			if data[i] == esc {
				// Look for the given byte following the escape character within bounds
				if i+1 < len(data) {
					char := data[i+1]
					switch char {
					case ack, start, end:
						// Advance the pointer past the 2nd command character
						return i + 2, data[:i], nil
					case esc:
						// Ignore double 0x07
						return i + 2, nil, nil
					default:
					}
				}
			}
		}
		return
	}

	scanner.Split(splitFunc)

	// Read until first escape sequence (ACK)
	pr, err := ScanTimeout(scanner, timer)
	if err != nil {
		return out, err
	}

	if len(pr) != 0 {
		return out, errScanInput
	}

	// Return if we're not expecting data (only ACK)
	if !expect {
		return
	}
	// Read second escape sequence (start)
	pr, err = ScanTimeout(scanner, timer)
	if err != nil {
		return out, err
	}

	if len(pr) != 0 {
		return out, errScanInput
	}

	// Read second escape sequence (data + stop)
	pr, err = ScanTimeout(scanner, timer)
	if err != nil {
		return out, err
	}

	// Abort on invalid input
	if len(pr) > 0 && len(pr) < 4 {
		return out, errTooShort
	}

	// Decode the payload
	if len(pr) >= 4 {
		out, err = UnmarshalPacket(pr)
		if err != nil {
			return out, err
		}
	}

	return
}

// WritePacket serializes a Packet into wire representation, wrapped
// in start and end sequences, and writes to the given connection.
func WritePacket(in Packet, conn io.Writer) (out bool, err error) {

	// Get wire representation of the given Packet
	pb, err := MarshalPacket(in)
	if err != nil {
		return out, errMarshalPacket
	}

	// Wrap start and end escape sequences
	wr := append(pktStart, pb...)
	wr = append(wr, pktEnd...)

	// Write slice to connection
	_, err = conn.Write(wr)
	if err != nil {
		return false, errWrite
	}

	return true, nil
}

// WriteAck writes an ACK response to a connection.
func WriteAck(conn io.Writer) (out bool, err error) {
	num, err := conn.Write(pktAck)
	if err != nil {
		return false, err
	}

	if num != len(pktAck) {
		return false, errWrite
	}

	return
}

func Query(in Packet, conn io.ReadWriter) (out Packet, err error) {

	// Take out lock - start critical section
	pm.Lock()
	defer pm.Unlock()

	// Write the Packet to the connection
	if _, err := WritePacket(in, conn); err != nil {
		return out, err
	}

	// Start a query-scoped timeout
	timer := time.NewTimer(time.Second)

	// Read packet from the remote
	out, err = ReadPacket(conn, timer, in.Expect)
	if err != nil {
		return out, err
	}

	// Send ACK
	WriteAck(conn)

	// Return
	return out, nil
}
<commit_msg>conn - ACK write error checking<commit_after>package main

import (
	"bufio"
	"io"
	"sync"
	"time"
)

var (
	// Serial connection Mutex
	pm = &sync.Mutex{}
)

func WaitTimeout(wait <-chan bool, timeout *time.Timer) (success bool, err error) {
	select {
	case result := <-wait:
		// Operation succeeded
		return result, nil
	case <-timeout.C:
		// Time out the transaction
		return false, errTimeout
	}
}

// ScanTimeout advances the given scanner until the timer expires.
// All output found on the way is returned.
func ScanTimeout(scanner *bufio.Scanner, timer *time.Timer) (out []byte, err error) {

	done := make(chan bool)

	// Advance the scanner past one delimiter
	go func() { done <- scanner.Scan() }()

	// Wait for delimiter to appear, or time out
	if _, err := WaitTimeout(done, timer); err != nil {
		return out, err
	}

	// Return all characters found on the way to the delimiter
	out = scanner.Bytes()

	return
}

func ReadPacket(conn io.Reader, timer *time.Timer, expect bool) (out Packet, err error) {

	// Read the first byte in the stream
	scanner := bufio.NewScanner(conn)

	// Split function with configurable
	splitFunc := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		for i := 0; i < len(data); i++ {
			// Look for escape characters
			if data[i] == esc {
				// Look for the given byte following the escape character within bounds
				if i+1 < len(data) {
					char := data[i+1]
					switch char {
					case ack, start, end:
						// Advance the pointer past the 2nd command character
						return i + 2, data[:i], nil
					case esc:
						// Ignore double 0x07
						return i + 2, nil, nil
					default:
					}
				}
			}
		}
		return
	}

	scanner.Split(splitFunc)

	// Read until first escape sequence (ACK)
	pr, err := ScanTimeout(scanner, timer)
	if err != nil {
		return out, err
	}

	if len(pr) != 0 {
		return out, errScanInput
	}

	// Return if we're not expecting data (only ACK)
	if !expect {
		return
	}
	// Read second escape sequence (start)
	pr, err = ScanTimeout(scanner, timer)
	if err != nil {
		return out, err
	}

	if len(pr) != 0 {
		return out, errScanInput
	}

	// Read second escape sequence (data + stop)
	pr, err = ScanTimeout(scanner, timer)
	if err != nil {
		return out, err
	}

	// Abort on invalid input
	if len(pr) > 0 && len(pr) < 4 {
		return out, errTooShort
	}

	// Decode the payload
	if len(pr) >= 4 {
		out, err = UnmarshalPacket(pr)
		if err != nil {
			return out, err
		}
	}

	return
}

// WritePacket serializes a Packet into wire representation, wrapped
// in start and end sequences, and writes to the given connection.
func WritePacket(in Packet, conn io.Writer) (out bool, err error) {

	// Get wire representation of the given Packet
	pb, err := MarshalPacket(in)
	if err != nil {
		return out, errMarshalPacket
	}

	// Wrap start and end escape sequences
	wr := append(pktStart, pb...)
	wr = append(wr, pktEnd...)

	// Write slice to connection
	_, err = conn.Write(wr)
	if err != nil {
		return false, errWrite
	}

	return true, nil
}

// WriteAck writes an ACK response to a connection.
func WriteAck(conn io.Writer) (out bool, err error) {
	num, err := conn.Write(pktAck)
	if err != nil {
		return false, err
	}

	if num != len(pktAck) {
		return false, errAck
	}

	return
}

func Query(in Packet, conn io.ReadWriter) (out Packet, err error) {

	// Take out lock - start critical section
	pm.Lock()
	defer pm.Unlock()

	// Write the Packet to the connection
	if _, err := WritePacket(in, conn); err != nil {
		return out, err
	}

	// Start a query-scoped timeout
	timer := time.NewTimer(time.Second)

	// Read packet from the remote
	out, err = ReadPacket(conn, timer, in.Expect)
	if err != nil {
		return out, err
	}

	// Send ACK
	_, err = WriteAck(conn)
	if err != nil {
		return out, err
	}

	// Return query result
	return out, nil
}
<|endoftext|>


<commit_before>package utp

/*
#include "utp.h"
*/
import "C"
import (
	"errors"
	"fmt"
	"io"
	"net"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

type Conn struct {
	s          *C.utp_socket
	cond       sync.Cond
	readBuf    []byte
	gotEOF     bool
	gotConnect bool
	// Set on state changed to UTP_STATE_DESTROYING. Not valid to refer to the
	// socket after getting this.
	destroyed bool
	// Conn.Close was called.
	closed   bool
	libError error

	writeDeadline      time.Time
	writeDeadlineTimer *time.Timer
	readDeadline       time.Time
	readDeadlineTimer  *time.Timer

	numBytesRead    int64
	numBytesWritten int64
}

func (c *Conn) onLibError(codeName string) {
	if c.libError != nil {
		panic(fmt.Sprintf("multiple lib errors: got %s, have %s", codeName, c.libError))
	}
	c.libError = errors.New(codeName)
	c.cond.Broadcast()
}

func (c *Conn) setConnected() {
	c.gotConnect = true
	c.cond.Broadcast()
}

func (c *Conn) waitForConnect() error {
	for {
		if c.libError != nil {
			return c.libError
		}
		if c.gotConnect {
			return nil
		}
		c.cond.Wait()
	}
}

func (c *Conn) Close() (err error) {
	mu.Lock()
	defer mu.Unlock()
	c.close()
	return nil
}

func (c *Conn) close() {
	if c.closed {
		return
	}
	if !c.destroyed {
		C.utp_close(c.s)
		c.s = nil
	}
	c.closed = true
	c.cond.Broadcast()
}

func (c *Conn) LocalAddr() net.Addr {
	mu.Lock()
	defer mu.Unlock()
	return getSocketForLibContext(C.utp_get_context(c.s)).pc.LocalAddr()
}

func (c *Conn) readNoWait(b []byte) (n int, err error) {
	n = copy(b, c.readBuf)
	c.readBuf = c.readBuf[n:]
	if n != 0 && len(c.readBuf) == 0 {
		// Can we call this if the utp_socket is closed, destroyed or errored?
		if c.s != nil {
			C.utp_read_drained(c.s)
			// C.utp_issue_deferred_acks(C.utp_get_context(c.s))
		}
	}
	if len(c.readBuf) != 0 {
		return
	}
	err = func() error {
		switch {
		case c.gotEOF:
			return io.EOF
		case c.libError != nil:
			return c.libError
		case c.destroyed:
			return errors.New("destroyed")
		case c.closed:
			return errors.New("closed")
		case !c.readDeadline.IsZero() && !time.Now().Before(c.readDeadline):
			return errDeadlineExceeded{}
		default:
			return nil
		}
	}()
	return
}

func (c *Conn) Read(b []byte) (int, error) {
	mu.Lock()
	defer mu.Unlock()
	for {
		n, err := c.readNoWait(b)
		c.numBytesRead += int64(n)
		// log.Printf("read %d bytes", c.numBytesRead)
		if n != 0 || len(b) == 0 || err != nil {
			// log.Printf("conn %p: read %d bytes: %s", c, n, err)
			return n, err
		}
		c.cond.Wait()
	}
}

func (c *Conn) writeNoWait(b []byte) (n int, err error) {
	err = func() error {
		switch {
		case c.libError != nil:
			return c.libError
		case c.closed:
			return errors.New("closed")
		case c.destroyed:
			return errors.New("destroyed")
		case !c.writeDeadline.IsZero() && !time.Now().Before(c.writeDeadline):
			return errDeadlineExceeded{}
		default:
			return nil
		}
	}()
	if err != nil {
		return
	}
	n = int(C.utp_write(c.s, unsafe.Pointer(&b[0]), C.size_t(len(b))))
	if n < 0 {
		panic(n)
	}
	// log.Print(n)
	return
}

func (c *Conn) Write(b []byte) (n int, err error) {
	// defer func() { log.Printf("wrote %d bytes: %s", n, err) }()
	// log.Print(len(b))
	mu.Lock()
	defer mu.Unlock()
	for len(b) != 0 {
		var n1 int
		n1, err = c.writeNoWait(b)
		b = b[n1:]
		n += n1
		if err != nil {
			break
		}
		if n1 != 0 {
			continue
		}
		c.cond.Wait()
	}
	c.numBytesWritten += int64(n)
	// log.Printf("wrote %d bytes", c.numBytesWritten)
	return
}

func (c *Conn) RemoteAddr() net.Addr {
	var rsa syscall.RawSockaddrAny
	var addrlen C.socklen_t = syscall.SizeofSockaddrAny
	C.utp_getpeername(c.s, (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), &addrlen)
	sa, err := anyToSockaddr(&rsa)
	if err != nil {
		panic(err)
	}
	return sockaddrToUDP(sa)
}

func (c *Conn) SetDeadline(t time.Time) error {
	mu.Lock()
	defer mu.Unlock()
	c.readDeadline = t
	c.writeDeadline = t
	if t.IsZero() {
		c.readDeadlineTimer.Stop()
		c.writeDeadlineTimer.Stop()
	} else {
		d := t.Sub(time.Now())
		c.readDeadlineTimer.Reset(d)
		c.writeDeadlineTimer.Reset(d)
	}
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetReadDeadline(t time.Time) error {
	mu.Lock()
	defer mu.Unlock()
	c.readDeadline = t
	if t.IsZero() {
		c.readDeadlineTimer.Stop()
	} else {
		d := t.Sub(time.Now())
		c.readDeadlineTimer.Reset(d)
	}
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetWriteDeadline(t time.Time) error {
	mu.Lock()
	defer mu.Unlock()
	c.writeDeadline = t
	if t.IsZero() {
		c.writeDeadlineTimer.Stop()
	} else {
		d := t.Sub(time.Now())
		c.writeDeadlineTimer.Reset(d)
	}
	c.cond.Broadcast()
	return nil
}

func (c *Conn) setGotEOF() {
	c.gotEOF = true
	c.cond.Broadcast()
}

func (c *Conn) onDestroyed() {
	c.destroyed = true
	c.s = nil
	c.cond.Broadcast()
}
<commit_msg>We don't actually care about duplicate errors, they're all treated the same<commit_after>package utp

/*
#include "utp.h"
*/
import "C"
import (
	"errors"
	"fmt"
	"io"
	"net"
	"sync"
	"syscall"
	"time"
	"unsafe"
)

type Conn struct {
	s          *C.utp_socket
	cond       sync.Cond
	readBuf    []byte
	gotEOF     bool
	gotConnect bool
	// Set on state changed to UTP_STATE_DESTROYING. Not valid to refer to the
	// socket after getting this.
	destroyed bool
	// Conn.Close was called.
	closed   bool
	libError error

	writeDeadline      time.Time
	writeDeadlineTimer *time.Timer
	readDeadline       time.Time
	readDeadlineTimer  *time.Timer

	numBytesRead    int64
	numBytesWritten int64
}

func (c *Conn) onLibError(codeName string) {
	c.libError = errors.New(codeName)
	c.cond.Broadcast()
}

func (c *Conn) setConnected() {
	c.gotConnect = true
	c.cond.Broadcast()
}

func (c *Conn) waitForConnect() error {
	for {
		if c.libError != nil {
			return c.libError
		}
		if c.gotConnect {
			return nil
		}
		c.cond.Wait()
	}
}

func (c *Conn) Close() (err error) {
	mu.Lock()
	defer mu.Unlock()
	c.close()
	return nil
}

func (c *Conn) close() {
	if c.closed {
		return
	}
	if !c.destroyed {
		C.utp_close(c.s)
		c.s = nil
	}
	c.closed = true
	c.cond.Broadcast()
}

func (c *Conn) LocalAddr() net.Addr {
	mu.Lock()
	defer mu.Unlock()
	return getSocketForLibContext(C.utp_get_context(c.s)).pc.LocalAddr()
}

func (c *Conn) readNoWait(b []byte) (n int, err error) {
	n = copy(b, c.readBuf)
	c.readBuf = c.readBuf[n:]
	if n != 0 && len(c.readBuf) == 0 {
		// Can we call this if the utp_socket is closed, destroyed or errored?
		if c.s != nil {
			C.utp_read_drained(c.s)
			// C.utp_issue_deferred_acks(C.utp_get_context(c.s))
		}
	}
	if len(c.readBuf) != 0 {
		return
	}
	err = func() error {
		switch {
		case c.gotEOF:
			return io.EOF
		case c.libError != nil:
			return c.libError
		case c.destroyed:
			return errors.New("destroyed")
		case c.closed:
			return errors.New("closed")
		case !c.readDeadline.IsZero() && !time.Now().Before(c.readDeadline):
			return errDeadlineExceeded{}
		default:
			return nil
		}
	}()
	return
}

func (c *Conn) Read(b []byte) (int, error) {
	mu.Lock()
	defer mu.Unlock()
	for {
		n, err := c.readNoWait(b)
		c.numBytesRead += int64(n)
		// log.Printf("read %d bytes", c.numBytesRead)
		if n != 0 || len(b) == 0 || err != nil {
			// log.Printf("conn %p: read %d bytes: %s", c, n, err)
			return n, err
		}
		c.cond.Wait()
	}
}

func (c *Conn) writeNoWait(b []byte) (n int, err error) {
	err = func() error {
		switch {
		case c.libError != nil:
			return c.libError
		case c.closed:
			return errors.New("closed")
		case c.destroyed:
			return errors.New("destroyed")
		case !c.writeDeadline.IsZero() && !time.Now().Before(c.writeDeadline):
			return errDeadlineExceeded{}
		default:
			return nil
		}
	}()
	if err != nil {
		return
	}
	n = int(C.utp_write(c.s, unsafe.Pointer(&b[0]), C.size_t(len(b))))
	if n < 0 {
		panic(n)
	}
	// log.Print(n)
	return
}

func (c *Conn) Write(b []byte) (n int, err error) {
	// defer func() { log.Printf("wrote %d bytes: %s", n, err) }()
	// log.Print(len(b))
	mu.Lock()
	defer mu.Unlock()
	for len(b) != 0 {
		var n1 int
		n1, err = c.writeNoWait(b)
		b = b[n1:]
		n += n1
		if err != nil {
			break
		}
		if n1 != 0 {
			continue
		}
		c.cond.Wait()
	}
	c.numBytesWritten += int64(n)
	// log.Printf("wrote %d bytes", c.numBytesWritten)
	return
}

func (c *Conn) RemoteAddr() net.Addr {
	var rsa syscall.RawSockaddrAny
	var addrlen C.socklen_t = syscall.SizeofSockaddrAny
	C.utp_getpeername(c.s, (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), &addrlen)
	sa, err := anyToSockaddr(&rsa)
	if err != nil {
		panic(err)
	}
	return sockaddrToUDP(sa)
}

func (c *Conn) SetDeadline(t time.Time) error {
	mu.Lock()
	defer mu.Unlock()
	c.readDeadline = t
	c.writeDeadline = t
	if t.IsZero() {
		c.readDeadlineTimer.Stop()
		c.writeDeadlineTimer.Stop()
	} else {
		d := t.Sub(time.Now())
		c.readDeadlineTimer.Reset(d)
		c.writeDeadlineTimer.Reset(d)
	}
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetReadDeadline(t time.Time) error {
	mu.Lock()
	defer mu.Unlock()
	c.readDeadline = t
	if t.IsZero() {
		c.readDeadlineTimer.Stop()
	} else {
		d := t.Sub(time.Now())
		c.readDeadlineTimer.Reset(d)
	}
	c.cond.Broadcast()
	return nil
}
func (c *Conn) SetWriteDeadline(t time.Time) error {
	mu.Lock()
	defer mu.Unlock()
	c.writeDeadline = t
	if t.IsZero() {
		c.writeDeadlineTimer.Stop()
	} else {
		d := t.Sub(time.Now())
		c.writeDeadlineTimer.Reset(d)
	}
	c.cond.Broadcast()
	return nil
}

func (c *Conn) setGotEOF() {
	c.gotEOF = true
	c.cond.Broadcast()
}

func (c *Conn) onDestroyed() {
	c.destroyed = true
	c.s = nil
	c.cond.Broadcast()
}
<|endoftext|>


<commit_before>package websocket

import (
	"bytes"
	"io"
	"net/url"
	"time"

	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/dom"
)

func beginHandlerOpen(ch chan error) func(ev js.Object) {
	return func(ev js.Object) {
		close(ch)
	}
}

func beginHandlerClose(ch chan error) func(ev js.Object) {
	return func(ev js.Object) {
		ch <- &js.Error{Object: ev}
		close(ch)
	}
}

// Dial opens a new WebSocket connection. It will block until the connection is
// established or fails to connect.
func Dial(url string) (*Conn, error) {
	ws, err := New(url)
	if err != nil {
		return nil, err
	}

	openCh := make(chan error, 1)

	// We have to use variables for the functions so that we can remove the
	// event handlers afterwards.
	openHandler := beginHandlerOpen(openCh)
	closeHandler := beginHandlerClose(openCh)

	ws.AddEventListener("open", false, openHandler)
	ws.AddEventListener("close", false, closeHandler)

	err, ok := <-openCh

	ws.RemoveEventListener("open", false, openHandler)
	ws.RemoveEventListener("close", false, closeHandler)

	if ok && err != nil {
		return nil, err
	}

	conn := &Conn{
		WebSocket: ws,
		ch:        make(chan *dom.MessageEvent, 1),
	}
	conn.Initialize()

	return conn, nil
}

// Conn is a high-level wrapper around WebSocket. It is intended to
// provide a net.TCPConn-like interface.
type Conn struct {
	*WebSocket

	ch      chan *dom.MessageEvent
	readBuf *bytes.Reader
}

func (c *Conn) onMessage(event js.Object) {
	go func() {
		c.ch <- dom.WrapEvent(event).(*dom.MessageEvent)
	}()
}

func (c *Conn) onClose(event js.Object) {
	go func() {
		// We queue nil to the end so that any messages received prior to
		// closing get handled first.
		c.ch <- nil
	}()
}

// Initialize adds all of the event handlers necessary for a Conn to function.
// It should never be called more than once and is already called if you used
// Dial to create the Conn.
func (c *Conn) Initialize() {
	// We need this so that received binary data is in ArrayBufferView format so
	// that it can easily be read.
	c.BinaryType = "arraybuffer"

	c.AddEventListener("message", false, c.onMessage)
	c.AddEventListener("close", false, c.onClose)
}

// receiveFrame receives one full frame from the WebSocket. It blocks until the
// frame is received.
func (c *Conn) receiveFrame() (*dom.MessageEvent, error) {
	item, ok := <-c.ch
	if !ok { // The channel has been closed
		return nil, io.EOF
	} else if item == nil {
		// See onClose for the explanation about sending a nil item.
		close(c.ch)
		return nil, io.EOF
	}
	return item, nil
}

func getFrameData(obj js.Object) []byte {
	// Check if it's an array buffer. If so, convert it to a Go byte slice.
	if constructor := obj.Get("constructor"); constructor == js.Global.Get("ArrayBuffer") {
		int8Array := js.Global.Get("Uint8Array").New(obj)
		return int8Array.Interface().([]byte)
	}

	return []byte(obj.Str())
}

func (c *Conn) Read(b []byte) (n int, err error) {
	// TODO(nightexcessive): Implement the deadline functions.

	if c.readBuf != nil {
		n, err = c.readBuf.Read(b)
		if err == io.EOF {
			c.readBuf = nil
			err = nil
		}
		// If we read nothing from the buffer, continue to trying to receive.
		// This saves us when the last Read call emptied the buffer and this
		// call triggers the EOF. There's probably a better way of doing this,
		// but I'm really tired.
		if n > 0 {
			return
		}
	}

	frame, err := c.receiveFrame()
	if err != nil {
		return 0, err
	}

	receivedBytes := getFrameData(frame.Data)

	n = copy(b, receivedBytes)
	// Fast path: The entire frame's contents have been copied into b.
	if n >= len(receivedBytes) {
		return
	}

	c.readBuf = bytes.NewReader(receivedBytes[n:])
	return
}

// Write writes the contents of b to the WebSocket using a binary opcode.
func (c *Conn) Write(b []byte) (n int, err error) {
	// []byte is converted to an (U)Int8Array by GopherJS, which fullfils the
	// ArrayBufferView definition.
	err = c.Send(b)
	if err != nil {
		return
	}
	n = len(b)
	return
}

// WriteString writes the contents of s to the WebSocket using a text frame
// opcode.
func (c *Conn) WriteString(s string) (n int, err error) {
	err = c.Send(s)
	if err != nil {
		return
	}
	n = len(s)
	return
}

// BUG(nightexcessive): We can't return net.Addr from Conn.LocalAddr and
// Conn.RemoteAddr because net.init() causes a panic due to attempts to make
// syscalls. See: https://github.com/gopherjs/gopherjs/issues/123

// LocalAddr would typically return the local network address, but due to
// limitations in the JavaScript API, it is unable to. Calling this method will
// cause a panic.
func (c *Conn) LocalAddr() *Addr {
	// BUG(nightexcessive): Conn.LocalAddr() panics because the underlying
	// JavaScript API has no way of figuring out the local address.

	// TODO(nightexcessive): Find a more graceful way to handle this
	panic("we are unable to implement websocket.Conn.LocalAddr() due to limitations in the underlying JavaScript API")
}

// RemoteAddr returns the remote network address, based on
// websocket.WebSocket.URL.
func (c *Conn) RemoteAddr() *Addr {
	wsURL, err := url.Parse(c.URL)
	if err != nil {
		// TODO(nightexcessive): Should we be panicking for this?
		panic(err)
	}
	return &Addr{wsURL}
}

// SetDeadline implements the net.Conn.SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetReadDeadline implements the net.Conn.SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetWriteDeadline implements the net.Conn.SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}
<commit_msg>In the process of testing, a few bugs were fixed. Dial also returns more informative errors.<commit_after>package websocket

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"time"

	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/dom"
)

func beginHandlerOpen(ch chan error, removeHandlers func()) func(ev js.Object) {
	return func(ev js.Object) {
		removeHandlers()
		close(ch)
	}
}

// closeError allows a CloseEvent to be used as an error.
type closeError struct {
	*dom.CloseEvent
}

func (e *closeError) Error() string {
	var cleanStmt string
	if e.WasClean {
		cleanStmt = "clean"
	} else {
		cleanStmt = "unclean"
	}
	return fmt.Sprintf("CloseEvent: (%s) (%d) %s", cleanStmt, e.Code, e.Reason)
}

func beginHandlerClose(ch chan error, removeHandlers func()) func(ev js.Object) {
	return func(ev js.Object) {
		removeHandlers()
		go func() {
			ce := dom.WrapEvent(ev).(*dom.CloseEvent)
			ch <- &closeError{CloseEvent: ce}
			close(ch)
		}()
	}
}

// Dial opens a new WebSocket connection. It will block until the connection is
// established or fails to connect.
func Dial(url string) (*Conn, error) {
	ws, err := New(url)
	if err != nil {
		return nil, err
	}
	conn := &Conn{
		WebSocket: ws,
		ch:        make(chan *dom.MessageEvent, 1),
	}
	conn.Initialize()

	openCh := make(chan error, 1)

	var (
		openHandler  func(ev js.Object)
		closeHandler func(ev js.Object)
	)

	// Handlers need to be removed to prevent a panic when the WebSocket closes
	// immediately and fires both open and close before they can be removed.
	// This way, handlers are removed before the channel is closed.
	removeHandlers := func() {
		ws.RemoveEventListener("open", false, openHandler)
		ws.RemoveEventListener("close", false, closeHandler)
	}

	// We have to use variables for the functions so that we can remove the
	// event handlers afterwards.
	openHandler = beginHandlerOpen(openCh, removeHandlers)
	closeHandler = beginHandlerClose(openCh, removeHandlers)

	ws.AddEventListener("open", false, openHandler)
	ws.AddEventListener("close", false, closeHandler)

	err, ok := <-openCh
	if ok && err != nil {
		return nil, err
	}

	return conn, nil
}

// Conn is a high-level wrapper around WebSocket. It is intended to
// provide a net.TCPConn-like interface.
type Conn struct {
	*WebSocket

	ch      chan *dom.MessageEvent
	readBuf *bytes.Reader
}

func (c *Conn) onMessage(event js.Object) {
	go func() {
		c.ch <- dom.WrapEvent(event).(*dom.MessageEvent)
	}()
}

func (c *Conn) onClose(event js.Object) {
	go func() {
		// We queue nil to the end so that any messages received prior to
		// closing get handled first.
		c.ch <- nil
	}()
}

// Initialize adds all of the event handlers necessary for a Conn to function.
// It should never be called more than once and is already called if you used
// Dial to create the Conn.
func (c *Conn) Initialize() {
	// We need this so that received binary data is in ArrayBufferView format so
	// that it can easily be read.
	c.BinaryType = "arraybuffer"

	c.AddEventListener("message", false, c.onMessage)
	c.AddEventListener("close", false, c.onClose)
}

// receiveFrame receives one full frame from the WebSocket. It blocks until the
// frame is received.
func (c *Conn) receiveFrame() (*dom.MessageEvent, error) {
	item, ok := <-c.ch
	if !ok { // The channel has been closed
		return nil, io.EOF
	} else if item == nil {
		// See onClose for the explanation about sending a nil item.
		close(c.ch)
		return nil, io.EOF
	}
	return item, nil
}

func getFrameData(obj js.Object) []byte {
	// Check if it's an array buffer. If so, convert it to a Go byte slice.
	if constructor := obj.Get("constructor"); constructor == js.Global.Get("ArrayBuffer") {
		int8Array := js.Global.Get("Uint8Array").New(obj)
		return int8Array.Interface().([]byte)
	}

	return []byte(obj.Str())
}

func (c *Conn) Read(b []byte) (n int, err error) {
	// TODO(nightexcessive): Implement the deadline functions.

	if c.readBuf != nil {
		n, err = c.readBuf.Read(b)
		if err == io.EOF {
			c.readBuf = nil
			err = nil
		}
		// If we read nothing from the buffer, continue to trying to receive.
		// This saves us when the last Read call emptied the buffer and this
		// call triggers the EOF. There's probably a better way of doing this,
		// but I'm really tired.
		if n > 0 {
			return
		}
	}

	frame, err := c.receiveFrame()
	if err != nil {
		return 0, err
	}

	receivedBytes := getFrameData(frame.Data)

	n = copy(b, receivedBytes)
	// Fast path: The entire frame's contents have been copied into b.
	if n >= len(receivedBytes) {
		return
	}

	c.readBuf = bytes.NewReader(receivedBytes[n:])
	return
}

// Write writes the contents of b to the WebSocket using a binary opcode.
func (c *Conn) Write(b []byte) (n int, err error) {
	// []byte is converted to an (U)Int8Array by GopherJS, which fullfils the
	// ArrayBufferView definition.
	err = c.Send(b)
	if err != nil {
		return
	}
	n = len(b)
	return
}

// WriteString writes the contents of s to the WebSocket using a text frame
// opcode.
func (c *Conn) WriteString(s string) (n int, err error) {
	err = c.Send(s)
	if err != nil {
		return
	}
	n = len(s)
	return
}

// BUG(nightexcessive): We can't return net.Addr from Conn.LocalAddr and
// Conn.RemoteAddr because net.init() causes a panic due to attempts to make
// syscalls. See: https://github.com/gopherjs/gopherjs/issues/123

// LocalAddr would typically return the local network address, but due to
// limitations in the JavaScript API, it is unable to. Calling this method will
// cause a panic.
func (c *Conn) LocalAddr() *Addr {
	// BUG(nightexcessive): Conn.LocalAddr() panics because the underlying
	// JavaScript API has no way of figuring out the local address.

	// TODO(nightexcessive): Find a more graceful way to handle this
	panic("we are unable to implement websocket.Conn.LocalAddr() due to limitations in the underlying JavaScript API")
}

// RemoteAddr returns the remote network address, based on
// websocket.WebSocket.URL.
func (c *Conn) RemoteAddr() *Addr {
	wsURL, err := url.Parse(c.URL)
	if err != nil {
		// TODO(nightexcessive): Should we be panicking for this?
		panic(err)
	}
	return &Addr{wsURL}
}

// SetDeadline implements the net.Conn.SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetReadDeadline implements the net.Conn.SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetWriteDeadline implements the net.Conn.SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}
<|endoftext|>


<commit_before>package styx

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net"

	"aqwari.net/net/styx/internal/qidpool"
	"aqwari.net/net/styx/internal/styxfile"
	"aqwari.net/net/styx/internal/threadsafe"
	"aqwari.net/net/styx/internal/tracing"
	"aqwari.net/net/styx/styxproto"

	"context"
)

var (
	errFidInUse     = errors.New("fid already in use")
	errTagInUse     = errors.New("tag in use")
	errNoFid        = errors.New("no such fid")
	errNotSupported = errors.New("not supported")
)

type fcall interface {
	styxproto.Msg
	Fid() uint32
}

// A note on identifiers (fids & tags)
//
// identifiers are chosen by the client, not by the server.  Therefore,
// it is important that the performance and behavior of a server does
// *not* change based on the fid or tag a client chooses. This is why
// a map is used; its performance is good, and doesn't change based
// on the input a client chooses (rather, it does not change in a way
// a client can predict).

// A conn receives and sends 9P messages across a single network connection.
// Multiple "sessions" may take place over a single connection. The conn
// struct contains the necessary information to route 9P messages to their
// established sessions.
type conn struct {
	// These wrap the network connection to read and write messages.
	*styxproto.Decoder
	*styxproto.Encoder

	// The Server a connection was spawned from. Contains configuration
	// settings and the authentication function, if any.
	srv *Server

	// The network connection itself. We expose it in the struct so that
	// it is available for transport-based auth and any timeouts we need
	// to implement.
	rwc io.ReadWriteCloser

	// This serves as the parent context for the context attached to all
	// requests.
	ctx context.Context

	// While srv.MaxSize holds the *desired* 9P protocol message
	// size, msize will contain the actual maximum negotiated with
	// the client, through a Tversion/Rversion exchange.
	msize int64

	// There is no "session id" in 9P. However, because all fids
	// for a connection must be derived from the fid established
	// in a Tattach call, any message that contains a fid can be
	// traced back to the original Tattach message.
	sessionFid *threadsafe.Map

	// Qids for the file tree, added on-demand.
	qidpool *qidpool.Pool

	// used to implement request cancellation when a Tflush
	// message is received.
	pendingReq *threadsafe.Map
}

func (c *conn) remoteAddr() net.Addr {
	type hasRemote interface {
		RemoteAddr() net.Addr
	}
	if nc, ok := c.rwc.(hasRemote); ok {
		return nc.RemoteAddr()
	}
	return nil
}

func (c *conn) sessionByFid(fid uint32) (*Session, bool) {
	if v, ok := c.sessionFid.Get(fid); ok {
		return v.(*Session), true
	}
	return nil, false
}

// Close the connection
func (c *conn) close() error {
	// Cancel all pending requests
	c.pendingReq.Do(func(m map[interface{}]interface{}) {
		for tag, cancel := range m {
			cancel.(context.CancelFunc)()
			delete(m, tag)
		}
	})

	// Close all open files and sessions
	c.sessionFid.Do(func(m map[interface{}]interface{}) {
		seen := make(map[*Session]struct{}, len(m))
		for k, v := range m {
			session := v.(*Session)
			if _, ok := seen[session]; !ok {
				seen[session] = struct{}{}
				session.endSession()
			}
			// Should probably let the GC take care of this
			delete(m, k)
		}
	})

	return c.rwc.Close()
}

func newConn(srv *Server, rwc io.ReadWriteCloser) *conn {
	var msize int64 = styxproto.DefaultMaxSize
	if srv.MaxSize > 0 {
		if srv.MaxSize > styxproto.MinBufSize {
			msize = srv.MaxSize
		} else {
			msize = styxproto.MinBufSize
		}
	}
	var enc *styxproto.Encoder
	var dec *styxproto.Decoder
	if srv.TraceLog != nil {
		enc = tracing.Encoder(rwc, func(m styxproto.Msg) {
			srv.TraceLog.Printf("← %03d %s", m.Tag(), m)
		})
		dec = tracing.Decoder(rwc, func(m styxproto.Msg) {
			srv.TraceLog.Printf("→ %03d %s", m.Tag(), m)
		})
	} else {
		enc = styxproto.NewEncoder(rwc)
		dec = styxproto.NewDecoder(rwc)
	}
	return &conn{
		Decoder:    dec,
		Encoder:    enc,
		srv:        srv,
		rwc:        rwc,
		ctx:        context.TODO(),
		msize:      msize,
		sessionFid: threadsafe.NewMap(),
		pendingReq: threadsafe.NewMap(),
		qidpool:    qidpool.New(),
	}
}

func (c *conn) qid(name string, qtype uint8) styxproto.Qid {
	return c.qidpool.Put(name, qtype)
}

// All request contexts must have their cancel functions
// called, to free up resources in the context. Returns false
// if the tag is already cancelled
func (c *conn) clearTag(tag uint16) bool {
	var cancel context.CancelFunc
	if c.pendingReq.Fetch(tag, &cancel) {
		cancel()
		c.pendingReq.Del(tag)
		return true
	}
	return false
}

// runs in its own goroutine, one per connection.
func (c *conn) serve() {
	defer c.close()

	if !c.acceptTversion() {
		return
	}

	for c.Next() && c.Encoder.Err() == nil {
		if !c.handleMessage(c.Msg()) {
			break
		}
	}
	if err := c.Encoder.Err(); err != nil {
		c.srv.logf("write error: %s", err)
	}
	c.srv.logf("closed connection from %s", c.remoteAddr())
}

func (c *conn) handleMessage(m styxproto.Msg) bool {
	if _, ok := c.pendingReq.Get(m.Tag()); ok {
		c.srv.logf("fatal: client re-used existing tag %d", m.Tag())
		return false
	}
	ctx, cancel := context.WithCancel(c.ctx)
	c.pendingReq.Put(m.Tag(), cancel)

	switch m := m.(type) {
	case styxproto.Tauth:
		return c.handleTauth(ctx, m)
	case styxproto.Tattach:
		return c.handleTattach(ctx, m)
	case styxproto.Tflush:
		return c.handleTflush(ctx, m)
	case fcall:
		return c.handleFcall(ctx, m)
	case styxproto.BadMessage:
		c.srv.logf("got bad message from %s: %s", c.remoteAddr(), m.Err)
		c.clearTag(m.Tag())
		c.Rerror(m.Tag(), "bad message: %s", m.Err)
		c.Flush()
		return true
	default:
		c.Rerror(m.Tag(), "unexpected %T message", m)
		c.Flush()
		return true
	}
}

// This is the first thing we do on a new connection. The first
// message a client sends *must* be a Tversion message.
func (c *conn) acceptTversion() bool {
	c.Encoder.MaxSize = c.msize
	c.Decoder.MaxSize = c.msize

	for c.Next() && c.Encoder.Err() == nil {
		tver, ok := c.Msg().(styxproto.Tversion)
		if !ok {
			c.Rerror(tver.Tag(), "need Tversion")
			break
		}
		msize := tver.Msize()
		if msize < styxproto.MinBufSize {
			c.Rerror(tver.Tag(), "buffer too small")
			break
		}
		if msize < c.msize {
			c.msize = msize
			c.Encoder.MaxSize = msize
			c.Decoder.MaxSize = msize
		}
		if !bytes.HasPrefix(tver.Version(), []byte("9P2000")) {
			c.Rversion(uint32(c.msize), "unknown")
			c.Flush()
		} else {
			c.Rversion(uint32(c.msize), "9P2000")
			c.Flush()
			return true
		}
	}
	c.Flush()
	c.srv.logf("%s version negotiation failed", c.remoteAddr())
	return false
}

// NOTE(droyo) consider a scenario where a malicious actor connects
// to the server that repeatedly spams Tauth requests. It can quickly
// use up resources on the server. Consider the following measures:
//
// - rate-limiting Tauth requests
// - Setting a per-connection session limit
// - close connections that have not established a session in N seconds
func (c *conn) handleTauth(ctx context.Context, m styxproto.Tauth) bool {
	defer c.Flush()
	if c.srv.Auth == nil {
		c.clearTag(m.Tag())
		c.Rerror(m.Tag(), "%s", errNotSupported)
		return true
	}
	if _, ok := c.sessionFid.Get(m.Afid()); ok {
		c.clearTag(m.Tag())
		c.Rerror(m.Tag(), "fid %x in use", m.Afid())
		return true
	}
	client, server := net.Pipe()
	ch := &Channel{
		Context:         c.ctx,
		ReadWriteCloser: server,
	}
	rwc, err := styxfile.New(client)
	if err != nil {
		// This should never happen
		panic(err)
	}
	s := newSession(c, m)
	go func() {
		s.authC <- c.srv.Auth(ch, s.User, s.Access)
		close(s.authC)
	}()

	c.sessionFid.Put(m.Afid(), s)
	s.files.Put(m.Afid(), file{rwc: rwc, auth: true})
	s.IncRef()
	return true
}

func (c *conn) handleTattach(ctx context.Context, m styxproto.Tattach) bool {
	defer c.Flush()
	var handler Handler = HandlerFunc(func(s *Session) {
		for s.Next() {
		}
	})
	if c.srv.Handler != nil {
		handler = c.srv.Handler
	}
	var s *Session
	if c.srv.Auth == nil {
		s = newSession(c, m)
	} else {
		// TODO(droyo) when a transport-based authentication scheme
		// is in use, the client should not have to do a Tauth request.
		// We should call the Auth handler if Afid is NOFID, passing it
		// a util.BlackHole.
		if !c.sessionFid.Fetch(s, m.Afid()) {
			c.clearTag(m.Tag())
			c.Rerror(m.Tag(), "invalid afid %x", m.Afid())
			return true
		}
		// From attach(5): The same validated afid may be used for
		// multiple attach messages with the same uname and aname.
		if s.User != string(m.Uname()) || s.Access != string(m.Aname()) {
			c.clearTag(m.Tag())
			c.Rerror(m.Tag(), "afid mismatch for %s on %s", m.Uname(), m.Aname())
			return true
		}
		if err := <-s.authC; err != nil {
			c.clearTag(m.Tag())
			c.Rerror(m.Tag(), "auth failed: %s", err)
			return true
		}
	}
	go func() {
		handler.Serve9P(s)
		s.cleanupHandler()
	}()
	c.sessionFid.Put(m.Fid(), s)
	s.IncRef()
	s.files.Put(m.Fid(), file{name: "/", rwc: nil})
	c.clearTag(m.Tag())
	c.Rattach(m.Tag(), c.qid(".", styxproto.QTDIR))
	return true
}

func (c *conn) handleTflush(ctx context.Context, m styxproto.Tflush) bool {
	c.clearTag(m.Oldtag())

	if c.clearTag(m.Tag()) {
		c.Rflush(m.Tag())
	}
	c.Flush()
	return true
}

func (c *conn) handleFcall(ctx context.Context, msg fcall) bool {
	s, ok := c.sessionByFid(msg.Fid())
	if !ok {
		c.clearTag(msg.Tag())
		c.Rerror(msg.Tag(), "%s", errNoFid)
		c.Flush()
		return true
	}

	file, ok := s.fetchFile(msg.Fid())
	if !ok {
		panic("bug: fid in session map, but no file associated")
	}

	// NOTE(droyo) on security and anonymous users: On a server with
	// authentication enabled, a client can only ever establish a handle
	// to the auth file.  At this point, we have checked that the fid
	// is valid, so *file can only be an auth file if the user has not
	// completed a Tattach.
	if file.auth {
		// Limit the number of request handlers we have to
		// audit.
		switch msg := msg.(type) {
		case styxproto.Twrite:
		case styxproto.Tread:
		case styxproto.Tstat:
		case styxproto.Tclunk:
		default:
			c.clearTag(msg.Tag())
			c.Rerror(msg.Tag(), "%T not allowed on afid", msg)
			c.Flush()
			return true
		}
	}

	switch msg := msg.(type) {
	case styxproto.Twalk:
		return s.handleTwalk(ctx, msg, file)
	case styxproto.Topen:
		return s.handleTopen(ctx, msg, file)
	case styxproto.Tcreate:
		return s.handleTcreate(ctx, msg, file)
	case styxproto.Tread:
		return s.handleTread(ctx, msg, file)
	case styxproto.Twrite:
		return s.handleTwrite(ctx, msg, file)
	case styxproto.Tremove:
		return s.handleTremove(ctx, msg, file)
	case styxproto.Tstat:
		return s.handleTstat(ctx, msg, file)
	case styxproto.Twstat:
		return s.handleTwstat(ctx, msg, file)
	case styxproto.Tclunk:
		return s.handleTclunk(ctx, msg, file)
	}
	// invalid messages should have been caught
	// in the conn.serve loop, so we should never
	// reach this point.
	panic(fmt.Errorf("unhandled message type %T", msg))
}
<commit_msg>Name the root directory consistently<commit_after>package styx

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net"

	"aqwari.net/net/styx/internal/qidpool"
	"aqwari.net/net/styx/internal/styxfile"
	"aqwari.net/net/styx/internal/threadsafe"
	"aqwari.net/net/styx/internal/tracing"
	"aqwari.net/net/styx/styxproto"

	"context"
)

var (
	errFidInUse     = errors.New("fid already in use")
	errTagInUse     = errors.New("tag in use")
	errNoFid        = errors.New("no such fid")
	errNotSupported = errors.New("not supported")
)

type fcall interface {
	styxproto.Msg
	Fid() uint32
}

// A note on identifiers (fids & tags)
//
// identifiers are chosen by the client, not by the server.  Therefore,
// it is important that the performance and behavior of a server does
// *not* change based on the fid or tag a client chooses. This is why
// a map is used; its performance is good, and doesn't change based
// on the input a client chooses (rather, it does not change in a way
// a client can predict).

// A conn receives and sends 9P messages across a single network connection.
// Multiple "sessions" may take place over a single connection. The conn
// struct contains the necessary information to route 9P messages to their
// established sessions.
type conn struct {
	// These wrap the network connection to read and write messages.
	*styxproto.Decoder
	*styxproto.Encoder

	// The Server a connection was spawned from. Contains configuration
	// settings and the authentication function, if any.
	srv *Server

	// The network connection itself. We expose it in the struct so that
	// it is available for transport-based auth and any timeouts we need
	// to implement.
	rwc io.ReadWriteCloser

	// This serves as the parent context for the context attached to all
	// requests.
	ctx context.Context

	// While srv.MaxSize holds the *desired* 9P protocol message
	// size, msize will contain the actual maximum negotiated with
	// the client, through a Tversion/Rversion exchange.
	msize int64

	// There is no "session id" in 9P. However, because all fids
	// for a connection must be derived from the fid established
	// in a Tattach call, any message that contains a fid can be
	// traced back to the original Tattach message.
	sessionFid *threadsafe.Map

	// Qids for the file tree, added on-demand.
	qidpool *qidpool.Pool

	// used to implement request cancellation when a Tflush
	// message is received.
	pendingReq *threadsafe.Map
}

func (c *conn) remoteAddr() net.Addr {
	type hasRemote interface {
		RemoteAddr() net.Addr
	}
	if nc, ok := c.rwc.(hasRemote); ok {
		return nc.RemoteAddr()
	}
	return nil
}

func (c *conn) sessionByFid(fid uint32) (*Session, bool) {
	if v, ok := c.sessionFid.Get(fid); ok {
		return v.(*Session), true
	}
	return nil, false
}

// Close the connection
func (c *conn) close() error {
	// Cancel all pending requests
	c.pendingReq.Do(func(m map[interface{}]interface{}) {
		for tag, cancel := range m {
			cancel.(context.CancelFunc)()
			delete(m, tag)
		}
	})

	// Close all open files and sessions
	c.sessionFid.Do(func(m map[interface{}]interface{}) {
		seen := make(map[*Session]struct{}, len(m))
		for k, v := range m {
			session := v.(*Session)
			if _, ok := seen[session]; !ok {
				seen[session] = struct{}{}
				session.endSession()
			}
			// Should probably let the GC take care of this
			delete(m, k)
		}
	})

	return c.rwc.Close()
}

func newConn(srv *Server, rwc io.ReadWriteCloser) *conn {
	var msize int64 = styxproto.DefaultMaxSize
	if srv.MaxSize > 0 {
		if srv.MaxSize > styxproto.MinBufSize {
			msize = srv.MaxSize
		} else {
			msize = styxproto.MinBufSize
		}
	}
	var enc *styxproto.Encoder
	var dec *styxproto.Decoder
	if srv.TraceLog != nil {
		enc = tracing.Encoder(rwc, func(m styxproto.Msg) {
			srv.TraceLog.Printf("← %03d %s", m.Tag(), m)
		})
		dec = tracing.Decoder(rwc, func(m styxproto.Msg) {
			srv.TraceLog.Printf("→ %03d %s", m.Tag(), m)
		})
	} else {
		enc = styxproto.NewEncoder(rwc)
		dec = styxproto.NewDecoder(rwc)
	}
	return &conn{
		Decoder:    dec,
		Encoder:    enc,
		srv:        srv,
		rwc:        rwc,
		ctx:        context.TODO(),
		msize:      msize,
		sessionFid: threadsafe.NewMap(),
		pendingReq: threadsafe.NewMap(),
		qidpool:    qidpool.New(),
	}
}

func (c *conn) qid(name string, qtype uint8) styxproto.Qid {
	return c.qidpool.Put(name, qtype)
}

// All request contexts must have their cancel functions
// called, to free up resources in the context. Returns false
// if the tag is already cancelled
func (c *conn) clearTag(tag uint16) bool {
	var cancel context.CancelFunc
	if c.pendingReq.Fetch(tag, &cancel) {
		cancel()
		c.pendingReq.Del(tag)
		return true
	}
	return false
}

// runs in its own goroutine, one per connection.
func (c *conn) serve() {
	defer c.close()

	if !c.acceptTversion() {
		return
	}

	for c.Next() && c.Encoder.Err() == nil {
		if !c.handleMessage(c.Msg()) {
			break
		}
	}
	if err := c.Encoder.Err(); err != nil {
		c.srv.logf("write error: %s", err)
	}
	c.srv.logf("closed connection from %s", c.remoteAddr())
}

func (c *conn) handleMessage(m styxproto.Msg) bool {
	if _, ok := c.pendingReq.Get(m.Tag()); ok {
		c.srv.logf("fatal: client re-used existing tag %d", m.Tag())
		return false
	}
	ctx, cancel := context.WithCancel(c.ctx)
	c.pendingReq.Put(m.Tag(), cancel)

	switch m := m.(type) {
	case styxproto.Tauth:
		return c.handleTauth(ctx, m)
	case styxproto.Tattach:
		return c.handleTattach(ctx, m)
	case styxproto.Tflush:
		return c.handleTflush(ctx, m)
	case fcall:
		return c.handleFcall(ctx, m)
	case styxproto.BadMessage:
		c.srv.logf("got bad message from %s: %s", c.remoteAddr(), m.Err)
		c.clearTag(m.Tag())
		c.Rerror(m.Tag(), "bad message: %s", m.Err)
		c.Flush()
		return true
	default:
		c.Rerror(m.Tag(), "unexpected %T message", m)
		c.Flush()
		return true
	}
}

// This is the first thing we do on a new connection. The first
// message a client sends *must* be a Tversion message.
func (c *conn) acceptTversion() bool {
	c.Encoder.MaxSize = c.msize
	c.Decoder.MaxSize = c.msize

	for c.Next() && c.Encoder.Err() == nil {
		tver, ok := c.Msg().(styxproto.Tversion)
		if !ok {
			c.Rerror(tver.Tag(), "need Tversion")
			break
		}
		msize := tver.Msize()
		if msize < styxproto.MinBufSize {
			c.Rerror(tver.Tag(), "buffer too small")
			break
		}
		if msize < c.msize {
			c.msize = msize
			c.Encoder.MaxSize = msize
			c.Decoder.MaxSize = msize
		}
		if !bytes.HasPrefix(tver.Version(), []byte("9P2000")) {
			c.Rversion(uint32(c.msize), "unknown")
			c.Flush()
		} else {
			c.Rversion(uint32(c.msize), "9P2000")
			c.Flush()
			return true
		}
	}
	c.Flush()
	c.srv.logf("%s version negotiation failed", c.remoteAddr())
	return false
}

// NOTE(droyo) consider a scenario where a malicious actor connects
// to the server that repeatedly spams Tauth requests. It can quickly
// use up resources on the server. Consider the following measures:
//
// - rate-limiting Tauth requests
// - Setting a per-connection session limit
// - close connections that have not established a session in N seconds
func (c *conn) handleTauth(ctx context.Context, m styxproto.Tauth) bool {
	defer c.Flush()
	if c.srv.Auth == nil {
		c.clearTag(m.Tag())
		c.Rerror(m.Tag(), "%s", errNotSupported)
		return true
	}
	if _, ok := c.sessionFid.Get(m.Afid()); ok {
		c.clearTag(m.Tag())
		c.Rerror(m.Tag(), "fid %x in use", m.Afid())
		return true
	}
	client, server := net.Pipe()
	ch := &Channel{
		Context:         c.ctx,
		ReadWriteCloser: server,
	}
	rwc, err := styxfile.New(client)
	if err != nil {
		// This should never happen
		panic(err)
	}
	s := newSession(c, m)
	go func() {
		s.authC <- c.srv.Auth(ch, s.User, s.Access)
		close(s.authC)
	}()

	c.sessionFid.Put(m.Afid(), s)
	s.files.Put(m.Afid(), file{rwc: rwc, auth: true})
	s.IncRef()
	return true
}

func (c *conn) handleTattach(ctx context.Context, m styxproto.Tattach) bool {
	defer c.Flush()
	var handler Handler = HandlerFunc(func(s *Session) {
		for s.Next() {
		}
	})
	if c.srv.Handler != nil {
		handler = c.srv.Handler
	}
	var s *Session
	if c.srv.Auth == nil {
		s = newSession(c, m)
	} else {
		// TODO(droyo) when a transport-based authentication scheme
		// is in use, the client should not have to do a Tauth request.
		// We should call the Auth handler if Afid is NOFID, passing it
		// a util.BlackHole.
		if !c.sessionFid.Fetch(s, m.Afid()) {
			c.clearTag(m.Tag())
			c.Rerror(m.Tag(), "invalid afid %x", m.Afid())
			return true
		}
		// From attach(5): The same validated afid may be used for
		// multiple attach messages with the same uname and aname.
		if s.User != string(m.Uname()) || s.Access != string(m.Aname()) {
			c.clearTag(m.Tag())
			c.Rerror(m.Tag(), "afid mismatch for %s on %s", m.Uname(), m.Aname())
			return true
		}
		if err := <-s.authC; err != nil {
			c.clearTag(m.Tag())
			c.Rerror(m.Tag(), "auth failed: %s", err)
			return true
		}
	}
	go func() {
		handler.Serve9P(s)
		s.cleanupHandler()
	}()
	c.sessionFid.Put(m.Fid(), s)
	s.IncRef()
	s.files.Put(m.Fid(), file{name: "/", rwc: nil})
	c.clearTag(m.Tag())
	c.Rattach(m.Tag(), c.qid("/", styxproto.QTDIR))
	return true
}

func (c *conn) handleTflush(ctx context.Context, m styxproto.Tflush) bool {
	c.clearTag(m.Oldtag())

	if c.clearTag(m.Tag()) {
		c.Rflush(m.Tag())
	}
	c.Flush()
	return true
}

func (c *conn) handleFcall(ctx context.Context, msg fcall) bool {
	s, ok := c.sessionByFid(msg.Fid())
	if !ok {
		c.clearTag(msg.Tag())
		c.Rerror(msg.Tag(), "%s", errNoFid)
		c.Flush()
		return true
	}

	file, ok := s.fetchFile(msg.Fid())
	if !ok {
		panic("bug: fid in session map, but no file associated")
	}

	// NOTE(droyo) on security and anonymous users: On a server with
	// authentication enabled, a client can only ever establish a handle
	// to the auth file.  At this point, we have checked that the fid
	// is valid, so *file can only be an auth file if the user has not
	// completed a Tattach.
	if file.auth {
		// Limit the number of request handlers we have to
		// audit.
		switch msg := msg.(type) {
		case styxproto.Twrite:
		case styxproto.Tread:
		case styxproto.Tstat:
		case styxproto.Tclunk:
		default:
			c.clearTag(msg.Tag())
			c.Rerror(msg.Tag(), "%T not allowed on afid", msg)
			c.Flush()
			return true
		}
	}

	switch msg := msg.(type) {
	case styxproto.Twalk:
		return s.handleTwalk(ctx, msg, file)
	case styxproto.Topen:
		return s.handleTopen(ctx, msg, file)
	case styxproto.Tcreate:
		return s.handleTcreate(ctx, msg, file)
	case styxproto.Tread:
		return s.handleTread(ctx, msg, file)
	case styxproto.Twrite:
		return s.handleTwrite(ctx, msg, file)
	case styxproto.Tremove:
		return s.handleTremove(ctx, msg, file)
	case styxproto.Tstat:
		return s.handleTstat(ctx, msg, file)
	case styxproto.Twstat:
		return s.handleTwstat(ctx, msg, file)
	case styxproto.Tclunk:
		return s.handleTclunk(ctx, msg, file)
	}
	// invalid messages should have been caught
	// in the conn.serve loop, so we should never
	// reach this point.
	panic(fmt.Errorf("unhandled message type %T", msg))
}
<|endoftext|>


<commit_before>package ice

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

func init() {
	LoadConfig()
}

//parse json from reader
func ParseJSON(reader io.Reader, out interface{}) error {
	d := json.NewDecoder(reader)
	err := d.Decode(&out)
	if err != nil {
		return err
	}
	return nil
}

//encode json
func EncodeJSON(writer io.Writer, data interface{}) error {
	e := json.NewEncoder(writer)
	return e.Encode(data)
}

func Start(host string, notfound http.HandlerFunc) error {
	http.HandleFunc("/connect", socketLoop)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		m, msg := makeFromFactory(strings.ToLower(r.Method), r.URL.Path)
		if msg == nil {
			if notfound != nil {
				notfound(w, r)
			} else {
				ServeAsset(w, r)
			}
			return
		}
		handleAPI(r.URL.Path, msg, w, r, m)
	})
	log.Println("Listening at " + host)
	return http.ListenAndServe(host, nil)
}

func ServeAsset(w http.ResponseWriter, r *http.Request) {
	if LoadAsset == nil {
		http.NotFound(w, r)
		return
	}
	path := strings.Trim(r.URL.Path, "/")
	if path == "" {
		path = "index.html"
	}
	data, err := LoadAsset(path)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	http.ServeContent(w, r, r.URL.Path, time.Now(), bytes.NewReader(data))
}

type IceError struct {
	Message string
	Code    int
}

func (r *IceError) Execute(conn Conn) {
	http.Error(conn.ResponseWriter(), r.Message, r.Code)
}

func ServerError(msg string) IceError {
	return IceError{msg, 500}
}

func NotFoundError(msg string) IceError {
	return IceError{msg, 404}
}

func ForbiddenError(msg string) IceError {
	return IceError{msg, 403}
}
<commit_msg>Make error funcs (ServerError, NotFoundError, For, ForbiddenError) return pointer to IceError to support Response interface<commit_after>package ice

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

func init() {
	LoadConfig()
}

//parse json from reader
func ParseJSON(reader io.Reader, out interface{}) error {
	d := json.NewDecoder(reader)
	err := d.Decode(&out)
	if err != nil {
		return err
	}
	return nil
}

//encode json
func EncodeJSON(writer io.Writer, data interface{}) error {
	e := json.NewEncoder(writer)
	return e.Encode(data)
}

func Start(host string, notfound http.HandlerFunc) error {
	http.HandleFunc("/connect", socketLoop)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		m, msg := makeFromFactory(strings.ToLower(r.Method), r.URL.Path)
		if msg == nil {
			if notfound != nil {
				notfound(w, r)
			} else {
				ServeAsset(w, r)
			}
			return
		}
		handleAPI(r.URL.Path, msg, w, r, m)
	})
	log.Println("Listening at " + host)
	return http.ListenAndServe(host, nil)
}

func ServeAsset(w http.ResponseWriter, r *http.Request) {
	if LoadAsset == nil {
		http.NotFound(w, r)
		return
	}
	path := strings.Trim(r.URL.Path, "/")
	if path == "" {
		path = "index.html"
	}
	data, err := LoadAsset(path)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	http.ServeContent(w, r, r.URL.Path, time.Now(), bytes.NewReader(data))
}

type IceError struct {
	Message string
	Code    int
}

func (r *IceError) Execute(conn Conn) {
	http.Error(conn.ResponseWriter(), r.Message, r.Code)
}

func ServerError(msg string) *IceError {
	return &IceError{msg, 500}
}

func NotFoundError(msg string) *IceError {
	return &IceError{msg, 404}
}

func ForbiddenError(msg string) *IceError {
	return &IceError{msg, 403}
}
<|endoftext|>