<commit_before>// mqttbot
// https://github.com/topfreegames/mqttbot
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>

package app_test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	. "github.com/franela/goblin"
	. "github.com/onsi/gomega"
	"github.com/satori/go.uuid"
	. "github.com/topfreegames/mqttbot/app"
	"github.com/topfreegames/mqttbot/es"
	"github.com/topfreegames/mqttbot/redisclient"
	. "github.com/topfreegames/mqttbot/testing"
)

func refreshIndex() {
	_, err := http.Post("http://localhost:9123/_refresh", "application/json", bytes.NewBufferString("{}"))
	Expect(err).To(BeNil())
}

func msToTime(ms int64) time.Time {
	return time.Unix(0, ms*int64(time.Millisecond))
}

func TestHistoryHandler(t *testing.T) {
	g := Goblin(t)

	// special hook for gomega
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("History", func() {
		esclient := es.GetESClient()
		g.BeforeEach(func() {
			esclient.DeleteIndex("chat")
			refreshIndex()
			// esclient.CreateIndex("chat")
		})

		g.Describe("History Handler", func() {
			g.It("It should return 401 if the user is not authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				path := fmt.Sprintf("/history/chat/test_%s?userid=test:test", testId)
				status, _ := Get(a, path, t)
				g.Assert(status).Equal(http.StatusUnauthorized)
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)
				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				testMessage := Message{
					Timestamp: time.Now(),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())

				refreshIndex()
				path := fmt.Sprintf("/history/%s?userid=test:test", topic)
				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
			})
		})

		g.Describe("History Since Handler", func() {
			g.It("It should return 401 if the user is not authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				path := fmt.Sprintf("/history/chat/test_%s?userid=test:test", testId)
				status, _ := Get(a, path, t)
				g.Assert(status).Equal(http.StatusUnauthorized)
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)

				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				testMessage := Message{
					Timestamp: time.Now(),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}

				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())

				refreshIndex()

				path := fmt.Sprintf("/history/%s?userid=test:test", topic)
				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)

				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				testMessage := Message{
					Timestamp: time.Now(),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}

				path := fmt.Sprintf(
					"/historysince/%s?userid=test:test&since=%d",
					topic, (time.Now().UnixNano() / 1000000), // now
				)
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())

				// Update indexes
				refreshIndex()

				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
				Expect(len(messages)).To(Equal(1))
				var message Message
				for i := 0; i < len(messages); i++ {
					message = messages[i]
					Expect(message.Topic).To(Equal(topic))
				}
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)
				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				now := time.Now().UnixNano() / 1000000
				testMessage := Message{}
				second := int64(1000)
				baseTime := now - (second * 70)
				for i := 0; i <= 30; i++ {
					messageTime := baseTime + 1*second
					testMessage = Message{
						Timestamp: msToTime(messageTime),
						Payload:   "{\"test1\":\"test2\"}",
						Topic:     topic,
					}
					_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
					Expect(err).To(BeNil())
				}

				// Update indexes
				refreshIndex()

				path := fmt.Sprintf(
					"/historysince/%s?userid=test:test&since=%d&limit=%d&from=%d",
					topic, baseTime, 10, 0,
				)

				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
				Expect(len(messages)).To(Equal(10))
				var message Message
				for i := 0; i < len(messages); i++ {
					message = messages[i]
					Expect(message.Topic).To(Equal(topic))
				}
			})
		})

		g.It("It should return 200 if the user is authorized into the topic", func() {
			a := GetDefaultTestApp()
			testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
			topic := fmt.Sprintf("chat/test_%s", testId)
			authStr := fmt.Sprintf("test:test-%s", topic)
			rc := redisclient.GetRedisClient("localhost", 4444, "")
			_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
			_, err = rc.Pool.Get().Do("set", authStr, 2)
			Expect(err).To(BeNil())

			startTime := time.Now().UnixNano() / 1000000
			testMessage := Message{}
			for i := 0; i < 3; i++ {
				messageTime := time.Now().UnixNano() / 1000000
				testMessage = Message{
					Timestamp: msToTime(messageTime),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())
			}

			// Sorry bout this =/
			time.Sleep(200 * time.Millisecond)

			// Update indexes
			refreshIndex()

			path := fmt.Sprintf(
				"/historysince/%s?userid=test:test&since=%d&limit=%d&from=%d",
				topic, startTime, 10, 0,
			)

			status, body := Get(a, path, t)
			g.Assert(status).Equal(http.StatusOK)

			var messages []Message
			err = json.Unmarshal([]byte(body), &messages)
			Expect(err).To(BeNil())
			Expect(len(messages)).To(Equal(3))
			var message Message
			for i := 0; i < len(messages); i++ {
				message = messages[i]
				Expect(message.Topic).To(Equal(topic))
			}
		})

		g.It("It should return 200 if the user is authorized into the topic", func() {
			a := GetDefaultTestApp()
			testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
			topic := fmt.Sprintf("chat/test_%s", testId)
			authStr := fmt.Sprintf("test:test-%s", topic)
			rc := redisclient.GetRedisClient("localhost", 4444, "")
			_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
			_, err = rc.Pool.Get().Do("set", authStr, 2)
			Expect(err).To(BeNil())

			startTime := time.Now().UnixNano() / 1000000
			testMessage := Message{}
			for i := 0; i < 3; i++ {
				messageTime := time.Now().UnixNano() / 1000000
				testMessage = Message{
					Timestamp: msToTime(messageTime),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())
			}

			// Sorry bout this =/
			time.Sleep(200 * time.Millisecond)

			// Update indexes
			refreshIndex()

			path := fmt.Sprintf(
				"/historysince/%s?userid=test:test&since=%d&limit=%d&from=%d",
				topic, startTime, 1, 0,
			)

			status, body := Get(a, path, t)
			g.Assert(status).Equal(http.StatusOK)

			var messages []Message
			err = json.Unmarshal([]byte(body), &messages)
			Expect(err).To(BeNil())
			Expect(len(messages)).To(Equal(1))

			var message Message
			for i := 0; i < len(messages); i++ {
				message = messages[i]
				Expect(message.Topic).To(Equal(topic))
			}
		})
	})
}
<commit_msg>Fix tests name<commit_after>// mqttbot
// https://github.com/topfreegames/mqttbot
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>

package app_test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	. "github.com/franela/goblin"
	. "github.com/onsi/gomega"
	"github.com/satori/go.uuid"
	. "github.com/topfreegames/mqttbot/app"
	"github.com/topfreegames/mqttbot/es"
	"github.com/topfreegames/mqttbot/redisclient"
	. "github.com/topfreegames/mqttbot/testing"
)

func refreshIndex() {
	_, err := http.Post("http://localhost:9123/_refresh", "application/json", bytes.NewBufferString("{}"))
	Expect(err).To(BeNil())
}

func msToTime(ms int64) time.Time {
	return time.Unix(0, ms*int64(time.Millisecond))
}

func TestHistoryHandler(t *testing.T) {
	g := Goblin(t)

	// special hook for gomega
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("History", func() {
		esclient := es.GetESClient()
		g.BeforeEach(func() {
			esclient.DeleteIndex("chat")
			refreshIndex()
			// esclient.CreateIndex("chat")
		})

		g.Describe("History Handler", func() {
			g.It("It should return 401 if the user is not authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				path := fmt.Sprintf("/history/chat/test_%s?userid=test:test", testId)
				status, _ := Get(a, path, t)
				g.Assert(status).Equal(http.StatusUnauthorized)
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)
				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				testMessage := Message{
					Timestamp: time.Now(),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())

				refreshIndex()
				path := fmt.Sprintf("/history/%s?userid=test:test", topic)
				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
			})
		})

		g.Describe("History Since Handler", func() {
			g.It("It should return 401 if the user is not authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				path := fmt.Sprintf("/history/chat/test_%s?userid=test:test", testId)
				status, _ := Get(a, path, t)
				g.Assert(status).Equal(http.StatusUnauthorized)
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)

				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				testMessage := Message{
					Timestamp: time.Now(),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}

				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())

				refreshIndex()

				path := fmt.Sprintf("/history/%s?userid=test:test", topic)
				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
			})

			g.It("It should return 200 if the user is authorized into the topic", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)

				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				testMessage := Message{
					Timestamp: time.Now(),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}

				path := fmt.Sprintf(
					"/historysince/%s?userid=test:test&since=%d",
					topic, (time.Now().UnixNano() / 1000000), // now
				)
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())

				// Update indexes
				refreshIndex()

				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
				Expect(len(messages)).To(Equal(1))
				var message Message
				for i := 0; i < len(messages); i++ {
					message = messages[i]
					Expect(message.Topic).To(Equal(topic))
				}
			})

			g.It("Should retrieve 10 messages when limit is 10 and the history size is greater than this", func() {
				a := GetDefaultTestApp()
				testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
				topic := fmt.Sprintf("chat/test_%s", testId)
				authStr := fmt.Sprintf("test:test-%s", topic)
				rc := redisclient.GetRedisClient("localhost", 4444, "")
				_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
				_, err = rc.Pool.Get().Do("set", authStr, 2)
				Expect(err).To(BeNil())

				now := time.Now().UnixNano() / 1000000
				testMessage := Message{}
				second := int64(1000)
				baseTime := now - (second * 70)
				for i := 0; i <= 30; i++ {
					messageTime := baseTime + 1*second
					testMessage = Message{
						Timestamp: msToTime(messageTime),
						Payload:   "{\"test1\":\"test2\"}",
						Topic:     topic,
					}
					_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
					Expect(err).To(BeNil())
				}

				// Update indexes
				refreshIndex()

				path := fmt.Sprintf(
					"/historysince/%s?userid=test:test&since=%d&limit=%d&from=%d",
					topic, baseTime, 10, 0,
				)

				status, body := Get(a, path, t)
				g.Assert(status).Equal(http.StatusOK)

				var messages []Message
				err = json.Unmarshal([]byte(body), &messages)
				Expect(err).To(BeNil())
				Expect(len(messages)).To(Equal(10))
				var message Message
				for i := 0; i < len(messages); i++ {
					message = messages[i]
					Expect(message.Topic).To(Equal(topic))
				}
			})
		})

		g.It("Should retrieve all messages eve if limit is greater than the size of current history", func() {
			a := GetDefaultTestApp()
			testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
			topic := fmt.Sprintf("chat/test_%s", testId)
			authStr := fmt.Sprintf("test:test-%s", topic)
			rc := redisclient.GetRedisClient("localhost", 4444, "")
			_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
			_, err = rc.Pool.Get().Do("set", authStr, 2)
			Expect(err).To(BeNil())

			startTime := time.Now().UnixNano() / 1000000
			testMessage := Message{}
			for i := 0; i < 3; i++ {
				messageTime := time.Now().UnixNano() / 1000000
				testMessage = Message{
					Timestamp: msToTime(messageTime),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())
			}

			// Sorry bout this =/
			time.Sleep(200 * time.Millisecond)

			// Update indexes
			refreshIndex()

			path := fmt.Sprintf(
				"/historysince/%s?userid=test:test&since=%d&limit=%d&from=%d",
				topic, startTime, 10, 0,
			)

			status, body := Get(a, path, t)
			g.Assert(status).Equal(http.StatusOK)

			var messages []Message
			err = json.Unmarshal([]byte(body), &messages)
			Expect(err).To(BeNil())
			Expect(len(messages)).To(Equal(3))
			var message Message
			for i := 0; i < len(messages); i++ {
				message = messages[i]
				Expect(message.Topic).To(Equal(topic))
			}
		})

		g.It("Should retrieve 1 message from history when limit is 1 and theres more than 1 message", func() {
			a := GetDefaultTestApp()
			testId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
			topic := fmt.Sprintf("chat/test_%s", testId)
			authStr := fmt.Sprintf("test:test-%s", topic)
			rc := redisclient.GetRedisClient("localhost", 4444, "")
			_, err := rc.Pool.Get().Do("set", "test:test", "lalala")
			_, err = rc.Pool.Get().Do("set", authStr, 2)
			Expect(err).To(BeNil())

			startTime := time.Now().UnixNano() / 1000000
			testMessage := Message{}
			for i := 0; i < 3; i++ {
				messageTime := time.Now().UnixNano() / 1000000
				testMessage = Message{
					Timestamp: msToTime(messageTime),
					Payload:   "{\"test1\":\"test2\"}",
					Topic:     topic,
				}
				_, err = esclient.Index().Index("chat").Type("message").BodyJson(testMessage).Do()
				Expect(err).To(BeNil())
			}

			// Sorry bout this =/
			time.Sleep(200 * time.Millisecond)

			// Update indexes
			refreshIndex()

			path := fmt.Sprintf(
				"/historysince/%s?userid=test:test&since=%d&limit=%d&from=%d",
				topic, startTime, 1, 0,
			)

			status, body := Get(a, path, t)
			g.Assert(status).Equal(http.StatusOK)

			var messages []Message
			err = json.Unmarshal([]byte(body), &messages)
			Expect(err).To(BeNil())
			Expect(len(messages)).To(Equal(1))

			var message Message
			for i := 0; i < len(messages); i++ {
				message = messages[i]
				Expect(message.Topic).To(Equal(topic))
			}
		})
	})
}
<|endoftext|>


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

// HTTP server.  See RFC 2616.

// TODO(rsc):
//	logging
//	cgi support
//	post support

package http

import (
	"bufio";
	"fmt";
	"http";
	"io";
	"log";
	"net";
	"os";
	"strconv";
)

var ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
var ErrHijacked = os.NewError("Conn has been hijacked")

type Conn struct

// Interface implemented by servers using this library.
type Handler interface {
	ServeHTTP(*Conn, *Request);
}

// Active HTTP connection (server side).
type Conn struct {
	RemoteAddr string;	// network address of remote side
	Req *Request;	// current HTTP request

	fd io.ReadWriteClose;	// i/o connection
	buf *bufio.BufReadWrite;	// buffered fd
	handler Handler;	// request handler
	hijacked bool;	// connection has been hijacked by handler

	// state for the current reply
	closeAfterReply bool;	// close connection after this reply
	chunking bool;	// using chunked transfer encoding for reply body
	wroteHeader bool;	// reply header has been written
	header map[string] string;	// reply header parameters
}

// Create new connection from rwc.
func newConn(rwc io.ReadWriteClose, raddr string, handler Handler) (c *Conn, err *os.Error) {
	c = new(Conn);
	c.RemoteAddr = raddr;
	c.handler = handler;
	c.fd = rwc;
	br := bufio.NewBufRead(rwc);
	bw := bufio.NewBufWrite(rwc);
	c.buf = bufio.NewBufReadWrite(br, bw);
	return c, nil
}

func (c *Conn) SetHeader(hdr, val string)

// Read next request from connection.
func (c *Conn) readRequest() (req *Request, err *os.Error) {
	if c.hijacked {
		return nil, ErrHijacked
	}
	if req, err = ReadRequest(c.buf.BufRead); err != nil {
		return nil, err
	}

	// Reset per-request connection state.
	c.header = make(map[string] string);
	c.wroteHeader = false;
	c.Req = req;

	// Default output is HTML encoded in UTF-8.
	c.SetHeader("Content-Type", "text/html; charset=utf-8");

	if req.ProtoAtLeast(1, 1) {
		// HTTP/1.1 or greater: use chunked transfer encoding
		// to avoid closing the connection at EOF.
		c.chunking = true;
		c.SetHeader("Transfer-Encoding", "chunked");
	} else {
		// HTTP version < 1.1: cannot do chunked transfer
		// encoding, so signal EOF by closing connection.
		// Could avoid closing the connection if there is
		// a Content-Length: header in the response,
		// but everyone who expects persistent connections
		// does HTTP/1.1 now.
		c.closeAfterReply = true;
		c.chunking = false;
	}

	return req, nil
}

func (c *Conn) SetHeader(hdr, val string) {
	c.header[CanonicalHeaderKey(hdr)] = val;
}

// Write header.
func (c *Conn) WriteHeader(code int) {
	if c.hijacked {
		log.Stderr("http: Conn.WriteHeader on hijacked connection");
		return
	}
	if c.wroteHeader {
		log.Stderr("http: multiple Conn.WriteHeader calls");
		return
	}
	c.wroteHeader = true;
	if !c.Req.ProtoAtLeast(1, 0) {
		return
	}
	proto := "HTTP/1.0";
	if c.Req.ProtoAtLeast(1, 1) {
		proto = "HTTP/1.1";
	}
	codestring := strconv.Itoa(code);
	text, ok := statusText[code];
	if !ok {
		text = "status code " + codestring;
	}
	io.WriteString(c.buf, proto + " " + codestring + " " + text + "\r\n");
	for k,v := range c.header {
		io.WriteString(c.buf, k + ": " + v + "\r\n");
	}
	io.WriteString(c.buf, "\r\n");
}

// TODO(rsc): BUG in 6g: must return "nn int" not "n int"
// so that the implicit struct assignment in
// return c.buf.Write(data) works.  oops
func (c *Conn) Write(data []byte) (nn int, err *os.Error) {
	if c.hijacked {
		log.Stderr("http: Conn.Write on hijacked connection");
		return 0, ErrHijacked
	}
	if !c.wroteHeader {
		c.WriteHeader(StatusOK);
	}
	if len(data) == 0 {
		return 0, nil
	}

	// TODO(rsc): if chunking happened after the buffering,
	// then there would be fewer chunk headers.
	// On the other hand, it would make hijacking more difficult.
	if c.chunking {
		fmt.Fprintf(c.buf, "%x\r\n", len(data));	// TODO(rsc): use strconv not fmt
	}
	return c.buf.Write(data);
}

func (c *Conn) flush() {
	if !c.wroteHeader {
		c.WriteHeader(StatusOK);
	}
	if c.chunking {
		io.WriteString(c.buf, "0\r\n");
		// trailer key/value pairs, followed by blank line
		io.WriteString(c.buf, "\r\n");
	}
	c.buf.Flush();
}

// Close the connection.
func (c *Conn) close() {
	if c.buf != nil {
		c.buf.Flush();
		c.buf = nil;
	}
	if c.fd != nil {
		c.fd.Close();
		c.fd = nil;
	}
}

// Serve a new connection.
func (c *Conn) serve() {
	for {
		req, err := c.readRequest();
		if err != nil {
			break
		}
		// HTTP cannot have multiple simultaneous active requests.
		// Until the server replies to this request, it can't read another,
		// so we might as well run the handler in this thread.
		c.handler.ServeHTTP(c, req);
		if c.hijacked {
			return;
		}
		c.flush();
		if c.closeAfterReply {
			break;
		}
	}
	c.close();
}

// Allow client to take over the connection.
// After a handler calls c.Hijack(), the HTTP server library
// will never touch the connection again.
// It is the caller's responsibility to manage and close
// the connection.
func (c *Conn) Hijack() (fd io.ReadWriteClose, buf *bufio.BufReadWrite, err *os.Error) {
	if c.hijacked {
		return nil, nil, ErrHijacked;
	}
	c.hijacked = true;
	fd = c.fd;
	buf = c.buf;
	c.fd = nil;
	c.buf = nil;
	return;
}

// Adapter: can use RequestFunction(f) as Handler
type handlerFunc struct {
	f func(*Conn, *Request)
}
func (h handlerFunc) ServeHTTP(c *Conn, req *Request) {
	h.f(c, req)
}
func HandlerFunc(f func(*Conn, *Request)) Handler {
	return handlerFunc{f}
}

/* simpler version of above, not accepted by 6g:

type HandlerFunc func(*Conn, *Request)
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
	f(c, req);
}
*/

// Helper handlers

// 404 not found
func notFound(c *Conn, req *Request) {
	c.SetHeader("Content-Type", "text/plain; charset=utf-8");
	c.WriteHeader(StatusNotFound);
	io.WriteString(c, "404 page not found\n");
}

var NotFoundHandler = HandlerFunc(notFound)

// Redirect to a fixed URL
type redirectHandler struct {
	to string;
}
func (h *redirectHandler) ServeHTTP(c *Conn, req *Request) {
	c.SetHeader("Location", h.to);
	c.WriteHeader(StatusMovedPermanently);
}

func RedirectHandler(to string) Handler {
	return &redirectHandler{to};
}

// Path-based HTTP request multiplexer.
// Patterns name fixed paths, like "/favicon.ico",
// or subtrees, like "/images/".
// For now, patterns must begin with /.
// Eventually, might want to allow host name
// at beginning of pattern, so that you could register
//	/codesearch
//	codesearch.google.com/
// but not take over /.

type ServeMux struct {
	m map[string] Handler
}

func NewServeMux() *ServeMux {
	return &ServeMux{make(map[string] Handler)};
}

var DefaultServeMux = NewServeMux();

// Does path match pattern?
func pathMatch(pattern, path string) bool {
	if len(pattern) == 0 {
		// should not happen
		return false
	}
	n := len(pattern);
	if pattern[n-1] != '/' {
		return pattern == path
	}
	return len(path) >= n && path[0:n] == pattern;
}

func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
	// Most-specific (longest) pattern wins.
	var h Handler;
	var n = 0;
	for k, v := range mux.m {
		if !pathMatch(k, req.Url.Path) {
			continue;
		}
		if h == nil || len(k) > n {
			n = len(k);
			h = v;
		}
	}
	if h == nil {
		h = NotFoundHandler;
	}
	h.ServeHTTP(c, req);
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	if pattern == "" || pattern[0] != '/' {
		panicln("http: invalid pattern", pattern);
	}

	mux.m[pattern] = handler;

	// Helpful behavior:
	// If pattern is /tree/, insert redirect for /tree.
	n := len(pattern);
	if n > 0 && pattern[n-1] == '/' {
		mux.m[pattern[0:n-1]] = RedirectHandler(pattern);
	}
}

func Handle(pattern string, h Handler) {
	DefaultServeMux.Handle(pattern, h);
}

// Web server: listening on l, call handler.ServeHTTP for each request.
func Serve(l net.Listener, handler Handler) *os.Error {
	if handler == nil {
		handler = DefaultServeMux;
	}
	for {
		rw, raddr, e := l.Accept();
		if e != nil {
			return e
		}
		c, err := newConn(rw, raddr, handler);
		if err != nil {
			continue;
		}
		go c.serve();
	}
	panic("not reached")
}

// Web server: listen on address, call f for each request.
func ListenAndServe(addr string, handler Handler) *os.Error {
	l, e := net.Listen("tcp", addr);
	if e != nil {
		return e
	}
	e = Serve(l, handler);
	l.Close();
	return e
}

<commit_msg>take advantage of methods on funcs<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// HTTP server.  See RFC 2616.

// TODO(rsc):
//	logging
//	cgi support
//	post support

package http

import (
	"bufio";
	"fmt";
	"http";
	"io";
	"log";
	"net";
	"os";
	"strconv";
)

var ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
var ErrHijacked = os.NewError("Conn has been hijacked")

type Conn struct

// Interface implemented by servers using this library.
type Handler interface {
	ServeHTTP(*Conn, *Request);
}

// Active HTTP connection (server side).
type Conn struct {
	RemoteAddr string;	// network address of remote side
	Req *Request;	// current HTTP request

	fd io.ReadWriteClose;	// i/o connection
	buf *bufio.BufReadWrite;	// buffered fd
	handler Handler;	// request handler
	hijacked bool;	// connection has been hijacked by handler

	// state for the current reply
	closeAfterReply bool;	// close connection after this reply
	chunking bool;	// using chunked transfer encoding for reply body
	wroteHeader bool;	// reply header has been written
	header map[string] string;	// reply header parameters
}

// Create new connection from rwc.
func newConn(rwc io.ReadWriteClose, raddr string, handler Handler) (c *Conn, err *os.Error) {
	c = new(Conn);
	c.RemoteAddr = raddr;
	c.handler = handler;
	c.fd = rwc;
	br := bufio.NewBufRead(rwc);
	bw := bufio.NewBufWrite(rwc);
	c.buf = bufio.NewBufReadWrite(br, bw);
	return c, nil
}

func (c *Conn) SetHeader(hdr, val string)

// Read next request from connection.
func (c *Conn) readRequest() (req *Request, err *os.Error) {
	if c.hijacked {
		return nil, ErrHijacked
	}
	if req, err = ReadRequest(c.buf.BufRead); err != nil {
		return nil, err
	}

	// Reset per-request connection state.
	c.header = make(map[string] string);
	c.wroteHeader = false;
	c.Req = req;

	// Default output is HTML encoded in UTF-8.
	c.SetHeader("Content-Type", "text/html; charset=utf-8");

	if req.ProtoAtLeast(1, 1) {
		// HTTP/1.1 or greater: use chunked transfer encoding
		// to avoid closing the connection at EOF.
		c.chunking = true;
		c.SetHeader("Transfer-Encoding", "chunked");
	} else {
		// HTTP version < 1.1: cannot do chunked transfer
		// encoding, so signal EOF by closing connection.
		// Could avoid closing the connection if there is
		// a Content-Length: header in the response,
		// but everyone who expects persistent connections
		// does HTTP/1.1 now.
		c.closeAfterReply = true;
		c.chunking = false;
	}

	return req, nil
}

func (c *Conn) SetHeader(hdr, val string) {
	c.header[CanonicalHeaderKey(hdr)] = val;
}

// Write header.
func (c *Conn) WriteHeader(code int) {
	if c.hijacked {
		log.Stderr("http: Conn.WriteHeader on hijacked connection");
		return
	}
	if c.wroteHeader {
		log.Stderr("http: multiple Conn.WriteHeader calls");
		return
	}
	c.wroteHeader = true;
	if !c.Req.ProtoAtLeast(1, 0) {
		return
	}
	proto := "HTTP/1.0";
	if c.Req.ProtoAtLeast(1, 1) {
		proto = "HTTP/1.1";
	}
	codestring := strconv.Itoa(code);
	text, ok := statusText[code];
	if !ok {
		text = "status code " + codestring;
	}
	io.WriteString(c.buf, proto + " " + codestring + " " + text + "\r\n");
	for k,v := range c.header {
		io.WriteString(c.buf, k + ": " + v + "\r\n");
	}
	io.WriteString(c.buf, "\r\n");
}

// TODO(rsc): BUG in 6g: must return "nn int" not "n int"
// so that the implicit struct assignment in
// return c.buf.Write(data) works.  oops
func (c *Conn) Write(data []byte) (nn int, err *os.Error) {
	if c.hijacked {
		log.Stderr("http: Conn.Write on hijacked connection");
		return 0, ErrHijacked
	}
	if !c.wroteHeader {
		c.WriteHeader(StatusOK);
	}
	if len(data) == 0 {
		return 0, nil
	}

	// TODO(rsc): if chunking happened after the buffering,
	// then there would be fewer chunk headers.
	// On the other hand, it would make hijacking more difficult.
	if c.chunking {
		fmt.Fprintf(c.buf, "%x\r\n", len(data));	// TODO(rsc): use strconv not fmt
	}
	return c.buf.Write(data);
}

func (c *Conn) flush() {
	if !c.wroteHeader {
		c.WriteHeader(StatusOK);
	}
	if c.chunking {
		io.WriteString(c.buf, "0\r\n");
		// trailer key/value pairs, followed by blank line
		io.WriteString(c.buf, "\r\n");
	}
	c.buf.Flush();
}

// Close the connection.
func (c *Conn) close() {
	if c.buf != nil {
		c.buf.Flush();
		c.buf = nil;
	}
	if c.fd != nil {
		c.fd.Close();
		c.fd = nil;
	}
}

// Serve a new connection.
func (c *Conn) serve() {
	for {
		req, err := c.readRequest();
		if err != nil {
			break
		}
		// HTTP cannot have multiple simultaneous active requests.
		// Until the server replies to this request, it can't read another,
		// so we might as well run the handler in this thread.
		c.handler.ServeHTTP(c, req);
		if c.hijacked {
			return;
		}
		c.flush();
		if c.closeAfterReply {
			break;
		}
	}
	c.close();
}

// Allow client to take over the connection.
// After a handler calls c.Hijack(), the HTTP server library
// will never touch the connection again.
// It is the caller's responsibility to manage and close
// the connection.
func (c *Conn) Hijack() (fd io.ReadWriteClose, buf *bufio.BufReadWrite, err *os.Error) {
	if c.hijacked {
		return nil, nil, ErrHijacked;
	}
	c.hijacked = true;
	fd = c.fd;
	buf = c.buf;
	c.fd = nil;
	c.buf = nil;
	return;
}

// Adapter: can use HandlerFunc(f) as Handler
type HandlerFunc func(*Conn, *Request)
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
	f(c, req);
}

// Helper handlers

// 404 not found
func notFound(c *Conn, req *Request) {
	c.SetHeader("Content-Type", "text/plain; charset=utf-8");
	c.WriteHeader(StatusNotFound);
	io.WriteString(c, "404 page not found\n");
}

var NotFoundHandler = HandlerFunc(notFound)

// Redirect to a fixed URL
type redirectHandler struct {
	to string;
}
func (h *redirectHandler) ServeHTTP(c *Conn, req *Request) {
	c.SetHeader("Location", h.to);
	c.WriteHeader(StatusMovedPermanently);
}

func RedirectHandler(to string) Handler {
	return &redirectHandler{to};
}

// Path-based HTTP request multiplexer.
// Patterns name fixed paths, like "/favicon.ico",
// or subtrees, like "/images/".
// For now, patterns must begin with /.
// Eventually, might want to allow host name
// at beginning of pattern, so that you could register
//	/codesearch
//	codesearch.google.com/
// but not take over /.

type ServeMux struct {
	m map[string] Handler
}

func NewServeMux() *ServeMux {
	return &ServeMux{make(map[string] Handler)};
}

var DefaultServeMux = NewServeMux();

// Does path match pattern?
func pathMatch(pattern, path string) bool {
	if len(pattern) == 0 {
		// should not happen
		return false
	}
	n := len(pattern);
	if pattern[n-1] != '/' {
		return pattern == path
	}
	return len(path) >= n && path[0:n] == pattern;
}

func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
	// Most-specific (longest) pattern wins.
	var h Handler;
	var n = 0;
	for k, v := range mux.m {
		if !pathMatch(k, req.Url.Path) {
			continue;
		}
		if h == nil || len(k) > n {
			n = len(k);
			h = v;
		}
	}
	if h == nil {
		h = NotFoundHandler;
	}
	h.ServeHTTP(c, req);
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	if pattern == "" || pattern[0] != '/' {
		panicln("http: invalid pattern", pattern);
	}

	mux.m[pattern] = handler;

	// Helpful behavior:
	// If pattern is /tree/, insert redirect for /tree.
	n := len(pattern);
	if n > 0 && pattern[n-1] == '/' {
		mux.m[pattern[0:n-1]] = RedirectHandler(pattern);
	}
}

func Handle(pattern string, h Handler) {
	DefaultServeMux.Handle(pattern, h);
}

// Web server: listening on l, call handler.ServeHTTP for each request.
func Serve(l net.Listener, handler Handler) *os.Error {
	if handler == nil {
		handler = DefaultServeMux;
	}
	for {
		rw, raddr, e := l.Accept();
		if e != nil {
			return e
		}
		c, err := newConn(rw, raddr, handler);
		if err != nil {
			continue;
		}
		go c.serve();
	}
	panic("not reached")
}

// Web server: listen on address, call f for each request.
func ListenAndServe(addr string, handler Handler) *os.Error {
	l, e := net.Listen("tcp", addr);
	if e != nil {
		return e
	}
	e = Serve(l, handler);
	l.Close();
	return e
}

<|endoftext|>


<commit_before>package parse

import (
	"../vm"
	"./comb"
)

const spaceChars = " ,\t\n\r"

func Parse(source string) vm.Object {
	o, err := newState(source).module()()

	if err != nil {
		panic(err.Error())
	}

	return o
}

func (s *state) module() comb.Parser {
	return s.Exhaust(s.elems())
}

func (s *state) elems() comb.Parser {
	return s.Lazy(s.strictElems)
}

func (s *state) strictElems() comb.Parser {
	return s.Many(s.elem())
}

func (s *state) elem() comb.Parser {
	ps := []comb.Parser{s.atom(), s.list(), s.array(), s.dict()}

	return s.strip(s.Or(append(ps, s.quotes(ps...)...)...))
}

func (s *state) atom() comb.Parser {
	return s.Or(s.stringLiteral(), s.identifier())
}

func (s *state) identifier() comb.Parser {
	return s.stringify(s.Many1(s.NotInString("()[]{}$'\x00" + spaceChars)))
}

func (s *state) stringLiteral() comb.Parser {
	b := s.blank()
	c := s.Char('"')

	return s.stringify(s.Wrap(
		c,
		s.Many(s.Or(s.NotInString("\"\\"), s.String("\\\""), s.String("\\\\"))),
		s.And(c, b)))
}

func (s *state) list() comb.Parser {
	return s.sequence('(', ')')
}

func (s *state) array() comb.Parser {
	return s.sequence('[', ']')
}

func (s *state) dict() comb.Parser {
	return s.sequence('{', '}')
}

func (s *state) sequence(l, r rune) comb.Parser {
	return s.wrapChars(l, s.elems(), r)
}

func (s *state) comment() comb.Parser {
	return s.Void(s.And(s.Char(';'), s.Many(s.NotChar('\n')), s.Char('\n')))
}

func (s *state) wrapChars(l rune, p comb.Parser, r rune) comb.Parser {
	return s.Wrap(s.And(s.Char(l), s.blank()), p, s.strippedChar(r))
}

func (s *state) strippedChar(r rune) comb.Parser {
	return s.strip(s.Char(r))
}

func (s *state) strip(p comb.Parser) comb.Parser {
	b := s.blank()
	return s.Wrap(b, p, b)
}

func (s *state) blank() comb.Parser {
	return s.Void(s.Many(s.Or(s.space(), s.comment())))
}

func (s *state) space() comb.Parser {
	return s.Void(s.Many1(s.InString(spaceChars)))
}

func (s *state) quote(p comb.Parser) comb.Parser {
	return s.And(s.Char('\''), p)
}

func (s *state) quotes(ps ...comb.Parser) []comb.Parser {
	qs := make([]comb.Parser, len(ps))

	for i, p := range ps {
		qs[i] = s.quote(p)
	}

	return qs
}

func (s *state) stringify(p comb.Parser) comb.Parser {
	f := func(any interface{}) interface{} {
		xs := any.([]interface{})
		rs := make([]rune, len(xs))

		for i, x := range xs {
			rs[i] = x.(rune)
		}

		return vm.NewString(string(rs))
	}

	return s.App(f, p)
}
<commit_msg>Don't return Object<commit_after>package parse

import (
	"./comb"
)

const spaceChars = " ,\t\n\r"

func Parse(source string) []interface{} {
	m, err := newState(source).module()()

	if err != nil {
		panic(err.Error())
	}

	return m.([]interface{})
}

func (s *state) module() comb.Parser {
	return s.Exhaust(s.elems())
}

func (s *state) elems() comb.Parser {
	return s.Lazy(s.strictElems)
}

func (s *state) strictElems() comb.Parser {
	return s.Many(s.elem())
}

func (s *state) elem() comb.Parser {
	ps := []comb.Parser{s.atom(), s.list(), s.array(), s.dict()}

	return s.strip(s.Or(append(ps, s.quotes(ps...)...)...))
}

func (s *state) atom() comb.Parser {
	return s.Or(s.stringLiteral(), s.identifier())
}

func (s *state) identifier() comb.Parser {
	return s.stringify(s.Many1(s.NotInString("()[]{}$'\x00" + spaceChars)))
}

func (s *state) stringLiteral() comb.Parser {
	b := s.blank()
	c := s.Char('"')

	return s.stringify(s.Wrap(
		c,
		s.Many(s.Or(s.NotInString("\"\\"), s.String("\\\""), s.String("\\\\"))),
		s.And(c, b)))
}

func (s *state) list() comb.Parser {
	return s.sequence('(', ')')
}

func (s *state) array() comb.Parser {
	return s.sequence('[', ']')
}

func (s *state) dict() comb.Parser {
	return s.sequence('{', '}')
}

func (s *state) sequence(l, r rune) comb.Parser {
	return s.wrapChars(l, s.elems(), r)
}

func (s *state) comment() comb.Parser {
	return s.Void(s.And(s.Char(';'), s.Many(s.NotChar('\n')), s.Char('\n')))
}

func (s *state) wrapChars(l rune, p comb.Parser, r rune) comb.Parser {
	return s.Wrap(s.And(s.Char(l), s.blank()), p, s.strippedChar(r))
}

func (s *state) strippedChar(r rune) comb.Parser {
	return s.strip(s.Char(r))
}

func (s *state) strip(p comb.Parser) comb.Parser {
	b := s.blank()
	return s.Wrap(b, p, b)
}

func (s *state) blank() comb.Parser {
	return s.Void(s.Many(s.Or(s.space(), s.comment())))
}

func (s *state) space() comb.Parser {
	return s.Void(s.Many1(s.InString(spaceChars)))
}

func (s *state) quote(p comb.Parser) comb.Parser {
	return s.And(s.Char('\''), p)
}

func (s *state) quotes(ps ...comb.Parser) []comb.Parser {
	qs := make([]comb.Parser, len(ps))

	for i, p := range ps {
		qs[i] = s.quote(p)
	}

	return qs
}

func (s *state) stringify(p comb.Parser) comb.Parser {
	f := func(any interface{}) interface{} {
		xs := any.([]interface{})
		rs := make([]rune, len(xs))

		for i, x := range xs {
			rs[i] = x.(rune)
		}

		return string(rs)
	}

	return s.App(f, p)
}
<|endoftext|>


<commit_before>package libnetwork

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/iptables"
	"github.com/miekg/dns"
)

// Resolver represents the embedded DNS server in Docker. It operates
// by listening on container's loopback interface for DNS queries.
type Resolver interface {
	// Start starts the name server for the container
	Start() error
	// Stop stops the name server for the container. Stopped resolver
	// can be reused after running the SetupFunc again.
	Stop()
	// SetupFunc() provides the setup function that should be run
	// in the container's network namespace.
	SetupFunc() func()
	// NameServer() returns the IP of the DNS resolver for the
	// containers.
	NameServer() string
	// To configure external name servers the resolver should use
	SetExtServers([]string)
	// ResolverOptions returns resolv.conf options that should be set
	ResolverOptions() []string
}

const (
	resolverIP      = "127.0.0.11"
	dnsPort         = "53"
	ptrIPv4domain   = ".in-addr.arpa."
	ptrIPv6domain   = ".ip6.arpa."
	respTTL         = 600
	maxExtDNS       = 3 //max number of external servers to try
	extIOTimeout    = 3 * time.Second
	defaultRespSize = 512
)

type extDNSEntry struct {
	ipStr   string
	extConn net.Conn
	extOnce sync.Once
}

// resolver implements the Resolver interface
type resolver struct {
	sb         *sandbox
	extDNSList [maxExtDNS]extDNSEntry
	server     *dns.Server
	conn       *net.UDPConn
	tcpServer  *dns.Server
	tcpListen  *net.TCPListener
	err        error
}

func init() {
	rand.Seed(time.Now().Unix())
}

// NewResolver creates a new instance of the Resolver
func NewResolver(sb *sandbox) Resolver {
	return &resolver{
		sb:  sb,
		err: fmt.Errorf("setup not done yet"),
	}
}

func (r *resolver) SetupFunc() func() {
	return (func() {
		var err error

		// DNS operates primarily on UDP
		addr := &net.UDPAddr{
			IP: net.ParseIP(resolverIP),
		}

		r.conn, err = net.ListenUDP("udp", addr)
		if err != nil {
			r.err = fmt.Errorf("error in opening name server socket %v", err)
			return
		}
		laddr := r.conn.LocalAddr()
		_, ipPort, _ := net.SplitHostPort(laddr.String())

		// Listen on a TCP as well
		tcpaddr := &net.TCPAddr{
			IP: net.ParseIP(resolverIP),
		}

		r.tcpListen, err = net.ListenTCP("tcp", tcpaddr)
		if err != nil {
			r.err = fmt.Errorf("error in opening name TCP server socket %v", err)
			return
		}
		ltcpaddr := r.tcpListen.Addr()
		_, tcpPort, _ := net.SplitHostPort(ltcpaddr.String())
		rules := [][]string{
			{"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", laddr.String()},
			{"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
			{"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", ltcpaddr.String()},
			{"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
		}

		for _, rule := range rules {
			r.err = iptables.RawCombinedOutputNative(rule...)
			if r.err != nil {
				return
			}
		}
		r.err = nil
	})
}

func (r *resolver) Start() error {
	// make sure the resolver has been setup before starting
	if r.err != nil {
		return r.err
	}
	s := &dns.Server{Handler: r, PacketConn: r.conn}
	r.server = s
	go func() {
		s.ActivateAndServe()
	}()

	tcpServer := &dns.Server{Handler: r, Listener: r.tcpListen}
	r.tcpServer = tcpServer
	go func() {
		tcpServer.ActivateAndServe()
	}()
	return nil
}

func (r *resolver) Stop() {
	for i := 0; i < maxExtDNS; i++ {
		r.extDNSList[i].extConn = nil
		r.extDNSList[i].extOnce = sync.Once{}
	}

	if r.server != nil {
		r.server.Shutdown()
	}
	if r.tcpServer != nil {
		r.tcpServer.Shutdown()
	}
	r.conn = nil
	r.tcpServer = nil
	r.err = fmt.Errorf("setup not done yet")
}

func (r *resolver) SetExtServers(dns []string) {
	l := len(dns)
	if l > maxExtDNS {
		l = maxExtDNS
	}
	for i := 0; i < l; i++ {
		r.extDNSList[i].ipStr = dns[i]
	}
}

func (r *resolver) NameServer() string {
	return resolverIP
}

func (r *resolver) ResolverOptions() []string {
	return []string{"ndots:0"}
}

func setCommonFlags(msg *dns.Msg) {
	msg.RecursionAvailable = true
}

func shuffleAddr(addr []net.IP) []net.IP {
	for i := len(addr) - 1; i > 0; i-- {
		r := rand.Intn(i + 1)
		addr[i], addr[r] = addr[r], addr[i]
	}
	return addr
}

func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
	addr := r.sb.ResolveName(name)
	if addr == nil {
		return nil, nil
	}

	log.Debugf("Lookup for %s: IP %v", name, addr)

	resp := new(dns.Msg)
	resp.SetReply(query)
	setCommonFlags(resp)

	if len(addr) > 1 {
		addr = shuffleAddr(addr)
	}

	for _, ip := range addr {
		rr := new(dns.A)
		rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
		rr.A = ip
		resp.Answer = append(resp.Answer, rr)
	}
	return resp, nil
}

func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) {
	parts := []string{}

	if strings.HasSuffix(ptr, ptrIPv4domain) {
		parts = strings.Split(ptr, ptrIPv4domain)
	} else if strings.HasSuffix(ptr, ptrIPv6domain) {
		parts = strings.Split(ptr, ptrIPv6domain)
	} else {
		return nil, fmt.Errorf("invalid PTR query, %v", ptr)
	}

	host := r.sb.ResolveIP(parts[0])
	if len(host) == 0 {
		return nil, nil
	}

	log.Debugf("Lookup for IP %s: name %s", parts[0], host)
	fqdn := dns.Fqdn(host)

	resp := new(dns.Msg)
	resp.SetReply(query)
	setCommonFlags(resp)

	rr := new(dns.PTR)
	rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
	rr.Ptr = fqdn
	resp.Answer = append(resp.Answer, rr)
	return resp, nil
}

func truncateResp(resp *dns.Msg, maxSize int, isTCP bool) {
	if !isTCP {
		resp.Truncated = true
	}

	// trim the Answer RRs one by one till the whole message fits
	// within the reply size
	for resp.Len() > maxSize {
		resp.Answer = resp.Answer[:len(resp.Answer)-1]
	}
}

func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
	var (
		extConn net.Conn
		resp    *dns.Msg
		err     error
	)

	if query == nil || len(query.Question) == 0 {
		return
	}
	name := query.Question[0].Name
	if query.Question[0].Qtype == dns.TypeA {
		resp, err = r.handleIPv4Query(name, query)
	} else if query.Question[0].Qtype == dns.TypePTR {
		resp, err = r.handlePTRQuery(name, query)
	}

	if err != nil {
		log.Error(err)
		return
	}

	proto := w.LocalAddr().Network()
	maxSize := 0
	if proto == "tcp" {
		maxSize = dns.MaxMsgSize - 1
	} else if proto == "udp" {
		optRR := query.IsEdns0()
		if optRR != nil {
			maxSize = int(optRR.UDPSize())
		}
		if maxSize < defaultRespSize {
			maxSize = defaultRespSize
		}
	}

	if resp != nil {
		if resp.Len() > maxSize {
			truncateResp(resp, maxSize, proto == "tcp")
		}
	} else {
		for i := 0; i < maxExtDNS; i++ {
			extDNS := &r.extDNSList[i]
			if extDNS.ipStr == "" {
				break
			}
			log.Debugf("Querying ext dns %s:%s for %s[%d]", proto, extDNS.ipStr, name, query.Question[0].Qtype)

			extConnect := func() {
				addr := fmt.Sprintf("%s:%d", extDNS.ipStr, 53)
				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
			}

			// For udp clients connection is persisted to reuse for further queries.
			// Accessing extDNS.extConn be a race here between go rouines. Hence the
			// connection setup is done in a Once block and fetch the extConn again
			extConn = extDNS.extConn
			if extConn == nil || proto == "tcp" {
				if proto == "udp" {
					extDNS.extOnce.Do(func() {
						r.sb.execFunc(extConnect)
						extDNS.extConn = extConn
					})
					extConn = extDNS.extConn
				} else {
					r.sb.execFunc(extConnect)
				}
				if err != nil {
					log.Debugf("Connect failed, %s", err)
					continue
				}
			}

			// Timeout has to be set for every IO operation.
			extConn.SetDeadline(time.Now().Add(extIOTimeout))
			co := &dns.Conn{Conn: extConn}

			defer func() {
				if proto == "tcp" {
					co.Close()
				}
			}()
			err = co.WriteMsg(query)
			if err != nil {
				log.Debugf("Send to DNS server failed, %s", err)
				continue
			}

			resp, err = co.ReadMsg()
			if err != nil {
				log.Debugf("Read from DNS server failed, %s", err)
				continue
			}

			resp.Compress = true
			break
		}

		if resp == nil {
			return
		}
	}

	err = w.WriteMsg(resp)
	if err != nil {
		log.Errorf("error writing resolver resp, %s", err)
	}
}
<commit_msg>Fix nil pointer reference in ServeDNS() with concurrent go routines.<commit_after>package libnetwork

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/iptables"
	"github.com/miekg/dns"
)

// Resolver represents the embedded DNS server in Docker. It operates
// by listening on container's loopback interface for DNS queries.
type Resolver interface {
	// Start starts the name server for the container
	Start() error
	// Stop stops the name server for the container. Stopped resolver
	// can be reused after running the SetupFunc again.
	Stop()
	// SetupFunc() provides the setup function that should be run
	// in the container's network namespace.
	SetupFunc() func()
	// NameServer() returns the IP of the DNS resolver for the
	// containers.
	NameServer() string
	// To configure external name servers the resolver should use
	SetExtServers([]string)
	// ResolverOptions returns resolv.conf options that should be set
	ResolverOptions() []string
}

const (
	resolverIP      = "127.0.0.11"
	dnsPort         = "53"
	ptrIPv4domain   = ".in-addr.arpa."
	ptrIPv6domain   = ".ip6.arpa."
	respTTL         = 600
	maxExtDNS       = 3 //max number of external servers to try
	extIOTimeout    = 3 * time.Second
	defaultRespSize = 512
)

type extDNSEntry struct {
	ipStr   string
	extConn net.Conn
	extOnce sync.Once
}

// resolver implements the Resolver interface
type resolver struct {
	sb         *sandbox
	extDNSList [maxExtDNS]extDNSEntry
	server     *dns.Server
	conn       *net.UDPConn
	tcpServer  *dns.Server
	tcpListen  *net.TCPListener
	err        error
}

func init() {
	rand.Seed(time.Now().Unix())
}

// NewResolver creates a new instance of the Resolver
func NewResolver(sb *sandbox) Resolver {
	return &resolver{
		sb:  sb,
		err: fmt.Errorf("setup not done yet"),
	}
}

func (r *resolver) SetupFunc() func() {
	return (func() {
		var err error

		// DNS operates primarily on UDP
		addr := &net.UDPAddr{
			IP: net.ParseIP(resolverIP),
		}

		r.conn, err = net.ListenUDP("udp", addr)
		if err != nil {
			r.err = fmt.Errorf("error in opening name server socket %v", err)
			return
		}
		laddr := r.conn.LocalAddr()
		_, ipPort, _ := net.SplitHostPort(laddr.String())

		// Listen on a TCP as well
		tcpaddr := &net.TCPAddr{
			IP: net.ParseIP(resolverIP),
		}

		r.tcpListen, err = net.ListenTCP("tcp", tcpaddr)
		if err != nil {
			r.err = fmt.Errorf("error in opening name TCP server socket %v", err)
			return
		}
		ltcpaddr := r.tcpListen.Addr()
		_, tcpPort, _ := net.SplitHostPort(ltcpaddr.String())
		rules := [][]string{
			{"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", laddr.String()},
			{"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
			{"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", ltcpaddr.String()},
			{"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
		}

		for _, rule := range rules {
			r.err = iptables.RawCombinedOutputNative(rule...)
			if r.err != nil {
				return
			}
		}
		r.err = nil
	})
}

func (r *resolver) Start() error {
	// make sure the resolver has been setup before starting
	if r.err != nil {
		return r.err
	}
	s := &dns.Server{Handler: r, PacketConn: r.conn}
	r.server = s
	go func() {
		s.ActivateAndServe()
	}()

	tcpServer := &dns.Server{Handler: r, Listener: r.tcpListen}
	r.tcpServer = tcpServer
	go func() {
		tcpServer.ActivateAndServe()
	}()
	return nil
}

func (r *resolver) Stop() {
	for i := 0; i < maxExtDNS; i++ {
		r.extDNSList[i].extConn = nil
		r.extDNSList[i].extOnce = sync.Once{}
	}

	if r.server != nil {
		r.server.Shutdown()
	}
	if r.tcpServer != nil {
		r.tcpServer.Shutdown()
	}
	r.conn = nil
	r.tcpServer = nil
	r.err = fmt.Errorf("setup not done yet")
}

func (r *resolver) SetExtServers(dns []string) {
	l := len(dns)
	if l > maxExtDNS {
		l = maxExtDNS
	}
	for i := 0; i < l; i++ {
		r.extDNSList[i].ipStr = dns[i]
	}
}

func (r *resolver) NameServer() string {
	return resolverIP
}

func (r *resolver) ResolverOptions() []string {
	return []string{"ndots:0"}
}

func setCommonFlags(msg *dns.Msg) {
	msg.RecursionAvailable = true
}

func shuffleAddr(addr []net.IP) []net.IP {
	for i := len(addr) - 1; i > 0; i-- {
		r := rand.Intn(i + 1)
		addr[i], addr[r] = addr[r], addr[i]
	}
	return addr
}

func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
	addr := r.sb.ResolveName(name)
	if addr == nil {
		return nil, nil
	}

	log.Debugf("Lookup for %s: IP %v", name, addr)

	resp := new(dns.Msg)
	resp.SetReply(query)
	setCommonFlags(resp)

	if len(addr) > 1 {
		addr = shuffleAddr(addr)
	}

	for _, ip := range addr {
		rr := new(dns.A)
		rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
		rr.A = ip
		resp.Answer = append(resp.Answer, rr)
	}
	return resp, nil
}

func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) {
	parts := []string{}

	if strings.HasSuffix(ptr, ptrIPv4domain) {
		parts = strings.Split(ptr, ptrIPv4domain)
	} else if strings.HasSuffix(ptr, ptrIPv6domain) {
		parts = strings.Split(ptr, ptrIPv6domain)
	} else {
		return nil, fmt.Errorf("invalid PTR query, %v", ptr)
	}

	host := r.sb.ResolveIP(parts[0])
	if len(host) == 0 {
		return nil, nil
	}

	log.Debugf("Lookup for IP %s: name %s", parts[0], host)
	fqdn := dns.Fqdn(host)

	resp := new(dns.Msg)
	resp.SetReply(query)
	setCommonFlags(resp)

	rr := new(dns.PTR)
	rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
	rr.Ptr = fqdn
	resp.Answer = append(resp.Answer, rr)
	return resp, nil
}

func truncateResp(resp *dns.Msg, maxSize int, isTCP bool) {
	if !isTCP {
		resp.Truncated = true
	}

	// trim the Answer RRs one by one till the whole message fits
	// within the reply size
	for resp.Len() > maxSize {
		resp.Answer = resp.Answer[:len(resp.Answer)-1]
	}
}

func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
	var (
		extConn net.Conn
		resp    *dns.Msg
		err     error
	)

	if query == nil || len(query.Question) == 0 {
		return
	}
	name := query.Question[0].Name
	if query.Question[0].Qtype == dns.TypeA {
		resp, err = r.handleIPv4Query(name, query)
	} else if query.Question[0].Qtype == dns.TypePTR {
		resp, err = r.handlePTRQuery(name, query)
	}

	if err != nil {
		log.Error(err)
		return
	}

	proto := w.LocalAddr().Network()
	maxSize := 0
	if proto == "tcp" {
		maxSize = dns.MaxMsgSize - 1
	} else if proto == "udp" {
		optRR := query.IsEdns0()
		if optRR != nil {
			maxSize = int(optRR.UDPSize())
		}
		if maxSize < defaultRespSize {
			maxSize = defaultRespSize
		}
	}

	if resp != nil {
		if resp.Len() > maxSize {
			truncateResp(resp, maxSize, proto == "tcp")
		}
	} else {
		for i := 0; i < maxExtDNS; i++ {
			extDNS := &r.extDNSList[i]
			if extDNS.ipStr == "" {
				break
			}
			log.Debugf("Querying ext dns %s:%s for %s[%d]", proto, extDNS.ipStr, name, query.Question[0].Qtype)

			extConnect := func() {
				addr := fmt.Sprintf("%s:%d", extDNS.ipStr, 53)
				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
			}

			// For udp clients connection is persisted to reuse for further queries.
			// Accessing extDNS.extConn be a race here between go rouines. Hence the
			// connection setup is done in a Once block and fetch the extConn again
			extConn = extDNS.extConn
			if extConn == nil || proto == "tcp" {
				if proto == "udp" {
					extDNS.extOnce.Do(func() {
						r.sb.execFunc(extConnect)
						extDNS.extConn = extConn
					})
					extConn = extDNS.extConn
				} else {
					r.sb.execFunc(extConnect)
				}
				if err != nil {
					log.Debugf("Connect failed, %s", err)
					continue
				}
			}
			// If two go routines are executing in parralel one will
			// block on the Once.Do and in case of error connecting
			// to the external server it will end up with a nil err
			// but extConn also being nil.
			if extConn == nil {
				continue
			}

			// Timeout has to be set for every IO operation.
			extConn.SetDeadline(time.Now().Add(extIOTimeout))
			co := &dns.Conn{Conn: extConn}

			defer func() {
				if proto == "tcp" {
					co.Close()
				}
			}()
			err = co.WriteMsg(query)
			if err != nil {
				log.Debugf("Send to DNS server failed, %s", err)
				continue
			}

			resp, err = co.ReadMsg()
			if err != nil {
				log.Debugf("Read from DNS server failed, %s", err)
				continue
			}

			resp.Compress = true
			break
		}

		if resp == nil {
			return
		}
	}

	err = w.WriteMsg(resp)
	if err != nil {
		log.Errorf("error writing resolver resp, %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"
)

var (
	cmd       *exec.Cmd
	state     sync.Mutex
	eventTime = make(map[string]time.Time)
)

func NewWatcher(paths []string) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for {
			select {
			case e := <-watcher.Event:
				isbuild := true

				// Skip TMP files for Sublime Text.
				if checkTMPFile(e.Name) {
					continue
				}

				if t, ok := eventTime[e.Name]; ok {
					// if 500ms change many times, then ignore it.
					// for liteide often gofmt code after save.
					if t.Add(time.Millisecond * 500).After(time.Now()) {
						fmt.Println("[SKIP]", e.String())
						isbuild = false
					}
				}
				eventTime[e.Name] = time.Now()

				if isbuild {
					fmt.Println("[EVEN]", e)
					go Autobuild()
				}
			case err := <-watcher.Error:
				log.Fatal("error:", err)
			}
		}
	}()

	fmt.Println("[INFO] Initializing watcher...")
	for _, path := range paths {
		fmt.Println(path)
		err = watcher.Watch(path)
		if err != nil {
			log.Fatal(err)
		}
	}

}

func Autobuild() {
	state.Lock()
	defer state.Unlock()

	fmt.Println("[INFO] Start building...")
	path, _ := os.Getwd()
	os.Chdir(path)

	var err error
	// For applications use full import path like "github.com/.../.."
	// are able to use "go install" to reduce build time.
	if conf.GoInstall {
		icmd := exec.Command("go", "install")
		icmd.Stdout = os.Stdout
		icmd.Stderr = os.Stderr
		err = icmd.Run()
	}

	if err == nil {
		bcmd := exec.Command("go", "build")
		bcmd.Stdout = os.Stdout
		bcmd.Stderr = os.Stderr
		err = bcmd.Run()
	}

	if err != nil {
		fmt.Println("[ERRO] ============== Build failed ===================")
		return
	}
	fmt.Println("[SUCC] Build was successful")
	Restart(appname)
}

func Kill() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Println("Kill -> ", e)
		}
	}()
	if cmd != nil {
		cmd.Process.Kill()
	}
}

func Restart(appname string) {
	Debugf("kill running process")
	Kill()
	go Start(appname)
}

func Start(appname string) {
	fmt.Println("[INFO] Restarting", appname)
	if strings.Index(appname, "./") == -1 {
		appname = "./" + appname
	}

	cmd = exec.Command(appname)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	go cmd.Run()
}

// checkTMPFile returns true if the event was for TMP files.
func checkTMPFile(name string) bool {
	if strings.HasSuffix(strings.ToLower(name), ".tmp") {
		return true
	}
	return false
}
<commit_msg>only watch go file's modify<commit_after>package main

import (
	"fmt"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"
)

var (
	cmd       *exec.Cmd
	state     sync.Mutex
	eventTime = make(map[string]time.Time)
)

func NewWatcher(paths []string) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for {
			select {
			case e := <-watcher.Event:
				isbuild := true

				// Skip TMP files for Sublime Text.
				if checkTMPFile(e.Name) {
					continue
				}
				if !checkIsGoFile(e.Name) {
					continue
				}

				if t, ok := eventTime[e.Name]; ok {
					// if 500ms change many times, then ignore it.
					// for liteide often gofmt code after save.
					if t.Add(time.Millisecond * 500).After(time.Now()) {
						fmt.Println("[SKIP]", e.String())
						isbuild = false
					}
				}
				eventTime[e.Name] = time.Now()

				if isbuild {
					fmt.Println("[EVEN]", e)
					go Autobuild()
				}
			case err := <-watcher.Error:
				log.Fatal("error:", err)
			}
		}
	}()

	fmt.Println("[INFO] Initializing watcher...")
	for _, path := range paths {
		fmt.Println(path)
		err = watcher.Watch(path)
		if err != nil {
			log.Fatal(err)
		}
	}

}

func Autobuild() {
	state.Lock()
	defer state.Unlock()

	fmt.Println("[INFO] Start building...")
	path, _ := os.Getwd()
	os.Chdir(path)

	var err error
	// For applications use full import path like "github.com/.../.."
	// are able to use "go install" to reduce build time.
	if conf.GoInstall {
		icmd := exec.Command("go", "install")
		icmd.Stdout = os.Stdout
		icmd.Stderr = os.Stderr
		err = icmd.Run()
	}

	if err == nil {
		bcmd := exec.Command("go", "build")
		bcmd.Stdout = os.Stdout
		bcmd.Stderr = os.Stderr
		err = bcmd.Run()
	}

	if err != nil {
		fmt.Println("[ERRO] ============== Build failed ===================")
		return
	}
	fmt.Println("[SUCC] Build was successful")
	Restart(appname)
}

func Kill() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Println("Kill -> ", e)
		}
	}()
	if cmd != nil {
		cmd.Process.Kill()
	}
}

func Restart(appname string) {
	Debugf("kill running process")
	Kill()
	go Start(appname)
}

func Start(appname string) {
	fmt.Println("[INFO] Restarting", appname)
	if strings.Index(appname, "./") == -1 {
		appname = "./" + appname
	}

	cmd = exec.Command(appname)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	go cmd.Run()
}

// checkTMPFile returns true if the event was for TMP files.
func checkTMPFile(name string) bool {
	if strings.HasSuffix(strings.ToLower(name), ".tmp") {
		return true
	}
	return false
}

// checkIsGoFile return true if the name is HasSuffix go
func checkIsGoFile(name string) bool {
	if strings.HasSuffix(name, ".go") {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package wrap

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mkr/logger"
	"golang.org/x/sync/errgroup"
	cli "gopkg.in/urfave/cli.v1"
)

// CommandPlugin is definition of mkr plugin
var Command = cli.Command{
	Name:      "wrap",
	Usage:     "wrap command status",
	ArgsUsage: "[--verbose | -v] [--name | -n <name>] [--memo | -m <memo>] -- /path/to/batch",
	Description: `
    wrap command line
`,
	Action: doWrap,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "name, n", Value: "", Usage: "monitor <name>"},
		cli.BoolFlag{Name: "verbose, v", Usage: "verbose output mode"},
		cli.StringFlag{Name: "memo, m", Value: "", Usage: "monitor <memo>"},
		cli.StringFlag{Name: "H, host", Value: "", Usage: "<hostId>"},
		cli.BoolFlag{Name: "warning, w", Usage: "alert as warning"},
	},
}

func doWrap(c *cli.Context) error {
	confFile := c.GlobalString("conf")
	conf, err := config.LoadConfig(confFile)
	if err != nil {
		return err
	}
	apibase := c.GlobalString("apibase")
	apikey := conf.Apikey
	if apikey == "" {
		apikey = os.Getenv("MACKEREL_APIKEY")
	}
	if apikey == "" {
		logger.Log("error", "[mkr wrap] failed to detect Mackerel APIKey. Try to specify in mackerel-agent.conf or export MACKEREL_APIKEY='<Your apikey>'")
	}
	hostID, _ := conf.LoadHostID()
	if c.String("host") != "" {
		hostID = c.String("host")
	}
	if hostID == "" {
		logger.Log("error", "[mkr wrap] failed to load hostID. Try to specify -host option explicitly")
	}
	// Since command execution has the highest priority, even when apikey or
	// hostID is empty, we don't return errors and only output the log here.

	cmd := c.Args()
	if len(cmd) > 0 && cmd[0] == "--" {
		cmd = cmd[1:]
	}
	if len(cmd) < 1 {
		return fmt.Errorf("no commands specified")
	}

	return (&app{
		apibase: apibase,
		name:    c.String("name"),
		verbose: c.Bool("verbose"),
		memo:    c.String("memo"),
		warning: c.Bool("warning"),
		hostID:  hostID,
		apikey:  apikey,
		cmd:     cmd,
	}).run()
}

type app struct {
	apibase string
	name    string
	verbose bool
	memo    string
	warning bool
	hostID  string
	apikey  string
	cmd     []string
}

type result struct {
	Cmd        []string
	Name, Memo string

	Output, Stdout, Stderr string
	Pid                    int
	ExitCode               *int
	Signaled               bool
	StartAt, EndAt         time.Time

	Msg     string
	Success bool
}

func (ap *app) run() error {
	re := ap.runCmd()
	return ap.report(re)
}

func (ap *app) runCmd() *result {
	cmd := exec.Command(ap.cmd[0], ap.cmd[1:]...)
	re := &result{
		Cmd:  ap.cmd,
		Name: ap.name,
		Memo: ap.memo,
	}

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		re.Msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stdoutPipe.Close()

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		re.Msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stderrPipe.Close()

	var (
		bufStdout = &bytes.Buffer{}
		bufStderr = &bytes.Buffer{}
		bufMerged = &bytes.Buffer{}
	)
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(bufStdout, bufMerged))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(bufStderr, bufMerged))

	re.StartAt = time.Now()
	err = cmd.Start()
	if err != nil {
		re.Msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	re.Pid = cmd.Process.Pid
	eg := &errgroup.Group{}

	eg.Go(func() error {
		defer stdoutPipe.Close()
		_, err := io.Copy(os.Stdout, stdoutPipe2)
		return err
	})
	eg.Go(func() error {
		defer stderrPipe.Close()
		_, err := io.Copy(os.Stderr, stderrPipe2)
		return err
	})
	eg.Wait()

	cmdErr := cmd.Wait()
	re.EndAt = time.Now()
	ex := wrapcommander.ResolveExitCode(cmdErr)
	re.ExitCode = &ex
	if *re.ExitCode > 128 {
		w, ok := wrapcommander.ErrorToWaitStatus(cmdErr)
		if ok {
			re.Signaled = w.Signaled()
		}
	}
	if !re.Signaled {
		re.Msg = fmt.Sprintf("command exited with code: %d", *re.ExitCode)
	} else {
		re.Msg = fmt.Sprintf("command died with signal: %d", *re.ExitCode&127)
	}
	re.Stdout = bufStdout.String()
	re.Stderr = bufStderr.String()
	re.Output = bufMerged.String()

	re.Success = *re.ExitCode == 0
	return re
}

func (ap *app) report(re *result) error {
	return nil
}
<commit_msg>define report.checkName()<commit_after>package wrap

import (
	"bytes"
	"crypto/md5"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/Songmu/wrapcommander"
	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mkr/logger"
	"golang.org/x/sync/errgroup"
	cli "gopkg.in/urfave/cli.v1"
)

// CommandPlugin is definition of mkr wrap
var Command = cli.Command{
	Name:      "wrap",
	Usage:     "wrap command status",
	ArgsUsage: "[--verbose | -v] [--name | -n <name>] [--memo | -m <memo>] -- /path/to/batch",
	Description: `
    wrap command line
`,
	Action: doWrap,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "name, n", Value: "", Usage: "monitor <name>"},
		cli.BoolFlag{Name: "verbose, v", Usage: "verbose output mode"},
		cli.StringFlag{Name: "memo, m", Value: "", Usage: "monitor <memo>"},
		cli.StringFlag{Name: "H, host", Value: "", Usage: "<hostId>"},
		cli.BoolFlag{Name: "warning, w", Usage: "alert as warning"},
	},
}

func doWrap(c *cli.Context) error {
	confFile := c.GlobalString("conf")
	conf, err := config.LoadConfig(confFile)
	if err != nil {
		return err
	}
	apibase := c.GlobalString("apibase")
	apikey := conf.Apikey
	if apikey == "" {
		apikey = os.Getenv("MACKEREL_APIKEY")
	}
	if apikey == "" {
		logger.Log("error", "[mkr wrap] failed to detect Mackerel APIKey. Try to specify in mackerel-agent.conf or export MACKEREL_APIKEY='<Your apikey>'")
	}
	hostID, _ := conf.LoadHostID()
	if c.String("host") != "" {
		hostID = c.String("host")
	}
	if hostID == "" {
		logger.Log("error", "[mkr wrap] failed to load hostID. Try to specify -host option explicitly")
	}
	// Since command execution has the highest priority, even when apikey or
	// hostID is empty, we don't return errors and only output the log here.

	cmd := c.Args()
	if len(cmd) > 0 && cmd[0] == "--" {
		cmd = cmd[1:]
	}
	if len(cmd) < 1 {
		return fmt.Errorf("no commands specified")
	}

	return (&app{
		apibase: apibase,
		name:    c.String("name"),
		verbose: c.Bool("verbose"),
		memo:    c.String("memo"),
		warning: c.Bool("warning"),
		hostID:  hostID,
		apikey:  apikey,
		cmd:     cmd,
	}).run()
}

type app struct {
	apibase string
	name    string
	verbose bool
	memo    string
	warning bool
	hostID  string
	apikey  string
	cmd     []string
}

type result struct {
	Cmd        []string
	Name, Memo string

	Output, Stdout, Stderr string
	Pid                    int
	ExitCode               *int
	Signaled               bool
	StartAt, EndAt         time.Time

	Msg     string
	Success bool
}

var reg = regexp.MustCompile(`[^-a-zA-Z0-9_]`)

func normalizeName(devName string) string {
	return reg.ReplaceAllString(strings.TrimSpace(devName), "_")
}

func (re *result) checkName() string {
	if re.Name != "" {
		return re.Name
	}
	sum := md5.Sum([]byte(strings.Join(re.Cmd, " ")))
	return fmt.Sprintf("mkrwrap-%s-%x",
		normalizeName(filepath.Base(re.Cmd[0])),
		sum[0:3])
}

func (ap *app) run() error {
	re := ap.runCmd()
	return ap.report(re)
}

func (ap *app) runCmd() *result {
	cmd := exec.Command(ap.cmd[0], ap.cmd[1:]...)
	re := &result{
		Cmd:  ap.cmd,
		Name: ap.name,
		Memo: ap.memo,
	}

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		re.Msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stdoutPipe.Close()

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		re.Msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	defer stderrPipe.Close()

	var (
		bufStdout = &bytes.Buffer{}
		bufStderr = &bytes.Buffer{}
		bufMerged = &bytes.Buffer{}
	)
	stdoutPipe2 := io.TeeReader(stdoutPipe, io.MultiWriter(bufStdout, bufMerged))
	stderrPipe2 := io.TeeReader(stderrPipe, io.MultiWriter(bufStderr, bufMerged))

	re.StartAt = time.Now()
	err = cmd.Start()
	if err != nil {
		re.Msg = fmt.Sprintf("command invocation failed with follwing error: %s", err)
		return re
	}
	re.Pid = cmd.Process.Pid
	eg := &errgroup.Group{}

	eg.Go(func() error {
		defer stdoutPipe.Close()
		_, err := io.Copy(os.Stdout, stdoutPipe2)
		return err
	})
	eg.Go(func() error {
		defer stderrPipe.Close()
		_, err := io.Copy(os.Stderr, stderrPipe2)
		return err
	})
	eg.Wait()

	cmdErr := cmd.Wait()
	re.EndAt = time.Now()
	ex := wrapcommander.ResolveExitCode(cmdErr)
	re.ExitCode = &ex
	if *re.ExitCode > 128 {
		w, ok := wrapcommander.ErrorToWaitStatus(cmdErr)
		if ok {
			re.Signaled = w.Signaled()
		}
	}
	if !re.Signaled {
		re.Msg = fmt.Sprintf("command exited with code: %d", *re.ExitCode)
	} else {
		re.Msg = fmt.Sprintf("command died with signal: %d", *re.ExitCode&127)
	}
	re.Stdout = bufStdout.String()
	re.Stderr = bufStderr.String()
	re.Output = bufMerged.String()

	re.Success = *re.ExitCode == 0
	return re
}

func (ap *app) report(re *result) error {
	fmt.Println(re.checkName())
	return nil
}
<|endoftext|>


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

package model

import (
	"fmt"
	"strconv"
	"strings"
)

// This is a list of all the current viersions including any patches.
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
	"1.4.0",
	"1.3.0",
	"1.2.1",
	"1.2.0",
	"1.1.0",
	"1.0.0",
	"0.7.1",
	"0.7.0",
	"0.6.0",
	"0.5.0",
}

var CurrentVersion string = versions[0]
var BuildNumber = "_BUILD_NUMBER_"
var BuildDate = "_BUILD_DATE_"
var BuildHash = "_BUILD_HASH_"
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_"
var versionsWithoutHotFixes []string

func init() {
	versionsWithoutHotFixes = make([]string, 0, len(versions))
	seen := make(map[string]string)

	for _, version := range versions {
		maj, min, _ := SplitVersion(version)
		verStr := fmt.Sprintf("%v.%v.0", maj, min)

		if seen[verStr] == "" {
			versionsWithoutHotFixes = append(versionsWithoutHotFixes, verStr)
			seen[verStr] = verStr
		}
	}
}

func SplitVersion(version string) (int64, int64, int64) {
	parts := strings.Split(version, ".")

	major := int64(0)
	minor := int64(0)
	patch := int64(0)

	if len(parts) > 0 {
		major, _ = strconv.ParseInt(parts[0], 10, 64)
	}

	if len(parts) > 1 {
		minor, _ = strconv.ParseInt(parts[1], 10, 64)
	}

	if len(parts) > 2 {
		patch, _ = strconv.ParseInt(parts[2], 10, 64)
	}

	return major, minor, patch
}

func GetPreviousVersion(version string) string {
	verMajor, verMinor, _ := SplitVersion(version)
	verStr := fmt.Sprintf("%v.%v.0", verMajor, verMinor)

	for index, v := range versionsWithoutHotFixes {
		if v == verStr && len(versionsWithoutHotFixes) > index+1 {
			return versionsWithoutHotFixes[index+1]
		}
	}

	return ""
}

func IsOfficalBuild() bool {
	return BuildNumber != "_BUILD_NUMBER_"
}

func IsCurrentVersion(versionToCheck string) bool {
	currentMajor, currentMinor, _ := SplitVersion(CurrentVersion)
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)

	if toCheckMajor == currentMajor && toCheckMinor == currentMinor {
		return true
	} else {
		return false
	}
}

func IsPreviousVersionsSupported(versionToCheck string) bool {
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
	versionToCheckStr := fmt.Sprintf("%v.%v.0", toCheckMajor, toCheckMinor)

	// Current Supported
	if versionsWithoutHotFixes[0] == versionToCheckStr {
		return true
	}

	// Current - 1 Supported
	if versionsWithoutHotFixes[1] == versionToCheckStr {
		return true
	}

	// Current - 2 Supported
	if versionsWithoutHotFixes[2] == versionToCheckStr {
		return true
	}

	return false
}
<commit_msg>Updating version.go for 2.0<commit_after>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"fmt"
	"strconv"
	"strings"
)

// This is a list of all the current viersions including any patches.
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
	"2.0.0",
	"1.4.0",
	"1.3.0",
	"1.2.1",
	"1.2.0",
	"1.1.0",
	"1.0.0",
	"0.7.1",
	"0.7.0",
	"0.6.0",
	"0.5.0",
}

var CurrentVersion string = versions[0]
var BuildNumber = "_BUILD_NUMBER_"
var BuildDate = "_BUILD_DATE_"
var BuildHash = "_BUILD_HASH_"
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_"
var versionsWithoutHotFixes []string

func init() {
	versionsWithoutHotFixes = make([]string, 0, len(versions))
	seen := make(map[string]string)

	for _, version := range versions {
		maj, min, _ := SplitVersion(version)
		verStr := fmt.Sprintf("%v.%v.0", maj, min)

		if seen[verStr] == "" {
			versionsWithoutHotFixes = append(versionsWithoutHotFixes, verStr)
			seen[verStr] = verStr
		}
	}
}

func SplitVersion(version string) (int64, int64, int64) {
	parts := strings.Split(version, ".")

	major := int64(0)
	minor := int64(0)
	patch := int64(0)

	if len(parts) > 0 {
		major, _ = strconv.ParseInt(parts[0], 10, 64)
	}

	if len(parts) > 1 {
		minor, _ = strconv.ParseInt(parts[1], 10, 64)
	}

	if len(parts) > 2 {
		patch, _ = strconv.ParseInt(parts[2], 10, 64)
	}

	return major, minor, patch
}

func GetPreviousVersion(version string) string {
	verMajor, verMinor, _ := SplitVersion(version)
	verStr := fmt.Sprintf("%v.%v.0", verMajor, verMinor)

	for index, v := range versionsWithoutHotFixes {
		if v == verStr && len(versionsWithoutHotFixes) > index+1 {
			return versionsWithoutHotFixes[index+1]
		}
	}

	return ""
}

func IsOfficalBuild() bool {
	return BuildNumber != "_BUILD_NUMBER_"
}

func IsCurrentVersion(versionToCheck string) bool {
	currentMajor, currentMinor, _ := SplitVersion(CurrentVersion)
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)

	if toCheckMajor == currentMajor && toCheckMinor == currentMinor {
		return true
	} else {
		return false
	}
}

func IsPreviousVersionsSupported(versionToCheck string) bool {
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
	versionToCheckStr := fmt.Sprintf("%v.%v.0", toCheckMajor, toCheckMinor)

	// Current Supported
	if versionsWithoutHotFixes[0] == versionToCheckStr {
		return true
	}

	// Current - 1 Supported
	if versionsWithoutHotFixes[1] == versionToCheckStr {
		return true
	}

	// Current - 2 Supported
	if versionsWithoutHotFixes[2] == versionToCheckStr {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>// weed_test.go
package weedo

import (
	"os"
	"testing"
)

var (
	client   = NewClient("localhost:9334", "localhost:8088")
	filename = "hello.txt"
)

func TestAssign(t *testing.T) {
	fid, err := client.Master().Assign()
	if err != nil {
		t.Fatal(err)
	}
	t.Log("assign", fid)

	fid, err = client.Master().AssignN(3)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("assign 3", fid)
}

func TestAssginUpload(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.AssignUpload(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("assign upload", filename, fid, size)
}

func TestMasterSubmit(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("master submit", filename, fid, size)
}

func TestVolumeSubmit(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}

	vol := NewVolume("localhost:8082", "localhost:8082")
	fid, size, err := vol.Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("volume submit", filename, fid, size)
}

func TestGetUrl(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, _, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}
	publicUrl, url, err := client.GetUrl(fid)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("publicUrl:", publicUrl, "url:", url)
}

func TestDelete(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("submit", fid, size)
	if err := client.Delete(fid, 1); err != nil {
		t.Fatal(err)
	}
	t.Log(fid, "deleted")
}

func TestDeleteN(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("submit", fid, size)
	if err := client.Delete(fid, 3); err != nil {
		t.Fatal(err)
	}
	t.Log(fid, "deleted")
}

func TestFilerUpload(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	if err := client.Filer("localhost:8088").Upload("text/world.txt", "text/plain", file); err != nil {
		t.Fatal(err)
	}
}

func TestFilerDelete(t *testing.T) {
	if err := client.Filer("localhost:8088").Delete("text/"); err != nil {
		t.Fatal(err)
	}
}

func TestFilerDir(t *testing.T) {
	dir, err := client.Filer("localhost:8088").Dir("/")
	if err != nil {
		t.Fatal(err)
	}

	t.Log(dir)
}
<commit_msg>update weed_test to use default weed server ports<commit_after>// weed_test.go
package weedo

import (
	"os"
	"testing"
)

var (
	client   = NewClient("localhost:9333", "localhost:8888")
	filename = "hello.txt"
)

func TestAssign(t *testing.T) {
	fid, err := client.Master().Assign()
	if err != nil {
		t.Fatal(err)
	}
	t.Log("assign", fid)

	fid, err = client.Master().AssignN(3)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("assign 3", fid)
}

func TestAssginUpload(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.AssignUpload(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("assign upload", filename, fid, size)
}

func TestMasterSubmit(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("master submit", filename, fid, size)
}

func TestVolumeSubmit(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}

	vol := NewVolume("localhost:8080", "localhost:8080")
	fid, size, err := vol.Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("volume submit", filename, fid, size)
}

func TestGetUrl(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, _, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}
	publicUrl, url, err := client.GetUrl(fid)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("publicUrl:", publicUrl, "url:", url)
}

func TestDelete(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("submit", fid, size)
	if err := client.Delete(fid, 1); err != nil {
		t.Fatal(err)
	}
	t.Log(fid, "deleted")
}

func TestDeleteN(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	fid, size, err := client.Master().Submit(filename, "text/plain", file)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("submit", fid, size)
	if err := client.Delete(fid, 3); err != nil {
		t.Fatal(err)
	}
	t.Log(fid, "deleted")
}

func TestFilerUpload(t *testing.T) {
	file, err := os.Open(filename)
	if err != nil {
		t.Fatal(err)
	}
	if err := client.Filer("localhost:8888").Upload("text/world.txt", "text/plain", file); err != nil {
		t.Fatal(err)
	}
}

func TestFilerDelete(t *testing.T) {
	if err := client.Filer("localhost:8888").Delete("text/"); err != nil {
		t.Fatal(err)
	}
}

func TestFilerDir(t *testing.T) {
	dir, err := client.Filer("localhost:8888").Dir("/")
	if err != nil {
		t.Fatal(err)
	}

	t.Log(dir)
}
<|endoftext|>


<commit_before>/*
    This is an implementation of a kronecker edge list generator v. closely
    based on the graph500 octave example (http://graph500.org)
 */
package main

import (
    "fmt"
    "krongen/kronecker"
    "math"
    "math/rand"
    "time"
    "runtime"
    "flag"
)

func parallel_generator(scale, edgefactor int) {
    // The number of vertices is 2^scale
    N := int(math.Exp2(float64(scale)))

    // N.o. edges
    M := edgefactor*N

    // initiator probabilities
    A, B, C := 0.57, 0.19, 0.19

    results := make(chan []int)
    dudes := 0
    for i := 0; i < 100; i++ {
        dudes++
        go func () {
            for {
                edge := kronecker.YieldEdge(scale, A, B, C)
                results <- edge
            }
        } ()
    }

    for i:=0;i<M;i++ {
        tst := <-results

        // permute edge labels
        //perm := rand.Perm(N)
        //tst[0] = perm[tst[0] - 1]
        //tst[1] = perm[tst[1] - 1]

        fmt.Printf("%d\t%d\n", tst[0], tst[1])
    }

}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    rand.Seed(time.Now().UTC().UnixNano())
    var scale = flag.Int("scale", 10, "n.o. vertexes = 2^scale")
    var edgefactor = flag.Int("edgef", 8, "n.o. edges = [n.o. vertexes]*edgef")

    flag.Parse()

    //fmt.Println(*scale, *edgefactor)
    parallel_generator(*scale, *edgefactor)
}
/*
    the below is old rubbish code that I might need later
 */
    //fmt.Println(A, B, C, M)
    //ij := make([]int, 2*M)
    //for i := range(ij) { ij[i] = 1 }

    //ab := A + B
    //c_norm := C/(1 - ab)
    //a_norm := A/ab

    //fmt.Println(ab, c_norm, a_norm)
    //for ib := 1; ib <= scale; ib++ {
    //    bits := make([]int, 2*M)
    //    for i := 0; i < M; i++ {
    //        bit := 0
    //        if rand.Float64() > ab {
    //            bit = 1
    //        }

    //        notbit := (bit + 1) % 2

    //        other_bit := 0
    //        if rand.Float64() > (c_norm*float64(bit) + a_norm*float64(notbit)) {
    //            other_bit = 1
    //        }

    //        bits[i] = bit
    //        bits[M + i] = other_bit

    //    }

    //    for i := range(bits) {
    //        coeff := int(math.Exp2(float64(ib - 1)))
    //        ij[i] = ij[i] + coeff*bits[i]
    //    }
    //}
<commit_msg>Added edge label permutation<commit_after>/*
    This is an implementation of a kronecker edge list generator v. closely
    based on the graph500 octave example (http://graph500.org)
 */
package main

import (
    "fmt"
    "krongen/kronecker"
    "math"
    "math/rand"
    "time"
    "runtime"
    "flag"
)

func parallel_generator(scale, edgefactor int) {
    // The number of vertices is 2^scale
    N := int(math.Exp2(float64(scale)))

    // N.o. edges
    M := edgefactor*N

    // initiator probabilities
    A, B, C := 0.57, 0.19, 0.19

    results := make(chan []int)
    dudes := 0
    for i := 0; i < 100; i++ {
        dudes++
        go func () {
            for {
                edge := kronecker.YieldEdge(scale, A, B, C)
                results <- edge
            }
        } ()
    }

    // permutation of edge labels, the kronecker generator has a greater
    // probability of creating edges in the lower ints
    perm := rand.Perm(N)
    for i:=0;i<M;i++ {
        tst := <-results

        // edges from the generator are 1-indexed,
        // those of the permutation are 0-indexed
        tst[0] = perm[tst[0] - 1] + 1
        tst[1] = perm[tst[1] - 1] + 1

        fmt.Printf("%d\t%d\n", tst[0], tst[1])
    }

}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    rand.Seed(time.Now().UTC().UnixNano())
    var scale = flag.Int("scale", 10, "n.o. vertexes = 2^scale")
    var edgefactor = flag.Int("edgef", 8, "n.o. edges = [n.o. vertexes]*edgef")

    flag.Parse()

    //fmt.Println(*scale, *edgefactor)
    parallel_generator(*scale, *edgefactor)
}
/*
    the below is old rubbish code that I might need later
 */
    //fmt.Println(A, B, C, M)
    //ij := make([]int, 2*M)
    //for i := range(ij) { ij[i] = 1 }

    //ab := A + B
    //c_norm := C/(1 - ab)
    //a_norm := A/ab

    //fmt.Println(ab, c_norm, a_norm)
    //for ib := 1; ib <= scale; ib++ {
    //    bits := make([]int, 2*M)
    //    for i := 0; i < M; i++ {
    //        bit := 0
    //        if rand.Float64() > ab {
    //            bit = 1
    //        }

    //        notbit := (bit + 1) % 2

    //        other_bit := 0
    //        if rand.Float64() > (c_norm*float64(bit) + a_norm*float64(notbit)) {
    //            other_bit = 1
    //        }

    //        bits[i] = bit
    //        bits[M + i] = other_bit

    //    }

    //    for i := range(bits) {
    //        coeff := int(math.Exp2(float64(ib - 1)))
    //        ij[i] = ij[i] + coeff*bits[i]
    //    }
    //}
<|endoftext|>