<commit_before>// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package caddyhttp

import (
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"net"
	"net/http"
	"net/textproto"
	"path"
	"strconv"
	"strings"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddytls"
)

func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.ResponseWriter) {
	httpVars := func(key string) (interface{}, bool) {
		if req != nil {
			// query string parameters
			if strings.HasPrefix(key, reqURIQueryReplPrefix) {
				vals := req.URL.Query()[key[len(reqURIQueryReplPrefix):]]
				// always return true, since the query param might
				// be present only in some requests
				return strings.Join(vals, ","), true
			}

			// request header fields
			if strings.HasPrefix(key, reqHeaderReplPrefix) {
				field := key[len(reqHeaderReplPrefix):]
				vals := req.Header[textproto.CanonicalMIMEHeaderKey(field)]
				// always return true, since the header field might
				// be present only in some requests
				return strings.Join(vals, ","), true
			}

			// cookies
			if strings.HasPrefix(key, reqCookieReplPrefix) {
				name := key[len(reqCookieReplPrefix):]
				for _, cookie := range req.Cookies() {
					if strings.EqualFold(name, cookie.Name) {
						// always return true, since the cookie might
						// be present only in some requests
						return cookie.Value, true
					}
				}
			}

			// http.request.tls.*
			if strings.HasPrefix(key, reqTLSReplPrefix) {
				return getReqTLSReplacement(req, key)
			}

			switch key {
			case "http.request.method":
				return req.Method, true
			case "http.request.scheme":
				if req.TLS != nil {
					return "https", true
				}
				return "http", true
			case "http.request.proto":
				return req.Proto, true
			case "http.request.host":
				host, _, err := net.SplitHostPort(req.Host)
				if err != nil {
					return req.Host, true // OK; there probably was no port
				}
				return host, true
			case "http.request.port":
				_, port, _ := net.SplitHostPort(req.Host)
				return port, true
			case "http.request.hostport":
				return req.Host, true
			case "http.request.remote":
				return req.RemoteAddr, true
			case "http.request.remote.host":
				host, _, err := net.SplitHostPort(req.RemoteAddr)
				if err != nil {
					return req.RemoteAddr, true
				}
				return host, true
			case "http.request.remote.port":
				_, port, _ := net.SplitHostPort(req.RemoteAddr)
				return port, true

			// current URI, including any internal rewrites
			case "http.request.uri":
				return req.URL.RequestURI(), true
			case "http.request.uri.path":
				return req.URL.Path, true
			case "http.request.uri.path.file":
				_, file := path.Split(req.URL.Path)
				return file, true
			case "http.request.uri.path.dir":
				dir, _ := path.Split(req.URL.Path)
				return dir, true
			case "http.request.uri.query":
				return req.URL.RawQuery, true

				// original request, before any internal changes
			case "http.request.orig_method":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.Method, true
			case "http.request.orig_uri":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.RequestURI, true
			case "http.request.orig_uri.path":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.URL.Path, true
			case "http.request.orig_uri.path.file":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				_, file := path.Split(or.URL.Path)
				return file, true
			case "http.request.orig_uri.path.dir":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				dir, _ := path.Split(or.URL.Path)
				return dir, true
			case "http.request.orig_uri.query":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.URL.RawQuery, true
			}

			// hostname labels
			if strings.HasPrefix(key, reqHostLabelsReplPrefix) {
				idxStr := key[len(reqHostLabelsReplPrefix):]
				idx, err := strconv.Atoi(idxStr)
				if err != nil {
					return "", false
				}
				reqHost, _, err := net.SplitHostPort(req.Host)
				if err != nil {
					reqHost = req.Host // OK; assume there was no port
				}
				hostLabels := strings.Split(reqHost, ".")
				if idx < 0 {
					return "", false
				}
				if idx > len(hostLabels) {
					return "", true
				}
				return hostLabels[len(hostLabels)-idx-1], true
			}

			// path parts
			if strings.HasPrefix(key, reqURIPathReplPrefix) {
				idxStr := key[len(reqURIPathReplPrefix):]
				idx, err := strconv.Atoi(idxStr)
				if err != nil {
					return "", false
				}
				pathParts := strings.Split(req.URL.Path, "/")
				if len(pathParts) > 0 && pathParts[0] == "" {
					pathParts = pathParts[1:]
				}
				if idx < 0 {
					return "", false
				}
				if idx >= len(pathParts) {
					return "", true
				}
				return pathParts[idx], true
			}

			// middleware variables
			if strings.HasPrefix(key, varsReplPrefix) {
				varName := key[len(varsReplPrefix):]
				tbl := req.Context().Value(VarsCtxKey).(map[string]interface{})
				raw, _ := tbl[varName]
				// variables can be dynamic, so always return true
				// even when it may not be set; treat as empty then
				return raw, true
			}
		}

		if w != nil {
			// response header fields
			if strings.HasPrefix(key, respHeaderReplPrefix) {
				field := key[len(respHeaderReplPrefix):]
				vals := w.Header()[textproto.CanonicalMIMEHeaderKey(field)]
				// always return true, since the header field might
				// be present only in some responses
				return strings.Join(vals, ","), true
			}
		}

		return nil, false
	}

	repl.Map(httpVars)
}

func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) {
	if req == nil || req.TLS == nil {
		return nil, false
	}

	if len(key) < len(reqTLSReplPrefix) {
		return nil, false
	}

	field := strings.ToLower(key[len(reqTLSReplPrefix):])

	if strings.HasPrefix(field, "client.") {
		cert := getTLSPeerCert(req.TLS)
		if cert == nil {
			return nil, false
		}

		switch field {
		case "client.fingerprint":
			return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true
		case "client.issuer":
			return cert.Issuer, true
		case "client.serial":
			return cert.SerialNumber, true
		case "client.subject":
			return cert.Subject, true
		default:
			return nil, false
		}
	}

	switch field {
	case "version":
		return caddytls.ProtocolName(req.TLS.Version), true
	case "cipher_suite":
		return tls.CipherSuiteName(req.TLS.CipherSuite), true
	case "resumed":
		return req.TLS.DidResume, true
	case "proto":
		return req.TLS.NegotiatedProtocol, true
	case "proto_mutual":
		return req.TLS.NegotiatedProtocolIsMutual, true
	case "server_name":
		return req.TLS.ServerName, true
	}
	return nil, false
}

// getTLSPeerCert retrieves the first peer certificate from a TLS session.
// Returns nil if no peer cert is in use.
func getTLSPeerCert(cs *tls.ConnectionState) *x509.Certificate {
	if len(cs.PeerCertificates) == 0 {
		return nil
	}
	return cs.PeerCertificates[0]
}

const (
	reqCookieReplPrefix     = "http.request.cookie."
	reqHeaderReplPrefix     = "http.request.header."
	reqHostLabelsReplPrefix = "http.request.host.labels."
	reqTLSReplPrefix        = "http.request.tls."
	reqURIPathReplPrefix    = "http.request.uri.path."
	reqURIQueryReplPrefix   = "http.request.uri.query."
	respHeaderReplPrefix    = "http.response.header."
	varsReplPrefix          = "http.vars."
)
<commit_msg>caddyhttp: Return port placeholders as ints<commit_after>// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package caddyhttp

import (
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"net"
	"net/http"
	"net/textproto"
	"path"
	"strconv"
	"strings"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddytls"
)

func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.ResponseWriter) {
	httpVars := func(key string) (interface{}, bool) {
		if req != nil {
			// query string parameters
			if strings.HasPrefix(key, reqURIQueryReplPrefix) {
				vals := req.URL.Query()[key[len(reqURIQueryReplPrefix):]]
				// always return true, since the query param might
				// be present only in some requests
				return strings.Join(vals, ","), true
			}

			// request header fields
			if strings.HasPrefix(key, reqHeaderReplPrefix) {
				field := key[len(reqHeaderReplPrefix):]
				vals := req.Header[textproto.CanonicalMIMEHeaderKey(field)]
				// always return true, since the header field might
				// be present only in some requests
				return strings.Join(vals, ","), true
			}

			// cookies
			if strings.HasPrefix(key, reqCookieReplPrefix) {
				name := key[len(reqCookieReplPrefix):]
				for _, cookie := range req.Cookies() {
					if strings.EqualFold(name, cookie.Name) {
						// always return true, since the cookie might
						// be present only in some requests
						return cookie.Value, true
					}
				}
			}

			// http.request.tls.*
			if strings.HasPrefix(key, reqTLSReplPrefix) {
				return getReqTLSReplacement(req, key)
			}

			switch key {
			case "http.request.method":
				return req.Method, true
			case "http.request.scheme":
				if req.TLS != nil {
					return "https", true
				}
				return "http", true
			case "http.request.proto":
				return req.Proto, true
			case "http.request.host":
				host, _, err := net.SplitHostPort(req.Host)
				if err != nil {
					return req.Host, true // OK; there probably was no port
				}
				return host, true
			case "http.request.port":
				_, port, _ := net.SplitHostPort(req.Host)
				if portNum, err := strconv.Atoi(port); err == nil {
					return portNum, true
				}
				return port, true
			case "http.request.hostport":
				return req.Host, true
			case "http.request.remote":
				return req.RemoteAddr, true
			case "http.request.remote.host":
				host, _, err := net.SplitHostPort(req.RemoteAddr)
				if err != nil {
					return req.RemoteAddr, true
				}
				return host, true
			case "http.request.remote.port":
				_, port, _ := net.SplitHostPort(req.RemoteAddr)
				if portNum, err := strconv.Atoi(port); err == nil {
					return portNum, true
				}
				return port, true

			// current URI, including any internal rewrites
			case "http.request.uri":
				return req.URL.RequestURI(), true
			case "http.request.uri.path":
				return req.URL.Path, true
			case "http.request.uri.path.file":
				_, file := path.Split(req.URL.Path)
				return file, true
			case "http.request.uri.path.dir":
				dir, _ := path.Split(req.URL.Path)
				return dir, true
			case "http.request.uri.query":
				return req.URL.RawQuery, true

				// original request, before any internal changes
			case "http.request.orig_method":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.Method, true
			case "http.request.orig_uri":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.RequestURI, true
			case "http.request.orig_uri.path":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.URL.Path, true
			case "http.request.orig_uri.path.file":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				_, file := path.Split(or.URL.Path)
				return file, true
			case "http.request.orig_uri.path.dir":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				dir, _ := path.Split(or.URL.Path)
				return dir, true
			case "http.request.orig_uri.query":
				or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)
				return or.URL.RawQuery, true
			}

			// hostname labels
			if strings.HasPrefix(key, reqHostLabelsReplPrefix) {
				idxStr := key[len(reqHostLabelsReplPrefix):]
				idx, err := strconv.Atoi(idxStr)
				if err != nil {
					return "", false
				}
				reqHost, _, err := net.SplitHostPort(req.Host)
				if err != nil {
					reqHost = req.Host // OK; assume there was no port
				}
				hostLabels := strings.Split(reqHost, ".")
				if idx < 0 {
					return "", false
				}
				if idx > len(hostLabels) {
					return "", true
				}
				return hostLabels[len(hostLabels)-idx-1], true
			}

			// path parts
			if strings.HasPrefix(key, reqURIPathReplPrefix) {
				idxStr := key[len(reqURIPathReplPrefix):]
				idx, err := strconv.Atoi(idxStr)
				if err != nil {
					return "", false
				}
				pathParts := strings.Split(req.URL.Path, "/")
				if len(pathParts) > 0 && pathParts[0] == "" {
					pathParts = pathParts[1:]
				}
				if idx < 0 {
					return "", false
				}
				if idx >= len(pathParts) {
					return "", true
				}
				return pathParts[idx], true
			}

			// middleware variables
			if strings.HasPrefix(key, varsReplPrefix) {
				varName := key[len(varsReplPrefix):]
				tbl := req.Context().Value(VarsCtxKey).(map[string]interface{})
				raw, _ := tbl[varName]
				// variables can be dynamic, so always return true
				// even when it may not be set; treat as empty then
				return raw, true
			}
		}

		if w != nil {
			// response header fields
			if strings.HasPrefix(key, respHeaderReplPrefix) {
				field := key[len(respHeaderReplPrefix):]
				vals := w.Header()[textproto.CanonicalMIMEHeaderKey(field)]
				// always return true, since the header field might
				// be present only in some responses
				return strings.Join(vals, ","), true
			}
		}

		return nil, false
	}

	repl.Map(httpVars)
}

func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) {
	if req == nil || req.TLS == nil {
		return nil, false
	}

	if len(key) < len(reqTLSReplPrefix) {
		return nil, false
	}

	field := strings.ToLower(key[len(reqTLSReplPrefix):])

	if strings.HasPrefix(field, "client.") {
		cert := getTLSPeerCert(req.TLS)
		if cert == nil {
			return nil, false
		}

		switch field {
		case "client.fingerprint":
			return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true
		case "client.issuer":
			return cert.Issuer, true
		case "client.serial":
			return cert.SerialNumber, true
		case "client.subject":
			return cert.Subject, true
		default:
			return nil, false
		}
	}

	switch field {
	case "version":
		return caddytls.ProtocolName(req.TLS.Version), true
	case "cipher_suite":
		return tls.CipherSuiteName(req.TLS.CipherSuite), true
	case "resumed":
		return req.TLS.DidResume, true
	case "proto":
		return req.TLS.NegotiatedProtocol, true
	case "proto_mutual":
		return req.TLS.NegotiatedProtocolIsMutual, true
	case "server_name":
		return req.TLS.ServerName, true
	}
	return nil, false
}

// getTLSPeerCert retrieves the first peer certificate from a TLS session.
// Returns nil if no peer cert is in use.
func getTLSPeerCert(cs *tls.ConnectionState) *x509.Certificate {
	if len(cs.PeerCertificates) == 0 {
		return nil
	}
	return cs.PeerCertificates[0]
}

const (
	reqCookieReplPrefix     = "http.request.cookie."
	reqHeaderReplPrefix     = "http.request.header."
	reqHostLabelsReplPrefix = "http.request.host.labels."
	reqTLSReplPrefix        = "http.request.tls."
	reqURIPathReplPrefix    = "http.request.uri.path."
	reqURIQueryReplPrefix   = "http.request.uri.query."
	respHeaderReplPrefix    = "http.response.header."
	varsReplPrefix          = "http.vars."
)
<|endoftext|>


<commit_before>package main

import (
	"github.com/coreos/go-etcd/etcd"
	"log"
	"testing"
)

func TestSarpa(t *testing.T) {
	// Setup
	client := etcd.NewClient([]string{"http://127.0.0.1:4001"})
	client.CreateDir("/sarpa", 200)

	client.CreateDir("/sarpa/blah", 200)
	client.Create("/sarpa/blah/asd", "1", 200)
	client.Create("/sarpa/blah/meh", "2", 200)

	client.CreateDir("/sarpa/hay", 200)
	client.AddChild("/sarpa/hay", "4", 200)
	client.AddChild("/sarpa/hay", "5", 200)
	client.AddChild("/sarpa/hay", "6", 200)

	config := &Config{}
	config.EtcdConnect([]string{"http://127.0.0.1:4001"})
	config.AwsConnect()

	config.GetServices()

	if len(config.Services["blah"]) != 2 {
		t.Error("blah doesn't have enough nodes")
	}

	if len(config.Services["hay"]) != 3 {
		t.Error("hay doesn't have enough nodes")
	}

	log.Println(string(config.jsonedServices()))

	// Clean up
	client.Delete("/sarpa", true)
}
<commit_msg>Fixed up the tests<commit_after>package main

import (
	"github.com/coreos/go-etcd/etcd"
	"log"
	"testing"
)

var (
	client *etcd.Client
)

func SetupEtcd() {
	// Setup
	client = etcd.NewClient([]string{"http://127.0.0.1:4001"})
	client.CreateDir("/sarpa", 200)

	client.CreateDir("/sarpa/blah", 200)
	client.Create("/sarpa/blah/asd", "1", 200)
	client.Create("/sarpa/blah/meh", "2", 200)

	client.CreateDir("/sarpa/hay", 200)
	client.AddChild("/sarpa/hay", "4", 200)
	client.AddChild("/sarpa/hay", "5", 200)
	client.AddChild("/sarpa/hay", "6", 200)
}

func CleanUpEtcd() {
	// Clean up
	client.Delete("/sarpa", true)
}

func TestSarpa(t *testing.T) {
	SetupEtcd()

	config := &Config{}
	config.EtcdConnect([]string{"http://127.0.0.1:4001"})
	config.AwsConnect()

	config.GetServices()

	if len(config.Services["blah"]) != 2 {
		t.Error("blah doesn't have enough nodes")
	}

	if len(config.Services["hay"]) != 3 {
		t.Error("hay doesn't have enough nodes")
	}

	log.Println(string(config.jsonedServices()))

	CleanUpEtcd()
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Workiva, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package queue

import (
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestPut(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	assert.Equal(t, int64(1), q.Len())

	results, err := q.Get(1)
	assert.Nil(t, err)

	result := results[0]
	assert.Equal(t, `test`, result)
	assert.True(t, q.Empty())

	q.Put(`test2`)
	assert.Equal(t, int64(1), q.Len())

	results, err = q.Get(1)
	assert.Nil(t, err)

	result = results[0]
	assert.Equal(t, `test2`, result)
	assert.True(t, q.Empty())
}

func TestGet(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	result, err := q.Get(2)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `test`, result[0])
	assert.Equal(t, int64(0), q.Len())

	q.Put(`1`)
	q.Put(`2`)

	result, err = q.Get(1)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `1`, result[0])
	assert.Equal(t, int64(1), q.Len())

	result, err = q.Get(2)
	if !assert.Nil(t, err) {
		return
	}

	assert.Equal(t, `2`, result[0])
}

func TestPoll(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	result, err := q.Poll(2, 0)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `test`, result[0])
	assert.Equal(t, int64(0), q.Len())

	q.Put(`1`)
	q.Put(`2`)

	result, err = q.Poll(1, time.Millisecond)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `1`, result[0])
	assert.Equal(t, int64(1), q.Len())

	result, err = q.Poll(2, time.Millisecond)
	if !assert.Nil(t, err) {
		return
	}

	assert.Equal(t, `2`, result[0])

	before := time.Now()
	_, err = q.Poll(1, 5*time.Millisecond)
	assert.InDelta(t, 5, time.Since(before).Seconds()*1000, 2)
	assert.Equal(t, ErrTimeout, err)
}

func TestAddEmptyPut(t *testing.T) {
	q := New(10)

	q.Put()

	if q.Len() != 0 {
		t.Errorf(`Expected len: %d, received: %d`, 0, q.Len())
	}
}

func TestGetNonPositiveNumber(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	result, err := q.Get(0)
	if !assert.Nil(t, err) {
		return
	}

	if len(result) != 0 {
		t.Errorf(`Expected len: %d, received: %d`, 0, len(result))
	}
}

func TestEmpty(t *testing.T) {
	q := New(10)

	if !q.Empty() {
		t.Errorf(`Expected empty queue.`)
	}

	q.Put(`test`)
	if q.Empty() {
		t.Errorf(`Expected non-empty queue.`)
	}
}

func TestGetEmpty(t *testing.T) {
	q := New(10)

	go func() {
		q.Put(`a`)
	}()

	result, err := q.Get(2)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `a`, result[0])
}

func TestMultipleGetEmpty(t *testing.T) {
	q := New(10)
	var wg sync.WaitGroup
	wg.Add(2)
	results := make([][]interface{}, 2)

	go func() {
		wg.Done()
		local, err := q.Get(1)
		assert.Nil(t, err)
		results[0] = local
		wg.Done()
	}()

	go func() {
		wg.Done()
		local, err := q.Get(1)
		assert.Nil(t, err)
		results[1] = local
		wg.Done()
	}()

	wg.Wait()
	wg.Add(2)

	q.Put(`a`, `b`, `c`)
	wg.Wait()

	if assert.Len(t, results[0], 1) && assert.Len(t, results[1], 1) {
		assert.True(t, (results[0][0] == `a` && results[1][0] == `b`) ||
			(results[0][0] == `b` && results[1][0] == `a`),
			`The array should be a, b or b, a`)
	}
}

func TestEmptyGetWithDispose(t *testing.T) {
	q := New(10)
	var wg sync.WaitGroup
	wg.Add(1)

	var err error

	go func() {
		wg.Done()
		_, err = q.Get(1)
		wg.Done()
	}()

	wg.Wait()
	wg.Add(1)

	q.Dispose()

	wg.Wait()

	assert.IsType(t, ErrDisposed, err)
}

func TestGetPutDisposed(t *testing.T) {
	q := New(10)

	q.Dispose()

	_, err := q.Get(1)
	assert.IsType(t, ErrDisposed, err)

	err = q.Put(`a`)
	assert.IsType(t, ErrDisposed, err)
}

func BenchmarkQueue(b *testing.B) {
	q := New(int64(b.N))
	var wg sync.WaitGroup
	wg.Add(1)
	i := 0

	go func() {
		for {
			q.Get(1)
			i++
			if i == b.N {
				wg.Done()
				break
			}
		}
	}()

	for i := 0; i < b.N; i++ {
		q.Put(`a`)
	}

	wg.Wait()
}

func BenchmarkChannel(b *testing.B) {
	ch := make(chan interface{}, 1)
	var wg sync.WaitGroup
	wg.Add(1)
	i := 0

	go func() {
		for {
			<-ch
			i++
			if i == b.N {
				wg.Done()
				break
			}
		}
	}()

	for i := 0; i < b.N; i++ {
		ch <- `a`
	}

	wg.Wait()
}

func TestTakeUntil(t *testing.T) {
	q := New(10)
	q.Put(`a`, `b`, `c`)
	result, err := q.TakeUntil(func(item interface{}) bool {
		return item != `c`
	})

	if !assert.Nil(t, err) {
		return
	}

	expected := []interface{}{`a`, `b`}
	assert.Equal(t, expected, result)
}

func TestTakeUntilEmptyQueue(t *testing.T) {
	q := New(10)
	result, err := q.TakeUntil(func(item interface{}) bool {
		return item != `c`
	})

	if !assert.Nil(t, err) {
		return
	}

	expected := []interface{}{}
	assert.Equal(t, expected, result)
}

func TestTakeUntilOnDisposedQueue(t *testing.T) {
	q := New(10)
	q.Dispose()
	result, err := q.TakeUntil(func(item interface{}) bool {
		return true
	})

	assert.Nil(t, result)
	assert.IsType(t, ErrDisposed, err)
}

func TestExecuteInParallel(t *testing.T) {
	q := New(10)
	for i := 0; i < 10; i++ {
		q.Put(i)
	}

	numCalls := uint64(0)

	ExecuteInParallel(q, func(item interface{}) {
		t.Logf("ExecuteInParallel called us with %+v", item)
		atomic.AddUint64(&numCalls, 1)
	})

	assert.Equal(t, uint64(10), numCalls)
	assert.True(t, q.Disposed())
}

func TestExecuteInParallelEmptyQueue(t *testing.T) {
	q := New(1)

	// basically just ensuring we don't deadlock here
	ExecuteInParallel(q, func(interface{}) {
		t.Fail()
	})
}

func BenchmarkQueuePut(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(10)
		qs = append(qs, q)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q := qs[i]
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
	}
}

func BenchmarkQueueGet(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(numItems)
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
		qs = append(qs, q)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		q := qs[i]
		for j := int64(0); j < numItems; j++ {
			q.Get(1)
		}
	}
}

func BenchmarkExecuteInParallel(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(numItems)
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
		qs = append(qs, q)
	}

	var counter int64
	fn := func(ifc interface{}) {
		c := ifc.(int64)
		atomic.AddInt64(&counter, c)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		q := qs[i]
		ExecuteInParallel(q, fn)
	}
}
<commit_msg>Add benchmark for Poll<commit_after>/*
Copyright 2014 Workiva, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package queue

import (
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestPut(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	assert.Equal(t, int64(1), q.Len())

	results, err := q.Get(1)
	assert.Nil(t, err)

	result := results[0]
	assert.Equal(t, `test`, result)
	assert.True(t, q.Empty())

	q.Put(`test2`)
	assert.Equal(t, int64(1), q.Len())

	results, err = q.Get(1)
	assert.Nil(t, err)

	result = results[0]
	assert.Equal(t, `test2`, result)
	assert.True(t, q.Empty())
}

func TestGet(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	result, err := q.Get(2)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `test`, result[0])
	assert.Equal(t, int64(0), q.Len())

	q.Put(`1`)
	q.Put(`2`)

	result, err = q.Get(1)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `1`, result[0])
	assert.Equal(t, int64(1), q.Len())

	result, err = q.Get(2)
	if !assert.Nil(t, err) {
		return
	}

	assert.Equal(t, `2`, result[0])
}

func TestPoll(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	result, err := q.Poll(2, 0)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `test`, result[0])
	assert.Equal(t, int64(0), q.Len())

	q.Put(`1`)
	q.Put(`2`)

	result, err = q.Poll(1, time.Millisecond)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `1`, result[0])
	assert.Equal(t, int64(1), q.Len())

	result, err = q.Poll(2, time.Millisecond)
	if !assert.Nil(t, err) {
		return
	}

	assert.Equal(t, `2`, result[0])

	before := time.Now()
	_, err = q.Poll(1, 5*time.Millisecond)
	assert.InDelta(t, 5, time.Since(before).Seconds()*1000, 2)
	assert.Equal(t, ErrTimeout, err)
}

func TestAddEmptyPut(t *testing.T) {
	q := New(10)

	q.Put()

	if q.Len() != 0 {
		t.Errorf(`Expected len: %d, received: %d`, 0, q.Len())
	}
}

func TestGetNonPositiveNumber(t *testing.T) {
	q := New(10)

	q.Put(`test`)
	result, err := q.Get(0)
	if !assert.Nil(t, err) {
		return
	}

	if len(result) != 0 {
		t.Errorf(`Expected len: %d, received: %d`, 0, len(result))
	}
}

func TestEmpty(t *testing.T) {
	q := New(10)

	if !q.Empty() {
		t.Errorf(`Expected empty queue.`)
	}

	q.Put(`test`)
	if q.Empty() {
		t.Errorf(`Expected non-empty queue.`)
	}
}

func TestGetEmpty(t *testing.T) {
	q := New(10)

	go func() {
		q.Put(`a`)
	}()

	result, err := q.Get(2)
	if !assert.Nil(t, err) {
		return
	}

	assert.Len(t, result, 1)
	assert.Equal(t, `a`, result[0])
}

func TestMultipleGetEmpty(t *testing.T) {
	q := New(10)
	var wg sync.WaitGroup
	wg.Add(2)
	results := make([][]interface{}, 2)

	go func() {
		wg.Done()
		local, err := q.Get(1)
		assert.Nil(t, err)
		results[0] = local
		wg.Done()
	}()

	go func() {
		wg.Done()
		local, err := q.Get(1)
		assert.Nil(t, err)
		results[1] = local
		wg.Done()
	}()

	wg.Wait()
	wg.Add(2)

	q.Put(`a`, `b`, `c`)
	wg.Wait()

	if assert.Len(t, results[0], 1) && assert.Len(t, results[1], 1) {
		assert.True(t, (results[0][0] == `a` && results[1][0] == `b`) ||
			(results[0][0] == `b` && results[1][0] == `a`),
			`The array should be a, b or b, a`)
	}
}

func TestEmptyGetWithDispose(t *testing.T) {
	q := New(10)
	var wg sync.WaitGroup
	wg.Add(1)

	var err error

	go func() {
		wg.Done()
		_, err = q.Get(1)
		wg.Done()
	}()

	wg.Wait()
	wg.Add(1)

	q.Dispose()

	wg.Wait()

	assert.IsType(t, ErrDisposed, err)
}

func TestGetPutDisposed(t *testing.T) {
	q := New(10)

	q.Dispose()

	_, err := q.Get(1)
	assert.IsType(t, ErrDisposed, err)

	err = q.Put(`a`)
	assert.IsType(t, ErrDisposed, err)
}

func BenchmarkQueue(b *testing.B) {
	q := New(int64(b.N))
	var wg sync.WaitGroup
	wg.Add(1)
	i := 0

	go func() {
		for {
			q.Get(1)
			i++
			if i == b.N {
				wg.Done()
				break
			}
		}
	}()

	for i := 0; i < b.N; i++ {
		q.Put(`a`)
	}

	wg.Wait()
}

func BenchmarkChannel(b *testing.B) {
	ch := make(chan interface{}, 1)
	var wg sync.WaitGroup
	wg.Add(1)
	i := 0

	go func() {
		for {
			<-ch
			i++
			if i == b.N {
				wg.Done()
				break
			}
		}
	}()

	for i := 0; i < b.N; i++ {
		ch <- `a`
	}

	wg.Wait()
}

func TestTakeUntil(t *testing.T) {
	q := New(10)
	q.Put(`a`, `b`, `c`)
	result, err := q.TakeUntil(func(item interface{}) bool {
		return item != `c`
	})

	if !assert.Nil(t, err) {
		return
	}

	expected := []interface{}{`a`, `b`}
	assert.Equal(t, expected, result)
}

func TestTakeUntilEmptyQueue(t *testing.T) {
	q := New(10)
	result, err := q.TakeUntil(func(item interface{}) bool {
		return item != `c`
	})

	if !assert.Nil(t, err) {
		return
	}

	expected := []interface{}{}
	assert.Equal(t, expected, result)
}

func TestTakeUntilOnDisposedQueue(t *testing.T) {
	q := New(10)
	q.Dispose()
	result, err := q.TakeUntil(func(item interface{}) bool {
		return true
	})

	assert.Nil(t, result)
	assert.IsType(t, ErrDisposed, err)
}

func TestExecuteInParallel(t *testing.T) {
	q := New(10)
	for i := 0; i < 10; i++ {
		q.Put(i)
	}

	numCalls := uint64(0)

	ExecuteInParallel(q, func(item interface{}) {
		t.Logf("ExecuteInParallel called us with %+v", item)
		atomic.AddUint64(&numCalls, 1)
	})

	assert.Equal(t, uint64(10), numCalls)
	assert.True(t, q.Disposed())
}

func TestExecuteInParallelEmptyQueue(t *testing.T) {
	q := New(1)

	// basically just ensuring we don't deadlock here
	ExecuteInParallel(q, func(interface{}) {
		t.Fail()
	})
}

func BenchmarkQueuePut(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(10)
		qs = append(qs, q)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q := qs[i]
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
	}
}

func BenchmarkQueueGet(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(numItems)
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
		qs = append(qs, q)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		q := qs[i]
		for j := int64(0); j < numItems; j++ {
			q.Get(1)
		}
	}
}

func BenchmarkQueuePoll(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(numItems)
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
		qs = append(qs, q)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		q := qs[i]
		for j := int64(0); j < numItems; j++ {
			q.Poll(1, time.Millisecond)
		}
	}
}

func BenchmarkExecuteInParallel(b *testing.B) {
	numItems := int64(1000)

	qs := make([]*Queue, 0, b.N)

	for i := 0; i < b.N; i++ {
		q := New(numItems)
		for j := int64(0); j < numItems; j++ {
			q.Put(j)
		}
		qs = append(qs, q)
	}

	var counter int64
	fn := func(ifc interface{}) {
		c := ifc.(int64)
		atomic.AddInt64(&counter, c)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		q := qs[i]
		ExecuteInParallel(q, fn)
	}
}
<|endoftext|>


<commit_before>package crawler

import (
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"log"
	"strings"
)

func failIfNeeded(e error) {
	if e != nil {
		log.Fatalln(e)
	}
}

func printResults(ts []anaconda.Tweet) {
	for _, t := range ts {
		printResult(t)
	}
}

func printResult(t anaconda.Tweet) {
	fmt.Println("InReplyToStatusID: ", t.InReplyToStatusID)
	p := Parser{}
	ns := p.ParseToNouns([]string{t.Text})
	wc := wordCount(ns)
	for noun, count := range wc {
		fmt.Println(count, noun)
	}
}

func wordCount(ss []string) map[string]int {
	res := make(map[string]int)
	for _, str := range ss {
		res[strings.ToLower(str)]++
	}
	return res
}

func containsString(ss[] string, target string) bool {
	for _, s := range ss {
		if s == target {
			return true
		}
	}
	return false
}
func containsNearlyString(ss[] string, target string) bool {
	for _, s := range ss {
		if strings.Contains(target, s) {
			return true
		}
	}
	return false
}

func OutputAniversarries(aniversaries []Anniversary) {
	log.Println("============SUMMARY============")
	log.Println("aniversary count: ", len(aniversaries))
	for _, aniv := range aniversaries {
		first := aniv.CreateFirstMessage()
		second, _ := aniv.CreateSecondMessage()
		log.Println("message: ", aniv.CreateFullMessage(first, second))
	}
}
<commit_msg>エラー隠蔽方針にした<commit_after>package crawler

import (
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"log"
	"strings"
)

func failIfNeeded(e error) {
	if e != nil {
		log.Fatalln(e)
	}
}

func printResults(ts []anaconda.Tweet) {
	for _, t := range ts {
		printResult(t)
	}
}

func printResult(t anaconda.Tweet) {
	fmt.Println("InReplyToStatusID: ", t.InReplyToStatusID)
	p := Parser{}
	ns := p.ParseToNouns([]string{t.Text})
	wc := wordCount(ns)
	for noun, count := range wc {
		fmt.Println(count, noun)
	}
}

func wordCount(ss []string) map[string]int {
	res := make(map[string]int)
	for _, str := range ss {
		res[strings.ToLower(str)]++
	}
	return res
}

func containsString(ss []string, target string) bool {
	for _, s := range ss {
		if s == target {
			return true
		}
	}
	return false
}
func containsNearlyString(ss []string, target string) bool {
	for _, s := range ss {
		if strings.Contains(target, s) {
			return true
		}
	}
	return false
}

func OutputAniversarries(aniversaries []Anniversary) {
	log.Println("============SUMMARY============")
	log.Println("aniversary count: ", len(aniversaries))
	for _, aniv := range aniversaries {
		first := aniv.CreateFirstMessage()
		second, _ := aniv.CreateSecondMessage()
		log.Println("message: ", aniv.CreateFullMessage(first, second))
	}
}
<|endoftext|>


<commit_before>package trackinglog

import (
	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"encoding/json"
	"code.google.com/p/go-uuid/uuid"
	"github.com/knightso/base/errors"
	"github.com/knightso/base/gae/ds"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"net/http"
)

const KIND_USER_AGENT = "UserAgent"
const KIND_TRACKING_LOG = "TrackingLog"

func init() {
	http.Handle("/", goji.DefaultMux)
	goji.Get("/tracking/*", saveTracking)
	goji.Get("/api/useragents", queryUserAgents)
	goji.Get("/api/useragents/:key", getUserAgent)
	goji.Get("/api/useragents/:key/trackinglogs", queryTrackingLogs)
}

type UserAgent struct {
	UserAgent string `json:"userAgent"`
	ds.Meta
}

type JsonUserAgent struct {
	*UserAgent
	Key *datastore.Key `json:"key"`
}

func NewUserAgentKey(c appengine.Context, ua string) *datastore.Key {
	return datastore.NewKey(c, KIND_USER_AGENT, ua, 0, nil)
}

type TrackingLog struct {
	UserAgent string `json:"userAgent"`
	URL       string `json:"url"`
	ds.Meta
}

func NewTrackingLogKey(c appengine.Context, uuid string) *datastore.Key {
	return datastore.NewKey(c, KIND_TRACKING_LOG, uuid, 0, nil)
}

func saveTracking(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	var t TrackingLog
	t.Key = NewTrackingLogKey(c, uuid.New())
	t.UserAgent = r.UserAgent()
	t.URL = r.URL.String()

	DoSaveTracking.Call(c, &t)
}

var DoSaveTracking = delay.Func("DoSaveTracking", func(c appengine.Context, t *TrackingLog) error {

	err := datastore.RunInTransaction(c, func(c appengine.Context) error {

		uaKey := NewUserAgentKey(c, t.UserAgent)

		var ua UserAgent
		if err := ds.Get(c, uaKey, &ua); err != nil {
			if errors.Root(err) == datastore.ErrNoSuchEntity {
				ua.Key = uaKey
				ua.UserAgent = t.UserAgent
			} else {
				return errors.WrapOr(err)
			}
		}
		if err := ds.Put(c, &ua); err != nil {
			return errors.WrapOr(err)
		}

		if err := ds.Put(c, t); err != nil {
			return errors.WrapOr(err)
		}

		return nil
	}, &datastore.TransactionOptions{XG: true})
	if err != nil {
		return errors.WrapOr(err)
	}
	return nil
})

func getUserAgent(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	uaKey, err := datastore.DecodeKey(gojic.URLParams["key"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var ua UserAgent
	if err := ds.Get(c, uaKey, &ua); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	jua := JsonUserAgent {
		UserAgent: &ua,
		Key: ua.Key,
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	jsn, err := json.MarshalIndent(jua, "", "\t")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(jsn); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func queryUserAgents(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	q := datastore.NewQuery(KIND_USER_AGENT).Order("-UpdatedAt")

	var uas []*UserAgent
	if err := ds.ExecuteQuery(c, q, &uas); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	juas := make([]*JsonUserAgent, len(uas))
	for i, ua := range uas {
		jua := JsonUserAgent{
			UserAgent: ua,
			Key: ua.Key,
		}
		juas[i] = &jua
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	jsn, err := json.MarshalIndent(juas, "", "\t")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(jsn); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func queryTrackingLogs(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	uaKey, err := datastore.DecodeKey(gojic.URLParams["key"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var ua UserAgent
	if err := ds.Get(c, uaKey, &ua); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	q := datastore.NewQuery(KIND_TRACKING_LOG).Filter("UserAgent =", ua.UserAgent).Order("-CreatedAt")

	var logs []*TrackingLog
	if err := ds.ExecuteQuery(c, q, &logs); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	jsn, err := json.MarshalIndent(logs, "", "\t")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(jsn); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
<commit_msg>added limit 500 to query log.<commit_after>package trackinglog

import (
	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"encoding/json"
	"code.google.com/p/go-uuid/uuid"
	"github.com/knightso/base/errors"
	"github.com/knightso/base/gae/ds"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"net/http"
)

const KIND_USER_AGENT = "UserAgent"
const KIND_TRACKING_LOG = "TrackingLog"

func init() {
	http.Handle("/", goji.DefaultMux)
	goji.Get("/tracking/*", saveTracking)
	goji.Get("/api/useragents", queryUserAgents)
	goji.Get("/api/useragents/:key", getUserAgent)
	goji.Get("/api/useragents/:key/trackinglogs", queryTrackingLogs)
}

type UserAgent struct {
	UserAgent string `json:"userAgent"`
	ds.Meta
}

type JsonUserAgent struct {
	*UserAgent
	Key *datastore.Key `json:"key"`
}

func NewUserAgentKey(c appengine.Context, ua string) *datastore.Key {
	return datastore.NewKey(c, KIND_USER_AGENT, ua, 0, nil)
}

type TrackingLog struct {
	UserAgent string `json:"userAgent"`
	URL       string `json:"url"`
	ds.Meta
}

func NewTrackingLogKey(c appengine.Context, uuid string) *datastore.Key {
	return datastore.NewKey(c, KIND_TRACKING_LOG, uuid, 0, nil)
}

func saveTracking(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	var t TrackingLog
	t.Key = NewTrackingLogKey(c, uuid.New())
	t.UserAgent = r.UserAgent()
	t.URL = r.URL.String()

	DoSaveTracking.Call(c, &t)
}

var DoSaveTracking = delay.Func("DoSaveTracking", func(c appengine.Context, t *TrackingLog) error {

	err := datastore.RunInTransaction(c, func(c appengine.Context) error {

		uaKey := NewUserAgentKey(c, t.UserAgent)

		var ua UserAgent
		if err := ds.Get(c, uaKey, &ua); err != nil {
			if errors.Root(err) == datastore.ErrNoSuchEntity {
				ua.Key = uaKey
				ua.UserAgent = t.UserAgent
			} else {
				return errors.WrapOr(err)
			}
		}
		if err := ds.Put(c, &ua); err != nil {
			return errors.WrapOr(err)
		}

		if err := ds.Put(c, t); err != nil {
			return errors.WrapOr(err)
		}

		return nil
	}, &datastore.TransactionOptions{XG: true})
	if err != nil {
		return errors.WrapOr(err)
	}
	return nil
})

func getUserAgent(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	uaKey, err := datastore.DecodeKey(gojic.URLParams["key"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var ua UserAgent
	if err := ds.Get(c, uaKey, &ua); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	jua := JsonUserAgent {
		UserAgent: &ua,
		Key: ua.Key,
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	jsn, err := json.MarshalIndent(jua, "", "\t")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(jsn); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func queryUserAgents(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	q := datastore.NewQuery(KIND_USER_AGENT).Order("-UpdatedAt")

	var uas []*UserAgent
	if err := ds.ExecuteQuery(c, q, &uas); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	juas := make([]*JsonUserAgent, len(uas))
	for i, ua := range uas {
		jua := JsonUserAgent{
			UserAgent: ua,
			Key: ua.Key,
		}
		juas[i] = &jua
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	jsn, err := json.MarshalIndent(juas, "", "\t")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(jsn); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func queryTrackingLogs(gojic web.C, w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	uaKey, err := datastore.DecodeKey(gojic.URLParams["key"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var ua UserAgent
	if err := ds.Get(c, uaKey, &ua); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	q := datastore.NewQuery(KIND_TRACKING_LOG).Filter("UserAgent =", ua.UserAgent).Order("-CreatedAt").Limit(500)

	var logs []*TrackingLog
	if err := ds.ExecuteQuery(c, q, &logs); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	jsn, err := json.MarshalIndent(logs, "", "\t")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, err := w.Write(jsn); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package ufop

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/qiniu/api/auth/digest"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

var (
	ufopPrefix  string
	jobHandlers map[string]UfopJobHandler
	unzipper    *UnZipper
	mkzipper    *Mkziper
	amerger     *AudioMerger
)

type UfopJobHandler interface {
	Do(ufopReq UfopRequest) (interface{}, string, error)
}

type UfopServer struct {
	cfg *UfopConfig
}

func NewServer(cfg *UfopConfig) *UfopServer {
	serv := UfopServer{}
	serv.cfg = cfg
	return &serv
}

func (this *UfopServer) registerJobHandlers() {
	mac := digest.Mac{
		AccessKey: this.cfg.AccessKey,
		SecretKey: []byte(this.cfg.SecretKey),
	}
	jobHandlers = make(map[string]UfopJobHandler, 0)
	ufopPrefix = this.cfg.UfopPrefix
	//unzipper
	unzipper = &UnZipper{
		mac:              &mac,
		maxZipFileLength: this.cfg.UnzipMaxZipFileLength,
		maxFileLength:    this.cfg.UnzipMaxFileLength,
		maxFileCount:     this.cfg.UnzipMaxFileCount,
	}
	//mkzipper
	mkzipper = &Mkziper{
		mac:           &mac,
		maxFileLength: this.cfg.MkzipMaxFileLength,
		maxFileCount:  this.cfg.MkzipMaxFileCount,
	}
	//audio merger
	amerger = &AudioMerger{
		mac:                 &mac,
		maxFirstFileLength:  this.cfg.AmergeMaxFirstFileLength,
		maxSecondFileLength: this.cfg.AmergeMaxSecondFileLength,
	}

	jobHandlers[ufopPrefix+"unzip"] = unzipper
	jobHandlers[ufopPrefix+"mkzip"] = mkzipper
	jobHandlers[ufopPrefix+"amerge"] = amerger
}

func (this *UfopServer) Listen() {
	//register
	this.registerJobHandlers()

	//define handler
	http.HandleFunc("/uop", serveUfop)

	//bind and listen
	endPoint := fmt.Sprintf("%s:%d", this.cfg.ListenHost, this.cfg.ListenPort)
	ufopServer := &http.Server{
		Addr:           endPoint,
		ReadTimeout:    time.Duration(this.cfg.ReadTimeout) * time.Second,
		WriteTimeout:   time.Duration(this.cfg.WriteTimeout) * time.Second,
		MaxHeaderBytes: this.cfg.MaxHeaderBytes,
	}

	listenErr := ufopServer.ListenAndServe()
	if listenErr != nil {
		log.Println(listenErr)
	}
}

func serveUfop(w http.ResponseWriter, req *http.Request) {
	//check method
	if req.Method != "POST" {
		writeJsonError(w, 405, "method not allowed")
		return
	}

	defer req.Body.Close()
	var err error
	var ufopReq UfopRequest
	var ufopResult interface{}
	var ufopResultContentType string

	ufopReqData, err := ioutil.ReadAll(req.Body)
	if err != nil {
		writeJsonError(w, 500, "read ufop request body error")
		return
	}

	err = json.Unmarshal(ufopReqData, &ufopReq)
	if err != nil {
		writeJsonError(w, 500, "parse ufop request body error")
		return
	}

	ufopResult, ufopResultContentType, err = handleJob(ufopReq)
	if err != nil {
		ufopErr := UfopError{
			Request: ufopReq,
			Error:   err.Error(),
		}
		logBytes, _ := json.Marshal(&ufopErr)
		log.Println(string(logBytes))
		writeJsonError(w, 400, err.Error())
	} else {
		switch ufopResultContentType {
		case "application/json":
			writeJsonResult(w, 200, ufopResult)
		default:
			writeOctetResultWithMime(w, 200, ufopResult, ufopResultContentType)
		}
	}
}

func handleJob(ufopReq UfopRequest) (interface{}, string, error) {
	var ufopResult interface{}
	var contentType string
	var err error
	cmd := ufopReq.Cmd

	items := strings.SplitN(cmd, "/", 2)
	fop := items[0]
	if jobHandler, ok := jobHandlers[fop]; ok {
		ufopReq.Cmd = strings.TrimPrefix(ufopReq.Cmd, ufopPrefix)
		ufopResult, contentType, err = jobHandler.Do(ufopReq)
	} else {
		err = errors.New("no fop available for the request")
	}
	return ufopResult, contentType, err
}

func writeJsonError(w http.ResponseWriter, statusCode int, message string) {
	w.WriteHeader(statusCode)
	if w.Header().Get("Content-Type") != "" {
		w.Header().Set("Content-Type", "application/json")
	} else {
		w.Header().Add("Content-Type", "application/json")
	}
	io.WriteString(w, fmt.Sprintf(`{"error": "%s"}`, message))
}

func writeJsonResult(w http.ResponseWriter, statusCode int, result interface{}) {
	w.WriteHeader(statusCode)
	w.Header().Add("Content-Type", "application/json")
	data, err := json.Marshal(result)
	if err != nil {
		log.Println("encode ufop result error,", err)
		writeJsonError(w, 500, "encode ufop result error")
	} else {
		_, err := io.WriteString(w, string(data))
		if err != nil {
			log.Println("write json response error", err)
		}
	}
}

func writeOctetResultWithMime(w http.ResponseWriter, statusCode int, result interface{}, mimeType string) {
	w.WriteHeader(statusCode)
	w.Header().Add("Content-Type", mimeType)
	if respData := result.([]byte); respData != nil {
		_, err := w.Write(respData)
		if err != nil {
			log.Println("write octect response error", err)
		}
	}
}
<commit_msg>Fix the call sequence in the http call of Header set and WriteHeader.<commit_after>package ufop

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/qiniu/api/auth/digest"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

var (
	ufopPrefix  string
	jobHandlers map[string]UfopJobHandler
	unzipper    *UnZipper
	mkzipper    *Mkziper
	amerger     *AudioMerger
)

type UfopJobHandler interface {
	Do(ufopReq UfopRequest) (interface{}, string, error)
}

type UfopServer struct {
	cfg *UfopConfig
}

func NewServer(cfg *UfopConfig) *UfopServer {
	serv := UfopServer{}
	serv.cfg = cfg
	return &serv
}

func (this *UfopServer) registerJobHandlers() {
	mac := digest.Mac{
		AccessKey: this.cfg.AccessKey,
		SecretKey: []byte(this.cfg.SecretKey),
	}
	jobHandlers = make(map[string]UfopJobHandler, 0)
	ufopPrefix = this.cfg.UfopPrefix
	//unzipper
	unzipper = &UnZipper{
		mac:              &mac,
		maxZipFileLength: this.cfg.UnzipMaxZipFileLength,
		maxFileLength:    this.cfg.UnzipMaxFileLength,
		maxFileCount:     this.cfg.UnzipMaxFileCount,
	}
	//mkzipper
	mkzipper = &Mkziper{
		mac:           &mac,
		maxFileLength: this.cfg.MkzipMaxFileLength,
		maxFileCount:  this.cfg.MkzipMaxFileCount,
	}
	//audio merger
	amerger = &AudioMerger{
		mac:                 &mac,
		maxFirstFileLength:  this.cfg.AmergeMaxFirstFileLength,
		maxSecondFileLength: this.cfg.AmergeMaxSecondFileLength,
	}

	jobHandlers[ufopPrefix+"unzip"] = unzipper
	jobHandlers[ufopPrefix+"mkzip"] = mkzipper
	jobHandlers[ufopPrefix+"amerge"] = amerger
}

func (this *UfopServer) Listen() {
	//register
	this.registerJobHandlers()

	//define handler
	http.HandleFunc("/uop", serveUfop)

	//bind and listen
	endPoint := fmt.Sprintf("%s:%d", this.cfg.ListenHost, this.cfg.ListenPort)
	ufopServer := &http.Server{
		Addr:           endPoint,
		ReadTimeout:    time.Duration(this.cfg.ReadTimeout) * time.Second,
		WriteTimeout:   time.Duration(this.cfg.WriteTimeout) * time.Second,
		MaxHeaderBytes: this.cfg.MaxHeaderBytes,
	}

	listenErr := ufopServer.ListenAndServe()
	if listenErr != nil {
		log.Println(listenErr)
	}
}

func serveUfop(w http.ResponseWriter, req *http.Request) {
	//check method
	if req.Method != "POST" {
		writeJsonError(w, 405, "method not allowed")
		return
	}

	defer req.Body.Close()
	var err error
	var ufopReq UfopRequest
	var ufopResult interface{}
	var ufopResultContentType string

	ufopReqData, err := ioutil.ReadAll(req.Body)
	if err != nil {
		writeJsonError(w, 500, "read ufop request body error")
		return
	}

	err = json.Unmarshal(ufopReqData, &ufopReq)
	if err != nil {
		writeJsonError(w, 500, "parse ufop request body error")
		return
	}

	ufopResult, ufopResultContentType, err = handleJob(ufopReq)
	if err != nil {
		ufopErr := UfopError{
			Request: ufopReq,
			Error:   err.Error(),
		}
		logBytes, _ := json.Marshal(&ufopErr)
		log.Println(string(logBytes))
		writeJsonError(w, 400, err.Error())
	} else {
		switch ufopResultContentType {
		case "application/json":
			writeJsonResult(w, 200, ufopResult)
		default:
			writeOctetResultWithMime(w, 200, ufopResult, ufopResultContentType)
		}
	}
}

func handleJob(ufopReq UfopRequest) (interface{}, string, error) {
	var ufopResult interface{}
	var contentType string
	var err error
	cmd := ufopReq.Cmd

	items := strings.SplitN(cmd, "/", 2)
	fop := items[0]
	if jobHandler, ok := jobHandlers[fop]; ok {
		ufopReq.Cmd = strings.TrimPrefix(ufopReq.Cmd, ufopPrefix)
		ufopResult, contentType, err = jobHandler.Do(ufopReq)
	} else {
		err = errors.New("no fop available for the request")
	}
	return ufopResult, contentType, err
}

func writeJsonError(w http.ResponseWriter, statusCode int, message string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	io.WriteString(w, fmt.Sprintf(`{"error": "%s"}`, message))
}

func writeJsonResult(w http.ResponseWriter, statusCode int, result interface{}) {
	w.Header().Set("Content-Type", "application/json")
	data, err := json.Marshal(result)
	if err != nil {
		log.Println("encode ufop result error,", err)
		writeJsonError(w, 500, "encode ufop result error")
	} else {
		_, err := io.WriteString(w, string(data))
		if err != nil {
			log.Println("write json response error", err)
		}
	}
}

func writeOctetResultWithMime(w http.ResponseWriter, statusCode int, result interface{}, mimeType string) {
	w.Header().Set("Content-Type", mimeType)
	if respData := result.([]byte); respData != nil {
		_, err := w.Write(respData)
		if err != nil {
			log.Println("write octect response error", err)
		}
	}
}
<|endoftext|>


<commit_before>// +build windows

package jibber_jabber

import (
	"errors"
	"fmt"
	"syscall"
	"unsafe"
)

const LOCALE_NAME_MAX_LENGTH uint32 = 85

var SUPPORTED_LOCALES = map[uintptr]string{
	0x0407: "de-DE",
	0x0409: "en-US",
	0x0c0a: "es-ES", //or is it 0x040a
	0x040c: "fr-FR",
	0x0410: "it-IT",
	0x0411: "ja-JA",
	//0x0412: "ko_KO", - Will add support for Korean when nicksnyder/go-i18n supports Korean
	0x0416: "pt-BR",
	//0x0419: "ru_RU", - Will add support for Russian when nicksnyder/go-i18n supports Russian
	0x0804: "zh-CN",
	0x0c04: "zh-CK",
}

func getWindowsLocaleFrom(sysCall string) (locale string, err error) {
	buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)

	dll := syscall.MustLoadDLL("kernel32")
	proc := dll.MustFindProc(sysCall)
	r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
	if r == 0 {
		err = errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
		return
	}

	locale = syscall.UTF16ToString(buffer)

	return
}

func getAllWindowsLocaleFrom(sysCall string) (string, error) {
	dll, err := syscall.LoadDLL("kernel32")
	if err != nil {
		return "", errors.New("Could not find kernel32 dll")
	}

	proc, err := dll.FindProc(sysCall)
	if err != nil {
		return "", err
	}

	r, locale, dllError := proc.Call()
	if r == 0 {
		return "", errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
	}

	return SUPPORTED_LOCALES[locale], nil
}

func getWindowsLocale() (locale string, err error) {
	dll, err := syscall.LoadDLL("kernel32")
	if err != nil {
		return "", errors.New("Could not find kernel32 dll")
	}

	proc, err := dll.FindProc("IsWindowsVistaOrGreater")
	if err != nil {
		return "", err
	}

	r, isVistaOrGreater, dllError := proc.Call()
	if r == 0 {
		return "", errors.New("Could not determine if the version of Windows is Vista or later:\n" + dllError.Error())
	}

	if isVistaOrGreater == 1 {
		locale, err = getWindowsLocaleFrom("GetUserDefaultLocaleName")
		if err != nil {
			locale, err = getWindowsLocaleFrom("GetSystemDefaultLocaleName")
		}
	} else if isVistaOrGreater == 0 {
		locale, err = getAllWindowsLocaleFrom("GetUserDefaultLCID")
		if err != nil {
			locale, err = getAllWindowsLocaleFrom("GetSystemDefaultLCID")
		}
	} else {
		panic(fmt.Sprintf("we do not know what we are doing and the value is: %s" + syscall.UTF16ToString(isVistaOrGreater)))
	}
	return
}
func DetectIETF() (locale string, err error) {
	locale, err = getWindowsLocale()
	return
}

func DetectLanguage() (language string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		language, _ = splitLocale(windows_locale)
	}

	return
}

func DetectTerritory() (territory string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		_, territory = splitLocale(windows_locale)
	}

	return
}
<commit_msg>Still trying to fix Windows<commit_after>// +build windows

package jibber_jabber

import (
	"errors"
	"fmt"
	"syscall"
	"unsafe"
)

const LOCALE_NAME_MAX_LENGTH uint32 = 85

var SUPPORTED_LOCALES = map[uintptr]string{
	0x0407: "de-DE",
	0x0409: "en-US",
	0x0c0a: "es-ES", //or is it 0x040a
	0x040c: "fr-FR",
	0x0410: "it-IT",
	0x0411: "ja-JA",
	//0x0412: "ko_KO", - Will add support for Korean when nicksnyder/go-i18n supports Korean
	0x0416: "pt-BR",
	//0x0419: "ru_RU", - Will add support for Russian when nicksnyder/go-i18n supports Russian
	0x0804: "zh-CN",
	0x0c04: "zh-CK",
}

func getWindowsLocaleFrom(sysCall string) (locale string, err error) {
	buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)

	dll := syscall.MustLoadDLL("kernel32")
	proc := dll.MustFindProc(sysCall)
	r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
	if r == 0 {
		err = errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
		return
	}

	locale = syscall.UTF16ToString(buffer)

	return
}

func getAllWindowsLocaleFrom(sysCall string) (string, error) {
	dll, err := syscall.LoadDLL("kernel32")
	if err != nil {
		return "", errors.New("Could not find kernel32 dll")
	}

	proc, err := dll.FindProc(sysCall)
	if err != nil {
		return "", err
	}

	r, locale, dllError := proc.Call()
	if r == 0 {
		return "", errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
	}

	return SUPPORTED_LOCALES[locale], nil
}

func getWindowsLocale() (locale string, err error) {
	dll, err := syscall.LoadDLL("kernel32")
	if err != nil {
		return "", errors.New("Could not find kernel32 dll")
	}

	proc, err := dll.FindProc("IsWindowsVistaOrGreater")
	if err != nil {
		return "", err
	}

	r, isVistaOrGreater, dllError := proc.Call()
	if r == 0 {
		return "", errors.New("Could not determine if the version of Windows is Vista or later:\n" + dllError.Error())
	}

	if isVistaOrGreater == 1 {
		locale, err = getWindowsLocaleFrom("GetUserDefaultLocaleName")
		if err != nil {
			locale, err = getWindowsLocaleFrom("GetSystemDefaultLocaleName")
		}
	} else if isVistaOrGreater == 0 {
		locale, err = getAllWindowsLocaleFrom("GetUserDefaultLCID")
		if err != nil {
			locale, err = getAllWindowsLocaleFrom("GetSystemDefaultLCID")
		}
	} else {
		panic(fmt.Sprintf("we do not know what we are doing and the value is: %d" + isVistaOrGreater))
	}
	return
}
func DetectIETF() (locale string, err error) {
	locale, err = getWindowsLocale()
	return
}

func DetectLanguage() (language string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		language, _ = splitLocale(windows_locale)
	}

	return
}

func DetectTerritory() (territory string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		_, territory = splitLocale(windows_locale)
	}

	return
}
<|endoftext|>


<commit_before>// +build windows

package jibber_jabber

import (
	"errors"
	"syscall"
	"unsafe"
)

const LOCALE_NAME_MAX_LENGTH uint32 = 85

func getWindowsLocale() (locale string, err error) {
	buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)

	dll := syscall.MustLoadDLL("kernel32")
	proc := dll.MustFindProc("GetSystemDefaultLocaleName")
	r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
	if r == 0 {
		err = errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
		return
	}

	locale = syscall.UTF16ToString(buffer)

	return
}

func DetectIETF() (locale string, err error) {
	locale, err = getWindowsLocale()
	return
}

func DetectLanguage() (language string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		language, _ = splitLocale(windows_locale)
	}

	return
}

func DetectTerritory() (territory string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		_, territory = splitLocale(windows_locale)
	}

	return
}
<commit_msg>Supporting user level language detection.<commit_after>// +build windows

package jibber_jabber

import (
	"errors"
	"syscall"
	"unsafe"
)

const LOCALE_NAME_MAX_LENGTH uint32 = 85

func getWindowsLocaleFrom(sysCall string) (locale string, err error) {
	buffer := make([]uint16, LOCALE_NAME_MAX_LENGTH)

	dll := syscall.MustLoadDLL("kernel32")
	proc := dll.MustFindProc(sysCall)
	r, _, dllError := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LOCALE_NAME_MAX_LENGTH))
	if r == 0 {
		err = errors.New(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE + ":\n" + dllError.Error())
		return
	}

	locale = syscall.UTF16ToString(buffer)

	return
}

func getWindowsLocale() (locale string, err error) {
	locale, err = getWindowsLocaleFrom("GetUserDefaultLocaleName")
	if err != nil {
		locale, err = getWindowsLocaleFrom("GetSystemDefaultLocaleName")
	}
	return
}
func DetectIETF() (locale string, err error) {
	locale, err = getWindowsLocale()
	return
}

func DetectLanguage() (language string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		language, _ = splitLocale(windows_locale)
	}

	return
}

func DetectTerritory() (territory string, err error) {
	windows_locale, err := getWindowsLocale()
	if err == nil {
		_, territory = splitLocale(windows_locale)
	}

	return
}
<|endoftext|>


<commit_before>package buffer

import (
	"bytes"
	"crypto/rand"
	"encoding/gob"
	"io"
	"io/ioutil"
	"os"
	"testing"
)

func BenchmarkMemory(b *testing.B) {
	buf := New(32 * 1024)
	for i := 0; i < b.N; i++ {
		io.Copy(buf, io.LimitReader(rand.Reader, 32*1024))
		io.Copy(ioutil.Discard, buf)
	}
}

func TestPool(t *testing.T) {
	pool := NewPool(func() Buffer { return New(10) })
	buf := pool.Get()
	buf.Write([]byte("hello world"))
	pool.Put(buf)
}

func TestMemPool(t *testing.T) {
	pool := NewMemPool(10)
	buf := pool.Get()
	if n, err := buf.Write([]byte("hello world")); n != 10 {
		t.Errorf("wrote incorrect amount")
	} else if err == nil {
		t.Errorf("should have been a shortwrite error here")
	}
}

func TestFilePool(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("there should have been a panic here!")
		}
	}()

	pool := NewFilePool(1024, "::~_bad_dir_~::")
	pool.Get()
}

func TestOverflow(t *testing.T) {
	buf := NewMulti(New(5), NewDiscard())
	buf.Write([]byte("Hello World"))

	data, err := ioutil.ReadAll(buf)
	if err != nil {
		t.Error(err.Error())
	}

	if !bytes.Equal(data, []byte("Hello")) {
		t.Errorf("Expected Hello got %s", string(data))
	}

}

func TestWriteAt(t *testing.T) {
	var b BufferAt

	b = New(5)
	BufferAtTester(t, b)

	file, err := ioutil.TempFile("", "buffer")
	if err != nil {
		t.Error(err.Error())
	}
	defer os.Remove(file.Name())
	defer file.Close()

	b = NewFile(5, file)
	BufferAtTester(t, b)

}

func BufferAtTester(t *testing.T, b BufferAt) {
	b.WriteAt([]byte("abc"), 0)
	Compare(t, b, "abc")

	b.WriteAt([]byte("abc"), 1)
	Compare(t, b, "aabc")

	b.WriteAt([]byte("abc"), 2)
	Compare(t, b, "aaabc")

	b.WriteAt([]byte("abc"), 3)
	Compare(t, b, "aaaab")

	b.Read(make([]byte, 2))

	Compare(t, b, "aab")
	b.Reset()
}

func Compare(t *testing.T, b BufferAt, s string) {
	data := make([]byte, b.Len())
	n, _ := b.ReadAt(data, 0)
	if string(data[:n]) != s {
		t.Error("Mismatch:", string(data[:n]), s)
	}
}

func TestRing(t *testing.T) {
	ring := NewRing(New(3))
	if ring.Len() != 0 {
		t.Errorf("Ring non-empty start!")
	}

	if ring.Cap() != MAXINT64 {
		t.Errorf("Ring has < max capacity")
	}

	ring.Write([]byte("abc"))
	if ring.Len() != 3 {
		t.Errorf("expected ring len == 3")
	}

	ring.Write([]byte("de"))
	if ring.Len() != 3 {
		t.Errorf("expected riing len == 3")
	}

	data := make([]byte, 12)
	if n, err := ring.Read(data); err != nil {
		t.Error(err.Error())
	} else {
		if !bytes.Equal(data[:n], []byte("cde")) {
			t.Errorf("expected cde, got %s", data[:n])
		}
	}

	if ring.Len() != 0 {
		t.Errorf("ring should now be empty")
	}

	ring.Write([]byte("hello"))
	ring.Reset()

	if ring.Len() != 0 {
		t.Errorf("ring should still be empty")
	}
}

func TestGob(t *testing.T) {
	str := "HelloWorld"

	buf := NewUnboundedBuffer(2, 2)
	buf.Write([]byte(str))
	b := bytes.NewBuffer(nil)
	var test Buffer = buf
	if err := gob.NewEncoder(b).Encode(&test); err != nil {
		t.Error(err.Error())
		return
	}
	var buffer Buffer
	if err := gob.NewDecoder(b).Decode(&buffer); err != nil {
		t.Error(err.Error())
		return
	}
	data := make([]byte, len(str))
	if _, err := buffer.Read(data); err != nil && err != io.EOF {
		t.Error(err.Error())
	}
	if !bytes.Equal(data, []byte(str)) {
		t.Error("Gob Recover Failed... " + string(data))
	}
	buffer.Reset()
}

func TestDiscard(t *testing.T) {
	buf := NewDiscard()
	if buf.Cap() != MAXINT64 {
		t.Errorf("cap isn't infinite")
	}
	buf.Write([]byte("hello"))
	if buf.Len() != 0 {
		t.Errorf("buf should always be empty")
	}
}

func TestList(t *testing.T) {
	mem := New(10)
	ory := New(10)
	mem.Write([]byte("Hello"))
	ory.Write([]byte("world"))

	buf := BufferList([]Buffer{mem, ory, NewDiscard()})
	if buf.Len() != 10 {
		t.Errorf("incorrect sum of lengths")
	}
	if buf.Cap() != MAXINT64 {
		t.Errorf("incorrect sum of caps")
	}

	buf.Reset()
	if buf.Len() != 0 {
		t.Errorf("buffer should be empty")
	}
}

func TestSpill(t *testing.T) {
	buf := NewSpill(New(5), NewDiscard())
	buf.Write([]byte("Hello World"))
	data := make([]byte, 12)
	n, _ := buf.Read(data)
	if !bytes.Equal(data[:n], []byte("Hello")) {
		t.Error("ReadAt Failed. " + string(data[:n]))
	}
}

func TestSpill2(t *testing.T) {
	buf := NewSpill(New(5), nil)

	if buf.Cap() != MAXINT64 {
		t.Errorf("cap isn't infinite")
	}

	buf.Write([]byte("Hello World"))
	data := make([]byte, 12)
	n, _ := buf.Read(data)
	if !bytes.Equal(data[:n], []byte("Hello")) {
		t.Error("ReadAt Failed. " + string(data[:n]))
	}
}

func TestFile(t *testing.T) {
	file, err := ioutil.TempFile("", "buffer")
	if err != nil {
		t.Error(err.Error())
	}
	defer os.Remove(file.Name())
	defer file.Close()

	buf := NewFile(1024, file)
	checkCap(t, buf, 1024)
	runPerfectSeries(t, buf)
	buf.Reset()

	buf = NewFile(3, file)
	buf.Write([]byte("abc"))
	buf.Read(make([]byte, 1))
	buf.Write([]byte("a"))
	d, _ := ioutil.ReadAll(buf)
	if !bytes.Equal(d, []byte("bca")) {
		t.Error("back and forth error!")
	}
}

func TestMem(t *testing.T) {
	buf := New(1024)
	checkCap(t, buf, 1024)
	runPerfectSeries(t, buf)
	buf.Reset()
}

func TestFilePartition(t *testing.T) {
	buf := NewPartition(NewFilePool(1024, ""))
	checkCap(t, buf, MAXINT64)
	runPerfectSeries(t, buf)
	buf.Reset()
}

func TestMulti(t *testing.T) {
	file, err := ioutil.TempFile("", "buffer")
	if err != nil {
		t.Error(err.Error())
	}
	defer os.Remove(file.Name())
	defer file.Close()

	buf := NewMulti(New(5), New(5), NewFile(500, file), NewPartition(NewFilePool(1024, "")))
	checkCap(t, buf, MAXINT64)
	runPerfectSeries(t, buf)
	isPerfectMatch(t, buf, 1024*1024)
	buf.Reset()
}

func runPerfectSeries(t *testing.T, buf Buffer) {
	checkEmpty(t, buf)
	simple(t, buf)

	max := int64(1024)
	isPerfectMatch(t, buf, 0)
	for i := int64(1); i < max; i *= 2 {
		isPerfectMatch(t, buf, i)
	}
	isPerfectMatch(t, buf, max)
}

func simple(t *testing.T, buf Buffer) {
	buf.Write([]byte("hello world"))
	data, err := ioutil.ReadAll(buf)
	if err != nil {
		t.Error(err.Error())
	}
	if !bytes.Equal([]byte("hello world"), data) {
		t.Error("Hello world failed.")
	}

	buf.Write([]byte("hello world"))
	data = make([]byte, 3)
	buf.Read(data)
	buf.Write([]byte(" yolo"))
	data, err = ioutil.ReadAll(buf)
	if err != nil {
		t.Error(err.Error())
	}
	if !bytes.Equal([]byte("lo world yolo"), data) {
		t.Error("Buffer crossing error :(", string(data))
	}
}

func buildOutputs(t *testing.T, buf Buffer, size int64) (wrote []byte, read []byte) {
	r := io.LimitReader(rand.Reader, size)
	tee := io.TeeReader(r, buf)

	wrote, _ = ioutil.ReadAll(tee)
	read, _ = ioutil.ReadAll(buf)

	return wrote, read
}

func isPerfectMatch(t *testing.T, buf Buffer, size int64) {
	wrote, read := buildOutputs(t, buf, size)
	if !bytes.Equal(wrote, read) {
		t.Error("Buffer should have matched")
	}
}

func checkEmpty(t *testing.T, buf Buffer) {
	if !Empty(buf) {
		t.Error("Buffer should start empty!")
	}
}

func checkCap(t *testing.T, buf Buffer, correctCap int64) {
	if buf.Cap() != correctCap {
		t.Error("Buffer cap is incorrect", buf.Cap(), correctCap)
	}
}
<commit_msg>test write past end of mem buffer<commit_after>package buffer

import (
	"bytes"
	"crypto/rand"
	"encoding/gob"
	"io"
	"io/ioutil"
	"os"
	"testing"
)

func BenchmarkMemory(b *testing.B) {
	buf := New(32 * 1024)
	for i := 0; i < b.N; i++ {
		io.Copy(buf, io.LimitReader(rand.Reader, 32*1024))
		io.Copy(ioutil.Discard, buf)
	}
}

func TestPool(t *testing.T) {
	pool := NewPool(func() Buffer { return New(10) })
	buf := pool.Get()
	buf.Write([]byte("hello world"))
	pool.Put(buf)
}

func TestMemPool(t *testing.T) {
	pool := NewMemPool(10)
	buf := pool.Get()
	if n, err := buf.Write([]byte("hello world")); n != 10 {
		t.Errorf("wrote incorrect amount")
	} else if err == nil {
		t.Errorf("should have been a shortwrite error here")
	}
}

func TestFilePool(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("there should have been a panic here!")
		}
	}()

	pool := NewFilePool(1024, "::~_bad_dir_~::")
	pool.Get()
}

func TestOverflow(t *testing.T) {
	buf := NewMulti(New(5), NewDiscard())
	buf.Write([]byte("Hello World"))

	data, err := ioutil.ReadAll(buf)
	if err != nil {
		t.Error(err.Error())
	}

	if !bytes.Equal(data, []byte("Hello")) {
		t.Errorf("Expected Hello got %s", string(data))
	}

}

func TestWriteAt(t *testing.T) {
	var b BufferAt

	b = New(5)
	BufferAtTester(t, b)

	file, err := ioutil.TempFile("", "buffer")
	if err != nil {
		t.Error(err.Error())
	}
	defer os.Remove(file.Name())
	defer file.Close()

	b = NewFile(5, file)
	BufferAtTester(t, b)

}

func BufferAtTester(t *testing.T, b BufferAt) {
	b.WriteAt([]byte("abc"), 0)
	Compare(t, b, "abc")

	b.WriteAt([]byte("abc"), 1)
	Compare(t, b, "aabc")

	b.WriteAt([]byte("abc"), 2)
	Compare(t, b, "aaabc")

	b.WriteAt([]byte("abc"), 3)
	Compare(t, b, "aaaab")

	b.Read(make([]byte, 2))

	Compare(t, b, "aab")
	b.Reset()
}

func Compare(t *testing.T, b BufferAt, s string) {
	data := make([]byte, b.Len())
	n, _ := b.ReadAt(data, 0)
	if string(data[:n]) != s {
		t.Error("Mismatch:", string(data[:n]), s)
	}
}

func TestRing(t *testing.T) {
	ring := NewRing(New(3))
	if ring.Len() != 0 {
		t.Errorf("Ring non-empty start!")
	}

	if ring.Cap() != MAXINT64 {
		t.Errorf("Ring has < max capacity")
	}

	ring.Write([]byte("abc"))
	if ring.Len() != 3 {
		t.Errorf("expected ring len == 3")
	}

	ring.Write([]byte("de"))
	if ring.Len() != 3 {
		t.Errorf("expected riing len == 3")
	}

	data := make([]byte, 12)
	if n, err := ring.Read(data); err != nil {
		t.Error(err.Error())
	} else {
		if !bytes.Equal(data[:n], []byte("cde")) {
			t.Errorf("expected cde, got %s", data[:n])
		}
	}

	if ring.Len() != 0 {
		t.Errorf("ring should now be empty")
	}

	ring.Write([]byte("hello"))
	ring.Reset()

	if ring.Len() != 0 {
		t.Errorf("ring should still be empty")
	}
}

func TestGob(t *testing.T) {
	str := "HelloWorld"

	buf := NewUnboundedBuffer(2, 2)
	buf.Write([]byte(str))
	b := bytes.NewBuffer(nil)
	var test Buffer = buf
	if err := gob.NewEncoder(b).Encode(&test); err != nil {
		t.Error(err.Error())
		return
	}
	var buffer Buffer
	if err := gob.NewDecoder(b).Decode(&buffer); err != nil {
		t.Error(err.Error())
		return
	}
	data := make([]byte, len(str))
	if _, err := buffer.Read(data); err != nil && err != io.EOF {
		t.Error(err.Error())
	}
	if !bytes.Equal(data, []byte(str)) {
		t.Error("Gob Recover Failed... " + string(data))
	}
	buffer.Reset()
}

func TestDiscard(t *testing.T) {
	buf := NewDiscard()
	if buf.Cap() != MAXINT64 {
		t.Errorf("cap isn't infinite")
	}
	buf.Write([]byte("hello"))
	if buf.Len() != 0 {
		t.Errorf("buf should always be empty")
	}
}

func TestList(t *testing.T) {
	mem := New(10)
	ory := New(10)
	mem.Write([]byte("Hello"))
	ory.Write([]byte("world"))

	buf := BufferList([]Buffer{mem, ory, NewDiscard()})
	if buf.Len() != 10 {
		t.Errorf("incorrect sum of lengths")
	}
	if buf.Cap() != MAXINT64 {
		t.Errorf("incorrect sum of caps")
	}

	buf.Reset()
	if buf.Len() != 0 {
		t.Errorf("buffer should be empty")
	}
}

func TestSpill(t *testing.T) {
	buf := NewSpill(New(5), NewDiscard())
	buf.Write([]byte("Hello World"))
	data := make([]byte, 12)
	n, _ := buf.Read(data)
	if !bytes.Equal(data[:n], []byte("Hello")) {
		t.Error("ReadAt Failed. " + string(data[:n]))
	}
}

func TestSpill2(t *testing.T) {
	buf := NewSpill(New(5), nil)

	if buf.Cap() != MAXINT64 {
		t.Errorf("cap isn't infinite")
	}

	buf.Write([]byte("Hello World"))
	data := make([]byte, 12)
	n, _ := buf.Read(data)
	if !bytes.Equal(data[:n], []byte("Hello")) {
		t.Error("ReadAt Failed. " + string(data[:n]))
	}
}

func TestFile(t *testing.T) {
	file, err := ioutil.TempFile("", "buffer")
	if err != nil {
		t.Error(err.Error())
	}
	defer os.Remove(file.Name())
	defer file.Close()

	buf := NewFile(1024, file)
	checkCap(t, buf, 1024)
	runPerfectSeries(t, buf)
	buf.Reset()

	buf = NewFile(3, file)
	buf.Write([]byte("abc"))
	buf.Read(make([]byte, 1))
	buf.Write([]byte("a"))
	d, _ := ioutil.ReadAll(buf)
	if !bytes.Equal(d, []byte("bca")) {
		t.Error("back and forth error!")
	}
}

func TestMem(t *testing.T) {
	buf := New(1024)
	checkCap(t, buf, 1024)
	runPerfectSeries(t, buf)
	buf.Reset()
	if n, err := buf.WriteAt([]byte("hello"), 1); err == nil || n != 0 {
		t.Errorf("write should have failed")
	}
}

func TestFilePartition(t *testing.T) {
	buf := NewPartition(NewFilePool(1024, ""))
	checkCap(t, buf, MAXINT64)
	runPerfectSeries(t, buf)
	buf.Reset()
}

func TestMulti(t *testing.T) {
	file, err := ioutil.TempFile("", "buffer")
	if err != nil {
		t.Error(err.Error())
	}
	defer os.Remove(file.Name())
	defer file.Close()

	buf := NewMulti(New(5), New(5), NewFile(500, file), NewPartition(NewFilePool(1024, "")))
	checkCap(t, buf, MAXINT64)
	runPerfectSeries(t, buf)
	isPerfectMatch(t, buf, 1024*1024)
	buf.Reset()
}

func runPerfectSeries(t *testing.T, buf Buffer) {
	checkEmpty(t, buf)
	simple(t, buf)

	max := int64(1024)
	isPerfectMatch(t, buf, 0)
	for i := int64(1); i < max; i *= 2 {
		isPerfectMatch(t, buf, i)
	}
	isPerfectMatch(t, buf, max)
}

func simple(t *testing.T, buf Buffer) {
	buf.Write([]byte("hello world"))
	data, err := ioutil.ReadAll(buf)
	if err != nil {
		t.Error(err.Error())
	}
	if !bytes.Equal([]byte("hello world"), data) {
		t.Error("Hello world failed.")
	}

	buf.Write([]byte("hello world"))
	data = make([]byte, 3)
	buf.Read(data)
	buf.Write([]byte(" yolo"))
	data, err = ioutil.ReadAll(buf)
	if err != nil {
		t.Error(err.Error())
	}
	if !bytes.Equal([]byte("lo world yolo"), data) {
		t.Error("Buffer crossing error :(", string(data))
	}
}

func buildOutputs(t *testing.T, buf Buffer, size int64) (wrote []byte, read []byte) {
	r := io.LimitReader(rand.Reader, size)
	tee := io.TeeReader(r, buf)

	wrote, _ = ioutil.ReadAll(tee)
	read, _ = ioutil.ReadAll(buf)

	return wrote, read
}

func isPerfectMatch(t *testing.T, buf Buffer, size int64) {
	wrote, read := buildOutputs(t, buf, size)
	if !bytes.Equal(wrote, read) {
		t.Error("Buffer should have matched")
	}
}

func checkEmpty(t *testing.T, buf Buffer) {
	if !Empty(buf) {
		t.Error("Buffer should start empty!")
	}
}

func checkCap(t *testing.T, buf Buffer, correctCap int64) {
	if buf.Cap() != correctCap {
		t.Error("Buffer cap is incorrect", buf.Cap(), correctCap)
	}
}
<|endoftext|>


<commit_before>// A long-polling HTTP chat server
package main

// TODO:
//
// add some kind of console thing?
// get WEBROOT on command line or environment
// handle users who leave
// handle idle users

import (
	"encoding/json"
	"fmt"
	"github.com/beejjorgensen/connectionmanager"
	"log"
	"net/http"
	"runtime"
	//"time"
)

const WEBROOT = "/home/beej/src/go/libs/src/github.com/beejjorgensen/connectionmanager/examples/chat/webroot"

type response map[string]interface{}

// Handler for user command requests (implements http.Handler)
type CommandHandler struct {
	userManager       *UserManager
	connectionManager *connectionmanager.ConnectionManager
}

// Handler for long-poll requests (implements http.Handler)
type LongPollHandler struct {
	userManager       *UserManager
	connectionManager *connectionmanager.ConnectionManager
}

// Helper function to make a status response
func makeStatusResponse(status string, message string) *response {
	return &response{
		"type":    "status",
		"status":  status,
		"message": message,
	}
}

// Helper function to log errors in response writes
func writeReponse(rw http.ResponseWriter, data *[]byte) {
	n, err := rw.Write(*data)
	if err != nil {
		log.Printf("error writing command response: %v", err)
		return
	}

	l := len(*data)
	if n != l {
		log.Printf("command response short write: %d bytes (out of %d)", n, l)
	}
}

// Service user command HTTP requests
func (h *CommandHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
	defer rq.Body.Close()

	rw.Header().Set("Content-Type", "application/json")

	var userName string
	var resp *connectionmanager.Message
	var jresp []byte

	// get passed parameters
	id := rq.FormValue("id")
	com := rq.FormValue("command")

	//log.Printf("Chat: serving command %s: %s\n", com, id)

	switch com {
	case "login":
		// extract username
		userName = rq.FormValue("username")

		resp = h.connectionManager.SendMessage(&connectionmanager.Message{
			Type: connectionmanager.ConnectRequest,
			Id:   id,
		})

		// if ok, record in our user list
		if resp.Err == nil {
			user, _ := h.userManager.AddUser(id, userName)
			jresp, _ = json.Marshal(response{
				"type":     "loginresponse",
				"id":       id,
				"publicid": user.pubId,
				"username": user.name,
			})

			// notify all other users of the new user
			// send the broadcast request
			h.connectionManager.SendMessage(&connectionmanager.Message{
				Type: connectionmanager.BroadcastRequest,
				Id:   id,
				Payload: &connectionmanager.MessagePayload{
					"type":     "newuser",
					"username": user.name,
					"publicid": user.pubId,
				},
			})

			//jresp, _ = json.Marshal(*makeStatusResponse("ok", ""))

		} else {
			jresp, _ = json.Marshal(*makeStatusResponse("error", resp.Err.Error()))
		}

		writeReponse(rw, &jresp)

	case "broadcast":
		// extract message
		msg := rq.FormValue("message")

		user, err := h.userManager.GetUserByID(id)

		if err == nil {
			// send the broadcast request
			h.connectionManager.SendMessage(&connectionmanager.Message{
				Type: connectionmanager.BroadcastRequest,
				Id:   id,
				Payload: &connectionmanager.MessagePayload{
					"type":     "message",
					"username": user.name,
					"publicid": user.pubId,
					"message":  msg,
				},
			})
			jresp, _ = json.Marshal(*makeStatusResponse("ok", ""))

		} else {
			jresp, _ = json.Marshal(*makeStatusResponse("error", fmt.Sprintf("%v", err)))
		}

		writeReponse(rw, &jresp)

	case "setusername":
		userName = rq.FormValue("username")

		user, err := h.userManager.GetUserByID(id)

		if err == nil {
			// broadcast that we're changing our username
			h.connectionManager.SendMessage(&connectionmanager.Message{
				Type: connectionmanager.BroadcastRequest,
				Id:   id,
				Payload: &connectionmanager.MessagePayload{
					"type":        "changeusername",
					"oldusername": user.name,
					"newusername": user.name,
					"publicid":    user.pubId,
				},
			})

			// change username
			user.name = userName

			jresp, _ = json.Marshal(*makeStatusResponse("ok", ""))

		} else {
			jresp, _ = json.Marshal(*makeStatusResponse("error", fmt.Sprintf("%v", err)))
		}

		writeReponse(rw, &jresp)
	}
}

// Service long-poll HTTP requests
func (h *LongPollHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
	defer rq.Body.Close()

	var jresp []byte

	rw.Header().Set("Content-Type", "application/json")

	// get ID
	id := rq.FormValue("id")

	//log.Printf("Chat: beginning long poll: %s\n", id)

	// request messages from ConnectionManager
	resp := h.connectionManager.SendMessage(&connectionmanager.Message{
		Type: connectionmanager.PollRequest,
		Id:   id,
	})

	// check for errors
	if resp.Err != nil {
		log.Printf("Chat: long poll request error: %s", resp.Err.Error())

		jresp, _ := json.Marshal(*makeStatusResponse("error", resp.Err.Error()))
		writeReponse(rw, &jresp)

		return
	}

	// wait for messages
	//log.Printf("Chat: long poll waiting on channel: %s\n", resp.RChan)

	// response channel in resp
	pollresp, ok := <-resp.PollChan

	if ok {
		messages := make([]*connectionmanager.MessagePayload, len(*pollresp))

		for i, v := range *pollresp {
			messages[i] = v.Payload
		}

		//log.Printf("Chat: long poll response received: %s\n", id)

		// send messages in response
		jresp, _ = json.Marshal(messages)

		//log.Printf("Chat: completed long poll: %s\n", id)
	} else {
		//log.Printf("Chat: long poll channel closed\n")

		// the remote side has probably closed at this point, but let's
		// send a response anyway
		jresp, _ = json.Marshal(*makeStatusResponse("error", "long poll canceled"))
	}

	//log.Printf(">>>>> %s", string(jresp))
	writeReponse(rw, &jresp)
}

// General file server
func fileHandler(rw http.ResponseWriter, r *http.Request) {
	filePath := fmt.Sprintf("%s%s", WEBROOT, r.URL.RequestURI())
	http.ServeFile(rw, r, filePath)
	r.Body.Close()
}

// Sets up the handlers and runs the HTTP server (run as a goroutine)
func runWebServer(connectionManager *connectionmanager.ConnectionManager,
	userManager *UserManager) {

	longPollHandler := &LongPollHandler{
		connectionManager: connectionManager,
		userManager:       userManager,
	}

	commandHandler := &CommandHandler{
		connectionManager: connectionManager,
		userManager:       userManager,
	}

	s := &http.Server{
		Addr:           ":8080",
		Handler:        nil,
		//ReadTimeout:    120 * time.Second,
		//WriteTimeout:   2 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	http.Handle("/poll", longPollHandler)
	http.Handle("/cmd", commandHandler)
	http.HandleFunc("/", fileHandler)

	log.Fatal(s.ListenAndServe())
}

// main
func main() {
	log.Printf("num cpus: %v", runtime.NumCPU())
	runtime.GOMAXPROCS(runtime.NumCPU())

	userManager := NewUserManager()
	userManager.Start()
	connectionManager := connectionmanager.New()
	connectionManager.SetActive(true)

	log.Println("Running server")

	go runWebServer(connectionManager, userManager)

	// console
	fmt.Scanln()
}
<commit_msg>fix paths for real<commit_after>// A long-polling HTTP chat server
package main

// TODO:
//
// add some kind of console thing?
// get WEBROOT on command line or environment
// handle users who leave
// handle idle users

import (
	"encoding/json"
	"fmt"
	"github.com/beejjorgensen/connectionmanager"
	"log"
	"net/http"
	"runtime"
	//"time"
)

const WEBROOT = "/home/beej/src/go/src/github.com/beejjorgensen/connectionmanager/examples/chat/webroot"

type response map[string]interface{}

// Handler for user command requests (implements http.Handler)
type CommandHandler struct {
	userManager       *UserManager
	connectionManager *connectionmanager.ConnectionManager
}

// Handler for long-poll requests (implements http.Handler)
type LongPollHandler struct {
	userManager       *UserManager
	connectionManager *connectionmanager.ConnectionManager
}

// Helper function to make a status response
func makeStatusResponse(status string, message string) *response {
	return &response{
		"type":    "status",
		"status":  status,
		"message": message,
	}
}

// Helper function to log errors in response writes
func writeReponse(rw http.ResponseWriter, data *[]byte) {
	n, err := rw.Write(*data)
	if err != nil {
		log.Printf("error writing command response: %v", err)
		return
	}

	l := len(*data)
	if n != l {
		log.Printf("command response short write: %d bytes (out of %d)", n, l)
	}
}

// Service user command HTTP requests
func (h *CommandHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
	defer rq.Body.Close()

	rw.Header().Set("Content-Type", "application/json")

	var userName string
	var resp *connectionmanager.Message
	var jresp []byte

	// get passed parameters
	id := rq.FormValue("id")
	com := rq.FormValue("command")

	//log.Printf("Chat: serving command %s: %s\n", com, id)

	switch com {
	case "login":
		// extract username
		userName = rq.FormValue("username")

		resp = h.connectionManager.SendMessage(&connectionmanager.Message{
			Type: connectionmanager.ConnectRequest,
			Id:   id,
		})

		// if ok, record in our user list
		if resp.Err == nil {
			user, _ := h.userManager.AddUser(id, userName)
			jresp, _ = json.Marshal(response{
				"type":     "loginresponse",
				"id":       id,
				"publicid": user.pubId,
				"username": user.name,
			})

			// notify all other users of the new user
			// send the broadcast request
			h.connectionManager.SendMessage(&connectionmanager.Message{
				Type: connectionmanager.BroadcastRequest,
				Id:   id,
				Payload: &connectionmanager.MessagePayload{
					"type":     "newuser",
					"username": user.name,
					"publicid": user.pubId,
				},
			})

			//jresp, _ = json.Marshal(*makeStatusResponse("ok", ""))

		} else {
			jresp, _ = json.Marshal(*makeStatusResponse("error", resp.Err.Error()))
		}

		writeReponse(rw, &jresp)

	case "broadcast":
		// extract message
		msg := rq.FormValue("message")

		user, err := h.userManager.GetUserByID(id)

		if err == nil {
			// send the broadcast request
			h.connectionManager.SendMessage(&connectionmanager.Message{
				Type: connectionmanager.BroadcastRequest,
				Id:   id,
				Payload: &connectionmanager.MessagePayload{
					"type":     "message",
					"username": user.name,
					"publicid": user.pubId,
					"message":  msg,
				},
			})
			jresp, _ = json.Marshal(*makeStatusResponse("ok", ""))

		} else {
			jresp, _ = json.Marshal(*makeStatusResponse("error", fmt.Sprintf("%v", err)))
		}

		writeReponse(rw, &jresp)

	case "setusername":
		userName = rq.FormValue("username")

		user, err := h.userManager.GetUserByID(id)

		if err == nil {
			// broadcast that we're changing our username
			h.connectionManager.SendMessage(&connectionmanager.Message{
				Type: connectionmanager.BroadcastRequest,
				Id:   id,
				Payload: &connectionmanager.MessagePayload{
					"type":        "changeusername",
					"oldusername": user.name,
					"newusername": user.name,
					"publicid":    user.pubId,
				},
			})

			// change username
			user.name = userName

			jresp, _ = json.Marshal(*makeStatusResponse("ok", ""))

		} else {
			jresp, _ = json.Marshal(*makeStatusResponse("error", fmt.Sprintf("%v", err)))
		}

		writeReponse(rw, &jresp)
	}
}

// Service long-poll HTTP requests
func (h *LongPollHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
	defer rq.Body.Close()

	var jresp []byte

	rw.Header().Set("Content-Type", "application/json")

	// get ID
	id := rq.FormValue("id")

	//log.Printf("Chat: beginning long poll: %s\n", id)

	// request messages from ConnectionManager
	resp := h.connectionManager.SendMessage(&connectionmanager.Message{
		Type: connectionmanager.PollRequest,
		Id:   id,
	})

	// check for errors
	if resp.Err != nil {
		log.Printf("Chat: long poll request error: %s", resp.Err.Error())

		jresp, _ := json.Marshal(*makeStatusResponse("error", resp.Err.Error()))
		writeReponse(rw, &jresp)

		return
	}

	// wait for messages
	//log.Printf("Chat: long poll waiting on channel: %s\n", resp.RChan)

	// response channel in resp
	pollresp, ok := <-resp.PollChan

	if ok {
		messages := make([]*connectionmanager.MessagePayload, len(*pollresp))

		for i, v := range *pollresp {
			messages[i] = v.Payload
		}

		//log.Printf("Chat: long poll response received: %s\n", id)

		// send messages in response
		jresp, _ = json.Marshal(messages)

		//log.Printf("Chat: completed long poll: %s\n", id)
	} else {
		//log.Printf("Chat: long poll channel closed\n")

		// the remote side has probably closed at this point, but let's
		// send a response anyway
		jresp, _ = json.Marshal(*makeStatusResponse("error", "long poll canceled"))
	}

	//log.Printf(">>>>> %s", string(jresp))
	writeReponse(rw, &jresp)
}

// General file server
func fileHandler(rw http.ResponseWriter, r *http.Request) {
	filePath := fmt.Sprintf("%s%s", WEBROOT, r.URL.RequestURI())
	http.ServeFile(rw, r, filePath)
	r.Body.Close()
}

// Sets up the handlers and runs the HTTP server (run as a goroutine)
func runWebServer(connectionManager *connectionmanager.ConnectionManager,
	userManager *UserManager) {

	longPollHandler := &LongPollHandler{
		connectionManager: connectionManager,
		userManager:       userManager,
	}

	commandHandler := &CommandHandler{
		connectionManager: connectionManager,
		userManager:       userManager,
	}

	s := &http.Server{
		Addr:           ":8080",
		Handler:        nil,
		//ReadTimeout:    120 * time.Second,
		//WriteTimeout:   2 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	http.Handle("/poll", longPollHandler)
	http.Handle("/cmd", commandHandler)
	http.HandleFunc("/", fileHandler)

	log.Fatal(s.ListenAndServe())
}

// main
func main() {
	log.Printf("num cpus: %v", runtime.NumCPU())
	runtime.GOMAXPROCS(runtime.NumCPU())

	userManager := NewUserManager()
	userManager.Start()
	connectionManager := connectionmanager.New()
	connectionManager.SetActive(true)

	log.Println("Running server")

	go runWebServer(connectionManager, userManager)

	// console
	fmt.Scanln()
}
<|endoftext|>


<commit_before>package utils

import (
    "github.com/Jeffail/gabs"
    "github.com/ugjka/cleverbot-go"
    "github.com/bwmarrin/discordgo"
    "fmt"
    "bytes"
    "io"
    "net/http"
    "strconv"
    "errors"
    "github.com/getsentry/raven-go"
)

type Callback func()

var (
    config *gabs.Container
    cleverbotSessions map[string]*cleverbot.Session
)

func LoadConfig(path string) {
    json, err := gabs.ParseJSONFile(path)

    if err != nil {
        panic(err)
    }

    config = json
}

func GetConfig() *gabs.Container {
    return config
}

func CleverbotSend(session *discordgo.Session, guild string, message string) {
    var msg string

    if cleverbotSessions[guild] == nil {
        if len(cleverbotSessions) == 0 {
            cleverbotSessions = make(map[string]*cleverbot.Session)
        }

        cleverbotSessions[guild] = cleverbot.New()
    }

    response, err := cleverbotSessions[guild].Ask(message)
    if err != nil {
        msg = "Error :frowning:\n```\n" + err.Error() + "\n```"
    } else {
        msg = response
    }

    session.ChannelMessageSend(guild, msg)
}

func CleverbotRefreshSession(guild string) {
    cleverbotSessions[guild] = cleverbot.New()
}

func CCTV(session *discordgo.Session, message *discordgo.Message) {
    var (
        channelName string = "?"
        channelID string = "?"
        serverName string = "?"
        serverID string = "?"
    )

    channel, err := session.Channel(message.ChannelID)
    if err == nil {
        channelName = channel.Name
        channelID = channel.ID

        server, err := session.Guild(channel.GuildID)
        if err == nil {
            serverName = server.Name
            serverID = server.ID
        }
    }

    template := `
At:      %s
Origin:  #%s (%s) in %s (%s)
Author:  %s#%s (%s)
Message:
%s
`

    msg :=
        "```\n" +
            fmt.Sprintf(
                template,
                message.Timestamp,
                channelName,
                channelID,
                serverName,
                serverID,
                message.Author.Username,
                message.Author.Discriminator,
                message.Author.ID,
                message.Content,
            ) +
            "\n```"

    session.ChannelMessageSend(
        config.Path("cctv").Data().(string),
        msg,
    )
}

func GetPrefixForServer(guild string) (string, error) {
    return GuildSettingGet(guild, "prefix")
}

func SetPrefixForServer(guild string, prefix string) error {
    return GuildSettingSet(guild, "prefix", prefix)
}

func SendError(session *discordgo.Session, msg *discordgo.Message, err interface{}) {
    session.ChannelMessageSend(
        msg.ChannelID,
        "Error :frowning:\n0xFADED#3237 has been notified.\n```\n" +
            fmt.Sprintf("%#v", err) +
            "\n```\nhttp://i.imgur.com/FcV2n4X.jpg",
    )

    raven.SetUserContext(&raven.User{
        ID: msg.ID,
        Username: msg.Author.Username + "#" + msg.Author.Discriminator,
    })
    raven.CaptureError(errors.New(fmt.Sprintf("%#v", err)), map[string]string{
        "ChannelID": msg.ChannelID,
        "Content": msg.Content,
        "Timestamp": msg.Timestamp,
        "TTS": strconv.FormatBool(msg.Tts),
        "MentionEveryone": strconv.FormatBool(msg.MentionEveryone),
        "IsBot": strconv.FormatBool(msg.Author.Bot),
    })
}

func WhileTypingIn(session *discordgo.Session, channel string, cb Callback) {
    session.ChannelTyping(channel)
    cb()
}

func GetJSON(url string) *gabs.Container {
    // Send request
    response, err := http.Get(url)
    if err != nil {
        panic(err)
    }

    // Only continue if code was 200
    if response.StatusCode != 200 {
        panic(errors.New("Expected status 200; Got " + strconv.Itoa(response.StatusCode)))
    } else {
        // Read body
        defer response.Body.Close()

        buf := bytes.NewBuffer(nil)
        _, err := io.Copy(buf, response.Body)
        if err != nil {
            panic(err)
        }

        // Parse json
        json, err := gabs.ParseJSON(buf.Bytes())
        if err != nil {
            panic(err)
        }

        return json
    }
}

func RequireAdmin(session *discordgo.Session, msg *discordgo.Message, cb Callback) {
    channel, e := session.Channel(msg.ChannelID)
    if e != nil {
        SendError(session, msg, errors.New("Cannot verify permissions"))
        return
    }

    guild, e := session.Guild(channel.GuildID)
    if e != nil {
        SendError(session, msg, errors.New("Cannot verify permissions"))
        return
    }

    if msg.Author.ID == guild.OwnerID {
        cb()
        return
    }

    // Check if role may manage server
    for _, role := range guild.Roles {
        if role.Permissions & 8 == 8 {
            cb()
            return
        }
    }

    session.ChannelMessageSend(msg.ChannelID, "You are not an admin :frowning:")
}<commit_msg>[BUGFIX] Adapt code to api changes<commit_after>package utils

import (
    "github.com/Jeffail/gabs"
    "github.com/ugjka/cleverbot-go"
    "github.com/bwmarrin/discordgo"
    "fmt"
    "bytes"
    "io"
    "net/http"
    "strconv"
    "errors"
    "github.com/getsentry/raven-go"
)

type Callback func()

var (
    config *gabs.Container
    cleverbotSessions map[string]*cleverbot.Session
)

func LoadConfig(path string) {
    json, err := gabs.ParseJSONFile(path)

    if err != nil {
        panic(err)
    }

    config = json
}

func GetConfig() *gabs.Container {
    return config
}

func CleverbotSend(session *discordgo.Session, guild string, message string) {
    var msg string

    if cleverbotSessions[guild] == nil {
        if len(cleverbotSessions) == 0 {
            cleverbotSessions = make(map[string]*cleverbot.Session)
        }

        cleverbotSessions[guild] = cleverbot.New()
    }

    response, err := cleverbotSessions[guild].Ask(message)
    if err != nil {
        msg = "Error :frowning:\n```\n" + err.Error() + "\n```"
    } else {
        msg = response
    }

    session.ChannelMessageSend(guild, msg)
}

func CleverbotRefreshSession(guild string) {
    cleverbotSessions[guild] = cleverbot.New()
}

func CCTV(session *discordgo.Session, message *discordgo.Message) {
    var (
        channelName string = "?"
        channelID string = "?"
        serverName string = "?"
        serverID string = "?"
    )

    channel, err := session.Channel(message.ChannelID)
    if err == nil {
        channelName = channel.Name
        channelID = channel.ID

        server, err := session.Guild(channel.GuildID)
        if err == nil {
            serverName = server.Name
            serverID = server.ID
        }
    }

    template := `
At:      %s
Origin:  #%s (%s) in %s (%s)
Author:  %s#%s (%s)
Message:
%s
`

    msg :=
        "```\n" +
            fmt.Sprintf(
                template,
                message.Timestamp,
                channelName,
                channelID,
                serverName,
                serverID,
                message.Author.Username,
                message.Author.Discriminator,
                message.Author.ID,
                message.Content,
            ) +
            "\n```"

    session.ChannelMessageSend(
        config.Path("cctv").Data().(string),
        msg,
    )
}

func GetPrefixForServer(guild string) (string, error) {
    return GuildSettingGet(guild, "prefix")
}

func SetPrefixForServer(guild string, prefix string) error {
    return GuildSettingSet(guild, "prefix", prefix)
}

func SendError(session *discordgo.Session, msg *discordgo.Message, err interface{}) {
    session.ChannelMessageSend(
        msg.ChannelID,
        "Error :frowning:\n0xFADED#3237 has been notified.\n```\n" +
            fmt.Sprintf("%#v", err) +
            "\n```\nhttp://i.imgur.com/FcV2n4X.jpg",
    )

    raven.SetUserContext(&raven.User{
        ID: msg.ID,
        Username: msg.Author.Username + "#" + msg.Author.Discriminator,
    })
    raven.CaptureError(errors.New(fmt.Sprintf("%#v", err)), map[string]string{
        "ChannelID": msg.ChannelID,
        "Content": msg.Content,
        "Timestamp": string(msg.Timestamp),
        "TTS": strconv.FormatBool(msg.Tts),
        "MentionEveryone": strconv.FormatBool(msg.MentionEveryone),
        "IsBot": strconv.FormatBool(msg.Author.Bot),
    })
}

func WhileTypingIn(session *discordgo.Session, channel string, cb Callback) {
    session.ChannelTyping(channel)
    cb()
}

func GetJSON(url string) *gabs.Container {
    // Send request
    response, err := http.Get(url)
    if err != nil {
        panic(err)
    }

    // Only continue if code was 200
    if response.StatusCode != 200 {
        panic(errors.New("Expected status 200; Got " + strconv.Itoa(response.StatusCode)))
    } else {
        // Read body
        defer response.Body.Close()

        buf := bytes.NewBuffer(nil)
        _, err := io.Copy(buf, response.Body)
        if err != nil {
            panic(err)
        }

        // Parse json
        json, err := gabs.ParseJSON(buf.Bytes())
        if err != nil {
            panic(err)
        }

        return json
    }
}

func RequireAdmin(session *discordgo.Session, msg *discordgo.Message, cb Callback) {
    channel, e := session.Channel(msg.ChannelID)
    if e != nil {
        SendError(session, msg, errors.New("Cannot verify permissions"))
        return
    }

    guild, e := session.Guild(channel.GuildID)
    if e != nil {
        SendError(session, msg, errors.New("Cannot verify permissions"))
        return
    }

    if msg.Author.ID == guild.OwnerID {
        cb()
        return
    }

    // Check if role may manage server
    for _, role := range guild.Roles {
        if role.Permissions & 8 == 8 {
            cb()
            return
        }
    }

    session.ChannelMessageSend(msg.ChannelID, "You are not an admin :frowning:")
}<|endoftext|>