<commit_before>package db

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/url"
	"sort"
	"strconv"
	"strings"

	"github.com/ponzu-cms/ponzu/system/item"

	"github.com/boltdb/bolt"
	"github.com/gorilla/schema"
	uuid "github.com/satori/go.uuid"
)

// SetContent inserts or updates values in the database.
// The `target` argument is a string made up of namespace:id (string:int)
func SetContent(target string, data url.Values) (int, error) {
	t := strings.Split(target, ":")
	ns, id := t[0], t[1]

	// check if content id == -1 (indicating new post).
	// if so, run an insert which will assign the next auto incremented int.
	// this is done because boltdb begins its bucket auto increment value at 0,
	// which is the zero-value of an int in the Item struct field for ID.
	// this is a problem when the original first post (with auto ID = 0) gets
	// overwritten by any new post, originally having no ID, defauting to 0.
	if id == "-1" {
		return insert(ns, data)
	}

	return update(ns, id, data)
}

func update(ns, id string, data url.Values) (int, error) {
	var specifier string // i.e. __pending, __sorted, etc.
	if strings.Contains(ns, "__") {
		spec := strings.Split(ns, "__")
		ns = spec[0]
		specifier = "__" + spec[1]
	}

	cid, err := strconv.Atoi(id)
	if err != nil {
		return 0, err
	}

	err = store.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
		if err != nil {
			return err
		}

		j, err := postToJSON(ns, data)
		if err != nil {
			return err
		}

		err = b.Put([]byte(fmt.Sprintf("%d", cid)), j)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return 0, nil
	}

	if specifier == "" {
		go SortContent(ns)
	}

	// update changes data, so invalidate client caching
	err = InvalidateCache()
	if err != nil {
		return 0, err
	}

	return cid, nil
}

func insert(ns string, data url.Values) (int, error) {
	var effectedID int
	var specifier string // i.e. __pending, __sorted, etc.
	if strings.Contains(ns, "__") {
		spec := strings.Split(ns, "__")
		ns = spec[0]
		specifier = "__" + spec[1]
	}

	err := store.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
		if err != nil {
			return err
		}

		// get the next available ID and convert to string
		// also set effectedID to int of ID
		id, err := b.NextSequence()
		if err != nil {
			return err
		}
		cid := strconv.FormatUint(id, 10)
		effectedID, err = strconv.Atoi(cid)
		if err != nil {
			return err
		}
		data.Set("id", cid)

		// add UUID to data for use in embedded Item
		uid := uuid.NewV4()
		data.Set("uuid", uid.String())

		// if type has a specifier, add it to data for downstream processing
		if specifier != "" {
			data.Set("__specifier", specifier)
		}

		j, err := postToJSON(ns, data)
		if err != nil {
			return err
		}

		err = b.Put([]byte(cid), j)
		if err != nil {
			return err
		}

		// store the slug,type:id in contentIndex if public content
		if specifier == "" {
			ci := tx.Bucket([]byte("__contentIndex"))
			k := []byte(data.Get("slug"))
			v := []byte(fmt.Sprintf("%s:%d", ns, effectedID))
			err := ci.Put(k, v)
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return 0, err
	}

	if specifier == "" {
		go SortContent(ns)
	}

	// insert changes data, so invalidate client caching
	err = InvalidateCache()
	if err != nil {
		return 0, err
	}

	return effectedID, nil
}

// DeleteContent removes an item from the database. Deleting a non-existent item
// will return a nil error.
func DeleteContent(target string, data url.Values) error {
	t := strings.Split(target, ":")
	ns, id := t[0], t[1]

	err := store.Update(func(tx *bolt.Tx) error {
		err := tx.Bucket([]byte(ns)).Delete([]byte(id))
		if err != nil {
			return err
		}

		// if content has a slug, also delete it from __contentIndex
		slug := data.Get("slug")
		if slug != "" {
			err := tx.Bucket([]byte("__contentIndex")).Delete([]byte(slug))
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return err
	}

	// delete changes data, so invalidate client caching
	err = InvalidateCache()
	if err != nil {
		return err
	}

	// exception to typical "run in goroutine" pattern:
	// we want to have an updated admin view as soon as this is deleted, so
	// in some cases, the delete and redirect is faster than the sort,
	// thus still showing a deleted post in the admin view.
	SortContent(ns)

	return nil
}

// Content retrives one item from the database. Non-existent values will return an empty []byte
// The `target` argument is a string made up of namespace:id (string:int)
func Content(target string) ([]byte, error) {
	t := strings.Split(target, ":")
	ns, id := t[0], t[1]

	val := &bytes.Buffer{}
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(ns))
		_, err := val.Write(b.Get([]byte(id)))
		if err != nil {
			log.Println(err)
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return val.Bytes(), nil
}

// ContentBySlug does a lookup in the content index to find the type and id of
// the requested content. Subsequently, issues the lookup in the type bucket and
// returns the the type and data at that ID or nil if nothing exists.
func ContentBySlug(slug string) (string, []byte, error) {
	val := &bytes.Buffer{}
	var t, id string
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__contentIndex"))
		idx := b.Get([]byte(slug))

		if idx != nil {
			tid := strings.Split(string(idx), ":")

			if len(tid) < 2 {
				return fmt.Errorf("Bad data in content index for slug: %s", slug)
			}

			t, id = tid[0], tid[1]
		}

		c := tx.Bucket([]byte(t))
		_, err := val.Write(c.Get([]byte(id)))
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return t, nil, err
	}

	return t, val.Bytes(), nil
}

// ContentAll retrives all items from the database within the provided namespace
func ContentAll(namespace string) [][]byte {
	var posts [][]byte
	store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(namespace))

		if b == nil {
			return nil
		}

		numKeys := b.Stats().KeyN
		posts = make([][]byte, 0, numKeys)

		b.ForEach(func(k, v []byte) error {
			posts = append(posts, v)

			return nil
		})

		return nil
	})

	return posts
}

// QueryOptions holds options for a query
type QueryOptions struct {
	Count  int
	Offset int
	Order  string
}

// Query retrieves a set of content from the db based on options
// and returns the total number of content in the namespace and the content
func Query(namespace string, opts QueryOptions) (int, [][]byte) {
	var posts [][]byte
	var total int

	// correct bad input rather than return nil or error
	// similar to default case for opts.Order switch below
	if opts.Count < 0 {
		opts.Count = -1
	}

	if opts.Offset < 0 {
		opts.Offset = 0
	}

	store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(namespace))
		if b == nil {
			return nil
		}

		c := b.Cursor()
		n := b.Stats().KeyN
		total = n

		// return nil if no content
		if n == 0 {
			return nil
		}

		var start, end int
		switch opts.Count {
		case -1:
			start = 0
			end = n

		default:
			start = opts.Count * opts.Offset
			end = start + opts.Count
		}

		// bounds check on posts given the start & end count
		if start > n {
			start = n - opts.Count
		}
		if end > n {
			end = n
		}

		i := 0   // count of num posts added
		cur := 0 // count of num cursor moves
		switch opts.Order {
		case "asc":
			for k, v := c.Last(); k != nil; k, v = c.Prev() {
				if cur < start {
					cur++
					continue
				}

				if cur >= end {
					break
				}

				posts = append(posts, v)
				i++
				cur++
			}

		case "desc", "":
			for k, v := c.First(); k != nil; k, v = c.Next() {
				if cur < start {
					cur++
					continue
				}

				if cur >= end {
					break
				}

				posts = append(posts, v)
				i++
				cur++
			}

		default:
			// results for DESC order
			for k, v := c.First(); k != nil; k, v = c.Next() {
				if cur < start {
					cur++
					continue
				}

				if cur >= end {
					break
				}

				posts = append(posts, v)
				i++
				cur++
			}
		}

		return nil
	})

	return total, posts
}

// SortContent sorts all content of the type supplied as the namespace by time,
// in descending order, from most recent to least recent
// Should be called from a goroutine after SetContent is successful
func SortContent(namespace string) {
	// only sort main content types i.e. Post
	if strings.Contains(namespace, "__") {
		return
	}

	all := ContentAll(namespace)

	var posts sortableContent
	// decode each (json) into type to then sort
	for i := range all {
		j := all[i]
		post := item.Types[namespace]()

		err := json.Unmarshal(j, &post)
		if err != nil {
			log.Println("Error decoding json while sorting", namespace, ":", err)
			return
		}

		posts = append(posts, post.(item.Sortable))
	}

	// sort posts
	sort.Sort(posts)

	// store in <namespace>_sorted bucket, first delete existing
	err := store.Update(func(tx *bolt.Tx) error {
		bname := []byte(namespace + "__sorted")
		err := tx.DeleteBucket(bname)
		if err != nil || err != bolt.ErrBucketNotFound {
			return err
		}

		b, err := tx.CreateBucketIfNotExists(bname)
		if err != nil {
			return err
		}

		// encode to json and store as 'i:post.Time()':post
		for i := range posts {
			j, err := json.Marshal(posts[i])
			if err != nil {
				return err
			}

			cid := fmt.Sprintf("%d:%d", i, posts[i].Time())
			err = b.Put([]byte(cid), j)
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		log.Println("Error while updating db with sorted", namespace, err)
	}

}

type sortableContent []item.Sortable

func (s sortableContent) Len() int {
	return len(s)
}

func (s sortableContent) Less(i, j int) bool {
	return s[i].Time() > s[j].Time()
}

func (s sortableContent) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func postToJSON(ns string, data url.Values) ([]byte, error) {
	// find the content type and decode values into it
	t, ok := item.Types[ns]
	if !ok {
		return nil, fmt.Errorf(item.ErrTypeNotRegistered.Error(), ns)
	}
	post := t()

	dec := schema.NewDecoder()
	dec.SetAliasTag("json")     // allows simpler struct tagging when creating a content type
	dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
	err := dec.Decode(post, data)
	if err != nil {
		return nil, err
	}

	// if the content has no slug, and has no specifier, create a slug, check it
	// for duplicates, and add it to our values
	if data.Get("slug") == "" && data.Get("__specifier") == "" {
		slug, err := item.Slug(post.(item.Identifiable))
		if err != nil {
			return nil, err
		}

		slug, err = checkSlugForDuplicate(slug)
		if err != nil {
			return nil, err
		}

		post.(item.Sluggable).SetSlug(slug)
		data.Set("slug", slug)
	}

	// marshall content struct to json for db storage
	j, err := json.Marshal(post)
	if err != nil {
		return nil, err
	}

	return j, nil
}

func checkSlugForDuplicate(slug string) (string, error) {
	// check for existing slug in __contentIndex
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__contentIndex"))
		original := slug
		exists := true
		i := 0
		for exists {
			s := b.Get([]byte(slug))
			if s == nil {
				exists = false
				return nil
			}

			i++
			slug = fmt.Sprintf("%s-%d", original, i)
		}

		return nil
	})
	if err != nil {
		return "", err
	}

	return slug, nil
}
<commit_msg>move expensive work outside store.Update in Sort<commit_after>package db

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/url"
	"sort"
	"strconv"
	"strings"

	"github.com/ponzu-cms/ponzu/system/item"

	"github.com/boltdb/bolt"
	"github.com/gorilla/schema"
	uuid "github.com/satori/go.uuid"
)

// SetContent inserts or updates values in the database.
// The `target` argument is a string made up of namespace:id (string:int)
func SetContent(target string, data url.Values) (int, error) {
	t := strings.Split(target, ":")
	ns, id := t[0], t[1]

	// check if content id == -1 (indicating new post).
	// if so, run an insert which will assign the next auto incremented int.
	// this is done because boltdb begins its bucket auto increment value at 0,
	// which is the zero-value of an int in the Item struct field for ID.
	// this is a problem when the original first post (with auto ID = 0) gets
	// overwritten by any new post, originally having no ID, defauting to 0.
	if id == "-1" {
		return insert(ns, data)
	}

	return update(ns, id, data)
}

func update(ns, id string, data url.Values) (int, error) {
	var specifier string // i.e. __pending, __sorted, etc.
	if strings.Contains(ns, "__") {
		spec := strings.Split(ns, "__")
		ns = spec[0]
		specifier = "__" + spec[1]
	}

	cid, err := strconv.Atoi(id)
	if err != nil {
		return 0, err
	}

	err = store.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
		if err != nil {
			return err
		}

		j, err := postToJSON(ns, data)
		if err != nil {
			return err
		}

		err = b.Put([]byte(fmt.Sprintf("%d", cid)), j)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return 0, nil
	}

	if specifier == "" {
		go SortContent(ns)
	}

	// update changes data, so invalidate client caching
	err = InvalidateCache()
	if err != nil {
		return 0, err
	}

	return cid, nil
}

func insert(ns string, data url.Values) (int, error) {
	var effectedID int
	var specifier string // i.e. __pending, __sorted, etc.
	if strings.Contains(ns, "__") {
		spec := strings.Split(ns, "__")
		ns = spec[0]
		specifier = "__" + spec[1]
	}

	err := store.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
		if err != nil {
			return err
		}

		// get the next available ID and convert to string
		// also set effectedID to int of ID
		id, err := b.NextSequence()
		if err != nil {
			return err
		}
		cid := strconv.FormatUint(id, 10)
		effectedID, err = strconv.Atoi(cid)
		if err != nil {
			return err
		}
		data.Set("id", cid)

		// add UUID to data for use in embedded Item
		uid := uuid.NewV4()
		data.Set("uuid", uid.String())

		// if type has a specifier, add it to data for downstream processing
		if specifier != "" {
			data.Set("__specifier", specifier)
		}

		j, err := postToJSON(ns, data)
		if err != nil {
			return err
		}

		err = b.Put([]byte(cid), j)
		if err != nil {
			return err
		}

		// store the slug,type:id in contentIndex if public content
		if specifier == "" {
			ci := tx.Bucket([]byte("__contentIndex"))
			k := []byte(data.Get("slug"))
			v := []byte(fmt.Sprintf("%s:%d", ns, effectedID))
			err := ci.Put(k, v)
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return 0, err
	}

	if specifier == "" {
		go SortContent(ns)
	}

	// insert changes data, so invalidate client caching
	err = InvalidateCache()
	if err != nil {
		return 0, err
	}

	return effectedID, nil
}

// DeleteContent removes an item from the database. Deleting a non-existent item
// will return a nil error.
func DeleteContent(target string, data url.Values) error {
	t := strings.Split(target, ":")
	ns, id := t[0], t[1]

	err := store.Update(func(tx *bolt.Tx) error {
		err := tx.Bucket([]byte(ns)).Delete([]byte(id))
		if err != nil {
			return err
		}

		// if content has a slug, also delete it from __contentIndex
		slug := data.Get("slug")
		if slug != "" {
			err := tx.Bucket([]byte("__contentIndex")).Delete([]byte(slug))
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return err
	}

	// delete changes data, so invalidate client caching
	err = InvalidateCache()
	if err != nil {
		return err
	}

	// exception to typical "run in goroutine" pattern:
	// we want to have an updated admin view as soon as this is deleted, so
	// in some cases, the delete and redirect is faster than the sort,
	// thus still showing a deleted post in the admin view.
	SortContent(ns)

	return nil
}

// Content retrives one item from the database. Non-existent values will return an empty []byte
// The `target` argument is a string made up of namespace:id (string:int)
func Content(target string) ([]byte, error) {
	t := strings.Split(target, ":")
	ns, id := t[0], t[1]

	val := &bytes.Buffer{}
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(ns))
		_, err := val.Write(b.Get([]byte(id)))
		if err != nil {
			log.Println(err)
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return val.Bytes(), nil
}

// ContentBySlug does a lookup in the content index to find the type and id of
// the requested content. Subsequently, issues the lookup in the type bucket and
// returns the the type and data at that ID or nil if nothing exists.
func ContentBySlug(slug string) (string, []byte, error) {
	val := &bytes.Buffer{}
	var t, id string
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__contentIndex"))
		idx := b.Get([]byte(slug))

		if idx != nil {
			tid := strings.Split(string(idx), ":")

			if len(tid) < 2 {
				return fmt.Errorf("Bad data in content index for slug: %s", slug)
			}

			t, id = tid[0], tid[1]
		}

		c := tx.Bucket([]byte(t))
		_, err := val.Write(c.Get([]byte(id)))
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return t, nil, err
	}

	return t, val.Bytes(), nil
}

// ContentAll retrives all items from the database within the provided namespace
func ContentAll(namespace string) [][]byte {
	var posts [][]byte
	store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(namespace))

		if b == nil {
			return nil
		}

		numKeys := b.Stats().KeyN
		posts = make([][]byte, 0, numKeys)

		b.ForEach(func(k, v []byte) error {
			posts = append(posts, v)

			return nil
		})

		return nil
	})

	return posts
}

// QueryOptions holds options for a query
type QueryOptions struct {
	Count  int
	Offset int
	Order  string
}

// Query retrieves a set of content from the db based on options
// and returns the total number of content in the namespace and the content
func Query(namespace string, opts QueryOptions) (int, [][]byte) {
	var posts [][]byte
	var total int

	// correct bad input rather than return nil or error
	// similar to default case for opts.Order switch below
	if opts.Count < 0 {
		opts.Count = -1
	}

	if opts.Offset < 0 {
		opts.Offset = 0
	}

	store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(namespace))
		if b == nil {
			return nil
		}

		c := b.Cursor()
		n := b.Stats().KeyN
		total = n

		// return nil if no content
		if n == 0 {
			return nil
		}

		var start, end int
		switch opts.Count {
		case -1:
			start = 0
			end = n

		default:
			start = opts.Count * opts.Offset
			end = start + opts.Count
		}

		// bounds check on posts given the start & end count
		if start > n {
			start = n - opts.Count
		}
		if end > n {
			end = n
		}

		i := 0   // count of num posts added
		cur := 0 // count of num cursor moves
		switch opts.Order {
		case "asc":
			for k, v := c.Last(); k != nil; k, v = c.Prev() {
				if cur < start {
					cur++
					continue
				}

				if cur >= end {
					break
				}

				posts = append(posts, v)
				i++
				cur++
			}

		case "desc", "":
			for k, v := c.First(); k != nil; k, v = c.Next() {
				if cur < start {
					cur++
					continue
				}

				if cur >= end {
					break
				}

				posts = append(posts, v)
				i++
				cur++
			}

		default:
			// results for DESC order
			for k, v := c.First(); k != nil; k, v = c.Next() {
				if cur < start {
					cur++
					continue
				}

				if cur >= end {
					break
				}

				posts = append(posts, v)
				i++
				cur++
			}
		}

		return nil
	})

	return total, posts
}

// SortContent sorts all content of the type supplied as the namespace by time,
// in descending order, from most recent to least recent
// Should be called from a goroutine after SetContent is successful
func SortContent(namespace string) {
	// only sort main content types i.e. Post
	if strings.Contains(namespace, "__") {
		return
	}

	all := ContentAll(namespace)

	var posts sortableContent
	// decode each (json) into type to then sort
	for i := range all {
		j := all[i]
		post := item.Types[namespace]()

		err := json.Unmarshal(j, &post)
		if err != nil {
			log.Println("Error decoding json while sorting", namespace, ":", err)
			return
		}

		posts = append(posts, post.(item.Sortable))
	}

	// sort posts
	sort.Sort(posts)

	// marshal posts to json
	var bb [][]byte
	for i := range posts {
		j, err := json.Marshal(posts[i])
		if err != nil {
			// log error and kill sort so __sorted is not in invalid state
			log.Println("Error marshal post to json in SortContent:", err)
			return
		}

		bb = append(bb, j)
	}

	// store in <namespace>_sorted bucket, first delete existing
	err := store.Update(func(tx *bolt.Tx) error {
		bname := []byte(namespace + "__sorted")
		err := tx.DeleteBucket(bname)
		if err != nil || err != bolt.ErrBucketNotFound {
			fmt.Println("Error in DeleteBucket")
			return err
		}

		b, err := tx.CreateBucketIfNotExists(bname)
		if err != nil {
			fmt.Println("Error in CreateBucketIfNotExists")
			return err
		}

		// encode to json and store as 'i:post.Time()':post
		for i := range bb {
			cid := fmt.Sprintf("%d:%d", i, posts[i].Time())
			err = b.Put([]byte(cid), bb[i])
			if err != nil {
				fmt.Println("Error in Put")
				return err
			}
		}

		return nil
	})
	if err != nil {
		log.Println("Error while updating db with sorted", namespace, err)
	}

}

type sortableContent []item.Sortable

func (s sortableContent) Len() int {
	return len(s)
}

func (s sortableContent) Less(i, j int) bool {
	return s[i].Time() > s[j].Time()
}

func (s sortableContent) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func postToJSON(ns string, data url.Values) ([]byte, error) {
	// find the content type and decode values into it
	t, ok := item.Types[ns]
	if !ok {
		return nil, fmt.Errorf(item.ErrTypeNotRegistered.Error(), ns)
	}
	post := t()

	dec := schema.NewDecoder()
	dec.SetAliasTag("json")     // allows simpler struct tagging when creating a content type
	dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
	err := dec.Decode(post, data)
	if err != nil {
		return nil, err
	}

	// if the content has no slug, and has no specifier, create a slug, check it
	// for duplicates, and add it to our values
	if data.Get("slug") == "" && data.Get("__specifier") == "" {
		slug, err := item.Slug(post.(item.Identifiable))
		if err != nil {
			return nil, err
		}

		slug, err = checkSlugForDuplicate(slug)
		if err != nil {
			return nil, err
		}

		post.(item.Sluggable).SetSlug(slug)
		data.Set("slug", slug)
	}

	// marshall content struct to json for db storage
	j, err := json.Marshal(post)
	if err != nil {
		return nil, err
	}

	return j, nil
}

func checkSlugForDuplicate(slug string) (string, error) {
	// check for existing slug in __contentIndex
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__contentIndex"))
		original := slug
		exists := true
		i := 0
		for exists {
			s := b.Get([]byte(slug))
			if s == nil {
				exists = false
				return nil
			}

			i++
			slug = fmt.Sprintf("%s-%d", original, i)
		}

		return nil
	})
	if err != nil {
		return "", err
	}

	return slug, nil
}
<|endoftext|>


<commit_before>package system

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"fmt"
	"net/http"
	"strings"

	"github.com/coopernurse/gorp"
	"github.com/golang/glog"
	"github.com/gorilla/sessions"
	"github.com/haruyama/golang-goji-sample/models"
	"github.com/zenazn/goji/web"
)

// Makes sure templates are stored in the context
func (application *Application) ApplyTemplates(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		c.Env["Template"] = application.Template
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

// Makes sure controllers can have access to session
func (application *Application) ApplySessions(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session, _ := application.Store.Get(r, "session")
		c.Env["Session"] = session
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyDbMap(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		c.Env["DbMap"] = application.DbMap
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyAuth(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := c.Env["Session"].(*sessions.Session)
		if userId, ok := session.Values["UserId"]; ok {
			dbMap := c.Env["DbMap"].(*gorp.DbMap)

			user, err := dbMap.Get(models.User{}, userId)
			if err != nil {
				glog.Warningf("Auth error: %v", err)
				c.Env["User"] = nil
			} else {
				c.Env["User"] = user
			}
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyIsXhr(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
			c.Env["IsXhr"] = true
		} else {
			c.Env["IsXhr"] = false
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func isValidToken(a, b string) bool {
	x := []byte(a)
	y := []byte(b)
	if len(x) != len(y) {
		return false
	}
	return subtle.ConstantTimeCompare(x, y) == 1
}

func (application *Application) ApplyCsrfProtection(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := c.Env["Session"].(*sessions.Session)
		csrfProtection := application.CsrfProtection
		if _, ok := session.Values["CsrfToken"]; !ok {
			hash := sha256.New()
			buffer := make([]byte, 32)
			_, err := rand.Read(buffer)
			if err != nil {
				glog.Fatalf("crypt/rand.Read failed: %s", err)
			}
			hash.Write(buffer)
			session.Values["CsrfToken"] = fmt.Sprintf("%x", hash.Sum(nil))
			if err = session.Save(r, w); err != nil {
				glog.Fatal("session.Save() failed")
			}
		}
		c.Env["CsrfKey"] = csrfProtection.Key
		c.Env["CsrfToken"] = session.Values["CsrfToken"]
		csrfToken := c.Env["CsrfToken"].(string)

		if c.Env["IsXhr"].(bool) {
			if !isValidToken(csrfToken, r.Header.Get(csrfProtection.Header)) {
				http.Error(w, "Invalid Csrf Header", http.StatusBadRequest)
			}
		} else {
			method := strings.ToUpper(r.Method)
			if method == "POST" || method == "PUT" || method == "DELETE" {
				if !isValidToken(csrfToken, r.PostFormValue(csrfProtection.Key)) {
					http.Error(w, "Invalid Csrf Token", http.StatusBadRequest)
				}
			}
		}
		http.SetCookie(w, &http.Cookie{
			Name:   csrfProtection.Cookie,
			Value:  csrfToken,
			Secure: csrfProtection.Secure,
		})
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Add isCsrfProtectionMethodForNoXhr.<commit_after>package system

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"fmt"
	"net/http"
	"strings"

	"github.com/coopernurse/gorp"
	"github.com/go-utils/uslice"
	"github.com/golang/glog"
	"github.com/gorilla/sessions"
	"github.com/haruyama/golang-goji-sample/models"
	"github.com/zenazn/goji/web"
)

// Makes sure templates are stored in the context
func (application *Application) ApplyTemplates(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		c.Env["Template"] = application.Template
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

// Makes sure controllers can have access to session
func (application *Application) ApplySessions(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session, _ := application.Store.Get(r, "session")
		c.Env["Session"] = session
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyDbMap(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		c.Env["DbMap"] = application.DbMap
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyAuth(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := c.Env["Session"].(*sessions.Session)
		if userId, ok := session.Values["UserId"]; ok {
			dbMap := c.Env["DbMap"].(*gorp.DbMap)

			user, err := dbMap.Get(models.User{}, userId)
			if err != nil {
				glog.Warningf("Auth error: %v", err)
				c.Env["User"] = nil
			} else {
				c.Env["User"] = user
			}
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func (application *Application) ApplyIsXhr(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("X-Requested-With") == "XMLHttpRequest" {
			c.Env["IsXhr"] = true
		} else {
			c.Env["IsXhr"] = false
		}
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

func isValidToken(a, b string) bool {
	x := []byte(a)
	y := []byte(b)
	if len(x) != len(y) {
		return false
	}
	return subtle.ConstantTimeCompare(x, y) == 1
}

var csrfProtectionMethodForNoXhr = []string{"POST", "PUT", "DELETE"}

func isCsrfProtectionMethodForNoXhr(method string) bool {
	return uslice.StrHas(csrfProtectionMethodForNoXhr, strings.ToUpper(method))
}

func (application *Application) ApplyCsrfProtection(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		session := c.Env["Session"].(*sessions.Session)
		csrfProtection := application.CsrfProtection
		if _, ok := session.Values["CsrfToken"]; !ok {
			hash := sha256.New()
			buffer := make([]byte, 32)
			_, err := rand.Read(buffer)
			if err != nil {
				glog.Fatalf("crypt/rand.Read failed: %s", err)
			}
			hash.Write(buffer)
			session.Values["CsrfToken"] = fmt.Sprintf("%x", hash.Sum(nil))
			if err = session.Save(r, w); err != nil {
				glog.Fatal("session.Save() failed")
			}
		}
		c.Env["CsrfKey"] = csrfProtection.Key
		c.Env["CsrfToken"] = session.Values["CsrfToken"]
		csrfToken := c.Env["CsrfToken"].(string)

		if c.Env["IsXhr"].(bool) {
			if !isValidToken(csrfToken, r.Header.Get(csrfProtection.Header)) {
				http.Error(w, "Invalid Csrf Header", http.StatusBadRequest)
			}
		} else {
			if isCsrfProtectionMethodForNoXhr(r.Method) {
				if !isValidToken(csrfToken, r.PostFormValue(csrfProtection.Key)) {
					http.Error(w, "Invalid Csrf Token", http.StatusBadRequest)
				}
			}
		}
		http.SetCookie(w, &http.Cookie{
			Name:   csrfProtection.Cookie,
			Value:  csrfToken,
			Secure: csrfProtection.Secure,
		})
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


<commit_before>package models

import (
	//"errors"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"testing"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

func TestReplyIsValid(t *testing.T) {

	reply := ReplyModel{
		Uid:     0,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "hehehe",
		Image:   false,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyIsValidNoImage(t *testing.T) {

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "a cool comment",
		Image:   false,
	}

	assert.True(t, reply.IsValid(), "Should not be false")
}

func TestReplyIsValidNoCommentNoImage(t *testing.T) {

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "",
		Image:   false,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyIsValidImage(t *testing.T) {

	reply := ReplyModel{
		Uid:         1,
		Ib:          1,
		Thread:      1,
		Ip:          "10.0.0.1",
		Comment:     "",
		Image:       true,
		Filename:    "test.jpg",
		Thumbnail:   "tests.jpg",
		MD5:         "test",
		OrigWidth:   1000,
		OrigHeight:  1000,
		ThumbWidth:  100,
		ThumbHeight: 100,
	}

	assert.True(t, reply.IsValid(), "Should not be false")
}

func TestReplyIsValidImageNoStats(t *testing.T) {

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "",
		Image:   true,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyIsValidImageBadStats(t *testing.T) {

	reply := ReplyModel{
		Uid:         1,
		Ib:          1,
		Thread:      1,
		Ip:          "10.0.0.1",
		Comment:     "",
		Image:       true,
		Filename:    "",
		Thumbnail:   "",
		MD5:         "",
		OrigWidth:   0,
		OrigHeight:  0,
		ThumbWidth:  0,
		ThumbHeight: 0,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyValidateInputCommentEmpty(t *testing.T) {

	var err error

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "",
		Image:   false,
	}

	err = reply.ValidateInput()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrNoComment, "Error should match")
	}

}

func TestReplyValidateInputCommentShort(t *testing.T) {

	var err error

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   false,
	}

	err = reply.ValidateInput()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrCommentShort, "Error should match")
	}

}

func TestReplyValidateInputShortCommentWithImage(t *testing.T) {

	var err error

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.ValidateInput()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrCommentShort, "Error should match")
	}

}

func TestReplyStatus(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"ib", "closed", "total"}).AddRow(1, 0, 2)
	mock.ExpectQuery(`SELECT ib_id,thread_closed,count\(post_num\) FROM threads`).WillReturnRows(rows)

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.Status()
	assert.NoError(t, err, "An error was not expected")

}

func TestReplyStatusClosed(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"ib", "closed", "total"}).AddRow(1, 1, 100)
	mock.ExpectQuery(`SELECT ib_id,thread_closed,count\(post_num\) FROM threads`).WillReturnRows(rows)

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.Status()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrThreadClosed, "Error should match")
	}

}

func TestReplyStatusAutoclose(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"ib", "closed", "total"}).AddRow(1, 1, config.Settings.Limits.PostsMax)
	mock.ExpectQuery(`SELECT ib_id,thread_closed,count\(post_num\) FROM threads`).WillReturnRows(rows)

	mock.ExpectExec("UPDATE threads SET thread_closed=1 WHERE thread_id").
		WithArgs(1).
		WillReturnResult(sqlmock.NewResult(0, 1))

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.Status()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrThreadClosed, "Error should match")
	}

}
<commit_msg>add reply model test<commit_after>package models

import (
	//"errors"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"testing"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

func TestReplyIsValid(t *testing.T) {

	reply := ReplyModel{
		Uid:     0,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "hehehe",
		Image:   false,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyIsValidNoImage(t *testing.T) {

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "a cool comment",
		Image:   false,
	}

	assert.True(t, reply.IsValid(), "Should not be false")
}

func TestReplyIsValidNoCommentNoImage(t *testing.T) {

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "",
		Image:   false,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyIsValidImage(t *testing.T) {

	reply := ReplyModel{
		Uid:         1,
		Ib:          1,
		Thread:      1,
		Ip:          "10.0.0.1",
		Comment:     "",
		Image:       true,
		Filename:    "test.jpg",
		Thumbnail:   "tests.jpg",
		MD5:         "test",
		OrigWidth:   1000,
		OrigHeight:  1000,
		ThumbWidth:  100,
		ThumbHeight: 100,
	}

	assert.True(t, reply.IsValid(), "Should not be false")
}

func TestReplyIsValidImageNoStats(t *testing.T) {

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "",
		Image:   true,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyIsValidImageBadStats(t *testing.T) {

	reply := ReplyModel{
		Uid:         1,
		Ib:          1,
		Thread:      1,
		Ip:          "10.0.0.1",
		Comment:     "",
		Image:       true,
		Filename:    "",
		Thumbnail:   "",
		MD5:         "",
		OrigWidth:   0,
		OrigHeight:  0,
		ThumbWidth:  0,
		ThumbHeight: 0,
	}

	assert.False(t, reply.IsValid(), "Should be false")
}

func TestReplyValidateInputCommentEmpty(t *testing.T) {

	var err error

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "",
		Image:   false,
	}

	err = reply.ValidateInput()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrNoComment, "Error should match")
	}

}

func TestReplyValidateInputCommentShort(t *testing.T) {

	var err error

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   false,
	}

	err = reply.ValidateInput()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrCommentShort, "Error should match")
	}

}

func TestReplyValidateInputShortCommentWithImage(t *testing.T) {

	var err error

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.ValidateInput()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrCommentShort, "Error should match")
	}

}

func TestReplyStatus(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"ib", "closed", "total"}).AddRow(1, 0, 2)
	mock.ExpectQuery(`SELECT ib_id,thread_closed,count\(post_num\) FROM threads`).WillReturnRows(rows)

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.Status()
	assert.NoError(t, err, "An error was not expected")

}

func TestReplyStatusClosed(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"ib", "closed", "total"}).AddRow(1, 1, 100)
	mock.ExpectQuery(`SELECT ib_id,thread_closed,count\(post_num\) FROM threads`).WillReturnRows(rows)

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.Status()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrThreadClosed, "Error should match")
	}

}

func TestReplyStatusAutoclose(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"ib", "closed", "total"}).AddRow(1, 1, config.Settings.Limits.PostsMax)
	mock.ExpectQuery(`SELECT ib_id,thread_closed,count\(post_num\) FROM threads`).WillReturnRows(rows)

	mock.ExpectExec("UPDATE threads SET thread_closed=1 WHERE thread_id").
		WithArgs(1).
		WillReturnResult(sqlmock.NewResult(0, 1))

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "d",
		Image:   true,
	}

	err = reply.Status()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, e.ErrThreadClosed, "Error should match")
	}

}

func TestReplyPost(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	mock.ExpectBegin()

	mock.ExpectExec("INSERT INTO posts").
		WithArgs(1, 1, "10.0.0.1", "test", 1).
		WillReturnResult(sqlmock.NewResult(2, 1))

	mock.ExpectCommit()

	reply := ReplyModel{
		Uid:     1,
		Ib:      1,
		Thread:  1,
		Ip:      "10.0.0.1",
		Comment: "test",
		Image:   false,
	}

	err = reply.Post()
	assert.NoError(t, err, "An error was not expected")

}

func TestReplyPostImage(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	mock.ExpectBegin()

	mock.ExpectExec("INSERT INTO posts").
		WithArgs(1, 1, "10.0.0.1", "test", 1).
		WillReturnResult(sqlmock.NewResult(2, 1))

	mock.ExpectExec("INSERT INTO images").
		WithArgs("test.jpg", "tests.jpg", "test", 1000, 1000, 100, 100).
		WillReturnResult(sqlmock.NewResult(1, 1))

	mock.ExpectCommit()

	reply := ReplyModel{
		Uid:         1,
		Ib:          1,
		Thread:      1,
		Ip:          "10.0.0.1",
		Comment:     "test",
		Image:       true,
		Filename:    "test.jpg",
		Thumbnail:   "tests.jpg",
		MD5:         "test",
		OrigWidth:   1000,
		OrigHeight:  1000,
		ThumbWidth:  100,
		ThumbHeight: 100,
	}

	err = reply.Post()
	assert.NoError(t, err, "An error was not expected")

}
<|endoftext|>


<commit_before>/*
Copyright 2013 Google Inc.

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

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

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

package appengine

import (
	"sync"

	"appengine"
)

type ContextPool struct {
	mu sync.Mutex // guards live

	// Live HTTP requests
	live map[appengine.Context]*sync.WaitGroup
}

// HandlerBegin notes that the provided context is beginning and it can be
// shared until HandlerEnd is called.
func (p *ContextPool) HandlerBegin(c appengine.Context) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.live == nil {
		p.live = make(map[appengine.Context]*sync.WaitGroup)
	}
	if _, ok := p.live[c]; ok {
		// dup; ignore.
		return
	}
	p.live[c] = new(sync.WaitGroup)
}

// HandlerEnd notes that the provided context is about to go out of service,
// removes it from the pool of available contexts, and blocks until everybody
// is done using it.
func (p *ContextPool) HandlerEnd(c appengine.Context) {
	p.mu.Lock()
	wg := p.live[c]
	delete(p.live, c)
	p.mu.Unlock()
	if wg != nil {
		wg.Wait()
	}
}

// A ContextLoan is a superset of a Context, so can passed anywhere
// that needs an appengine.Context.
//
// When done, Return it.
type ContextLoan interface {
	appengine.Context

	// Return returns the Context to the pool.
	// Return must be called exactly once.
	Return()
}

// Get returns a valid App Engine context from some active HTTP request
// which is guaranteed to stay valid.  Be sure to return it.
//
// Typical use:
//   ctx := pool.Get()
//   defer ctx.Return()
func (p *ContextPool) Get() ContextLoan {
	p.mu.Lock()
	defer p.mu.Unlock()

	// Pick a random active context.  TODO: pick the "right" one,
	// using some TLS-like-guess/hack from runtume.Stacks.
	var c appengine.Context
	var wg *sync.WaitGroup
	for c, wg = range p.live {
		break
	}
	if c == nil {
		panic("ContextPool.Get called with no live HTTP requests")
	}
	wg.Add(1)
	cl := &contextLoan{Context: c, wg: wg}
	// TODO: set warning finalizer on this?
	return cl
}

type contextLoan struct {
	appengine.Context

	mu sync.Mutex
	wg *sync.WaitGroup
}

func (cl *contextLoan) Return() {
	cl.mu.Lock()
	defer cl.mu.Unlock()
	if cl.wg == nil {
		panic("Return called twice")
	}
	cl.wg.Done()
	cl.wg = nil
}
<commit_msg>appengine: don't build contextpool except in appengine context<commit_after>// +build appengine

/*
Copyright 2013 Google Inc.

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

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

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

package appengine

import (
	"sync"

	"appengine"
)

type ContextPool struct {
	mu sync.Mutex // guards live

	// Live HTTP requests
	live map[appengine.Context]*sync.WaitGroup
}

// HandlerBegin notes that the provided context is beginning and it can be
// shared until HandlerEnd is called.
func (p *ContextPool) HandlerBegin(c appengine.Context) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.live == nil {
		p.live = make(map[appengine.Context]*sync.WaitGroup)
	}
	if _, ok := p.live[c]; ok {
		// dup; ignore.
		return
	}
	p.live[c] = new(sync.WaitGroup)
}

// HandlerEnd notes that the provided context is about to go out of service,
// removes it from the pool of available contexts, and blocks until everybody
// is done using it.
func (p *ContextPool) HandlerEnd(c appengine.Context) {
	p.mu.Lock()
	wg := p.live[c]
	delete(p.live, c)
	p.mu.Unlock()
	if wg != nil {
		wg.Wait()
	}
}

// A ContextLoan is a superset of a Context, so can passed anywhere
// that needs an appengine.Context.
//
// When done, Return it.
type ContextLoan interface {
	appengine.Context

	// Return returns the Context to the pool.
	// Return must be called exactly once.
	Return()
}

// Get returns a valid App Engine context from some active HTTP request
// which is guaranteed to stay valid.  Be sure to return it.
//
// Typical use:
//   ctx := pool.Get()
//   defer ctx.Return()
func (p *ContextPool) Get() ContextLoan {
	p.mu.Lock()
	defer p.mu.Unlock()

	// Pick a random active context.  TODO: pick the "right" one,
	// using some TLS-like-guess/hack from runtume.Stacks.
	var c appengine.Context
	var wg *sync.WaitGroup
	for c, wg = range p.live {
		break
	}
	if c == nil {
		panic("ContextPool.Get called with no live HTTP requests")
	}
	wg.Add(1)
	cl := &contextLoan{Context: c, wg: wg}
	// TODO: set warning finalizer on this?
	return cl
}

type contextLoan struct {
	appengine.Context

	mu sync.Mutex
	wg *sync.WaitGroup
}

func (cl *contextLoan) Return() {
	cl.mu.Lock()
	defer cl.mu.Unlock()
	if cl.wg == nil {
		panic("Return called twice")
	}
	cl.wg.Done()
	cl.wg = nil
}
<|endoftext|>


<commit_before>package wsdlgen

import (
	"encoding/xml"

	"aqwari.net/xml/wsdl"
	"aqwari.net/xml/xsdgen"
)

func init() {
	defaultConfig.Option(DefaultOptions...)
}

// A Config contains parameters for the various code generation processes.
// Users may modify the output of the wsdlgen package's code generation
// by using a Config's Option method to change these parameters.
type Config struct {
	pkgName    string
	pkgHeader  string
	logger     Logger
	loglevel   int
	xsdgen     xsdgen.Config
	portFilter func(wsdl.Port) bool

	maxArgs, maxReturns int
}

var defaultConfig Config

func (cfg *Config) logf(format string, args ...interface{}) {
	if cfg.logger != nil {
		cfg.logger.Printf(format, args...)
	}
}

func (cfg *Config) verbosef(format string, args ...interface{}) {
	if cfg.loglevel > 0 {
		cfg.logf(format, args...)
	}
}

func (cfg *Config) debugf(format string, args ...interface{}) {
	if cfg.loglevel > 2 {
		cfg.logf(format, args...)
	}
}

func (cfg *Config) publicName(name xml.Name) string {
	return cfg.xsdgen.NameOf(name)
}

// Option applies the provides Options to a Config, modifying the
// code generation process. The return value of Option can be
// used to revert the effects of the final parameter.
func (cfg *Config) Option(opts ...Option) (previous Option) {
	for _, opt := range opts {
		previous = opt(cfg)
	}
	return previous
}

// XSDOption controls the generation of type declarations according
// to the xsdgen package.
func (cfg *Config) XSDOption(opts ...xsdgen.Option) (previous xsdgen.Option) {
	return cfg.xsdgen.Option(opts...)
}

// An Option modifies code generation parameters. The return value of an
// Option can be used to undo its effect.
type Option func(*Config) Option

// DefaultOptions are the default options for Go source code generation.
var DefaultOptions = []Option{
	PackageName("ws"),
}

// The OnlyPorts option defines a whitelist of WSDL ports to generate
// code for. Any other ports will not have types or methods present in
// the generated output.
func OnlyPorts(ports ...string) Option {
	return func(cfg *Config) Option {
		cfg.portFilter = func(p wsdl.Port) bool {
			for _, name := range ports {
				if name == p.Name {
					return true
				}
			}
			return false
		}
		return OnlyPorts()
	}
}

// PackageName specifies the name of the generated Go package.
func PackageName(name string) Option {
	return func(cfg *Config) Option {
		prev := cfg.pkgName
		cfg.pkgName = name
		return PackageName(prev)
	}
}

// PackageComment specifies the first line of package-level Godoc comments.
// If the input WSDL file provides package-level comments, they are added after
// the provided comment, separated by a newline.
func PackageComment(comment string) Option {
	return func(cfg *Config) Option {
		prev := cfg.pkgHeader
		cfg.pkgHeader = comment
		return PackageComment(prev)
	}
}

// LogLevel sets the level of verbosity for log messages generated during
// the code generation process.
func LogLevel(level int) Option {
	return func(cfg *Config) Option {
		prev := cfg.loglevel
		cfg.loglevel = level
		cfg.xsdgen.Option(xsdgen.LogLevel(level))
		return LogLevel(prev)
	}
}

// LogOutput sets the destination for log messages generated during
// code generation.
func LogOutput(dest Logger) Option {
	return func(cfg *Config) Option {
		prev := cfg.logger
		cfg.logger = dest
		cfg.xsdgen.Option(xsdgen.LogOutput(dest))
		return LogOutput(prev)
	}
}

// InputThreshold sets the maximum number of parameters a
// generated function may take. If a WSDL operation is defined as
// taking greater than n parameters, the generated function will
// take only one parameter; a struct, through which all arguments
// will be accessed.
func InputThreshold(n int) Option {
	return func(cfg *Config) Option {
		prev := cfg.maxArgs
		cfg.maxArgs = n
		return InputThreshold(prev)
	}
}

// OutputThreshold sets the maximum number of values that a
// generated function may return. If a WSDL operation is defined
// as returning greater than n values, the generated function will
// return a wrapper struct instead. Note that the error value that all
// generated functions return is not counted against the threshold.
func OutputThreshold(n int) Option {
	return func(cfg *Config) Option {
		prev := cfg.maxReturns
		cfg.maxReturns = n
		return OutputThreshold(prev)
	}
}
<commit_msg>remove unused variable<commit_after>package wsdlgen

import (
	"encoding/xml"

	"aqwari.net/xml/wsdl"
	"aqwari.net/xml/xsdgen"
)

// A Config contains parameters for the various code generation processes.
// Users may modify the output of the wsdlgen package's code generation
// by using a Config's Option method to change these parameters.
type Config struct {
	pkgName    string
	pkgHeader  string
	logger     Logger
	loglevel   int
	xsdgen     xsdgen.Config
	portFilter func(wsdl.Port) bool

	maxArgs, maxReturns int
}

func (cfg *Config) logf(format string, args ...interface{}) {
	if cfg.logger != nil {
		cfg.logger.Printf(format, args...)
	}
}

func (cfg *Config) verbosef(format string, args ...interface{}) {
	if cfg.loglevel > 0 {
		cfg.logf(format, args...)
	}
}

func (cfg *Config) debugf(format string, args ...interface{}) {
	if cfg.loglevel > 2 {
		cfg.logf(format, args...)
	}
}

func (cfg *Config) publicName(name xml.Name) string {
	return cfg.xsdgen.NameOf(name)
}

// Option applies the provides Options to a Config, modifying the
// code generation process. The return value of Option can be
// used to revert the effects of the final parameter.
func (cfg *Config) Option(opts ...Option) (previous Option) {
	for _, opt := range opts {
		previous = opt(cfg)
	}
	return previous
}

// XSDOption controls the generation of type declarations according
// to the xsdgen package.
func (cfg *Config) XSDOption(opts ...xsdgen.Option) (previous xsdgen.Option) {
	return cfg.xsdgen.Option(opts...)
}

// An Option modifies code generation parameters. The return value of an
// Option can be used to undo its effect.
type Option func(*Config) Option

// DefaultOptions are the default options for Go source code generation.
var DefaultOptions = []Option{
	PackageName("ws"),
}

// The OnlyPorts option defines a whitelist of WSDL ports to generate
// code for. Any other ports will not have types or methods present in
// the generated output.
func OnlyPorts(ports ...string) Option {
	return func(cfg *Config) Option {
		cfg.portFilter = func(p wsdl.Port) bool {
			for _, name := range ports {
				if name == p.Name {
					return true
				}
			}
			return false
		}
		return OnlyPorts()
	}
}

// PackageName specifies the name of the generated Go package.
func PackageName(name string) Option {
	return func(cfg *Config) Option {
		prev := cfg.pkgName
		cfg.pkgName = name
		return PackageName(prev)
	}
}

// PackageComment specifies the first line of package-level Godoc comments.
// If the input WSDL file provides package-level comments, they are added after
// the provided comment, separated by a newline.
func PackageComment(comment string) Option {
	return func(cfg *Config) Option {
		prev := cfg.pkgHeader
		cfg.pkgHeader = comment
		return PackageComment(prev)
	}
}

// LogLevel sets the level of verbosity for log messages generated during
// the code generation process.
func LogLevel(level int) Option {
	return func(cfg *Config) Option {
		prev := cfg.loglevel
		cfg.loglevel = level
		cfg.xsdgen.Option(xsdgen.LogLevel(level))
		return LogLevel(prev)
	}
}

// LogOutput sets the destination for log messages generated during
// code generation.
func LogOutput(dest Logger) Option {
	return func(cfg *Config) Option {
		prev := cfg.logger
		cfg.logger = dest
		cfg.xsdgen.Option(xsdgen.LogOutput(dest))
		return LogOutput(prev)
	}
}

// InputThreshold sets the maximum number of parameters a
// generated function may take. If a WSDL operation is defined as
// taking greater than n parameters, the generated function will
// take only one parameter; a struct, through which all arguments
// will be accessed.
func InputThreshold(n int) Option {
	return func(cfg *Config) Option {
		prev := cfg.maxArgs
		cfg.maxArgs = n
		return InputThreshold(prev)
	}
}

// OutputThreshold sets the maximum number of values that a
// generated function may return. If a WSDL operation is defined
// as returning greater than n values, the generated function will
// return a wrapper struct instead. Note that the error value that all
// generated functions return is not counted against the threshold.
func OutputThreshold(n int) Option {
	return func(cfg *Config) Option {
		prev := cfg.maxReturns
		cfg.maxReturns = n
		return OutputThreshold(prev)
	}
}
<|endoftext|>


<commit_before>package hypervisors

import (
	"bufio"
	"fmt"
	"net/http"
	"sort"

	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/json"
	"github.com/Symantec/Dominator/lib/url"
	proto "github.com/Symantec/Dominator/proto/fleetmanager"
)

const (
	showOK = iota
	showConnected
	showAll
)

type hypervisorList []*hypervisorType

func (h *hypervisorType) getHealthStatus() string {
	healthStatus := h.probeStatus.String()
	if h.probeStatus == probeStatusConnected {
		if h.healthStatus != "" {
			healthStatus = h.healthStatus
		}
	}
	return healthStatus
}

func (h *hypervisorType) getNumVMs() uint {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	return uint(len(h.vms))
}

func (m *Manager) listHypervisors(topologyDir string, showFilter int,
	subnetId string) (hypervisorList, error) {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	machines, err := m.topology.ListMachines(topologyDir)
	if err != nil {
		return nil, err
	}
	hypervisors := make([]*hypervisorType, 0, len(machines))
	for _, machine := range machines {
		if subnetId != "" {
			hasSubnet, _ := m.topology.CheckIfMachineHasSubnet(
				machine.Hostname, subnetId)
			if !hasSubnet {
				continue
			}
		}
		hypervisor := m.hypervisors[machine.Hostname]
		switch showFilter {
		case showOK:
			if hypervisor.probeStatus == probeStatusConnected &&
				(hypervisor.healthStatus == "" ||
					hypervisor.healthStatus == "healthy") {
				hypervisors = append(hypervisors, hypervisor)
			}
		case showConnected:
			if hypervisor.probeStatus == probeStatusConnected {
				hypervisors = append(hypervisors, hypervisor)
			}
		case showAll:
			hypervisors = append(hypervisors, hypervisor)
		}
	}
	return hypervisors, nil
}

func (m *Manager) listHypervisorsHandler(w http.ResponseWriter,
	req *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	_, err := m.getTopology()
	if err != nil {
		fmt.Fprintln(writer, err)
		return
	}
	parsedQuery := url.ParseQuery(req.URL)
	showFilter := showAll
	switch parsedQuery.Table["state"] {
	case "connected":
		showFilter = showConnected
	case "OK":
		showFilter = showOK
	}
	hypervisors, err := m.listHypervisors("", showFilter, "")
	if err != nil {
		fmt.Fprintln(writer, err)
		return
	}
	sort.Sort(hypervisors)
	if parsedQuery.OutputType() == url.OutputTypeText {
		for _, hypervisor := range hypervisors {
			fmt.Fprintln(writer, hypervisor.machine.Hostname)
		}
		return
	}
	if parsedQuery.OutputType() == url.OutputTypeJson {
		json.WriteWithIndent(writer, "    ", hypervisors)
		return
	}
	fmt.Fprintf(writer, "<title>List of hypervisors</title>\n")
	writer.WriteString(commonStyleSheet)
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, `<table border="1" style="width:100%">`)
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "    Name	")
	fmt.Fprintln(writer, "    Status	")
	fmt.Fprintln(writer, "    IP Addr	")
	fmt.Fprintln(writer, "    MAC Addr	")
	fmt.Fprintln(writer, "    Location	")
	fmt.Fprintln(writer, "    NumVMs	")
	fmt.Fprintln(writer, "
")
	lastRowHighlighted := true
	for _, hypervisor := range hypervisors {
		machine := hypervisor.machine
		if lastRowHighlighted {
			lastRowHighlighted = false
			fmt.Fprintf(writer, "
\n")
		} else {
			lastRowHighlighted = true
			fmt.Fprintf(writer, "
\n",
				rowStyles[rowStyleHighlight].html)
		}
		fmt.Fprintf(writer,
			"    %s	\n",
			machine.Hostname, machine.Hostname)
		fmt.Fprintf(writer, "    %s	\n",
			machine.Hostname, constants.HypervisorPortNumber,
			hypervisor.getHealthStatus())
		fmt.Fprintf(writer, "    %s	\n", machine.HostIpAddress)
		fmt.Fprintf(writer, "    %s	\n", machine.HostMacAddress)
		fmt.Fprintf(writer, "    %s	\n", hypervisor.location)
		fmt.Fprintf(writer,
			"    %d	\n",
			machine.Hostname, constants.HypervisorPortNumber,
			hypervisor.getNumVMs())
		fmt.Fprintf(writer, "
\n")
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "")
}

func (m *Manager) listHypervisorsInLocation(
	request proto.ListHypervisorsInLocationRequest) ([]string, error) {
	hypervisors, err := m.listHypervisors(request.Location, showConnected,
		request.SubnetId)
	if err != nil {
		return nil, err
	}
	addresses := make([]string, 0, len(hypervisors))
	for _, hypervisor := range hypervisors {
		addresses = append(addresses,
			fmt.Sprintf("%s:%d",
				hypervisor.machine.Hostname, constants.HypervisorPortNumber))
	}
	return addresses, nil
}

func (list hypervisorList) Len() int {
	return len(list)
}

func (list hypervisorList) Less(i, j int) bool {
	if list[i].location < list[j].location {
		return true
	} else if list[i].location > list[j].location {
		return false
	} else {
		return list[i].machine.Hostname < list[j].machine.Hostname
	}
}

func (list hypervisorList) Swap(i, j int) {
	list[i], list[j] = list[j], list[i]
}
<commit_msg>Do not return unhealthy hypervisors in ListHypervisorsInLocations.<commit_after>package hypervisors

import (
	"bufio"
	"fmt"
	"net/http"
	"sort"

	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/json"
	"github.com/Symantec/Dominator/lib/url"
	proto "github.com/Symantec/Dominator/proto/fleetmanager"
)

const (
	showOK = iota
	showConnected
	showAll
)

type hypervisorList []*hypervisorType

func (h *hypervisorType) getHealthStatus() string {
	healthStatus := h.probeStatus.String()
	if h.probeStatus == probeStatusConnected {
		if h.healthStatus != "" {
			healthStatus = h.healthStatus
		}
	}
	return healthStatus
}

func (h *hypervisorType) getNumVMs() uint {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	return uint(len(h.vms))
}

func (m *Manager) listHypervisors(topologyDir string, showFilter int,
	subnetId string) (hypervisorList, error) {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	machines, err := m.topology.ListMachines(topologyDir)
	if err != nil {
		return nil, err
	}
	hypervisors := make([]*hypervisorType, 0, len(machines))
	for _, machine := range machines {
		if subnetId != "" {
			hasSubnet, _ := m.topology.CheckIfMachineHasSubnet(
				machine.Hostname, subnetId)
			if !hasSubnet {
				continue
			}
		}
		hypervisor := m.hypervisors[machine.Hostname]
		switch showFilter {
		case showOK:
			if hypervisor.probeStatus == probeStatusConnected &&
				(hypervisor.healthStatus == "" ||
					hypervisor.healthStatus == "healthy") {
				hypervisors = append(hypervisors, hypervisor)
			}
		case showConnected:
			if hypervisor.probeStatus == probeStatusConnected {
				hypervisors = append(hypervisors, hypervisor)
			}
		case showAll:
			hypervisors = append(hypervisors, hypervisor)
		}
	}
	return hypervisors, nil
}

func (m *Manager) listHypervisorsHandler(w http.ResponseWriter,
	req *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	_, err := m.getTopology()
	if err != nil {
		fmt.Fprintln(writer, err)
		return
	}
	parsedQuery := url.ParseQuery(req.URL)
	showFilter := showAll
	switch parsedQuery.Table["state"] {
	case "connected":
		showFilter = showConnected
	case "OK":
		showFilter = showOK
	}
	hypervisors, err := m.listHypervisors("", showFilter, "")
	if err != nil {
		fmt.Fprintln(writer, err)
		return
	}
	sort.Sort(hypervisors)
	if parsedQuery.OutputType() == url.OutputTypeText {
		for _, hypervisor := range hypervisors {
			fmt.Fprintln(writer, hypervisor.machine.Hostname)
		}
		return
	}
	if parsedQuery.OutputType() == url.OutputTypeJson {
		json.WriteWithIndent(writer, "    ", hypervisors)
		return
	}
	fmt.Fprintf(writer, "<title>List of hypervisors</title>\n")
	writer.WriteString(commonStyleSheet)
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, `<table border="1" style="width:100%">`)
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "    Name	")
	fmt.Fprintln(writer, "    Status	")
	fmt.Fprintln(writer, "    IP Addr	")
	fmt.Fprintln(writer, "    MAC Addr	")
	fmt.Fprintln(writer, "    Location	")
	fmt.Fprintln(writer, "    NumVMs	")
	fmt.Fprintln(writer, "
")
	lastRowHighlighted := true
	for _, hypervisor := range hypervisors {
		machine := hypervisor.machine
		if lastRowHighlighted {
			lastRowHighlighted = false
			fmt.Fprintf(writer, "
\n")
		} else {
			lastRowHighlighted = true
			fmt.Fprintf(writer, "
\n",
				rowStyles[rowStyleHighlight].html)
		}
		fmt.Fprintf(writer,
			"    %s	\n",
			machine.Hostname, machine.Hostname)
		fmt.Fprintf(writer, "    %s	\n",
			machine.Hostname, constants.HypervisorPortNumber,
			hypervisor.getHealthStatus())
		fmt.Fprintf(writer, "    %s	\n", machine.HostIpAddress)
		fmt.Fprintf(writer, "    %s	\n", machine.HostMacAddress)
		fmt.Fprintf(writer, "    %s	\n", hypervisor.location)
		fmt.Fprintf(writer,
			"    %d	\n",
			machine.Hostname, constants.HypervisorPortNumber,
			hypervisor.getNumVMs())
		fmt.Fprintf(writer, "
\n")
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "")
}

func (m *Manager) listHypervisorsInLocation(
	request proto.ListHypervisorsInLocationRequest) ([]string, error) {
	hypervisors, err := m.listHypervisors(request.Location, showOK,
		request.SubnetId)
	if err != nil {
		return nil, err
	}
	addresses := make([]string, 0, len(hypervisors))
	for _, hypervisor := range hypervisors {
		addresses = append(addresses,
			fmt.Sprintf("%s:%d",
				hypervisor.machine.Hostname, constants.HypervisorPortNumber))
	}
	return addresses, nil
}

func (list hypervisorList) Len() int {
	return len(list)
}

func (list hypervisorList) Less(i, j int) bool {
	if list[i].location < list[j].location {
		return true
	} else if list[i].location > list[j].location {
		return false
	} else {
		return list[i].machine.Hostname < list[j].machine.Hostname
	}
}

func (list hypervisorList) Swap(i, j int) {
	list[i], list[j] = list[j], list[i]
}
<|endoftext|>


<commit_before>// Copyright 2015 Geofrey Ernest <geofreyernest@live.com>. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

//Package i18n is a translation library.
package i18n

import (
	"github.com/melvinmt/gt"
)

// Tr contains translations.
var Tr = &gt.Build{
	Origin: "en",
	Target: "sw",
	Index: gt.Strings{
		"home-btn": {
			"en": "home",
			"sw": "nyumbani",
		},
		"jobs-btn": {
			"en": "jobs",
			"sw": "ajira",
		},
		"help-btn": {
			"en": "help",
			"sw": "msaada",
		},
		"contact-btn": {
			"en": "contact us",
			"sw": "wasiliana nasi",
		},
		"deadline": {
			"en": "deadline",
			"sw": "mwisho",
		},
		"regions": {
			"en": "regions",
			"sw": "mikoa",
		},
		"apply-btn": {
			"en": " apply now",
			"sw": "omba sasa",
		},
		"login": {
			"en": "login",
			"sw": "ingia",
		},
		"logout": {
			"en": "logout",
			"sw": "jitoe",
		},
		"register": {
			"en": "register",
			"sw": "jiunge",
		},
		"message_required": {
			"en": "this field should not be empty",
			"sw": "hili eneo halitakiwi kuachwa wazi",
		},
		"message_min_length": {
			"en": "this field should be at least %d characters",
			"sw": "namba ya siri inatakiwa kuanzia herufi %d na kuendelea",
		},
		"message_email": {
			"en": "incorrect email, should of the form example@examples.com",
			"sw": "barua pepe sio sahihi. mfano example@example.com",
		},
		"message_age": {
			"en": "age should be more than %d years",
			"sw": "umri unatakiwa uwe zaidi ya miaka %d",
		},
		"message_equal": {
			"en": "%s should be equal to %s",
			"sw": "%s inatakiwa iwe sawa na %s",
		},
		"documents": {
			"en": "documents",
			"sw": "makala",
		},
		"flash_account_create": {
			"en": "congard, your account has been successful created",
			"sw": "hongera, akaunti yako imefanikiwa kutengenezwa",
		},
		"flash_account_create_fail": {
			"en": "sorry, we can't create you account please try again later",
			"sw": "samahaani, tumeshindwa kutengeneza akaunti yako, jaribu tena baadae",
		},
		"flash_login_success": {
			"en": "welcome %s",
			"sw": "karibu %s",
		},
		"flash_login_failed": {
			"en": "there was a problem encountered, please check the details and try again",
			"sw": "kuna majanga mkuu, jaribu kupitia maelezo ya fomu na ujaribu tena",
		},
		"issued_by": {
			"en": "issued by",
			"sw": "imetolewa na",
		},
		"valid_name_msg": {
			"en": "field %s should conatin letters a-zA-Z e.g baba",
			"sw": "eneo %s linatakiwa liwe na herufi to a-zA-Z mfano baba",
		},
		"given_name": {
			"en": "first name",
			"sw": "jina la kwanza",
		},
		"family_name": {
			"en": "family name",
			"sw": "jina la ukoo",
		},
		"middle_name": {
			"en": "middle name",
			"sw": "jina la baba",
		},
	},
}

// CloneLang returns a copy of translations.
func CloneLang() *gt.Build {
	b := &gt.Build{}
	b.Origin = Tr.Origin
	b.Target = Tr.Target
	b.Index = Tr.Index
	return b
}
<commit_msg>updated translation<commit_after>// Copyright 2015 Geofrey Ernest <geofreyernest@live.com>. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

//Package i18n is a translation library.
package i18n

import (
	"github.com/melvinmt/gt"
)

// Tr contains translations.
var Tr = &gt.Build{
	Origin: "en",
	Target: "sw",
	Index: gt.Strings{
		"home-btn": {
			"en": "home",
			"sw": "nyumbani",
		},
		"jobs-btn": {
			"en": "jobs",
			"sw": "ajira",
		},
		"help-btn": {
			"en": "help",
			"sw": "msaada",
		},
		"contact-btn": {
			"en": "contact us",
			"sw": "wasiliana nasi",
		},
		"deadline": {
			"en": "deadline",
			"sw": "mwisho",
		},
		"regions": {
			"en": "regions",
			"sw": "mikoa",
		},
		"apply-btn": {
			"en": " apply now",
			"sw": "omba sasa",
		},
		"login": {
			"en": "login",
			"sw": "ingia",
		},
		"logout": {
			"en": "logout",
			"sw": "jitoe",
		},
		"register": {
			"en": "register",
			"sw": "jiunge",
		},
		"message_required": {
			"en": "this field should not be empty",
			"sw": "hili eneo halitakiwi kuachwa wazi",
		},
		"message_min_length": {
			"en": "this field should be at least %d characters",
			"sw": "namba ya siri inatakiwa kuanzia herufi %d na kuendelea",
		},
		"message_email": {
			"en": "incorrect email, should of the form example@examples.com",
			"sw": "barua pepe sio sahihi. mfano example@example.com",
		},
		"message_age": {
			"en": "age should be more than %d years",
			"sw": "umri unatakiwa uwe zaidi ya miaka %d",
		},
		"message_equal": {
			"en": "%s should be equal to %s",
			"sw": "%s inatakiwa iwe sawa na %s",
		},
		"documents": {
			"en": "documents",
			"sw": "makala",
		},
		"flash_account_create": {
			"en": "congard, your account has been successful created",
			"sw": "hongera, akaunti yako imefanikiwa kutengenezwa",
		},
		"flash_account_create_fail": {
			"en": "sorry, we can't create you account please try again later",
			"sw": "samahaani, tumeshindwa kutengeneza akaunti yako, jaribu tena baadae",
		},
		"flash_login_success": {
			"en": "welcome back",
			"sw": "karibu ",
		},
		"flash_login_failed": {
			"en": "there was a problem encountered, please check the details and try again",
			"sw": "kuna majanga mkuu, jaribu kupitia maelezo ya fomu na ujaribu tena",
		},
		"issued_by": {
			"en": "issued by",
			"sw": "imetolewa na",
		},
		"valid_name_msg": {
			"en": "field %s should conatin letters a-zA-Z e.g baba",
			"sw": "eneo %s linatakiwa liwe na herufi to a-zA-Z mfano baba",
		},
		"given_name": {
			"en": "first name",
			"sw": "jina la kwanza",
		},
		"family_name": {
			"en": "family name",
			"sw": "jina la ukoo",
		},
		"middle_name": {
			"en": "middle name",
			"sw": "jina la baba",
		},
	},
}

// CloneLang returns a copy of translations.
func CloneLang() *gt.Build {
	b := &gt.Build{}
	b.Origin = Tr.Origin
	b.Target = Tr.Target
	b.Index = Tr.Index
	return b
}
<|endoftext|>


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

package driver

/*

#include <jni.h>
#include <stdlib.h>

static char* initAudioTrack(uintptr_t java_vm, uintptr_t jni_env,
    int sampleRate, int channelNum, int bytesPerSample, jobject* audioTrack, int* bufferSize) {
  *bufferSize = 0;
  JavaVM* vm = (JavaVM*)java_vm;
  JNIEnv* env = (JNIEnv*)jni_env;

  const jclass android_media_AudioFormat =
      (*env)->FindClass(env, "android/media/AudioFormat");
  const jclass android_media_AudioManager =
      (*env)->FindClass(env, "android/media/AudioManager");
  const jclass android_media_AudioTrack =
      (*env)->FindClass(env, "android/media/AudioTrack");

  const jint android_media_AudioManager_STREAM_MUSIC =
      (*env)->GetStaticIntField(
          env, android_media_AudioManager,
          (*env)->GetStaticFieldID(env, android_media_AudioManager, "STREAM_MUSIC", "I"));
  const jint android_media_AudioTrack_MODE_STREAM =
      (*env)->GetStaticIntField(
          env, android_media_AudioTrack,
          (*env)->GetStaticFieldID(env, android_media_AudioTrack, "MODE_STREAM", "I"));
  const jint android_media_AudioFormat_CHANNEL_OUT_MONO =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "CHANNEL_OUT_MONO", "I"));
  const jint android_media_AudioFormat_CHANNEL_OUT_STEREO =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "CHANNEL_OUT_STEREO", "I"));
  const jint android_media_AudioFormat_ENCODING_PCM_8BIT =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "ENCODING_PCM_8BIT", "I"));
  const jint android_media_AudioFormat_ENCODING_PCM_16BIT =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "ENCODING_PCM_16BIT", "I"));

  jint channel = android_media_AudioFormat_CHANNEL_OUT_MONO;
  switch (channelNum) {
  case 1:
    channel = android_media_AudioFormat_CHANNEL_OUT_MONO;
    break;
  case 2:
    channel = android_media_AudioFormat_CHANNEL_OUT_STEREO;
    break;
  default:
    return "invalid channel";
  }

  jint encoding = android_media_AudioFormat_ENCODING_PCM_8BIT;
  switch (bytesPerSample) {
  case 1:
    encoding = android_media_AudioFormat_ENCODING_PCM_8BIT;
    break;
  case 2:
    encoding = android_media_AudioFormat_ENCODING_PCM_16BIT;
    break;
  default:
    return "invalid bytesPerSample";
  }

  *bufferSize =
      (*env)->CallStaticIntMethod(
          env, android_media_AudioTrack,
          (*env)->GetStaticMethodID(env, android_media_AudioTrack, "getMinBufferSize", "(III)I"),
          sampleRate, channel, encoding);

  const jobject tmpAudioTrack =
      (*env)->NewObject(
          env, android_media_AudioTrack,
          (*env)->GetMethodID(env, android_media_AudioTrack, "<init>", "(IIIIII)V"),
          android_media_AudioManager_STREAM_MUSIC,
          sampleRate, channel, encoding, *bufferSize,
          android_media_AudioTrack_MODE_STREAM);
  // Note that *audioTrack will never be released.
  *audioTrack = (*env)->NewGlobalRef(env, tmpAudioTrack);

  (*env)->CallVoidMethod(
      env, *audioTrack,
      (*env)->GetMethodID(env, android_media_AudioTrack, "play", "()V"));

  return NULL;
}

static char* writeToAudioTrack(uintptr_t java_vm, uintptr_t jni_env,
    jobject audioTrack, int bytesPerSample, void* data, int length) {
  JavaVM* vm = (JavaVM*)java_vm;
  JNIEnv* env = (JNIEnv*)jni_env;

  const jclass android_media_AudioTrack =
      (*env)->FindClass(env, "android/media/AudioTrack");

  jbyteArray arrInBytes;
  jshortArray arrInShorts;
  switch (bytesPerSample) {
  case 1:
    arrInBytes = (*env)->NewByteArray(env, length);
    (*env)->SetByteArrayRegion(env, arrInBytes, 0, length, data);
    break;
  case 2:
    arrInShorts = (*env)->NewShortArray(env, length);
    (*env)->SetShortArrayRegion(env, arrInShorts, 0, length, data);
    break;
  }

  jint result;
  switch (bytesPerSample) {
  case 1:
    result =
        (*env)->CallIntMethod(
            env, audioTrack,
            (*env)->GetMethodID(env, android_media_AudioTrack, "write", "([BII)I"),
            arrInBytes, 0, length);
    break;
  case 2:
    result =
        (*env)->CallIntMethod(
            env, audioTrack,
            (*env)->GetMethodID(env, android_media_AudioTrack, "write", "([SII)I"),
            arrInShorts, 0, length);
    break;
  }

  switch (result) {
  case -3: // ERROR_INVALID_OPERATION
    return "invalid operation";
  case -2: // ERROR_BAD_VALUE
    return "bad value";
  case -1: // ERROR
    return "error";
  }
  if (result < 0) {
    return "unknown error";
  }
  return NULL;
}

*/
import "C"

import (
	"errors"
	"unsafe"

	"github.com/hajimehoshi/ebiten/internal/jni"
)

type Player struct {
	sampleRate     int
	channelNum     int
	bytesPerSample int
	audioTrack     C.jobject
	buffer         []byte
	bufferSize     int
	chErr          chan error
	chBuffer       chan []byte
}

func NewPlayer(sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	p := &Player{
		sampleRate:     sampleRate,
		channelNum:     channelNum,
		bytesPerSample: bytesPerSample,
		buffer:         []byte{},
		chErr:          make(chan error),
		chBuffer:       make(chan []byte, 8),
	}
	if err := jni.RunOnJVM(func(vm, env, ctx uintptr) error {
		audioTrack := C.jobject(nil)
		bufferSize := C.int(0)
		if msg := C.initAudioTrack(C.uintptr_t(vm), C.uintptr_t(env),
			C.int(sampleRate), C.int(channelNum), C.int(bytesPerSample),
			&audioTrack, &bufferSize); msg != nil {
			return errors.New("driver: " + C.GoString(msg))
		}
		p.audioTrack = audioTrack
		p.bufferSize = int(bufferSize)
		return nil
	}); err != nil {
		return nil, err
	}
	go p.loop()
	return p, nil
}

func (p *Player) loop() {
	for bufInBytes := range p.chBuffer {
		var bufInShorts []int16
		if p.bytesPerSample == 2 {
			bufInShorts = make([]int16, len(bufInBytes)/2)
			for i := 0; i < len(bufInShorts); i++ {
				bufInShorts[i] = int16(bufInBytes[2*i]) | (int16(bufInBytes[2*i+1]) << 8)
			}
		}

		if err := jni.RunOnJVM(func(vm, env, ctx uintptr) error {
			msg := (*C.char)(nil)
			switch p.bytesPerSample {
			case 1:
				msg = C.writeToAudioTrack(C.uintptr_t(vm), C.uintptr_t(env),
					p.audioTrack, C.int(p.bytesPerSample),
					unsafe.Pointer(&bufInBytes[0]), C.int(len(bufInBytes)))
			case 2:
				msg = C.writeToAudioTrack(C.uintptr_t(vm), C.uintptr_t(env),
					p.audioTrack, C.int(p.bytesPerSample),
					unsafe.Pointer(&bufInShorts[0]), C.int(len(bufInShorts)))
			default:
				panic("not reach")
			}
			if msg != nil {
				return errors.New(C.GoString(msg))
			}
			return nil
		}); err != nil {
			p.chErr <- err
			return
		}
	}
}

func (p *Player) Proceed(data []byte) error {
	p.buffer = append(p.buffer, data...)
	if len(p.buffer) < p.bufferSize {
		return nil
	}
	buf := p.buffer[:p.bufferSize]
	select {
	case p.chBuffer <- buf:
	case err := <-p.chErr:
		return err
	}
	p.buffer = p.buffer[p.bufferSize:]
	return nil
}

func (p *Player) Close() error {
	return nil
}
<commit_msg>audio: Delete local refs explicitly in JNI (#336)<commit_after>// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package driver

/*

#include <jni.h>
#include <stdlib.h>

static char* initAudioTrack(uintptr_t java_vm, uintptr_t jni_env,
    int sampleRate, int channelNum, int bytesPerSample, jobject* audioTrack, int* bufferSize) {
  *bufferSize = 0;
  JavaVM* vm = (JavaVM*)java_vm;
  JNIEnv* env = (JNIEnv*)jni_env;

  const jclass android_media_AudioFormat =
      (*env)->FindClass(env, "android/media/AudioFormat");
  const jclass android_media_AudioManager =
      (*env)->FindClass(env, "android/media/AudioManager");
  const jclass android_media_AudioTrack =
      (*env)->FindClass(env, "android/media/AudioTrack");

  const jint android_media_AudioManager_STREAM_MUSIC =
      (*env)->GetStaticIntField(
          env, android_media_AudioManager,
          (*env)->GetStaticFieldID(env, android_media_AudioManager, "STREAM_MUSIC", "I"));
  const jint android_media_AudioTrack_MODE_STREAM =
      (*env)->GetStaticIntField(
          env, android_media_AudioTrack,
          (*env)->GetStaticFieldID(env, android_media_AudioTrack, "MODE_STREAM", "I"));
  const jint android_media_AudioFormat_CHANNEL_OUT_MONO =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "CHANNEL_OUT_MONO", "I"));
  const jint android_media_AudioFormat_CHANNEL_OUT_STEREO =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "CHANNEL_OUT_STEREO", "I"));
  const jint android_media_AudioFormat_ENCODING_PCM_8BIT =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "ENCODING_PCM_8BIT", "I"));
  const jint android_media_AudioFormat_ENCODING_PCM_16BIT =
      (*env)->GetStaticIntField(
          env, android_media_AudioFormat,
          (*env)->GetStaticFieldID(env, android_media_AudioFormat, "ENCODING_PCM_16BIT", "I"));

  jint channel = android_media_AudioFormat_CHANNEL_OUT_MONO;
  switch (channelNum) {
  case 1:
    channel = android_media_AudioFormat_CHANNEL_OUT_MONO;
    break;
  case 2:
    channel = android_media_AudioFormat_CHANNEL_OUT_STEREO;
    break;
  default:
    return "invalid channel";
  }

  jint encoding = android_media_AudioFormat_ENCODING_PCM_8BIT;
  switch (bytesPerSample) {
  case 1:
    encoding = android_media_AudioFormat_ENCODING_PCM_8BIT;
    break;
  case 2:
    encoding = android_media_AudioFormat_ENCODING_PCM_16BIT;
    break;
  default:
    return "invalid bytesPerSample";
  }

  *bufferSize =
      (*env)->CallStaticIntMethod(
          env, android_media_AudioTrack,
          (*env)->GetStaticMethodID(env, android_media_AudioTrack, "getMinBufferSize", "(III)I"),
          sampleRate, channel, encoding);

  const jobject tmpAudioTrack =
      (*env)->NewObject(
          env, android_media_AudioTrack,
          (*env)->GetMethodID(env, android_media_AudioTrack, "<init>", "(IIIIII)V"),
          android_media_AudioManager_STREAM_MUSIC,
          sampleRate, channel, encoding, *bufferSize,
          android_media_AudioTrack_MODE_STREAM);
  // Note that *audioTrack will never be released.
  *audioTrack = (*env)->NewGlobalRef(env, tmpAudioTrack);
  (*env)->DeleteLocalRef(env, tmpAudioTrack);

  (*env)->CallVoidMethod(
      env, *audioTrack,
      (*env)->GetMethodID(env, android_media_AudioTrack, "play", "()V"));

  return NULL;
}

static char* writeToAudioTrack(uintptr_t java_vm, uintptr_t jni_env,
    jobject audioTrack, int bytesPerSample, void* data, int length) {
  JavaVM* vm = (JavaVM*)java_vm;
  JNIEnv* env = (JNIEnv*)jni_env;

  const jclass android_media_AudioTrack =
      (*env)->FindClass(env, "android/media/AudioTrack");

  jbyteArray arrInBytes;
  jshortArray arrInShorts;
  switch (bytesPerSample) {
  case 1:
    arrInBytes = (*env)->NewByteArray(env, length);
    (*env)->SetByteArrayRegion(env, arrInBytes, 0, length, data);
    break;
  case 2:
    arrInShorts = (*env)->NewShortArray(env, length);
    (*env)->SetShortArrayRegion(env, arrInShorts, 0, length, data);
    break;
  }

  jint result;
  switch (bytesPerSample) {
  case 1:
    result =
        (*env)->CallIntMethod(
            env, audioTrack,
            (*env)->GetMethodID(env, android_media_AudioTrack, "write", "([BII)I"),
            arrInBytes, 0, length);
    (*env)->DeleteLocalRef(env, arrInBytes);
    break;
  case 2:
    result =
        (*env)->CallIntMethod(
            env, audioTrack,
            (*env)->GetMethodID(env, android_media_AudioTrack, "write", "([SII)I"),
            arrInShorts, 0, length);
    (*env)->DeleteLocalRef(env, arrInShorts);
    break;
  }

  switch (result) {
  case -3: // ERROR_INVALID_OPERATION
    return "invalid operation";
  case -2: // ERROR_BAD_VALUE
    return "bad value";
  case -1: // ERROR
    return "error";
  }
  if (result < 0) {
    return "unknown error";
  }
  return NULL;
}

*/
import "C"

import (
	"errors"
	"unsafe"

	"github.com/hajimehoshi/ebiten/internal/jni"
)

type Player struct {
	sampleRate     int
	channelNum     int
	bytesPerSample int
	audioTrack     C.jobject
	buffer         []byte
	bufferSize     int
	chErr          chan error
	chBuffer       chan []byte
}

func NewPlayer(sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	p := &Player{
		sampleRate:     sampleRate,
		channelNum:     channelNum,
		bytesPerSample: bytesPerSample,
		buffer:         []byte{},
		chErr:          make(chan error),
		chBuffer:       make(chan []byte, 8),
	}
	if err := jni.RunOnJVM(func(vm, env, ctx uintptr) error {
		audioTrack := C.jobject(nil)
		bufferSize := C.int(0)
		if msg := C.initAudioTrack(C.uintptr_t(vm), C.uintptr_t(env),
			C.int(sampleRate), C.int(channelNum), C.int(bytesPerSample),
			&audioTrack, &bufferSize); msg != nil {
			return errors.New("driver: " + C.GoString(msg))
		}
		p.audioTrack = audioTrack
		p.bufferSize = int(bufferSize)
		return nil
	}); err != nil {
		return nil, err
	}
	go p.loop()
	return p, nil
}

func (p *Player) loop() {
	for bufInBytes := range p.chBuffer {
		var bufInShorts []int16
		if p.bytesPerSample == 2 {
			bufInShorts = make([]int16, len(bufInBytes)/2)
			for i := 0; i < len(bufInShorts); i++ {
				bufInShorts[i] = int16(bufInBytes[2*i]) | (int16(bufInBytes[2*i+1]) << 8)
			}
		}

		if err := jni.RunOnJVM(func(vm, env, ctx uintptr) error {
			msg := (*C.char)(nil)
			switch p.bytesPerSample {
			case 1:
				msg = C.writeToAudioTrack(C.uintptr_t(vm), C.uintptr_t(env),
					p.audioTrack, C.int(p.bytesPerSample),
					unsafe.Pointer(&bufInBytes[0]), C.int(len(bufInBytes)))
			case 2:
				msg = C.writeToAudioTrack(C.uintptr_t(vm), C.uintptr_t(env),
					p.audioTrack, C.int(p.bytesPerSample),
					unsafe.Pointer(&bufInShorts[0]), C.int(len(bufInShorts)))
			default:
				panic("not reach")
			}
			if msg != nil {
				return errors.New(C.GoString(msg))
			}
			return nil
		}); err != nil {
			p.chErr <- err
			return
		}
	}
}

func (p *Player) Proceed(data []byte) error {
	p.buffer = append(p.buffer, data...)
	if len(p.buffer) < p.bufferSize {
		return nil
	}
	buf := p.buffer[:p.bufferSize]
	select {
	case p.chBuffer <- buf:
	case err := <-p.chErr:
		return err
	}
	p.buffer = p.buffer[p.bufferSize:]
	return nil
}

func (p *Player) Close() error {
	return nil
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"fmt"

	"v.io/v23"
	"v.io/v23/ipc"
	"v.io/x/lib/vlog"
	"v.io/x/ref/lib/signals"
	_ "v.io/x/ref/profiles"

	"pingpong"
)

type pongd struct{}

func (f *pongd) Ping(ctx ipc.ServerCall, message string) (result string, err error) {
	remote, _ := ctx.RemoteBlessings().ForCall(ctx)
	fmt.Printf("%v: %q\n", remote, message)
	return "PONG", nil
}

func main() {
	ctx, shutdown := v23.Init()
	defer shutdown()

	s, err := v23.NewServer(ctx)
	if err != nil {
		vlog.Fatal("failure creating server: ", err)
	}

	serverPong := pingpong.PingPongServer(&pongd{})

	fmt.Printf("Starting server\n")
	if endpoint, err := s.Listen(v23.GetListenSpec(ctx)); err == nil {
		fmt.Printf("Listening at: %v\n", endpoint)
	} else {
		vlog.Fatal("error listening to service: ", err)
	}

	if err := s.Serve("pingpong", serverPong, nil); err == nil {
		fmt.Printf("Serving pingpong\n")
	} else {
		vlog.Fatal("error serving service: ", err)
	}

	// Wait forever.
	<-signals.ShutdownOnSignals(ctx)
}
<commit_msg>playground: Update many variable names for *Calls to call.<commit_after>// +build ignore

package main

import (
	"fmt"

	"v.io/v23"
	"v.io/v23/ipc"
	"v.io/x/lib/vlog"
	"v.io/x/ref/lib/signals"
	_ "v.io/x/ref/profiles"

	"pingpong"
)

type pongd struct{}

func (f *pongd) Ping(call ipc.ServerCall, message string) (result string, err error) {
	remote, _ := call.RemoteBlessings().ForCall(call)
	fmt.Printf("%v: %q\n", remote, message)
	return "PONG", nil
}

func main() {
	ctx, shutdown := v23.Init()
	defer shutdown()

	s, err := v23.NewServer(ctx)
	if err != nil {
		vlog.Fatal("failure creating server: ", err)
	}

	serverPong := pingpong.PingPongServer(&pongd{})

	fmt.Printf("Starting server\n")
	if endpoint, err := s.Listen(v23.GetListenSpec(ctx)); err == nil {
		fmt.Printf("Listening at: %v\n", endpoint)
	} else {
		vlog.Fatal("error listening to service: ", err)
	}

	if err := s.Serve("pingpong", serverPong, nil); err == nil {
		fmt.Printf("Serving pingpong\n")
	} else {
		vlog.Fatal("error serving service: ", err)
	}

	// Wait forever.
	<-signals.ShutdownOnSignals(ctx)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

This tests select/insert using the unshared keyspace added in main_test
*/
package clustertest

import (
	"context"
	"fmt"
	"testing"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
)

func TestVtgateProcess(t *testing.T) {
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()

	exec(t, conn, "insert into customer(id, email) values(1,'email1')")

	qr := exec(t, conn, "select id, email from customer")
	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("email1")]]`; got != want {
		t.Errorf("select:\n%v want\n%v", got, want)
	}
}

func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
	t.Helper()
	qr, err := conn.ExecuteFetch(query, 1000, true)
	if err != nil {
		t.Fatal(err)
	}
	return qr
}
<commit_msg>added testcase for vtgate vars<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

This tests select/insert using the unshared keyspace added in main_test
*/
package clustertest

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
	"testing"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
)

func TestVtgateProcess(t *testing.T) {
	verifyVtgateVariables(t, clusterInstance.VtgateProcess.VerifyURL)
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()

	exec(t, conn, "insert into customer(id, email) values(1,'email1')")

	qr := exec(t, conn, "select id, email from customer")
	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("email1")]]`; got != want {
		t.Errorf("select:\n%v want\n%v", got, want)
	}
}

func verifyVtgateVariables(t *testing.T, url string) {
	resp, _ := http.Get(url)
	if resp != nil && resp.StatusCode == 200 {
		resultMap := make(map[string]interface{})
		respByte, _ := ioutil.ReadAll(resp.Body)
		err := json.Unmarshal(respByte, &resultMap)
		if err != nil {
			t.Fatal(err)
		}
		if resultMap["VtgateVSchemaCounts"] == nil {
			t.Error("Vschema count should be present in variables")
		}
		vschemaCountMap := getMapFromJSON(resultMap, "VtgateVSchemaCounts")
		if _, present := vschemaCountMap["Reload"]; !present {
			t.Error("Reload count should be present in vschemacount")
		} else if object := reflect.ValueOf(vschemaCountMap["Reload"]); object.NumField() <= 0 {
			t.Error("Reload count should be greater than 0")
		}
		if _, present := vschemaCountMap["WatchError"]; present {
			t.Error("There should not be any WatchError in VschemaCount")
		}
		if _, present := vschemaCountMap["Parsing"]; present {
			t.Error("There should not be any Parsing in VschemaCount")
		}

		if resultMap["HealthcheckConnections"] == nil {
			t.Error("HealthcheckConnections count should be present in variables")
		}

		healthCheckConnection := getMapFromJSON(resultMap, "HealthcheckConnections")
		if len(healthCheckConnection) <= 0 {
			t.Error("Atleast one healthy tablet needs to be present")
		}
		if !isMasterTabletPresent(healthCheckConnection) {
			t.Error("Atleast one master tablet needs to be present")
		}
	} else {
		t.Error("Vtgate api url response not found")
	}
}

func getMapFromJSON(JSON map[string]interface{}, key string) map[string]interface{} {
	result := make(map[string]interface{})
	object := reflect.ValueOf(JSON[key])
	if object.Kind() == reflect.Map {
		for _, key := range object.MapKeys() {
			value := object.MapIndex(key)
			result[key.String()] = value
		}
	}
	return result
}

func isMasterTabletPresent(tablets map[string]interface{}) bool {
	for key := range tablets {
		if strings.Contains(key, "master") {
			return true
		}
	}
	return false
}

func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
	t.Helper()
	qr, err := conn.ExecuteFetch(query, 1000, true)
	if err != nil {
		t.Fatal(err)
	}
	return qr
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/aws/aws-sdk-go/aws"
)

func dataSourceAwsInternetGateway() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceAwsInternetGatewayRead,
		Schema: map[string]*schema.Schema{
			"internet_gateway_id": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"filter": ec2CustomFiltersSchema(),
			"tags":   tagsSchemaComputed(),
			"attachments": {
				Type:     schema.TypeList,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"state": {
							Type:     schema.TypeString,
							Computed: true,
						},
						"vpc_id": {
							Type:     schema.TypeString,
							Computed: true,
						},
					},
				},
			},
		},
	}
}

func dataSourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	req := &ec2.DescribeInternetGatewaysInput{}
	internetGatewayId, internetGatewayIdOk := d.GetOk("internet_gateway_id")
	tags, tagsOk := d.GetOk("tags")
	filter, filterOk := d.GetOk("filter")

	if !internetGatewayIdOk && !filterOk && !tagsOk {
		return fmt.Errorf("One of internet_gateway_id or filter or tags must be assigned")
	}

	req.Filters = buildEC2AttributeFilterList(map[string]string{
		"internet-gateway-id": internetGatewayId.(string),
	})
	req.Filters = append(req.Filters, buildEC2TagFilterList(
		tagsFromMap(tags.(map[string]interface{})),
	)...)
	req.Filters = append(req.Filters, buildEC2CustomFilterList(
		filter.(*schema.Set),
	)...)
	log.Printf("[DEBUG] Describe Internet Gateways %v\n", req)

	resp, err := conn.DescribeInternetGateways(req)

	if err != nil {
		return err
	}
	if resp == nil || len(resp.InternetGateways) == 0 {
		return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
	}
	if len(resp.InternetGateways) > 1 {
		return fmt.Errorf("Multiple Internet Gateways matched; use additional constraints to reduce matches to a single Internet Gateway")
	}

	igw := resp.InternetGateways[0]
	d.SetId(aws.StringValue(igw.InternetGatewayId))
	d.Set("tags", tagsToMap(igw.Tags))
	d.Set("internet_gateway_id", igw.InternetGatewayId)
	if err := d.Set("attachments", dataSourceAttachmentsRead(igw.Attachments)); err != nil {
		return err
	}

	return nil
}

func dataSourceAttachmentsRead(igwAttachments []*ec2.InternetGatewayAttachment) []map[string]interface{} {
	attachments := make([]map[string]interface{}, 0, len(igwAttachments))
	for _, a := range igwAttachments {
		m := make(map[string]interface{})
		m["state"] = *a.State
		m["vpc_id"] = *a.VpcId
		attachments = append(attachments, m)
	}

	return attachments
}
<commit_msg>run go fmt<commit_after>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsInternetGateway() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceAwsInternetGatewayRead,
		Schema: map[string]*schema.Schema{
			"internet_gateway_id": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"filter": ec2CustomFiltersSchema(),
			"tags":   tagsSchemaComputed(),
			"attachments": {
				Type:     schema.TypeList,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"state": {
							Type:     schema.TypeString,
							Computed: true,
						},
						"vpc_id": {
							Type:     schema.TypeString,
							Computed: true,
						},
					},
				},
			},
		},
	}
}

func dataSourceAwsInternetGatewayRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	req := &ec2.DescribeInternetGatewaysInput{}
	internetGatewayId, internetGatewayIdOk := d.GetOk("internet_gateway_id")
	tags, tagsOk := d.GetOk("tags")
	filter, filterOk := d.GetOk("filter")

	if !internetGatewayIdOk && !filterOk && !tagsOk {
		return fmt.Errorf("One of internet_gateway_id or filter or tags must be assigned")
	}

	req.Filters = buildEC2AttributeFilterList(map[string]string{
		"internet-gateway-id": internetGatewayId.(string),
	})
	req.Filters = append(req.Filters, buildEC2TagFilterList(
		tagsFromMap(tags.(map[string]interface{})),
	)...)
	req.Filters = append(req.Filters, buildEC2CustomFilterList(
		filter.(*schema.Set),
	)...)
	log.Printf("[DEBUG] Describe Internet Gateways %v\n", req)

	resp, err := conn.DescribeInternetGateways(req)

	if err != nil {
		return err
	}
	if resp == nil || len(resp.InternetGateways) == 0 {
		return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
	}
	if len(resp.InternetGateways) > 1 {
		return fmt.Errorf("Multiple Internet Gateways matched; use additional constraints to reduce matches to a single Internet Gateway")
	}

	igw := resp.InternetGateways[0]
	d.SetId(aws.StringValue(igw.InternetGatewayId))
	d.Set("tags", tagsToMap(igw.Tags))
	d.Set("internet_gateway_id", igw.InternetGatewayId)
	if err := d.Set("attachments", dataSourceAttachmentsRead(igw.Attachments)); err != nil {
		return err
	}

	return nil
}

func dataSourceAttachmentsRead(igwAttachments []*ec2.InternetGatewayAttachment) []map[string]interface{} {
	attachments := make([]map[string]interface{}, 0, len(igwAttachments))
	for _, a := range igwAttachments {
		m := make(map[string]interface{})
		m["state"] = *a.State
		m["vpc_id"] = *a.VpcId
		attachments = append(attachments, m)
	}

	return attachments
}
<|endoftext|>