<commit_before>package simtime

import (
	"container/heap"
	"time"

	"github.com/ninjasphere/go-ninja/config"
)

var enabled = config.Bool(false, "simtime.enable")
var startOffset = config.Duration(time.Hour*24*30, "simtime.offset")
var allowFuture = config.Bool(false, "simtime.allowFuture")

var currentTime = time.Now()

var addQueue = make(chan *event)
var queue = eventQueue{}

var added = make(chan bool)
var tick = make(chan bool)
var start = make(chan bool)

func addQueuedEvents() {
	for {
		select {
		case e := <-addQueue:
			heap.Push(&queue, e)
		default:
			if len(queue) > 0 {
				return
			}
		}

	}
}

func init() {

	if !enabled {
		return
	}

	SetCurrentTime(time.Now().Add(-startOffset))

	go func() {
		<-start
		for {

			//spew.Dump("Adding queued events")
			// Add any to-be-queued events (the heap isn't threadsafe)
			addQueuedEvents()

			//spew.Dump("pop")

			event := heap.Pop(&queue).(*event)

			//spew.Dump("event", event)

			currentTime = time.Unix(0, event.fireAt)

			if !allowFuture && currentTime.After(time.Now()) {
				//spew.Dump("Sleeping")
				time.Sleep(currentTime.Sub(time.Now()))
			}

			if event.c != nil {
				//spew.Dump("Sending event")
				event.c <- currentTime
				//spew.Dump("Waiting for tick")
				select {
				case <-tick:
				case <-time.After(time.Second * 5):
					panic("When using simtime, you MUST call simtime.Continue() when you are done with your time event")
				}
				//spew.Dump("Got tick")
			} else {
				event.f(currentTime)
			}

			if event.interval > 0 {
				event.fireAt = currentTime.Add(event.interval).UnixNano()
				heap.Push(&queue, event)
			}

		}
	}()

}

func Start() {
	select {
	case start <- true:
	default:
	}
}

func Continue() {
	if enabled {
		tick <- true
	}
}

func SetCurrentTime(time time.Time) {
	currentTime = time
	queue = eventQueue{}
}

func Now() time.Time {
	if !enabled {
		return time.Now()
	}
	return currentTime
}

func Enabled() bool {
	return enabled
}

func Tick(d time.Duration) <-chan time.Time {
	if !enabled {
		return time.Tick(d)
	}
	return addChannelEvent(d, true)
}

func After(d time.Duration) <-chan time.Time {
	if !enabled {
		return time.After(d)
	}
	return addChannelEvent(d, false)
}

func Sleep(d time.Duration) {
	<-After(d)
}

func addFuncEvent(f func(time.Time), d time.Duration, interval bool) {
	e := &event{
		fireAt: currentTime.Add(d).UnixNano(),
		f:      f,
	}

	if interval {
		e.interval = d
	}

	addEvent(e)

}

func addChannelEvent(d time.Duration, interval bool) chan time.Time {

	e := &event{
		fireAt: currentTime.Add(d).UnixNano(),
		c:      make(chan time.Time),
	}

	if interval {
		e.interval = d
	}

	addEvent(e)

	return e.c
}

func addEvent(e *event) {
	addQueue <- e

	select {
	case added <- true:
	default:
	}
}

type event struct {
	f        func(time.Time)
	c        chan time.Time
	fireAt   int64
	interval time.Duration
}

// A eventQueue implements heap.Interface and holds Events.
type eventQueue []*event

func (pq eventQueue) Len() int { return len(pq) }

func (pq eventQueue) Less(i, j int) bool {
	return pq[i].fireAt < pq[j].fireAt
}

func (pq eventQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *eventQueue) Push(x interface{}) {
	item := x.(*event)
	*pq = append(*pq, item)
}

func (pq *eventQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}
<commit_msg>Some extra logging for simtime<commit_after>package simtime

import (
	"container/heap"
	"runtime/debug"
	"time"

	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/logger"
)

var log = logger.GetLogger("simtime")

var enabled = config.Bool(false, "simtime.enable")
var startOffset = config.Duration(time.Hour*24*30, "simtime.offset")
var allowFuture = config.Bool(false, "simtime.allowFuture")

var currentTime = time.Now()

var addQueue = make(chan *event)
var queue = eventQueue{}

var added = make(chan bool)
var tick = make(chan bool)
var start = make(chan bool)

func addQueuedEvents() {
	for {
		select {
		case e := <-addQueue:
			heap.Push(&queue, e)
		default:
			if len(queue) > 0 {
				return
			}
		}

	}
}

func init() {

	log.Infof("Starting. Enabled %t", enabled)

	if !enabled {
		return
	}

	SetCurrentTime(time.Now().Add(-startOffset))

	go func() {
		<-start
		for {

			//spew.Dump("Adding queued events")
			// Add any to-be-queued events (the heap isn't threadsafe)
			addQueuedEvents()

			//spew.Dump("pop")

			event := heap.Pop(&queue).(*event)

			//spew.Dump("event", event)

			currentTime = time.Unix(0, event.fireAt)

			if !allowFuture && currentTime.After(time.Now()) {
				//spew.Dump("Sleeping")
				time.Sleep(currentTime.Sub(time.Now()))
			}

			if event.c != nil {
				select {
				case event.c <- currentTime:
				case <-time.After(time.Second * 20):
					panic("An simtime channel listener didn't respond. (Check that you aren't calling simtime.Continue() more than once per tick.)")
				}

				select {
				case <-tick:
				case <-time.After(time.Second * 5):
					panic("When using simtime, you MUST call simtime.Continue() when you are done with your time event with 5 seconds.")
				}
			} else {
				event.f(currentTime)
			}

			if event.interval > 0 {
				event.fireAt = currentTime.Add(event.interval).UnixNano()
				heap.Push(&queue, event)
			}

		}
	}()

}

func Start() {
	log.Infof("Starting. Time: %s", Now())
	select {
	case start <- true:
	default:
	}
}

func Continue() {
	if enabled {
		select {
		case tick <- true:
		case <-time.After(time.Second * 5):
			panic("Continue took more than 5 seconds. Check that you are only calling it once per channel tick.")
		}
	}
}

func SetCurrentTime(time time.Time) {
	log.Infof("Setting time to %s", time)
	currentTime = time
	queue = eventQueue{}
}

func Now() time.Time {
	if !enabled {
		return time.Now()
	}
	return currentTime
}

func Enabled() bool {
	return enabled
}

func Tick(d time.Duration) <-chan time.Time {
	if !enabled {
		return time.Tick(d)
	}
	return addChannelEvent(d, true)
}

func After(d time.Duration) <-chan time.Time {
	if !enabled {
		return time.After(d)
	}
	return addChannelEvent(d, false)
}

func Sleep(d time.Duration) {
	<-After(d)
}

func addFuncEvent(f func(time.Time), d time.Duration, interval bool) {
	e := &event{
		fireAt: currentTime.Add(d).UnixNano(),
		f:      f,
		stack:  string(debug.Stack()),
	}

	if interval {
		e.interval = d
	}

	addEvent(e)

}

func addChannelEvent(d time.Duration, interval bool) chan time.Time {

	e := &event{
		fireAt: currentTime.Add(d).UnixNano(),
		c:      make(chan time.Time),
		stack:  string(debug.Stack()),
	}

	if interval {
		e.interval = d
	}

	addEvent(e)

	return e.c
}

func addEvent(e *event) {
	addQueue <- e

	select {
	case added <- true:
	default:
	}
}

type event struct {
	f        func(time.Time)
	c        chan time.Time
	fireAt   int64
	interval time.Duration
	stack    string
}

// A eventQueue implements heap.Interface and holds Events.
type eventQueue []*event

func (pq eventQueue) Len() int { return len(pq) }

func (pq eventQueue) Less(i, j int) bool {
	return pq[i].fireAt < pq[j].fireAt
}

func (pq eventQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *eventQueue) Push(x interface{}) {
	item := x.(*event)
	*pq = append(*pq, item)
}

func (pq *eventQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}
<|endoftext|>


<commit_before>package gobcodec

import (
	"bytes"
	"encoding/gob"
	"sync"
)

type Codec struct {
	l sync.Mutex
	b *bytes.Buffer
	e *gob.Encoder
	d *gob.Decoder
}

func NewCodec() *Codec {
	b := &bytes.Buffer{}
	return &Codec{
		b: b,
		e: gob.NewEncoder(b),
		d: gob.NewDecoder(b),
	}
}

func (c *Codec) Register(v interface{}) error {
	c.l.Lock()
	if err := c.e.Encode(v); err != nil {
		return returnErr(c, err)

	}
	var z interface{}
	if err := c.d.Decode(z); err != nil {
		return returnErr(c, err)
	}
	c.l.Unlock()
	return nil
}

func (c *Codec) Encode(v interface{}, dst []byte) ([]byte, error) {
	c.l.Lock()
	if err := c.e.Encode(v); err != nil {
		return dst, returnErr(c, err)
	}
	src := c.b.Bytes()
	srcLen := len(src)
	if srcLen > cap(dst) {
		dst = make([]byte, srcLen)
	}
	copy(dst, src)
	c.b.Reset()
	c.l.Unlock()
	return dst, nil
}

func (c *Codec) Decode(v interface{}, src []byte) ([]byte, error) {
	c.l.Lock()
	c.b.Write(src)
	if err := c.d.Decode(v); err != nil {
		return src, returnErr(c, err)
	}
	n := c.b.Len()
	c.b.Reset()
	c.l.Unlock()
	return src[len(src)-n:], nil
}

func returnErr(c *Codec, err error) error {
	c.b.Reset()
	c.l.Unlock()
	return err
}
<commit_msg>eliminated unnesessary bytes' copying in Codec's Encode() and Decode() calls<commit_after>package gobcodec

import (
	"encoding/gob"
	"sync"
)

type buffer struct {
	buf []byte
	n   int
}

func (b *buffer) Read(p []byte) (int, error) {
	n := copy(p, b.buf)
	b.buf = b.buf[n:]
	return n, nil
}

func (b *buffer) Write(p []byte) (int, error) {
	b.buf = append(b.buf[:b.n], p...)
	n := len(p)
	b.n += n
	return n, nil
}

type Codec struct {
	l sync.Mutex
	b *buffer
	e *gob.Encoder
	d *gob.Decoder
}

func NewCodec() *Codec {
	b := &buffer{}
	return &Codec{
		b: b,
		e: gob.NewEncoder(b),
		d: gob.NewDecoder(b),
	}
}

func (c *Codec) Register(v interface{}) error {
	c.l.Lock()
	c.b.n = 0
	if err := c.e.Encode(v); err != nil {
		return returnErr(c, err)

	}
	var z interface{}
	if err := c.d.Decode(z); err != nil {
		return returnErr(c, err)
	}
	c.l.Unlock()
	return nil
}

func (c *Codec) Encode(v interface{}, dst []byte) ([]byte, error) {
	c.l.Lock()
	c.b.buf = dst
	c.b.n = 0
	if err := c.e.Encode(v); err != nil {
		return dst, returnErr(c, err)
	}
	dst = c.b.buf
	c.l.Unlock()
	return dst, nil
}

func (c *Codec) Decode(v interface{}, src []byte) ([]byte, error) {
	c.l.Lock()
	c.b.buf = src
	if err := c.d.Decode(v); err != nil {
		return src, returnErr(c, err)
	}
	src = c.b.buf
	c.l.Unlock()
	return src, nil
}

func returnErr(c *Codec, err error) error {
	c.l.Unlock()
	return err
}
<|endoftext|>


<commit_before>package main

import (
	goopt "github.com/droundy/goopt"
	"fmt"
	"http"
	"time"
	"strings"
	"os"
	"net"
	"bufio"
	"sort"
	)

var Author = "Alexander Solovyov"
var Version = "0.1"
var Summary = "gofigure [OPTS] URL\n"

var reqs = goopt.Int([]string{"-n", "--requests"}, 1,
	"number of requests to make")
var concurrency = goopt.Int([]string{"-c", "--concurrency"}, 1,
	"concurrency level")

type someError struct {
	what string
	str  string
}

func (e *someError) String() string {
	return fmt.Sprintf(e.what, e.str)
}

type result struct {
	time int64
	err os.Error
}

type Int64Array []int64
func (p Int64Array) Len() int           { return len(p) }
func (p Int64Array) Less(i, j int) bool { return p[i] < p[j] }
func (p Int64Array) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Parse(nil)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	url, err := getURL(goopt.Args[0])
	if err != nil {
		fmt.Printf("url is invalid: %s\n", err)
		return
	}

	fmt.Printf("Statistics for requests to %s\n", goopt.Args[0])

	ch := make(chan result, *reqs)
	results := make([]result, *reqs)
	running, i, j := 0, 0, 0
	hadProgress := false

	now := time.Nanoseconds()
	for {
		if running < *concurrency && i < *reqs {
			go send(url, ch)
			running++
			i++
		} else if j < *reqs {
			results[j] = <- ch
			j++
			running--

			if j > 0 && j % 100 == 0 {
				fmt.Printf("\rCompleted %d from %d requests", j, *reqs)
				hadProgress = true
			}
		}

		if i == j && j >= *reqs {
			break
		}
	}

	if hadProgress {
		fmt.Print("\r                                  ")
	}

	printStats(results, time.Nanoseconds() - now)
}

func printStats(results []result, workTime int64) {
	times := make(Int64Array, 0)
	total := int64(0)

	for _, r := range(results) {
		if r.err == nil {
			times = append(times, r.time)
			total += r.time
		}
	}
	sort.Sort(times)

	average, median := int64(0), int64(0)
	if len(times) > 0 {
		average = total / int64(len(times))
		median = times[len(times) / 2]
	} else {
		average = 0
		median = 0
	}

	fmt.Printf(`
Total requests performed:       %d
Total failures:                 %d
Time taken for tests:           %.3f ms
Average request takes:          %.3f ms
Median request time:            %.3f ms
Average time between responses: %.3f ms
`,
		*reqs,
		*reqs - len(times),
		ms(workTime),
		ms(average),
		ms(median),
		ms(workTime / int64(*reqs)))
}

func ms(x int64) (float64) {
	return float64(x) / 1000000
}

func hasPort(s string) bool {
	return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
}

func getURL(url string) (*http.URL, os.Error) {
	URL, err := http.ParseURL(url)
	if err != nil {
		return nil, err
	}

	if URL.Scheme != "http" && URL.Scheme != "https" {
		return nil, &someError{"unsupported protocol scheme: %s", URL.Scheme}
	}

	if !hasPort(URL.Host) {
		URL.Host += ":http"
	}

	return URL, nil
}

func send(url *http.URL, out chan result) {
	var req http.Request
	req.URL = url
	rerr := func (err os.Error) result { return result{0, err} }

	now := time.Nanoseconds()
	conn, err := net.Dial("tcp", req.URL.Host)
	if err != nil {
		out <- rerr(err)
		return
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		out <- rerr(err)
		return
	}

	reader := bufio.NewReader(conn)
	resp, err := http.ReadResponse(reader, req.Method)
	out <- result{time.Nanoseconds() - now, err}

	conn.Close()
	resp.Body.Close()
}
<commit_msg>check input parameters<commit_after>package main

import (
	goopt "github.com/droundy/goopt"
	"fmt"
	"http"
	"time"
	"strings"
	"os"
	"net"
	"bufio"
	"sort"
	)

var Author = "Alexander Solovyov"
var Version = "0.1"
var Summary = "gofigure [OPTS] URL\n"

var reqs = goopt.Int([]string{"-n", "--requests"}, 1,
	"number of requests to make")
var concurrency = goopt.Int([]string{"-c", "--concurrency"}, 1,
	"concurrency level")

type someError struct {
	what string
	str  string
}

func (e *someError) String() string {
	return fmt.Sprintf(e.what, e.str)
}

type result struct {
	time int64
	err os.Error
}

type Int64Array []int64
func (p Int64Array) Len() int           { return len(p) }
func (p Int64Array) Less(i, j int) bool { return p[i] < p[j] }
func (p Int64Array) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Parse(nil)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	if *concurrency > *reqs {
		fmt.Printf("You can't have concurrency higher than number of requests\n")
		return
	}

	url, err := getURL(goopt.Args[0])
	if err != nil {
		fmt.Printf("url is invalid: %s\n", err)
		return
	}

	fmt.Printf("Statistics for requests to %s\n", goopt.Args[0])

	ch := make(chan result, *reqs)
	results := make([]result, *reqs)
	running, i, j := 0, 0, 0
	hadProgress := false

	now := time.Nanoseconds()
	for {
		if running < *concurrency && i < *reqs {
			go send(url, ch)
			running++
			i++
		} else if j < *reqs {
			results[j] = <- ch
			j++
			running--

			if j > 0 && j % 100 == 0 {
				fmt.Printf("\rCompleted %d from %d requests", j, *reqs)
				hadProgress = true
			}
		}

		if i == j && j >= *reqs {
			break
		}
	}

	if hadProgress {
		fmt.Print("\r                                  ")
	}

	printStats(results, time.Nanoseconds() - now)
}

func printStats(results []result, workTime int64) {
	times := make(Int64Array, 0)
	total := int64(0)

	for _, r := range(results) {
		if r.err == nil {
			times = append(times, r.time)
			total += r.time
		}
	}
	sort.Sort(times)

	average, median := int64(0), int64(0)
	if len(times) > 0 {
		average = total / int64(len(times))
		median = times[len(times) / 2]
	} else {
		average = 0
		median = 0
	}

	fmt.Printf(`
Total requests performed:       %d
Total failures:                 %d
Time taken for tests:           %.3f ms
Average request takes:          %.3f ms
Median request time:            %.3f ms
Average time between responses: %.3f ms
`,
		*reqs,
		*reqs - len(times),
		ms(workTime),
		ms(average),
		ms(median),
		ms(workTime / int64(*reqs)))
}

func ms(x int64) (float64) {
	return float64(x) / 1000000
}

func hasPort(s string) bool {
	return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
}

func getURL(url string) (*http.URL, os.Error) {
	URL, err := http.ParseURL(url)
	if err != nil {
		return nil, err
	}

	if URL.Scheme != "http" && URL.Scheme != "https" {
		return nil, &someError{"unsupported protocol scheme: %s", URL.Scheme}
	}

	if !hasPort(URL.Host) {
		URL.Host += ":http"
	}

	return URL, nil
}

func send(url *http.URL, out chan result) {
	var req http.Request
	req.URL = url
	rerr := func (err os.Error) result { return result{0, err} }

	now := time.Nanoseconds()
	conn, err := net.Dial("tcp", req.URL.Host)
	if err != nil {
		out <- rerr(err)
		return
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		out <- rerr(err)
		return
	}

	reader := bufio.NewReader(conn)
	resp, err := http.ReadResponse(reader, req.Method)
	out <- result{time.Nanoseconds() - now, err}

	conn.Close()
	resp.Body.Close()
}
<|endoftext|>


<commit_before>// Usage: (uh, eventually, once all of this is implemented...)
// $ googlecl help  # prints help
// $ googlecl list  # lists all available APIs
// $ googlecl describe calendar                          # describes all methods available in Calendar API
// $ googlecl describe calendar calendars.get            # describes one method in Calendar API
//
// $ googlecl calendar calendars.get --calendarId=12345  # prints JSON API response
//
// $ cat someEvent.json | googlecl calendar events.insert --calendarId=12345 --in  # inserts an event
// $ googlecl calendar events.insert --calendarId=12345 --inFile=someEvent.json    # equivalent to above
//
// TODO: Handle auth somehow.

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

var cmds = map[string]func(){
	"help":     func() { log.Fatal("TODO: implement help command") },
	"list":     func() { log.Fatal("TODO: implement list command") },
	"describe": func() { log.Fatal("TODO: implement describe command") },
}

func parseArgs(args []string) map[string]string {
	m := make(map[string]string)
	for _, a := range args {
		if strings.HasPrefix(a, "--") {
			a = a[2:]
		} else if strings.HasPrefix(a, "-") {
			a = a[1:]
		} else {
			log.Fatalf("Invalid flag format %s", a)
		}

		if !strings.Contains(a, "=") {
			m[a] = "true"
		} else {
			parts := strings.SplitN(a, "=", 2)
			m[parts[0]] = parts[1]
		}
	}
	return m
}

func main() {
	if len(os.Args) == 1 {
		cmds["help"]()
		return
	}

	cmd := os.Args[1]
	if cmd == "" {
		log.Fatal("Must specify command or API name")
	}
	if cmdFn, found := cmds[cmd]; found {
		cmdFn()
		return
	}

	method := os.Args[2]
	if method == "" {
		log.Fatal("Must specify API method to call")
	}

	apiName := cmd
	fs := parseArgs(os.Args[3:])
	v := flagValue(fs, "v")
	if v == "" {
		// Look up preferred version in Directory
		var err error
		v, err = getPreferredVersion(apiName)
		if err != nil {
			log.Fatal(err)
		}
	}
	api, err := loadApi(apiName, v)
	if err != nil {
		log.Fatal(err)
	}
	if api == nil || (len(api.Resources) == 0 && len(api.Methods) == 0) {
		log.Fatalf("Couldn't load API %s %s", apiName, v)
	}

	m := findMethod(method, *api)
	if m == nil {
		log.Fatalf("Can't find requested method %s", method)
	}

	m.call(fs, apiName, v)
}

func findMethod(method string, api Api) *Method {
	parts := strings.Split(method, ".")
	var ms map[string]Method
	rs := api.Resources
	for i := 0; i < len(parts)-1; i++ {
		r, found := rs[parts[i]]
		if !found {
			return nil
		}
		rs = r.Resources
		ms = r.Methods
	}
	lp := parts[len(parts)-1:][0]
	m, found := ms[lp]
	if !found {
		return nil
	}
	return &m
}

func flagValue(fs map[string]string, k string) string {
	v, found := fs[k]
	if !found {
		return ""
	}
	return v
}

func getPreferredVersion(api string) (string, error) {
	var d struct {
		Items []struct {
			Version string
		}
	}
	err := getAndParse(fmt.Sprintf("https://www.googleapis.com/discovery/v1/apis?preferred=true&name=%s&fields=items/version", api), &d)
	if err != nil {
		return "", err
	}
	return d.Items[0].Version, nil
}

func loadApi(api, version string) (*Api, error) {
	var a Api
	err := getAndParse(fmt.Sprintf("https://www.googleapis.com/discovery/v1/apis/%s/%s/rest", api, version), &a)
	if err != nil {
		return nil, err
	}
	return &a, nil
}

func getAndParse(url string, v interface{}) error {
	r, err := http.Get(url)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	err = json.NewDecoder(r.Body).Decode(v)
	if err != nil {
		return err
	}
	return nil
}

type Api struct {
	Resources map[string]Resource
	Methods   map[string]Method
}

type Resource struct {
	Resources map[string]Resource
	Methods   map[string]Method
}

type Method struct {
	Id, Path, HttpMethod string
	Parameters           map[string]Parameter
}

func (m Method) call(fs map[string]string, apiName, version string) {
	url := fmt.Sprintf("https://www.googleapis.com/%s/%s/%s", apiName, version, m.Path)
	for k, p := range m.Parameters {
		v := flagValue(fs, k)
		if p.Location == "path" {
			t := fmt.Sprintf("{%s}", k)
			if p.Required && v == "" {
				log.Printf("Missing required parameter %s", k)
			}
			url = strings.Replace(url, t, v, -1)
		} else if p.Location == "query" {
			if !strings.Contains(url, "?") {
				url += "?"
			}
			url += fmt.Sprintf("&%s=%s", k, v)
		}
	}

	var body io.Reader
	if v, found := fs["in"]; found && v == "true" {
		// If user passes the --in flag, use stdin as the request body
		body = os.Stdin
	} else if v, found := fs["inFile"]; found {
		// If user passes --inFile flag, open that file and use its content as request body
		var err error
		body, err = os.Open(v)
		if err != nil {
			log.Fatal(err)
		}
	}

	r, err := http.NewRequest(m.HttpMethod, url, body)
	if err != nil {
		log.Fatal(err)
	}

	client := &http.Client{}
	resp, err := client.Do(r)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		io.Copy(os.Stderr, resp.Body)
		os.Exit(1)
	} else {
		io.Copy(os.Stdout, resp.Body)
	}
}

type Parameter struct {
	Type, Description, Location string
	Required                    bool
}
<commit_msg>Handle parameters better<commit_after>// Usage: (uh, eventually, once all of this is implemented...)
// $ googlecl help  # prints help
// $ googlecl list  # lists all available APIs
// $ googlecl describe calendar                          # describes all methods available in Calendar API
// $ googlecl describe calendar calendars.get            # describes one method in Calendar API
//
// $ googlecl calendar calendars.get --calendarId=12345  # prints JSON API response
//
// $ cat someEvent.json | googlecl calendar events.insert --calendarId=12345 --in  # inserts an event
// $ googlecl calendar events.insert --calendarId=12345 --inFile=someEvent.json    # equivalent to above
//
// TODO: Handle auth somehow.

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

var cmds = map[string]func(){
	"help":     func() { log.Fatal("TODO: implement help command") },
	"list":     func() { log.Fatal("TODO: implement list command") },
	"describe": func() { log.Fatal("TODO: implement describe command") },
}

func parseArgs(args []string) map[string]string {
	m := make(map[string]string)
	for _, a := range args {
		if strings.HasPrefix(a, "--") {
			a = a[2:]
		} else if strings.HasPrefix(a, "-") {
			a = a[1:]
		} else {
			log.Fatalf("Invalid flag format %s", a)
		}

		if !strings.Contains(a, "=") {
			m[a] = "true"
		} else {
			parts := strings.SplitN(a, "=", 2)
			m[parts[0]] = parts[1]
		}
	}
	return m
}

func main() {
	if len(os.Args) == 1 {
		cmds["help"]()
		return
	}

	cmd := os.Args[1]
	if cmd == "" {
		log.Fatal("Must specify command or API name")
	}
	if cmdFn, found := cmds[cmd]; found {
		cmdFn()
		return
	}

	method := os.Args[2]
	if method == "" {
		log.Fatal("Must specify API method to call")
	}

	apiName := cmd
	fs := parseArgs(os.Args[3:])
	v := flagValue(fs, "v")
	if v == "" {
		// Look up preferred version in Directory
		var err error
		v, err = getPreferredVersion(apiName)
		if err != nil {
			log.Fatal(err)
		}
	}
	api, err := loadApi(apiName, v)
	if err != nil {
		log.Fatal(err)
	}
	if api == nil || (len(api.Resources) == 0 && len(api.Methods) == 0) {
		log.Fatalf("Couldn't load API %s %s", apiName, v)
	}

	m := findMethod(method, *api)
	if m == nil {
		log.Fatalf("Can't find requested method %s", method)
	}

	m.call(fs, apiName, v)
}

func findMethod(method string, api Api) *Method {
	parts := strings.Split(method, ".")
	var ms map[string]Method
	rs := api.Resources
	for i := 0; i < len(parts)-1; i++ {
		r, found := rs[parts[i]]
		if !found {
			return nil
		}
		rs = r.Resources
		ms = r.Methods
	}
	lp := parts[len(parts)-1:][0]
	m, found := ms[lp]
	if !found {
		return nil
	}
	return &m
}

func flagValue(fs map[string]string, k string) string {
	v, found := fs[k]
	if !found {
		return ""
	}
	return v
}

func getPreferredVersion(api string) (string, error) {
	var d struct {
		Items []struct {
			Version string
		}
	}
	err := getAndParse(fmt.Sprintf("https://www.googleapis.com/discovery/v1/apis?preferred=true&name=%s&fields=items/version", api), &d)
	if err != nil {
		return "", err
	}
	return d.Items[0].Version, nil
}

func loadApi(api, version string) (*Api, error) {
	var a Api
	err := getAndParse(fmt.Sprintf("https://www.googleapis.com/discovery/v1/apis/%s/%s/rest", api, version), &a)
	if err != nil {
		return nil, err
	}
	return &a, nil
}

func getAndParse(url string, v interface{}) error {
	r, err := http.Get(url)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	err = json.NewDecoder(r.Body).Decode(v)
	if err != nil {
		return err
	}
	return nil
}

type Api struct {
	Resources map[string]Resource
	Methods   map[string]Method
}

type Resource struct {
	Resources map[string]Resource
	Methods   map[string]Method
}

type Method struct {
	Id, Path, HttpMethod string
	Parameters           map[string]Parameter
}

func (m Method) call(fs map[string]string, apiName, version string) {
	url := fmt.Sprintf("https://www.googleapis.com/%s/%s/%s", apiName, version, m.Path)
	for k, p := range m.Parameters {
		v := flagValue(fs, k)
		if v == "" {
			v = p.Default
		}
		if v == "" {
			continue
		}
		if p.Location == "path" {
			t := fmt.Sprintf("{%s}", k)
			if p.Required && v == "" {
				log.Printf("Missing required parameter %s", k)
			}
			url = strings.Replace(url, t, v, -1)
		} else if p.Location == "query" {
			if !strings.Contains(url, "?") {
				url += "?"
			}
			url += fmt.Sprintf("&%s=%s", k, v)
		}
	}

	var body io.Reader
	if v, found := fs["in"]; found && v == "true" {
		// If user passes the --in flag, use stdin as the request body
		body = os.Stdin
	} else if v, found := fs["inFile"]; found {
		// If user passes --inFile flag, open that file and use its content as request body
		var err error
		body, err = os.Open(v)
		if err != nil {
			log.Fatal(err)
		}
	}

	r, err := http.NewRequest(m.HttpMethod, url, body)
	if err != nil {
		log.Fatal(err)
	}

	client := &http.Client{}
	resp, err := client.Do(r)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		io.Copy(os.Stderr, resp.Body)
		os.Exit(1)
	} else {
		io.Copy(os.Stdout, resp.Body)
	}
}

type Parameter struct {
	Type, Description, Location, Default string
	Required                             bool
}
<|endoftext|>


<commit_before>package graceful

import (
	"crypto/tls"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/stretchr/pat/stop"
)

// Server wraps an http.Server with graceful connection handling.
// It may be used directly in the same way as http.Server, or may
// be constructed with the global functions in this package.
//
// Example:
//	srv := &graceful.Server{
//		Timeout: 5 * time.Second,
//		Server: &http.Server{Addr: ":1234", Handler: handler},
//	}
//	srv.ListenAndServe()
type Server struct {
	*http.Server

	// Timeout is the duration to allow outstanding requests to survive
	// before forcefully terminating them.
	Timeout time.Duration

	// ConnState specifies an optional callback function that is
	// called when a client connection changes state. This is a proxy
	// to the underlying http.Server's ConnState, and the original
	// must not be set directly.
	ConnState func(net.Conn, http.ConnState)

	// ShutdownInitiated is an optional  callback function that is called
	// when shutdown is initiated. It can be used to notify the client
	// side of long lived connections (e.g. websockets) to reconnect.
	ShutdownInitiated func()

	// interrupt signals the listener to stop serving connections,
	// and the server to shut down.
	interrupt chan os.Signal

	// stopChan is the channel on which callers may block while waiting for
	// the server to stop.
	stopChan chan stop.Signal

	// stopChanOnce is used to create the stop channel on demand, once, per
	// instance.
	stopChanOnce sync.Once

	// connections holds all connections managed by graceful
	connections map[net.Conn]struct{}
}

// ensure Server conforms to stop.Stopper
var _ stop.Stopper = (*Server)(nil)

// Run serves the http.Handler with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Run(addr string, timeout time.Duration, n http.Handler) {
	srv := &Server{
		Timeout: timeout,
		Server:  &http.Server{Addr: addr, Handler: n},
	}

	if err := srv.ListenAndServe(); err != nil {
		if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
			logger := log.New(os.Stdout, "[graceful] ", 0)
			logger.Fatal(err)
		}
	}
}

// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServe(server *http.Server, timeout time.Duration) error {
	srv := &Server{Timeout: timeout, Server: server}
	return srv.ListenAndServe()
}

// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
func (srv *Server) ListenAndServe() error {
	// Create the listener so we can control their lifetime
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	return srv.Serve(l)
}

// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
	// Create the listener ourselves so we can control its lifetime
	srv := &Server{Timeout: timeout, Server: server}
	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}

	config := &tls.Config{}
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	tlsListener := tls.NewListener(conn, config)
	return srv.Serve(tlsListener)
}

// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Serve(server *http.Server, l net.Listener, timeout time.Duration) error {
	srv := &Server{Timeout: timeout, Server: server}
	return srv.Serve(l)
}

// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
func (srv *Server) Serve(listener net.Listener) error {
	// Track connection state
	add := make(chan net.Conn)
	remove := make(chan net.Conn)

	srv.Server.ConnState = func(conn net.Conn, state http.ConnState) {
		switch state {
		case http.StateNew:
			add <- conn
		case http.StateClosed, http.StateHijacked:
			remove <- conn
		}

		if srv.ConnState != nil {
			srv.ConnState(conn, state)
		}
	}

	// Manage open connections
	shutdown := make(chan chan struct{})
	kill := make(chan struct{})
	go func() {
		var done chan struct{}
		srv.connections = map[net.Conn]struct{}{}
		for {
			select {
			case conn := <-add:
				srv.connections[conn] = struct{}{}
			case conn := <-remove:
				delete(srv.connections, conn)
				if done != nil && len(srv.connections) == 0 {
					done <- struct{}{}
					return
				}
			case done = <-shutdown:
				if len(srv.connections) == 0 {
					done <- struct{}{}
					return
				}
			case <-kill:
				for k := range srv.connections {
					k.Close()
				}
				return
			}
		}
	}()

	if srv.interrupt == nil {
		srv.interrupt = make(chan os.Signal, 1)
	}

	// Set up the interrupt catch
	signal.Notify(srv.interrupt, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-srv.interrupt
		srv.SetKeepAlivesEnabled(false)
		listener.Close()

		if srv.ShutdownInitiated != nil {
			srv.ShutdownInitiated()
		}

		signal.Stop(srv.interrupt)
		close(srv.interrupt)
	}()

	// Serve with graceful listener.
	// Execution blocks here until listener.Close() is called, above.
	err := srv.Server.Serve(listener)

	// Request done notification
	done := make(chan struct{})
	shutdown <- done

	if srv.Timeout > 0 {
		select {
		case <-done:
		case <-time.After(srv.Timeout):
			close(kill)
		}
	} else {
		<-done
	}
	// Close the stopChan to wake up any blocked goroutines.
	if srv.stopChan != nil {
		close(srv.stopChan)
	}
	return err
}

// Stop instructs the type to halt operations and close
// the stop channel when it is finished.
//
// timeout is grace period for which to wait before shutting
// down the server. The timeout value passed here will override the
// timeout given when constructing the server, as this is an explicit
// command to stop the server.
func (srv *Server) Stop(timeout time.Duration) {
	srv.Timeout = timeout
	srv.interrupt <- syscall.SIGINT
}

// StopChan gets the stop channel which will block until
// stopping has completed, at which point it is closed.
// Callers should never close the stop channel.
func (srv *Server) StopChan() <-chan stop.Signal {
	srv.stopChanOnce.Do(func() {
		if srv.stopChan == nil {
			srv.stopChan = stop.Make()
		}
	})
	return srv.stopChan
}
<commit_msg>Use LimitListener if a limit is specified<commit_after>package graceful

import (
	"crypto/tls"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/stretchr/pat/stop"
	"code.google.com/p/go.net/netutil"
)

// Server wraps an http.Server with graceful connection handling.
// It may be used directly in the same way as http.Server, or may
// be constructed with the global functions in this package.
//
// Example:
//	srv := &graceful.Server{
//		Timeout: 5 * time.Second,
//		Server: &http.Server{Addr: ":1234", Handler: handler},
//	}
//	srv.ListenAndServe()
type Server struct {
	*http.Server

	// Timeout is the duration to allow outstanding requests to survive
	// before forcefully terminating them.
	Timeout time.Duration

	// Limit the number of outstanding requests
	ListenLimit int

	// ConnState specifies an optional callback function that is
	// called when a client connection changes state. This is a proxy
	// to the underlying http.Server's ConnState, and the original
	// must not be set directly.
	ConnState func(net.Conn, http.ConnState)

	// ShutdownInitiated is an optional  callback function that is called
	// when shutdown is initiated. It can be used to notify the client
	// side of long lived connections (e.g. websockets) to reconnect.
	ShutdownInitiated func()

	// interrupt signals the listener to stop serving connections,
	// and the server to shut down.
	interrupt chan os.Signal

	// stopChan is the channel on which callers may block while waiting for
	// the server to stop.
	stopChan chan stop.Signal

	// stopChanOnce is used to create the stop channel on demand, once, per
	// instance.
	stopChanOnce sync.Once

	// connections holds all connections managed by graceful
	connections map[net.Conn]struct{}
}

// ensure Server conforms to stop.Stopper
var _ stop.Stopper = (*Server)(nil)

// Run serves the http.Handler with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Run(addr string, timeout time.Duration, n http.Handler) {
	srv := &Server{
		Timeout: timeout,
		Server:  &http.Server{Addr: addr, Handler: n},
	}

	if err := srv.ListenAndServe(); err != nil {
		if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
			logger := log.New(os.Stdout, "[graceful] ", 0)
			logger.Fatal(err)
		}
	}
}

// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServe(server *http.Server, timeout time.Duration) error {
	srv := &Server{Timeout: timeout, Server: server}
	return srv.ListenAndServe()
}

// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
func (srv *Server) ListenAndServe() error {
	// Create the listener so we can control their lifetime
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	if srv.ListenLimit != 0 {
		l = netutil.LimitListener(l, srv.ListenLimit)
	}
	return srv.Serve(l)
}

// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
	// Create the listener ourselves so we can control its lifetime
	srv := &Server{Timeout: timeout, Server: server}
	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}

	config := &tls.Config{}
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	tlsListener := tls.NewListener(conn, config)
	return srv.Serve(tlsListener)
}

// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Serve(server *http.Server, l net.Listener, timeout time.Duration) error {
	srv := &Server{Timeout: timeout, Server: server}
	return srv.Serve(l)
}

// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
func (srv *Server) Serve(listener net.Listener) error {
	// Track connection state
	add := make(chan net.Conn)
	remove := make(chan net.Conn)

	srv.Server.ConnState = func(conn net.Conn, state http.ConnState) {
		switch state {
		case http.StateNew:
			add <- conn
		case http.StateClosed, http.StateHijacked:
			remove <- conn
		}

		if srv.ConnState != nil {
			srv.ConnState(conn, state)
		}
	}

	// Manage open connections
	shutdown := make(chan chan struct{})
	kill := make(chan struct{})
	go func() {
		var done chan struct{}
		srv.connections = map[net.Conn]struct{}{}
		for {
			select {
			case conn := <-add:
				srv.connections[conn] = struct{}{}
			case conn := <-remove:
				delete(srv.connections, conn)
				if done != nil && len(srv.connections) == 0 {
					done <- struct{}{}
					return
				}
			case done = <-shutdown:
				if len(srv.connections) == 0 {
					done <- struct{}{}
					return
				}
			case <-kill:
				for k := range srv.connections {
					k.Close()
				}
				return
			}
		}
	}()

	if srv.interrupt == nil {
		srv.interrupt = make(chan os.Signal, 1)
	}

	// Set up the interrupt catch
	signal.Notify(srv.interrupt, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-srv.interrupt
		srv.SetKeepAlivesEnabled(false)
		listener.Close()

		if srv.ShutdownInitiated != nil {
			srv.ShutdownInitiated()
		}

		signal.Stop(srv.interrupt)
		close(srv.interrupt)
	}()

	// Serve with graceful listener.
	// Execution blocks here until listener.Close() is called, above.
	err := srv.Server.Serve(listener)

	// Request done notification
	done := make(chan struct{})
	shutdown <- done

	if srv.Timeout > 0 {
		select {
		case <-done:
		case <-time.After(srv.Timeout):
			close(kill)
		}
	} else {
		<-done
	}
	// Close the stopChan to wake up any blocked goroutines.
	if srv.stopChan != nil {
		close(srv.stopChan)
	}
	return err
}

// Stop instructs the type to halt operations and close
// the stop channel when it is finished.
//
// timeout is grace period for which to wait before shutting
// down the server. The timeout value passed here will override the
// timeout given when constructing the server, as this is an explicit
// command to stop the server.
func (srv *Server) Stop(timeout time.Duration) {
	srv.Timeout = timeout
	srv.interrupt <- syscall.SIGINT
}

// StopChan gets the stop channel which will block until
// stopping has completed, at which point it is closed.
// Callers should never close the stop channel.
func (srv *Server) StopChan() <-chan stop.Signal {
	srv.stopChanOnce.Do(func() {
		if srv.stopChan == nil {
			srv.stopChan = stop.Make()
		}
	})
	return srv.stopChan
}
<|endoftext|>


<commit_before>package privatemessage

import (
	"errors"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"

	"github.com/koding/bongo"
)

func Init(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	return response.HandleResultAndError(req.Create())
}

func Send(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	return response.HandleResultAndError(req.Send())
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	q := request.GetQuery(u)

	if q.AccountId == 0 || q.GroupName == "" {
		return response.NewBadRequest(errors.New("request is not valid"))
	}

	channelList, err := getPrivateMessageChannels(q)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cc := models.NewChannelContainers()
	if err := cc.Fetch(channelList, q); err != nil {
		return response.NewBadRequest(err)
	}

	cc.AddIsParticipant(q.AccountId)

	// TODO this should be in the channel cache by default
	cc.AddLastMessage()
	cc.AddUnreadCount(q.AccountId)

	return response.HandleResultAndError(cc, cc.Err())
}

func getPrivateMessageChannels(q *request.Query) ([]models.Channel, error) {
	// build query for
	c := models.NewChannel()
	channelIds := make([]int64, 0)
	query := bongo.B.DB.
		Model(c).
		Table(c.TableName()).
		Select("api.channel_participant.channel_id").
		Joins("left join api.channel_participant on api.channel_participant.channel_id = api.channel.id").
		Where("api.channel_participant.account_id = ? and "+
		"api.channel.group_name = ? and "+
		"api.channel.type_constant = ? and "+
		"api.channel_participant.status_constant = ?",
		q.AccountId,
		q.GroupName,
		models.Channel_TYPE_PRIVATE_MESSAGE,
		models.ChannelParticipant_STATUS_ACTIVE)

	// add exempt clause if needed
	if !q.ShowExempt {
		query = query.Where("api.channel.meta_bits = ?", models.Safe)
	}

	query = query.Limit(q.Limit).
		Offset(q.Skip).
		Order("api.channel.updated_at DESC")

	rows, err := query.Rows()
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	for rows.Next() {
		var channelId int64
		err := rows.Scan(&channelId)
		if err == nil {
			channelIds = append(channelIds, channelId)
		}
	}

	channels, err := c.FetchByIds(channelIds)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<commit_msg>PrivateMessage: Move user's private channel fetch query into getUserChannelsQuery function<commit_after>package privatemessage

import (
	"errors"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

func Init(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	return response.HandleResultAndError(req.Create())
}

func Send(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	return response.HandleResultAndError(req.Send())
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	q := request.GetQuery(u)

	if q.AccountId == 0 || q.GroupName == "" {
		return response.NewBadRequest(errors.New("request is not valid"))
	}

	channelList, err := getPrivateMessageChannels(q)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cc := models.NewChannelContainers()
	if err := cc.Fetch(channelList, q); err != nil {
		return response.NewBadRequest(err)
	}

	cc.AddIsParticipant(q.AccountId)

	// TODO this should be in the channel cache by default
	cc.AddLastMessage()
	cc.AddUnreadCount(q.AccountId)

	return response.HandleResultAndError(cc, cc.Err())
}

func getUserChannelsQuery(q *request.Query) *gorm.DB {
	c := models.NewChannel()

	return bongo.B.DB.
		Model(c).
		Table(c.TableName()).
		Select("api.channel_participant.channel_id").
		Joins("left join api.channel_participant on api.channel_participant.channel_id = api.channel.id").
		Where("api.channel_participant.account_id = ? and "+
		"api.channel.group_name = ? and "+
		"api.channel.type_constant = ? and "+
		"api.channel_participant.status_constant = ?",
		q.AccountId,
		q.GroupName,
		models.Channel_TYPE_PRIVATE_MESSAGE,
		models.ChannelParticipant_STATUS_ACTIVE)
}

func getPrivateMessageChannels(q *request.Query) ([]models.Channel, error) {
	// build query for
	if q.AccountId == 0 || q.GroupName == "" {
		return nil, errors.New("request is not valid")
	}

	c := models.NewChannel()
	channelIds := make([]int64, 0)

	query := getUserChannelsQuery(q)

	if q.Name != "" {
		query = query.Where("api.channel.purpose like ?", "%"+q.Name+"%")
	}

	// add exempt clause if needed
	if !q.ShowExempt {
		query = query.Where("api.channel.meta_bits = ?", models.Safe)
	}

	query = query.Limit(q.Limit).
		Offset(q.Skip).
		Order("api.channel.updated_at DESC")

	rows, err := query.Rows()
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	for rows.Next() {
		var channelId int64
		err := rows.Scan(&channelId)
		if err == nil {
			channelIds = append(channelIds, channelId)
		}
	}

	channels, err := c.FetchByIds(channelIds)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<|endoftext|>


<commit_before>package pixel

import (
	"image/color"

	"github.com/faiface/pixel/pixelgl"
	"github.com/go-gl/mathgl/mgl32"
	"github.com/pkg/errors"
)

// Drawer is anything that can be drawn. It's by no means a drawer inside your table.
//
// Drawer consists of a single methods: Draw. Draw methods takes any number of Transform arguments. It applies these
// transforms in the reverse order and finally draws something transformed by these transforms.
//
// Example:
//
//   // object is a drawer
//   object.Draw(pixel.Position(pixel.V(100, 100).Rotate(math.Pi / 2)))
//   camera := pixel.Camera(pixel.V(0, 0), pixel.V(500, 500), pixel.V(window.Size()))
//   object.Draw(camera, pixel.Position(0).Scale(0.5))
type Drawer interface {
	Draw(t ...Transform)
}

// Deleter is anything that can be deleted. All graphics objects that have some associated video memory
// are deleters. It is necessary to call Delete when you're done with an object, otherwise you're going
// to have video memory leaks.
type Deleter interface {
	Delete()
}

// DrawDeleter combines Drawer and Deleter interfaces.
type DrawDeleter interface {
	Drawer
	Deleter
}

// PolygonColor is a polygon shape filled with a single color.
type PolygonColor struct {
	parent pixelgl.Doer
	color  color.Color
	points []Vec
	va     *pixelgl.VertexArray
}

// NewPolygonColor creates a new polygon shape filled with a single color. Parent is an object that this shape belongs to,
// such as a window, or a graphical effect.
func NewPolygonColor(parent pixelgl.Doer, c color.Color, points ...Vec) *PolygonColor {
	pc := &PolygonColor{
		parent: parent,
		color:  c,
		points: points,
	}

	var format pixelgl.VertexFormat
	parent.Do(func(ctx pixelgl.Context) {
		format = ctx.Shader().VertexFormat()
	})

	var err error
	pc.va, err = pixelgl.NewVertexArray(parent, format, pixelgl.TriangleFanDrawMode, pixelgl.DynamicUsage, len(points))
	if err != nil {
		panic(errors.Wrap(err, "failed to create polygon"))
	}

	for i, p := range points {
		pc.va.SetVertexAttributeVec2(i, pixelgl.Position, mgl32.Vec2{float32(p.X()), float32(p.Y())})
		pc.va.SetVertexAttributeVec4(i, pixelgl.Color, mgl32.Vec4{1, 1, 1, 1})
	}

	return pc
}

// Count returns the number of points in a polygon.
func (pc *PolygonColor) Count() int {
	return len(pc.points)
}

// SetColor changes the color of a polygon to c.
func (pc *PolygonColor) SetColor(c color.Color) {
	pc.color = c
}

// Color returns the current color of a polygon.
func (pc *PolygonColor) Color() color.Color {
	return pc.color
}

// SetPoint changes the position of a point in a polygon.
//
// If the index is out of range, this function panics.
func (pc *PolygonColor) SetPoint(i int, point Vec) {
	pc.points[i] = point
	pc.va.SetVertexAttributeVec2(i, pixelgl.Position, mgl32.Vec2{float32(point.X()), float32(point.Y())})
}

// Point returns the position of a point in a polygon.
//
// If the index is out of range, this function panics.
func (pc *PolygonColor) Point(i int) Vec {
	return pc.points[i]
}

// Draw draws a polygon transformed by the supplied transforms applied in the reverse order.
func (pc *PolygonColor) Draw(t ...Transform) {
	mat := mgl32.Ident3()
	for i := range t {
		mat = mat.Mul3(t[i].Mat3())
	}

	var shader *pixelgl.Shader
	pc.parent.Do(func(ctx pixelgl.Context) {
		shader = ctx.Shader()
	})

	r, g, b, a := colorToRGBA(pc.color)
	shader.SetUniformVec4(pixelgl.MaskColor, mgl32.Vec4{r, g, b, a})
	shader.SetUniformMat3(pixelgl.Transform, mat)
	shader.SetUniformInt(pixelgl.IsTexture, 0)

	pc.va.Draw()
}

// Delete destroys a polygon shape and releases it's video memory. Do not use this shape after calling Delete.
func (pc *PolygonColor) Delete() {
	pc.va.Delete()
}
<commit_msg>add ellipse shape<commit_after>package pixel

import (
	"image/color"
	"math"

	"github.com/faiface/pixel/pixelgl"
	"github.com/go-gl/mathgl/mgl32"
	"github.com/pkg/errors"
)

// Drawer is anything that can be drawn. It's by no means a drawer inside your table.
//
// Drawer consists of a single methods: Draw. Draw methods takes any number of Transform arguments. It applies these
// transforms in the reverse order and finally draws something transformed by these transforms.
//
// Example:
//
//   // object is a drawer
//   object.Draw(pixel.Position(pixel.V(100, 100).Rotate(math.Pi / 2)))
//   camera := pixel.Camera(pixel.V(0, 0), pixel.V(500, 500), pixel.V(window.Size()))
//   object.Draw(camera, pixel.Position(0).Scale(0.5))
type Drawer interface {
	Draw(t ...Transform)
}

// Deleter is anything that can be deleted. All graphics objects that have some associated video memory
// are deleters. It is necessary to call Delete when you're done with an object, otherwise you're going
// to have video memory leaks.
type Deleter interface {
	Delete()
}

// DrawDeleter combines Drawer and Deleter interfaces.
type DrawDeleter interface {
	Drawer
	Deleter
}

// PolygonColor is a polygon shape filled with a single color.
type PolygonColor struct {
	parent pixelgl.Doer
	color  color.Color
	points []Vec
	va     *pixelgl.VertexArray
}

// NewPolygonColor creates a new polygon shape filled with a single color. Parent is an object that this shape belongs to,
// such as a window, or a graphics effect.
func NewPolygonColor(parent pixelgl.Doer, c color.Color, points ...Vec) *PolygonColor {
	pc := &PolygonColor{
		parent: parent,
		color:  c,
		points: points,
	}

	var format pixelgl.VertexFormat
	parent.Do(func(ctx pixelgl.Context) {
		format = ctx.Shader().VertexFormat()
	})

	var err error
	pc.va, err = pixelgl.NewVertexArray(
		parent,
		format,
		pixelgl.TriangleFanDrawMode,
		pixelgl.DynamicUsage,
		len(points),
	)
	if err != nil {
		panic(errors.Wrap(err, "failed to create polygon"))
	}

	for i, p := range points {
		pc.va.SetVertexAttributeVec2(
			i,
			pixelgl.Position,
			mgl32.Vec2{
				float32(p.X()),
				float32(p.Y()),
			},
		)
		pc.va.SetVertexAttributeVec4(
			i,
			pixelgl.Color,
			mgl32.Vec4{1, 1, 1, 1},
		)
	}

	return pc
}

// Count returns the number of points in a polygon.
func (pc *PolygonColor) Count() int {
	return len(pc.points)
}

// SetColor changes the color of a polygon to c.
func (pc *PolygonColor) SetColor(c color.Color) {
	pc.color = c
}

// Color returns the current color of a polygon.
func (pc *PolygonColor) Color() color.Color {
	return pc.color
}

// SetPoint changes the position of a point in a polygon.
//
// If the index is out of range, this function panics.
func (pc *PolygonColor) SetPoint(i int, point Vec) {
	pc.points[i] = point
	pc.va.SetVertexAttributeVec2(i, pixelgl.Position, mgl32.Vec2{float32(point.X()), float32(point.Y())})
}

// Point returns the position of a point in a polygon.
//
// If the index is out of range, this function panics.
func (pc *PolygonColor) Point(i int) Vec {
	return pc.points[i]
}

// Draw draws a polygon transformed by the supplied transforms applied in the reverse order.
func (pc *PolygonColor) Draw(t ...Transform) {
	mat := mgl32.Ident3()
	for i := range t {
		mat = mat.Mul3(t[i].Mat3())
	}

	var shader *pixelgl.Shader
	pc.parent.Do(func(ctx pixelgl.Context) {
		shader = ctx.Shader()
	})

	r, g, b, a := colorToRGBA(pc.color)
	shader.SetUniformVec4(pixelgl.MaskColor, mgl32.Vec4{r, g, b, a})
	shader.SetUniformMat3(pixelgl.Transform, mat)
	shader.SetUniformInt(pixelgl.IsTexture, 0)

	pc.va.Draw()
}

// Delete destroys a polygon shape and releases it's video memory. Do not use this shape after calling Delete.
func (pc *PolygonColor) Delete() {
	pc.va.Delete()
}

// EllipseColor is an ellipse shape filled with a single color.
type EllipseColor struct {
	parent pixelgl.Doer
	color  color.Color
	radius Vec
	fill   float64
	va     *pixelgl.VertexArray
}

// NewEllipseColor creates a new ellipse shape filled with a single color. Parent is an object that this shape belongs to,
// such as a window, or a graphics effect. Fill should be a number between 0 and 1 which specifies how much of the ellipse will
// be filled (from the outside). The value of 1 means that the whole ellipse is filled. The value of 0 means that none of the
// ellipse is filled (which makes the ellipse invisible).
func NewEllipseColor(parent pixelgl.Doer, c color.Color, radius Vec, fill float64) *EllipseColor {
	const n = 256

	ec := &EllipseColor{
		parent: parent,
		color:  c,
		radius: radius,
		fill:   fill,
	}

	var format pixelgl.VertexFormat
	parent.Do(func(ctx pixelgl.Context) {
		format = ctx.Shader().VertexFormat()
	})

	var err error
	ec.va, err = pixelgl.NewVertexArray(
		parent,
		format,
		pixelgl.TriangleStripDrawMode,
		pixelgl.DynamicUsage,
		(n+1)*2,
	)
	if err != nil {
		panic(errors.Wrap(err, "failed to create circle"))
	}

	for k := 0; k < n+1; k++ {
		i, j := k*2, k*2+1
		angle := math.Pi * 2 * float64(k%n) / n
		ec.va.SetVertexAttributeVec2(
			i,
			pixelgl.Position,
			mgl32.Vec2{
				float32(math.Cos(angle)),
				float32(math.Sin(angle)),
			},
		)
		ec.va.SetVertexAttributeVec4(
			i,
			pixelgl.Color,
			mgl32.Vec4{1, 1, 1, 1},
		)
		ec.va.SetVertexAttributeVec2(
			j,
			pixelgl.Position,
			mgl32.Vec2{
				float32(math.Cos(angle) * (1 - fill)),
				float32(math.Sin(angle) * (1 - fill)),
			},
		)
		ec.va.SetVertexAttributeVec4(
			j,
			pixelgl.Color,
			mgl32.Vec4{1, 1, 1, 1},
		)
	}

	return ec
}

// SetColor changes the color of an ellipse.
func (ec *EllipseColor) SetColor(c color.Color) {
	ec.color = c
}

// Color returns the current color of an ellipse.
func (ec *EllipseColor) Color() color.Color {
	return ec.color
}

// SetRadius sets the radius (which can be different in X and Y axis) of an ellipse.
func (ec *EllipseColor) SetRadius(radius Vec) {
	ec.radius = radius
}

// Radius returns the current radius of an ellipse.
func (ec *EllipseColor) Radius() Vec {
	return ec.radius
}

// Draw dras an ellipse transformed by the supplied transforms applied in the reverse order.
func (ec *EllipseColor) Draw(t ...Transform) {
	mat := mgl32.Ident3()
	for i := range t {
		mat = mat.Mul3(t[i].Mat3())
	}
	mat = mat.Mul3(mgl32.Scale2D(float32(ec.radius.X()), float32(ec.radius.Y())))

	var shader *pixelgl.Shader
	ec.parent.Do(func(ctx pixelgl.Context) {
		shader = ctx.Shader()
	})

	r, g, b, a := colorToRGBA(ec.color)
	shader.SetUniformVec4(pixelgl.MaskColor, mgl32.Vec4{r, g, b, a})
	shader.SetUniformMat3(pixelgl.Transform, mat)
	shader.SetUniformInt(pixelgl.IsTexture, 0)

	ec.va.Draw()
}
<|endoftext|>


<commit_before>package db

import (
	"database/sql"
	"log"
	"os"

	_ "github.com/mattn/go-sqlite3"
)

type Store struct {
	db *sql.DB
}

func (s *Store) Open(database string) {
	db, err := sql.Open("sqlite3", database)
	if err != nil {
		log.Fatal(err)
	}
	s.db = db

	if _, err := os.Stat(database); err != nil {
		if os.IsNotExist(err) {
			s.createDatabase()
		}
	}
}

func (s *Store) Close() {
	s.db.Close()
}

func (s *Store) createDatabase() {

	// TODO: create all tables in one variable when multiple statements will
	// be supported see https://github.com/mattn/go-sqlite3/issues/60
	sql_people_table := `CREATE TABLE people (
	id INTEGER NOT NULL PRIMARY KEY autoincrement,
	name TEXT
);`

	sql_quotes_table := `CREATE TABLE quotes (
	id INTEGER NOT NULL PRIMARY KEY autoincrement,
	person_id INTEGER NOT NULL,
	quote TEXT,
	FOREIGN KEY(person_id) REFERENCES people(id)
);`

	sql_alias_table := `CREATE TABLE alias (
	person_id INTEGER NOT NULL,
	alias TEXT,
	FOREIGN KEY(person_id) REFERENCES people(id)
);`

	s.db.Exec(sql_people_table)
	s.db.Exec(sql_quotes_table)
	s.db.Exec(sql_alias_table)
}

func (s *Store) getPerson(name string) (id int) {
	query_people := `SELECT id FROM people WHERE name = ?`
	query_alias := `SELECT person_id FROM alias WHERE alias = ?`

	s.db.QueryRow(query_people, name).Scan(&id)
	if id == 0 {
		s.db.QueryRow(query_alias, name).Scan(&id)
	}

	return
}

func (s *Store) GetQuote(person string) (quote string) {
	var q string
	query := `SELECT quote FROM quotes WHERE person_id = ?
		ORDER BY RANDOM() LIMIT 1;`
	s.db.QueryRow(query, s.getPerson(person)).Scan(&q)
	return q
}
<commit_msg>Made text columns case insensitive<commit_after>package db

import (
	"database/sql"
	"log"
	"os"

	_ "github.com/mattn/go-sqlite3"
)

type Store struct {
	db *sql.DB
}

func (s *Store) Open(database string) {
	db, err := sql.Open("sqlite3", database)
	if err != nil {
		log.Fatal(err)
	}
	s.db = db

	if _, err := os.Stat(database); err != nil {
		if os.IsNotExist(err) {
			s.createDatabase()
		}
	}
}

func (s *Store) Close() {
	s.db.Close()
}

func (s *Store) createDatabase() {

	// TODO: create all tables in one variable when multiple statements will
	// be supported see https://github.com/mattn/go-sqlite3/issues/60
	sql_people_table := `CREATE TABLE people (
	id INTEGER NOT NULL PRIMARY KEY autoincrement,
	name TEXT COLLATE NOCASE
);`

	sql_quotes_table := `CREATE TABLE quotes (
	id INTEGER NOT NULL PRIMARY KEY autoincrement,
	person_id INTEGER NOT NULL,
	quote TEXT COLLATE NOCASE,
	FOREIGN KEY(person_id) REFERENCES people(id)
);`

	sql_alias_table := `CREATE TABLE alias (
	person_id INTEGER NOT NULL,
	alias TEXT COLLATE NOCASE,
	FOREIGN KEY(person_id) REFERENCES people(id)
);`

	s.db.Exec(sql_people_table)
	s.db.Exec(sql_quotes_table)
	s.db.Exec(sql_alias_table)
}

func (s *Store) getPerson(name string) (id int) {
	query_people := `SELECT id FROM people WHERE name = ?`
	query_alias := `SELECT person_id FROM alias WHERE alias = ?`

	s.db.QueryRow(query_people, name).Scan(&id)
	if id == 0 {
		s.db.QueryRow(query_alias, name).Scan(&id)
	}

	return
}

func (s *Store) GetQuote(person string) (quote string) {
	var q string
	query := `SELECT quote FROM quotes WHERE person_id = ?
		ORDER BY RANDOM() LIMIT 1;`
	s.db.QueryRow(query, s.getPerson(person)).Scan(&q)
	return q
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package common

import (
	"github.com/webx-top/db"
	"github.com/webx-top/echo"
	"github.com/webx-top/pagination"
)

// Lister 页码分页列表查询接口
type Lister interface {
	List(recv interface{}, mw func(db.Result) db.Result, page, size int, args ...interface{}) (func() int64, error)
}

// OffsetLister 偏移值分页列表查询接口
type OffsetLister interface {
	ListByOffset(recv interface{}, mw func(db.Result) db.Result, offset, size int, args ...interface{}) (func() int64, error)
}

// NewLister 创建页码分页列表查询
func NewLister(list Lister, recv interface{}, mw func(db.Result) db.Result, args ...interface{}) *List {
	return &List{
		mw:   mw,
		recv: recv,
		ls:   list,
		args: args,
	}
}

// List 页码分页列表封装
type List struct {
	recv interface{}
	mw   func(db.Result) db.Result
	ls   Lister
	args []interface{}
}

// List 分页查询
func (f *List) List(recv interface{}, mw func(db.Result) db.Result, page, size int, args ...interface{}) (func() int64, error) {
	if recv == nil {
		recv = f.recv
	}
	if mw == nil {
		mw = f.mw
	}
	return f.ls.List(recv, mw, page, size, f.args...)
}

// Paging 分页信息
func (f *List) Paging(ctx echo.Context, varSuffix ...string) (*pagination.Pagination, error) {
	return PagingWithLister(ctx, f, varSuffix...)
}

// NewOffsetLister 创建偏移值分页列表查询
func NewOffsetLister(list OffsetLister, recv interface{}, mw func(db.Result) db.Result, args ...interface{}) *OffsetList {
	return &OffsetList{
		mw:   mw,
		recv: recv,
		ls:   list,
		args: args,
	}
}

// OffsetList 偏移值分页列表查询封装
type OffsetList struct {
	recv interface{}
	mw   func(db.Result) db.Result
	ls   OffsetLister
	args []interface{}
}

// ListByOffset 分页查询
func (f *OffsetList) ListByOffset(recv interface{}, mw func(db.Result) db.Result, offset, size int, args ...interface{}) (func() int64, error) {
	if recv == nil {
		recv = f.recv
	}
	if mw == nil {
		mw = f.mw
	}
	if len(args) < 1 {
		args = f.args
	}
	return f.ls.ListByOffset(recv, mw, offset, size, args...)
}

// ChunkList 分批查询列表
func (f *OffsetList) ChunkList(eachPageCallback func() error, size int, offset int) error {
	cnt, err := f.ListByOffset(nil, nil, offset, size)
	if err != nil {
		if err == db.ErrNoMoreRows {
			return nil
		}
		return err
	}
	for total := cnt(); int64(offset) < total; offset += size {
		if offset > 0 {
			_, err = f.ListByOffset(nil, nil, offset, size)
			if err != nil {
				if err == db.ErrNoMoreRows {
					return nil
				}
				return err
			}
		}
		err = eachPageCallback()
		if err != nil {
			return err
		}
	}
	return err
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package common

import (
	"github.com/webx-top/db"
	"github.com/webx-top/echo"
	"github.com/webx-top/pagination"
)

// Lister 页码分页列表查询接口
type Lister interface {
	List(recv interface{}, mw func(db.Result) db.Result, page, size int, args ...interface{}) (func() int64, error)
}

// OffsetLister 偏移值分页列表查询接口
type OffsetLister interface {
	ListByOffset(recv interface{}, mw func(db.Result) db.Result, offset, size int, args ...interface{}) (func() int64, error)
}

// NewLister 创建页码分页列表查询
func NewLister(list Lister, recv interface{}, mw func(db.Result) db.Result, args ...interface{}) *List {
	return &List{
		mw:   mw,
		recv: recv,
		ls:   list,
		args: args,
	}
}

// List 页码分页列表封装
type List struct {
	recv interface{}
	mw   func(db.Result) db.Result
	ls   Lister
	args []interface{}
}

// List 分页查询
func (f *List) List(recv interface{}, mw func(db.Result) db.Result, page, size int, args ...interface{}) (func() int64, error) {
	if recv == nil {
		recv = f.recv
	}
	if mw == nil {
		mw = f.mw
	}
	return f.ls.List(recv, mw, page, size, f.args...)
}

// Paging 分页信息
func (f *List) Paging(ctx echo.Context, varSuffix ...string) (*pagination.Pagination, error) {
	return PagingWithLister(ctx, f, varSuffix...)
}

// DataTable 分页信息
func (f *List) DataTable(ctx echo.Context, args ...string) (echo.H, error) {
	pageRowsKey := `length`
	totalRowsKey := `totalrows`
	offsetKey := `start`
	switch len(args) {
	case 3:
		pageRowsKey = args[2]
		fallthrough
	case 2:
		totalRowsKey = args[1]
		fallthrough
	case 1:
		offsetKey = args[0]
	}
	size := ctx.Formx(pageRowsKey).Int()
	offset := ctx.Formx(offsetKey).Int()
	if size < 1 || size > 1000 {
		size = 10
	}
	if offset < 0 {
		offset = 0
	}
	page := (offset + size) / size
	totalRows := ctx.Formx(totalRowsKey).Int()
	cnt, err := f.List(nil, nil, page, size)
	if totalRows < 1 {
		totalRows = int(cnt())
	}
	data := echo.H{
		"draw":            ctx.Form(`draw`),
		"recordsTotal":    totalRows,
		"recordsFiltered": totalRows,
		"list":            f.recv,
	}
	return data, err
}

// NewOffsetLister 创建偏移值分页列表查询
func NewOffsetLister(list OffsetLister, recv interface{}, mw func(db.Result) db.Result, args ...interface{}) *OffsetList {
	return &OffsetList{
		mw:   mw,
		recv: recv,
		ls:   list,
		args: args,
	}
}

// OffsetList 偏移值分页列表查询封装
type OffsetList struct {
	recv interface{}
	mw   func(db.Result) db.Result
	ls   OffsetLister
	args []interface{}
}

// ListByOffset 分页查询
func (f *OffsetList) ListByOffset(recv interface{}, mw func(db.Result) db.Result, offset, size int, args ...interface{}) (func() int64, error) {
	if recv == nil {
		recv = f.recv
	}
	if mw == nil {
		mw = f.mw
	}
	if len(args) < 1 {
		args = f.args
	}
	return f.ls.ListByOffset(recv, mw, offset, size, args...)
}

// ChunkList 分批查询列表
func (f *OffsetList) ChunkList(eachPageCallback func() error, size int, offset int) error {
	cnt, err := f.ListByOffset(nil, nil, offset, size)
	if err != nil {
		if err == db.ErrNoMoreRows {
			return nil
		}
		return err
	}
	for total := cnt(); int64(offset) < total; offset += size {
		if offset > 0 {
			_, err = f.ListByOffset(nil, nil, offset, size)
			if err != nil {
				if err == db.ErrNoMoreRows {
					return nil
				}
				return err
			}
		}
		err = eachPageCallback()
		if err != nil {
			return err
		}
	}
	return err
}
<|endoftext|>


<commit_before>package skl

import (
	"reflect"
	"strings"
	"testing"
)

// Ensure the parser can parse strings into Statement ASTs.
func TestParser_ParseStatement(t *testing.T) {

	var tests = []struct {
		skip bool
		s    string
		stmt Statement
		err  string
	}{
		{
			s:    `USE acme.example`,
			stmt: &UseStatement{Name: "acme.example"},
		},

		// Errors
		{s: `USE acme.example.`, err: `found EOF, expected identifier at line 1, char 18`},
		{s: `USE acme.example. `, err: `found WS, expected identifier at line 1, char 18`},
	}

	for i, tt := range tests {
		if tt.skip {
			t.Logf("skipping test of '%s'", tt.s)
			continue
		}
		stmt, err := NewParser(strings.NewReader(tt.s)).ParseStatement()

		if !reflect.DeepEqual(tt.err, errstring(err)) {
			t.Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == "" && !reflect.DeepEqual(tt.stmt, stmt) {
			// t.Logf("\nexp=%s\ngot=%s\n", mustMarshalJSON(tt.stmt), mustMarshalJSON(stmt))
			t.Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.stmt, stmt)
		}
	}
}

// errstring converts an error to its string representation.
func errstring(err error) string {
	if err != nil {
		return err.Error()
	}
	return ""
}
<commit_msg>Increase parser coverage<commit_after>package skl

import (
	"reflect"
	"strings"
	"testing"

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

// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestParserTestSuite(t *testing.T) {
	suite.Run(t, new(ParserTestSuite))
}

// ParserTestSuite executes all the parser tests
type ParserTestSuite struct {
	suite.Suite
}

func (suite *ParserTestSuite) SetupTest() {
}

func (suite *ParserTestSuite) TearDownTest() {
}

// Ensure the parser can parse strings into Statement ASTs.
func (suite *ParserTestSuite) TestStatements() {
	var tests = []struct {
		skip bool
		s    string
		stmt Statement
		err  string
	}{
		{
			s:    `USE acme.example`,
			stmt: &UseStatement{Name: "acme.example"},
		},

		// Errors
		{s: `a bad statement.`, err: `found a, expected USE at line 1, char 1`},
		{s: `USE `, err: `found EOF, expected namespace at line 1, char 6`},
		{s: `USE acme.example.`, err: `found EOF, expected identifier at line 1, char 18`},
		{s: `USE acme.example. `, err: `found WS, expected identifier at line 1, char 18`},
	}

	for i, tt := range tests {
		if tt.skip {
			suite.T().Logf("skipping test of '%s'", tt.s)
			continue
		}
		stmt, err := NewParser(strings.NewReader(tt.s)).ParseStatement()

		if !reflect.DeepEqual(tt.err, errstring(err)) {
			suite.T().Errorf("%d. %q: error mismatch:\n  exp=%s\n  got=%s\n\n", i, tt.s, tt.err, err)
		} else if tt.err == "" && !reflect.DeepEqual(tt.stmt, stmt) {
			suite.T().Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.stmt, stmt)
		}
	}
}

// errstring converts an error to its string representation.
func errstring(err error) string {
	if err != nil {
		return err.Error()
	}
	return ""
}
<|endoftext|>


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

// Package bam implements BAM file format reading and writing. The SAM format
// is described in the SAM specification.
//
// http://samtools.github.io/hts-specs/SAMv1.pdf
package bam
<commit_msg>Fix bam package doc<commit_after>// Copyright ©2012 The bíogo.bam Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package bam implements BAM file format reading, writing and indexing.
// The BAM format is described in the SAM specification.
//
// http://samtools.github.io/hts-specs/SAMv1.pdf
package bam
<|endoftext|>


<commit_before>package main

import (
	"strconv"
	"strings"
	"time"

	"github.com/golang/glog"

	"github.com/BotBotMe/botbot-bot/common"
	"github.com/BotBotMe/botbot-bot/dispatch"
	"github.com/BotBotMe/botbot-bot/line"
	"github.com/BotBotMe/botbot-bot/network"
	"github.com/BotBotMe/botbot-bot/user"
)

/*
 * BOTBOT - the main object
 */

type BotBot struct {
	netMan     *network.NetworkManager
	dis        *dispatch.Dispatcher
	users      *user.UserManager
	storage    common.Storage
	queue      common.Queue
	fromServer chan *line.Line
	fromBus    chan string
}

func NewBotBot(storage common.Storage, queue common.Queue) *BotBot {

	fromServer := make(chan *line.Line)
	fromBus := make(chan string)

	netMan := network.NewNetworkManager(storage, fromServer)
	netMan.RefreshChatbots()
	// TODO (yml) We might be able to get rid of this goroutine
	//go netMan.MonitorChatbots()

	dis := dispatch.NewDispatcher(queue)

	users := user.NewUserManager()

	return &BotBot{
		netMan:     netMan,
		dis:        dis,
		users:      users,
		queue:      queue,
		storage:    storage,
		fromServer: fromServer,
		fromBus:    fromBus}
}

// Listen for incoming commands
func (self *BotBot) listen(queueName string) {

	var msg []byte
	var err error

	for {
		_, msg, err = self.queue.Blpop([]string{queueName}, 0)
		if err != nil {
			glog.Fatal("Error reading (BLPOP) from queue. ", err)
		}
		if len(msg) != 0 {
			if glog.V(1) {
				glog.Infoln("Command: ", string(msg))
			}
			self.fromBus <- string(msg)
		}
	}
}

func (self *BotBot) mainLoop() {

	go self.recordUserCounts()

	var busCommand string
	var args string
	for {
		select {

		case serverLine, ok := <-self.fromServer:
			if !ok {
				// Channel is closed, we're offline. Stop.
				break
			}

			switch serverLine.Command {

			// QUIT and NICK don't have a channel name
			// They need to go to all channels the user is in
			case "QUIT", "NICK":
				self.dis.DispatchMany(serverLine, self.users.In(serverLine.User))

			default:
				self.dis.Dispatch(serverLine)
			}

			self.users.Act(serverLine)

		case busMessage, ok := <-self.fromBus:
			if !ok {
				break
			}

			parts := strings.SplitN(busMessage, " ", 2)
			busCommand = parts[0]
			if len(parts) > 1 {
				args = parts[1]
			}

			self.handleCommand(busCommand, args)
		}
	}
}

// Handle a command send from a plugin.
// Current commands:
//  - WRITE <chatbotid> <channel> <msg>: Send message to server
//  - REFRESH: Reload plugin configuration
func (self *BotBot) handleCommand(cmd string, args string) {
	if glog.V(2) {
		glog.Infoln("HandleCommand:", cmd)
	}
	switch cmd {
	case "WRITE":
		parts := strings.SplitN(args, " ", 3)
		chatbotId, err := strconv.Atoi(parts[0])
		if err != nil {
			if glog.V(1) {
				glog.Errorln("Invalid chatbot id: ", parts[0])
			}
			return
		}

		self.netMan.Send(chatbotId, parts[1], parts[2])

		// Now send it back to ourself, so other plugins see it
		internalLine := &line.Line{
			ChatBotId: chatbotId,
			Raw:       args,
			User:      self.netMan.GetUserByChatbotId(chatbotId),
			Command:   "PRIVMSG",
			Received:  time.Now().UTC().Format(time.RFC3339Nano),
			Content:   parts[2],
			Channel:   strings.TrimSpace(parts[1])}

		self.dis.Dispatch(internalLine)

	case "REFRESH":
		if glog.V(1) {
			glog.Infoln("Reloading configuration from database")
		}
		self.netMan.RefreshChatbots()
	}
}

// Writes the number of users per channel, every hour. Run in go routine.
func (self *BotBot) recordUserCounts() {

	for {

		for ch, _ := range self.users.Channels() {
			self.storage.SetCount(ch, self.users.Count(ch))
		}
		time.Sleep(1 * time.Hour)
	}
}

// Stop
func (self *BotBot) shutdown() {
	self.netMan.Shutdown()
}
<commit_msg>Temporary remove self.recordUserCounts() from the code base because I think it is leaking postgres connection<commit_after>package main

import (
	"strconv"
	"strings"
	"time"

	"github.com/golang/glog"

	"github.com/BotBotMe/botbot-bot/common"
	"github.com/BotBotMe/botbot-bot/dispatch"
	"github.com/BotBotMe/botbot-bot/line"
	"github.com/BotBotMe/botbot-bot/network"
	"github.com/BotBotMe/botbot-bot/user"
)

/*
 * BOTBOT - the main object
 */

type BotBot struct {
	netMan     *network.NetworkManager
	dis        *dispatch.Dispatcher
	users      *user.UserManager
	storage    common.Storage
	queue      common.Queue
	fromServer chan *line.Line
	fromBus    chan string
}

func NewBotBot(storage common.Storage, queue common.Queue) *BotBot {

	fromServer := make(chan *line.Line)
	fromBus := make(chan string)

	netMan := network.NewNetworkManager(storage, fromServer)
	netMan.RefreshChatbots()
	// TODO (yml) We might be able to get rid of this goroutine
	//go netMan.MonitorChatbots()

	dis := dispatch.NewDispatcher(queue)

	users := user.NewUserManager()

	return &BotBot{
		netMan:     netMan,
		dis:        dis,
		users:      users,
		queue:      queue,
		storage:    storage,
		fromServer: fromServer,
		fromBus:    fromBus}
}

// Listen for incoming commands
func (self *BotBot) listen(queueName string) {

	var msg []byte
	var err error

	for {
		_, msg, err = self.queue.Blpop([]string{queueName}, 0)
		if err != nil {
			glog.Fatal("Error reading (BLPOP) from queue. ", err)
		}
		if len(msg) != 0 {
			if glog.V(1) {
				glog.Infoln("Command: ", string(msg))
			}
			self.fromBus <- string(msg)
		}
	}
}

func (self *BotBot) mainLoop() {

	// TODO (yml) comment out self.recordUserCounts because I think it is
	// leaking postgres connection.
	//go self.recordUserCounts()

	var busCommand string
	var args string
	for {
		select {

		case serverLine, ok := <-self.fromServer:
			if !ok {
				// Channel is closed, we're offline. Stop.
				break
			}

			switch serverLine.Command {

			// QUIT and NICK don't have a channel name
			// They need to go to all channels the user is in
			case "QUIT", "NICK":
				self.dis.DispatchMany(serverLine, self.users.In(serverLine.User))

			default:
				self.dis.Dispatch(serverLine)
			}

			self.users.Act(serverLine)

		case busMessage, ok := <-self.fromBus:
			if !ok {
				break
			}

			parts := strings.SplitN(busMessage, " ", 2)
			busCommand = parts[0]
			if len(parts) > 1 {
				args = parts[1]
			}

			self.handleCommand(busCommand, args)
		}
	}
}

// Handle a command send from a plugin.
// Current commands:
//  - WRITE <chatbotid> <channel> <msg>: Send message to server
//  - REFRESH: Reload plugin configuration
func (self *BotBot) handleCommand(cmd string, args string) {
	if glog.V(2) {
		glog.Infoln("HandleCommand:", cmd)
	}
	switch cmd {
	case "WRITE":
		parts := strings.SplitN(args, " ", 3)
		chatbotId, err := strconv.Atoi(parts[0])
		if err != nil {
			if glog.V(1) {
				glog.Errorln("Invalid chatbot id: ", parts[0])
			}
			return
		}

		self.netMan.Send(chatbotId, parts[1], parts[2])

		// Now send it back to ourself, so other plugins see it
		internalLine := &line.Line{
			ChatBotId: chatbotId,
			Raw:       args,
			User:      self.netMan.GetUserByChatbotId(chatbotId),
			Command:   "PRIVMSG",
			Received:  time.Now().UTC().Format(time.RFC3339Nano),
			Content:   parts[2],
			Channel:   strings.TrimSpace(parts[1])}

		self.dis.Dispatch(internalLine)

	case "REFRESH":
		if glog.V(1) {
			glog.Infoln("Reloading configuration from database")
		}
		self.netMan.RefreshChatbots()
	}
}

// Writes the number of users per channel, every hour. Run in go routine.
func (self *BotBot) recordUserCounts() {

	for {

		for ch, _ := range self.users.Channels() {
			self.storage.SetCount(ch, self.users.Count(ch))
		}
		time.Sleep(1 * time.Hour)
	}
}

// Stop
func (self *BotBot) shutdown() {
	self.netMan.Shutdown()
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	// We depend on assets in order to build - how to tell user doesn't want assets?
	"github.com/fragmenta/assets"
)

// If it exists, simply run the binary in bin/deploy
// (this might be a shell script which runs ansible for example)
func runDeploy(args []string) {

	// Build our app assets and update secrets/assets.json
	buildAssets()

	// Build deploy server
	buildDeployServer()

	deploy := "./bin/deploy"

	_, err := os.Stat(deploy)
	if err != nil {
		log.Printf("Could not find deploy script at %s", deploy)
		return
	}

	// Default to development
	mode := "development"
	if len(args) == 3 {
		mode = args[2]
	}

	log.Printf("Running deploy from " + deploy)
	result, err := runCommand(deploy, mode)
	if err != nil {
		log.Printf("Error running deploy %s", err)
		return
	}

	log.Printf(string(result))
}

// Compile the app assets before a deploy, so that they're available for production use
func buildAssets() {
	log.Printf("#debug Compiling assets...")
	err := assets.New(true).Compile("src", "public")
	if err != nil {
		log.Fatalf("#error compiling assets %s", err)
	}
}
<commit_msg>Adjusted logging<commit_after>package main

import (
	"log"
	"os"

	// We depend on assets in order to build - how to tell user doesn't want assets?
	"github.com/fragmenta/assets"
)

// If it exists, simply run the binary in bin/deploy
// (this might be a shell script which runs ansible for example)
func runDeploy(args []string) {

	// Build our app assets and update secrets/assets.json
	buildAssets()

	// Build deploy server
	buildDeployServer()

	deploy := "./bin/deploy"

	_, err := os.Stat(deploy)
	if err != nil {
		log.Printf("Could not find deploy script at %s", deploy)
		return
	}

	// Default to development
	mode := "development"
	if len(args) == 3 {
		mode = args[2]
	}

	log.Printf("Running deploy from " + deploy)
	result, err := runCommand(deploy, mode)
	if err != nil {
		log.Printf("Error running deploy %s", err)
		return
	}

	log.Printf(string(result))
}

// Compile the app assets before a deploy, so that they're available for production use
func buildAssets() {
	log.Printf("Compiling assets...")
	err := assets.New(true).Compile("src", "public")
	if err != nil {
		log.Fatalf("#error compiling assets %s", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	stdtesting "testing"

	gc "launchpad.net/gocheck"
	"launchpad.net/golxc"
	"launchpad.net/goyaml"
	"launchpad.net/loggo"

	"launchpad.net/juju-core/container"
	"launchpad.net/juju-core/container/lxc"
	lxctesting "launchpad.net/juju-core/container/lxc/testing"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/instance"
	instancetest "launchpad.net/juju-core/instance/testing"
	jujutesting "launchpad.net/juju-core/juju/testing"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/testing/testbase"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/version"
)

func Test(t *stdtesting.T) {
	gc.TestingT(t)
}

type LxcSuite struct {
	lxctesting.TestSuite
}

var _ = gc.Suite(&LxcSuite{})

func (s *LxcSuite) SetUpSuite(c *gc.C) {
	s.TestSuite.SetUpSuite(c)
	tmpDir := c.MkDir()
	restore := testbase.PatchEnvironment("PATH", tmpDir)
	s.AddSuiteCleanup(func(*gc.C) { restore() })
	err := ioutil.WriteFile(
		filepath.Join(tmpDir, "apt-config"),
		[]byte(aptConfigScript),
		0755)
	c.Assert(err, gc.IsNil)
}

func (s *LxcSuite) SetUpTest(c *gc.C) {
	s.TestSuite.SetUpTest(c)
	loggo.GetLogger("juju.container.lxc").SetLogLevel(loggo.TRACE)
}

const (
	aptHTTPProxy     = "http://1.2.3.4:3142"
	configProxyExtra = `Acquire::https::Proxy "false";
Acquire::ftp::Proxy "false";`
)

var (
	configHttpProxy = fmt.Sprintf(`Acquire::http::Proxy "%s";`, aptHTTPProxy)
	aptConfigScript = fmt.Sprintf("#!/bin/sh\n echo '%s\n%s'", configHttpProxy, configProxyExtra)
)

func StartContainer(c *gc.C, manager container.Manager, machineId string) instance.Instance {
	stateInfo := jujutesting.FakeStateInfo(machineId)
	apiInfo := jujutesting.FakeAPIInfo(machineId)
	machineConfig := environs.NewMachineConfig(machineId, "fake-nonce", stateInfo, apiInfo)
	machineConfig.Tools = &tools.Tools{
		Version: version.MustParseBinary("2.3.4-foo-bar"),
		URL:     "http://tools.testing.invalid/2.3.4-foo-bar.tgz",
	}

	series := "series"
	network := container.BridgeNetworkConfig("nic42")
	inst, err := manager.StartContainer(machineConfig, series, network)
	c.Assert(err, gc.IsNil)
	return inst
}

func (s *LxcSuite) TestStartContainer(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	// Check our container config files.
	lxcConfContents, err := ioutil.ReadFile(filepath.Join(s.ContainerDir, name, "lxc.conf"))
	c.Assert(err, gc.IsNil)
	c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.link = nic42")

	cloudInitFilename := filepath.Join(s.ContainerDir, name, "cloud-init")
	c.Assert(cloudInitFilename, jc.IsNonEmptyFile)
	data, err := ioutil.ReadFile(cloudInitFilename)
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), jc.HasPrefix, "#cloud-config\n")

	x := make(map[interface{}]interface{})
	err = goyaml.Unmarshal(data, &x)
	c.Assert(err, gc.IsNil)

	c.Assert(x["apt_proxy"], gc.Equals, aptHTTPProxy)

	var scripts []string
	for _, s := range x["runcmd"].([]interface{}) {
		scripts = append(scripts, s.(string))
	}

	c.Assert(scripts[len(scripts)-4:], gc.DeepEquals, []string{
		"start jujud-machine-1-lxc-0",
		"install -m 644 /dev/null '/etc/apt/apt.conf.d/99proxy-extra'",
		fmt.Sprintf(`printf '%%s\n' '%s' > '/etc/apt/apt.conf.d/99proxy-extra'`, configProxyExtra),
		"ifconfig",
	})

	// Check the mount point has been created inside the container.
	c.Assert(filepath.Join(s.LxcDir, name, "rootfs/var/log/juju"), jc.IsDirectory)
	// Check that the config file is linked in the restart dir.
	expectedLinkLocation := filepath.Join(s.RestartDir, name+".conf")
	expectedTarget := filepath.Join(s.LxcDir, name, "config")
	linkInfo, err := os.Lstat(expectedLinkLocation)
	c.Assert(err, gc.IsNil)
	c.Assert(linkInfo.Mode()&os.ModeSymlink, gc.Equals, os.ModeSymlink)

	location, err := os.Readlink(expectedLinkLocation)
	c.Assert(err, gc.IsNil)
	c.Assert(location, gc.Equals, expectedTarget)
}

func (s *LxcSuite) TestContainerState(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	// The mock container will be immediately "running".
	c.Assert(instance.Status(), gc.Equals, string(golxc.StateRunning))

	// StopContainer stops and then destroys the container, putting it
	// into "unknown" state.
	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)
	c.Assert(instance.Status(), gc.Equals, string(golxc.StateUnknown))
}

func (s *LxcSuite) TestStopContainer(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)

	name := string(instance.Id())
	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
	// but instead, in the removed container dir
	c.Assert(filepath.Join(s.RemovedDir, name), jc.IsDirectory)
}

func (s *LxcSuite) TestStopContainerNameClash(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	targetDir := filepath.Join(s.RemovedDir, name)
	err := os.MkdirAll(targetDir, 0755)
	c.Assert(err, gc.IsNil)

	err = manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)

	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
	// but instead, in the removed container dir with a ".1" suffix as there was already a directory there.
	c.Assert(filepath.Join(s.RemovedDir, fmt.Sprintf("%s.1", name)), jc.IsDirectory)
}

func (s *LxcSuite) TestNamedManagerPrefix(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{Name: "eric"})
	instance := StartContainer(c, manager, "1/lxc/0")
	c.Assert(string(instance.Id()), gc.Equals, "eric-machine-1-lxc-0")
}

func (s *LxcSuite) TestListContainers(c *gc.C) {
	foo := lxc.NewContainerManager(container.ManagerConfig{Name: "foo"})
	bar := lxc.NewContainerManager(container.ManagerConfig{Name: "bar"})

	foo1 := StartContainer(c, foo, "1/lxc/0")
	foo2 := StartContainer(c, foo, "1/lxc/1")
	foo3 := StartContainer(c, foo, "1/lxc/2")

	bar1 := StartContainer(c, bar, "1/lxc/0")
	bar2 := StartContainer(c, bar, "1/lxc/1")

	result, err := foo.ListContainers()
	c.Assert(err, gc.IsNil)
	instancetest.MatchInstances(c, result, foo1, foo2, foo3)

	result, err = bar.ListContainers()
	c.Assert(err, gc.IsNil)
	instancetest.MatchInstances(c, result, bar1, bar2)
}

func (s *LxcSuite) TestStartContainerAutostarts(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")
	autostartLink := lxc.RestartSymlink(string(instance.Id()))
	c.Assert(autostartLink, jc.IsSymlink)
}

func (s *LxcSuite) TestStopContainerRemovesAutostartLink(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")
	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)
	autostartLink := lxc.RestartSymlink(string(instance.Id()))
	c.Assert(autostartLink, jc.SymlinkDoesNotExist)
}

type NetworkSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&NetworkSuite{})

func (*NetworkSuite) TestGenerateNetworkConfig(c *gc.C) {
	for _, test := range []struct {
		config *container.NetworkConfig
		net    string
		link   string
	}{{
		config: nil,
		net:    "veth",
		link:   "lxcbr0",
	}, {
		config: lxc.DefaultNetworkConfig(),
		net:    "veth",
		link:   "lxcbr0",
	}, {
		config: container.BridgeNetworkConfig("foo"),
		net:    "veth",
		link:   "foo",
	}, {
		config: container.PhysicalNetworkConfig("foo"),
		net:    "phys",
		link:   "foo",
	}} {
		config := lxc.GenerateNetworkConfig(test.config)
		c.Assert(config, jc.Contains, fmt.Sprintf("lxc.network.type = %s\n", test.net))
		c.Assert(config, jc.Contains, fmt.Sprintf("lxc.network.link = %s\n", test.link))
	}
}

func (*NetworkSuite) TestNetworkConfigTemplate(c *gc.C) {
	config := lxc.NetworkConfigTemplate("foo", "bar")
	expected := `
lxc.network.type = foo
lxc.network.link = bar
lxc.network.flags = up
`
	c.Assert(config, gc.Equals, expected)
}
<commit_msg>lxc tests were missing syslog port in basic config.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	stdtesting "testing"

	gc "launchpad.net/gocheck"
	"launchpad.net/golxc"
	"launchpad.net/goyaml"
	"launchpad.net/loggo"

	"launchpad.net/juju-core/container"
	"launchpad.net/juju-core/container/lxc"
	lxctesting "launchpad.net/juju-core/container/lxc/testing"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/instance"
	instancetest "launchpad.net/juju-core/instance/testing"
	jujutesting "launchpad.net/juju-core/juju/testing"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/testing/testbase"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/version"
)

func Test(t *stdtesting.T) {
	gc.TestingT(t)
}

type LxcSuite struct {
	lxctesting.TestSuite
}

var _ = gc.Suite(&LxcSuite{})

func (s *LxcSuite) SetUpSuite(c *gc.C) {
	s.TestSuite.SetUpSuite(c)
	tmpDir := c.MkDir()
	restore := testbase.PatchEnvironment("PATH", tmpDir)
	s.AddSuiteCleanup(func(*gc.C) { restore() })
	err := ioutil.WriteFile(
		filepath.Join(tmpDir, "apt-config"),
		[]byte(aptConfigScript),
		0755)
	c.Assert(err, gc.IsNil)
}

func (s *LxcSuite) SetUpTest(c *gc.C) {
	s.TestSuite.SetUpTest(c)
	loggo.GetLogger("juju.container.lxc").SetLogLevel(loggo.TRACE)
}

const (
	aptHTTPProxy     = "http://1.2.3.4:3142"
	configProxyExtra = `Acquire::https::Proxy "false";
Acquire::ftp::Proxy "false";`
)

var (
	configHttpProxy = fmt.Sprintf(`Acquire::http::Proxy "%s";`, aptHTTPProxy)
	aptConfigScript = fmt.Sprintf("#!/bin/sh\n echo '%s\n%s'", configHttpProxy, configProxyExtra)
)

func StartContainer(c *gc.C, manager container.Manager, machineId string) instance.Instance {
	stateInfo := jujutesting.FakeStateInfo(machineId)
	apiInfo := jujutesting.FakeAPIInfo(machineId)
	machineConfig := environs.NewMachineConfig(machineId, "fake-nonce", stateInfo, apiInfo)
	machineConfig.SyslogPort = 2345
	machineConfig.Tools = &tools.Tools{
		Version: version.MustParseBinary("2.3.4-foo-bar"),
		URL:     "http://tools.testing.invalid/2.3.4-foo-bar.tgz",
	}

	series := "series"
	network := container.BridgeNetworkConfig("nic42")
	inst, err := manager.StartContainer(machineConfig, series, network)
	c.Assert(err, gc.IsNil)
	return inst
}

func (s *LxcSuite) TestStartContainer(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	// Check our container config files.
	lxcConfContents, err := ioutil.ReadFile(filepath.Join(s.ContainerDir, name, "lxc.conf"))
	c.Assert(err, gc.IsNil)
	c.Assert(string(lxcConfContents), jc.Contains, "lxc.network.link = nic42")

	cloudInitFilename := filepath.Join(s.ContainerDir, name, "cloud-init")
	c.Assert(cloudInitFilename, jc.IsNonEmptyFile)
	data, err := ioutil.ReadFile(cloudInitFilename)
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), jc.HasPrefix, "#cloud-config\n")

	x := make(map[interface{}]interface{})
	err = goyaml.Unmarshal(data, &x)
	c.Assert(err, gc.IsNil)

	c.Assert(x["apt_proxy"], gc.Equals, aptHTTPProxy)

	var scripts []string
	for _, s := range x["runcmd"].([]interface{}) {
		scripts = append(scripts, s.(string))
	}

	c.Assert(scripts[len(scripts)-4:], gc.DeepEquals, []string{
		"start jujud-machine-1-lxc-0",
		"install -m 644 /dev/null '/etc/apt/apt.conf.d/99proxy-extra'",
		fmt.Sprintf(`printf '%%s\n' '%s' > '/etc/apt/apt.conf.d/99proxy-extra'`, configProxyExtra),
		"ifconfig",
	})

	// Check the mount point has been created inside the container.
	c.Assert(filepath.Join(s.LxcDir, name, "rootfs/var/log/juju"), jc.IsDirectory)
	// Check that the config file is linked in the restart dir.
	expectedLinkLocation := filepath.Join(s.RestartDir, name+".conf")
	expectedTarget := filepath.Join(s.LxcDir, name, "config")
	linkInfo, err := os.Lstat(expectedLinkLocation)
	c.Assert(err, gc.IsNil)
	c.Assert(linkInfo.Mode()&os.ModeSymlink, gc.Equals, os.ModeSymlink)

	location, err := os.Readlink(expectedLinkLocation)
	c.Assert(err, gc.IsNil)
	c.Assert(location, gc.Equals, expectedTarget)
}

func (s *LxcSuite) TestContainerState(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	// The mock container will be immediately "running".
	c.Assert(instance.Status(), gc.Equals, string(golxc.StateRunning))

	// StopContainer stops and then destroys the container, putting it
	// into "unknown" state.
	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)
	c.Assert(instance.Status(), gc.Equals, string(golxc.StateUnknown))
}

func (s *LxcSuite) TestStopContainer(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)

	name := string(instance.Id())
	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
	// but instead, in the removed container dir
	c.Assert(filepath.Join(s.RemovedDir, name), jc.IsDirectory)
}

func (s *LxcSuite) TestStopContainerNameClash(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	targetDir := filepath.Join(s.RemovedDir, name)
	err := os.MkdirAll(targetDir, 0755)
	c.Assert(err, gc.IsNil)

	err = manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)

	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.ContainerDir, name), jc.DoesNotExist)
	// but instead, in the removed container dir with a ".1" suffix as there was already a directory there.
	c.Assert(filepath.Join(s.RemovedDir, fmt.Sprintf("%s.1", name)), jc.IsDirectory)
}

func (s *LxcSuite) TestNamedManagerPrefix(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{Name: "eric"})
	instance := StartContainer(c, manager, "1/lxc/0")
	c.Assert(string(instance.Id()), gc.Equals, "eric-machine-1-lxc-0")
}

func (s *LxcSuite) TestListContainers(c *gc.C) {
	foo := lxc.NewContainerManager(container.ManagerConfig{Name: "foo"})
	bar := lxc.NewContainerManager(container.ManagerConfig{Name: "bar"})

	foo1 := StartContainer(c, foo, "1/lxc/0")
	foo2 := StartContainer(c, foo, "1/lxc/1")
	foo3 := StartContainer(c, foo, "1/lxc/2")

	bar1 := StartContainer(c, bar, "1/lxc/0")
	bar2 := StartContainer(c, bar, "1/lxc/1")

	result, err := foo.ListContainers()
	c.Assert(err, gc.IsNil)
	instancetest.MatchInstances(c, result, foo1, foo2, foo3)

	result, err = bar.ListContainers()
	c.Assert(err, gc.IsNil)
	instancetest.MatchInstances(c, result, bar1, bar2)
}

func (s *LxcSuite) TestStartContainerAutostarts(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")
	autostartLink := lxc.RestartSymlink(string(instance.Id()))
	c.Assert(autostartLink, jc.IsSymlink)
}

func (s *LxcSuite) TestStopContainerRemovesAutostartLink(c *gc.C) {
	manager := lxc.NewContainerManager(container.ManagerConfig{})
	instance := StartContainer(c, manager, "1/lxc/0")
	err := manager.StopContainer(instance)
	c.Assert(err, gc.IsNil)
	autostartLink := lxc.RestartSymlink(string(instance.Id()))
	c.Assert(autostartLink, jc.SymlinkDoesNotExist)
}

type NetworkSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&NetworkSuite{})

func (*NetworkSuite) TestGenerateNetworkConfig(c *gc.C) {
	for _, test := range []struct {
		config *container.NetworkConfig
		net    string
		link   string
	}{{
		config: nil,
		net:    "veth",
		link:   "lxcbr0",
	}, {
		config: lxc.DefaultNetworkConfig(),
		net:    "veth",
		link:   "lxcbr0",
	}, {
		config: container.BridgeNetworkConfig("foo"),
		net:    "veth",
		link:   "foo",
	}, {
		config: container.PhysicalNetworkConfig("foo"),
		net:    "phys",
		link:   "foo",
	}} {
		config := lxc.GenerateNetworkConfig(test.config)
		c.Assert(config, jc.Contains, fmt.Sprintf("lxc.network.type = %s\n", test.net))
		c.Assert(config, jc.Contains, fmt.Sprintf("lxc.network.link = %s\n", test.link))
	}
}

func (*NetworkSuite) TestNetworkConfigTemplate(c *gc.C) {
	config := lxc.NetworkConfigTemplate("foo", "bar")
	expected := `
lxc.network.type = foo
lxc.network.link = bar
lxc.network.flags = up
`
	c.Assert(config, gc.Equals, expected)
}
<|endoftext|>