<commit_before>package router

import (
	"fmt"
	"sort"
	"sync"
)

type Peer struct {
	sync.RWMutex
	Name          PeerName
	NameByte      []byte
	NickName      string
	UID           uint64
	version       uint64
	localRefCount uint64
	connections   map[PeerName]Connection
}

type ConnectionSet map[Connection]struct{}

func NewPeer(name PeerName, nickName string, uid uint64, version uint64) *Peer {
	if uid == 0 {
		uid = randUint64()
	}
	return &Peer{
		Name:        name,
		NameByte:    name.Bin(),
		NickName:    nickName,
		UID:         uid,
		version:     version,
		connections: make(map[PeerName]Connection)}
}

func (peer *Peer) String() string {
	peer.RLock()
	defer peer.RUnlock()
	return fmt.Sprint("Peer ", peer.FullName(), " (v", peer.version, ") (UID ", peer.UID, ")")
}

func (peer *Peer) FullName() string {
	return fmt.Sprint(peer.Name, "(", peer.NickName, ")")
}

func (peer *Peer) Version() uint64 {
	peer.RLock()
	defer peer.RUnlock()
	return peer.version
}

func (peer *Peer) IncrementLocalRefCount() {
	peer.Lock()
	defer peer.Unlock()
	peer.localRefCount++
}

func (peer *Peer) DecrementLocalRefCount() {
	peer.Lock()
	defer peer.Unlock()
	peer.localRefCount--
}

func (peer *Peer) IsLocallyReferenced() bool {
	peer.RLock()
	defer peer.RUnlock()
	return peer.localRefCount != 0
}

func (peer *Peer) ConnectionCount() int {
	peer.RLock()
	defer peer.RUnlock()
	return len(peer.connections)
}

func (peer *Peer) ConnectionTo(name PeerName) (Connection, bool) {
	peer.RLock()
	defer peer.RUnlock()
	conn, found := peer.connections[name]
	return conn, found // yes, you really can't inline that. FFS.
}

func (peer *Peer) Connections() ConnectionSet {
	connections := make(ConnectionSet)
	peer.RLock()
	defer peer.RUnlock()
	for _, conn := range peer.connections {
		connections[conn] = void
	}
	return connections
}

func (peer *Peer) SetVersionAndConnections(version uint64, connections map[PeerName]Connection) {
	peer.Lock()
	defer peer.Unlock()
	peer.version = version
	peer.connections = connections
}

func (peer *Peer) addConnection(conn Connection) {
	peer.Lock()
	defer peer.Unlock()
	peer.connections[conn.Remote().Name] = conn
	peer.version++
}

func (peer *Peer) deleteConnection(conn Connection) {
	peer.Lock()
	defer peer.Unlock()
	delete(peer.connections, conn.Remote().Name)
	peer.version++
}

func (peer *Peer) connectionEstablished(conn Connection) {
	peer.Lock()
	defer peer.Unlock()
	peer.version++
}

// Calculate the routing table from this peer to all peers reachable
// from it, returning a "next hop" map of PeerNameX -> PeerNameY,
// which says "in order to send a message to X, the peer should send
// the message to its neighbour Y".
//
// Because currently we do not have weightings on the connections
// between peers, there is no need to use a minimum spanning tree
// algorithm. Instead we employ the simpler and cheaper breadth-first
// widening. The computation is deterministic, which ensures that when
// it is performed on the same data by different peers, they get the
// same result. This is important since otherwise we risk message loss
// or routing cycles.
//
// When the 'establishedAndSymmetric' flag is set, only connections
// that are marked as 'established' and are symmetric (i.e. where both
// sides indicate they have a connection to the other) are considered.
//
// When a non-nil stopAt peer is supplied, the widening stops when it
// reaches that peer. The boolean return indicates whether that has
// happened.
//
// We acquire read locks on peers as we encounter them during the
// traversal. This prevents the connectivity graph from changing
// underneath us in ways that would invalidate the result. Thus the
// answer returned may be out of date, but never inconsistent.
func (peer *Peer) Routes(stopAt *Peer, establishedAndSymmetric bool) (bool, map[PeerName]PeerName) {
	peer.RLock()
	defer peer.RUnlock()
	routes := make(map[PeerName]PeerName)
	routes[peer.Name] = UnknownPeerName
	nextWorklist := []*Peer{peer}
	for len(nextWorklist) > 0 {
		worklist := nextWorklist
		sort.Sort(ListOfPeers(worklist))
		nextWorklist = []*Peer{}
		for _, curPeer := range worklist {
			if curPeer == stopAt {
				return true, routes
			}
			curName := curPeer.Name
			for remoteName, conn := range curPeer.connections {
				if establishedAndSymmetric && !conn.Established() {
					continue
				}
				if _, found := routes[remoteName]; found {
					continue
				}
				remote := conn.Remote()
				remote.RLock()
				// DANGER holding rlock on remote, possibly taking
				// rlock on remoteConn
				if remoteConn, found := remote.connections[curName]; !establishedAndSymmetric || (found && remoteConn.Established()) {
					defer remote.RUnlock()
					nextWorklist = append(nextWorklist, remote)
					// We now know how to get to remoteName: the same
					// way we get to curPeer. Except, if curPeer is
					// the starting peer in which case we know we can
					// reach remoteName directly.
					if curPeer == peer {
						routes[remoteName] = remoteName
					} else {
						routes[remoteName] = routes[curName]
					}
				} else {
					remote.RUnlock()
				}
			}
		}
	}
	return false, routes
}
<commit_msg>drop "Peer " prefix in Peers section of status it's redundant and the output looks much better w/o it<commit_after>package router

import (
	"fmt"
	"sort"
	"sync"
)

type Peer struct {
	sync.RWMutex
	Name          PeerName
	NameByte      []byte
	NickName      string
	UID           uint64
	version       uint64
	localRefCount uint64
	connections   map[PeerName]Connection
}

type ConnectionSet map[Connection]struct{}

func NewPeer(name PeerName, nickName string, uid uint64, version uint64) *Peer {
	if uid == 0 {
		uid = randUint64()
	}
	return &Peer{
		Name:        name,
		NameByte:    name.Bin(),
		NickName:    nickName,
		UID:         uid,
		version:     version,
		connections: make(map[PeerName]Connection)}
}

func (peer *Peer) String() string {
	peer.RLock()
	defer peer.RUnlock()
	return fmt.Sprint(peer.FullName(), " (v", peer.version, ") (UID ", peer.UID, ")")
}

func (peer *Peer) FullName() string {
	return fmt.Sprint(peer.Name, "(", peer.NickName, ")")
}

func (peer *Peer) Version() uint64 {
	peer.RLock()
	defer peer.RUnlock()
	return peer.version
}

func (peer *Peer) IncrementLocalRefCount() {
	peer.Lock()
	defer peer.Unlock()
	peer.localRefCount++
}

func (peer *Peer) DecrementLocalRefCount() {
	peer.Lock()
	defer peer.Unlock()
	peer.localRefCount--
}

func (peer *Peer) IsLocallyReferenced() bool {
	peer.RLock()
	defer peer.RUnlock()
	return peer.localRefCount != 0
}

func (peer *Peer) ConnectionCount() int {
	peer.RLock()
	defer peer.RUnlock()
	return len(peer.connections)
}

func (peer *Peer) ConnectionTo(name PeerName) (Connection, bool) {
	peer.RLock()
	defer peer.RUnlock()
	conn, found := peer.connections[name]
	return conn, found // yes, you really can't inline that. FFS.
}

func (peer *Peer) Connections() ConnectionSet {
	connections := make(ConnectionSet)
	peer.RLock()
	defer peer.RUnlock()
	for _, conn := range peer.connections {
		connections[conn] = void
	}
	return connections
}

func (peer *Peer) SetVersionAndConnections(version uint64, connections map[PeerName]Connection) {
	peer.Lock()
	defer peer.Unlock()
	peer.version = version
	peer.connections = connections
}

func (peer *Peer) addConnection(conn Connection) {
	peer.Lock()
	defer peer.Unlock()
	peer.connections[conn.Remote().Name] = conn
	peer.version++
}

func (peer *Peer) deleteConnection(conn Connection) {
	peer.Lock()
	defer peer.Unlock()
	delete(peer.connections, conn.Remote().Name)
	peer.version++
}

func (peer *Peer) connectionEstablished(conn Connection) {
	peer.Lock()
	defer peer.Unlock()
	peer.version++
}

// Calculate the routing table from this peer to all peers reachable
// from it, returning a "next hop" map of PeerNameX -> PeerNameY,
// which says "in order to send a message to X, the peer should send
// the message to its neighbour Y".
//
// Because currently we do not have weightings on the connections
// between peers, there is no need to use a minimum spanning tree
// algorithm. Instead we employ the simpler and cheaper breadth-first
// widening. The computation is deterministic, which ensures that when
// it is performed on the same data by different peers, they get the
// same result. This is important since otherwise we risk message loss
// or routing cycles.
//
// When the 'establishedAndSymmetric' flag is set, only connections
// that are marked as 'established' and are symmetric (i.e. where both
// sides indicate they have a connection to the other) are considered.
//
// When a non-nil stopAt peer is supplied, the widening stops when it
// reaches that peer. The boolean return indicates whether that has
// happened.
//
// We acquire read locks on peers as we encounter them during the
// traversal. This prevents the connectivity graph from changing
// underneath us in ways that would invalidate the result. Thus the
// answer returned may be out of date, but never inconsistent.
func (peer *Peer) Routes(stopAt *Peer, establishedAndSymmetric bool) (bool, map[PeerName]PeerName) {
	peer.RLock()
	defer peer.RUnlock()
	routes := make(map[PeerName]PeerName)
	routes[peer.Name] = UnknownPeerName
	nextWorklist := []*Peer{peer}
	for len(nextWorklist) > 0 {
		worklist := nextWorklist
		sort.Sort(ListOfPeers(worklist))
		nextWorklist = []*Peer{}
		for _, curPeer := range worklist {
			if curPeer == stopAt {
				return true, routes
			}
			curName := curPeer.Name
			for remoteName, conn := range curPeer.connections {
				if establishedAndSymmetric && !conn.Established() {
					continue
				}
				if _, found := routes[remoteName]; found {
					continue
				}
				remote := conn.Remote()
				remote.RLock()
				// DANGER holding rlock on remote, possibly taking
				// rlock on remoteConn
				if remoteConn, found := remote.connections[curName]; !establishedAndSymmetric || (found && remoteConn.Established()) {
					defer remote.RUnlock()
					nextWorklist = append(nextWorklist, remote)
					// We now know how to get to remoteName: the same
					// way we get to curPeer. Except, if curPeer is
					// the starting peer in which case we know we can
					// reach remoteName directly.
					if curPeer == peer {
						routes[remoteName] = remoteName
					} else {
						routes[remoteName] = routes[curName]
					}
				} else {
					remote.RUnlock()
				}
			}
		}
	}
	return false, routes
}
<|endoftext|>


<commit_before>package buffalo

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"testing"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/packr"
	"github.com/gobuffalo/plush"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func testApp() *App {
	a := New(Options{})
	a.Redirect(301, "/foo", "/bar")
	a.GET("/bar", func(c Context) error {
		return c.Render(200, render.String("bar"))
	})

	rt := a.Group("/router/tests")

	h := func(c Context) error {
		return c.Render(200, render.String(c.Request().Method+"|"+c.Value("current_path").(string)))
	}

	rt.GET("/", h)
	rt.POST("/", h)
	rt.PUT("/", h)
	rt.DELETE("/", h)
	rt.OPTIONS("/", h)
	rt.PATCH("/", h)
	return a
}

func Test_Router(t *testing.T) {
	r := require.New(t)

	table := []string{
		"GET",
		"POST",
		"PUT",
		"DELETE",
		"OPTIONS",
		"PATCH",
	}

	ts := httptest.NewServer(testApp())
	defer ts.Close()

	for _, v := range table {
		req, err := http.NewRequest(v, fmt.Sprintf("%s/router/tests", ts.URL), nil)
		r.NoError(err)
		res, err := http.DefaultClient.Do(req)
		r.NoError(err)
		b, _ := ioutil.ReadAll(res.Body)
		r.Equal(fmt.Sprintf("%s|/router/tests", v), string(b))
	}
}

func Test_Router_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/users").Get()
	r.Equal(201, res.Code)
}

func Test_Router_Group_on_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})
	f := g.Group("/foo")
	f.GET("/bar", func(c Context) error {
		return c.Render(420, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/foo/bar").Get()
	r.Equal(420, res.Code)
}

func Test_Router_Group_Middleware(t *testing.T) {
	r := require.New(t)

	a := testApp()
	a.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)

	g := a.Group("/api/v1")
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 1)

	g.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 2)
}

func Test_Router_Redirect(t *testing.T) {
	r := require.New(t)
	w := willie.New(testApp())
	res := w.Request("/foo").Get()
	r.Equal(301, res.Code)
	r.Equal("/bar", res.Location())
}

func Test_Router_ServeFiles(t *testing.T) {
	r := require.New(t)

	tmpFile, err := ioutil.TempFile("", "assets")
	r.NoError(err)

	af := []byte("hi")
	_, err = tmpFile.Write(af)
	r.NoError(err)

	a := New(Options{})
	a.ServeFiles("/assets", http.Dir(filepath.Dir(tmpFile.Name())))

	w := willie.New(a)
	res := w.Request("/assets/%s", filepath.Base(tmpFile.Name())).Get()

	r.Equal(200, res.Code)
	r.Equal(af, res.Body.Bytes())
}

func Test_App_NamedRoutes(t *testing.T) {
	r := require.New(t)
	a := Automatic(Options{})

	rr := render.New(render.Options{
		HTMLLayout:     "application.html",
		TemplateEngine: plush.BuffaloRenderer,
		TemplatesBox:   packr.NewBox("../templates"),
		Helpers:        map[string]interface{}{},
	})

	sampleHandler := func(c Context) error {
		return c.Render(200, rr.String(`
			1. <%= rootPath() %>
			2. <%= usersPath() %>
			3. <%= userPath({user_id: 1}) %>
			4. <%= myPeepsPath() %>
		`))
	}

	a.GET("/", sampleHandler)
	a.GET("/users", sampleHandler)
	a.GET("/users/{user_id}", sampleHandler)
	a.GET("/peeps", sampleHandler).Name("myPeeps")

	w := willie.New(a)
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "1. /")
	r.Contains(res.Body.String(), "2. /users")
	r.Contains(res.Body.String(), "3. /users/1")
	r.Contains(res.Body.String(), "4. /peeps")
}

func Test_Resource(t *testing.T) {
	r := require.New(t)

	type trs struct {
		Method string
		Path   string
		Result string
	}

	tests := []trs{
		{
			Method: "GET",
			Path:   "",
			Result: "list",
		},
		{
			Method: "GET",
			Path:   "/new",
			Result: "new",
		},
		{
			Method: "GET",
			Path:   "/1",
			Result: "show 1",
		},
		{
			Method: "GET",
			Path:   "/1/edit",
			Result: "edit 1",
		},
		{
			Method: "POST",
			Path:   "",
			Result: "create",
		},
		{
			Method: "PUT",
			Path:   "/1",
			Result: "update 1",
		},
		{
			Method: "DELETE",
			Path:   "/1",
			Result: "destroy 1",
		},
	}

	a := Automatic(Options{})
	a.Resource("/users", &userResource{})
	a.Resource("/api/v1/users", &userResource{})

	ts := httptest.NewServer(a)
	defer ts.Close()

	c := http.Client{}
	for _, path := range []string{"/users", "/api/v1/users"} {
		for _, test := range tests {
			u := ts.URL + path + test.Path
			req, err := http.NewRequest(test.Method, u, nil)
			r.NoError(err)
			res, err := c.Do(req)
			r.NoError(err)
			b, err := ioutil.ReadAll(res.Body)
			r.NoError(err)
			r.Equal(test.Result, string(b))
		}
	}

}

type userResource struct{}

func (u *userResource) List(c Context) error {
	return c.Render(200, render.String("list"))
}

func (u *userResource) Show(c Context) error {
	return c.Render(200, render.String(`show <%=params["user_id"] %>`))
}

func (u *userResource) New(c Context) error {
	return c.Render(200, render.String("new"))
}

func (u *userResource) Create(c Context) error {
	return c.Render(200, render.String("create"))
}

func (u *userResource) Edit(c Context) error {
	return c.Render(200, render.String(`edit <%=params["user_id"] %>`))
}

func (u *userResource) Update(c Context) error {
	return c.Render(200, render.String(`update <%=params["user_id"] %>`))
}

func (u *userResource) Destroy(c Context) error {
	return c.Render(200, render.String(`destroy <%=params["user_id"] %>`))
}

func Test_buildRouteName(t *testing.T) {
	r := require.New(t)
	cases := map[string]string{
		"/":                                          "root",
		"/users":                                     "users",
		"/users/new":                                 "newUsers",
		"/users/{user_id}":                           "user",
		"/users/{user_id}/children":                  "userChildren",
		"/users/{user_id}/children/{child_id}":       "userChild",
		"/users/{user_id}/children/new":              "newUserChildren",
		"/users/{user_id}/children/{child_id}/build": "userChildBuild",
	}

	for input, result := range cases {
		fResult := buildRouteName(input)
		r.Equal(result, fResult, input)
	}
}
<commit_msg>[case] covering the case where not enough info is passed<commit_after>package buffalo

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"testing"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/packr"
	"github.com/gobuffalo/plush"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func testApp() *App {
	a := New(Options{})
	a.Redirect(301, "/foo", "/bar")
	a.GET("/bar", func(c Context) error {
		return c.Render(200, render.String("bar"))
	})

	rt := a.Group("/router/tests")

	h := func(c Context) error {
		return c.Render(200, render.String(c.Request().Method+"|"+c.Value("current_path").(string)))
	}

	rt.GET("/", h)
	rt.POST("/", h)
	rt.PUT("/", h)
	rt.DELETE("/", h)
	rt.OPTIONS("/", h)
	rt.PATCH("/", h)
	return a
}

func Test_Router(t *testing.T) {
	r := require.New(t)

	table := []string{
		"GET",
		"POST",
		"PUT",
		"DELETE",
		"OPTIONS",
		"PATCH",
	}

	ts := httptest.NewServer(testApp())
	defer ts.Close()

	for _, v := range table {
		req, err := http.NewRequest(v, fmt.Sprintf("%s/router/tests", ts.URL), nil)
		r.NoError(err)
		res, err := http.DefaultClient.Do(req)
		r.NoError(err)
		b, _ := ioutil.ReadAll(res.Body)
		r.Equal(fmt.Sprintf("%s|/router/tests", v), string(b))
	}
}

func Test_Router_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/users").Get()
	r.Equal(201, res.Code)
}

func Test_Router_Group_on_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})
	f := g.Group("/foo")
	f.GET("/bar", func(c Context) error {
		return c.Render(420, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/foo/bar").Get()
	r.Equal(420, res.Code)
}

func Test_Router_Group_Middleware(t *testing.T) {
	r := require.New(t)

	a := testApp()
	a.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)

	g := a.Group("/api/v1")
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 1)

	g.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 2)
}

func Test_Router_Redirect(t *testing.T) {
	r := require.New(t)
	w := willie.New(testApp())
	res := w.Request("/foo").Get()
	r.Equal(301, res.Code)
	r.Equal("/bar", res.Location())
}

func Test_Router_ServeFiles(t *testing.T) {
	r := require.New(t)

	tmpFile, err := ioutil.TempFile("", "assets")
	r.NoError(err)

	af := []byte("hi")
	_, err = tmpFile.Write(af)
	r.NoError(err)

	a := New(Options{})
	a.ServeFiles("/assets", http.Dir(filepath.Dir(tmpFile.Name())))

	w := willie.New(a)
	res := w.Request("/assets/%s", filepath.Base(tmpFile.Name())).Get()

	r.Equal(200, res.Code)
	r.Equal(af, res.Body.Bytes())
}

func Test_App_NamedRoutes(t *testing.T) {
	r := require.New(t)
	a := Automatic(Options{})

	rr := render.New(render.Options{
		HTMLLayout:     "application.html",
		TemplateEngine: plush.BuffaloRenderer,
		TemplatesBox:   packr.NewBox("../templates"),
		Helpers:        map[string]interface{}{},
	})

	sampleHandler := func(c Context) error {
		c.Set("opts", map[string]interface{}{})
		return c.Render(200, rr.String(`
			1. <%= rootPath() %>
			2. <%= usersPath() %>
			3. <%= userPath({user_id: 1}) %>
			4. <%= myPeepsPath() %>
			5. <%= userPath(opts) %>
		`))
	}

	a.GET("/", sampleHandler)
	a.GET("/users", sampleHandler)
	a.GET("/users/{user_id}", sampleHandler)
	a.GET("/peeps", sampleHandler).Name("myPeeps")

	w := willie.New(a)
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "1. /")
	r.Contains(res.Body.String(), "2. /users")
	r.Contains(res.Body.String(), "3. /users/1")
	r.Contains(res.Body.String(), "4. /peeps")
	r.Contains(res.Body.String(), "5. /users/{user_id}")
}

func Test_Resource(t *testing.T) {
	r := require.New(t)

	type trs struct {
		Method string
		Path   string
		Result string
	}

	tests := []trs{
		{
			Method: "GET",
			Path:   "",
			Result: "list",
		},
		{
			Method: "GET",
			Path:   "/new",
			Result: "new",
		},
		{
			Method: "GET",
			Path:   "/1",
			Result: "show 1",
		},
		{
			Method: "GET",
			Path:   "/1/edit",
			Result: "edit 1",
		},
		{
			Method: "POST",
			Path:   "",
			Result: "create",
		},
		{
			Method: "PUT",
			Path:   "/1",
			Result: "update 1",
		},
		{
			Method: "DELETE",
			Path:   "/1",
			Result: "destroy 1",
		},
	}

	a := Automatic(Options{})
	a.Resource("/users", &userResource{})
	a.Resource("/api/v1/users", &userResource{})

	ts := httptest.NewServer(a)
	defer ts.Close()

	c := http.Client{}
	for _, path := range []string{"/users", "/api/v1/users"} {
		for _, test := range tests {
			u := ts.URL + path + test.Path
			req, err := http.NewRequest(test.Method, u, nil)
			r.NoError(err)
			res, err := c.Do(req)
			r.NoError(err)
			b, err := ioutil.ReadAll(res.Body)
			r.NoError(err)
			r.Equal(test.Result, string(b))
		}
	}

}

type userResource struct{}

func (u *userResource) List(c Context) error {
	return c.Render(200, render.String("list"))
}

func (u *userResource) Show(c Context) error {
	return c.Render(200, render.String(`show <%=params["user_id"] %>`))
}

func (u *userResource) New(c Context) error {
	return c.Render(200, render.String("new"))
}

func (u *userResource) Create(c Context) error {
	return c.Render(200, render.String("create"))
}

func (u *userResource) Edit(c Context) error {
	return c.Render(200, render.String(`edit <%=params["user_id"] %>`))
}

func (u *userResource) Update(c Context) error {
	return c.Render(200, render.String(`update <%=params["user_id"] %>`))
}

func (u *userResource) Destroy(c Context) error {
	return c.Render(200, render.String(`destroy <%=params["user_id"] %>`))
}

func Test_buildRouteName(t *testing.T) {
	r := require.New(t)
	cases := map[string]string{
		"/":                                          "root",
		"/users":                                     "users",
		"/users/new":                                 "newUsers",
		"/users/{user_id}":                           "user",
		"/users/{user_id}/children":                  "userChildren",
		"/users/{user_id}/children/{child_id}":       "userChild",
		"/users/{user_id}/children/new":              "newUserChildren",
		"/users/{user_id}/children/{child_id}/build": "userChildBuild",
	}

	for input, result := range cases {
		fResult := buildRouteName(input)
		r.Equal(result, fResult, input)
	}
}
<|endoftext|>


<commit_before>package expresscarduino

type Serial struct {
}

func Connect(Serial ser) {
}
<commit_msg>Putting together the initial skeleton<commit_after>package expresscarduino

import (
    "os"
    "syscall"
    // "time"
    // "unsafe"
)

const initialBaudRate uint32 = syscall.B9600

type Serial struct {
    deviceName string
}

type Connection struct {
    file *os.File
}

func (c *Connection) Connect() (error) {
    // Open the file
    // do an IOCTL call to set the parity and initial baud rate
    // Perform handshake with EC
    return nil
}

func New(ser Serial) (*Connection, error) {
    return nil, nil
}
<|endoftext|>


<commit_before>package log

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/pkg/errors"
)

var (
	pool = &sync.Pool{
		New: func() interface{} {
			return make([]byte, 0, maxLogSize)
		},
	}

	utsname string
)

func init() {
	hname, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	utsname = hname
}

// Logger is a collection of properties how to output logs.
// Properties are initially set by NewLogger.  They can be customized
// later by Logger methods.
type Logger struct {
	topic     atomic.Value
	threshold int32
	defaults  atomic.Value
	format    atomic.Value

	mu     sync.Mutex
	output io.Writer
}

// NewLogger constructs a new Logger struct.
// The struct is initialized as follows:
//    topic:        the program name normalized for tag spec.
//    threshold: LvInfo, i.e., debug logs are disabled.
//    format:    PlainFormat
//    output:    os.Stderr
//    defaults:  no default fields.
func NewLogger() *Logger {
	l := &Logger{
		output: os.Stderr,
	}
	l.SetTopic(normalizeTopic(path.Base(os.Args[0])))
	l.SetThreshold(LvInfo)
	l.SetDefaults(nil)
	l.SetFormatter(PlainFormat{})
	return l
}

func normalizeTopic(n string) string {
	// Topic must match [.a-z0-9-]+
	topic := strings.Map(func(r rune) rune {
		switch {
		case r == '.' || r == '-':
			return r
		case r >= '0' && r < '9':
			return r
		case r >= 'a' && r <= 'z':
			return r
		case r >= 'A' && r < 'Z':
			return r + ('a' - 'A')
		default:
			return '-'
		}
	}, n)
	if len(topic) > maxTopicLength {
		return topic[:maxTopicLength]
	}
	return topic
}

// Topic returns the topic for the logger.
func (l *Logger) Topic() string {
	return l.topic.Load().(string)
}

// SetTopic sets a new topic for the logger.
// topic must not be empty.  Too long topic may be shortened automatically.
func (l *Logger) SetTopic(topic string) {
	if len(topic) == 0 {
		panic("Empty tag")
	}

	l.mu.Lock()
	l.topic.Store(topic)
	l.mu.Unlock()
}

// Threshold returns the current threshold of the logger.
func (l *Logger) Threshold() int {
	return int(atomic.LoadInt32(&l.threshold))
}

// Enabled returns true if the log for the given level will be logged.
// This can be used to avoid futile computation for logs being ignored.
//
//    if log.Enabled(log.LvDebug) {
//        log.Debug("message", map[string]interface{}{
//            "debug info": "...",
//        })
//    }
func (l *Logger) Enabled(level int) bool {
	return level <= l.Threshold()
}

// SetThreshold sets the threshold for the logger.
// level must be a pre-defined constant such as LvInfo.
func (l *Logger) SetThreshold(level int) {
	l.mu.Lock()
	atomic.StoreInt32(&l.threshold, int32(level))
	l.mu.Unlock()
}

// SetThresholdByName sets the threshold for the logger by the level name.
func (l *Logger) SetThresholdByName(n string) error {
	var level int
	switch n {
	case "critical", "crit":
		level = LvCritical
	case "error":
		level = LvError
	case "warning", "warn":
		level = LvWarn
	case "information", "info":
		level = LvInfo
	case "debug":
		level = LvDebug
	default:
		return fmt.Errorf("No such level: %s", n)
	}
	l.SetThreshold(level)
	return nil
}

// SetDefaults sets default field values for the logger.
// Setting nil effectively clear the defaults.
func (l *Logger) SetDefaults(d map[string]interface{}) error {
	for key := range d {
		if !IsValidKey(key) {
			return ErrInvalidKey
		}
	}

	l.mu.Lock()
	l.defaults.Store(d)
	l.mu.Unlock()
	return nil
}

// Defaults returns default field values.
func (l *Logger) Defaults() map[string]interface{} {
	return l.defaults.Load().(map[string]interface{})
}

// SetFormatter sets log formatter.
func (l *Logger) SetFormatter(f Formatter) {
	l.mu.Lock()
	l.format.Store(&f)
	l.mu.Unlock()
}

// Formatter returns the current log formatter.
func (l *Logger) Formatter() Formatter {
	return *l.format.Load().(*Formatter)
}

// SetOutput sets io.Writer for log output.
// Setting nil disables log output.
func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	l.output = w
	l.mu.Unlock()
}

// Writer returns an io.Writer.
// Each line written in the writer will be logged to the logger
// with the given severity.
func (l *Logger) Writer(severity int) io.Writer {
	r, w := io.Pipe()

	go func() {
		scanner := bufio.NewScanner(r)
		for scanner.Scan() {
			if err := l.Log(severity, scanner.Text(), nil); err != nil {
				r.CloseWithError(err)
			}
		}
		if err := scanner.Err(); err != nil {
			r.CloseWithError(err)
		}
	}()

	return w
}

// Log outputs a log message with additional fields.
// fields can be nil.
func (l *Logger) Log(severity int, msg string, fields map[string]interface{}) error {
	if severity > l.Threshold() {
		return nil
	}

	t := time.Now()
	buf := pool.Get().([]byte)
	defer pool.Put(buf)

	if l.output != nil {
		b, err := l.Formatter().Format(buf, l, t, severity, msg, fields)
		if err != nil {
			return err
		}

		l.mu.Lock()
		defer l.mu.Unlock()
		if _, err := l.output.Write(b); err != nil {
			fmt.Fprintf(os.Stderr, "logger output causes an error: %v", err)
			return errors.Wrap(err, "Logger.Log")
		}
	}

	return nil
}

// Critical outputs a critical log.
// fields can be nil.
func (l *Logger) Critical(msg string, fields map[string]interface{}) error {
	return l.Log(LvCritical, msg, fields)
}

// Error outputs an error log.
// fields can be nil.
func (l *Logger) Error(msg string, fields map[string]interface{}) error {
	return l.Log(LvError, msg, fields)
}

// Warn outputs a warning log.
// fields can be nil.
func (l *Logger) Warn(msg string, fields map[string]interface{}) error {
	return l.Log(LvWarn, msg, fields)
}

// Info outputs an informational log.
// fields can be nil.
func (l *Logger) Info(msg string, fields map[string]interface{}) error {
	return l.Log(LvInfo, msg, fields)
}

// Debug outputs a debug log.
// fields can be nil.
func (l *Logger) Debug(msg string, fields map[string]interface{}) error {
	return l.Log(LvDebug, msg, fields)
}
<commit_msg>Update doc comment.<commit_after>package log

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/pkg/errors"
)

var (
	pool = &sync.Pool{
		New: func() interface{} {
			return make([]byte, 0, maxLogSize)
		},
	}

	utsname string
)

func init() {
	hname, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	utsname = hname
}

// Logger is a collection of properties how to output logs.
// Properties are initially set by NewLogger.  They can be customized
// later by Logger methods.
type Logger struct {
	topic     atomic.Value
	threshold int32
	defaults  atomic.Value
	format    atomic.Value

	mu     sync.Mutex
	output io.Writer
}

// NewLogger constructs a new Logger struct.
//
// Attributes are initialized as follows:
//    Topic:     path.Base(os.Args[0])
//    Threshold: LvInfo
//    Formatter: PlainFormat
//    Output:    os.Stderr
//    Defaults:  nil
func NewLogger() *Logger {
	l := &Logger{
		output: os.Stderr,
	}
	l.SetTopic(normalizeTopic(path.Base(os.Args[0])))
	l.SetThreshold(LvInfo)
	l.SetDefaults(nil)
	l.SetFormatter(PlainFormat{})
	return l
}

func normalizeTopic(n string) string {
	// Topic must match [.a-z0-9-]+
	topic := strings.Map(func(r rune) rune {
		switch {
		case r == '.' || r == '-':
			return r
		case r >= '0' && r < '9':
			return r
		case r >= 'a' && r <= 'z':
			return r
		case r >= 'A' && r < 'Z':
			return r + ('a' - 'A')
		default:
			return '-'
		}
	}, n)
	if len(topic) > maxTopicLength {
		return topic[:maxTopicLength]
	}
	return topic
}

// Topic returns the topic for the logger.
func (l *Logger) Topic() string {
	return l.topic.Load().(string)
}

// SetTopic sets a new topic for the logger.
// topic must not be empty.  Too long topic may be shortened automatically.
func (l *Logger) SetTopic(topic string) {
	if len(topic) == 0 {
		panic("Empty tag")
	}

	l.mu.Lock()
	l.topic.Store(topic)
	l.mu.Unlock()
}

// Threshold returns the current threshold of the logger.
func (l *Logger) Threshold() int {
	return int(atomic.LoadInt32(&l.threshold))
}

// Enabled returns true if the log for the given level will be logged.
// This can be used to avoid futile computation for logs being ignored.
//
//    if log.Enabled(log.LvDebug) {
//        log.Debug("message", map[string]interface{}{
//            "debug info": "...",
//        })
//    }
func (l *Logger) Enabled(level int) bool {
	return level <= l.Threshold()
}

// SetThreshold sets the threshold for the logger.
// level must be a pre-defined constant such as LvInfo.
func (l *Logger) SetThreshold(level int) {
	l.mu.Lock()
	atomic.StoreInt32(&l.threshold, int32(level))
	l.mu.Unlock()
}

// SetThresholdByName sets the threshold for the logger by the level name.
func (l *Logger) SetThresholdByName(n string) error {
	var level int
	switch n {
	case "critical", "crit":
		level = LvCritical
	case "error":
		level = LvError
	case "warning", "warn":
		level = LvWarn
	case "information", "info":
		level = LvInfo
	case "debug":
		level = LvDebug
	default:
		return fmt.Errorf("No such level: %s", n)
	}
	l.SetThreshold(level)
	return nil
}

// SetDefaults sets default field values for the logger.
// Setting nil effectively clear the defaults.
func (l *Logger) SetDefaults(d map[string]interface{}) error {
	for key := range d {
		if !IsValidKey(key) {
			return ErrInvalidKey
		}
	}

	l.mu.Lock()
	l.defaults.Store(d)
	l.mu.Unlock()
	return nil
}

// Defaults returns default field values.
func (l *Logger) Defaults() map[string]interface{} {
	return l.defaults.Load().(map[string]interface{})
}

// SetFormatter sets log formatter.
func (l *Logger) SetFormatter(f Formatter) {
	l.mu.Lock()
	l.format.Store(&f)
	l.mu.Unlock()
}

// Formatter returns the current log formatter.
func (l *Logger) Formatter() Formatter {
	return *l.format.Load().(*Formatter)
}

// SetOutput sets io.Writer for log output.
// Setting nil disables log output.
func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	l.output = w
	l.mu.Unlock()
}

// Writer returns an io.Writer.
// Each line written in the writer will be logged to the logger
// with the given severity.
func (l *Logger) Writer(severity int) io.Writer {
	r, w := io.Pipe()

	go func() {
		scanner := bufio.NewScanner(r)
		for scanner.Scan() {
			if err := l.Log(severity, scanner.Text(), nil); err != nil {
				r.CloseWithError(err)
			}
		}
		if err := scanner.Err(); err != nil {
			r.CloseWithError(err)
		}
	}()

	return w
}

// Log outputs a log message with additional fields.
// fields can be nil.
func (l *Logger) Log(severity int, msg string, fields map[string]interface{}) error {
	if severity > l.Threshold() {
		return nil
	}

	t := time.Now()
	buf := pool.Get().([]byte)
	defer pool.Put(buf)

	if l.output != nil {
		b, err := l.Formatter().Format(buf, l, t, severity, msg, fields)
		if err != nil {
			return err
		}

		l.mu.Lock()
		defer l.mu.Unlock()
		if _, err := l.output.Write(b); err != nil {
			fmt.Fprintf(os.Stderr, "logger output causes an error: %v", err)
			return errors.Wrap(err, "Logger.Log")
		}
	}

	return nil
}

// Critical outputs a critical log.
// fields can be nil.
func (l *Logger) Critical(msg string, fields map[string]interface{}) error {
	return l.Log(LvCritical, msg, fields)
}

// Error outputs an error log.
// fields can be nil.
func (l *Logger) Error(msg string, fields map[string]interface{}) error {
	return l.Log(LvError, msg, fields)
}

// Warn outputs a warning log.
// fields can be nil.
func (l *Logger) Warn(msg string, fields map[string]interface{}) error {
	return l.Log(LvWarn, msg, fields)
}

// Info outputs an informational log.
// fields can be nil.
func (l *Logger) Info(msg string, fields map[string]interface{}) error {
	return l.Log(LvInfo, msg, fields)
}

// Debug outputs a debug log.
// fields can be nil.
func (l *Logger) Debug(msg string, fields map[string]interface{}) error {
	return l.Log(LvDebug, msg, fields)
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/mattn/go-isatty"
)

var (
	green        = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white        = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow       = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red          = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue         = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta      = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan         = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset        = string([]byte{27, 91, 48, 109})
	disableColor = false
)

func DisableConsoleColor() {
	disableColor = true
}

func ErrorLogger() HandlerFunc {
	return ErrorLoggerT(ErrorTypeAny)
}

func ErrorLoggerT(typ ErrorType) HandlerFunc {
	return func(c *Context) {
		c.Next()
		errors := c.Errors.ByType(typ)
		if len(errors) > 0 {
			c.JSON(-1, errors)
		}
	}
}

// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func Logger() HandlerFunc {
	return LoggerWithWriter(DefaultWriter)
}

// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
	isTerm := true

	if w, ok := out.(*os.File); !ok ||
		(os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd()))) ||
		disableColor {
		isTerm = false
	}

	var skip map[string]struct{}

	if length := len(notlogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, path := range notlogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path

		// Process request
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			// Stop timer
			end := time.Now()
			latency := end.Sub(start)

			clientIP := c.ClientIP()
			method := c.Request.Method
			statusCode := c.Writer.Status()
			var statusColor, methodColor string
			if isTerm {
				statusColor = colorForStatus(statusCode)
				methodColor = colorForMethod(method)
			}
			comment := c.Errors.ByType(ErrorTypePrivate).String()

			fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s  %s %-7s %s\n%s",
				end.Format("2006/01/02 - 15:04:05"),
				statusColor, statusCode, reset,
				latency,
				clientIP,
				methodColor, method, reset,
				path,
				comment,
			)
		}
	}
}

func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return green
	case code >= 300 && code < 400:
		return white
	case code >= 400 && code < 500:
		return yellow
	default:
		return red
	}
}

func colorForMethod(method string) string {
	switch method {
	case "GET":
		return blue
	case "POST":
		return cyan
	case "PUT":
		return yellow
	case "DELETE":
		return red
	case "PATCH":
		return green
	case "HEAD":
		return magenta
	case "OPTIONS":
		return white
	default:
		return reset
	}
}
<commit_msg>docs(logger): add missing inline docs<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/mattn/go-isatty"
)

var (
	green        = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white        = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow       = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red          = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue         = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta      = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan         = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset        = string([]byte{27, 91, 48, 109})
	disableColor = false
)

// DisableConsoleColor disables color output in the console
func DisableConsoleColor() {
	disableColor = true
}

// ErrorLogger returns a handlerfunc for any error type
func ErrorLogger() HandlerFunc {
	return ErrorLoggerT(ErrorTypeAny)
}

// ErrorLoggerT returns a handlerfunc for a given error type
func ErrorLoggerT(typ ErrorType) HandlerFunc {
	return func(c *Context) {
		c.Next()
		errors := c.Errors.ByType(typ)
		if len(errors) > 0 {
			c.JSON(-1, errors)
		}
	}
}

// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func Logger() HandlerFunc {
	return LoggerWithWriter(DefaultWriter)
}

// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
	isTerm := true

	if w, ok := out.(*os.File); !ok ||
		(os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd()))) ||
		disableColor {
		isTerm = false
	}

	var skip map[string]struct{}

	if length := len(notlogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, path := range notlogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path

		// Process request
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			// Stop timer
			end := time.Now()
			latency := end.Sub(start)

			clientIP := c.ClientIP()
			method := c.Request.Method
			statusCode := c.Writer.Status()
			var statusColor, methodColor string
			if isTerm {
				statusColor = colorForStatus(statusCode)
				methodColor = colorForMethod(method)
			}
			comment := c.Errors.ByType(ErrorTypePrivate).String()

			fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s  %s %-7s %s\n%s",
				end.Format("2006/01/02 - 15:04:05"),
				statusColor, statusCode, reset,
				latency,
				clientIP,
				methodColor, method, reset,
				path,
				comment,
			)
		}
	}
}

func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return green
	case code >= 300 && code < 400:
		return white
	case code >= 400 && code < 500:
		return yellow
	default:
		return red
	}
}

func colorForMethod(method string) string {
	switch method {
	case "GET":
		return blue
	case "POST":
		return cyan
	case "PUT":
		return yellow
	case "DELETE":
		return red
	case "PATCH":
		return green
	case "HEAD":
		return magenta
	case "OPTIONS":
		return white
	default:
		return reset
	}
}
<|endoftext|>


<commit_before>package golog

import (
	"flag"
	"os"
)

// Prints everything this level and above. (Set to SILENT to disable).
var flag_minloglevel = flag.Int("golog.minloglevel", INFO,
	"Log messages at or above this level. The "+
		"numbers of severity levels INFO, WARNING, "+
		"ERROR, and FATAL are 0, 1, 2, and 3, respectively")

// Logger.Log uses the level to determine whether or not to output the
// arguments. Logger.Log will output the provided arguments exactly, without
// additional formatting such as adding a prefix etc. In addition, Logger.Log
// must be thread safe. The FailNow() function flushes the Logger and performs
// some action. The action performed by FailNow() is deliberately unspecified,
// but could include os.Exit(1) or testing.(*T).FailNow(), etc.
type Logger interface {
	// If the message is to be logged, evaluates the closure and outputs
	// the result.
	Log(level int, closure func() *LogMessage)
	FailNow()
	SetMinLogLevel(level int)
}

func exitNow() {
	os.Exit(1)
}

func NewLogger(outer LogOuter, minloglevel int, failFunc func()) Logger {
	return &loggerImpl{outer, &minloglevel, failFunc}
}

func NewDefaultLogger() Logger {
	return &loggerImpl{
		NewDefaultMultiLogOuter(),
		flag_minloglevel,
		exitNow,
	}
}

type loggerImpl struct {
	LogOuter
	// This is a reference type so we can add log writers before having
	// parsed flag_minloglevel.
	minloglevel *int
	failFunc    func()
}

func (l *loggerImpl) Log(level int, closure func() *LogMessage) {
	if level >= *l.minloglevel {
		l.Output(closure())
	}
}

func (l *loggerImpl) FailNow() {
	// TODO Flush log outer?
	l.failFunc()
}

func (l *loggerImpl) SetMinLogLevel(level int) {
	*l.minloglevel = level
}
<commit_msg>Comment Logger constructors<commit_after>package golog

import (
	"flag"
	"os"
)

// Prints everything this level and above. (Set to SILENT to disable).
var flag_minloglevel = flag.Int("golog.minloglevel", INFO,
	"Log messages at or above this level. The "+
		"numbers of severity levels INFO, WARNING, "+
		"ERROR, and FATAL are 0, 1, 2, and 3, respectively")

// Logger.Log uses the level to determine whether or not to output the
// arguments. Logger.Log will output the provided arguments exactly, without
// additional formatting such as adding a prefix etc. In addition, Logger.Log
// must be thread safe. The FailNow() function flushes the Logger and performs
// some action. The action performed by FailNow() is deliberately unspecified,
// but could include os.Exit(1) or testing.(*T).FailNow(), etc.
type Logger interface {
	// If the message is to be logged, evaluates the closure and outputs
	// the result.
	Log(level int, closure func() *LogMessage)
	FailNow()
	SetMinLogLevel(level int)
}

func exitNow() {
	os.Exit(1)
}

// Construct a new Logger that writes any messages of level minloglevel or
// higher to the given LogOuter. Calls to Logger.FailNow() call the provided
// failFunc closure.
func NewLogger(outer LogOuter, minloglevel int, failFunc func()) Logger {
	return &loggerImpl{outer, &minloglevel, failFunc}
}

// Return the default log outer. Note: calls to SetMinLogLevel will affect
// all instances of the DefaultLogger.
func NewDefaultLogger() Logger {
	// TODO Use only one global default logger, pass a ptr to it.
	return &loggerImpl{
		NewDefaultMultiLogOuter(),
		flag_minloglevel,
		exitNow,
	}
}

type loggerImpl struct {
	LogOuter
	// This is a reference type so we can add log writers before having
	// parsed flag_minloglevel.
	minloglevel *int
	failFunc    func()
}

func (l *loggerImpl) Log(level int, closure func() *LogMessage) {
	if level >= *l.minloglevel {
		l.Output(closure())
	}
}

func (l *loggerImpl) FailNow() {
	// TODO Flush log outer?
	l.failFunc()
}

func (l *loggerImpl) SetMinLogLevel(level int) {
	*l.minloglevel = level
}
<|endoftext|>


<commit_before>// Package logger provides a logging framework similar to those of python
// and haskell.
package logger

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"text/template"
	"time"
)

// Format represents the format which will be used to print the message
// for an logger.
type Format string

// Logger represent different lognames and priorities. They can have
// parents and child loggers which will inherit the priority of the
// parent if it has none. The hirachy of loggers is represented through
// sepperation with dots ('.'). The root logger has the name '.'.
type Logger string

type message struct {
	Time string
	Logger
	Priority string
	Message  string
}

type logger struct {
	Logger
	Priority
	Format
	TimeFormat string
}

// Priority defines how important a log message is. Loggers will output
// messages which are above their priority level.
type Priority int

// Different priority levels ordered by their severity.
const (
	Debug Priority = iota
	Info
	Notice
	Warning
	Error
	Critical
	Alert
	Emergency
	Disable
)

// DefaultPriority of the root logger.
const (
	DefaultPriority Priority = Notice
)

const (
	defroot      = Logger(".")
	defseperator = "."
)

var (
	format     = "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
	timeformat = time.RFC3339

	priorities     map[Priority]string
	loggers        map[Logger]logger
	formattemplate template.Template
)

func init() {
	loggers = make(map[Logger]logger)
	l := logger{Logger: defroot,
		Priority:   DefaultPriority,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[defroot] = l

	priorities = make(map[Priority]string)
	priorities[Debug] = "Debug"
	priorities[Info] = "Info"
	priorities[Notice] = "Notice"
	priorities[Warning] = "Warning"
	priorities[Error] = "Error"
	priorities[Critical] = "Critical"
	priorities[Alert] = "Alert"
	priorities[Emergency] = "Emergency"
	priorities[Disable] = "Disabled"
}

// New will return a logger with the given name.
func New(na string) (log Logger) {
	return Logger(na)
}

// SetLevel sets the priority level for the logger which should be
// logged.
func SetLevel(lo Logger, pr Priority) (err error) {
	err = errors.New("this priority does not exist")

	for k := range priorities {
		if k == pr {
			err = nil
			break
		}
	}

	if err != nil {
		return
	}

	l := logger{Logger: lo,
		Priority:   pr,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[lo] = l
	return
}

// GetLevel returns the priority level of the given logger.
func GetLevel(lo Logger) (pri Priority) {
	l, e := loggers[lo]
	if e {
		pri = l.Priority
	} else {
		pri = getParentLevel(lo)
	}

	return
}

func getParentLevel(lo Logger) (pri Priority) {
	p := getParent(lo)
	pri = GetLevel(p)

	return
}

func getParent(lo Logger) (log Logger) {
	// Return root if root
	if lo == defroot {
		log = defroot
		return
	}

	s := strings.Split(string(lo), defseperator)

	// Return root if first level logger
	if len(s) == 1 {
		log = defroot
		return
	}

	// Return root if parent is empty
	if s[0] == "" {
		log = defroot
		return
	}

	l := len(s) - 1
	z := s[0:l]

	log = Logger(strings.Join(z, defseperator))

	return
}

func getLogger(lo Logger) (log logger) {
	l, e := loggers[lo]
	if e {
		log = l
	} else {
		log = getParentLogger(lo)
	}

	return
}

func getParentLogger(lo Logger) (log logger) {
	l := getParent(lo)
	log = getLogger(l)
	log.Logger = lo

	return
}

// ParsePriority tries to parse the priority by the given string.
func ParsePriority(pr string) (Priority, error) {
	for k, v := range priorities {
		if v == pr {
			return k, nil
		}
	}

	e := errors.New("Can not parse " + pr + ". Using DefaultPriority")
	return DefaultPriority, e
}

// NamePriority returns the string value of the given priority.
func NamePriority(pr Priority) string {
	return priorities[pr]
}

// SetFormat changes the message format for the given logger. Avaivable
// fields are:
//
// Time: The time when the message is printed.
//
// Logger: The name of the logger.
//
// Priority: The priority of the logger.
//
// Message: The output message.
//
// The default Format is:
//
// "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
func SetFormat(lo Logger, fo Format) (err error) {
	l := getLogger(lo)
	l.Format = fo
	loggers[lo] = l

	return
}

// SetTimeFormat sets the TimeFormat which will be used in the message
// format for the specified logger
//
// The default format is: RFC3339
func SetTimeFormat(lo Logger, fo string) (err error) {
	l := getLogger(lo)
	l.TimeFormat = fo
	loggers[lo] = l

	return
}

// Log logs a message using the given logger at a given priority.
func Log(lo Logger, pr Priority, me ...interface{}) {
	l := getLogger(lo)

	if l.Priority > pr {
		return
	}

	printMessage(l, pr, os.Stderr, me...)
}

func printMessage(lo logger, pr Priority, wr io.Writer, me ...interface{}) {
	m := new(message)
	m.Time = time.Now().Format(string(lo.TimeFormat))
	m.Logger = lo.Logger
	m.Priority = priorities[pr]
	m.Message = fmt.Sprint(me...)

	s := formatMessage(m, lo.Format)

	fmt.Fprint(wr, s)
}

func formatMessage(me *message, fo Format) (so string) {
	so = strings.Replace(string(fo), "{{.Time}}", me.Time, -1)
	so = strings.Replace(so, "{{.Logger}}", string(me.Logger), -1)
	so = strings.Replace(so, "{{.Priority}}", me.Priority, -1)
	so = strings.Replace(so, "{{.Message}}", me.Message, -1)

	return
}

// DebugM logs a message with the Debug priority.
func (lo Logger) Debug(me ...interface{}) {
	Log(lo, Debug, me...)
}

// InfoM logs a message with the Debug priority.
func (lo Logger) Info(me ...interface{}) {
	Log(lo, Info, me...)
}

// NoticeM logs a message with the Debug priority.
func (lo Logger) Notice(me ...interface{}) {
	Log(lo, Notice, me...)
}

// WarningM logs a message with the Debug priority.
func (lo Logger) Warning(me ...interface{}) {
	Log(lo, Warning, me...)
}

// ErrorM logs a message with the Debug priority.
func (lo Logger) Error(me ...interface{}) {
	Log(lo, Error, me...)
}

// CriticalM logs a message with the Debug priority.
func (lo Logger) Critical(me ...interface{}) {
	Log(lo, Critical, me...)
}

// AlertM logs a message with the Debug priority.
func (lo Logger) Alert(me ...interface{}) {
	Log(lo, Alert, me...)
}

// EmergencyM logs a message with the Debug priority.
func (lo Logger) Emergency(me ...interface{}) {
	Log(lo, Emergency, me...)
}
<commit_msg>Moved Priority before Logger in defaultformat.<commit_after>// Package logger provides a logging framework similar to those of python
// and haskell.
package logger

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"text/template"
	"time"
)

// Format represents the format which will be used to print the message
// for an logger.
type Format string

// Logger represent different lognames and priorities. They can have
// parents and child loggers which will inherit the priority of the
// parent if it has none. The hirachy of loggers is represented through
// sepperation with dots ('.'). The root logger has the name '.'.
type Logger string

type message struct {
	Time string
	Logger
	Priority string
	Message  string
}

type logger struct {
	Logger
	Priority
	Format
	TimeFormat string
}

// Priority defines how important a log message is. Loggers will output
// messages which are above their priority level.
type Priority int

// Different priority levels ordered by their severity.
const (
	Debug Priority = iota
	Info
	Notice
	Warning
	Error
	Critical
	Alert
	Emergency
	Disable
)

// DefaultPriority of the root logger.
const (
	DefaultPriority Priority = Notice
)

const (
	defroot      = Logger(".")
	defseperator = "."
)

var (
	format     = "[{{.Time}} {{.Priority}} {{.Logger}}] - {{.Message}}.\n"
	timeformat = time.RFC3339

	priorities     map[Priority]string
	loggers        map[Logger]logger
	formattemplate template.Template
)

func init() {
	loggers = make(map[Logger]logger)
	l := logger{Logger: defroot,
		Priority:   DefaultPriority,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[defroot] = l

	priorities = make(map[Priority]string)
	priorities[Debug] = "Debug"
	priorities[Info] = "Info"
	priorities[Notice] = "Notice"
	priorities[Warning] = "Warning"
	priorities[Error] = "Error"
	priorities[Critical] = "Critical"
	priorities[Alert] = "Alert"
	priorities[Emergency] = "Emergency"
	priorities[Disable] = "Disabled"
}

// New will return a logger with the given name.
func New(na string) (log Logger) {
	return Logger(na)
}

// SetLevel sets the priority level for the logger which should be
// logged.
func SetLevel(lo Logger, pr Priority) (err error) {
	err = errors.New("this priority does not exist")

	for k := range priorities {
		if k == pr {
			err = nil
			break
		}
	}

	if err != nil {
		return
	}

	l := logger{Logger: lo,
		Priority:   pr,
		Format:     Format(format),
		TimeFormat: timeformat,
	}

	loggers[lo] = l
	return
}

// GetLevel returns the priority level of the given logger.
func GetLevel(lo Logger) (pri Priority) {
	l, e := loggers[lo]
	if e {
		pri = l.Priority
	} else {
		pri = getParentLevel(lo)
	}

	return
}

func getParentLevel(lo Logger) (pri Priority) {
	p := getParent(lo)
	pri = GetLevel(p)

	return
}

func getParent(lo Logger) (log Logger) {
	// Return root if root
	if lo == defroot {
		log = defroot
		return
	}

	s := strings.Split(string(lo), defseperator)

	// Return root if first level logger
	if len(s) == 1 {
		log = defroot
		return
	}

	// Return root if parent is empty
	if s[0] == "" {
		log = defroot
		return
	}

	l := len(s) - 1
	z := s[0:l]

	log = Logger(strings.Join(z, defseperator))

	return
}

func getLogger(lo Logger) (log logger) {
	l, e := loggers[lo]
	if e {
		log = l
	} else {
		log = getParentLogger(lo)
	}

	return
}

func getParentLogger(lo Logger) (log logger) {
	l := getParent(lo)
	log = getLogger(l)
	log.Logger = lo

	return
}

// ParsePriority tries to parse the priority by the given string.
func ParsePriority(pr string) (Priority, error) {
	for k, v := range priorities {
		if v == pr {
			return k, nil
		}
	}

	e := errors.New("Can not parse " + pr + ". Using DefaultPriority")
	return DefaultPriority, e
}

// NamePriority returns the string value of the given priority.
func NamePriority(pr Priority) string {
	return priorities[pr]
}

// SetFormat changes the message format for the given logger. Avaivable
// fields are:
//
// Time: The time when the message is printed.
//
// Logger: The name of the logger.
//
// Priority: The priority of the logger.
//
// Message: The output message.
//
// The default Format is:
//
// "[{{.Time}} {{.Logger}} {{.Priority}}] - {{.Message}}.\n"
func SetFormat(lo Logger, fo Format) (err error) {
	l := getLogger(lo)
	l.Format = fo
	loggers[lo] = l

	return
}

// SetTimeFormat sets the TimeFormat which will be used in the message
// format for the specified logger
//
// The default format is: RFC3339
func SetTimeFormat(lo Logger, fo string) (err error) {
	l := getLogger(lo)
	l.TimeFormat = fo
	loggers[lo] = l

	return
}

// Log logs a message using the given logger at a given priority.
func Log(lo Logger, pr Priority, me ...interface{}) {
	l := getLogger(lo)

	if l.Priority > pr {
		return
	}

	printMessage(l, pr, os.Stderr, me...)
}

func printMessage(lo logger, pr Priority, wr io.Writer, me ...interface{}) {
	m := new(message)
	m.Time = time.Now().Format(string(lo.TimeFormat))
	m.Logger = lo.Logger
	m.Priority = priorities[pr]
	m.Message = fmt.Sprint(me...)

	s := formatMessage(m, lo.Format)

	fmt.Fprint(wr, s)
}

func formatMessage(me *message, fo Format) (so string) {
	so = strings.Replace(string(fo), "{{.Time}}", me.Time, -1)
	so = strings.Replace(so, "{{.Logger}}", string(me.Logger), -1)
	so = strings.Replace(so, "{{.Priority}}", me.Priority, -1)
	so = strings.Replace(so, "{{.Message}}", me.Message, -1)

	return
}

// DebugM logs a message with the Debug priority.
func (lo Logger) Debug(me ...interface{}) {
	Log(lo, Debug, me...)
}

// InfoM logs a message with the Debug priority.
func (lo Logger) Info(me ...interface{}) {
	Log(lo, Info, me...)
}

// NoticeM logs a message with the Debug priority.
func (lo Logger) Notice(me ...interface{}) {
	Log(lo, Notice, me...)
}

// WarningM logs a message with the Debug priority.
func (lo Logger) Warning(me ...interface{}) {
	Log(lo, Warning, me...)
}

// ErrorM logs a message with the Debug priority.
func (lo Logger) Error(me ...interface{}) {
	Log(lo, Error, me...)
}

// CriticalM logs a message with the Debug priority.
func (lo Logger) Critical(me ...interface{}) {
	Log(lo, Critical, me...)
}

// AlertM logs a message with the Debug priority.
func (lo Logger) Alert(me ...interface{}) {
	Log(lo, Alert, me...)
}

// EmergencyM logs a message with the Debug priority.
func (lo Logger) Emergency(me ...interface{}) {
	Log(lo, Emergency, me...)
}
<|endoftext|>


<commit_before>package fluent

import (
	"errors"
	"log"
	"net"
	"strconv"
	"time"
)

// Logger owns asynchronous logging to fluentd.
type Logger struct {
	config   Config
	postCh   chan message
	buffer   []byte
	conn     net.Conn
	ticker   *time.Ticker
	logError bool
}

// NewLogger() launches a goroutine to log and returns logger.
// Logger has a channel to interact with the goroutine.
func NewLogger(config Config) *Logger {
	config.applyDefaultValues()

	logger := &Logger{
		config:   config,
		postCh:   make(chan message, config.ChannelLength),
		buffer:   make([]byte, config.BufferLength),
		ticker:   time.NewTicker(config.BufferingTimeout),
		logError: true,
	}
	logger.connect()
	go logger.loop()

	return logger
}

// You can send message to logger's goroutine via channel.
// This logging is executed asynchronously.
func (l *Logger) Post(tag string, data interface{}) {
	tag = l.prependTagPrefix(tag)
	l.postCh <- message{tag: tag, time: time.Now(), data: data}
}

// You can send message immediately to fluentd.
func (l *Logger) Log(tag string, data interface{}) error {
	tag = l.prependTagPrefix(tag)
	msg := &message{tag: tag, time: time.Now(), data: data}
	pack, err := msg.toMsgpack()
	if err != nil {
		return err
	}

	l.buffer = append(l.buffer, pack...)
	return l.sendMessage()
}

func (l *Logger) loop() {
	for {
		select {
		case msg := <-l.postCh:
			pack, err := msg.toMsgpack()
			if err != nil {
				log.Printf("message pack dump error: " + err.Error())
				continue
			}

			l.buffer = append(l.buffer, pack...)
			if len(l.buffer) > l.config.BufferLength {
				l.sendMessage()
			}
		case <-l.ticker.C:
			l.sendMessage()
		}
	}
}

func (l *Logger) sendMessage() error {
	if len(l.buffer) == 0 {
		return errors.New("Buffer is empty")
	}

	l.connect()
	if l.conn == nil {
		return errors.New("Failed to establish connection with fluentd")
	}

	_, err := l.conn.Write(l.buffer)

	if err == nil {
		l.buffer = l.buffer[0:0]
	} else {
		log.Printf("failed to send message: " + err.Error())
		l.conn.Close()
		l.conn = nil
	}
	return err
}

func (l *Logger) connect() {
	if l.conn != nil {
		return
	}

	var err error
	for i := 0; i < l.config.MaxTrialForConnection; i++ {
		l.conn, err = net.DialTimeout(
			"tcp",
			l.config.FluentHost+":"+strconv.Itoa(l.config.FluentPort),
			l.config.ConnectionTimeout,
		)

		if err == nil {
			l.logError = true
			return
		}
	}

	if l.logError {
		log.Printf("failed to establish connection with fluentd: " + err.Error())
		l.logError = false
	}
}

func (l *Logger) prependTagPrefix(tag string) string {
	if l.config.TagPrefix != "" {
		tag = l.config.TagPrefix + "." + tag
	}
	return tag
}
<commit_msg>Revert "Allocate logging buffer first"<commit_after>package fluent

import (
	"errors"
	"log"
	"net"
	"strconv"
	"time"
)

// Logger owns asynchronous logging to fluentd.
type Logger struct {
	config   Config
	postCh   chan message
	buffer   []byte
	conn     net.Conn
	ticker   *time.Ticker
	logError bool
}

// NewLogger() launches a goroutine to log and returns logger.
// Logger has a channel to interact with the goroutine.
func NewLogger(config Config) *Logger {
	config.applyDefaultValues()

	logger := &Logger{
		config:   config,
		postCh:   make(chan message, config.ChannelLength),
		ticker:   time.NewTicker(config.BufferingTimeout),
		logError: true,
	}
	logger.connect()
	go logger.loop()

	return logger
}

// You can send message to logger's goroutine via channel.
// This logging is executed asynchronously.
func (l *Logger) Post(tag string, data interface{}) {
	tag = l.prependTagPrefix(tag)
	l.postCh <- message{tag: tag, time: time.Now(), data: data}
}

// You can send message immediately to fluentd.
func (l *Logger) Log(tag string, data interface{}) error {
	tag = l.prependTagPrefix(tag)
	msg := &message{tag: tag, time: time.Now(), data: data}
	pack, err := msg.toMsgpack()
	if err != nil {
		return err
	}

	l.buffer = append(l.buffer, pack...)
	return l.sendMessage()
}

func (l *Logger) loop() {
	for {
		select {
		case msg := <-l.postCh:
			pack, err := msg.toMsgpack()
			if err != nil {
				log.Printf("message pack dump error: " + err.Error())
				continue
			}

			l.buffer = append(l.buffer, pack...)
			if len(l.buffer) > l.config.BufferLength {
				l.sendMessage()
			}
		case <-l.ticker.C:
			l.sendMessage()
		}
	}
}

func (l *Logger) sendMessage() error {
	if len(l.buffer) == 0 {
		return errors.New("Buffer is empty")
	}

	l.connect()
	if l.conn == nil {
		return errors.New("Failed to establish connection with fluentd")
	}

	_, err := l.conn.Write(l.buffer)

	if err == nil {
		l.buffer = l.buffer[0:0]
	} else {
		log.Printf("failed to send message: " + err.Error())
		l.conn.Close()
		l.conn = nil
	}
	return err
}

func (l *Logger) connect() {
	if l.conn != nil {
		return
	}

	var err error
	for i := 0; i < l.config.MaxTrialForConnection; i++ {
		l.conn, err = net.DialTimeout(
			"tcp",
			l.config.FluentHost+":"+strconv.Itoa(l.config.FluentPort),
			l.config.ConnectionTimeout,
		)

		if err == nil {
			l.logError = true
			return
		}
	}

	if l.logError {
		log.Printf("failed to establish connection with fluentd: " + err.Error())
		l.logError = false
	}
}

func (l *Logger) prependTagPrefix(tag string) string {
	if l.config.TagPrefix != "" {
		tag = l.config.TagPrefix + "." + tag
	}
	return tag
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
)

const (
	// strings longer than this will cause slices, arrays and structs to be printed on multiple lines when newlines is enabled
	maxShortStringLen = 7
	// string used for one indentation level (when printing on multiple lines)
	indentString = "\t"
)

// SinglelineString returns a representation of v on a single line.
func (v *Variable) SinglelineString() string {
	var buf bytes.Buffer
	v.writeTo(&buf, true, false, true, "")
	return buf.String()
}

// MultilineString returns a representation of v on multiple lines.
func (v *Variable) MultilineString(indent string) string {
	var buf bytes.Buffer
	v.writeTo(&buf, true, true, true, indent)
	return buf.String()
}

func (v *Variable) writeTo(buf io.Writer, top, newlines, includeType bool, indent string) {
	if v.Unreadable != "" {
		fmt.Fprintf(buf, "(unreadable %s)", v.Unreadable)
		return
	}

	if !top && v.Addr == 0 && v.Value == "" {
		if includeType && v.Type != "void" {
			fmt.Fprintf(buf, "%s nil", v.Type)
		} else {
			fmt.Fprint(buf, "nil")
		}
		return
	}

	switch v.Kind {
	case reflect.Slice:
		v.writeSliceTo(buf, newlines, includeType, indent)
	case reflect.Array:
		v.writeArrayTo(buf, newlines, includeType, indent)
	case reflect.Ptr:
		if v.Type == "" {
			fmt.Fprint(buf, "nil")
		} else if v.Children[0].OnlyAddr && v.Children[0].Addr != 0 {
			fmt.Fprintf(buf, "(%s)(0x%x)", v.Type, v.Children[0].Addr)
		} else {
			fmt.Fprint(buf, "*")
			v.Children[0].writeTo(buf, false, newlines, includeType, indent)
		}
	case reflect.UnsafePointer:
		fmt.Fprintf(buf, "unsafe.Pointer(0x%x)", v.Children[0].Addr)
	case reflect.String:
		v.writeStringTo(buf)
	case reflect.Chan:
		if newlines {
			v.writeStructTo(buf, newlines, includeType, indent)
		} else {
			if len(v.Children) == 0 {
				fmt.Fprintf(buf, "%s nil", v.Type)
			} else {
				fmt.Fprintf(buf, "%s %s/%s", v.Type, v.Children[0].Value, v.Children[1].Value)
			}
		}
	case reflect.Struct:
		v.writeStructTo(buf, newlines, includeType, indent)
	case reflect.Interface:
		if includeType {
			if v.Children[0].Kind == reflect.Invalid {
				fmt.Fprintf(buf, "%s ", v.Type)
				if v.Children[0].Addr == 0 {
					fmt.Fprint(buf, "nil")
					return
				}
			} else {
				fmt.Fprintf(buf, "%s(%s) ", v.Type, v.Children[0].Type)
			}
		}
		data := v.Children[0]
		if data.Kind == reflect.Ptr {
			if len(data.Children) == 0 {
				fmt.Fprint(buf, "...")
			} else if data.Children[0].Addr == 0 {
				fmt.Fprint(buf, "nil")
			} else if data.Children[0].OnlyAddr {
				fmt.Fprintf(buf, "0x%x", v.Children[0].Addr)
			} else {
				v.Children[0].writeTo(buf, false, newlines, !includeType, indent)
			}
		} else if data.OnlyAddr {
			fmt.Fprintf(buf, "*(*%q)(0x%x)", v.Type, v.Addr)
		} else {
			v.Children[0].writeTo(buf, false, newlines, !includeType, indent)
		}
	case reflect.Map:
		v.writeMapTo(buf, newlines, includeType, indent)
	case reflect.Func:
		if v.Value == "" {
			fmt.Fprint(buf, "nil")
		} else {
			fmt.Fprintf(buf, "%s", v.Value)
		}
	case reflect.Complex64, reflect.Complex128:
		fmt.Fprintf(buf, "(%s + %si)", v.Children[0].Value, v.Children[1].Value)
	default:
		if v.Value != "" {
			buf.Write([]byte(v.Value))
		} else {
			fmt.Fprintf(buf, "(unknown %s)", v.Kind)
		}
	}
}

func (v *Variable) writeStringTo(buf io.Writer) {
	s := v.Value
	if len(s) != int(v.Len) {
		s = fmt.Sprintf("%s...+%d more", s, int(v.Len)-len(s))
	}
	fmt.Fprintf(buf, "%q", s)
}

func (v *Variable) writeSliceTo(buf io.Writer, newlines, includeType bool, indent string) {
	if includeType {
		fmt.Fprintf(buf, "%s len: %d, cap: %d, ", v.Type, v.Len, v.Cap)
	}
	if v.Base == 0 && len(v.Children) == 0 {
		fmt.Fprintf(buf, "nil")
		return
	}
	v.writeSliceOrArrayTo(buf, newlines, indent)
}

func (v *Variable) writeArrayTo(buf io.Writer, newlines, includeType bool, indent string) {
	if includeType {
		fmt.Fprintf(buf, "%s ", v.Type)
	}
	v.writeSliceOrArrayTo(buf, newlines, indent)
}

func (v *Variable) writeStructTo(buf io.Writer, newlines, includeType bool, indent string) {
	if int(v.Len) != len(v.Children) && len(v.Children) == 0 {
		fmt.Fprintf(buf, "(*%s)(0x%x)", v.Type, v.Addr)
		return
	}

	if includeType {
		fmt.Fprintf(buf, "%s ", v.Type)
	}

	nl := v.shouldNewlineStruct(newlines)

	fmt.Fprint(buf, "{")

	for i := range v.Children {
		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		}
		fmt.Fprintf(buf, "%s: ", v.Children[i].Name)
		v.Children[i].writeTo(buf, false, nl, true, indent+indentString)
		if i != len(v.Children)-1 || nl {
			fmt.Fprint(buf, ",")
			if !nl {
				fmt.Fprint(buf, " ")
			}
		}
	}

	if len(v.Children) != int(v.Len) {
		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		} else {
			fmt.Fprint(buf, ",")
		}
		fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children))
	}

	fmt.Fprint(buf, "}")
}

func (v *Variable) writeMapTo(buf io.Writer, newlines, includeType bool, indent string) {
	if includeType {
		fmt.Fprintf(buf, "%s ", v.Type)
	}
	if v.Base == 0 && len(v.Children) == 0 {
		fmt.Fprintf(buf, "nil")
		return
	}

	nl := newlines && (len(v.Children) > 0)

	fmt.Fprint(buf, "[")

	for i := 0; i < len(v.Children); i += 2 {
		key := &v.Children[i]
		value := &v.Children[i+1]

		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		}

		key.writeTo(buf, false, false, false, indent+indentString)
		fmt.Fprint(buf, ": ")
		value.writeTo(buf, false, nl, false, indent+indentString)
		if i != len(v.Children)-1 || nl {
			fmt.Fprint(buf, ", ")
		}
	}

	if len(v.Children)/2 != int(v.Len) {
		if len(v.Children) != 0 {
			if nl {
				fmt.Fprintf(buf, "\n%s%s", indent, indentString)
			} else {
				fmt.Fprint(buf, ",")
			}
			fmt.Fprintf(buf, "...+%d more", int(v.Len)-(len(v.Children)/2))
		} else {
			fmt.Fprint(buf, "...")
		}
	}

	if nl {
		fmt.Fprintf(buf, "\n%s", indent)
	}
	fmt.Fprint(buf, "]")
}

func (v *Variable) shouldNewlineArray(newlines bool) bool {
	if !newlines || len(v.Children) == 0 {
		return false
	}

	kind, hasptr := (&v.Children[0]).recursiveKind()

	switch kind {
	case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
		return true
	case reflect.String:
		if hasptr {
			return true
		}
		for i := range v.Children {
			if len(v.Children[i].Value) > maxShortStringLen {
				return true
			}
		}
		return false
	default:
		return false
	}
}

func (v *Variable) recursiveKind() (reflect.Kind, bool) {
	hasptr := false
	var kind reflect.Kind
	for {
		kind = v.Kind
		if kind == reflect.Ptr {
			hasptr = true
			v = &(v.Children[0])
		} else {
			break
		}
	}
	return kind, hasptr
}

func (v *Variable) shouldNewlineStruct(newlines bool) bool {
	if !newlines || len(v.Children) == 0 {
		return false
	}

	for i := range v.Children {
		kind, hasptr := (&v.Children[i]).recursiveKind()

		switch kind {
		case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
			return true
		case reflect.String:
			if hasptr {
				return true
			}
			if len(v.Children[i].Value) > maxShortStringLen {
				return true
			}
		}
	}

	return false
}

func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent string) {
	nl := v.shouldNewlineArray(newlines)
	fmt.Fprint(buf, "[")

	for i := range v.Children {
		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		}
		v.Children[i].writeTo(buf, false, nl, false, indent+indentString)
		if i != len(v.Children)-1 || nl {
			fmt.Fprint(buf, ",")
		}
	}

	if len(v.Children) != int(v.Len) {
		if len(v.Children) != 0 {
			if nl {
				fmt.Fprintf(buf, "\n%s%s", indent, indentString)
			} else {
				fmt.Fprint(buf, ",")
			}
			fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children))
		} else {
			fmt.Fprint(buf, "...")
		}
	}

	if nl {
		fmt.Fprintf(buf, "\n%s", indent)
	}

	fmt.Fprint(buf, "]")
}
<commit_msg>variables: toplevel interface variables may have a 0 address<commit_after>package api

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
)

const (
	// strings longer than this will cause slices, arrays and structs to be printed on multiple lines when newlines is enabled
	maxShortStringLen = 7
	// string used for one indentation level (when printing on multiple lines)
	indentString = "\t"
)

// SinglelineString returns a representation of v on a single line.
func (v *Variable) SinglelineString() string {
	var buf bytes.Buffer
	v.writeTo(&buf, true, false, true, "")
	return buf.String()
}

// MultilineString returns a representation of v on multiple lines.
func (v *Variable) MultilineString(indent string) string {
	var buf bytes.Buffer
	v.writeTo(&buf, true, true, true, indent)
	return buf.String()
}

func (v *Variable) writeTo(buf io.Writer, top, newlines, includeType bool, indent string) {
	if v.Unreadable != "" {
		fmt.Fprintf(buf, "(unreadable %s)", v.Unreadable)
		return
	}

	if !top && v.Addr == 0 && v.Value == "" {
		if includeType && v.Type != "void" {
			fmt.Fprintf(buf, "%s nil", v.Type)
		} else {
			fmt.Fprint(buf, "nil")
		}
		return
	}

	switch v.Kind {
	case reflect.Slice:
		v.writeSliceTo(buf, newlines, includeType, indent)
	case reflect.Array:
		v.writeArrayTo(buf, newlines, includeType, indent)
	case reflect.Ptr:
		if v.Type == "" {
			fmt.Fprint(buf, "nil")
		} else if v.Children[0].OnlyAddr && v.Children[0].Addr != 0 {
			fmt.Fprintf(buf, "(%s)(0x%x)", v.Type, v.Children[0].Addr)
		} else {
			fmt.Fprint(buf, "*")
			v.Children[0].writeTo(buf, false, newlines, includeType, indent)
		}
	case reflect.UnsafePointer:
		fmt.Fprintf(buf, "unsafe.Pointer(0x%x)", v.Children[0].Addr)
	case reflect.String:
		v.writeStringTo(buf)
	case reflect.Chan:
		if newlines {
			v.writeStructTo(buf, newlines, includeType, indent)
		} else {
			if len(v.Children) == 0 {
				fmt.Fprintf(buf, "%s nil", v.Type)
			} else {
				fmt.Fprintf(buf, "%s %s/%s", v.Type, v.Children[0].Value, v.Children[1].Value)
			}
		}
	case reflect.Struct:
		v.writeStructTo(buf, newlines, includeType, indent)
	case reflect.Interface:
		if v.Addr == 0 {
			// an escaped interface variable that points to nil, this shouldn't
			// happen in normal code but can happen if the variable is out of scope.
			fmt.Fprintf(buf, "nil")
			return
		}
		if includeType {
			if v.Children[0].Kind == reflect.Invalid {
				fmt.Fprintf(buf, "%s ", v.Type)
				if v.Children[0].Addr == 0 {
					fmt.Fprint(buf, "nil")
					return
				}
			} else {
				fmt.Fprintf(buf, "%s(%s) ", v.Type, v.Children[0].Type)
			}
		}
		data := v.Children[0]
		if data.Kind == reflect.Ptr {
			if len(data.Children) == 0 {
				fmt.Fprint(buf, "...")
			} else if data.Children[0].Addr == 0 {
				fmt.Fprint(buf, "nil")
			} else if data.Children[0].OnlyAddr {
				fmt.Fprintf(buf, "0x%x", v.Children[0].Addr)
			} else {
				v.Children[0].writeTo(buf, false, newlines, !includeType, indent)
			}
		} else if data.OnlyAddr {
			fmt.Fprintf(buf, "*(*%q)(0x%x)", v.Type, v.Addr)
		} else {
			v.Children[0].writeTo(buf, false, newlines, !includeType, indent)
		}
	case reflect.Map:
		v.writeMapTo(buf, newlines, includeType, indent)
	case reflect.Func:
		if v.Value == "" {
			fmt.Fprint(buf, "nil")
		} else {
			fmt.Fprintf(buf, "%s", v.Value)
		}
	case reflect.Complex64, reflect.Complex128:
		fmt.Fprintf(buf, "(%s + %si)", v.Children[0].Value, v.Children[1].Value)
	default:
		if v.Value != "" {
			buf.Write([]byte(v.Value))
		} else {
			fmt.Fprintf(buf, "(unknown %s)", v.Kind)
		}
	}
}

func (v *Variable) writeStringTo(buf io.Writer) {
	s := v.Value
	if len(s) != int(v.Len) {
		s = fmt.Sprintf("%s...+%d more", s, int(v.Len)-len(s))
	}
	fmt.Fprintf(buf, "%q", s)
}

func (v *Variable) writeSliceTo(buf io.Writer, newlines, includeType bool, indent string) {
	if includeType {
		fmt.Fprintf(buf, "%s len: %d, cap: %d, ", v.Type, v.Len, v.Cap)
	}
	if v.Base == 0 && len(v.Children) == 0 {
		fmt.Fprintf(buf, "nil")
		return
	}
	v.writeSliceOrArrayTo(buf, newlines, indent)
}

func (v *Variable) writeArrayTo(buf io.Writer, newlines, includeType bool, indent string) {
	if includeType {
		fmt.Fprintf(buf, "%s ", v.Type)
	}
	v.writeSliceOrArrayTo(buf, newlines, indent)
}

func (v *Variable) writeStructTo(buf io.Writer, newlines, includeType bool, indent string) {
	if int(v.Len) != len(v.Children) && len(v.Children) == 0 {
		fmt.Fprintf(buf, "(*%s)(0x%x)", v.Type, v.Addr)
		return
	}

	if includeType {
		fmt.Fprintf(buf, "%s ", v.Type)
	}

	nl := v.shouldNewlineStruct(newlines)

	fmt.Fprint(buf, "{")

	for i := range v.Children {
		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		}
		fmt.Fprintf(buf, "%s: ", v.Children[i].Name)
		v.Children[i].writeTo(buf, false, nl, true, indent+indentString)
		if i != len(v.Children)-1 || nl {
			fmt.Fprint(buf, ",")
			if !nl {
				fmt.Fprint(buf, " ")
			}
		}
	}

	if len(v.Children) != int(v.Len) {
		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		} else {
			fmt.Fprint(buf, ",")
		}
		fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children))
	}

	fmt.Fprint(buf, "}")
}

func (v *Variable) writeMapTo(buf io.Writer, newlines, includeType bool, indent string) {
	if includeType {
		fmt.Fprintf(buf, "%s ", v.Type)
	}
	if v.Base == 0 && len(v.Children) == 0 {
		fmt.Fprintf(buf, "nil")
		return
	}

	nl := newlines && (len(v.Children) > 0)

	fmt.Fprint(buf, "[")

	for i := 0; i < len(v.Children); i += 2 {
		key := &v.Children[i]
		value := &v.Children[i+1]

		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		}

		key.writeTo(buf, false, false, false, indent+indentString)
		fmt.Fprint(buf, ": ")
		value.writeTo(buf, false, nl, false, indent+indentString)
		if i != len(v.Children)-1 || nl {
			fmt.Fprint(buf, ", ")
		}
	}

	if len(v.Children)/2 != int(v.Len) {
		if len(v.Children) != 0 {
			if nl {
				fmt.Fprintf(buf, "\n%s%s", indent, indentString)
			} else {
				fmt.Fprint(buf, ",")
			}
			fmt.Fprintf(buf, "...+%d more", int(v.Len)-(len(v.Children)/2))
		} else {
			fmt.Fprint(buf, "...")
		}
	}

	if nl {
		fmt.Fprintf(buf, "\n%s", indent)
	}
	fmt.Fprint(buf, "]")
}

func (v *Variable) shouldNewlineArray(newlines bool) bool {
	if !newlines || len(v.Children) == 0 {
		return false
	}

	kind, hasptr := (&v.Children[0]).recursiveKind()

	switch kind {
	case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
		return true
	case reflect.String:
		if hasptr {
			return true
		}
		for i := range v.Children {
			if len(v.Children[i].Value) > maxShortStringLen {
				return true
			}
		}
		return false
	default:
		return false
	}
}

func (v *Variable) recursiveKind() (reflect.Kind, bool) {
	hasptr := false
	var kind reflect.Kind
	for {
		kind = v.Kind
		if kind == reflect.Ptr {
			hasptr = true
			v = &(v.Children[0])
		} else {
			break
		}
	}
	return kind, hasptr
}

func (v *Variable) shouldNewlineStruct(newlines bool) bool {
	if !newlines || len(v.Children) == 0 {
		return false
	}

	for i := range v.Children {
		kind, hasptr := (&v.Children[i]).recursiveKind()

		switch kind {
		case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
			return true
		case reflect.String:
			if hasptr {
				return true
			}
			if len(v.Children[i].Value) > maxShortStringLen {
				return true
			}
		}
	}

	return false
}

func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent string) {
	nl := v.shouldNewlineArray(newlines)
	fmt.Fprint(buf, "[")

	for i := range v.Children {
		if nl {
			fmt.Fprintf(buf, "\n%s%s", indent, indentString)
		}
		v.Children[i].writeTo(buf, false, nl, false, indent+indentString)
		if i != len(v.Children)-1 || nl {
			fmt.Fprint(buf, ",")
		}
	}

	if len(v.Children) != int(v.Len) {
		if len(v.Children) != 0 {
			if nl {
				fmt.Fprintf(buf, "\n%s%s", indent, indentString)
			} else {
				fmt.Fprint(buf, ",")
			}
			fmt.Fprintf(buf, "...+%d more", int(v.Len)-len(v.Children))
		} else {
			fmt.Fprint(buf, "...")
		}
	}

	if nl {
		fmt.Fprintf(buf, "\n%s", indent)
	}

	fmt.Fprint(buf, "]")
}
<|endoftext|>


<commit_before>package object

import (
	"fmt"
)

/* Structs */
type (
	Number struct {
		Value float64
	}

	Boolean struct {
		Value bool
	}

	String struct {
		Value string
	}

	Char struct {
		Value byte
	}

	Null struct{}
)

/* Type() methods */
func (_ *Number) Type() Type  { return NUMBER }
func (_ *Boolean) Type() Type { return BOOLEAN }
func (_ *String) Type() Type  { return STRING }
func (_ *Char) Type() Type    { return CHAR }
func (_ *Null) Type() Type    { return NULL }

/* Equals() methods */
func (n *Number) Equals(o Object) bool {
	if other, ok := o.(*Number); ok {
		return n.Value == other.Value
	}

	return false
}

func (b *Boolean) Equals(o Object) bool {
	if other, ok := o.(*Boolean); ok {
		return b.Value == other.Value
	}

	return false
}

func (s *String) Equals(o Object) bool {
	if other, ok := o.(*String); ok {
		return s.Value == other.Value
	}

	return false
}

func (c *Char) Equals(o Object) bool {
	if other, ok := o.(*Char); ok {
		return c.Value == other.Value
	}

	return false
}

func (_ *Null) Equals(o Object) bool {
	_, ok := o.(*Null)
	return ok
}

/* Stringer implementations */
func (n *Number) String() string {
	return fmt.Sprintf("%f", n.Value)
}

func (b *Boolean) String() string {
	return fmt.Sprintf("%t", b.Value)
}

func (s *String) String() string {
	return s.Value
}

func (c *Char) String() string {
	return string(c.Value)
}

func (_ *Null) String() string {
	return "null"
}
<commit_msg>Make strings collections<commit_after>package object

import (
	"fmt"
)

/* Structs */
type (
	Number struct {
		Value float64
	}

	Boolean struct {
		Value bool
	}

	String struct {
		Value string
	}

	Char struct {
		Value rune
	}

	Null struct{}
)

/* Type() methods */
func (_ *Number) Type() Type  { return NUMBER }
func (_ *Boolean) Type() Type { return BOOLEAN }
func (_ *String) Type() Type  { return STRING }
func (_ *Char) Type() Type    { return CHAR }
func (_ *Null) Type() Type    { return NULL }

/* Equals() methods */
func (n *Number) Equals(o Object) bool {
	if other, ok := o.(*Number); ok {
		return n.Value == other.Value
	}

	return false
}

func (b *Boolean) Equals(o Object) bool {
	if other, ok := o.(*Boolean); ok {
		return b.Value == other.Value
	}

	return false
}

func (s *String) Equals(o Object) bool {
	if other, ok := o.(*String); ok {
		return s.Value == other.Value
	}

	return false
}

func (c *Char) Equals(o Object) bool {
	if other, ok := o.(*Char); ok {
		return c.Value == other.Value
	}

	return false
}

func (_ *Null) Equals(o Object) bool {
	_, ok := o.(*Null)
	return ok
}

/* Stringer implementations */
func (n *Number) String() string {
	return fmt.Sprintf("%f", n.Value)
}

func (b *Boolean) String() string {
	return fmt.Sprintf("%t", b.Value)
}

func (s *String) String() string {
	return s.Value
}

func (c *Char) String() string {
	return string(c.Value)
}

func (_ *Null) String() string {
	return "null"
}

/* Collection implementations */
func (s *String) Elements() []Object {
	chars := make([]Object, len(s.Value))

	for i, ch := range s.Value {
		chars[i] = &Char{ch}
	}

	return chars
}
<|endoftext|>


<commit_before>// Copyright 2017 Ole Krüger.
// Licensed under the MIT license which can be found in the LICENSE file.

// Package knxnet provides the means to parse and generate frames of the KNXnet/IP protocol.
package knxnet

import (
	"errors"

	"fmt"

	"github.com/vapourismo/knx-go/knx/util"
)

// ServiceID identifies the service that is contained in a packet.
type ServiceID uint16

// String generates a string representation.
func (srv ServiceID) String() string {
	return fmt.Sprintf("%#04x", uint16(srv))
}

// These are supported services.
const (
	SearchReqService    ServiceID = 0x0201
	SearchResService    ServiceID = 0x0202
	ConnReqService      ServiceID = 0x0205
	ConnResService      ServiceID = 0x0206
	ConnStateReqService ServiceID = 0x0207
	ConnStateResService ServiceID = 0x0208
	DiscReqService      ServiceID = 0x0209
	DiscResService      ServiceID = 0x020a
	TunnelReqService    ServiceID = 0x0420
	TunnelResService    ServiceID = 0x0421
	RoutingIndService   ServiceID = 0x0530
	RoutingLostService  ServiceID = 0x0531
	RoutingBusyService  ServiceID = 0x0532
)

// Service describes a KNXnet/IP service.
type Service interface {
	Service() ServiceID
}

// ServicePackable combines Packable and Service.
type ServicePackable interface {
	util.Packable
	Service
}

// UnknownService is the payload of an unknown service.
type UnknownService struct {
	service ServiceID
	Data    []byte
}

// Service returns the service identifier.
func (us *UnknownService) Service() ServiceID {
	return us.service
}

// Size returns the size of the payload.
func (us *UnknownService) Size() uint {
	return uint(len(us.Data))
}

// Pack the payload into the buffer.
func (us *UnknownService) Pack(buffer []byte) {
	copy(buffer, us.Data)
}

// Unpack copies the entire data.
func (us *UnknownService) Unpack(data []byte) (uint, error) {
	us.Data = make([]byte, len(data))
	return uint(copy(us.Data, data)), nil
}

// Size returns the size of a KNXnet/IP packet.
func Size(service ServicePackable) uint {
	return 6 + service.Size()
}

// Pack generates a KNXnet/IP packet. Utilize Size() to determine the required size of the buffer.
func Pack(buffer []byte, srv ServicePackable) {
	buffer[0] = 6
	buffer[1] = 16
	util.Pack(buffer[2:], uint16(srv.Service()))
	util.Pack(buffer[4:], uint16(srv.Size()+6))
	srv.Pack(buffer[6:])
}

// AllocAndPack allocates a buffer and packs the KNXnet/IP packet into it.
func AllocAndPack(srv ServicePackable) []byte {
	buffer := make([]byte, Size(srv))
	Pack(buffer, srv)
	return buffer
}

// These are errors that might occur during unpacking.
var (
	ErrHeaderLength  = errors.New("Header length is not 6")
	ErrHeaderVersion = errors.New("Protocol version is not 16")
)

type serviceUnpackable interface {
	util.Unpackable
	Service
}

// Unpack parses a KNXnet/IP packet and retrieves its service payload.
//
// On success, the variable pointed to by srv will contain a pointer to a service type.
// You can cast it to the matching against service type, like so:
//
// 	var srv Service
//
// 	_, err := Unpack(r, &srv)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
//
// 	switch srv := srv.(type) {
// 		case *ConnRes:
// 			// ...
//
// 		case *TunnelReq:
// 			// ...
//
// 		// ...
// 	}
//
func Unpack(data []byte, srv *Service) (uint, error) {
	var headerLen, version uint8
	var srvID ServiceID
	var totalLen uint16

	n, err := util.UnpackSome(data, &headerLen, &version, (*uint16)(&srvID), &totalLen)
	if err != nil {
		return n, err
	}

	if headerLen != 6 {
		return n, ErrHeaderLength
	}

	if version != 16 {
		return n, ErrHeaderVersion
	}

	var body serviceUnpackable
	switch srvID {
	case SearchReqService:
		body = &SearchReq{}

	case SearchResService:
		body = &SearchRes{}

	case ConnReqService:
		body = &ConnReq{}

	case ConnResService:
		body = &ConnRes{}

	case ConnStateReqService:
		body = &ConnStateReq{}

	case ConnStateResService:
		body = &ConnStateRes{}

	case DiscReqService:
		body = &DiscReq{}

	case DiscResService:
		body = &DiscRes{}

	case TunnelReqService:
		body = &TunnelReq{}

	case TunnelResService:
		body = &TunnelRes{}

	case RoutingIndService:
		body = &RoutingInd{}

	case RoutingLostService:
		body = &RoutingLost{}

	case RoutingBusyService:
		body = &RoutingBusy{}

	default:
		body = &UnknownService{service: srvID}
	}

	m, err := body.Unpack(data[n:])

	if err == nil {
		*srv = body
	}

	return n + m, err
}
<commit_msg>Do not unpack if data is empty<commit_after>// Copyright 2017 Ole Krüger.
// Licensed under the MIT license which can be found in the LICENSE file.

// Package knxnet provides the means to parse and generate frames of the KNXnet/IP protocol.
package knxnet

import (
	"errors"

	"fmt"

	"github.com/vapourismo/knx-go/knx/util"
)

// ServiceID identifies the service that is contained in a packet.
type ServiceID uint16

// String generates a string representation.
func (srv ServiceID) String() string {
	return fmt.Sprintf("%#04x", uint16(srv))
}

// These are supported services.
const (
	SearchReqService    ServiceID = 0x0201
	SearchResService    ServiceID = 0x0202
	ConnReqService      ServiceID = 0x0205
	ConnResService      ServiceID = 0x0206
	ConnStateReqService ServiceID = 0x0207
	ConnStateResService ServiceID = 0x0208
	DiscReqService      ServiceID = 0x0209
	DiscResService      ServiceID = 0x020a
	TunnelReqService    ServiceID = 0x0420
	TunnelResService    ServiceID = 0x0421
	RoutingIndService   ServiceID = 0x0530
	RoutingLostService  ServiceID = 0x0531
	RoutingBusyService  ServiceID = 0x0532
)

// Service describes a KNXnet/IP service.
type Service interface {
	Service() ServiceID
}

// ServicePackable combines Packable and Service.
type ServicePackable interface {
	util.Packable
	Service
}

// UnknownService is the payload of an unknown service.
type UnknownService struct {
	service ServiceID
	Data    []byte
}

// Service returns the service identifier.
func (us *UnknownService) Service() ServiceID {
	return us.service
}

// Size returns the size of the payload.
func (us *UnknownService) Size() uint {
	return uint(len(us.Data))
}

// Pack the payload into the buffer.
func (us *UnknownService) Pack(buffer []byte) {
	copy(buffer, us.Data)
}

// Unpack copies the entire data.
func (us *UnknownService) Unpack(data []byte) (uint, error) {
	us.Data = make([]byte, len(data))
	return uint(copy(us.Data, data)), nil
}

// Size returns the size of a KNXnet/IP packet.
func Size(service ServicePackable) uint {
	return 6 + service.Size()
}

// Pack generates a KNXnet/IP packet. Utilize Size() to determine the required size of the buffer.
func Pack(buffer []byte, srv ServicePackable) {
	buffer[0] = 6
	buffer[1] = 16
	util.Pack(buffer[2:], uint16(srv.Service()))
	util.Pack(buffer[4:], uint16(srv.Size()+6))
	srv.Pack(buffer[6:])
}

// AllocAndPack allocates a buffer and packs the KNXnet/IP packet into it.
func AllocAndPack(srv ServicePackable) []byte {
	buffer := make([]byte, Size(srv))
	Pack(buffer, srv)
	return buffer
}

// These are errors that might occur during unpacking.
var (
	ErrHeaderLength  = errors.New("Header length is not 6")
	ErrHeaderVersion = errors.New("Protocol version is not 16")
)

type serviceUnpackable interface {
	util.Unpackable
	Service
}

// Unpack parses a KNXnet/IP packet and retrieves its service payload.
//
// On success, the variable pointed to by srv will contain a pointer to a service type.
// You can cast it to the matching against service type, like so:
//
// 	var srv Service
//
// 	_, err := Unpack(r, &srv)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
//
// 	switch srv := srv.(type) {
// 		case *ConnRes:
// 			// ...
//
// 		case *TunnelReq:
// 			// ...
//
// 		// ...
// 	}
//
func Unpack(data []byte, srv *Service) (uint, error) {
	var headerLen, version uint8
	var srvID ServiceID
	var totalLen uint16

	if len(data) == 0 {
		return 0, nil
	}

	n, err := util.UnpackSome(data, &headerLen, &version, (*uint16)(&srvID), &totalLen)
	if err != nil {
		return n, err
	}

	if headerLen != 6 {
		return n, ErrHeaderLength
	}

	if version != 16 {
		return n, ErrHeaderVersion
	}

	var body serviceUnpackable
	switch srvID {
	case SearchReqService:
		body = &SearchReq{}

	case SearchResService:
		body = &SearchRes{}

	case ConnReqService:
		body = &ConnReq{}

	case ConnResService:
		body = &ConnRes{}

	case ConnStateReqService:
		body = &ConnStateReq{}

	case ConnStateResService:
		body = &ConnStateRes{}

	case DiscReqService:
		body = &DiscReq{}

	case DiscResService:
		body = &DiscRes{}

	case TunnelReqService:
		body = &TunnelReq{}

	case TunnelResService:
		body = &TunnelRes{}

	case RoutingIndService:
		body = &RoutingInd{}

	case RoutingLostService:
		body = &RoutingLost{}

	case RoutingBusyService:
		body = &RoutingBusy{}

	default:
		body = &UnknownService{service: srvID}
	}

	m, err := body.Unpack(data[n:])

	if err == nil {
		*srv = body
	}

	return n + m, err
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"os"
	"os/user"
	"strings"
)

func kobitoPath() (path string, err error) {
	usr, _ := user.Current()
	home := usr.HomeDir

	lookUpPaths := []string{
		home + "/Applications/Kobito.app",
		"/Applications/Kobito.app",
	}

	for _, path = range lookUpPaths {
		println(path)
		if directoryExists(path) {
			return
		}
	}

	err = errors.New("Kobito.app not found in: " + strings.Join(lookUpPaths, ", "))

	return
}

func directoryExists(dir string) bool {
	info, err := os.Stat(dir)
	if err != nil {
		return false
	}
	return info.IsDir()
}
<commit_msg>remove debug code<commit_after>package main

import (
	"errors"
	"os"
	"os/user"
	"strings"
)

func kobitoPath() (path string, err error) {
	usr, _ := user.Current()
	home := usr.HomeDir

	lookUpPaths := []string{
		home + "/Applications/Kobito.app",
		"/Applications/Kobito.app",
	}

	for _, path = range lookUpPaths {
		if directoryExists(path) {
			return
		}
	}

	err = errors.New("Kobito.app not found in: " + strings.Join(lookUpPaths, ", "))

	return
}

func directoryExists(dir string) bool {
	info, err := os.Stat(dir)
	if err != nil {
		return false
	}
	return info.IsDir()
}
<|endoftext|>