<commit_before>package io

import (
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"os"
)

// gadgetHeader is the formatting for meta-information used by Gadget 2.
type lGadget2Header struct {
	NPart                                     [6]uint32
	Mass                                      [6]float64
	Time, Redshift                            float64
	FlagSfr, FlagFeedback                     int32
	NPartTotal                                [6]uint32
	FlagCooling, NumFiles                     int32
	BoxSize, Omega0, OmegaLambda, HubbleParam float64
	FlagStellarAge, HashTabSize               int32

	Padding [88]byte
}

func (gh *lGadget2Header) postprocess(xs [][3]float32, out *Header) {
	// Assumes the catalog has already been checked for corruption.

	out.N = int64(gh.NPart[1] + gh.NPart[0]<<32)
	out.TotalWidth = gh.BoxSize

	out.Cosmo.Z = gh.Redshift
	out.Cosmo.OmegaM = gh.Omega0
	out.Cosmo.OmegaL = gh.OmegaLambda
	out.Cosmo.H100 = gh.HubbleParam

	out.Origin, out.Width = boundingBox(xs, gh.BoxSize)
}

// readInt32 returns single 32-bit interger from the given file using the
// given endianness.
func readInt32(r io.Reader, order binary.ByteOrder) int32 {
	var n int32
	if err := binary.Read(r, order, &n); err != nil {
		panic(err)
	}
	return n
}

func readLGadget2Header(
	path string, order binary.ByteOrder, out *lGadget2Header,
) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	_ = readInt32(f, order)
	err = binary.Read(f, binary.LittleEndian, out)
	return err
}

func (buf *LGadget2Buffer) readLGadget2Particles(
	path string,
	order binary.ByteOrder,
	xsBuf [][3]float32,
	msBuf []float32,
) (xs [][3]float32, ms []float32, err error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, nil, err
	}
	defer f.Close()

	gh := &lGadget2Header{}

	_ = readInt32(f, order)
	binary.Read(f, binary.LittleEndian, gh)
	_ = readInt32(f, order)
	count := int(gh.NPart[1] + gh.NPart[0]<<32)
	xsBuf = expandVectors(xsBuf[:0], count)

	_ = readInt32(f, order)
	readVecAsByte(f, order, xsBuf)
	//_ = readInt32(f, order)

	tw := float32(gh.BoxSize)
	for i := range xsBuf {
		for j := 0; j < 3; j++ {
			if xsBuf[i][j] < 0 {
				xsBuf[i][j] += tw
			} else if xsBuf[i][j] >= tw {
				xsBuf[i][j] -= tw
			}

			if math.IsNaN(float64(xsBuf[i][j])) ||
				math.IsInf(float64(xsBuf[i][j]), 0) ||
				xsBuf[i][j] < -tw || xsBuf[i][j] > 2*tw {

				return nil, nil, fmt.Errorf(
					"Corruption detected in the file %s. I can't analyze it.",
					path,
				)
			}
		}
	}

	msBuf = expandScalars(msBuf, count)
	for i := range msBuf {
		msBuf[i] = buf.mass
	}

	return xsBuf, msBuf, nil
}

func expandVectors(vecs [][3]float32, n int) [][3]float32 {
	switch {
	case cap(vecs) <= n:
		return vecs[:n]
	case int(float64(cap(vecs))*1.5) > n:
		return append(vecs[:cap(vecs)],
			make([][3]float32, n-cap(vecs))...)
	default:
		return make([][3]float32, n)
	}
}

func expandScalars(scalars []float32, n int) []float32 {
	switch {
	case cap(scalars) <= n:
		return scalars[:n]
	case int(float64(cap(scalars))*1.5) > n:
		return append(scalars[:cap(scalars)],
			make([]float32, n-cap(scalars))...)
	default:
		return make([]float32, n)
	}
}

type LGadget2Buffer struct {
	open  bool
	order binary.ByteOrder
	hd    lGadget2Header
	mass  float32
	xs    [][3]float32
	ms    []float32
}

func NewLGadget2Buffer(path, orderFlag string) (VectorBuffer, error) {
	var order binary.ByteOrder = binary.LittleEndian
	switch orderFlag {
	case "LittleEndian":
	case "BigEndian":
		order = binary.BigEndian
	case "SystemOrder":
		if !IsSysOrder(order) {
			order = binary.BigEndian
		}
	}

	buf := &LGadget2Buffer{order: order}
	err := readLGadget2Header(path, order, &buf.hd)
	if err != nil {
		return nil, err
	}

	c := CosmologyHeader{
		Z: buf.hd.Redshift, OmegaM: buf.hd.Omega0,
		OmegaL: buf.hd.OmegaLambda, H100: buf.hd.HubbleParam,
	}
	totCount := int64(buf.hd.NPartTotal[1] + buf.hd.NPartTotal[0]<<32)
	buf.mass = calcUniformMass(totCount, buf.hd.BoxSize, c)

	return buf, nil
}

func (buf *LGadget2Buffer) Read(fname string) ([][3]float32, []float32, error) {
	if buf.open {
		panic("Buffer already open.")
	}
	buf.open = true

	var err error
	buf.xs, buf.ms, err = buf.readLGadget2Particles(
		fname, buf.order, buf.xs, buf.ms,
	)

	return buf.xs, buf.ms, err
}

func (buf *LGadget2Buffer) Close() {
	if !buf.open {
		panic("Buffer not open.")
	}
	buf.open = false
}

func (buf *LGadget2Buffer) IsOpen() bool {
	return buf.open
}

func (buf *LGadget2Buffer) ReadHeader(fname string, out *Header) error {

	err := readLGadget2Header(fname, buf.order, &buf.hd)
	if err != nil {
		return err
	}
	xs, _, err := buf.Read(fname)
	if err != nil {
		return err
	}

	buf.hd.postprocess(xs, out)

	return nil
}

func (buf *LGadget2Buffer) MinMass() float32 { return buf.mass }
<commit_msg>Corrected conditional error in expandVectors()<commit_after>package io

import (
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"os"
)

// gadgetHeader is the formatting for meta-information used by Gadget 2.
type lGadget2Header struct {
	NPart                                     [6]uint32
	Mass                                      [6]float64
	Time, Redshift                            float64
	FlagSfr, FlagFeedback                     int32
	NPartTotal                                [6]uint32
	FlagCooling, NumFiles                     int32
	BoxSize, Omega0, OmegaLambda, HubbleParam float64
	FlagStellarAge, HashTabSize               int32

	Padding [88]byte
}

func (gh *lGadget2Header) postprocess(xs [][3]float32, out *Header) {
	// Assumes the catalog has already been checked for corruption.

	out.N = int64(gh.NPart[1] + gh.NPart[0]<<32)
	out.TotalWidth = gh.BoxSize

	out.Cosmo.Z = gh.Redshift
	out.Cosmo.OmegaM = gh.Omega0
	out.Cosmo.OmegaL = gh.OmegaLambda
	out.Cosmo.H100 = gh.HubbleParam

	out.Origin, out.Width = boundingBox(xs, gh.BoxSize)
}

// readInt32 returns single 32-bit interger from the given file using the
// given endianness.
func readInt32(r io.Reader, order binary.ByteOrder) int32 {
	var n int32
	if err := binary.Read(r, order, &n); err != nil {
		panic(err)
	}
	return n
}

func readLGadget2Header(
	path string, order binary.ByteOrder, out *lGadget2Header,
) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	_ = readInt32(f, order)
	err = binary.Read(f, binary.LittleEndian, out)
	return err
}

func (buf *LGadget2Buffer) readLGadget2Particles(
	path string,
	order binary.ByteOrder,
	xsBuf [][3]float32,
	msBuf []float32,
) (xs [][3]float32, ms []float32, err error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, nil, err
	}
	defer f.Close()

	gh := &lGadget2Header{}

	_ = readInt32(f, order)
	binary.Read(f, binary.LittleEndian, gh)
	_ = readInt32(f, order)
	count := int(gh.NPart[1] + gh.NPart[0]<<32)
	xsBuf = expandVectors(xsBuf[:0], count)

	_ = readInt32(f, order)
	readVecAsByte(f, order, xsBuf)
	//_ = readInt32(f, order)

	tw := float32(gh.BoxSize)
	for i := range xsBuf {
		for j := 0; j < 3; j++ {
			if xsBuf[i][j] < 0 {
				xsBuf[i][j] += tw
			} else if xsBuf[i][j] >= tw {
				xsBuf[i][j] -= tw
			}

			if math.IsNaN(float64(xsBuf[i][j])) ||
				math.IsInf(float64(xsBuf[i][j]), 0) ||
				xsBuf[i][j] < -tw || xsBuf[i][j] > 2*tw {

				return nil, nil, fmt.Errorf(
					"Corruption detected in the file %s. I can't analyze it.",
					path,
				)
			}
		}
	}

	msBuf = expandScalars(msBuf, count)
	for i := range msBuf {
		msBuf[i] = buf.mass
	}

	return xsBuf, msBuf, nil
}

func expandVectors(vecs [][3]float32, n int) [][3]float32 {
	switch {
	case cap(vecs) >= n:
		return vecs[:n]
	case int(float64(cap(vecs))*1.5) > n:
		return append(vecs[:cap(vecs)],
			make([][3]float32, n-cap(vecs))...)
	default:
		return make([][3]float32, n)
	}
}

func expandScalars(scalars []float32, n int) []float32 {
	switch {
	case cap(scalars) >= n:
		return scalars[:n]
	case int(float64(cap(scalars))*1.5) > n:
		return append(scalars[:cap(scalars)],
			make([]float32, n-cap(scalars))...)
	default:
		return make([]float32, n)
	}
}

type LGadget2Buffer struct {
	open  bool
	order binary.ByteOrder
	hd    lGadget2Header
	mass  float32
	xs    [][3]float32
	ms    []float32
}

func NewLGadget2Buffer(path, orderFlag string) (VectorBuffer, error) {
	var order binary.ByteOrder = binary.LittleEndian
	switch orderFlag {
	case "LittleEndian":
	case "BigEndian":
		order = binary.BigEndian
	case "SystemOrder":
		if !IsSysOrder(order) {
			order = binary.BigEndian
		}
	}

	buf := &LGadget2Buffer{order: order}
	err := readLGadget2Header(path, order, &buf.hd)
	if err != nil {
		return nil, err
	}

	c := CosmologyHeader{
		Z: buf.hd.Redshift, OmegaM: buf.hd.Omega0,
		OmegaL: buf.hd.OmegaLambda, H100: buf.hd.HubbleParam,
	}
	totCount := int64(buf.hd.NPartTotal[1] + buf.hd.NPartTotal[0]<<32)
	buf.mass = calcUniformMass(totCount, buf.hd.BoxSize, c)

	return buf, nil
}

func (buf *LGadget2Buffer) Read(fname string) ([][3]float32, []float32, error) {
	if buf.open {
		panic("Buffer already open.")
	}
	buf.open = true

	var err error
	buf.xs, buf.ms, err = buf.readLGadget2Particles(
		fname, buf.order, buf.xs, buf.ms,
	)

	return buf.xs, buf.ms, err
}

func (buf *LGadget2Buffer) Close() {
	if !buf.open {
		panic("Buffer not open.")
	}
	buf.open = false
}

func (buf *LGadget2Buffer) IsOpen() bool {
	return buf.open
}

func (buf *LGadget2Buffer) ReadHeader(fname string, out *Header) error {

	err := readLGadget2Header(fname, buf.order, &buf.hd)
	if err != nil {
		return err
	}
	xs, _, err := buf.Read(fname)
	if err != nil {
		return err
	}

	buf.hd.postprocess(xs, out)

	return nil
}

func (buf *LGadget2Buffer) MinMass() float32 { return buf.mass }
<|endoftext|>


<commit_before>//    Copyright 2016 Alex Macleod
//
//    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 irc

import (
	"strings"
	"time"
)

// ParseMessage creates a Message from a raw IRC message
func ParseMessage(raw string) *Message {
	message := &Message{}
	message.time = time.Now()
	// Message tags
	if strings.HasPrefix(raw, "@") {
		i := strings.IndexByte(raw, ' ')
		message.tags = parseTags(raw[1:i])
		raw = raw[i+1:]
	}
	// Message prefix
	if strings.HasPrefix(raw, ":") {
		i := strings.IndexByte(raw, ' ')
		message.prefix = raw[1:i]
		raw = raw[i+1:]
	}
	return message
}

func parseTags(tagString string) []Tag {
	tagStrings := strings.Split(tagString, ";")
	// http://ircv3.net/specs/core/message-tags-3.2.html#escaping-values
	r := strings.NewReplacer(
		`\:`, `;`,
		`\s`, ` `,
		`\\`, `\`,
		`\r`, "\r",
		`\n`, "\n",
	)
	tags := []Tag{}
	for i, tag := range tagStrings {
		kv := strings.SplitN(tag, "=", 2)
		tags[i].key = kv[0]
		tags[i].value = r.Replace(kv[1])
	}
	return tags
}

// Tag represents IRCv3 message tags, see:
// - http://ircv3.net/specs/core/message-tags-3.2.html
// - http://ircv3.net/specs/core/message-tags-3.3.html
//
// <tag> ::= <key> ['=' <escaped value>]
type Tag struct {
	// <key>           ::= [ <vendor> '/' ] <sequence of letters, digits, hyphens (`-`)>
	key string
	// <escaped value> ::= <sequence of any characters except NUL, CR, LF, semicolon
	//                     (`;`) and SPACE>
	// value is unescaped
	value string
}

// Message represents a parsed Message, see:
// - https://tools.ietf.org/html/rfc1459#section-2.3.1
//
// <message> ::= ['@' <tags> <SPACE>] [':' <prefix> <SPACE> ] <command> <params> <crlf>
type Message struct {
	// <tags>     ::= <tag> [';' <tag>]*
	tags []Tag
	// <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
	prefix string
	// <command>  ::= <letter> { <letter> } | <number> <number> <number>
	command string
	// <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
	// <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
	//                     or NUL or CR or LF, the first of which may not be ':'>
	// <trailing> ::= <Any, possibly *empty*, sequence of octets not including
	//                     NUL or CR or LF>
	params []string
	// time the message was received, may be replaced with server indicated time
	// if server-time is supported
	time time.Time
}
<commit_msg>Parse command + tags correctly<commit_after>//    Copyright 2016 Alex Macleod
//
//    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 irc

import (
	"strings"
	"time"
)

// ParseMessage creates a Message from a raw IRC message
func ParseMessage(raw string) *Message {
	message := &Message{}
	message.time = time.Now()
	// tags
	if strings.HasPrefix(raw, "@") {
		i := strings.IndexByte(raw, ' ')
		message.tags = parseTags(raw[1:i])
		raw = raw[i+1:]
	}
	// prefix
	if strings.HasPrefix(raw, ":") {
		i := strings.IndexByte(raw, ' ')
		message.prefix = raw[1:i]
		raw = raw[i+1:]
	}
	// command
	i := strings.IndexByte(raw, ' ')
	if i < 0 {
		i = len(raw)
	}
	message.command = raw[:i]
	// params
	for len(raw) > i {
		raw = raw[i+1:]
		i = strings.IndexByte(raw, ' ')
		message.params = append(message.params, raw[:i])
	}
	return message
}

// func nextToken(raw *string, lead, trail int) (newLead, newTrail int) {
// 	length := len(*raw)

// 	return 0, 0
// }

func parseTags(tagString string) []Tag {
	tagStrings := strings.Split(tagString, ";")
	// http://ircv3.net/specs/core/message-tags-3.2.html#escaping-values
	r := strings.NewReplacer(
		`\:`, `;`,
		`\s`, ` `,
		`\\`, `\`,
		`\r`, "\r",
		`\n`, "\n",
	)
	tags := make([]Tag, len(tagStrings))
	for i, tag := range tagStrings {
		kv := strings.SplitN(tag, "=", 2)
		tags[i].key = kv[0]
		tags[i].value = r.Replace(kv[1])
	}

	return tags
}

// Tag represents IRCv3 message tags, see:
// - http://ircv3.net/specs/core/message-tags-3.2.html
// - http://ircv3.net/specs/core/message-tags-3.3.html
//
// <tag> ::= <key> ['=' <escaped value>]
type Tag struct {
	// <key>           ::= [ <vendor> '/' ] <sequence of letters, digits, hyphens (`-`)>
	key string
	// <escaped value> ::= <sequence of any characters except NUL, CR, LF, semicolon
	//                     (`;`) and SPACE>
	// value is unescaped
	value string
}

// Message represents a parsed Message, see:
// - https://tools.ietf.org/html/rfc1459#section-2.3.1
//
// <message> ::= ['@' <tags> <SPACE>] [':' <prefix> <SPACE> ] <command> <params> <crlf>
type Message struct {
	// <tags>     ::= <tag> [';' <tag>]*
	tags []Tag
	// <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
	prefix string
	// <command>  ::= <letter> { <letter> } | <number> <number> <number>
	command string
	// <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
	// <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
	//                     or NUL or CR or LF, the first of which may not be ':'>
	// <trailing> ::= <Any, possibly *empty*, sequence of octets not including
	//                     NUL or CR or LF>
	params []string
	// time the message was received, may be replaced with server indicated time
	// if server-time is supported
	time time.Time
}
<|endoftext|>


<commit_before>package job

import (
	"fmt"
	"github.com/ory-am/gitdeploy/storage"
	"log"
	"os/exec"
	"strings"
	"time"
)

func KillAppsOnHitList(store storage.Storage) {
	for {
		apps, err := store.FindAppsOnKillList()
		if err != nil {
			log.Printf("Could not fetch kill-list: %s", err)
		} else {
			for _, app := range apps {
				for _, appliance := range app.Appliances {
					go func() {
						e := exec.Command("flynn", "-a", appliance.ID, "delete", "-y")
						if out, err := e.CombinedOutput(); err != nil {
							log.Printf("An error occured while cleanup %s. Reason: %s", err.Error(), out)
							return
						}
					}()
				}

				go func() {
					e := exec.Command("flynn", "-a", app.ID, "delete", "-y")
					out, err := e.CombinedOutput()
					reason := strings.Trim(string(out), " \n\r")
					if reason == "controller: resource not found" {
						log.Printf("App %s is not known to controller.", app.ID)
					} else if err != nil {
						log.Printf("An error occured while cleanup %s. Reason: %s", err.Error(), out)
						return
					}
					store.KillApp(app)
				}()
			}
		}
		time.Sleep(15 * time.Second)
	}
}
<commit_msg>job: removed unused import<commit_after>package job

import (
	"github.com/ory-am/gitdeploy/storage"
	"log"
	"os/exec"
	"strings"
	"time"
)

func KillAppsOnHitList(store storage.Storage) {
	for {
		apps, err := store.FindAppsOnKillList()
		if err != nil {
			log.Printf("Could not fetch kill-list: %s", err)
		} else {
			for _, app := range apps {
				for _, appliance := range app.Appliances {
					go func() {
						e := exec.Command("flynn", "-a", appliance.ID, "delete", "-y")
						if out, err := e.CombinedOutput(); err != nil {
							log.Printf("An error occured while cleanup %s. Reason: %s", err.Error(), out)
							return
						}
					}()
				}

				go func() {
					e := exec.Command("flynn", "-a", app.ID, "delete", "-y")
					out, err := e.CombinedOutput()
					reason := strings.Trim(string(out), " \n\r")
					if reason == "controller: resource not found" {
						log.Printf("App %s is not known to controller.", app.ID)
					} else if err != nil {
						log.Printf("An error occured while cleanup %s. Reason: %s", err.Error(), out)
						return
					}
					store.KillApp(app)
				}()
			}
		}
		time.Sleep(15 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"html"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	p "path"
	"strconv"
	"strings"
	"time"
)

func main() {
	http.HandleFunc("/", handleAny)
	log.Fatal(http.ListenAndServe(":"+httpPort(), nil))
}

func handleAny(res http.ResponseWriter, req *http.Request) {
	log.Printf("method=%s path=%q", req.Method, req.URL.Path)

	path, err := os.Open(req.URL.Path)
	if err != nil {
		if os.IsNotExist(err) {
			handleError(res, req, err, http.StatusNotFound, "File not found")
			return
		}

		handleError(res, req, err, http.StatusBadRequest, "Error reading path")
		return
	}
	defer path.Close()

	pathInfo, err := path.Stat()
	if err != nil {
		handleError(res, req, err, http.StatusInternalServerError, "Error reading path info")
		return
	}

	if strings.HasPrefix(req.Header.Get("Origin"), "ws://") { // TODO: how to detect? scheme is null
		handleWs(res, req, path, pathInfo)
		return
	}

	switch req.Method {
	case "GET":
		handleGet(res, req, path, pathInfo)
	case "POST":
		handlePost(res, req, path, pathInfo)
	default:
		http.Error(res, "Only GET and POST supported", http.StatusMethodNotAllowed)
	}
}

func handleGet(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo) {
	if pathInfo.Mode().IsDir() {
		fileInfos, err := path.Readdir(0)
		if err != nil {
			handleError(res, req, err, http.StatusInternalServerError, "Error reading directory")
			return
		}

		if strings.Contains(req.Header.Get("Accept"), "html") {
			renderDirHtml(res, path.Name(), fileInfos)
		} else {
			renderDirJson(res, fileInfos)
		}
	} else if pathInfo.Mode().IsRegular() {
		stat, err := path.Stat()
		if err != nil {
			handleError(res, req, err, http.StatusInternalServerError, "Error reading file stat")
			return
		}

		// explicitly set Content-Length for clients to track download progress
		// except for 0 bytes files which could include special 0-byte unix files
		if stat.Size() > 0 {
			res.Header().Set("Content-Length", strconv.FormatInt(stat.Size(), 10))
		}

		io.Copy(res, path)
	} else {
		handleError(res, req, nil,
			http.StatusBadRequest,
			"Invalid file type for GET. Only directories and regular files are supported.")
	}
}

func handlePost(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo) {
	resFlusherWriter := flushWriterWrapper{res.(flushWriter)}
	execCmd(res, req, path, pathInfo, req.Body, resFlusherWriter, false)
}

func handleWs(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo) {
	handler := func(ws *websocket.Conn) {
		execCmd(res, req, path, pathInfo, ws, ws, true)
	}

	websocket.Handler(handler).ServeHTTP(res, req)
}

func execCmd(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo, in io.Reader, out io.Writer, interactive bool) {
	var cmd *exec.Cmd

	if pathInfo.Mode().IsDir() {
		if interactive {
			// TODO: allow interactive session to have a prompt, support heredocs, handle arrow keys, and generally act like a real terminal
			// cmd = exec.Command("bash", "-i") // double echos (ws + bash -i) and displays arrow character

			// pseudo-interactive-bash worksaround `bash -i` echoing problem, but breaks on heredocs and probably other bash special cases
			dir, err := os.Getwd()
			if err != nil {
				log.Fatal(err)
			}
			log.Println(dir)
			cmd = exec.Command(p.Join(dir, "bin", "pseudo-interactive-bash"))
		} else {
			cmd = exec.Command("bash")
		}
		cmd.Dir = path.Name()
	} else if pathInfo.Mode().IsRegular() && pathInfo.Mode()&0110 != 0 /* is executable for user or group */ {
		cmd = exec.Command(path.Name())
		cmd.Dir = path.Name()[0:strings.LastIndex(path.Name(), string(os.PathSeparator))]
	} else {
		handleError(res, req, nil,
			http.StatusBadRequest,
			"Invalid file type for POST. Only directories and regular executable file are supported")
		return
	}

	cmd.Env = append(os.Environ(), cgiEnv(req)...)
	if interactive {
		cmd.Env = append(cmd.Env, "PS1=\\[\\033[01;34m\\]\\w\\[\\033[00m\\] \\[\\033[01;32m\\]$ \\[\\033[00m\\]")
	}
	cmd.Stdin = in
	cmd.Stdout = out
	cmd.Stderr = out
	if err := cmd.Run(); err != nil {
		// error already sent to client. log only
		log.Printf("method=%s path=%q message=%q", req.Method, req.URL.Path, err)
	}
}

func renderDirHtml(res http.ResponseWriter, pathName string, fileInfos []os.FileInfo) {
	res.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(res, "

")
	for _, fi := range fileInfos {
		if !strings.HasSuffix(pathName, "/") {
			pathName += "/"
		}

		label := fi.Name()
		if fi.IsDir() {
			label = label + "/"
		}

		fmt.Fprintf(res, "
%s
", pathName, fi.Name(), html.EscapeString(label))
	}
	fmt.Fprintf(res, "

")
}

func renderDirJson(res http.ResponseWriter, fileInfos []os.FileInfo) {
	res.Header().Set("Content-Type", "application/json")
	fileResponses := map[string]FileInfoDetails{}
	for _, fi := range fileInfos {
		fileResponses[fi.Name()] = toFileInfoDetails(fi)
	}
	fileResponsesJson, err := json.MarshalIndent(fileResponses, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Fprintln(res, string(fileResponsesJson))
}

type FileInfoDetails struct {
	Size    int64     `json:"size"`
	Type    string    `json:"type"`
	Perm    int       `json:"permission"`
	ModTime time.Time `json:"updated_at"`
}

func toFileInfoDetails(fi os.FileInfo) FileInfoDetails {
	return FileInfoDetails{
		Size:    fi.Size(),
		Type:    string(fi.Mode().String()[0]),
		Perm:    int(fi.Mode().Perm()),
		ModTime: fi.ModTime(),
	}
}

type stdError struct {
	Message string `json:"message"`
	Cause   error  `json:"cause"`
}

func handleError(res http.ResponseWriter, req *http.Request, err error, httpStatus int, message string) {
	stdError := stdError{
		Message: message,
		Cause:   err,
	}

	log.Printf("method=%s path=%q message=%q cause=%q", req.Method, req.URL.Path, stdError.Message, stdError.Cause)

	stdErrorJson, err := json.MarshalIndent(stdError, "", "  ")
	if err != nil {
		panic(err)
	}

	res.Header().Set("Content-Type", "application/json")
	http.Error(res, string(stdErrorJson), httpStatus)
}

type flushWriter interface {
	Flush()
	Write(buf []byte) (int, error)
}

type flushWriterWrapper struct {
	fw flushWriter
}

func (fww flushWriterWrapper) Write(p []byte) (n int, err error) {
	n, err = fww.fw.Write(p)
	fww.fw.Flush()
	return
}

func httpPort() string {
	if port := os.Getenv("PORT"); port != "" {
		return port
	}
	return "5000"
}

// copied from net/http/cgi/host.go
func cgiEnv(req *http.Request) []string {
	env := []string{
		"SERVER_SOFTWARE=go",
		"SERVER_NAME=" + req.Host,
		"SERVER_PROTOCOL=HTTP/1.1",
		"HTTP_HOST=" + req.Host,
		"GATEWAY_INTERFACE=CGI/1.1",
		"REQUEST_METHOD=" + req.Method,
		"QUERY_STRING=" + req.URL.RawQuery,
		"REQUEST_URI=" + req.URL.RequestURI(),
		"PATH_INFO=" + req.URL.Path,
		"SCRIPT_NAME=" + req.URL.Path,
		"SCRIPT_FILENAME=" + req.URL.Path,
		"REMOTE_ADDR=" + req.RemoteAddr,
		"REMOTE_HOST=" + req.RemoteAddr,
		"SERVER_PORT=" + httpPort(),
	}

	if req.TLS != nil {
		env = append(env, "HTTPS=on")
	}

	for k, v := range req.Header {
		k = strings.Map(upperCaseAndUnderscore, k)
		joinStr := ", "
		if k == "COOKIE" {
			joinStr = "; "
		}
		env = append(env, "HTTP_"+k+"="+strings.Join(v, joinStr))
	}

	if req.ContentLength > 0 {
		env = append(env, fmt.Sprintf("CONTENT_LENGTH=%d", req.ContentLength))
	}
	if ctype := req.Header.Get("Content-Type"); ctype != "" {
		env = append(env, "CONTENT_TYPE="+ctype)
	}

	return env
}

func upperCaseAndUnderscore(r rune) rune {
	switch {
	case r >= 'a' && r <= 'z':
		return r - ('a' - 'A')
	case r == '-':
		return '_'
	case r == '=':
		// Maybe not part of the CGI 'spec' but would mess up
		// the environment in any case, as Go represents the
		// environment as a slice of "key=value" strings.
		return '_'
	}
	// TODO: other transformations in spec or practice?
	return r
}
<commit_msg>Golint fixes<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"html"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	p "path"
	"strconv"
	"strings"
	"time"
)

func main() {
	http.HandleFunc("/", handleAny)
	log.Fatal(http.ListenAndServe(":"+httpPort(), nil))
}

func handleAny(res http.ResponseWriter, req *http.Request) {
	log.Printf("method=%s path=%q", req.Method, req.URL.Path)

	path, err := os.Open(req.URL.Path)
	if err != nil {
		if os.IsNotExist(err) {
			handleError(res, req, err, http.StatusNotFound, "File not found")
			return
		}

		handleError(res, req, err, http.StatusBadRequest, "Error reading path")
		return
	}
	defer path.Close()

	pathInfo, err := path.Stat()
	if err != nil {
		handleError(res, req, err, http.StatusInternalServerError, "Error reading path info")
		return
	}

	if strings.HasPrefix(req.Header.Get("Origin"), "ws://") { // TODO: how to detect? scheme is null
		handleWs(res, req, path, pathInfo)
		return
	}

	switch req.Method {
	case "GET":
		handleGet(res, req, path, pathInfo)
	case "POST":
		handlePost(res, req, path, pathInfo)
	default:
		http.Error(res, "Only GET and POST supported", http.StatusMethodNotAllowed)
	}
}

func handleGet(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo) {
	if pathInfo.Mode().IsDir() {
		fileInfos, err := path.Readdir(0)
		if err != nil {
			handleError(res, req, err, http.StatusInternalServerError, "Error reading directory")
			return
		}

		if strings.Contains(req.Header.Get("Accept"), "html") {
			renderDirHTML(res, path.Name(), fileInfos)
		} else {
			renderDirJSON(res, fileInfos)
		}
	} else if pathInfo.Mode().IsRegular() {
		stat, err := path.Stat()
		if err != nil {
			handleError(res, req, err, http.StatusInternalServerError, "Error reading file stat")
			return
		}

		// explicitly set Content-Length for clients to track download progress
		// except for 0 bytes files which could include special 0-byte unix files
		if stat.Size() > 0 {
			res.Header().Set("Content-Length", strconv.FormatInt(stat.Size(), 10))
		}

		io.Copy(res, path)
	} else {
		handleError(res, req, nil,
			http.StatusBadRequest,
			"Invalid file type for GET. Only directories and regular files are supported.")
	}
}

func handlePost(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo) {
	resFlusherWriter := flushWriterWrapper{res.(flushWriter)}
	execCmd(res, req, path, pathInfo, req.Body, resFlusherWriter, false)
}

func handleWs(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo) {
	handler := func(ws *websocket.Conn) {
		execCmd(res, req, path, pathInfo, ws, ws, true)
	}

	websocket.Handler(handler).ServeHTTP(res, req)
}

func execCmd(res http.ResponseWriter, req *http.Request, path *os.File, pathInfo os.FileInfo, in io.Reader, out io.Writer, interactive bool) {
	var cmd *exec.Cmd

	if pathInfo.Mode().IsDir() {
		if interactive {
			// TODO: allow interactive session to have a prompt, support heredocs, handle arrow keys, and generally act like a real terminal
			// cmd = exec.Command("bash", "-i") // double echos (ws + bash -i) and displays arrow character

			// pseudo-interactive-bash worksaround `bash -i` echoing problem, but breaks on heredocs and probably other bash special cases
			dir, err := os.Getwd()
			if err != nil {
				log.Fatal(err)
			}
			log.Println(dir)
			cmd = exec.Command(p.Join(dir, "bin", "pseudo-interactive-bash"))
		} else {
			cmd = exec.Command("bash")
		}
		cmd.Dir = path.Name()
	} else if pathInfo.Mode().IsRegular() && pathInfo.Mode()&0110 != 0 /* is executable for user or group */ {
		cmd = exec.Command(path.Name())
		cmd.Dir = path.Name()[0:strings.LastIndex(path.Name(), string(os.PathSeparator))]
	} else {
		handleError(res, req, nil,
			http.StatusBadRequest,
			"Invalid file type for POST. Only directories and regular executable file are supported")
		return
	}

	cmd.Env = append(os.Environ(), cgiEnv(req)...)
	if interactive {
		cmd.Env = append(cmd.Env, "PS1=\\[\\033[01;34m\\]\\w\\[\\033[00m\\] \\[\\033[01;32m\\]$ \\[\\033[00m\\]")
	}
	cmd.Stdin = in
	cmd.Stdout = out
	cmd.Stderr = out
	if err := cmd.Run(); err != nil {
		// error already sent to client. log only
		log.Printf("method=%s path=%q message=%q", req.Method, req.URL.Path, err)
	}
}

func renderDirHTML(res http.ResponseWriter, pathName string, fileInfos []os.FileInfo) {
	res.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(res, "

")
	for _, fi := range fileInfos {
		if !strings.HasSuffix(pathName, "/") {
			pathName += "/"
		}

		label := fi.Name()
		if fi.IsDir() {
			label = label + "/"
		}

		fmt.Fprintf(res, "
%s
", pathName, fi.Name(), html.EscapeString(label))
	}
	fmt.Fprintf(res, "

")
}

func renderDirJSON(res http.ResponseWriter, fileInfos []os.FileInfo) {
	res.Header().Set("Content-Type", "application/json")
	fileResponses := map[string]FileInfoDetails{}
	for _, fi := range fileInfos {
		fileResponses[fi.Name()] = toFileInfoDetails(fi)
	}
	fileResponsesJSON, err := json.MarshalIndent(fileResponses, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Fprintln(res, string(fileResponsesJSON))
}

// FileInfoDetails contains basic stat + permission details about a file
type FileInfoDetails struct {
	Size    int64     `json:"size"`
	Type    string    `json:"type"`
	Perm    int       `json:"permission"`
	ModTime time.Time `json:"updated_at"`
}

func toFileInfoDetails(fi os.FileInfo) FileInfoDetails {
	return FileInfoDetails{
		Size:    fi.Size(),
		Type:    string(fi.Mode().String()[0]),
		Perm:    int(fi.Mode().Perm()),
		ModTime: fi.ModTime(),
	}
}

type stdError struct {
	Message string `json:"message"`
	Cause   error  `json:"cause"`
}

func handleError(res http.ResponseWriter, req *http.Request, err error, httpStatus int, message string) {
	stdError := stdError{
		Message: message,
		Cause:   err,
	}

	log.Printf("method=%s path=%q message=%q cause=%q", req.Method, req.URL.Path, stdError.Message, stdError.Cause)

	stdErrorJSON, err := json.MarshalIndent(stdError, "", "  ")
	if err != nil {
		panic(err)
	}

	res.Header().Set("Content-Type", "application/json")
	http.Error(res, string(stdErrorJSON), httpStatus)
}

type flushWriter interface {
	Flush()
	Write(buf []byte) (int, error)
}

type flushWriterWrapper struct {
	fw flushWriter
}

func (fww flushWriterWrapper) Write(p []byte) (n int, err error) {
	n, err = fww.fw.Write(p)
	fww.fw.Flush()
	return
}

func httpPort() string {
	if port := os.Getenv("PORT"); port != "" {
		return port
	}
	return "5000"
}

// copied from net/http/cgi/host.go
func cgiEnv(req *http.Request) []string {
	env := []string{
		"SERVER_SOFTWARE=go",
		"SERVER_NAME=" + req.Host,
		"SERVER_PROTOCOL=HTTP/1.1",
		"HTTP_HOST=" + req.Host,
		"GATEWAY_INTERFACE=CGI/1.1",
		"REQUEST_METHOD=" + req.Method,
		"QUERY_STRING=" + req.URL.RawQuery,
		"REQUEST_URI=" + req.URL.RequestURI(),
		"PATH_INFO=" + req.URL.Path,
		"SCRIPT_NAME=" + req.URL.Path,
		"SCRIPT_FILENAME=" + req.URL.Path,
		"REMOTE_ADDR=" + req.RemoteAddr,
		"REMOTE_HOST=" + req.RemoteAddr,
		"SERVER_PORT=" + httpPort(),
	}

	if req.TLS != nil {
		env = append(env, "HTTPS=on")
	}

	for k, v := range req.Header {
		k = strings.Map(upperCaseAndUnderscore, k)
		joinStr := ", "
		if k == "COOKIE" {
			joinStr = "; "
		}
		env = append(env, "HTTP_"+k+"="+strings.Join(v, joinStr))
	}

	if req.ContentLength > 0 {
		env = append(env, fmt.Sprintf("CONTENT_LENGTH=%d", req.ContentLength))
	}
	if ctype := req.Header.Get("Content-Type"); ctype != "" {
		env = append(env, "CONTENT_TYPE="+ctype)
	}

	return env
}

func upperCaseAndUnderscore(r rune) rune {
	switch {
	case r >= 'a' && r <= 'z':
		return r - ('a' - 'A')
	case r == '-':
		return '_'
	case r == '=':
		// Maybe not part of the CGI 'spec' but would mess up
		// the environment in any case, as Go represents the
		// environment as a slice of "key=value" strings.
		return '_'
	}
	// TODO: other transformations in spec or practice?
	return r
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"exec"
	"fmt"
	"log"
	"net"
	"os"
	"exp/regexp"
	"strings"
)

var (
	rcptToRE   = regexp.MustCompile(`(?i)^to:\s*<(.+?)>`)
	mailFromRE = regexp.MustCompile(`(?i)^from:\s*<(.+?)>`)
)

// Server is an SMTP server.
type Server struct {
	Addr         string // TCP address to listen on, ":25" if empty
	Hostname     string // optional Hostname to announce; "" to use system hostname
	ReadTimeout  int64  // optional net.Conn.SetReadTimeout value for new connections
	WriteTimeout int64  // optional net.Conn.SetWriteTimeout value for new connections

	// OnNewConnection, if non-nil, is called on new connections.
	// If it returns non-nil, the connection is closed.
	OnNewConnection func(c Connection) os.Error

	// OnNewMail must be defined and is called when a new message beings.
	// (when a MAIL FROM line arrives)
	OnNewMail func(c Connection, from MailAddress) (Envelope, os.Error)
}

// MailAddress is defined by
type MailAddress interface {
	Email() string    // email address, as provided
	Hostname() string // canonical hostname, lowercase
}

// Connection is implemented by the SMTP library and provided to callers
// customizing their own Servers.
type Connection interface {
	Addr() net.Addr
}

type Envelope interface {
	AddRecipient(rcpt MailAddress) os.Error
}

type BasicEnvelope struct {
	rcpts []MailAddress
}

func (e *BasicEnvelope) AddRecipient(rcpt MailAddress) os.Error {
	e.rcpts = append(e.rcpts, rcpt)
	return nil
}

// ArrivingMessage is the interface that must be implement by servers
// receiving mail.
type ArrivingMessage interface {
	AddHeaderLine(s string) os.Error
	EndHeaders() os.Error
}

func (srv *Server) hostname() string {
	if srv.Hostname != "" {
		return srv.Hostname
	}
	out, err := exec.Command("hostname").Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(out))
}

// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.  If
// srv.Addr is blank, ":25" is used.
func (srv *Server) ListenAndServe() os.Error {
	addr := srv.Addr
	if addr == "" {
		addr = ":25"
	}
	ln, e := net.Listen("tcp", addr)
	if e != nil {
		return e
	}
	return srv.Serve(ln)
}

func (srv *Server) Serve(ln net.Listener) os.Error {
	defer ln.Close()
	for {
		rw, e := ln.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				log.Printf("smtpd: Accept error: %v", e)
				continue
			}
			return e
		}
		if srv.ReadTimeout != 0 {
			rw.SetReadTimeout(srv.ReadTimeout)
		}
		if srv.WriteTimeout != 0 {
			rw.SetWriteTimeout(srv.WriteTimeout)
		}
		sess, err := srv.newSession(rw)
		if err != nil {
			continue
		}
		go sess.serve()
	}
	panic("not reached")
}

type session struct {
	srv *Server
	rwc net.Conn
	br  *bufio.Reader
	bw  *bufio.Writer

	env Envelope // current envelope, or nil

	helloType string
	helloHost string
}

func (srv *Server) newSession(rwc net.Conn) (s *session, err os.Error) {
	s = &session{
		srv: srv,
		rwc: rwc,
		br:  bufio.NewReader(rwc),
		bw:  bufio.NewWriter(rwc),
	}
	return
}

func (s *session) errorf(format string, args ...interface{}) {
	log.Printf("Client error: "+format, args...)
}

func (s *session) sendf(format string, args ...interface{}) {
	fmt.Fprintf(s.bw, format, args...)
	s.bw.Flush()
}

func (s *session) sendlinef(format string, args ...interface{}) {
	s.sendf(format+"\r\n", args...)
}

func (s *session) Addr() net.Addr {
	return s.rwc.RemoteAddr()
}

func (s *session) serve() {
	defer s.rwc.Close()
	if onc := s.srv.OnNewConnection; onc != nil {
		if err := onc(s); err != nil {
			// TODO: if the error implements a SMTPErrorStringer,
			// call it and send the error back
			//
			// TODO: if the user error is 554 (rejecting this connection),
			// we should relay that back too, and stick around for
			// a bit (see RFC 5321 3.1)
			return
		}
	}
	s.sendf("220 %s ESMTP gosmtpd\r\n", s.srv.hostname())
	for {
		sl, err := s.br.ReadSlice('\n')
		if err != nil {
			s.errorf("read error: %v", err)
			return
		}
		line := cmdLine(string(sl))
		if !line.valid() {
			s.sendlinef("500 ??? invalid line received, not ending in \\r\\n")
			return
		}
		log.Printf("Client: %q, verb: %q", line, line.Verb())
		switch line.Verb() {
		case "HELO", "EHLO":
			s.handleHello(line.Verb(), line.Arg())
		case "QUIT":
			s.sendlinef("221 2.0.0 Bye")
			return
		case "MAIL":
			arg := line.Arg() // "From:<foo@bar.com>"
			m := mailFromRE.FindStringSubmatch(arg)
			if m == nil {
				s.sendlinef("501 5.1.7 Bad sender address syntax")
				continue
			}
			s.handleMailFrom(m[1])
		case "RCPT":
			s.handleRcpt(line)
		case "DATA":
			s.sendlinef("354 Go ahead")
		default:
			s.sendlinef("502 5.5.2 Error: command not recognized")
		}
	}
}

func (s *session) handleHello(greeting, host string) {
	s.helloType = greeting
	s.helloHost = host
	fmt.Fprintf(s.bw, "250-%s\r\n", s.srv.hostname())
	for _, ext := range []string{
		"250-PIPELINING",
		"250-SIZE 10240000",
		"250-ENHANCEDSTATUSCODES",
		"250-8BITMIME",
		"250 DSN",
	} {
		fmt.Fprintf(s.bw, "%s\r\n", ext)
	}
	s.bw.Flush()
}

func (s *session) handleMailFrom(email string) {
	log.Printf("mail from: %q", email)
	cb := s.srv.OnNewMail
	if cb == nil {
		log.Printf("smtp: Server.OnNewMail is nil; rejecting MAIL FROM")
		s.sendf("451 Server.OnNewMail not configured\r\n")
		return
	}
	s.env = nil
	env, err := cb(s, addrString(email))
	if err != nil {
		log.Printf("rejecting MAIL FROM %q: %v", email, err)
		// TODO: send it back to client if warranted, like above
		return
	}
	s.env = env
	s.sendlinef("250 2.1.0 Ok")
}

func (s *session) handleRcpt(line cmdLine) {
	if s.env == nil {
		s.sendlinef("503 5.5.1 Error: need MAIL command")
		return
	}
	arg := line.Arg() // "To:<foo@bar.com>"
	m := rcptToRE.FindStringSubmatch(arg)
	if m == nil {
		s.sendlinef("501 5.1.7 Bad sender address syntax")
	}
	err := s.env.AddRecipient(addrString(m[1]))
	if err != nil {
		// TODO: don't always proxy the error to the client
		s.sendlinef("550 bad recipient: %v", err)
		return
	}
	s.sendlinef("250 2.1.0 Ok")
}

type addrString string

func (a addrString) Email() string {
	return string(a)
}

func (a addrString) Hostname() string {
	e := string(a)
	if idx := strings.Index(e, "@"); idx != -1 {
		return strings.ToLower(e[idx+1:])
	}
	return ""
}

type cmdLine string

func (cl cmdLine) valid() bool {
	return strings.HasSuffix(string(cl), "\r\n")
}

func (cl cmdLine) Verb() string {
	s := string(cl)
	if idx := strings.Index(s, " "); idx != -1 {
		return strings.ToUpper(s[:idx])
	}
	return strings.ToUpper(s[:len(s)-2])
}

func (cl cmdLine) Arg() string {
	s := string(cl)
	if idx := strings.Index(s, " "); idx != -1 {
		return s[idx+1 : len(s)-2]
	}
	return ""
}

func (cl cmdLine) String() string {
	s := string(cl)
	if cl.valid() {
		return s[:len(s)-2]
	}
	return s + "[!MISSING_NEWLINE]"
}
<commit_msg>trim space before newline, don't allow args on RSET, DATA, QUIT<commit_after>package main

// TODO:
//  -- send 421 to connected clients on graceful server shutdown (s3.8)
//

import (
	"bufio"
	"exec"
	"fmt"
	"log"
	"net"
	"os"
	"exp/regexp"
	"strings"
	"unicode"
)

var (
	rcptToRE   = regexp.MustCompile(`(?i)^to:\s*<(.+?)>`)
	mailFromRE = regexp.MustCompile(`(?i)^from:\s*<(.*?)>`)
)

// Server is an SMTP server.
type Server struct {
	Addr         string // TCP address to listen on, ":25" if empty
	Hostname     string // optional Hostname to announce; "" to use system hostname
	ReadTimeout  int64  // optional net.Conn.SetReadTimeout value for new connections
	WriteTimeout int64  // optional net.Conn.SetWriteTimeout value for new connections

	// OnNewConnection, if non-nil, is called on new connections.
	// If it returns non-nil, the connection is closed.
	OnNewConnection func(c Connection) os.Error

	// OnNewMail must be defined and is called when a new message beings.
	// (when a MAIL FROM line arrives)
	OnNewMail func(c Connection, from MailAddress) (Envelope, os.Error)
}

// MailAddress is defined by
type MailAddress interface {
	Email() string    // email address, as provided
	Hostname() string // canonical hostname, lowercase
}

// Connection is implemented by the SMTP library and provided to callers
// customizing their own Servers.
type Connection interface {
	Addr() net.Addr
}

type Envelope interface {
	AddRecipient(rcpt MailAddress) os.Error
}

type BasicEnvelope struct {
	rcpts []MailAddress
}

func (e *BasicEnvelope) AddRecipient(rcpt MailAddress) os.Error {
	e.rcpts = append(e.rcpts, rcpt)
	return nil
}

// ArrivingMessage is the interface that must be implement by servers
// receiving mail.
type ArrivingMessage interface {
	AddHeaderLine(s string) os.Error
	EndHeaders() os.Error
}

func (srv *Server) hostname() string {
	if srv.Hostname != "" {
		return srv.Hostname
	}
	out, err := exec.Command("hostname").Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(out))
}

// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.  If
// srv.Addr is blank, ":25" is used.
func (srv *Server) ListenAndServe() os.Error {
	addr := srv.Addr
	if addr == "" {
		addr = ":25"
	}
	ln, e := net.Listen("tcp", addr)
	if e != nil {
		return e
	}
	return srv.Serve(ln)
}

func (srv *Server) Serve(ln net.Listener) os.Error {
	defer ln.Close()
	for {
		rw, e := ln.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				log.Printf("smtpd: Accept error: %v", e)
				continue
			}
			return e
		}
		if srv.ReadTimeout != 0 {
			rw.SetReadTimeout(srv.ReadTimeout)
		}
		if srv.WriteTimeout != 0 {
			rw.SetWriteTimeout(srv.WriteTimeout)
		}
		sess, err := srv.newSession(rw)
		if err != nil {
			continue
		}
		go sess.serve()
	}
	panic("not reached")
}

type session struct {
	srv *Server
	rwc net.Conn
	br  *bufio.Reader
	bw  *bufio.Writer

	env Envelope // current envelope, or nil

	helloType string
	helloHost string
}

func (srv *Server) newSession(rwc net.Conn) (s *session, err os.Error) {
	s = &session{
		srv: srv,
		rwc: rwc,
		br:  bufio.NewReader(rwc),
		bw:  bufio.NewWriter(rwc),
	}
	return
}

func (s *session) errorf(format string, args ...interface{}) {
	log.Printf("Client error: "+format, args...)
}

func (s *session) sendf(format string, args ...interface{}) {
	fmt.Fprintf(s.bw, format, args...)
	s.bw.Flush()
}

func (s *session) sendlinef(format string, args ...interface{}) {
	s.sendf(format+"\r\n", args...)
}

func (s *session) Addr() net.Addr {
	return s.rwc.RemoteAddr()
}

func (s *session) serve() {
	defer s.rwc.Close()
	if onc := s.srv.OnNewConnection; onc != nil {
		if err := onc(s); err != nil {
			// TODO: if the error implements a SMTPErrorStringer,
			// call it and send the error back
			//
			// TODO: if the user error is 554 (rejecting this connection),
			// we should relay that back too, and stick around for
			// a bit (see RFC 5321 3.1)
			return
		}
	}
	s.sendf("220 %s ESMTP gosmtpd\r\n", s.srv.hostname())
	for {
		sl, err := s.br.ReadSlice('\n')
		if err != nil {
			s.errorf("read error: %v", err)
			return
		}
		line := cmdLine(string(sl))
		if err := line.checkValid(); err != nil {
			s.sendlinef("500 %v", err)
			continue
		}
		log.Printf("Client: %q, verb: %q", line, line.Verb())

		switch line.Verb() {
		case "HELO", "EHLO":
			s.handleHello(line.Verb(), line.Arg())
		case "QUIT":
			s.sendlinef("221 2.0.0 Bye")
			return
		case "MAIL":
			arg := line.Arg() // "From:<foo@bar.com>"
			m := mailFromRE.FindStringSubmatch(arg)
			if m == nil {
				s.sendlinef("501 5.1.7 Bad sender address syntax")
				continue
			}
			s.handleMailFrom(m[1])
		case "RCPT":
			s.handleRcpt(line)
		case "DATA":
			s.sendlinef("354 Go ahead")
		default:
			s.sendlinef("502 5.5.2 Error: command not recognized")
		}
	}
}

func (s *session) handleHello(greeting, host string) {
	s.helloType = greeting
	s.helloHost = host
	fmt.Fprintf(s.bw, "250-%s\r\n", s.srv.hostname())
	for _, ext := range []string{
		"250-PIPELINING",
		"250-SIZE 10240000",
		"250-ENHANCEDSTATUSCODES",
		"250-8BITMIME",
		"250 DSN",
	} {
		fmt.Fprintf(s.bw, "%s\r\n", ext)
	}
	s.bw.Flush()
}

func (s *session) handleMailFrom(email string) {
	log.Printf("mail from: %q", email)
	cb := s.srv.OnNewMail
	if cb == nil {
		log.Printf("smtp: Server.OnNewMail is nil; rejecting MAIL FROM")
		s.sendf("451 Server.OnNewMail not configured\r\n")
		return
	}
	s.env = nil
	env, err := cb(s, addrString(email))
	if err != nil {
		log.Printf("rejecting MAIL FROM %q: %v", email, err)
		// TODO: send it back to client if warranted, like above
		return
	}
	s.env = env
	s.sendlinef("250 2.1.0 Ok")
}

func (s *session) handleRcpt(line cmdLine) {
	if s.env == nil {
		s.sendlinef("503 5.5.1 Error: need MAIL command")
		return
	}
	arg := line.Arg() // "To:<foo@bar.com>"
	m := rcptToRE.FindStringSubmatch(arg)
	if m == nil {
		s.sendlinef("501 5.1.7 Bad sender address syntax")
	}
	err := s.env.AddRecipient(addrString(m[1]))
	if err != nil {
		// TODO: don't always proxy the error to the client
		s.sendlinef("550 bad recipient: %v", err)
		return
	}
	s.sendlinef("250 2.1.0 Ok")
}

type addrString string

func (a addrString) Email() string {
	return string(a)
}

func (a addrString) Hostname() string {
	e := string(a)
	if idx := strings.Index(e, "@"); idx != -1 {
		return strings.ToLower(e[idx+1:])
	}
	return ""
}

type cmdLine string

func (cl cmdLine) checkValid() os.Error {
	if !strings.HasSuffix(string(cl), "\r\n") {
		return os.NewError(`line doesn't end in \r\n`)
	}
	// Check for verbs defined not to have an argument
	// (RFC 5321 s4.1.1)
	switch cl.Verb() {
	case "RSET", "DATA", "QUIT":
		if cl.Arg() != "" {
			return os.NewError("unexpected argument")
		}
	}
	return nil
}

func (cl cmdLine) Verb() string {
	s := string(cl)
	if idx := strings.Index(s, " "); idx != -1 {
		return strings.ToUpper(s[:idx])
	}
	return strings.ToUpper(s[:len(s)-2])
}

func (cl cmdLine) Arg() string {
	s := string(cl)
	if idx := strings.Index(s, " "); idx != -1 {
		return strings.TrimRightFunc(s[idx+1:len(s)-2], unicode.IsSpace)
	}
	return ""
}

func (cl cmdLine) String() string {
	return string(cl)
}
<|endoftext|>


<commit_before>package main

import (
	"container/list"
)

type Snake struct {
	Pos *list.List
}

func NewSnake() *Snake {
	pos := list.New()
	pos.PushFront([2]int{10, 10})
	return &Snake{
		Pos: pos,
	}
}

func (this *Snake) MoveDown(eaten bool) {
	headNode, headPos := this.addHead()
	headNode.Value = [2]int{headPos[0], headPos[1] + 1}
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) MoveLeft(eaten bool) {
	headNode, headPos := this.addHead()
	headNode.Value = [2]int{headPos[0] - 1, headPos[1]}
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) MoveUp(eaten bool) {
	headNode, headPos := this.addHead()
	headNode.Value = [2]int{headPos[0], headPos[1] - 1}
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) MoveRight(eaten bool) {
	headNode, headPos := this.addHead()
	headNode.Value = [2]int{headPos[0] + 1, headPos[1]}
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) addHead() (headNode *list.Element, headPos [2]int) {
	node := this.Pos.Front()
	headNode = this.Pos.PushFront(node.Value)
	return headNode, headNode.Value.([2]int)
}

func (this *Snake) cutTail() {
	tail := this.Pos.Back()
	this.Pos.Remove(tail)
}
<commit_msg>Snake refactoring.<commit_after>package main

import (
	"container/list"
)

type Snake struct {
	Pos       *list.List
	KeepGoing func(bool)
}

func NewSnake() *Snake {
	pos := list.New()
	pos.PushFront([2]int{10, 10})
	return &Snake{
		Pos: pos,
	}
}

func (this *Snake) MoveDown(eaten bool) {
	this.move(0, 1)
	this.KeepGoing = this.MoveDown
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) MoveLeft(eaten bool) {
	this.move(-1, 0)
	this.KeepGoing = this.MoveLeft
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) MoveUp(eaten bool) {
	this.move(0, -1)
	this.KeepGoing = this.MoveUp
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) MoveRight(eaten bool) {
	this.move(1, 0)
	this.KeepGoing = this.MoveRight
	if !eaten {
		this.cutTail()
	}
}

func (this *Snake) move(x, y int) {
	headNode, headPos := this.addHead()
	headNode.Value = [2]int{headPos[0] + x, headPos[1] + y}
}

func (this *Snake) addHead() (headNode *list.Element, headPos [2]int) {
	node := this.Pos.Front()
	headNode = this.Pos.PushFront(node.Value)
	return headNode, headNode.Value.([2]int)
}

func (this *Snake) cutTail() {
	tail := this.Pos.Back()
	this.Pos.Remove(tail)
}
<|endoftext|>


<commit_before>// Copyright 2012, Hailiang Wang. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package socks implements a SOCKS (SOCKS4, SOCKS4A and SOCKS5) proxy client.

A complete example using this package:
	package main

	import (
		"h12.me/socks"
		"fmt"
		"net/http"
		"io/ioutil"
	)

	func main() {
		dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
		tr := &http.Transport{Dial: dialSocksProxy}
		httpClient := &http.Client{Transport: tr}

		bodyText, err := TestHttpsGet(httpClient, "https://h12.me/about")
		if err != nil {
			fmt.Println(err.Error())
		}
		fmt.Print(bodyText)
	}

	func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) {
		resp, err := c.Get(url)
		if err != nil { return }
		defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil { return }
		bodyText = string(body)
		return
	}
*/
package socks // import "h12.me/socks"

import (
	"errors"
	"fmt"
	"net"
	"strconv"
)

// Constants to choose which version of SOCKS protocol to use.
const (
	SOCKS4 = iota
	SOCKS4A
	SOCKS5
)

// DialSocksProxy returns the dial function to be used in http.Transport object.
// Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5.
// Argument proxy should be in this format "127.0.0.1:1080".
func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) {
	if socksType == SOCKS5 {
		return func(_, targetAddr string) (conn net.Conn, err error) {
			return dialSocks5(proxy, targetAddr)
		}
	}

	// SOCKS4, SOCKS4A
	return func(_, targetAddr string) (conn net.Conn, err error) {
		return dialSocks4(socksType, proxy, targetAddr)
	}
}

func dialSocks5(proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil {
		return
	}

	// version identifier/method selection request
	req := []byte{
		5, // version number
		1, // number of methods
		0, // method 0: no authentication (only anonymous access supported for now)
	}
	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 2 {
		err = errors.New("Server does not respond properly.")
        return
	} else if resp[0] != 5 {
		err = errors.New("Server does not support Socks 5.")
        return
	} else if resp[1] != 0 { // no auth
		err = errors.New("socks method negotiation failed.")
		return
	}

	// detail request
	host, port, err := splitHostPort(targetAddr)
	req = []byte{
		5,               // version number
		1,               // connect command
		0,               // reserved, must be zero
		3,               // address type, 3 means domain name
		byte(len(host)), // address length
	}
	req = append(req, []byte(host)...)
	req = append(req, []byte{
		byte(port >> 8), // higher byte of destination port
		byte(port),      // lower byte of destination port (big endian)
	}...)
	resp, err = sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 10 {
		err = errors.New("Server does not respond properly.")
	} else if resp[1] != 0 {
		err = errors.New("Can't complete SOCKS5 connection.")
	}

	return
}

func dialSocks4(socksType int, proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil {
		return
	}

	// connection request
	host, port, err := splitHostPort(targetAddr)
	if err != nil {
		return
	}
	ip := net.IPv4(0, 0, 0, 1).To4()
	if socksType == SOCKS4 {
		ip, err = lookupIP(host)
		if err != nil {
			return
		}
	}
	req := []byte{
		4,                          // version number
		1,                          // command CONNECT
		byte(port >> 8),            // higher byte of destination port
		byte(port),                 // lower byte of destination port (big endian)
		ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided
		0, // user id is empty, anonymous proxy only
	}
	if socksType == SOCKS4A {
		req = append(req, []byte(host+"\x00")...)
	}

	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 8 {
		err = errors.New("Server does not respond properly.")
        return
	}
	switch resp[1] {
	case 90:
		// request granted
	case 91:
		err = errors.New("Socks connection request rejected or failed.")
	case 92:
		err = errors.New("Socks connection request rejected becasue SOCKS server cannot connect to identd on the client.")
	case 93:
		err = errors.New("Socks connection request rejected because the client program and identd report different user-ids.")
	default:
		err = errors.New("Socks connection request failed, unknown error.")
	}
	return
}

func sendReceive(conn net.Conn, req []byte) (resp []byte, err error) {
	_, err = conn.Write(req)
	if err != nil {
		return
	}
	resp, err = readAll(conn)
	return
}

func readAll(conn net.Conn) (resp []byte, err error) {
	resp = make([]byte, 1024)
	n, err := conn.Read(resp)
	resp = resp[:n]
	return
}

func lookupIP(host string) (ip net.IP, err error) {
	ips, err := net.LookupIP(host)
	if err != nil {
		return
	}
	if len(ips) == 0 {
		err = errors.New(fmt.Sprintf("Cannot resolve host: %s.", host))
		return
	}
	ip = ips[0].To4()
	if len(ip) != net.IPv4len {
		fmt.Println(len(ip), ip)
		err = errors.New("IPv6 is not supported by SOCKS4.")
		return
	}
	return
}

func splitHostPort(addr string) (host string, port uint16, err error) {
	host, portStr, err := net.SplitHostPort(addr)
	portInt, err := strconv.ParseUint(portStr, 10, 16)
	port = uint16(portInt)
	return
}
<commit_msg>Fix formatting with go fmt.<commit_after>// Copyright 2012, Hailiang Wang. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package socks implements a SOCKS (SOCKS4, SOCKS4A and SOCKS5) proxy client.

A complete example using this package:
	package main

	import (
		"h12.me/socks"
		"fmt"
		"net/http"
		"io/ioutil"
	)

	func main() {
		dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
		tr := &http.Transport{Dial: dialSocksProxy}
		httpClient := &http.Client{Transport: tr}

		bodyText, err := TestHttpsGet(httpClient, "https://h12.me/about")
		if err != nil {
			fmt.Println(err.Error())
		}
		fmt.Print(bodyText)
	}

	func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) {
		resp, err := c.Get(url)
		if err != nil { return }
		defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil { return }
		bodyText = string(body)
		return
	}
*/
package socks // import "h12.me/socks"

import (
	"errors"
	"fmt"
	"net"
	"strconv"
)

// Constants to choose which version of SOCKS protocol to use.
const (
	SOCKS4 = iota
	SOCKS4A
	SOCKS5
)

// DialSocksProxy returns the dial function to be used in http.Transport object.
// Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5.
// Argument proxy should be in this format "127.0.0.1:1080".
func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) {
	if socksType == SOCKS5 {
		return func(_, targetAddr string) (conn net.Conn, err error) {
			return dialSocks5(proxy, targetAddr)
		}
	}

	// SOCKS4, SOCKS4A
	return func(_, targetAddr string) (conn net.Conn, err error) {
		return dialSocks4(socksType, proxy, targetAddr)
	}
}

func dialSocks5(proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil {
		return
	}

	// version identifier/method selection request
	req := []byte{
		5, // version number
		1, // number of methods
		0, // method 0: no authentication (only anonymous access supported for now)
	}
	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 2 {
		err = errors.New("Server does not respond properly.")
		return
	} else if resp[0] != 5 {
		err = errors.New("Server does not support Socks 5.")
		return
	} else if resp[1] != 0 { // no auth
		err = errors.New("socks method negotiation failed.")
		return
	}

	// detail request
	host, port, err := splitHostPort(targetAddr)
	req = []byte{
		5,               // version number
		1,               // connect command
		0,               // reserved, must be zero
		3,               // address type, 3 means domain name
		byte(len(host)), // address length
	}
	req = append(req, []byte(host)...)
	req = append(req, []byte{
		byte(port >> 8), // higher byte of destination port
		byte(port),      // lower byte of destination port (big endian)
	}...)
	resp, err = sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 10 {
		err = errors.New("Server does not respond properly.")
	} else if resp[1] != 0 {
		err = errors.New("Can't complete SOCKS5 connection.")
	}

	return
}

func dialSocks4(socksType int, proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil {
		return
	}

	// connection request
	host, port, err := splitHostPort(targetAddr)
	if err != nil {
		return
	}
	ip := net.IPv4(0, 0, 0, 1).To4()
	if socksType == SOCKS4 {
		ip, err = lookupIP(host)
		if err != nil {
			return
		}
	}
	req := []byte{
		4,                          // version number
		1,                          // command CONNECT
		byte(port >> 8),            // higher byte of destination port
		byte(port),                 // lower byte of destination port (big endian)
		ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided
		0, // user id is empty, anonymous proxy only
	}
	if socksType == SOCKS4A {
		req = append(req, []byte(host+"\x00")...)
	}

	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 8 {
		err = errors.New("Server does not respond properly.")
		return
	}
	switch resp[1] {
	case 90:
		// request granted
	case 91:
		err = errors.New("Socks connection request rejected or failed.")
	case 92:
		err = errors.New("Socks connection request rejected becasue SOCKS server cannot connect to identd on the client.")
	case 93:
		err = errors.New("Socks connection request rejected because the client program and identd report different user-ids.")
	default:
		err = errors.New("Socks connection request failed, unknown error.")
	}
	return
}

func sendReceive(conn net.Conn, req []byte) (resp []byte, err error) {
	_, err = conn.Write(req)
	if err != nil {
		return
	}
	resp, err = readAll(conn)
	return
}

func readAll(conn net.Conn) (resp []byte, err error) {
	resp = make([]byte, 1024)
	n, err := conn.Read(resp)
	resp = resp[:n]
	return
}

func lookupIP(host string) (ip net.IP, err error) {
	ips, err := net.LookupIP(host)
	if err != nil {
		return
	}
	if len(ips) == 0 {
		err = errors.New(fmt.Sprintf("Cannot resolve host: %s.", host))
		return
	}
	ip = ips[0].To4()
	if len(ip) != net.IPv4len {
		fmt.Println(len(ip), ip)
		err = errors.New("IPv6 is not supported by SOCKS4.")
		return
	}
	return
}

func splitHostPort(addr string) (host string, port uint16, err error) {
	host, portStr, err := net.SplitHostPort(addr)
	portInt, err := strconv.ParseUint(portStr, 10, 16)
	port = uint16(portInt)
	return
}
<|endoftext|>


<commit_before>package pt

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
)

const (
	socksVersion         = 0x04
	socksCmdConnect      = 0x01
	socksResponseVersion = 0x00
	socksRequestGranted  = 0x5a
	socksRequestRejected = 0x5b
)

// SocksRequest describes a SOCKS request.
type SocksRequest struct {
	// The endpoint requested by the client as a "host:port" string.
	Target string
	// The userid string sent by the client.
	Username string
	// The parsed contents of Username as a key–value mapping.
	Args Args
}

// SocksConn encapsulates a net.Conn and information associated with a SOCKS request.
type SocksConn struct {
	net.Conn
	Req SocksRequest
}

// Send a message to the proxy client that access to the given address is
// granted. If the IP field inside addr is not an IPv4 address, the IP portion
// of the response will be four zero bytes.
func (conn *SocksConn) Grant(addr *net.TCPAddr) error {
	return sendSocks4aResponseGranted(conn, addr)
}

// Send a message to the proxy client that access was rejected or failed.
func (conn *SocksConn) Reject() error {
	return sendSocks4aResponseRejected(conn)
}

// SocksListener wraps a net.Listener in order to read a SOCKS request on Accept.
//
// 	func handleConn(conn *pt.SocksConn) error {
// 		defer conn.Close()
// 		remote, err := net.Dial("tcp", conn.Req.Target)
// 		if err != nil {
// 			conn.Reject()
// 			return err
// 		}
// 		defer remote.Close()
// 		err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
// 		if err != nil {
// 			return err
// 		}
//
// 		// do something with conn and remote
//
// 		return nil
// 	}
// 	...
// 	ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
// 	if err != nil {
// 		panic(err.Error())
// 	}
// 	for {
// 		conn, err := ln.AcceptSocks()
// 		if err != nil {
// 			break
// 		}
// 		go handleConn(conn)
// 	}
type SocksListener struct {
	net.Listener
}

// Open a net.Listener according to network and laddr, and return it as a
// SocksListener.
func ListenSocks(network, laddr string) (*SocksListener, error) {
	ln, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewSocksListener(ln), nil
}

// Create a new SocksListener wrapping the given net.Listener.
func NewSocksListener(ln net.Listener) *SocksListener {
	return &SocksListener{ln}
}

// Accept is the same as AcceptSocks, except that it returns a generic net.Conn.
// It is present for the sake of satisfying the net.Listener interface.
func (ln *SocksListener) Accept() (net.Conn, error) {
	return ln.AcceptSocks()
}

// Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
// SocksConn. After accepting, you must call either conn.Grant or conn.Reject
// (presumably after trying to connect to conn.Req.Target).
func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
	c, err := ln.Listener.Accept()
	if err != nil {
		return nil, err
	}
	conn := new(SocksConn)
	conn.Conn = c
	conn.Req, err = readSocks4aConnect(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return conn, nil
}

// Returns "socks4", suitable to be included in a call to pt.Cmethod.
func (ln *SocksListener) Version() string {
	return "socks4"
}

// Read a SOCKS4a connect request. Returns a SocksRequest.
func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
	r := bufio.NewReader(s)

	var h [8]byte
	_, err = io.ReadFull(r, h[:])
	if err != nil {
		return
	}
	if h[0] != socksVersion {
		err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, not 0x%02x", h[0], socksVersion))
		return
	}
	if h[1] != socksCmdConnect {
		err = errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, not 0x%02x", h[1], socksCmdConnect))
		return
	}

	var usernameBytes []byte
	usernameBytes, err = r.ReadBytes('\x00')
	if err != nil {
		return
	}
	req.Username = string(usernameBytes[:len(usernameBytes)-1])

	req.Args, err = parseClientParameters(req.Username)
	if err != nil {
		return
	}

	var port int
	var host string

	port = int(h[2])<<8 | int(h[3])<<0
	if h[4] == 0 && h[5] == 0 && h[6] == 0 && h[7] != 0 {
		var hostBytes []byte
		hostBytes, err = r.ReadBytes('\x00')
		if err != nil {
			return
		}
		host = string(hostBytes[:len(hostBytes)-1])
	} else {
		host = net.IPv4(h[4], h[5], h[6], h[7]).String()
	}

	if r.Buffered() != 0 {
		err = errors.New(fmt.Sprintf("%d bytes left after SOCKS header", r.Buffered()))
		return
	}

	req.Target = fmt.Sprintf("%s:%d", host, port)
	return
}

// Send a SOCKS4a response with the given code and address. If the IP field
// inside addr is not an IPv4 address, the IP portion of the response will be
// four zero bytes.
func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
	var resp [8]byte
	resp[0] = socksResponseVersion
	resp[1] = code
	resp[2] = byte((addr.Port >> 8) & 0xff)
	resp[3] = byte((addr.Port >> 0) & 0xff)
	ipv4 := addr.IP.To4()
	if ipv4 != nil {
		resp[4] = ipv4[0]
		resp[5] = ipv4[1]
		resp[6] = ipv4[2]
		resp[7] = ipv4[3]
	}
	_, err := w.Write(resp[:])
	return err
}

var emptyAddr = net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}

// Send a SOCKS4a response code 0x5a.
func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
	return sendSocks4aResponse(w, socksRequestGranted, addr)
}

// Send a SOCKS4a response code 0x5b (with an all-zero address).
func sendSocks4aResponseRejected(w io.Writer) error {
	return sendSocks4aResponse(w, socksRequestRejected, &emptyAddr)
}
<commit_msg>I guess the convention is not to use the package prefix.<commit_after>package pt

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
)

const (
	socksVersion         = 0x04
	socksCmdConnect      = 0x01
	socksResponseVersion = 0x00
	socksRequestGranted  = 0x5a
	socksRequestRejected = 0x5b
)

// SocksRequest describes a SOCKS request.
type SocksRequest struct {
	// The endpoint requested by the client as a "host:port" string.
	Target string
	// The userid string sent by the client.
	Username string
	// The parsed contents of Username as a key–value mapping.
	Args Args
}

// SocksConn encapsulates a net.Conn and information associated with a SOCKS request.
type SocksConn struct {
	net.Conn
	Req SocksRequest
}

// Send a message to the proxy client that access to the given address is
// granted. If the IP field inside addr is not an IPv4 address, the IP portion
// of the response will be four zero bytes.
func (conn *SocksConn) Grant(addr *net.TCPAddr) error {
	return sendSocks4aResponseGranted(conn, addr)
}

// Send a message to the proxy client that access was rejected or failed.
func (conn *SocksConn) Reject() error {
	return sendSocks4aResponseRejected(conn)
}

// SocksListener wraps a net.Listener in order to read a SOCKS request on Accept.
//
// 	func handleConn(conn *pt.SocksConn) error {
// 		defer conn.Close()
// 		remote, err := net.Dial("tcp", conn.Req.Target)
// 		if err != nil {
// 			conn.Reject()
// 			return err
// 		}
// 		defer remote.Close()
// 		err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
// 		if err != nil {
// 			return err
// 		}
//
// 		// do something with conn and remote
//
// 		return nil
// 	}
// 	...
// 	ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
// 	if err != nil {
// 		panic(err.Error())
// 	}
// 	for {
// 		conn, err := ln.AcceptSocks()
// 		if err != nil {
// 			break
// 		}
// 		go handleConn(conn)
// 	}
type SocksListener struct {
	net.Listener
}

// Open a net.Listener according to network and laddr, and return it as a
// SocksListener.
func ListenSocks(network, laddr string) (*SocksListener, error) {
	ln, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewSocksListener(ln), nil
}

// Create a new SocksListener wrapping the given net.Listener.
func NewSocksListener(ln net.Listener) *SocksListener {
	return &SocksListener{ln}
}

// Accept is the same as AcceptSocks, except that it returns a generic net.Conn.
// It is present for the sake of satisfying the net.Listener interface.
func (ln *SocksListener) Accept() (net.Conn, error) {
	return ln.AcceptSocks()
}

// Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
// SocksConn. After accepting, you must call either conn.Grant or conn.Reject
// (presumably after trying to connect to conn.Req.Target).
func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
	c, err := ln.Listener.Accept()
	if err != nil {
		return nil, err
	}
	conn := new(SocksConn)
	conn.Conn = c
	conn.Req, err = readSocks4aConnect(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return conn, nil
}

// Returns "socks4", suitable to be included in a call to Cmethod.
func (ln *SocksListener) Version() string {
	return "socks4"
}

// Read a SOCKS4a connect request. Returns a SocksRequest.
func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
	r := bufio.NewReader(s)

	var h [8]byte
	_, err = io.ReadFull(r, h[:])
	if err != nil {
		return
	}
	if h[0] != socksVersion {
		err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, not 0x%02x", h[0], socksVersion))
		return
	}
	if h[1] != socksCmdConnect {
		err = errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, not 0x%02x", h[1], socksCmdConnect))
		return
	}

	var usernameBytes []byte
	usernameBytes, err = r.ReadBytes('\x00')
	if err != nil {
		return
	}
	req.Username = string(usernameBytes[:len(usernameBytes)-1])

	req.Args, err = parseClientParameters(req.Username)
	if err != nil {
		return
	}

	var port int
	var host string

	port = int(h[2])<<8 | int(h[3])<<0
	if h[4] == 0 && h[5] == 0 && h[6] == 0 && h[7] != 0 {
		var hostBytes []byte
		hostBytes, err = r.ReadBytes('\x00')
		if err != nil {
			return
		}
		host = string(hostBytes[:len(hostBytes)-1])
	} else {
		host = net.IPv4(h[4], h[5], h[6], h[7]).String()
	}

	if r.Buffered() != 0 {
		err = errors.New(fmt.Sprintf("%d bytes left after SOCKS header", r.Buffered()))
		return
	}

	req.Target = fmt.Sprintf("%s:%d", host, port)
	return
}

// Send a SOCKS4a response with the given code and address. If the IP field
// inside addr is not an IPv4 address, the IP portion of the response will be
// four zero bytes.
func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
	var resp [8]byte
	resp[0] = socksResponseVersion
	resp[1] = code
	resp[2] = byte((addr.Port >> 8) & 0xff)
	resp[3] = byte((addr.Port >> 0) & 0xff)
	ipv4 := addr.IP.To4()
	if ipv4 != nil {
		resp[4] = ipv4[0]
		resp[5] = ipv4[1]
		resp[6] = ipv4[2]
		resp[7] = ipv4[3]
	}
	_, err := w.Write(resp[:])
	return err
}

var emptyAddr = net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}

// Send a SOCKS4a response code 0x5a.
func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
	return sendSocks4aResponse(w, socksRequestGranted, addr)
}

// Send a SOCKS4a response code 0x5b (with an all-zero address).
func sendSocks4aResponseRejected(w io.Writer) error {
	return sendSocks4aResponse(w, socksRequestRejected, &emptyAddr)
}
<|endoftext|>


<commit_before>// Package solve provides algorithms like A*, IDA* and Depth-first
package solve

import (
	"fmt"
	"math"
)

// Context can be used to interact with the solver and to maintain a custom context
// during the search.
type Context struct {
	Custom interface{}
}

// The State representing a state in the search tree
//
// An implementation of this interface represents the problem. It tells the algorithm how
// to get from one state to another, how much it costs to reach the state etc.
type State interface {
	// The costs to reach this state
	Cost(ctx Context) float64

	// Returns true if this is a goal state
	IsGoal(ctx Context) bool

	// Expands this state in zero or more child states
	Expand(ctx Context) []State

	// Estimated costs to reach a goal. Use 0 for no heuristic. Most algorithms will
	// find the optimal solution if the heuristic is admissible, meaning it will never
	// over-estimate the costs to reach a goal
	Heuristic(ctx Context) float64
}

// Result of the search
type Result struct {
	// The list of states leading from the root state to the goal state. If no solution
	// is found this list will be empty
	Solution []State

	// Number of nodes visited (dequeued) by the algorithm
	Visited int

	// Number of nodes expanded (enqueued) by the algorithm
	Expanded int
}

// Solved returns true if the result yields a solution
func (r Result) Solved() bool {
	return len(r.Solution) > 0
}

// GoalState returns the last state of Solution(). Can only be called if r.Solved() == true
func (r Result) GoalState() State {
	return r.Solution[len(r.Solution)-1]
}

type node struct {
	parent *node
	state  State
	value  float64
}

type result struct {
	node     *node
	contour  float64
	visited  int
	expanded int

	next *func() result
}

func expand(n *node, queue strategy, expanded int, constr iconstraint, limit float64, contour float64, context Context) (newExpanded int, newContour float64) {
	newExpanded = expanded
	newContour = contour
	for _, child := range n.state.Expand(context) {
		childNode := &node{n, child, math.Max(n.value, child.Cost(context)+child.Heuristic(context))}
		if constr.onExpand(childNode) {
			continue
		}
		if childNode.value > limit {
			newContour = math.Min(newContour, childNode.value)
			continue
		}
		queue.Add(childNode)
		newExpanded++
	}
	return
}

func generalSearch(queue strategy, visited int, expanded int, constr iconstraint, ubound float64, limit float64, contour float64, context Context) result {
	for {
		n := queue.Take()
		if n == nil {
			return result{nil, contour, visited, expanded, nil}
		}
		visited++
		if constr.onVisit(n) {
			continue
		}
		if n.state.IsGoal(context) && n.value > ubound {
			next := func() result {
				expanded, contour = expand(n, queue, expanded, constr, limit, contour, context)
				return generalSearch(queue, visited, expanded, constr, ubound, limit, contour, context)
			}
			return result{n, contour, visited, expanded, &next}
		}
		expanded, contour = expand(n, queue, expanded, constr, limit, contour, context)
	}
}

func startGeneralSearch(queue strategy, constr iconstraint, limit float64, context Context) result {
	return generalSearch(queue, 0, 0, constr, -1.0, limit, math.Inf(1), context)
}

func idaStar(rootState State, constraint iconstraint, contour float64, ubound float64, limit float64, context Context, nextfn *func() result) result {
	visited := 0
	expanded := 0
	for true {
		var lastResult result
		if nextfn == nil {
			// start with new iteration
			s := depthFirst()
			s.Add(&node{nil, rootState, rootState.Cost(context) + rootState.Heuristic(context)})
			constraint.reset()
			lastResult = generalSearch(s, visited, expanded, constraint, ubound, contour, math.Inf(1), context)
		} else {
			// continue previous iteration
			fn := *nextfn
			nextfn = nil
			lastResult = fn()
		}
		if lastResult.node != nil {
			// Found a solution
			underlyingNextFn := lastResult.next
			nextIdaStarFn := func() result {
				return idaStar(rootState, constraint, contour, ubound, limit, context, underlyingNextFn)
			}
			lastResult.next = &nextIdaStarFn
			return lastResult
		}
		lastResult.next = nil
		if lastResult.contour > limit || math.IsInf(lastResult.contour, 1) || math.IsNaN(lastResult.contour) {
			// no (more) solutions
			return lastResult
		}
		ubound = contour
		visited = lastResult.visited
		expanded = lastResult.expanded
		contour = lastResult.contour
		fmt.Printf("%v - %v\n", contour, visited)
	}
	panic("Shouldn't be reached")
}

func startIdaStar(rootState State, constraint iconstraint, limit float64, context Context) result {
	return idaStar(rootState, constraint, 0.0, -1.0, limit, context, nil)
}

func toSlice(node *node) []State {
	if node == nil {
		return make([]State, 0)
	}
	return append(toSlice(node.parent), node.state)
}

func toResult(r *result) Result {
	return Result{toSlice(r.node), r.visited, r.expanded}
}

type solver struct {
	rootState  State
	algorithm  Algorithm
	constraint Constraint
	limit      float64
	context    interface{}

	started bool
	result  *result
}

func solve(ss *solver) Result {
	if ss.started {
		if ss.result.next == nil {
			// no more possible solutions
			return Result{[]State{}, ss.result.visited, ss.result.expanded}
		}
		nextResult := (*ss.result.next)()
		ss.result = &nextResult
		return toResult(ss.result)
	}
	ss.started = true
	context := Context{ss.context}
	constraint := ss.constraint.(iconstraint)
	if ss.algorithm == IDAstar {
		nextResult := startIdaStar(ss.rootState, constraint, ss.limit, context)
		ss.result = &nextResult
		return toResult(ss.result)
	}
	var s strategy
	switch ss.algorithm {
	case Astar:
		s = aStar()
	case DepthFirst:
		s = depthFirst()
	case BreadthFirst:
		s = breadthFirst()
	}
	s.Add(&node{nil, ss.rootState, ss.rootState.Cost(context) + ss.rootState.Heuristic(context)})

	constraint.reset()
	nextResult := startGeneralSearch(s, constraint, ss.limit, context)
	ss.result = &nextResult
	return toResult(ss.result)
}

// Solver to solve the problem.
type Solver interface {
	// The algorithm to use, defaults to IDAstar
	Algorithm(algorithm Algorithm) Solver

	// The constraint to use, defaults to NONE
	Constraint(constraint Constraint) Solver

	// The limit to use. The problem will not be exanded beyond this limit. Defaults
	// to math.Inf(1).
	Limit(limit float64) Solver

	// Custom context which is passed to the methods of the state. Can contain for example precalculated data that
	// is used to speed up calculations. Be careful with state in the context though.
	Context(context interface{}) Solver

	// Solves the problem returning the result
	Solve() Result

	// Convenience method for finding all solutions. This method returns immediately and runs the search in a
	// goroutine. The resulting channel is closed when the search is completed.
	SolveAll() <-chan Result

	// True if the search is completed
	Completed() bool
}

func (s *solver) Algorithm(algorithm Algorithm) Solver {
	s.algorithm = algorithm
	return s
}

func (s *solver) Constraint(constraint Constraint) Solver {
	s.constraint = constraint
	return s
}

func (s *solver) Limit(limit float64) Solver {
	s.limit = limit
	return s
}

func (s *solver) Context(context interface{}) Solver {
	s.context = context
	return s
}

func (s *solver) Solve() Result {
	return solve(s)
}

func (s *solver) SolveAll() <-chan Result {
	solutions := make(chan Result)
	go func() {
		defer close(solutions)
		for result := s.Solve(); result.Solved(); result = s.Solve() {
			solutions <- result
		}
	}()
	return solutions
}

func (s *solver) Completed() bool {
	return s.started && s.result.next == nil
}

// NewSolver creates a new solver
func NewSolver(rootState State) Solver {
	return &solver{rootState, Astar, NoConstraint(), math.Inf(1), nil, false, nil}
}
<commit_msg>Removed debugging code<commit_after>// Package solve provides algorithms like A*, IDA* and Depth-first
package solve

import (
	"math"
)

// Context can be used to interact with the solver and to maintain a custom context
// during the search.
type Context struct {
	Custom interface{}
}

// The State representing a state in the search tree
//
// An implementation of this interface represents the problem. It tells the algorithm how
// to get from one state to another, how much it costs to reach the state etc.
type State interface {
	// The costs to reach this state
	Cost(ctx Context) float64

	// Returns true if this is a goal state
	IsGoal(ctx Context) bool

	// Expands this state in zero or more child states
	Expand(ctx Context) []State

	// Estimated costs to reach a goal. Use 0 for no heuristic. Most algorithms will
	// find the optimal solution if the heuristic is admissible, meaning it will never
	// over-estimate the costs to reach a goal
	Heuristic(ctx Context) float64
}

// Result of the search
type Result struct {
	// The list of states leading from the root state to the goal state. If no solution
	// is found this list will be empty
	Solution []State

	// Number of nodes visited (dequeued) by the algorithm
	Visited int

	// Number of nodes expanded (enqueued) by the algorithm
	Expanded int
}

// Solved returns true if the result yields a solution
func (r Result) Solved() bool {
	return len(r.Solution) > 0
}

// GoalState returns the last state of Solution(). Can only be called if r.Solved() == true
func (r Result) GoalState() State {
	return r.Solution[len(r.Solution)-1]
}

type node struct {
	parent *node
	state  State
	value  float64
}

type result struct {
	node     *node
	contour  float64
	visited  int
	expanded int

	next *func() result
}

func expand(n *node, queue strategy, expanded int, constr iconstraint, limit float64, contour float64, context Context) (newExpanded int, newContour float64) {
	newExpanded = expanded
	newContour = contour
	for _, child := range n.state.Expand(context) {
		childNode := &node{n, child, math.Max(n.value, child.Cost(context)+child.Heuristic(context))}
		if constr.onExpand(childNode) {
			continue
		}
		if childNode.value > limit {
			newContour = math.Min(newContour, childNode.value)
			continue
		}
		queue.Add(childNode)
		newExpanded++
	}
	return
}

func generalSearch(queue strategy, visited int, expanded int, constr iconstraint, ubound float64, limit float64, contour float64, context Context) result {
	for {
		n := queue.Take()
		if n == nil {
			return result{nil, contour, visited, expanded, nil}
		}
		visited++
		if constr.onVisit(n) {
			continue
		}
		if n.state.IsGoal(context) && n.value > ubound {
			next := func() result {
				expanded, contour = expand(n, queue, expanded, constr, limit, contour, context)
				return generalSearch(queue, visited, expanded, constr, ubound, limit, contour, context)
			}
			return result{n, contour, visited, expanded, &next}
		}
		expanded, contour = expand(n, queue, expanded, constr, limit, contour, context)
	}
}

func startGeneralSearch(queue strategy, constr iconstraint, limit float64, context Context) result {
	return generalSearch(queue, 0, 0, constr, -1.0, limit, math.Inf(1), context)
}

func idaStar(rootState State, constraint iconstraint, contour float64, ubound float64, limit float64, context Context, nextfn *func() result) result {
	visited := 0
	expanded := 0
	for true {
		var lastResult result
		if nextfn == nil {
			// start with new iteration
			s := depthFirst()
			s.Add(&node{nil, rootState, rootState.Cost(context) + rootState.Heuristic(context)})
			constraint.reset()
			lastResult = generalSearch(s, visited, expanded, constraint, ubound, contour, math.Inf(1), context)
		} else {
			// continue previous iteration
			fn := *nextfn
			nextfn = nil
			lastResult = fn()
		}
		if lastResult.node != nil {
			// Found a solution
			underlyingNextFn := lastResult.next
			nextIdaStarFn := func() result {
				return idaStar(rootState, constraint, contour, ubound, limit, context, underlyingNextFn)
			}
			lastResult.next = &nextIdaStarFn
			return lastResult
		}
		lastResult.next = nil
		if lastResult.contour > limit || math.IsInf(lastResult.contour, 1) || math.IsNaN(lastResult.contour) {
			// no (more) solutions
			return lastResult
		}
		ubound = contour
		visited = lastResult.visited
		expanded = lastResult.expanded
		contour = lastResult.contour
	}
	panic("Shouldn't be reached")
}

func startIdaStar(rootState State, constraint iconstraint, limit float64, context Context) result {
	return idaStar(rootState, constraint, 0.0, -1.0, limit, context, nil)
}

func toSlice(node *node) []State {
	if node == nil {
		return make([]State, 0)
	}
	return append(toSlice(node.parent), node.state)
}

func toResult(r *result) Result {
	return Result{toSlice(r.node), r.visited, r.expanded}
}

type solver struct {
	rootState  State
	algorithm  Algorithm
	constraint Constraint
	limit      float64
	context    interface{}

	started bool
	result  *result
}

func solve(ss *solver) Result {
	if ss.started {
		if ss.result.next == nil {
			// no more possible solutions
			return Result{[]State{}, ss.result.visited, ss.result.expanded}
		}
		nextResult := (*ss.result.next)()
		ss.result = &nextResult
		return toResult(ss.result)
	}
	ss.started = true
	context := Context{ss.context}
	constraint := ss.constraint.(iconstraint)
	if ss.algorithm == IDAstar {
		nextResult := startIdaStar(ss.rootState, constraint, ss.limit, context)
		ss.result = &nextResult
		return toResult(ss.result)
	}
	var s strategy
	switch ss.algorithm {
	case Astar:
		s = aStar()
	case DepthFirst:
		s = depthFirst()
	case BreadthFirst:
		s = breadthFirst()
	}
	s.Add(&node{nil, ss.rootState, ss.rootState.Cost(context) + ss.rootState.Heuristic(context)})

	constraint.reset()
	nextResult := startGeneralSearch(s, constraint, ss.limit, context)
	ss.result = &nextResult
	return toResult(ss.result)
}

// Solver to solve the problem.
type Solver interface {
	// The algorithm to use, defaults to IDAstar
	Algorithm(algorithm Algorithm) Solver

	// The constraint to use, defaults to NONE
	Constraint(constraint Constraint) Solver

	// The limit to use. The problem will not be exanded beyond this limit. Defaults
	// to math.Inf(1).
	Limit(limit float64) Solver

	// Custom context which is passed to the methods of the state. Can contain for example precalculated data that
	// is used to speed up calculations. Be careful with state in the context though.
	Context(context interface{}) Solver

	// Solves the problem returning the result
	Solve() Result

	// Convenience method for finding all solutions. This method returns immediately and runs the search in a
	// goroutine. The resulting channel is closed when the search is completed.
	SolveAll() <-chan Result

	// True if the search is completed
	Completed() bool
}

func (s *solver) Algorithm(algorithm Algorithm) Solver {
	s.algorithm = algorithm
	return s
}

func (s *solver) Constraint(constraint Constraint) Solver {
	s.constraint = constraint
	return s
}

func (s *solver) Limit(limit float64) Solver {
	s.limit = limit
	return s
}

func (s *solver) Context(context interface{}) Solver {
	s.context = context
	return s
}

func (s *solver) Solve() Result {
	return solve(s)
}

func (s *solver) SolveAll() <-chan Result {
	solutions := make(chan Result)
	go func() {
		defer close(solutions)
		for result := s.Solve(); result.Solved(); result = s.Solve() {
			solutions <- result
		}
	}()
	return solutions
}

func (s *solver) Completed() bool {
	return s.started && s.result.next == nil
}

// NewSolver creates a new solver
func NewSolver(rootState State) Solver {
	return &solver{rootState, Astar, NoConstraint(), math.Inf(1), nil, false, nil}
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"strconv"

	"github.com/urfave/cli"
)

type Start struct{}

func (cmd *Start) Commands() cli.Command {
	return cli.Command{
		Name:  "start",
		Usage: "Start the docker-machine and container services",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "driver",
				Value: "virtualbox",
				Usage: "Which virtualization driver to use: virtualbox (default), vmwarefusion, xhyve. Only used if start needs to create a machine",
			},
			cli.IntFlag{
				Name:  "disk-size",
				Value: 40,
				Usage: "Size of the VM disk in GB. Defaults to 40. Only used if start needs to create a machine.",
			},
			cli.IntFlag{
				Name:  "memory-size",
				Value: 4096,
				Usage: "Amount of memory for the VM in MB. Defaults to 4096. Only used if start needs to create a machine.",
			},
			cli.IntFlag{
				Name:  "cpu-count",
				Value: 2,
				Usage: "Number of CPU to allocate to the VM. Defaults to 2. Only used if start needs to create a machine.",
			},
			cli.StringFlag{
				Name:   "nameservers",
				Value:  "8.8.8.8:53",
				Usage:  "Comma separated list of fallback names servers for DNS resolution.",
				EnvVar: "RIG_NAMESERVERS",
			},
		},
		Action: cmd.Run,
	}
}

func (cmd *Start) Run(c *cli.Context) error {
	out.Info.Printf("Starting '%s'", machine.Name)
	out.Info.Println("Pre-flight check...")

	if err := exec.Command("grep", "-qE", "'^\"?/Users/'", "/etc/exports").Run(); err == nil {
		out.Error.Fatal("Vagrant NFS mount found. Please remove any non-Outrigger mounts that begin with /Users from your /etc/exports file")
	}

	out.Info.Println("Resetting Docker environment variables...")
	machine.UnsetEnv()

	// Does the docker-machine exist
	if !machine.Exists() {
		out.Warning.Printf("No machine named '%s' exists", machine.Name)

		driver := c.String("driver")
		diskSize := strconv.Itoa(c.Int("disk-size") * 1000)
		memSize := strconv.Itoa(c.Int("memory-size"))
		cpuCount := strconv.Itoa(c.Int("cpu-count"))
		machine.Create(driver, cpuCount, memSize, diskSize)
	}

	machine.Start()

	out.Info.Println("Configuring the local Docker environment")
	machine.SetEnv()

	out.Info.Println("Setting up DNS...")
	dns := Dns{}
	dns.ConfigureDns(machine, c.String("nameservers"))

	out.Info.Println("Enabling NFS file sharing")
	if nfsErr := StreamCommand(exec.Command("docker-machine-nfs", machine.Name)); nfsErr != nil {
		out.Error.Printf("Error enabling NFS: %s", nfsErr)
	}
	out.Info.Println("NFS is ready to use")

	// NFS enabling may have caused a machine restart, wait for it to be available before proceeding
	machine.WaitForDev()

	out.Info.Println("Setting up persistent /data volume...")
	dataMountSetup := `if [ ! -d /mnt/sda1/data ];
    then echo '===> Creating /mnt/sda1/data directory';
    sudo mkdir /mnt/sda1/data;
    sudo chgrp staff /mnt/sda1/data;
    sudo chmod g+w /mnt/sda1/data;
    echo '===> Creating /var/lib/boot2docker/bootsync.sh';
    echo '#!/bin/sh' | sudo tee /var/lib/boot2docker/bootsync.sh > /dev/null;
    echo 'sudo ln -sf /mnt/sda1/data /data' | sudo tee -a /var/lib/boot2docker/bootsync.sh > /dev/null;
    sudo chmod +x /var/lib/boot2docker/bootsync.sh;
  fi;
  if [ ! -L /data ];
    then echo '===> Creating symlink from /data to /mnt/sda1/data';
    sudo ln -s /mnt/sda1/data /data;
  fi;`
	StreamCommand(exec.Command("docker-machine", "ssh", machine.Name, dataMountSetup))

	dns.ConfigureRoutes(machine)

	out.Info.Println("Launching Dashboard...")
	dash := Dashboard{}
	dash.LaunchDashboard(machine)

	out.Info.Println("Your Phase2 Dev Tools VM is ready to use")

	return nil
}
<commit_msg>fixed startup message<commit_after>package main

import (
	"os/exec"
	"strconv"

	"github.com/urfave/cli"
)

type Start struct{}

func (cmd *Start) Commands() cli.Command {
	return cli.Command{
		Name:  "start",
		Usage: "Start the docker-machine and container services",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "driver",
				Value: "virtualbox",
				Usage: "Which virtualization driver to use: virtualbox (default), vmwarefusion, xhyve. Only used if start needs to create a machine",
			},
			cli.IntFlag{
				Name:  "disk-size",
				Value: 40,
				Usage: "Size of the VM disk in GB. Defaults to 40. Only used if start needs to create a machine.",
			},
			cli.IntFlag{
				Name:  "memory-size",
				Value: 4096,
				Usage: "Amount of memory for the VM in MB. Defaults to 4096. Only used if start needs to create a machine.",
			},
			cli.IntFlag{
				Name:  "cpu-count",
				Value: 2,
				Usage: "Number of CPU to allocate to the VM. Defaults to 2. Only used if start needs to create a machine.",
			},
			cli.StringFlag{
				Name:   "nameservers",
				Value:  "8.8.8.8:53",
				Usage:  "Comma separated list of fallback names servers for DNS resolution.",
				EnvVar: "RIG_NAMESERVERS",
			},
		},
		Action: cmd.Run,
	}
}

func (cmd *Start) Run(c *cli.Context) error {
	out.Info.Printf("Starting '%s'", machine.Name)
	out.Info.Println("Pre-flight check...")

	if err := exec.Command("grep", "-qE", "'^\"?/Users/'", "/etc/exports").Run(); err == nil {
		out.Error.Fatal("Vagrant NFS mount found. Please remove any non-Outrigger mounts that begin with /Users from your /etc/exports file")
	}

	out.Info.Println("Resetting Docker environment variables...")
	machine.UnsetEnv()

	// Does the docker-machine exist
	if !machine.Exists() {
		out.Warning.Printf("No machine named '%s' exists", machine.Name)

		driver := c.String("driver")
		diskSize := strconv.Itoa(c.Int("disk-size") * 1000)
		memSize := strconv.Itoa(c.Int("memory-size"))
		cpuCount := strconv.Itoa(c.Int("cpu-count"))
		machine.Create(driver, cpuCount, memSize, diskSize)
	}

	machine.Start()

	out.Info.Println("Configuring the local Docker environment")
	machine.SetEnv()

	out.Info.Println("Setting up DNS...")
	dns := Dns{}
	dns.ConfigureDns(machine, c.String("nameservers"))

	out.Info.Println("Enabling NFS file sharing")
	if nfsErr := StreamCommand(exec.Command("docker-machine-nfs", machine.Name)); nfsErr != nil {
		out.Error.Printf("Error enabling NFS: %s", nfsErr)
	}
	out.Info.Println("NFS is ready to use")

	// NFS enabling may have caused a machine restart, wait for it to be available before proceeding
	machine.WaitForDev()

	out.Info.Println("Setting up persistent /data volume...")
	dataMountSetup := `if [ ! -d /mnt/sda1/data ];
    then echo '===> Creating /mnt/sda1/data directory';
    sudo mkdir /mnt/sda1/data;
    sudo chgrp staff /mnt/sda1/data;
    sudo chmod g+w /mnt/sda1/data;
    echo '===> Creating /var/lib/boot2docker/bootsync.sh';
    echo '#!/bin/sh' | sudo tee /var/lib/boot2docker/bootsync.sh > /dev/null;
    echo 'sudo ln -sf /mnt/sda1/data /data' | sudo tee -a /var/lib/boot2docker/bootsync.sh > /dev/null;
    sudo chmod +x /var/lib/boot2docker/bootsync.sh;
  fi;
  if [ ! -L /data ];
    then echo '===> Creating symlink from /data to /mnt/sda1/data';
    sudo ln -s /mnt/sda1/data /data;
  fi;`
	StreamCommand(exec.Command("docker-machine", "ssh", machine.Name, dataMountSetup))

	dns.ConfigureRoutes(machine)

	out.Info.Println("Launching Dashboard...")
	dash := Dashboard{}
	dash.LaunchDashboard(machine)

	out.Info.Println("Outrigger is ready to use")

	return nil
}
<|endoftext|>