<commit_before>/*
Package gorbac provides a lightweight role-based access
control implementation in Golang.

For the purposes of this package:

	* an identity has one or more roles.
	* a role requests access to a permission.
	* a permission is given to a role.

Thus, RBAC has the following model:

	* many to many relationship between identities and roles.
	* many to many relationship between roles and permissions.
	* roles can have parent roles.
*/
package gorbac

import (
	"errors"
	"sync"
)

var (
	ErrRoleNotExist = errors.New("Role does not exist")
	ErrRoleExist    = errors.New("Role has already existed")
	empty           = struct{}{}
)

// AssertionFunc supplies more fine-grained permission controls.
type AssertionFunc func(*RBAC, string, Permission) bool

// RBAC object, in most cases it should be used as a singleton.
type RBAC struct {
	mutex       sync.RWMutex
	roles       Roles
	permissions Permissions
	parents     map[string]map[string]struct{}
}

// New returns a RBAC structure.
// The default role structure will be used.
func New() *RBAC {
	return &RBAC{
		roles:       make(Roles),
		permissions: make(Permissions),
		parents:     make(map[string]map[string]struct{}),
	}
}

// SetParents bind `parents` to the role `id`.
// If the role or any of parents is not existing,
// an error will be returned.
func (rbac *RBAC) SetParents(id string, parents []string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	for _, parent := range parents {
		if _, ok := rbac.roles[parent]; !ok {
			return ErrRoleNotExist
		}
	}
	if _, ok := rbac.parents[id]; !ok {
		rbac.parents[id] = make(map[string]struct{})
	}
	for _, parent := range parents {
		rbac.parents[id][parent] = empty
	}
	return nil
}

// GetParents return `parents` of the role `id`.
// If the role is not existing, an error will be returned.
// Or the role doesn't have any parents,
// a nil slice will be returned.
func (rbac *RBAC) GetParents(id string) ([]string, error) {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return nil, ErrRoleNotExist
	}
	ids, ok := rbac.parents[id]
	if !ok {
		return nil, nil
	}
	parents := make([]string, 0)
	for parent, _ := range ids {
		parents = append(parents, parent)
	}
	return parents, nil
}

// SetParent bind the `parent` to the role `id`.
// If the role or the parent is not existing,
// an error will be returned.
func (rbac *RBAC) SetParent(id string, parent string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	if _, ok := rbac.roles[parent]; !ok {
		return ErrRoleNotExist
	}
	if _, ok := rbac.parents[id]; !ok {
		rbac.parents[id] = make(map[string]struct{})
	}
	var empty struct{}
	rbac.parents[id][parent] = empty
	return nil
}

// RemoveParent unbind the `parent` with the role `id`.
// If the role or the parent is not existing,
// an error will be returned.
func (rbac *RBAC) RemoveParent(id string, parent string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	if _, ok := rbac.roles[parent]; !ok {
		return ErrRoleNotExist
	}
	delete(rbac.parents[id], parent)
	return nil
}

// Add a role `r`.
func (rbac *RBAC) Add(r Role) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[r.Id()]; ok {
		return ErrRoleExist
	}
	rbac.roles[r.Id()] = r
	return nil
}

// Remove the role by `id`.
func (rbac *RBAC) Remove(id string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	delete(rbac.roles, id)
	for rid, parents := range rbac.parents {
		if rid == id {
			delete(rbac.parents, rid)
			continue
		}
		for parent, _ := range parents {
			if parent == id {
				delete(rbac.parents[rid], id)
				break
			}
		}
	}
	return nil
}

// Get the role by `id` and a slice of its parents id.
func (rbac *RBAC) Get(id string) (Role, []string, error) {
	rbac.mutex.RLock()
	defer rbac.mutex.RUnlock()
	r, ok := rbac.roles[id]
	if !ok {
		return nil, nil, ErrRoleNotExist
	}
	parents := make([]string, 0)
	for parent, _ := range rbac.parents[id] {
		parents = append(parents, parent)
	}
	return r, parents, nil
}

// IsGranted tests if the role `id` has Permission `p` with the condition `assert`.
func (rbac *RBAC) IsGranted(id string, p Permission, assert AssertionFunc) bool {
	rbac.mutex.RLock()
	defer rbac.mutex.RUnlock()
	return rbac.isGranted(id, p, assert)
}

func (rbac *RBAC) isGranted(id string, p Permission, assert AssertionFunc) bool {
	if assert != nil && !assert(rbac, id, p) {
		return false
	}
	if role, ok := rbac.roles[id]; ok {
		if role.HasPermission(p) {
			return true
		}
		if parents, ok := rbac.parents[id]; ok {
			for pId, _ := range parents {
				if pRole, ok := rbac.roles[pId]; ok {
					if pRole.HasPermission(p) {
						return true
					}
				}
			}
		}
	}
	return false
}
<commit_msg>fixed parent granted issue<commit_after>/*
Package gorbac provides a lightweight role-based access
control implementation in Golang.

For the purposes of this package:

	* an identity has one or more roles.
	* a role requests access to a permission.
	* a permission is given to a role.

Thus, RBAC has the following model:

	* many to many relationship between identities and roles.
	* many to many relationship between roles and permissions.
	* roles can have parent roles.
*/
package gorbac

import (
	"errors"
	"sync"
)

var (
	ErrRoleNotExist = errors.New("Role does not exist")
	ErrRoleExist    = errors.New("Role has already existed")
	empty           = struct{}{}
)

// AssertionFunc supplies more fine-grained permission controls.
type AssertionFunc func(*RBAC, string, Permission) bool

// RBAC object, in most cases it should be used as a singleton.
type RBAC struct {
	mutex       sync.RWMutex
	roles       Roles
	permissions Permissions
	parents     map[string]map[string]struct{}
}

// New returns a RBAC structure.
// The default role structure will be used.
func New() *RBAC {
	return &RBAC{
		roles:       make(Roles),
		permissions: make(Permissions),
		parents:     make(map[string]map[string]struct{}),
	}
}

// SetParents bind `parents` to the role `id`.
// If the role or any of parents is not existing,
// an error will be returned.
func (rbac *RBAC) SetParents(id string, parents []string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	for _, parent := range parents {
		if _, ok := rbac.roles[parent]; !ok {
			return ErrRoleNotExist
		}
	}
	if _, ok := rbac.parents[id]; !ok {
		rbac.parents[id] = make(map[string]struct{})
	}
	for _, parent := range parents {
		rbac.parents[id][parent] = empty
	}
	return nil
}

// GetParents return `parents` of the role `id`.
// If the role is not existing, an error will be returned.
// Or the role doesn't have any parents,
// a nil slice will be returned.
func (rbac *RBAC) GetParents(id string) ([]string, error) {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return nil, ErrRoleNotExist
	}
	ids, ok := rbac.parents[id]
	if !ok {
		return nil, nil
	}
	parents := make([]string, 0)
	for parent, _ := range ids {
		parents = append(parents, parent)
	}
	return parents, nil
}

// SetParent bind the `parent` to the role `id`.
// If the role or the parent is not existing,
// an error will be returned.
func (rbac *RBAC) SetParent(id string, parent string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	if _, ok := rbac.roles[parent]; !ok {
		return ErrRoleNotExist
	}
	if _, ok := rbac.parents[id]; !ok {
		rbac.parents[id] = make(map[string]struct{})
	}
	var empty struct{}
	rbac.parents[id][parent] = empty
	return nil
}

// RemoveParent unbind the `parent` with the role `id`.
// If the role or the parent is not existing,
// an error will be returned.
func (rbac *RBAC) RemoveParent(id string, parent string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	if _, ok := rbac.roles[parent]; !ok {
		return ErrRoleNotExist
	}
	delete(rbac.parents[id], parent)
	return nil
}

// Add a role `r`.
func (rbac *RBAC) Add(r Role) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[r.Id()]; ok {
		return ErrRoleExist
	}
	rbac.roles[r.Id()] = r
	return nil
}

// Remove the role by `id`.
func (rbac *RBAC) Remove(id string) error {
	rbac.mutex.Lock()
	defer rbac.mutex.Unlock()
	if _, ok := rbac.roles[id]; !ok {
		return ErrRoleNotExist
	}
	delete(rbac.roles, id)
	for rid, parents := range rbac.parents {
		if rid == id {
			delete(rbac.parents, rid)
			continue
		}
		for parent, _ := range parents {
			if parent == id {
				delete(rbac.parents[rid], id)
				break
			}
		}
	}
	return nil
}

// Get the role by `id` and a slice of its parents id.
func (rbac *RBAC) Get(id string) (Role, []string, error) {
	rbac.mutex.RLock()
	defer rbac.mutex.RUnlock()
	r, ok := rbac.roles[id]
	if !ok {
		return nil, nil, ErrRoleNotExist
	}
	parents := make([]string, 0)
	for parent, _ := range rbac.parents[id] {
		parents = append(parents, parent)
	}
	return r, parents, nil
}

// IsGranted tests if the role `id` has Permission `p` with the condition `assert`.
func (rbac *RBAC) IsGranted(id string, p Permission, assert AssertionFunc) bool {
	rbac.mutex.RLock()
	defer rbac.mutex.RUnlock()
	return rbac.isGranted(id, p, assert)
}

func (rbac *RBAC) isGranted(id string, p Permission, assert AssertionFunc) bool {
	if assert != nil && !assert(rbac, id, p) {
		return false
	}
	return rbac.recursionCheck(id, p)
}

func (rbac *RBAC) recursionCheck(id string, p Permission) bool {
	if role, ok := rbac.roles[id]; ok {
		if role.HasPermission(p) {
			return true
		}
		if parents, ok := rbac.parents[id]; ok {
			for pId, _ := range parents {
				if _, ok := rbac.roles[pId]; ok {
					if rbac.recursionCheck(pId, p) {
						return true
					}
				}
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All rights reserved.
//
// 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 zoekt

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"log"
	"sort"
)

// reader is a stateful file
type reader struct {
	r   IndexFile
	off uint32
}

func (r *reader) seek(off uint32) {
	r.off = off
}

func (r *reader) U32() (uint32, error) {
	b, err := r.r.Read(r.off, 4)
	r.off += 4
	if err != nil {
		return 0, err
	}
	return binary.BigEndian.Uint32(b), nil
}

var _ = log.Println

func (r *reader) readTOC(toc *indexTOC) error {
	sz, err := r.r.Size()
	if err != nil {
		return err
	}
	r.off = sz - 8

	var tocSection simpleSection
	if err := tocSection.read(r); err != nil {
		return err
	}

	r.seek(tocSection.off)

	sectionCount, err := r.U32()
	if err != nil {
		return err
	}

	secs := toc.sections()

	if len(secs) != int(sectionCount) {
		return fmt.Errorf("section count mismatch: got %d want %d", len(secs), sectionCount)
	}

	for _, s := range toc.sections() {
		if err := s.read(r); err != nil {
			return err
		}
	}
	return nil
}

func (r *indexData) readSectionBlob(sec simpleSection) ([]byte, error) {
	return r.file.Read(sec.off, sec.sz)
}

func (r *indexData) readSectionU32(sec simpleSection) ([]uint32, error) {
	return readSectionU32(r.file, sec)
}

func readSectionU32(f IndexFile, sec simpleSection) ([]uint32, error) {
	if sec.sz%4 != 0 {
		return nil, fmt.Errorf("barf: section size %% 4 != 0: sz %d ", sec.sz)
	}
	blob, err := f.Read(sec.off, sec.sz)
	if err != nil {
		return nil, err
	}
	arr := make([]uint32, 0, len(blob)/4)
	for len(blob) > 0 {
		arr = append(arr, binary.BigEndian.Uint32(blob))
		blob = blob[4:]
	}
	return arr, nil
}

func (r *reader) readIndexData(toc *indexTOC) (*indexData, error) {
	d := indexData{
		file:           r.r,
		ngrams:         map[ngram]simpleSection{},
		fileNameNgrams: map[ngram][]uint32{},
		branchIDs:      map[string]uint{},
		branchNames:    map[uint]string{},
	}
	blob, err := d.readSectionBlob(toc.unaryData)
	if err != nil {
		return nil, err
	}

	if err := json.Unmarshal(blob, &d.unaryData); err != nil {
		return nil, err
	}

	if d.unaryData.IndexFormatVersion != IndexFormatVersion {
		return nil, fmt.Errorf("file is v%d, want v%d", d.unaryData.IndexFormatVersion, IndexFormatVersion)
	}

	d.boundaries = toc.fileContents.absoluteIndex()
	d.newlinesIndex = toc.newlines.absoluteIndex()
	d.docSectionsIndex = toc.fileSections.absoluteIndex()

	textContent, err := d.readSectionBlob(toc.ngramText)
	if err != nil {
		return nil, err
	}
	postingsIndex := toc.postings.absoluteIndex()

	for i := 0; i < len(textContent); i += ngramSize {
		j := i / ngramSize
		d.ngrams[bytesToNGram(textContent[i:i+ngramSize])] = simpleSection{
			postingsIndex[j],
			postingsIndex[j+1] - postingsIndex[j],
		}
	}

	if r := toc.fileContents.relativeIndex(); len(r) > 0 {
		d.fileEnds = r[1:]
	}
	d.fileBranchMasks, err = d.readSectionU32(toc.branchMasks)
	if err != nil {
		return nil, err
	}

	d.fileNameContent, err = d.readSectionBlob(toc.fileNames.data)
	if err != nil {
		return nil, err
	}

	d.fileNameIndex = toc.fileNames.relativeIndex()

	nameNgramText, err := d.readSectionBlob(toc.nameNgramText)
	if err != nil {
		return nil, err
	}

	fileNamePostingsData, err := d.readSectionBlob(toc.namePostings.data)
	if err != nil {
		return nil, err
	}

	fileNamePostingsIndex := toc.namePostings.relativeIndex()
	for i := 0; i < len(nameNgramText); i += ngramSize {
		j := i / ngramSize
		off := fileNamePostingsIndex[j]
		end := fileNamePostingsIndex[j+1]
		ngram := bytesToNGram(nameNgramText[i : i+ngramSize])
		d.fileNameNgrams[ngram] = fromDeltas(fileNamePostingsData[off:end], nil)
	}

	for j, br := range d.unaryData.Repository.Branches {
		id := uint(1) << uint(j)
		d.branchIDs[br.Name] = id
		d.branchNames[id] = br.Name
	}

	if blob, err := d.readSectionBlob(toc.subRepos); err != nil {
		return nil, err
	} else {
		d.subRepos = fromSizedDeltas(blob, nil)
	}

	var keys []string
	for k := range d.unaryData.SubRepoMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	d.subRepoPaths = keys

	return &d, nil
}

func (d *indexData) readContents(i uint32) ([]byte, error) {
	return d.readSectionBlob(simpleSection{
		off: d.boundaries[i],
		sz:  d.boundaries[i+1] - d.boundaries[i],
	})
}

func (d *indexData) readNewlines(i uint32, buf []uint32) ([]uint32, error) {
	blob, err := d.readSectionBlob(simpleSection{
		off: d.newlinesIndex[i],
		sz:  d.newlinesIndex[i+1] - d.newlinesIndex[i],
	})
	if err != nil {
		return nil, err
	}

	return fromSizedDeltas(blob, buf), nil
}

func (d *indexData) readDocSections(i uint32) ([]DocumentSection, error) {
	blob, err := d.readSectionBlob(simpleSection{
		off: d.docSectionsIndex[i],
		sz:  d.docSectionsIndex[i+1] - d.docSectionsIndex[i],
	})
	if err != nil {
		return nil, err
	}

	return unmarshalDocSections(blob), nil
}

// IndexFile is a file suitable for concurrent read access. For performance
// reasons, it allows a mmap'd implementation.
type IndexFile interface {
	Read(off uint32, sz uint32) ([]byte, error)
	Size() (uint32, error)
	Close()
	Name() string
}

// NewSearcher creates a Searcher for a single index file.
func NewSearcher(r IndexFile) (Searcher, error) {
	rd := &reader{r: r}

	var toc indexTOC
	if err := rd.readTOC(&toc); err != nil {
		return nil, err
	}
	indexData, err := rd.readIndexData(&toc)
	if err != nil {
		return nil, err
	}
	indexData.file = r
	return indexData, nil
}
<commit_msg>Add some basic paranoia checks after reading the index.<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// 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 zoekt

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"log"
	"sort"
)

// reader is a stateful file
type reader struct {
	r   IndexFile
	off uint32
}

func (r *reader) seek(off uint32) {
	r.off = off
}

func (r *reader) U32() (uint32, error) {
	b, err := r.r.Read(r.off, 4)
	r.off += 4
	if err != nil {
		return 0, err
	}
	return binary.BigEndian.Uint32(b), nil
}

var _ = log.Println

func (r *reader) readTOC(toc *indexTOC) error {
	sz, err := r.r.Size()
	if err != nil {
		return err
	}
	r.off = sz - 8

	var tocSection simpleSection
	if err := tocSection.read(r); err != nil {
		return err
	}

	r.seek(tocSection.off)

	sectionCount, err := r.U32()
	if err != nil {
		return err
	}

	secs := toc.sections()

	if len(secs) != int(sectionCount) {
		return fmt.Errorf("section count mismatch: got %d want %d", len(secs), sectionCount)
	}

	for _, s := range toc.sections() {
		if err := s.read(r); err != nil {
			return err
		}
	}
	return nil
}

func (r *indexData) readSectionBlob(sec simpleSection) ([]byte, error) {
	return r.file.Read(sec.off, sec.sz)
}

func (r *indexData) readSectionU32(sec simpleSection) ([]uint32, error) {
	return readSectionU32(r.file, sec)
}

func readSectionU32(f IndexFile, sec simpleSection) ([]uint32, error) {
	if sec.sz%4 != 0 {
		return nil, fmt.Errorf("barf: section size %% 4 != 0: sz %d ", sec.sz)
	}
	blob, err := f.Read(sec.off, sec.sz)
	if err != nil {
		return nil, err
	}
	arr := make([]uint32, 0, len(blob)/4)
	for len(blob) > 0 {
		arr = append(arr, binary.BigEndian.Uint32(blob))
		blob = blob[4:]
	}
	return arr, nil
}

func (r *reader) readIndexData(toc *indexTOC) (*indexData, error) {
	d := indexData{
		file:           r.r,
		ngrams:         map[ngram]simpleSection{},
		fileNameNgrams: map[ngram][]uint32{},
		branchIDs:      map[string]uint{},
		branchNames:    map[uint]string{},
	}
	blob, err := d.readSectionBlob(toc.unaryData)
	if err != nil {
		return nil, err
	}

	if err := json.Unmarshal(blob, &d.unaryData); err != nil {
		return nil, err
	}

	if d.unaryData.IndexFormatVersion != IndexFormatVersion {
		return nil, fmt.Errorf("file is v%d, want v%d", d.unaryData.IndexFormatVersion, IndexFormatVersion)
	}

	d.boundaries = toc.fileContents.absoluteIndex()
	d.newlinesIndex = toc.newlines.absoluteIndex()
	d.docSectionsIndex = toc.fileSections.absoluteIndex()

	textContent, err := d.readSectionBlob(toc.ngramText)
	if err != nil {
		return nil, err
	}
	postingsIndex := toc.postings.absoluteIndex()

	for i := 0; i < len(textContent); i += ngramSize {
		j := i / ngramSize
		d.ngrams[bytesToNGram(textContent[i:i+ngramSize])] = simpleSection{
			postingsIndex[j],
			postingsIndex[j+1] - postingsIndex[j],
		}
	}

	if r := toc.fileContents.relativeIndex(); len(r) > 0 {
		d.fileEnds = r[1:]
	}
	d.fileBranchMasks, err = d.readSectionU32(toc.branchMasks)
	if err != nil {
		return nil, err
	}

	d.fileNameContent, err = d.readSectionBlob(toc.fileNames.data)
	if err != nil {
		return nil, err
	}

	d.fileNameIndex = toc.fileNames.relativeIndex()

	nameNgramText, err := d.readSectionBlob(toc.nameNgramText)
	if err != nil {
		return nil, err
	}

	fileNamePostingsData, err := d.readSectionBlob(toc.namePostings.data)
	if err != nil {
		return nil, err
	}

	fileNamePostingsIndex := toc.namePostings.relativeIndex()
	for i := 0; i < len(nameNgramText); i += ngramSize {
		j := i / ngramSize
		off := fileNamePostingsIndex[j]
		end := fileNamePostingsIndex[j+1]
		ngram := bytesToNGram(nameNgramText[i : i+ngramSize])
		d.fileNameNgrams[ngram] = fromDeltas(fileNamePostingsData[off:end], nil)
	}

	for j, br := range d.unaryData.Repository.Branches {
		id := uint(1) << uint(j)
		d.branchIDs[br.Name] = id
		d.branchNames[id] = br.Name
	}

	if blob, err := d.readSectionBlob(toc.subRepos); err != nil {
		return nil, err
	} else {
		d.subRepos = fromSizedDeltas(blob, nil)
	}

	var keys []string
	for k := range d.unaryData.SubRepoMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	d.subRepoPaths = keys

	if err := d.verify(); err != nil {
		return nil, err
	}

	return &d, nil
}

func (d *indexData) verify() error {
	n := len(d.fileNameIndex)
	if n == 0 {
		return nil
	}

	n--
	if len(d.fileEnds) != n {
		return fmt.Errorf("file ends %d != %d", len(d.fileEnds), n)
	}
	if len(d.boundaries) != n+1 {
		return fmt.Errorf("file name idx %d != %d", len(d.fileNameIndex), n+1)
	}
	if len(d.fileBranchMasks) != n {
		return fmt.Errorf("branch masks.")
	}
	if len(d.docSectionsIndex) != n+1 {
		return fmt.Errorf("doc sections.")
	}
	if len(d.newlinesIndex) != n+1 {
		return fmt.Errorf("nls sections.")
	}
	return nil
}

func (d *indexData) readContents(i uint32) ([]byte, error) {
	return d.readSectionBlob(simpleSection{
		off: d.boundaries[i],
		sz:  d.boundaries[i+1] - d.boundaries[i],
	})
}

func (d *indexData) readNewlines(i uint32, buf []uint32) ([]uint32, error) {
	blob, err := d.readSectionBlob(simpleSection{
		off: d.newlinesIndex[i],
		sz:  d.newlinesIndex[i+1] - d.newlinesIndex[i],
	})
	if err != nil {
		return nil, err
	}

	return fromSizedDeltas(blob, buf), nil
}

func (d *indexData) readDocSections(i uint32) ([]DocumentSection, error) {
	blob, err := d.readSectionBlob(simpleSection{
		off: d.docSectionsIndex[i],
		sz:  d.docSectionsIndex[i+1] - d.docSectionsIndex[i],
	})
	if err != nil {
		return nil, err
	}

	return unmarshalDocSections(blob), nil
}

// IndexFile is a file suitable for concurrent read access. For performance
// reasons, it allows a mmap'd implementation.
type IndexFile interface {
	Read(off uint32, sz uint32) ([]byte, error)
	Size() (uint32, error)
	Close()
	Name() string
}

// NewSearcher creates a Searcher for a single index file.
func NewSearcher(r IndexFile) (Searcher, error) {
	rd := &reader{r: r}

	var toc indexTOC
	if err := rd.readTOC(&toc); err != nil {
		return nil, err
	}
	indexData, err := rd.readIndexData(&toc)
	if err != nil {
		return nil, err
	}
	indexData.file = r
	return indexData, nil
}
<|endoftext|>


<commit_before>package resp

import (
	"io"
	"errors"
	"bytes"
	"strconv"
	"strings"
)

const (
	T_SimpleString = '+'
	T_Error	   = '-'
	T_Integer	   = ':'
	T_BulkString  = '$'
	T_Array	   = '*'
)

var CRLF = []byte{'\r', '\n'}

//Command
//
//Command 格式：Inline Command 与 Array With BulkString
type Command struct {
	//根据惯例，Args[0] 是Name本身
	Args []string
}

//返回Command的名称，如GET\SET
func (c Command) Name() string {
	if len(c.Args)==0 {
		return ""
	} else {
		return c.Args[0]
	}
}

//以String形式获取Command[index]
func (c Command) String(index int) (ret string) {
	if len(c.Args) > index {
		ret = c.Args[index]
	}
	return ret
}

//以int64的形式返回Command.Args[index]
func (c Command) Integer(index int) (ret int64) {
	if len(c.Args) > index {
		ret, _ = strconv.ParseInt(c.Args[index], 10, 64)
	}
	return ret
}

//统一格式化为ArrayWithBulkString
func (c Command) Format() []byte {
	var ret *bytes.Buffer
	ret = new(bytes.Buffer)

	ret.WriteByte(T_Array)
	ret.WriteString(strconv.Itoa(len(c.Args)))
	ret.Write(CRLF)
	for index := range c.Args {
		ret.WriteByte(T_BulkString)
		ret.WriteString(strconv.Itoa(len(c.Args[index])))
		ret.Write(CRLF)
		ret.WriteString(c.Args[index])
		ret.Write(CRLF)
	}
	return ret.Bytes()
}

func NewCommand(args ...string) (*Command, error) {
	if len(args) == 0 {
		return nil, errors.New("err_new_cmd")
	}
	return &Command{Args:args}, nil
}

//从Reader中读取Command
func ReadCommand(r io.Reader) (*Command, error) {
	buf, err := readRespCommandLine(r)
	if nil != err {
		return nil, err
	}

	if T_Array != buf[0] {
		return NewCommand(strings.Fields(string(buf))...)
	}

	//Command: BulkString
	var ret *Data
	ret = new(Data)

	ret, err = readDataForSpecType(r, buf)
	if nil != err {
		return nil, err
	}

	commandArgs := make([]string, len(ret.Array))
	for index := range ret.Array {
		if ret.Array[index].T != T_BulkString {
			return nil, errors.New("Unexpected Command Type")
		}
		commandArgs[index] = string(ret.Array[index].String)
	}

	return NewCommand(commandArgs...)
}

type Data struct {
	T byte
	String []byte
	Integer int64
	Array []*Data
	IsNil bool
}

func (d Data) Format() []byte {
	var ret *bytes.Buffer
	ret = new(bytes.Buffer)

	ret.WriteByte(d.T)
	if d.IsNil {
		ret.WriteString("-1")
		ret.Write(CRLF)
		return ret.Bytes()
	}

	switch d.T {
		case T_SimpleString, T_Error:
			ret.Write(d.String)
			ret.Write(CRLF)
		case T_BulkString:
			ret.WriteString(strconv.Itoa(len(d.String)))
			ret.Write(CRLF)
			ret.Write(d.String)
			ret.Write(CRLF)
		case T_Integer:
			ret.WriteString(strconv.FormatInt(d.Integer, 10))
			ret.Write(CRLF)
		case T_Array:
			ret.WriteString(strconv.Itoa(len(d.Array)))
			ret.Write(CRLF)
			for index := range d.Array {
				ret.Write(d.Array[index].Format())
			}
	}
	return ret.Bytes()
}

func ReadData(r io.Reader) (*Data, error) {
	buf, err := readRespLine(r)
	if nil != err {
		return nil, err
	}

	if len(buf) < 2 {
		return nil, errors.New("invalid Data Source: " + string(buf))
	}

	return readDataForSpecType(r, buf)
}

func readDataForSpecType(r io.Reader, line []byte) (*Data, error) {

	var err error
	var ret *Data

	ret = new(Data)
	switch line[0] {
		case T_SimpleString:
			ret.T = T_SimpleString
			ret.String = line[1:]

		case T_Error:
			ret.T = T_Error
			ret.String = line[1:]

		case T_Integer:
			ret.T = T_Integer
			ret.Integer, err = strconv.ParseInt(string(line[1:]), 10, 64)

		case T_BulkString:
			var lenBulkString int64
			lenBulkString, err = strconv.ParseInt(string(line[1:]), 10, 64)

			ret.T = T_BulkString
			if -1 != lenBulkString {
				ret.String, err = readRespN(r, lenBulkString)
				_, err = readRespN(r, 2)
			} else {
				ret.IsNil = true
			}

		case T_Array:
			var lenArray int64
			var i int64
			lenArray, err = strconv.ParseInt(string(line[1:]), 10, 64)

			ret.T = T_Array
			if nil==err {
				if -1 != lenArray {
					ret.Array = make([]*Data, lenArray)
					for i=0; i<lenArray && nil == err; i++ {
						ret.Array[i], err = ReadData(r)
					}
				} else {
					ret.IsNil = true
				}
			}

		default: //Maybe you are Inline Command
			err = errors.New("Unexpected type ")

	}
	return ret, err
}

//读取当前行，并去掉最后的\r\n
func readRespLine(r io.Reader) ([]byte, error) {

	var i int
	var err error
	var buf []byte
	var ret *bytes.Buffer

	buf = make([]byte, 1)
	ret = &bytes.Buffer{}

	for {
		_, err = io.ReadFull(r, buf)
		if nil != err {
			return nil, err
		}

		i++
		ret.WriteByte(buf[0])
		if '\n' == buf[0] {
			break
		}
	}

	return ret.Next(i-2), nil
}

//读取老的redis协议 InlineCommand
func readRespCommandLine(r io.Reader) ([]byte, error) {

	var err error
	var buf []byte
	var ret *bytes.Buffer

	buf = make([]byte, 1)
	ret = &bytes.Buffer{}

	for {
		_, err = io.ReadFull(r, buf)
		if nil != err {
			if io.EOF == err {
				break
			}
			return nil, err
		}

		ret.WriteByte(buf[0])
		if '\n' == buf[0] {
			break
		}
	}

	return bytes.TrimSpace(ret.Bytes()), nil
}

//读取N个字节，并去掉最后的\r\n
func readRespN(r io.Reader, n int64) ([]byte, error) {
	var err error
	var ret []byte

	ret = make([]byte, n)
	_, err = io.ReadFull(r, ret)
	if nil!=err {
		ret = nil
	}
	return ret, err
}

//读取当前行的数字，并去掉最后的\r\n
func readRespIntLine(r io.Reader) (int64, error) {
	line, err := readRespLine(r)
	if nil!=err {
		return 0, err
	}
	return strconv.ParseInt(string(line), 10, 64)
}
<commit_msg>improve performance<commit_after>package resp

import (
	"io"
	"errors"
	"bytes"
	"strconv"
	"strings"
)

const (
	T_SimpleString = '+'
	T_Error	   = '-'
	T_Integer	   = ':'
	T_BulkString  = '$'
	T_Array	   = '*'
)

var CRLF = []byte{'\r', '\n'}

//Command
//
//Command 格式：Inline Command 与 Array With BulkString
type Command struct {
	//根据惯例，Args[0] 是Name本身
	Args []string
}

//返回Command的名称，如GET\SET
func (c Command) Name() string {
	if len(c.Args)==0 {
		return ""
	} else {
		return c.Args[0]
	}
}

//以String形式获取Command[index]
func (c Command) String(index int) (ret string) {
	if len(c.Args) > index {
		ret = c.Args[index]
	}
	return ret
}

//以int64的形式返回Command.Args[index]
func (c Command) Integer(index int) (ret int64) {
	if len(c.Args) > index {
		ret, _ = strconv.ParseInt(c.Args[index], 10, 64)
	}
	return ret
}

//统一格式化为ArrayWithBulkString
func (c Command) Format() []byte {
	var ret *bytes.Buffer
	ret = new(bytes.Buffer)

	ret.WriteByte(T_Array)
	ret.WriteString(strconv.Itoa(len(c.Args)))
	ret.Write(CRLF)
	for index := range c.Args {
		ret.WriteByte(T_BulkString)
		ret.WriteString(strconv.Itoa(len(c.Args[index])))
		ret.Write(CRLF)
		ret.WriteString(c.Args[index])
		ret.Write(CRLF)
	}
	return ret.Bytes()
}

func NewCommand(args ...string) (*Command, error) {
	if len(args) == 0 {
		return nil, errors.New("err_new_cmd")
	}
	return &Command{Args:args}, nil
}

//从Reader中读取Command
func ReadCommand(r io.Reader) (*Command, error) {
	buf, err := readRespCommandLine(r)

	if nil != err && !(io.EOF == err && len(buf) > 1 ) {
		return nil, err
	}

	if T_Array != buf[0] {
		return NewCommand(strings.Fields(string(buf))...)
	}

	//Command: BulkString
	var ret *Data
	ret = new(Data)

	ret, err = readDataForSpecType(r, buf)
	if nil != err {
		return nil, err
	}

	commandArgs := make([]string, len(ret.Array))
	for index := range ret.Array {
		if ret.Array[index].T != T_BulkString {
			return nil, errors.New("Unexpected Command Type")
		}
		commandArgs[index] = string(ret.Array[index].String)
	}

	return NewCommand(commandArgs...)
}

type Data struct {
	T byte
	String []byte
	Integer int64
	Array []*Data
	IsNil bool
}

func (d Data) Format() []byte {
	var ret *bytes.Buffer
	ret = new(bytes.Buffer)

	ret.WriteByte(d.T)
	if d.IsNil {
		ret.WriteString("-1")
		ret.Write(CRLF)
		return ret.Bytes()
	}

	switch d.T {
		case T_SimpleString, T_Error:
			ret.Write(d.String)
			ret.Write(CRLF)
		case T_BulkString:
			ret.WriteString(strconv.Itoa(len(d.String)))
			ret.Write(CRLF)
			ret.Write(d.String)
			ret.Write(CRLF)
		case T_Integer:
			ret.WriteString(strconv.FormatInt(d.Integer, 10))
			ret.Write(CRLF)
		case T_Array:
			ret.WriteString(strconv.Itoa(len(d.Array)))
			ret.Write(CRLF)
			for index := range d.Array {
				ret.Write(d.Array[index].Format())
			}
	}
	return ret.Bytes()
}

func ReadData(r io.Reader) (*Data, error) {
	buf, err := readRespLine(r)
	if nil != err {
		return nil, err
	}

	if len(buf) < 2 {
		return nil, errors.New("invalid Data Source: " + string(buf))
	}

	return readDataForSpecType(r, buf)
}

func readDataForSpecType(r io.Reader, line []byte) (*Data, error) {

	var err error
	var ret *Data

	ret = new(Data)
	switch line[0] {
		case T_SimpleString:
			ret.T = T_SimpleString
			ret.String = line[1:]

		case T_Error:
			ret.T = T_Error
			ret.String = line[1:]

		case T_Integer:
			ret.T = T_Integer
			ret.Integer, err = strconv.ParseInt(string(line[1:]), 10, 64)

		case T_BulkString:
			var lenBulkString int64
			lenBulkString, err = strconv.ParseInt(string(line[1:]), 10, 64)

			ret.T = T_BulkString
			if -1 != lenBulkString {
				ret.String, err = readRespN(r, lenBulkString)
				_, err = readRespN(r, 2)
			} else {
				ret.IsNil = true
			}

		case T_Array:
			var lenArray int64
			var i int64
			lenArray, err = strconv.ParseInt(string(line[1:]), 10, 64)

			ret.T = T_Array
			if nil==err {
				if -1 != lenArray {
					ret.Array = make([]*Data, lenArray)
					for i=0; i<lenArray && nil == err; i++ {
						ret.Array[i], err = ReadData(r)
					}
				} else {
					ret.IsNil = true
				}
			}

		default: //Maybe you are Inline Command
			err = errors.New("Unexpected type ")

	}
	return ret, err
}

//读取当前行，并去掉最后的\r\n
func readRespLine(r io.Reader) ([]byte, error) {

	var i int
	var err error
	var buf []byte
	var ret *bytes.Buffer

	buf = make([]byte, 1)
	ret = &bytes.Buffer{}

	for {
		_, err = io.ReadFull(r, buf)
		if nil != err {
			return nil, err
		}

		i++
		ret.WriteByte(buf[0])
		if '\n' == buf[0] {
			break
		}
	}

	return ret.Next(i-2), nil
}

//读取老的redis协议 InlineCommand
func readRespCommandLine(r io.Reader) ([]byte, error) {

	var err error
	var buf []byte
	var ret *bytes.Buffer

	buf = make([]byte, 1)
	ret = &bytes.Buffer{}

	for {
		_, err = io.ReadFull(r, buf)
		if nil != err {
			if io.EOF == err {
				break
			}
			return nil, err
		}

		ret.WriteByte(buf[0])
		if '\n' == buf[0] {
			break
		}
	}

	return bytes.TrimSpace(ret.Bytes()), err
}

//读取N个字节，并去掉最后的\r\n
func readRespN(r io.Reader, n int64) ([]byte, error) {
	var err error
	var ret []byte

	ret = make([]byte, n)
	_, err = io.ReadFull(r, ret)
	if nil!=err {
		ret = nil
	}
	return ret, err
}

//读取当前行的数字，并去掉最后的\r\n
func readRespIntLine(r io.Reader) (int64, error) {
	line, err := readRespLine(r)
	if nil!=err {
		return 0, err
	}
	return strconv.ParseInt(string(line), 10, 64)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"bitbucket.org/tebeka/nrsc"
	"github.com/gorilla/mux"
)

type httpResponse struct {
	Raw interface{}
}

func (r httpResponse) String() (s string) {
	b, err := json.Marshal(r.Raw)
	if err != nil {
		b, err = json.Marshal(map[string]string{
			"error": fmt.Sprint("", err),
		})
	}
	s = string(b)
	return
}

func newRouter() *mux.Router {
	r := mux.NewRouter()
	r.StrictSlash(true)
	r.HandleFunc("/", listDatabases).Methods("GET")
	r.HandleFunc("/{db}", listSources).Methods("GET")
	r.HandleFunc("/{db}/{source}", listMetrics).Methods("GET")
	r.HandleFunc("/{db}/{source}", addSamples).Methods("POST")
	r.HandleFunc("/{db}/{source}/{metric}", getRawValues).Methods("GET")
	r.HandleFunc("/{db}/{source}/{metric}/summary", getSummary).Methods("GET")
	r.HandleFunc("/{db}/{source}/{metric}/linechart", getLineChart).Methods("GET")
	r.HandleFunc("/{db}/{source}/{metric}/heatmap", getHeatMap).Methods("GET")

	return r
}

func internalError(rw http.ResponseWriter) {
	rw.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintf(rw, "Internal Server Error")
}

func validJSON(rw http.ResponseWriter, data interface{}) {
	rw.Header().Set("Content-Type", "application/json")
	fmt.Fprint(rw, httpResponse{data})
}

func validHTML(rw http.ResponseWriter, content string) {
	rw.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(rw, content)
}

func listDatabases(rw http.ResponseWriter, r *http.Request) {
	databases, err := storage.listDatabases()
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, databases)
}

func stringInSlice(a string, array []string) bool {
	for _, b := range array {
		if b == a {
			return true
		}
	}
	return false
}

func checkDbExists(rw http.ResponseWriter, dbname string) error {
	if allDbs, err := storage.listDatabases(); !stringInSlice(dbname, allDbs) || err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(rw, "not existing snapshot")
		return errors.New("not existing snapshot")
	}
	return nil
}

func listSources(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}
	sources, err := storage.listCollections(dbname)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, sources)
}

func listMetrics(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	metrics, err := storage.listMetrics(dbname, source)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, metrics)
}

func getRawValues(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]
	metric := vars["metric"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	values, err := storage.findValues(dbname, source, metric)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, values)
}

func getSummary(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]
	metric := vars["metric"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	values, err := storage.aggregate(dbname, source, metric)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, values)
}

func readHTML(path string) (string, error) {
	var html nrsc.Resource
	if html = nrsc.Get(path); html == nil {
		return "", errors.New("cannot read HTML")
	}
	var htmlReader io.Reader
	var err error
	if htmlReader, err = html.Open(); err != nil {
		return "", err
	}
	var content []byte
	if content, err = ioutil.ReadAll(htmlReader); err != nil {
		return "", err
	}
	return string(content), nil
}

func getLineChart(rw http.ResponseWriter, r *http.Request) {
	content, err := readHTML("linechart.html")
	if err != nil {
		internalError(rw)
		return
	}
	validHTML(rw, content)
}

func addSamples(rw http.ResponseWriter, r *http.Request) {
	var tsNano int64
	if timestamps, ok := r.URL.Query()["ts"]; ok {
		tsNano = parseTimestamp(timestamps[0])
	} else {
		tsNano = time.Now().UnixNano()
	}
	ts := strconv.FormatInt(tsNano, 10)

	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]

	var samples map[string]interface{}
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&samples)
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(rw, "Cannot decode sample: %s\n", err)
		return
	}

	for m, v := range samples {
		sample := map[string]interface{}{
			"ts": ts,
			"m":  m,
			"v":  v,
		}
		go storage.insertSample(dbname, source, sample)
	}
}

func getHeatMap(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]
	metric := vars["metric"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	values, err := storage.getHeatMap(dbname, source, metric)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, values)
}
<commit_msg>Log errors in html reader<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"bitbucket.org/tebeka/nrsc"
	"github.com/gorilla/mux"
)

type httpResponse struct {
	Raw interface{}
}

func (r httpResponse) String() (s string) {
	b, err := json.Marshal(r.Raw)
	if err != nil {
		b, err = json.Marshal(map[string]string{
			"error": fmt.Sprint("", err),
		})
	}
	s = string(b)
	return
}

func newRouter() *mux.Router {
	r := mux.NewRouter()
	r.StrictSlash(true)
	r.HandleFunc("/", listDatabases).Methods("GET")
	r.HandleFunc("/{db}", listSources).Methods("GET")
	r.HandleFunc("/{db}/{source}", listMetrics).Methods("GET")
	r.HandleFunc("/{db}/{source}", addSamples).Methods("POST")
	r.HandleFunc("/{db}/{source}/{metric}", getRawValues).Methods("GET")
	r.HandleFunc("/{db}/{source}/{metric}/summary", getSummary).Methods("GET")
	r.HandleFunc("/{db}/{source}/{metric}/linechart", getLineChart).Methods("GET")
	r.HandleFunc("/{db}/{source}/{metric}/heatmap", getHeatMap).Methods("GET")

	return r
}

func internalError(rw http.ResponseWriter) {
	rw.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintf(rw, "Internal Server Error")
}

func validJSON(rw http.ResponseWriter, data interface{}) {
	rw.Header().Set("Content-Type", "application/json")
	fmt.Fprint(rw, httpResponse{data})
}

func validHTML(rw http.ResponseWriter, content string) {
	rw.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(rw, content)
}

func listDatabases(rw http.ResponseWriter, r *http.Request) {
	databases, err := storage.listDatabases()
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, databases)
}

func stringInSlice(a string, array []string) bool {
	for _, b := range array {
		if b == a {
			return true
		}
	}
	return false
}

func checkDbExists(rw http.ResponseWriter, dbname string) error {
	if allDbs, err := storage.listDatabases(); !stringInSlice(dbname, allDbs) || err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(rw, "not existing snapshot")
		return errors.New("not existing snapshot")
	}
	return nil
}

func listSources(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}
	sources, err := storage.listCollections(dbname)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, sources)
}

func listMetrics(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	metrics, err := storage.listMetrics(dbname, source)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, metrics)
}

func getRawValues(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]
	metric := vars["metric"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	values, err := storage.findValues(dbname, source, metric)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, values)
}

func getSummary(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]
	metric := vars["metric"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	values, err := storage.aggregate(dbname, source, metric)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, values)
}

func readHTML(path string) (string, error) {
	var html nrsc.Resource
	if html = nrsc.Get(path); html == nil {
		err := errors.New("cannot read HTML")
		logger.Critical(err)
		return "", err
	}
	var htmlReader io.Reader
	var err error
	if htmlReader, err = html.Open(); err != nil {
		logger.Critical(err)
		return "", err
	}
	var content []byte
	if content, err = ioutil.ReadAll(htmlReader); err != nil {
		logger.Critical(err)
		return "", err
	}
	return string(content), nil
}

func getLineChart(rw http.ResponseWriter, r *http.Request) {
	content, err := readHTML("linechart.html")
	if err != nil {
		internalError(rw)
		return
	}
	validHTML(rw, content)
}

func addSamples(rw http.ResponseWriter, r *http.Request) {
	var tsNano int64
	if timestamps, ok := r.URL.Query()["ts"]; ok {
		tsNano = parseTimestamp(timestamps[0])
	} else {
		tsNano = time.Now().UnixNano()
	}
	ts := strconv.FormatInt(tsNano, 10)

	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]

	var samples map[string]interface{}
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&samples)
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(rw, "Cannot decode sample: %s\n", err)
		return
	}

	for m, v := range samples {
		sample := map[string]interface{}{
			"ts": ts,
			"m":  m,
			"v":  v,
		}
		go storage.insertSample(dbname, source, sample)
	}
}

func getHeatMap(rw http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	dbname := vars["db"]
	source := vars["source"]
	metric := vars["metric"]

	if err := checkDbExists(rw, dbname); err != nil {
		return
	}

	values, err := storage.getHeatMap(dbname, source, metric)
	if err != nil {
		internalError(rw)
		return
	}
	validJSON(rw, values)
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "os"
import "log"
import "flag"
import "io"
import md5 "crypto/md5"
import hex "encoding/hex"
import "path"

func main() {
	filename := flag.String("directory", "", "Directory to scan")
	flag.Parse()

	f,err := os.Open(*filename)
	if err != nil {
		log.Fatalf("Unable to open %s", *filename);
	}

	for {
		files,err := f.Readdir(100)
		if err == io.EOF {
			log.Print("EOF on readdir")
			break;
		}
		if err != nil {
			log.Fatal("Readdir failed")
		}
		for _,stat := range files {
			log.Printf("Name: %s\nSize: %d\n", stat.Name(), stat.Size())
			path := path.Join(*filename, stat.Name())
			f,err := os.Open(path)
			if err != nil {
				log.Printf("Couldn't open %s. Skipping it.", path)
				continue
			}
			for {
				b := make([]byte, 1<<20)
				n,err := f.Read(b)
				if n == 0 {
					log.Printf("EOF on %s", f.Name())
					break
				} else if err != nil {
					log.Fatal("Non EOF error on ", f.Name())
				}
				csum := md5.Sum(b[:n])
				fmt.Printf("%s: %s", f.Name(), hex.EncodeToString(csum[:]))
			}
		}
	}
}
<commit_msg>Recurse through directories<commit_after>package main

import "fmt"
import "os"
import "log"
import "flag"
import "io"
import md5 "crypto/md5"
import hex "encoding/hex"
import "path"

func walkDirectory(root string) <-chan string {
	out := make(chan string)
	var queue []string
	queue = append(queue, root)

	go func() {
		for len(queue) > 0 {
			d := queue[0]
			queue = queue[:1]

			f,err := os.Open(d)
			if err != nil {
				log.Print("Unable to open: %s\n", d)
				continue
			}

			for {
				infos,err := f.Readdir(100)
				if err == io.EOF {
					log.Print("EOF on readdir")
					break;
				}
				if err != nil {
					log.Fatal("Readdir failed")
				}

				for _,stat := range infos {
					full_path := path.Join(d, stat.Name())
					if stat.IsDir() {
						queue = append(queue, full_path)
					} else {
						out <- full_path
					}
				}
			}

		}
		close(out)
	}()

	return out
}

func hashFiles(files <-chan string) {
	for path := range files {
		f,err := os.Open(path)
		if err != nil {
			log.Printf("Couldn't open %s. Skipping it.", path)
		}
		for {
			b := make([]byte, 1<<20)
			n,err := f.Read(b)
			if n == 0 {
				log.Printf("EOF on %s", f.Name())
				break
			} else if err != nil {
				log.Fatal("Non EOF error on ", f.Name())
			}
			csum := md5.Sum(b[:n])
			fmt.Printf("%s: %s\n", f.Name(), hex.EncodeToString(csum[:]))
		}
	}
}

func main() {
	root := flag.String("directory", "", "Directory to scan")
	flag.Parse()

	files := walkDirectory(*root)
	hashFiles(files)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/VonC/godbg"
)

func main() {
	godbg.Pdbgf("senvgo")
	// http://stackoverflow.com/questions/18963984/exit-with-error-code-in-go
	os.Exit(run())
}

func run() int {
	// here goes
	// the code
	fmt.Println("No program to install: nothing to do")
	return 0
}
<commit_msg>Uses ExitFunc to call (default) os.Exit(x)<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/VonC/godbg"
)

// By default, os.Exit()
type ExitFunc func(int)

var exit ExitFunc

func init() {
	exit = os.Exit
}

func main() {
	godbg.Pdbgf("senvgo")
	// http://stackoverflow.com/questions/18963984/exit-with-error-code-in-go
	exit(run())
}

func run() int {
	// here goes
	// the code
	fmt.Println("No program to install: nothing to do")
	return 0
}
<|endoftext|>


<commit_before>package flowbase

type Sink struct {
	Process
	inPorts []chan *interface{}
}

// Instantiate a Sink component
func NewSink() (s *Sink) {
	return &Sink{
		inPorts: make([]chan *interface{}, BUFSIZE),
	}
}

func (proc *Sink) Connect(ch chan *interface{}) {
	proc.inPorts = append(proc.inPorts, ch)
}

// Execute the Sink component
func (proc *Sink) Run() {
	ok := true
	for len(proc.inPorts) > 0 {
		for i, ich := range proc.inPorts {
			select {
			case _, ok = <-ich:
				if !ok {
					proc.deleteInPortAtKey(i)
					continue
				}
			default:
			}
		}
	}
}

func (proc *Sink) deleteInPortAtKey(i int) {
	proc.inPorts = append(proc.inPorts[:i], proc.inPorts[i+1:]...)
}
<commit_msg>Add SinkString component<commit_after>package flowbase

type Sink struct {
	Process
	inPorts []chan *interface{}
}

// Instantiate a Sink component
func NewSink() (s *Sink) {
	return &Sink{
		inPorts: make([]chan *interface{}, BUFSIZE),
	}
}

func (proc *Sink) Connect(ch chan *interface{}) {
	proc.inPorts = append(proc.inPorts, ch)
}

// Execute the Sink component
func (proc *Sink) Run() {
	ok := true
	for len(proc.inPorts) > 0 {
		for i, ich := range proc.inPorts {
			select {
			case _, ok = <-ich:
				if !ok {
					proc.deleteInPortAtKey(i)
					continue
				}
			default:
			}
		}
	}
}

func (proc *Sink) deleteInPortAtKey(i int) {
	proc.inPorts = append(proc.inPorts[:i], proc.inPorts[i+1:]...)
}

type SinkString struct {
	Process
	inPorts []chan string
}

// Instantiate a SinkString component
func NewSinkString() (s *SinkString) {
	return &SinkString{}
}

func (proc *SinkString) Connect(ch chan string) {
	proc.inPorts = append(proc.inPorts, ch)
}

// Execute the SinkString component
func (proc *SinkString) Run() {
	for len(proc.inPorts) > 0 {
		for i, ich := range proc.inPorts {
			select {
			case str, ok := <-ich:
				Debug.Printf("Received string in sink: %s\n", str)
				if !ok {
					Debug.Println("Port was not ok!")
					proc.deleteInPortAtKey(i)
					continue
				}
			default:
			}
		}
		Debug.Printf("Finished looping\n")
	}
}

func (proc *SinkString) deleteInPortAtKey(i int) {
	proc.inPorts = append(proc.inPorts[:i], proc.inPorts[i+1:]...)
}
<|endoftext|>


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

// Package slug transforms strings into a normalized
// form well suited for use in URLs.
package slug

import (
	"code.google.com/p/go.text/unicode/norm"
	"encoding/hex"
	"unicode"
	"unicode/utf8"
)

var lat = []*unicode.RangeTable{unicode.Letter, unicode.Number}
var nop = []*unicode.RangeTable{unicode.Mark, unicode.Sk, unicode.Lm}

// Slug replaces each run of characters which are not unicode letters or
// numbers with a single hyphen, except for leading or trailing runs. Letters
// will be stripped of diacritical marks and lowercased.
func Slug(s string) string {
	buf := make([]rune, 0, len(s))
	dash := false
	for _, r := range norm.NFKD.String(s) {
		switch {
		// unicode 'letters' like mandarin characters pass through
		case unicode.IsOneOf(lat, r):
			buf = append(buf, unicode.ToLower(r))
			dash = true
		case unicode.IsOneOf(nop, r):
			// skip
		case dash:
			buf = append(buf, '-')
			dash = false
		}
	}
	if i := len(buf) - 1; i >= 0 && buf[i] == '-' {
		buf = buf[:i]
	}
	return string(buf)
}

// SlugAscii replaces each run of characters which are not unicode letters or
// numbers with a single hyphen, except for leading or trailing runs. Letters
// will be stripped of diacritical marks and lowercased.
func SlugAscii(s string) string {
	const m = utf8.UTFMax
	var (
		ib    [m * 3]byte
		ob    []byte
		buf   = make([]byte, 0, len(s))
		dash  = false
		latin = true
	)
	for _, r := range norm.NFKD.String(s) {
		switch {
		case unicode.IsOneOf(lat, r):
			r = unicode.ToLower(r)
			n := utf8.EncodeRune(ib[:m], r)
			if r >= 128 {
				if latin && dash {
					buf = append(buf, '-')
				}
				n = hex.Encode(ib[m:], ib[:n])
				ob = ib[m : m+n]
				latin = false
			} else {
				if !latin {
					buf = append(buf, '-')
				}
				ob = ib[:n]
				latin = true
			}
			dash = true
			buf = append(buf, ob...)
		case unicode.IsOneOf(nop, r):
			// skip
		case dash:
			buf = append(buf, '-')
			dash = false
			latin = true
		}
	}
	if i := len(buf) - 1; i >= 0 && buf[i] == '-' {
		buf = buf[:i]
	}
	return string(buf)
}

func IsSlugAscii(s string) bool {
	dash := true
	for _, r := range s {
		switch {
		case r == '-':
			if dash {
				return false
			}
			dash = true
		case 'a' <= r && r <= 'z', '0' <= r && r <= '9':
			dash = false
		default:
			return false
		}
	}
	return !dash
}
<commit_msg>Expanded documentation.<commit_after>// Copyright 2012 Kevin Gillette. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package slug transforms strings into a normalized form well suited for use in URLs.
package slug

import (
	"code.google.com/p/go.text/unicode/norm"
	"encoding/hex"
	"unicode"
	"unicode/utf8"
)

var lat = []*unicode.RangeTable{unicode.Letter, unicode.Number}
var nop = []*unicode.RangeTable{unicode.Mark, unicode.Sk, unicode.Lm}

// Slug replaces each run of characters which are not unicode letters or
// numbers with a single hyphen, except for leading or trailing runs. Letters
// will be stripped of diacritical marks and lowercased. Letter or number
// codepoints that do not have combining marks or a lower-cased variant will
// be passed through unaltered.
func Slug(s string) string {
	buf := make([]rune, 0, len(s))
	dash := false
	for _, r := range norm.NFKD.String(s) {
		switch {
		// unicode 'letters' like mandarin characters pass through
		case unicode.IsOneOf(lat, r):
			buf = append(buf, unicode.ToLower(r))
			dash = true
		case unicode.IsOneOf(nop, r):
			// skip
		case dash:
			buf = append(buf, '-')
			dash = false
		}
	}
	if i := len(buf) - 1; i >= 0 && buf[i] == '-' {
		buf = buf[:i]
	}
	return string(buf)
}

// SlugAscii is identical to Slug, except that if a transformed unicode letter
// or number still falls outside the ASCII range, it will be hex encoded and
// delimited by hyphens. As with Slug, in no case will hyphens appear at either
// end of the returned string.
func SlugAscii(s string) string {
	const m = utf8.UTFMax
	var (
		ib    [m * 3]byte
		ob    []byte
		buf   = make([]byte, 0, len(s))
		dash  = false
		latin = true
	)
	for _, r := range norm.NFKD.String(s) {
		switch {
		case unicode.IsOneOf(lat, r):
			r = unicode.ToLower(r)
			n := utf8.EncodeRune(ib[:m], r)
			if r >= 128 {
				if latin && dash {
					buf = append(buf, '-')
				}
				n = hex.Encode(ib[m:], ib[:n])
				ob = ib[m : m+n]
				latin = false
			} else {
				if !latin {
					buf = append(buf, '-')
				}
				ob = ib[:n]
				latin = true
			}
			dash = true
			buf = append(buf, ob...)
		case unicode.IsOneOf(nop, r):
			// skip
		case dash:
			buf = append(buf, '-')
			dash = false
			latin = true
		}
	}
	if i := len(buf) - 1; i >= 0 && buf[i] == '-' {
		buf = buf[:i]
	}
	return string(buf)
}

// IsSlugAscii returns true only if SlugAscii(s) == s.
func IsSlugAscii(s string) bool {
	dash := true
	for _, r := range s {
		switch {
		case r == '-':
			if dash {
				return false
			}
			dash = true
		case 'a' <= r && r <= 'z', '0' <= r && r <= '9':
			dash = false
		default:
			return false
		}
	}
	return !dash
}
<|endoftext|>


<commit_before>package lily

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"strconv"
)

type sendReplySt struct {
	ID        uint64 `json:"id"`
	CNT       int    `json:"cnt"`
	ErrorCode int    `json:"error_code"`
	Error     string `json:"error"`
}

type getBalanceReplySt struct {
	Balance   string `json:"balance"`
	ErrorCode int    `json:"error_code"`
	Error     string `json:"error"`
}

var (
	SmscDebug = false
)

func SmscSend(username, password string, phones string, msg string) bool {
	if SmscDebug {
		log.Printf("Sent sms: %s - %q\n", phones, msg)
		return true
	}
	client := &http.Client{
		Timeout: 20 * time.Second,
	}
	req, err := http.NewRequest("GET", "https://smsc.kz/sys/send.php", nil)
	ErrPanic(err)
	params := req.URL.Query()
	params.Add("login", username)
	params.Add("psw", password)
	params.Add("phones", phones)
	params.Add("mes", msg)
	params.Add("charset", "utf-8")
	params.Add("fmt", "3")
	req.URL.RawQuery = params.Encode()
	resp, err := client.Do(req)
	if err != nil {
		log.Println("(sms-send) fail to send sms:", err)
		return false
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("(sms-send) fail to read sms-send reply body:", err)
		return false
	}
	if resp.StatusCode != 200 {
		log.Printf("(sms-send) bad status code %d in sms-send reply, data: %s\n", resp.StatusCode, string(data))
		return false
	}
	reply := sendReplySt{}
	err = json.Unmarshal(data, &reply)
	if err != nil {
		log.Printf("(sms-send) fail to parse sms-send reply: %s, %s\n", err.Error(), string(data))
		return false
	}
	if (reply.ErrorCode != 0) || (reply.Error != "") {
		if reply.ErrorCode != 7 && reply.ErrorCode != 8 { // 7 - invalid number, 8 - can't to deliver
			log.Printf("(sms-send) sms provider error for (%s, %q):\n%s\n", phones, msg, string(data))
		}
		return false
	}
	return true
}

func SmscSendBcast(username, password string, phones string, msg string) (bool, uint64) {
	if SmscDebug {
		log.Printf("Sent sms-bcast: %s - %q\n", phones, msg)
		return true, 777
	}
	client := &http.Client{
		Timeout: 20 * time.Second,
	}
	req, err := http.NewRequest("GET", "https://smsc.kz/sys/jobs.php", nil)
	ErrPanic(err)
	params := req.URL.Query()
	params.Add("add", "1")
	params.Add("login", username)
	params.Add("psw", password)
	params.Add("name", "bcast")
	params.Add("phones", phones)
	params.Add("mes", msg)
	params.Add("charset", "utf-8")
	params.Add("fmt", "3")
	req.URL.RawQuery = params.Encode()
	resp, err := client.Do(req)
	if err != nil {
		log.Println("(sms-bcast) fail to send sms:", err)
		return false, 0
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("(sms-bcast) fail to read sms-send reply body:", err)
		return false, 0
	}
	if resp.StatusCode != 200 {
		log.Printf("(sms-bcast) bad status code %d in sms-send reply, data: %s\n", resp.StatusCode, string(data))
		return false, 0
	}
	reply := sendReplySt{}
	err = json.Unmarshal(data, &reply)
	if err != nil {
		log.Printf("(sms-bcast) fail to parse sms-send reply: %s, %s\n", err.Error(), string(data))
		return false, 0
	}
	if (reply.ErrorCode != 0) || (reply.Error != "") {
		log.Printf("(sms-bcast) sms provider error for (%s, %q):\n%s\n", phones, msg, string(data))
		return false, 0
	}
	return true, reply.ID
}

func SmscGetBalance(username, password string) (bool, float64) {
	var result float64

	client := &http.Client{
		Timeout: 20 * time.Second,
	}

	req, err := http.NewRequest("GET", "https://smsc.kz/sys/balance.php", nil)
	if err != nil {
		return false, 0
	}

	params := req.URL.Query()
	params.Add("login", username)
	params.Add("psw", password)
	params.Add("fmt", "3")

	req.URL.RawQuery = params.Encode()

	resp, err := client.Do(req)
	if err != nil {
		log.Println("fail to get sms-balance:", err)
		return false, 0
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		log.Printf("bad status code %d in sms-balance reply\n", resp.StatusCode)
		return false, 0
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("fail to read sms-balance reply body:", err)
		return false, 0
	}

	reply := getBalanceReplySt{}
	err = json.Unmarshal(data, &reply)
	if err != nil {
		log.Println("fail to parse sms-balance reply:", err)
		return false, 0
	}

	if (reply.ErrorCode != 0) || (reply.Error != "") {
		log.Printf("sms provider error for getting balance:\n%s\n", string(data))
		return false, 0
	}

	result, _ = strconv.ParseFloat(reply.Balance, 64)

	return true, result
}
<commit_msg>some fixes<commit_after>package lily

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"strconv"
)

type SmscErrorSt struct {
	Code string
	Desc string
}

func (o *SmscErrorSt) Error() string {
	return o.Code + ", " + o.Desc
}

type smscSendReplySt struct {
	ID        uint64 `json:"id"`
	CNT       int    `json:"cnt"`
	ErrorCode int    `json:"error_code"`
	Error     string `json:"error"`
}

type smscGetBalanceReplySt struct {
	Balance   string `json:"balance"`
	ErrorCode int    `json:"error_code"`
	Error     string `json:"error"`
}

const (
	urlPrefix = `https://smsc.kz/sys/`
)

var (
	SmscDebug = false
)

func SmscSend(username, password string, phones string, msg string) bool {
	if SmscDebug {
		log.Printf("Sent sms: %s - %q\n", phones, msg)
		return true
	}
	client := &http.Client{
		Timeout: 20 * time.Second,
	}
	req, err := http.NewRequest("GET", urlPrefix+"send.php", nil)
	ErrPanic(err)
	params := req.URL.Query()
	params.Add("login", username)
	params.Add("psw", password)
	params.Add("phones", phones)
	params.Add("mes", msg)
	params.Add("charset", "utf-8")
	params.Add("fmt", "3")
	req.URL.RawQuery = params.Encode()
	resp, err := client.Do(req)
	if err != nil {
		log.Println("(sms-send) fail to send sms:", err)
		return false
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("(sms-send) fail to read sms-send reply body:", err)
		return false
	}
	if resp.StatusCode != 200 {
		log.Printf("(sms-send) bad status code %d in sms-send reply, data: %s\n", resp.StatusCode, string(data))
		return false
	}
	reply := smscSendReplySt{}
	err = json.Unmarshal(data, &reply)
	if err != nil {
		log.Printf("(sms-send) fail to parse sms-send reply: %s, %s\n", err.Error(), string(data))
		return false
	}
	if (reply.ErrorCode != 0) || (reply.Error != "") {
		if reply.ErrorCode != 7 && reply.ErrorCode != 8 { // 7 - invalid number, 8 - can't to deliver
			log.Printf("(sms-send) sms provider error for (%s, %q):\n%s\n", phones, msg, string(data))
		}
		return false
	}
	return true
}

func SmscSendBcast(username, password string, phones string, msg string) (bool, uint64) {
	if SmscDebug {
		log.Printf("Sent sms-bcast: %s - %q\n", phones, msg)
		return true, 777
	}
	client := &http.Client{
		Timeout: 20 * time.Second,
	}
	req, err := http.NewRequest("GET", urlPrefix+"jobs.php", nil)
	ErrPanic(err)
	params := req.URL.Query()
	params.Add("add", "1")
	params.Add("login", username)
	params.Add("psw", password)
	params.Add("name", "bcast")
	params.Add("phones", phones)
	params.Add("mes", msg)
	params.Add("charset", "utf-8")
	params.Add("fmt", "3")
	req.URL.RawQuery = params.Encode()
	resp, err := client.Do(req)
	if err != nil {
		log.Println("(sms-bcast) fail to send sms:", err)
		return false, 0
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("(sms-bcast) fail to read sms-send reply body:", err)
		return false, 0
	}
	if resp.StatusCode != 200 {
		log.Printf("(sms-bcast) bad status code %d in sms-send reply, data: %s\n", resp.StatusCode, string(data))
		return false, 0
	}
	reply := smscSendReplySt{}
	err = json.Unmarshal(data, &reply)
	if err != nil {
		log.Printf("(sms-bcast) fail to parse sms-send reply: %s, %s\n", err.Error(), string(data))
		return false, 0
	}
	if (reply.ErrorCode != 0) || (reply.Error != "") {
		log.Printf("(sms-bcast) sms provider error for (%s, %q):\n%s\n", phones, msg, string(data))
		return false, 0
	}
	return true, reply.ID
}

func SmscGetBalance(username, password string) (*SmscErrorSt, float64) {
	var result float64

	client := &http.Client{
		Timeout: 20 * time.Second,
	}

	req, err := http.NewRequest("GET", urlPrefix+"balance.php", nil)
	if err != nil {
		return &SmscErrorSt{Code: "request_fail", Desc: "Fail to create new request - " + err.Error()}, 0
	}

	params := req.URL.Query()
	params.Add("login", username)
	params.Add("psw", password)
	params.Add("fmt", "3")

	req.URL.RawQuery = params.Encode()

	resp, err := client.Do(req)
	if err != nil {
		return &SmscErrorSt{Code: "request_fail", Desc: "Fail to request smsc - " + err.Error()}, 0
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return &SmscErrorSt{Code: "bad_status_code", Desc: "Bad status code - " + strconv.Itoa(resp.StatusCode)}, 0
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return &SmscErrorSt{Code: "fail_to_read_body", Desc: "Fail to read body - " + err.Error()}, 0
	}

	reply := smscGetBalanceReplySt{}
	err = json.Unmarshal(data, &reply)
	if err != nil {
		return &SmscErrorSt{Code: "fail_to_parse_body", Desc: "Fail to parse body - " + err.Error()}, 0
	}

	if (reply.ErrorCode != 0) || (reply.Error != "") {
		return &SmscErrorSt{Code: "provider_error", Desc: "Provider error - " + string(data)}, 0
	}

	result, _ = strconv.ParseFloat(reply.Balance, 64)

	return nil, result
}
<|endoftext|>


<commit_before>// Package sqlz implements an SQL query builder based on
// github.com/jmoiron/sqlx.
package sqlz

import (
	"database/sql"
	"strings"

	"github.com/jmoiron/sqlx"
)

// DB is a wrapper around sqlx.DB (which is a wrapper around sql.DB)
type DB struct {
	*sqlx.DB
}

// Tx is a wrapper around sqlx.Tx (which is a wrapper around sql.Tx)
type Tx struct {
	*sqlx.Tx
}

// New creates a new DB instance from an underlying sql.DB object.
// It requires the name of the SQL driver in order to use the correct
// placeholders when generating SQL
func New(db *sql.DB, driverName string) *DB {
	return &DB{DB: sqlx.NewDb(db, driverName)}
}

// Newx creates a new DB instance from an underlying sqlx.DB object
func Newx(db *sqlx.DB) *DB {
	return &DB{DB: db}
}

// Transactional runs the provided function inside a transaction. The
// function must receive an sqlz Tx object, and return an error. If the
// function returns an error, the transaction is automatically rolled
// back. Otherwise, the transaction is committed.
func (db *DB) Transactional(f func(tx *Tx) error) error {
	tx, err := db.Beginx()
	if err != nil {
		return err
	}

	err = f(&Tx{tx})
	if err != nil {
		return tx.Rollback()
	}

	err = tx.Commit()
	if err != nil {
		return tx.Rollback()
	}

	return nil
}

// WhereCondition is an interface describing conditions
// that can be used inside an SQL WHERE clause. It defines
// the Parse function that generates SQL (with placeholders)
// from the condition(s) and returns a list of data bindings
// for the placeholders (if any)
type WhereCondition interface {
	Parse() (asSQL string, bindings []interface{})
}

// SimpleCondition represents the most basic WHERE
// condition, where one left-value (usually a column)
// is compared with a right-value using an operator (e.g.
// "=", "<>", ">=", ...)
type SimpleCondition struct {
	Left     string
	Right    interface{}
	Operator string
}

// AndOrCondition represents a group of AND or OR
// conditions.
type AndOrCondition struct {
	Or         bool
	Conditions []WhereCondition
}

// SubqueryCondition is a WHERE condition on the results
// of a sub-query.
type SubqueryCondition struct {
	Stmt     *SelectStmt
	Operator string
}

// IndirectValue represents a reference to a database name
// (e.g. column, function) that should be used as-is in a
// query rather than replaced with a placeholder.
type IndirectValue struct {
	Reference string
}

// Indirect receives a string and injects it into a query
// as-is rather than with a placeholder. Use this when
// comparing columns, modifying columns based on their (or
// others') existing values, using database functions, etc.
// Never use this with user-supplied input, as this may
// open the door for SQL injections!
func Indirect(value string) IndirectValue {
	return IndirectValue{value}
}

// And joins multiple where conditions as an AndOrCondition
// (representing AND conditions). You will use this a lot
// less than Or as passing multiple conditions to functions
// like Where or Having are all AND conditions.
func And(conds ...WhereCondition) AndOrCondition {
	return AndOrCondition{false, conds}
}

// Or joins multiple where conditions as an AndOrCondition
// (representing OR conditions).
func Or(conds ...WhereCondition) AndOrCondition {
	return AndOrCondition{true, conds}
}

// Eq represents a simple equality condition ("=" operator)
func Eq(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "="}
}

// Ne represents a simple non-equality condition ("<>" operator)
func Ne(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "<>"}
}

// Gt represents a simple greater-than condition (">" operator)
func Gt(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, ">"}
}

// Gte represents a simple greater-than-or-equals condition (">=" operator)
func Gte(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, ">="}
}

// Lt represents a simple less-than condition ("<" operator)
func Lt(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "<"}
}

// Lte represents a simple less-than-or-equals condition ("<=" operator)
func Lte(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "<="}
}

// Like represents a wildcard equality condition ("LIKE" operator)
func Like(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "LIKE"}
}

// NotLike represents a wildcard non-equality condition ("NOT LIKE" operator)
func NotLike(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "NOT LIKE"}
}

// IsNull represents a simple nullity condition ("IS NULL" operator)
func IsNull(col string) SimpleCondition {
	return SimpleCondition{col, nil, "IS NULL"}
}

// IsNotNull represents a simple non-nullity condition ("IS NOT NULL" operator)
func IsNotNull(col string) SimpleCondition {
	return SimpleCondition{col, nil, "IS NOT NULL"}
}

// Exists creates a sub-query condition checking the sub-query
// returns results ("EXISTS" operator)
func Exists(stmt *SelectStmt) SubqueryCondition {
	return SubqueryCondition{stmt, "EXISTS"}
}

// NotExists creates a sub-query condition checking the sub-query
// does not return results ("NOT EXISTS" operator)
func NotExists(stmt *SelectStmt) SubqueryCondition {
	return SubqueryCondition{stmt, "NOT EXISTS"}
}

// JSONBOp creates simple conditions with JSONB operators for
// PostgreSQL databases (supported operators are "@>", "<@",
// "?", "?!", "?&", "||", "-" and "#-")
func JSONBOp(op string, left string, value interface{}) SimpleCondition {
	switch op {
	case "@>", "<@", "?", "?!", "?&", "||", "-", "#-":
		return SimpleCondition{left, value, op}
	default:
		return SimpleCondition{}
	}
}

// Parse implements the WhereCondition interface, generating SQL from
// the condition
func (simple SimpleCondition) Parse() (asSQL string, bindings []interface{}) {
	asSQL = simple.Left + " " + simple.Operator

	if simple.Right != nil {
		placeholder := "?"
		if indirect, isIndirect := simple.Right.(IndirectValue); isIndirect {
			placeholder = indirect.Reference
		} else {
			bindings = append(bindings, simple.Right)
		}
		asSQL += " " + placeholder
	}

	return asSQL, bindings
}

// Parse implements the WhereCondition interface, generating SQL from
// the condition
func (andOr AndOrCondition) Parse() (asSQL string, bindings []interface{}) {
	var sqls []string
	for _, cond := range andOr.Conditions {
		innerSQL, innerBindings := cond.Parse()
		sqls = append(sqls, innerSQL)
		bindings = append(bindings, innerBindings...)
	}
	op := " AND "
	if andOr.Or {
		op = " OR "
	}
	return "(" + strings.Join(sqls, op) + ")", bindings
}

// Parse implements the WhereCondition interface, generating SQL from
// the condition
func (subCond SubqueryCondition) Parse() (asSQL string, bindings []interface{}) {
	asSQL, bindings = subCond.Stmt.ToSQL(false)
	return subCond.Operator + " (" + asSQL + ")", bindings
}

func parseConditions(conds []WhereCondition) (asSQL string, bindings []interface{}) {
	if len(conds) > 1 {
		asSQL, bindings = (AndOrCondition{false, conds}).Parse()
	} else if len(conds) == 1 {
		asSQL, bindings = conds[0].Parse()
	}

	if strings.HasPrefix(asSQL, "(") {
		asSQL = strings.TrimPrefix(strings.TrimSuffix(asSQL, ")"), "(")
	}

	return asSQL, bindings
}
<commit_msg>Return original error message when Transactional fails<commit_after>// Package sqlz implements an SQL query builder based on
// github.com/jmoiron/sqlx.
package sqlz

import (
	"database/sql"
	"fmt"
	"strings"

	"github.com/jmoiron/sqlx"
)

// DB is a wrapper around sqlx.DB (which is a wrapper around sql.DB)
type DB struct {
	*sqlx.DB
}

// Tx is a wrapper around sqlx.Tx (which is a wrapper around sql.Tx)
type Tx struct {
	*sqlx.Tx
}

// New creates a new DB instance from an underlying sql.DB object.
// It requires the name of the SQL driver in order to use the correct
// placeholders when generating SQL
func New(db *sql.DB, driverName string) *DB {
	return &DB{DB: sqlx.NewDb(db, driverName)}
}

// Newx creates a new DB instance from an underlying sqlx.DB object
func Newx(db *sqlx.DB) *DB {
	return &DB{DB: db}
}

// Transactional runs the provided function inside a transaction. The
// function must receive an sqlz Tx object, and return an error. If the
// function returns an error, the transaction is automatically rolled
// back. Otherwise, the transaction is committed.
func (db *DB) Transactional(f func(tx *Tx) error) error {
	tx, err := db.Beginx()
	if err != nil {
		return fmt.Errorf("failed starting transaction: %s", err)
	}

	err = f(&Tx{tx})
	if err != nil {
		rErr := tx.Rollback()
		err = fmt.Errorf("transaction failed: %s", err)
		if rErr != nil {
			err = fmt.Errorf("%s (rollback failed: %s)", err, rErr)
		}
		return err
	}

	err = tx.Commit()
	if err != nil {
		return fmt.Errorf("failed committing transaction: %s", err)
	}

	return nil
}

// WhereCondition is an interface describing conditions
// that can be used inside an SQL WHERE clause. It defines
// the Parse function that generates SQL (with placeholders)
// from the condition(s) and returns a list of data bindings
// for the placeholders (if any)
type WhereCondition interface {
	Parse() (asSQL string, bindings []interface{})
}

// SimpleCondition represents the most basic WHERE
// condition, where one left-value (usually a column)
// is compared with a right-value using an operator (e.g.
// "=", "<>", ">=", ...)
type SimpleCondition struct {
	Left     string
	Right    interface{}
	Operator string
}

// AndOrCondition represents a group of AND or OR
// conditions.
type AndOrCondition struct {
	Or         bool
	Conditions []WhereCondition
}

// SubqueryCondition is a WHERE condition on the results
// of a sub-query.
type SubqueryCondition struct {
	Stmt     *SelectStmt
	Operator string
}

// IndirectValue represents a reference to a database name
// (e.g. column, function) that should be used as-is in a
// query rather than replaced with a placeholder.
type IndirectValue struct {
	Reference string
}

// Indirect receives a string and injects it into a query
// as-is rather than with a placeholder. Use this when
// comparing columns, modifying columns based on their (or
// others') existing values, using database functions, etc.
// Never use this with user-supplied input, as this may
// open the door for SQL injections!
func Indirect(value string) IndirectValue {
	return IndirectValue{value}
}

// And joins multiple where conditions as an AndOrCondition
// (representing AND conditions). You will use this a lot
// less than Or as passing multiple conditions to functions
// like Where or Having are all AND conditions.
func And(conds ...WhereCondition) AndOrCondition {
	return AndOrCondition{false, conds}
}

// Or joins multiple where conditions as an AndOrCondition
// (representing OR conditions).
func Or(conds ...WhereCondition) AndOrCondition {
	return AndOrCondition{true, conds}
}

// Eq represents a simple equality condition ("=" operator)
func Eq(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "="}
}

// Ne represents a simple non-equality condition ("<>" operator)
func Ne(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "<>"}
}

// Gt represents a simple greater-than condition (">" operator)
func Gt(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, ">"}
}

// Gte represents a simple greater-than-or-equals condition (">=" operator)
func Gte(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, ">="}
}

// Lt represents a simple less-than condition ("<" operator)
func Lt(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "<"}
}

// Lte represents a simple less-than-or-equals condition ("<=" operator)
func Lte(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "<="}
}

// Like represents a wildcard equality condition ("LIKE" operator)
func Like(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "LIKE"}
}

// NotLike represents a wildcard non-equality condition ("NOT LIKE" operator)
func NotLike(col string, value interface{}) SimpleCondition {
	return SimpleCondition{col, value, "NOT LIKE"}
}

// IsNull represents a simple nullity condition ("IS NULL" operator)
func IsNull(col string) SimpleCondition {
	return SimpleCondition{col, nil, "IS NULL"}
}

// IsNotNull represents a simple non-nullity condition ("IS NOT NULL" operator)
func IsNotNull(col string) SimpleCondition {
	return SimpleCondition{col, nil, "IS NOT NULL"}
}

// Exists creates a sub-query condition checking the sub-query
// returns results ("EXISTS" operator)
func Exists(stmt *SelectStmt) SubqueryCondition {
	return SubqueryCondition{stmt, "EXISTS"}
}

// NotExists creates a sub-query condition checking the sub-query
// does not return results ("NOT EXISTS" operator)
func NotExists(stmt *SelectStmt) SubqueryCondition {
	return SubqueryCondition{stmt, "NOT EXISTS"}
}

// JSONBOp creates simple conditions with JSONB operators for
// PostgreSQL databases (supported operators are "@>", "<@",
// "?", "?!", "?&", "||", "-" and "#-")
func JSONBOp(op string, left string, value interface{}) SimpleCondition {
	switch op {
	case "@>", "<@", "?", "?!", "?&", "||", "-", "#-":
		return SimpleCondition{left, value, op}
	default:
		return SimpleCondition{}
	}
}

// Parse implements the WhereCondition interface, generating SQL from
// the condition
func (simple SimpleCondition) Parse() (asSQL string, bindings []interface{}) {
	asSQL = simple.Left + " " + simple.Operator

	if simple.Right != nil {
		placeholder := "?"
		if indirect, isIndirect := simple.Right.(IndirectValue); isIndirect {
			placeholder = indirect.Reference
		} else {
			bindings = append(bindings, simple.Right)
		}
		asSQL += " " + placeholder
	}

	return asSQL, bindings
}

// Parse implements the WhereCondition interface, generating SQL from
// the condition
func (andOr AndOrCondition) Parse() (asSQL string, bindings []interface{}) {
	var sqls []string
	for _, cond := range andOr.Conditions {
		innerSQL, innerBindings := cond.Parse()
		sqls = append(sqls, innerSQL)
		bindings = append(bindings, innerBindings...)
	}
	op := " AND "
	if andOr.Or {
		op = " OR "
	}
	return "(" + strings.Join(sqls, op) + ")", bindings
}

// Parse implements the WhereCondition interface, generating SQL from
// the condition
func (subCond SubqueryCondition) Parse() (asSQL string, bindings []interface{}) {
	asSQL, bindings = subCond.Stmt.ToSQL(false)
	return subCond.Operator + " (" + asSQL + ")", bindings
}

func parseConditions(conds []WhereCondition) (asSQL string, bindings []interface{}) {
	if len(conds) > 1 {
		asSQL, bindings = (AndOrCondition{false, conds}).Parse()
	} else if len(conds) == 1 {
		asSQL, bindings = conds[0].Parse()
	}

	if strings.HasPrefix(asSQL, "(") {
		asSQL = strings.TrimPrefix(strings.TrimSuffix(asSQL, ")"), "(")
	}

	return asSQL, bindings
}
<|endoftext|>


<commit_before>package main

import (
	"./mysql";
	"fmt";
)

func main() {
	dbh, err := mysql.Connect("127.0.0.1:3306", "test", "test", "test");
	if err != nil {
		fmt.Printf("%s\n", err);
	}
	fmt.Printf("Connected to %s\n", dbh.ServerVersion);
	//var res * mysql.MySQLResponse;
	_, err = dbh.Query("SHOW PROCESSLIST");
	if err != nil {
		fmt.Printf("%s\n", err);
	}
}
<commit_msg>Simple query test. Dosen't return any data.<commit_after>package main

import (
	"./mysql";
	"fmt";
	"os";
)

func main() {
	dbh, err := mysql.Connect("127.0.0.1:3306", "test", "test", "test");
	if err != nil {
		fmt.Printf("%s\n", err);
		os.Exit(1);
	}
	fmt.Printf("Connected to %s\n", dbh.ServerVersion);
	var res * mysql.MySQLResponse;
	res, err = dbh.Query("SHOW PROCESSLIST");
	if err != nil {
		fmt.Printf("%s\n", err);
		os.Exit(1);
	}
	fmt.Printf("%#v\n", res);
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ymotongpoo/goltsv"
)

type Todo struct {
	Number int
	Title  string
	Done   bool
}

func (todo Todo) Encode() map[string]string {
	m := make(map[string]string)
	m["title"] = todo.Title
	if todo.Done {
		m["done"] = "true"
	} else {
		m["done"] = "false"
	}
	return m
}

func ReadTodos() ([]Todo, error) {
	if !fileIsExist() {
		err := createNewFile()
		if err != nil {
			return nil, err
		}
	}

	path := getTodosPath()
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	buf := bytes.NewBuffer(data)
	reader := goltsv.NewReader(buf)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	todos := []Todo{}
	for i, record := range records {
		var title string
		var done bool

		for k, v := range record {
			switch k {
			case "title":
				title = v
			case "done":
				done = (v == "true")
			}
		}

		todo := Todo{Number: i + 1, Title: title, Done: done}
		todos = append(todos, todo)
	}

	return todos, nil
}

func WriteTodos(todos []Todo) error {
	var data []map[string]string
	for _, todo := range todos {
		data = append(data, todo.Encode())
	}

	if !fileIsExist() {
		err := createNewFile()
		if err != nil {
			return err
		}
	}

	path := getTodosPath()
	file, err := os.OpenFile(path, os.O_RDWR, 0644)
	if err != nil {
		return err
	}

	writer := goltsv.NewWriter(file)

	err = writer.WriteAll(data)
	if err != nil {
		return err
	}

	return nil
}

func AppendTodo(todo Todo) error {
	todos, err := ReadTodos()
	if err != nil {
		return err
	}

	todos = append(todos, todo)
	return WriteTodos(todos)
}

func DeleteTodo(num int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		index := num - 1
		if index >= len(todos) {
			return nil, errors.New("Index out of bounds.")
		}

		return append(todos[:index], todos[index+1:]...), nil
	})
}

func MoveTodo(from, to int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		fromIndex, toIndex := from-1, to-1
		if fromIndex >= len(todos) || toIndex >= len(todos) {
			return nil, errors.New("Index out of bounds.")
		}

		movedTodo := todos[fromIndex]
		todos = append(todos[:fromIndex], todos[fromIndex+1:]...)
		todos = append(todos[:toIndex], append([]Todo{movedTodo}, todos[toIndex:]...)...)
		return todos, nil
	})
}

func RenameTodo(num int, title string) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		index := num - 1
		if index >= len(todos) {
			return nil, errors.New("Index out of bounds.")
		}

		todos[index].Title = title
		return todos, nil
	})
}

func DoneTodo(nums ...int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		var err error
		indices := make([]int, len(nums))
		for _, num := range nums {
			index := num - 1
			if index >= len(todos) {
				err = errors.New("Index out of bounds.")
			}
			indices = append(indices, index)
		}
		if err != nil {
			return nil, err
		}

		newTodos := make([]Todo, len(todos))
		for i, todo := range todos {
			if contains(indices, i) {
				todo.Done = true
			}
			newTodos[i] = todo
		}
		return newTodos, nil
	})
}

func UndoneTodo(nums ...int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		var err error
		indices := make([]int, len(nums))
		for _, num := range nums {
			index := num - 1
			if index >= len(todos) {
				err = errors.New("Index out of bounds.")
			}
			indices = append(indices, index)
		}
		if err != nil {
			return nil, err
		}

		newTodos := make([]Todo, len(todos))
		for i, todo := range todos {
			if contains(indices, i) {
				todo.Done = false
			}
			newTodos[i] = todo
		}
		return newTodos, nil
	})
}

func ClearTodos() error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		var newTodos []Todo
		for _, todo := range todos {
			if !todo.Done {
				newTodos = append(newTodos, todo)
			}
		}
		return newTodos, nil
	})
}

func getTodosPath() string {
	path := os.Getenv("TODO_PATH")
	if path == "" {
		path = os.Getenv("HOME")
	}

	return filepath.Join(path, ".todo")
}

func fileIsExist() bool {
	path := getTodosPath()
	_, err := os.Stat(path)
	return err == nil
}

func createNewFile() error {
	path := getTodosPath()
	_, err := os.Create(path)
	return err
}

func rewriteFile(f func([]Todo) ([]Todo, error)) error {
	todos, err := ReadTodos()
	if err != nil {
		return err
	}

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

	newTodos, err := f(todos)
	if err != nil {
		// Recover removed todos
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		return WriteTodos(todos)
	}

	return WriteTodos(newTodos)
}

func removeFile() error {
	path := getTodosPath()
	err := os.Remove(path)
	return err
}

func contains(xs []int, n int) bool {
	for _, x := range xs {
		if x == n {
			return true
		}
	}
	return false
}
<commit_msg>Fix a bug causing to done/undone a TODO unexpectedly<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ymotongpoo/goltsv"
)

type Todo struct {
	Number int
	Title  string
	Done   bool
}

func (todo Todo) Encode() map[string]string {
	m := make(map[string]string)
	m["title"] = todo.Title
	if todo.Done {
		m["done"] = "true"
	} else {
		m["done"] = "false"
	}
	return m
}

func ReadTodos() ([]Todo, error) {
	if !fileIsExist() {
		err := createNewFile()
		if err != nil {
			return nil, err
		}
	}

	path := getTodosPath()
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	buf := bytes.NewBuffer(data)
	reader := goltsv.NewReader(buf)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	todos := []Todo{}
	for i, record := range records {
		var title string
		var done bool

		for k, v := range record {
			switch k {
			case "title":
				title = v
			case "done":
				done = (v == "true")
			}
		}

		todo := Todo{Number: i + 1, Title: title, Done: done}
		todos = append(todos, todo)
	}

	return todos, nil
}

func WriteTodos(todos []Todo) error {
	var data []map[string]string
	for _, todo := range todos {
		data = append(data, todo.Encode())
	}

	if !fileIsExist() {
		err := createNewFile()
		if err != nil {
			return err
		}
	}

	path := getTodosPath()
	file, err := os.OpenFile(path, os.O_RDWR, 0644)
	if err != nil {
		return err
	}

	writer := goltsv.NewWriter(file)

	err = writer.WriteAll(data)
	if err != nil {
		return err
	}

	return nil
}

func AppendTodo(todo Todo) error {
	todos, err := ReadTodos()
	if err != nil {
		return err
	}

	todos = append(todos, todo)
	return WriteTodos(todos)
}

func DeleteTodo(num int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		index := num - 1
		if index >= len(todos) {
			return nil, errors.New("Index out of bounds.")
		}

		return append(todos[:index], todos[index+1:]...), nil
	})
}

func MoveTodo(from, to int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		fromIndex, toIndex := from-1, to-1
		if fromIndex >= len(todos) || toIndex >= len(todos) {
			return nil, errors.New("Index out of bounds.")
		}

		movedTodo := todos[fromIndex]
		todos = append(todos[:fromIndex], todos[fromIndex+1:]...)
		todos = append(todos[:toIndex], append([]Todo{movedTodo}, todos[toIndex:]...)...)
		return todos, nil
	})
}

func RenameTodo(num int, title string) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		index := num - 1
		if index >= len(todos) {
			return nil, errors.New("Index out of bounds.")
		}

		todos[index].Title = title
		return todos, nil
	})
}

func DoneTodo(nums ...int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		var err error
		var indices []int
		for _, num := range nums {
			index := num - 1
			if index >= len(todos) {
				err = errors.New("Index out of bounds.")
			}
			indices = append(indices, index)
		}
		if err != nil {
			return nil, err
		}

		newTodos := make([]Todo, len(todos))
		for i, todo := range todos {
			if contains(indices, i) {
				todo.Done = true
			}
			newTodos[i] = todo
		}
		return newTodos, nil
	})
}

func UndoneTodo(nums ...int) error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		var err error
		var indices []int
		for _, num := range nums {
			index := num - 1
			if index >= len(todos) {
				err = errors.New("Index out of bounds.")
			}
			indices = append(indices, index)
		}
		if err != nil {
			return nil, err
		}

		newTodos := make([]Todo, len(todos))
		for i, todo := range todos {
			if contains(indices, i) {
				todo.Done = false
			}
			newTodos[i] = todo
		}
		return newTodos, nil
	})
}

func ClearTodos() error {
	return rewriteFile(func(todos []Todo) ([]Todo, error) {
		var newTodos []Todo
		for _, todo := range todos {
			if !todo.Done {
				newTodos = append(newTodos, todo)
			}
		}
		return newTodos, nil
	})
}

func getTodosPath() string {
	path := os.Getenv("TODO_PATH")
	if path == "" {
		path = os.Getenv("HOME")
	}

	return filepath.Join(path, ".todo")
}

func fileIsExist() bool {
	path := getTodosPath()
	_, err := os.Stat(path)
	return err == nil
}

func createNewFile() error {
	path := getTodosPath()
	_, err := os.Create(path)
	return err
}

func rewriteFile(f func([]Todo) ([]Todo, error)) error {
	todos, err := ReadTodos()
	if err != nil {
		return err
	}

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

	newTodos, err := f(todos)
	if err != nil {
		// Recover removed todos
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		return WriteTodos(todos)
	}

	return WriteTodos(newTodos)
}

func removeFile() error {
	path := getTodosPath()
	err := os.Remove(path)
	return err
}

func contains(xs []int, n int) bool {
	for _, x := range xs {
		if x == n {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/jeffbmartinez/cleanexit"
	"github.com/jeffbmartinez/delay"
	"github.com/jeffbmartinez/stdoutlog"

	"github.com/jeffbmartinez/todo/handler"
)

const projectName string = "todo"
const defaultListenPort = 8000

func main() {
	cleanexit.SetUpSimpleExitOnCtrlC()

	allowAnyHostToConnect, listenPort := getCommandLineArgs()

	n := negroni.New()
	n.Use(delay.Middleware{})
	n.Use(stdoutlog.Middleware{})

	router := getRouter()
	n.UseHandler(router)

	listenHost := "localhost"
	if allowAnyHostToConnect {
		listenHost = ""
	}
	displayServerInfo(listenHost, listenPort)

	listenAddress := fmt.Sprintf("%v:%v", listenHost, listenPort)
	n.Run(listenAddress)
}

func getRouter() *mux.Router {
	router := mux.NewRouter()

	api := router.PathPrefix("/api/").Subrouter()

	api.HandleFunc("/tasks", handler.Tasks)
	api.HandleFunc("/tasks/new", handler.NewTask)
	api.HandleFunc("/tasks/{id}", handler.Task)

	return router
}

func getCommandLineArgs() (allowAnyHostToConnect bool, port int) {
	flag.BoolVar(&allowAnyHostToConnect, "a", false, "Use to allow any ip address (any host) to connect. Default allows ony localhost.")
	flag.IntVar(&port, "port", defaultListenPort, "Port on which to listen for connections.")

	flag.Parse()

	/* Don't accept any positional command line arguments. flag.NArgs()
	counts only non-flag arguments. */
	if flag.NArg() != 0 {
		flag.Usage()
		os.Exit(2)
	}

	return
}

func displayServerInfo(listenHost string, listenPort int) {
	visibleTo := listenHost
	if visibleTo == "" {
		visibleTo = "All ip addresses"
	}

	fmt.Printf("%v is running.\n\n", projectName)
	fmt.Printf("Port: %v\n\n", listenPort)
	fmt.Printf("Hit [ctrl-c] to quit\n")
}
<commit_msg>remove "api/" prefix from endpoints<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/jeffbmartinez/cleanexit"
	"github.com/jeffbmartinez/delay"
	"github.com/jeffbmartinez/stdoutlog"

	"github.com/jeffbmartinez/todo/handler"
)

const projectName string = "todo"
const defaultListenPort = 8000

func main() {
	cleanexit.SetUpSimpleExitOnCtrlC()

	allowAnyHostToConnect, listenPort := getCommandLineArgs()

	n := negroni.New()
	n.Use(delay.Middleware{})
	n.Use(stdoutlog.Middleware{})

	router := getRouter()
	n.UseHandler(router)

	listenHost := "localhost"
	if allowAnyHostToConnect {
		listenHost = ""
	}
	displayServerInfo(listenHost, listenPort)

	listenAddress := fmt.Sprintf("%v:%v", listenHost, listenPort)
	n.Run(listenAddress)
}

func getRouter() *mux.Router {
	router := mux.NewRouter()

	router.HandleFunc("/tasks", handler.Tasks)
	router.HandleFunc("/tasks/new", handler.NewTask)
	router.HandleFunc("/tasks/{id}", handler.Task)

	return router
}

func getCommandLineArgs() (allowAnyHostToConnect bool, port int) {
	flag.BoolVar(&allowAnyHostToConnect, "a", false, "Use to allow any ip address (any host) to connect. Default allows ony localhost.")
	flag.IntVar(&port, "port", defaultListenPort, "Port on which to listen for connections.")

	flag.Parse()

	/* Don't accept any positional command line arguments. flag.NArgs()
	counts only non-flag arguments. */
	if flag.NArg() != 0 {
		flag.Usage()
		os.Exit(2)
	}

	return
}

func displayServerInfo(listenHost string, listenPort int) {
	visibleTo := listenHost
	if visibleTo == "" {
		visibleTo = "All ip addresses"
	}

	fmt.Printf("%v is running.\n\n", projectName)
	fmt.Printf("Port: %v\n\n", listenPort)
	fmt.Printf("Hit [ctrl-c] to quit\n")
}
<|endoftext|>