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

package reddit

// vote represents the three possible states of a vote on reddit.
type vote string

const (
	UpVote     vote = "1"
	DownVote        = "-1"
	RemoveVote      = "0"
)

// popularitySort represents the possible ways to sort submissions by popularity.
type popularitySort string

const (
	DefaultPopularity        popularitySort = ""
	HotSubmissions                          = "hot"
	NewSubmissions                          = "new"
	RisingSubmissions                       = "rising"
	TopSubmissions                          = "top"
	ControversialSubmissions                = "controversial"
)

// ageSort represents the possible ways to sort submissions by age.
type ageSort string

const (
	DefaultAge ageSort = ""
	ThisHour           = "hour"
	ThisMonth          = "month"
	ThisYear           = "year"
	AllTime            = "all"
)

// Voter represents something that can be voted on reddit.com.
type Voter interface {
	voteID() string
}

// Deleter represents something that can be deleted on reddit.com.
type Deleter interface {
	deleteID() string
}

// Replier represents something that can be replied to on reddit.com.
type Replier interface {
	replyID() string
}
<commit_msg>add struct for new submission<commit_after>// Copyright 2012 Jimmy Zelinskie. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package reddit

// vote represents the three possible states of a vote on reddit.
type vote string

const (
	UpVote     vote = "1"
	DownVote        = "-1"
	RemoveVote      = "0"
)

// newSubmission contains the data needed to submit
type newSubmission struct {
	Title       string
	Content     string
	Self        bool
	SendReplies bool
	Resubmit    bool
}

// popularitySort represents the possible ways to sort submissions by popularity.
type popularitySort string

const (
	DefaultPopularity        popularitySort = ""
	HotSubmissions                          = "hot"
	NewSubmissions                          = "new"
	RisingSubmissions                       = "rising"
	TopSubmissions                          = "top"
	ControversialSubmissions                = "controversial"
)

// ageSort represents the possible ways to sort submissions by age.
type ageSort string

const (
	DefaultAge ageSort = ""
	ThisHour           = "hour"
	ThisMonth          = "month"
	ThisYear           = "year"
	AllTime            = "all"
)

type Submitter interface {
	submitID() string
}

// Voter represents something that can be voted on reddit.com.
type Voter interface {
	voteID() string
}

// Deleter represents something that can be deleted on reddit.com.
type Deleter interface {
	deleteID() string
}

// Replier represents something that can be replied to on reddit.com.
type Replier interface {
	replyID() string
}
<|endoftext|>


<commit_before>package main

import (
	"tgbotapi"
)

type CAHGame struct {
	Bot           tgbotapi.BotAPI
	ShuffledCards []int
	Players       map[string]PlayerGameInfo
}

type PlayerGameInfo struct {
	Player     tgbotapi.User
	Points     int
	Cards      []int
	IsCardTzar bool
}
<commit_msg>Preliminary type setup<commit_after>package main

import (
	"tgbotapi"
)

type CAHGame struct {
	ShuffledCards []int
	Players       map[string]PlayerGameInfo
	Settings      GameSettings
}

type PlayerGameInfo struct {
	Player          tgbotapi.User
	Points          int
	Cards           []int
	IsCardTzar      bool
	IsMysteryPlayer bool
}

type GameSettings struct {
	MysteryPlayer             bool
	TradeInTwoCardsEveryRound bool
	PickWorstToo              bool
	NumCardsInHand            int
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	// "log"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/cors"
	"github.com/martini-contrib/render"
	"os"
	"strings"
)

var session *mgo.Session
var collection *mgo.Collection
var err error

type Torrent struct {
	Btih     string `bson:"_id,omitempty"`
	Title    []string
	Category []string
	Details  []string
	Download []string
}

func main() {
	// Try to connect to the database
	session, err = mgo.Dial("10.0.1.12")
	if err != nil {
		fmt.Println("Couldn't connect to Mongo. Please make sure it is installed and running.")
		return
	}
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	collection = session.DB("bitcannon").C("torrents")
	collection.EnsureIndex(mgo.Index{Key: []string{"$text:title"}, Name: "title"})

	if len(os.Args) > 1 {
		importFile(os.Args[1])
	} else {
		runServer()
	}
}

func runServer() {
	fmt.Println("Starting the API server.")
	m := martini.Classic()
	m.Use(render.Renderer())
	m.Use(cors.Allow(&cors.Options{
		AllowAllOrigins: true,
		AllowMethods:    []string{"POST", "GET"},
		ExposeHeaders:   []string{"Content-Length"},
	}))
	m.Get("/stats", func(r render.Render) {
		count, err := collection.Count()
		if err != nil {
			r.JSON(500, map[string]interface{}{"count": "API Error"})
			return
		}
		r.JSON(200, map[string]interface{}{"count": count})
	})
	m.Get("/browse", func(r render.Render) {
		var result []string
		err := collection.Find(nil).Distinct("category", &result)
		if err != nil {
			r.JSON(500, map[string]interface{}{"error": "API Error"})
			return
		}
		r.JSON(200, result)
	})
	m.Get("/torrent/:btih", func(r render.Render, params martini.Params) {
		result := Torrent{}
		err = collection.Find(bson.M{"btih": params["btih"]}).One(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": "Torrent not found."})
			return
		}
		r.JSON(200, result)
	})
	m.Get("/search/:query", func(r render.Render, params martini.Params) {
		result := []Torrent{}
		pipe := collection.Pipe([]bson.M{
			{"$match": bson.M{"$text": bson.M{"$search": params["query"]}}},
			{"$sort": bson.M{"score": bson.M{"$meta": "textScore"}}},
		})
		iter := pipe.Iter()
		err = iter.All(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": err.Error()})
			return
		}
		r.JSON(200, result)
	})
	m.RunOnAddr(":1337")
}

func importFile(filename string) {
	fmt.Print("Attempting to parse ")
	fmt.Println(filename)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error opening the file. Make sure it exists and is readable.")
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	imported := 0
	skipped := 0
	for scanner.Scan() {
		status, _ := importLine(scanner.Text())
		if status {
			imported++
		} else {
			skipped++
		}
	}

	fmt.Println("File parsing ended.")
	fmt.Print("New: ")
	fmt.Println(imported)
	fmt.Print("Dup: ")
	fmt.Println(skipped)

	if err := scanner.Err(); err != nil {
		fmt.Println("The program encountered an error while reading the file. Ensure that the file isn't corrupted.")
		return
	}
}

func importLine(line string) (bool, error) {
	if strings.Count(line, "|") != 4 {
		return false, errors.New("Something's up with this torrent. Expected 5 values separated by |.")
	}
	data := strings.Split(line, "|")
	return importHash(data[0], data[1], data[2], data[3], data[4])
}

// hash, title, category, details, download /*hash string, title string, category string, details string*/
func importHash(btih string, title string, category string, details string, download string) (bool, error) {
	err := collection.Insert(&Torrent{Btih: btih, Title: []string{title}, Category: []string{category}, Details: []string{details}, Download: []string{download}})
	if err != nil {
		return false, errors.New("Something went wrong when trying to insert.")
	}
	return true, nil
}
<commit_msg>Include counts for each category for the category list endpoint.<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	// "log"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/cors"
	"github.com/martini-contrib/render"
	"os"
	"strings"
)

var session *mgo.Session
var collection *mgo.Collection
var err error

type Torrent struct {
	Btih     string `bson:"_id,omitempty"`
	Title    []string
	Category []string
	Details  []string
	Download []string
}

func main() {
	// Try to connect to the database
	session, err = mgo.Dial("10.0.1.12")
	if err != nil {
		fmt.Println("Couldn't connect to Mongo. Please make sure it is installed and running.")
		return
	}
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	collection = session.DB("bitcannon").C("torrents")
	collection.EnsureIndex(mgo.Index{Key: []string{"$text:title"}, Name: "title"})

	if len(os.Args) > 1 {
		importFile(os.Args[1])
	} else {
		runServer()
	}
}

func runServer() {
	fmt.Println("Starting the API server.")
	m := martini.Classic()
	m.Use(render.Renderer())
	m.Use(cors.Allow(&cors.Options{
		AllowAllOrigins: true,
		AllowMethods:    []string{"POST", "GET"},
		ExposeHeaders:   []string{"Content-Length"},
	}))
	m.Get("/stats", func(r render.Render) {
		count, err := collection.Count()
		if err != nil {
			r.JSON(500, map[string]interface{}{"count": "API Error"})
			return
		}
		r.JSON(200, map[string]interface{}{"count": count})
	})
	m.Get("/browse", func(r render.Render) {
		var result []string
		err := collection.Find(nil).Distinct("category", &result)
		if err != nil {
			r.JSON(500, map[string]interface{}{"error": "API Error"})
			return
		}
		var size int
		for size = range result {
		}
		stats := make([]map[string]interface{}, size+1, size+1)
		for i, cat := range result {
			total, err := collection.Find(bson.M{"category": cat}).Count()
			if err != nil {
				stats[i] = map[string]interface{}{cat: 0}
			} else {
				stats[i] = map[string]interface{}{"name": cat, "count": total}
			}
		}
		r.JSON(200, stats)
	})
	m.Get("/torrent/:btih", func(r render.Render, params martini.Params) {
		result := Torrent{}
		err = collection.Find(bson.M{"btih": params["btih"]}).One(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": "Torrent not found."})
			return
		}
		r.JSON(200, result)
	})
	m.Get("/search/:query", func(r render.Render, params martini.Params) {
		result := []Torrent{}
		pipe := collection.Pipe([]bson.M{
			{"$match": bson.M{"$text": bson.M{"$search": params["query"]}}},
			{"$sort": bson.M{"score": bson.M{"$meta": "textScore"}}},
		})
		iter := pipe.Iter()
		err = iter.All(&result)
		if err != nil {
			r.JSON(404, map[string]interface{}{"message": err.Error()})
			return
		}
		r.JSON(200, result)
	})
	m.RunOnAddr(":1337")
}

func importFile(filename string) {
	fmt.Print("Attempting to parse ")
	fmt.Println(filename)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error opening the file. Make sure it exists and is readable.")
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	imported := 0
	skipped := 0
	for scanner.Scan() {
		status, _ := importLine(scanner.Text())
		if status {
			imported++
		} else {
			skipped++
		}
	}

	fmt.Println("File parsing ended.")
	fmt.Print("New: ")
	fmt.Println(imported)
	fmt.Print("Dup: ")
	fmt.Println(skipped)

	if err := scanner.Err(); err != nil {
		fmt.Println("The program encountered an error while reading the file. Ensure that the file isn't corrupted.")
		return
	}
}

func importLine(line string) (bool, error) {
	if strings.Count(line, "|") != 4 {
		return false, errors.New("Something's up with this torrent. Expected 5 values separated by |.")
	}
	data := strings.Split(line, "|")
	return importHash(data[0], data[1], data[2], data[3], data[4])
}

// hash, title, category, details, download /*hash string, title string, category string, details string*/
func importHash(btih string, title string, category string, details string, download string) (bool, error) {
	err := collection.Insert(&Torrent{Btih: btih, Title: []string{title}, Category: []string{category}, Details: []string{details}, Download: []string{download}})
	if err != nil {
		return false, errors.New("Something went wrong when trying to insert.")
	}
	return true, nil
}
<|endoftext|>


<commit_before>package test

import (
	"testing"

	"github.com/miekg/dns"
)

// TODO(miek): this test needs to be fleshed out.

func TestFileUpstream(t *testing.T) {
	name, rm, err := TempFile(".", `$ORIGIN example.org.
@	3600 IN	SOA sns.dns.icann.org. noc.dns.icann.org. (
		2017042745 ; serial
		7200       ; refresh (2 hours)
		3600       ; retry (1 hour)
		1209600    ; expire (2 weeks)
		3600       ; minimum (1 hour)
	)

        3600 IN NS a.iana-servers.net.
	3600 IN NS b.iana-servers.net.

www 3600 IN CNAME   www.example.net.
`)
	if err != nil {
		t.Fatalf("Failed to create zone: %s", err)
	}
	defer rm()

	// Corefile with for example without proxy section.
	corefile := `example.org:0 {
       file ` + name + ` {
	       upstream
	}
	hosts {
		10.0.0.1 www.example.net.
		fallthrough
	}
}
`
	i, udp, _, err := CoreDNSServerAndPorts(corefile)
	if err != nil {
		t.Fatalf("Could not get CoreDNS serving instance: %s", err)
	}
	defer i.Stop()

	m := new(dns.Msg)
	m.SetQuestion("www.example.org.", dns.TypeA)
	m.SetEdns0(4096, true)

	r, err := dns.Exchange(m, udp)
	if err != nil {
		t.Fatalf("Could not exchange msg: %s", err)
	}
	if r.Rcode == dns.RcodeServerFailure {
		t.Fatalf("Rcode should not be dns.RcodeServerFailure")
	}
	t.Logf("%s", r)
}
<commit_msg>Add upstream unit test (#1830)<commit_after>package test

import (
	"testing"

	"github.com/miekg/dns"
)

// TODO(miek): this test needs to be fleshed out.

func TestFileUpstream(t *testing.T) {
	name, rm, err := TempFile(".", `$ORIGIN example.org.
@	3600 IN	SOA sns.dns.icann.org. noc.dns.icann.org. (
		2017042745 ; serial
		7200       ; refresh (2 hours)
		3600       ; retry (1 hour)
		1209600    ; expire (2 weeks)
		3600       ; minimum (1 hour)
	)

        3600 IN NS a.iana-servers.net.
	3600 IN NS b.iana-servers.net.

www 3600 IN CNAME   www.example.net.
`)
	if err != nil {
		t.Fatalf("Failed to create zone: %s", err)
	}
	defer rm()

	corefile := `.:0 {
	file ` + name + ` example.org {
	       upstream
	}
	hosts {
               10.0.0.1 www.example.net.
               fallthrough
       }
}
`
	i, udp, _, err := CoreDNSServerAndPorts(corefile)
	if err != nil {
		t.Fatalf("Could not get CoreDNS serving instance: %s", err)
	}
	defer i.Stop()

	m := new(dns.Msg)
	m.SetQuestion("www.example.org.", dns.TypeA)
	m.SetEdns0(4096, true)

	r, err := dns.Exchange(m, udp)
	if err != nil {
		t.Fatalf("Could not exchange msg: %s", err)
	}
	if r.Rcode == dns.RcodeServerFailure {
		t.Fatalf("Rcode should not be dns.RcodeServerFailure")
	}
	if x := r.Answer[1].(*dns.A).A.String(); x != "10.0.0.1" {
		t.Errorf("Failed to get address for CNAME, expected 10.0.0.1 got %s", x)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"strconv"
	"time"
)

type TorrentDB struct {
	session    *mgo.Session
	collection *mgo.Collection
}

type Torrent struct {
	Btih     string `bson:"_id,omitempty"`
	Title    string
	Category string
	Size int
	Details  []string
	Download []string
	Swarm    Stats
	Lastmod  time.Time
}

type Stats struct {
	Seeders  int
	Leechers int
}

func NewTorrentDB(url string) (*TorrentDB, error) {
	session, err := mgo.Dial(url)
	if err != nil {
		return nil, err
	}
	session.SetMode(mgo.Monotonic, true)
	collection := session.DB("bitcannon").C("torrents")
	collection.EnsureIndex(mgo.Index{Key: []string{"$text:title"}, Name: "title"})
	collection.EnsureIndex(mgo.Index{Key: []string{"category"}, Name: "category"})
	return &TorrentDB{session, collection}, nil
}

func (torrentDB *TorrentDB) Close() {
	torrentDB.session.Close()
}

func (torrentDB *TorrentDB) Count(r render.Render) {
	count, err := torrentDB.collection.Count()
	if err != nil {
		r.JSON(500, map[string]interface{}{"count": "API Error"})
		return
	}
	r.JSON(200, map[string]interface{}{"count": count})
}

func (torrentDB *TorrentDB) Categories(r render.Render) {
	var result []string
	err := torrentDB.collection.Find(nil).Distinct("category", &result)
	if err != nil {
		r.JSON(500, map[string]interface{}{"error": "API Error"})
		return
	}
	var size int
	for size = range result {
	}
	stats := make([]map[string]interface{}, size+1, size+1)
	for i, cat := range result {
		total, err := torrentDB.collection.Find(bson.M{"category": cat}).Count()
		if err != nil {
			stats[i] = map[string]interface{}{cat: 0}
		} else {
			stats[i] = map[string]interface{}{"name": cat, "count": total}
		}
	}
	r.JSON(200, stats)
}

func (torrentDB *TorrentDB) Browse(r render.Render, params martini.Params) {
	result := []Torrent{}
	err = torrentDB.collection.Find(bson.M{"category": params["category"]}).Limit(resultLimit).All(&result)
	if err != nil {
		r.JSON(404, map[string]interface{}{"message": err.Error()})
		return
	}
	r.JSON(200, result)
}

func (torrentDB *TorrentDB) Search(r render.Render, params martini.Params) {
	result := []Torrent{}
	skip := 0
	if value, ok := params["page"]; ok {
		page, err := strconv.Atoi(value)
		if err != nil {
			r.JSON(400, map[string]interface{}{"message": err.Error()})
			return
		}
		skip = page * resultLimit
	}
	pipe := torrentDB.collection.Pipe([]bson.M{
		{"$match": bson.M{"$text": bson.M{"$search": params["query"]}}},
		{"$sort": bson.M{"score": bson.M{"$meta": "textScore"}}},
		{"$skip": skip},
		{"$limit": resultLimit},
	})
	iter := pipe.Iter()
	err = iter.All(&result)
	if err != nil {
		r.JSON(404, map[string]interface{}{"message": err.Error()})
		return
	}
	r.JSON(200, result)
}

func (torrentDB *TorrentDB) Get(r render.Render, params martini.Params) {
	result := Torrent{}
	err = torrentDB.collection.Find(bson.M{"_id": params["btih"]}).One(&result)
	if err != nil {
		r.JSON(404, map[string]interface{}{"message": "Torrent not found."})
		return
	}
	r.JSON(200, result)
}

func (torrentDB *TorrentDB) Insert(btih string, title string, category string, size int, details string, download string) (bool, error) {
	err := torrentDB.collection.Insert(
		&Torrent{Btih: btih,
			Title:    title,
			Category: category,
			Size: size,
			Details:  []string{details},
			Download: []string{download},
			Swarm:    Stats{Seeders: -1, Leechers: -1},
			Lastmod:  time.Now(),
		})
	if err != nil {
		return false, errors.New("Something went wrong when trying to insert.")
	}
	return true, nil
}

func (torrentDB *TorrentDB) Update(btih string, seeders int, leechers int) {
	match := bson.M{"_id": btih}
	update := bson.M{"$set": bson.M{"swarm": &Stats{Seeders: seeders, Leechers: leechers}, "lastmod": time.Now()}}
	torrentDB.collection.Update(match, update)
}
<commit_msg>Formatting?<commit_after>package main

import (
	"errors"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"strconv"
	"time"
)

type TorrentDB struct {
	session    *mgo.Session
	collection *mgo.Collection
}

type Torrent struct {
	Btih     string `bson:"_id,omitempty"`
	Title    string
	Category string
	Size     int
	Details  []string
	Download []string
	Swarm    Stats
	Lastmod  time.Time
}

type Stats struct {
	Seeders  int
	Leechers int
}

func NewTorrentDB(url string) (*TorrentDB, error) {
	session, err := mgo.Dial(url)
	if err != nil {
		return nil, err
	}
	session.SetMode(mgo.Monotonic, true)
	collection := session.DB("bitcannon").C("torrents")
	collection.EnsureIndex(mgo.Index{Key: []string{"$text:title"}, Name: "title"})
	collection.EnsureIndex(mgo.Index{Key: []string{"category"}, Name: "category"})
	return &TorrentDB{session, collection}, nil
}

func (torrentDB *TorrentDB) Close() {
	torrentDB.session.Close()
}

func (torrentDB *TorrentDB) Count(r render.Render) {
	count, err := torrentDB.collection.Count()
	if err != nil {
		r.JSON(500, map[string]interface{}{"count": "API Error"})
		return
	}
	r.JSON(200, map[string]interface{}{"count": count})
}

func (torrentDB *TorrentDB) Categories(r render.Render) {
	var result []string
	err := torrentDB.collection.Find(nil).Distinct("category", &result)
	if err != nil {
		r.JSON(500, map[string]interface{}{"error": "API Error"})
		return
	}
	var size int
	for size = range result {
	}
	stats := make([]map[string]interface{}, size+1, size+1)
	for i, cat := range result {
		total, err := torrentDB.collection.Find(bson.M{"category": cat}).Count()
		if err != nil {
			stats[i] = map[string]interface{}{cat: 0}
		} else {
			stats[i] = map[string]interface{}{"name": cat, "count": total}
		}
	}
	r.JSON(200, stats)
}

func (torrentDB *TorrentDB) Browse(r render.Render, params martini.Params) {
	result := []Torrent{}
	err = torrentDB.collection.Find(bson.M{"category": params["category"]}).Limit(resultLimit).All(&result)
	if err != nil {
		r.JSON(404, map[string]interface{}{"message": err.Error()})
		return
	}
	r.JSON(200, result)
}

func (torrentDB *TorrentDB) Search(r render.Render, params martini.Params) {
	result := []Torrent{}
	skip := 0
	if value, ok := params["page"]; ok {
		page, err := strconv.Atoi(value)
		if err != nil {
			r.JSON(400, map[string]interface{}{"message": err.Error()})
			return
		}
		skip = page * resultLimit
	}
	pipe := torrentDB.collection.Pipe([]bson.M{
		{"$match": bson.M{"$text": bson.M{"$search": params["query"]}}},
		{"$sort": bson.M{"score": bson.M{"$meta": "textScore"}}},
		{"$skip": skip},
		{"$limit": resultLimit},
	})
	iter := pipe.Iter()
	err = iter.All(&result)
	if err != nil {
		r.JSON(404, map[string]interface{}{"message": err.Error()})
		return
	}
	r.JSON(200, result)
}

func (torrentDB *TorrentDB) Get(r render.Render, params martini.Params) {
	result := Torrent{}
	err = torrentDB.collection.Find(bson.M{"_id": params["btih"]}).One(&result)
	if err != nil {
		r.JSON(404, map[string]interface{}{"message": "Torrent not found."})
		return
	}
	r.JSON(200, result)
}

func (torrentDB *TorrentDB) Insert(btih string, title string, category string, size int, details string, download string) (bool, error) {
	err := torrentDB.collection.Insert(
		&Torrent{Btih: btih,
			Title:    title,
			Category: category,
			Size:     size,
			Details:  []string{details},
			Download: []string{download},
			Swarm:    Stats{Seeders: -1, Leechers: -1},
			Lastmod:  time.Now(),
		})
	if err != nil {
		return false, errors.New("Something went wrong when trying to insert.")
	}
	return true, nil
}

func (torrentDB *TorrentDB) Update(btih string, seeders int, leechers int) {
	match := bson.M{"_id": btih}
	update := bson.M{"$set": bson.M{"swarm": &Stats{Seeders: seeders, Leechers: leechers}, "lastmod": time.Now()}}
	torrentDB.collection.Update(match, update)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strconv"
	"syscall"
)

const (
	MFLAG = 1 << iota
	NFLAG
	PFLAG
	RFLAG
	SFLAG
	VFLAG
	IFLAG
	KFLAG
)

func main() {
	allFlag := flag.Bool("a", false, "")
	identFlag := flag.Bool("i", false, "")
	platformFlag := flag.Bool("m", false, "")
	hostnameFlag := flag.Bool("n", false, "")
	osnameFlag := flag.Bool("o", false, "")
	archFlag := flag.Bool("p", false, "")
	releaseFlag := flag.Bool("r", false, "")
	sysnameFlag := flag.Bool("s", false, "")
	versionFlag := flag.Bool("v", false, "")
	kernversFlag := flag.Bool("K", false, "")
	helpFlag := flag.Bool("h", false, "")

	flag.Parse()

	var flags int = 0

	if *allFlag {
		flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG)
	}

	if *identFlag {
		flags |= IFLAG
	}

	if *osnameFlag || *sysnameFlag {
		flags |= SFLAG
	}

	if *platformFlag {
		flags |= MFLAG
	}

	if *hostnameFlag {
		flags |= NFLAG
	}

	if *archFlag {
		flags |= PFLAG
	}

	if *releaseFlag {
		flags |= RFLAG
	}

	if *versionFlag {
		flags |= VFLAG
	}

	if *kernversFlag {
		flags |= KFLAG
	}

	if *helpFlag {
		usage()
	}

	if flags == 0 {
		flags |= SFLAG
	}

	printUname(flags)
}

var isPrinted bool

func printFlag(flags, flg int, envVar, sysctlName string, fn func(string, string) string) {
	if flags&flg == flg {
		if isPrinted {
			fmt.Print(" ")
		}

		fmt.Print(fn(envVar, sysctlName))
		isPrinted = true
	}
}

func printUname(flags int) {
	printFlag(flags, SFLAG, "s", "kern.ostype", getValue)
	printFlag(flags, NFLAG, "n", "kern.hostname", getValue)
	printFlag(flags, RFLAG, "r", "kern.osrelease", getValue)
	printFlag(flags, VFLAG, "v", "kern.version", getVersion)
	printFlag(flags, MFLAG, "m", "hw.machine", getValue)
	printFlag(flags, PFLAG, "p", "hw.machine_arch", getValue)
	printFlag(flags, IFLAG, "i", "kern.ident", getValue)
	printFlag(flags, KFLAG, "K", "kern.osreldate", getIntValue)

	fmt.Println()
}

func isEnvSet(flg string) (bool, string) {
	if val := os.Getenv("UNAME_" + flg); val != "" {
		return true, val
	} else {
		return false, ""
	}
}

func getSysctl(sysctlName string) (val string) {
	var err error
	if val, err = syscall.Sysctl(sysctlName); err != nil {
		fmt.Fprintf(os.Stderr, "%s - %v\n", sysctlName, err)
		os.Exit(1)
	}

	return val
}

func getSysctlUint32AsString(sysctlName string) (val string) {
	if ret, err := syscall.SysctlUint32(sysctlName); err != nil {
		fmt.Fprintf(os.Stderr, "%s - %v", sysctlName, err)
		os.Exit(1)
	} else {
		val = strconv.FormatUint(uint64(ret), 10)
	}

	return
}

func getValue(envVar, sysctlName string) string {
	if yes, envVal := isEnvSet(envVar); yes {
		return envVal
	} else {
		return getSysctl(sysctlName)
	}
}

func getIntValue(envVar, sysctlName string) string {
	if yes, envVal := isEnvSet(envVar); yes {
		return envVal
	} else {
		return getSysctlUint32AsString(sysctlName)
	}
}

func getVersion(envVar, sysctlName string) string {
	if yes, envVal := isEnvSet(envVar); yes {
		return envVal
	} else {
		version := []byte(getSysctl(sysctlName))
		for i, r := range version {
			if r == '\n' || r == '\t' {
				version[i] = ' '
			}
		}

		return string(version)
	}
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: uname [-aiKmnoprsUv]\n")
	os.Exit(1)
}
<commit_msg>flag descriptions added and help flag removed<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strconv"
	"syscall"
)

const (
	MFLAG = 1 << iota
	NFLAG
	PFLAG
	RFLAG
	SFLAG
	VFLAG
	IFLAG
	KFLAG
)

func main() {
	allFlag := flag.Bool("a", false, "Behave as though the options -m, -n, -r, -s, and -v were specified.")
	identFlag := flag.Bool("i", false, "Write the kernel ident to standard output.")
	platformFlag := flag.Bool("m", false, "Write the type of the current hardware platform to standard output.")
	hostnameFlag := flag.Bool("n", false, "Write the name of the system to standard output.")
	osnameFlag := flag.Bool("o", false, "This is a synonym for the -s option, for compatibility with other systems.")
	archFlag := flag.Bool("p", false, "Write the type of the machine processor architecture to standard output.")
	releaseFlag := flag.Bool("r", false, "Write the current release level of the operating system to standard output.")
	sysnameFlag := flag.Bool("s", false, "Write the name of the operating system implementation to standard output.")
	versionFlag := flag.Bool("v", false, "Write the version level of this release of the operating system to standard output.")
	kernversFlag := flag.Bool("K", false, "Write the FreeBSD version of the kernel.")
	flag.Usage = usage

	flag.Parse()

	var flags int

	if *allFlag {
		flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG)
	}

	if *identFlag {
		flags |= IFLAG
	}

	if *osnameFlag || *sysnameFlag {
		flags |= SFLAG
	}

	if *platformFlag {
		flags |= MFLAG
	}

	if *hostnameFlag {
		flags |= NFLAG
	}

	if *archFlag {
		flags |= PFLAG
	}

	if *releaseFlag {
		flags |= RFLAG
	}

	if *versionFlag {
		flags |= VFLAG
	}

	if *kernversFlag {
		flags |= KFLAG
	}

	if flags == 0 {
		flags |= SFLAG
	}

	printUname(flags)
}

var isPrinted bool

func printFlag(flags, flg int, envVar, sysctlName string, fn func(string, string) string) {
	if flags&flg == flg {
		if isPrinted {
			fmt.Print(" ")
		}

		fmt.Print(fn(envVar, sysctlName))
		isPrinted = true
	}
}

func printUname(flags int) {
	printFlag(flags, SFLAG, "s", "kern.ostype", getValue)
	printFlag(flags, NFLAG, "n", "kern.hostname", getValue)
	printFlag(flags, RFLAG, "r", "kern.osrelease", getValue)
	printFlag(flags, VFLAG, "v", "kern.version", getVersion)
	printFlag(flags, MFLAG, "m", "hw.machine", getValue)
	printFlag(flags, PFLAG, "p", "hw.machine_arch", getValue)
	printFlag(flags, IFLAG, "i", "kern.ident", getValue)
	printFlag(flags, KFLAG, "K", "kern.osreldate", getIntValue)

	fmt.Println()
}

func isEnvSet(flg string) (bool, string) {
	if val := os.Getenv("UNAME_" + flg); val != "" {
		return true, val
	} else {
		return false, ""
	}
}

func getSysctl(sysctlName string) (val string) {
	var err error
	if val, err = syscall.Sysctl(sysctlName); err != nil {
		fmt.Fprintf(os.Stderr, "%s - %v\n", sysctlName, err)
		os.Exit(1)
	}

	return val
}

func getSysctlUint32AsString(sysctlName string) (val string) {
	if ret, err := syscall.SysctlUint32(sysctlName); err != nil {
		fmt.Fprintf(os.Stderr, "%s - %v", sysctlName, err)
		os.Exit(1)
	} else {
		val = strconv.FormatUint(uint64(ret), 10)
	}

	return
}

func getValue(envVar, sysctlName string) string {
	if yes, envVal := isEnvSet(envVar); yes {
		return envVal
	} else {
		return getSysctl(sysctlName)
	}
}

func getIntValue(envVar, sysctlName string) string {
	if yes, envVal := isEnvSet(envVar); yes {
		return envVal
	} else {
		return getSysctlUint32AsString(sysctlName)
	}
}

func getVersion(envVar, sysctlName string) string {
	if yes, envVal := isEnvSet(envVar); yes {
		return envVal
	} else {
		version := []byte(getSysctl(sysctlName))
		for i, r := range version {
			if r == '\n' || r == '\t' {
				version[i] = ' '
			}
		}

		return string(version)
	}
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: uname [-aiKmnoprsUv]\n")
	os.Exit(1)
}
<|endoftext|>


<commit_before>package output

import (
	"bytes"
	"fmt"
	"os"
	"time"

	"github.com/hoop33/limo/model"
)

// Text is a monochrome text output
type Text struct {
}

// Inline displays text in line
func (t *Text) Inline(s string) {
	fmt.Print(s)
}

// Info displays information
func (t *Text) Info(s string) {
	fmt.Println(s)
}

// Error displays an error
func (t *Text) Error(s string) {
	fmt.Fprintln(os.Stderr, s)
}

// Fatal displays an error and ends the program
func (t *Text) Fatal(s string) {
	t.Error(s)
	os.Exit(1)
}

// StarLine displays a star in one line
func (t *Text) StarLine(star *model.Star) {
	var buffer bytes.Buffer

	_, err := buffer.WriteString(*star.FullName)
	if err != nil {
		t.Error(err.Error())
	}

	if star.Stargazers > 0 {
		_, err = buffer.WriteString(fmt.Sprintf(" (*: %d)", star.Stargazers))
		if err != nil {
			t.Error(err.Error())
		}
	}

	if star.Language != nil {
		_, err := buffer.WriteString(fmt.Sprintf(" (%s)", *star.Language))
		if err != nil {
			t.Error(err.Error())
		}
	}
	fmt.Println(buffer.String())
}

// Star displays a star
func (t *Text) Star(star *model.Star) {
	t.StarLine(star)

	if len(star.Tags) > 0 {
		var buffer bytes.Buffer
		leader := ""
		for _, tag := range star.Tags {
			_, err := buffer.WriteString(fmt.Sprintf("%s%s", leader, tag.Name))
			if err != nil {
				t.Error(err.Error())
			}
			leader = ", "
		}
		fmt.Println(buffer.String())
	}

	if star.Description != nil && *star.Description != "" {
		fmt.Println(*star.Description)
	}

	if star.Homepage != nil && *star.Homepage != "" {
		fmt.Println(fmt.Sprintf("Home page: %s", *star.Homepage))
	}

	if star.URL != nil {
		fmt.Println(fmt.Sprintf("URL: %s", *star.URL))
	}

	fmt.Println(fmt.Sprintf("Starred on %s", star.StarredAt.Format(time.UnixDate)))
}

// Tick displays evidence that the program is working
func (t *Text) Tick() {
	fmt.Print(".")
}

func init() {
	registerOutput(&Text{})
}
<commit_msg>Fix Println/Sprintf calls<commit_after>package output

import (
	"bytes"
	"fmt"
	"os"
	"time"

	"github.com/hoop33/limo/model"
)

// Text is a monochrome text output
type Text struct {
}

// Inline displays text in line
func (t *Text) Inline(s string) {
	fmt.Print(s)
}

// Info displays information
func (t *Text) Info(s string) {
	fmt.Println(s)
}

// Error displays an error
func (t *Text) Error(s string) {
	fmt.Fprintln(os.Stderr, s)
}

// Fatal displays an error and ends the program
func (t *Text) Fatal(s string) {
	t.Error(s)
	os.Exit(1)
}

// StarLine displays a star in one line
func (t *Text) StarLine(star *model.Star) {
	var buffer bytes.Buffer

	_, err := buffer.WriteString(*star.FullName)
	if err != nil {
		t.Error(err.Error())
	}

	if star.Stargazers > 0 {
		_, err = buffer.WriteString(fmt.Sprintf(" (*: %d)", star.Stargazers))
		if err != nil {
			t.Error(err.Error())
		}
	}

	if star.Language != nil {
		_, err := buffer.WriteString(fmt.Sprintf(" (%s)", *star.Language))
		if err != nil {
			t.Error(err.Error())
		}
	}
	fmt.Println(buffer.String())
}

// Star displays a star
func (t *Text) Star(star *model.Star) {
	t.StarLine(star)

	if len(star.Tags) > 0 {
		var buffer bytes.Buffer
		leader := ""
		for _, tag := range star.Tags {
			_, err := buffer.WriteString(fmt.Sprintf("%s%s", leader, tag.Name))
			if err != nil {
				t.Error(err.Error())
			}
			leader = ", "
		}
		fmt.Println(buffer.String())
	}

	if star.Description != nil && *star.Description != "" {
		fmt.Println(*star.Description)
	}

	if star.Homepage != nil && *star.Homepage != "" {
		fmt.Printf("Home page: %s\n", *star.Homepage)
	}

	if star.URL != nil {
		fmt.Printf("URL: %s\n", *star.URL)
	}

	fmt.Printf("Starred on %s\n", star.StarredAt.Format(time.UnixDate))
}

// Tick displays evidence that the program is working
func (t *Text) Tick() {
	fmt.Print(".")
}

func init() {
	registerOutput(&Text{})
}
<|endoftext|>


<commit_before>// {{{ Copyright (c) Paul R. Tagliamonte <paultag@gmail.com>, 2016
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. }}}

package pkcs7

import (
	"fmt"
)

func Unpad(data []byte, blockSize uint) ([]byte, error) {
	if blockSize < 1 {
		return nil, fmt.Errorf("Block size looks wrong")
	}

	if uint(len(data))%blockSize != 0 {
		return nil, fmt.Errorf("Data isn't aligned to blockSize")
	}

	if len(data) == 0 {
		return nil, fmt.Errorf("Data is empty")
	}

	paddingLength := int(data[len(data)-1])
	for _, el := range data[len(data)-paddingLength:] {
		if el != byte(paddingLength) {
			return nil, fmt.Errorf("Padding had malformed entries")
		}
	}

	return data[:len(data)-paddingLength], nil
}

// vim: foldmethod=marker
<commit_msg>fix padding<commit_after>// {{{ Copyright (c) Paul R. Tagliamonte <paultag@gmail.com>, 2016
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. }}}

package pkcs7

import (
	"bytes"
	"fmt"
)

func Unpad(data []byte, blockSize uint) ([]byte, error) {
	if blockSize < 1 {
		return nil, fmt.Errorf("Block size looks wrong")
	}

	if uint(len(data))%blockSize != 0 {
		return nil, fmt.Errorf("Data isn't aligned to blockSize")
	}

	if len(data) == 0 {
		return nil, fmt.Errorf("Data is empty")
	}

	paddingLength := int(data[len(data)-1])
	for _, el := range data[len(data)-paddingLength:] {
		if el != byte(paddingLength) {
			return nil, fmt.Errorf("Padding had malformed entries")
		}
	}

	return data[:len(data)-paddingLength], nil
}

func Pad(data []byte, blockSize uint) ([]byte, error) {
	neededBytes := blockSize - (uint(len(data)) % blockSize)
	return append(data, bytes.Repeat([]byte{byte(neededBytes)}, int(neededBytes))...), nil

}

// vim: foldmethod=marker
<|endoftext|>


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

package srv

import (
	"code.google.com/p/go9p/p"
)

func (srv *Srv) version(req *Req) {
	tc := req.Tc
	conn := req.Conn

	if tc.Msize < p.IOHDRSZ {
		req.RespondError(&p.Error{"msize too small", p.EINVAL})
		return
	}

	if tc.Msize < conn.Msize {
		conn.Msize = tc.Msize
	}

	conn.Dotu = tc.Version == "9P2000.u" && srv.Dotu
	ver := "9P2000"
	if conn.Dotu {
		ver = "9P2000.u"
	}

	/* make sure that the responses of all current requests will be ignored */
	conn.Lock()
	for tag, r := range conn.reqs {
		if tag == p.NOTAG {
			continue
		}

		for rr := r; rr != nil; rr = rr.next {
			rr.Lock()
			rr.status |= reqFlush
			rr.Unlock()
		}
	}
	conn.Unlock()

	req.RespondRversion(conn.Msize, ver)
}

func (srv *Srv) auth(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Afid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Afid = conn.FidNew(tc.Afid)
	if req.Afid == nil {
		req.RespondError(Einuse)
		return
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Afid.User = user
	req.Afid.Type = p.QTAUTH
	if aop, ok := (srv.ops).(AuthOps); ok {
		aqid, err := aop.AuthInit(req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
		} else {
			aqid.Type |= p.QTAUTH // just in case
			req.RespondRauth(aqid)
		}
	} else {
		req.RespondError(Enoauth)
	}

}

func (srv *Srv) authPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rauth {
		req.Afid.IncRef()
	}
}

func (srv *Srv) attach(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Fid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Fid = conn.FidNew(tc.Fid)
	if req.Fid == nil {
		req.RespondError(Einuse)
		return
	}

	if tc.Afid != p.NOFID {
		req.Afid = conn.FidGet(tc.Afid)
		if req.Afid == nil {
			req.RespondError(Eunknownfid)
		}
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Fid.User = user
	if aop, ok := (srv.ops).(AuthOps); ok {
		err := aop.AuthCheck(req.Fid, req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
			return
		}
	}

	(srv.ops).(ReqOps).Attach(req)
}

func (srv *Srv) attachPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rattach {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.IncRef()
	}
}

func (srv *Srv) flush(req *Req) {
	conn := req.Conn
	tag := req.Tc.Oldtag
	p.PackRflush(req.Rc)
	conn.Lock()
	r := conn.reqs[tag]
	if r != nil {
		req.flushreq = r.flushreq
		r.flushreq = req
	}
	conn.Unlock()

	if r == nil {
		// there are no requests with that tag
		req.Respond()
		return
	}

	r.Lock()
	status := r.status
	if (status & (reqWork | reqSaved)) == 0 {
		/* the request is not worked on yet */
		r.status |= reqFlush
	}
	r.Unlock()

	if (status & (reqWork | reqSaved)) == 0 {
		r.Respond()
	} else {
		if op, ok := (srv.ops).(FlushOp); ok {
			op.Flush(r)
		}
	}
}

func (srv *Srv) walk(req *Req) {
	conn := req.Conn
	tc := req.Tc
	fid := req.Fid

	/* we can't walk regular files, only clone them */
	if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* we can't walk open files */
	if fid.opened {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Fid != tc.Newfid {
		req.Newfid = conn.FidNew(tc.Newfid)
		if req.Newfid == nil {
			req.RespondError(Einuse)
			return
		}

		req.Newfid.User = fid.User
		req.Newfid.Type = fid.Type
	} else {
		req.Newfid = req.Fid
		req.Newfid.IncRef()
	}

	(req.Conn.Srv.ops).(ReqOps).Walk(req)
}

func (srv *Srv) walkPost(req *Req) {
	rc := req.Rc
	if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
		return
	}

	n := len(rc.Wqid)
	if n > 0 {
		req.Newfid.Type = rc.Wqid[n-1].Type
	} else {
		req.Newfid.Type = req.Fid.Type
	}

	// Don't retain the fid if only a partial walk succeeded
	if n != len(req.Tc.Wname) {
		return
	}

	if req.Newfid.fid != req.Fid.fid {
		req.Newfid.IncRef()
	}
}

func (srv *Srv) open(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Open(req)
}

func (srv *Srv) openPost(req *Req) {
	if req.Fid != nil {
		req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
	}
}

func (srv *Srv) create(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type & p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* can't open directories for other than reading */
	if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	/* can't create special files if not 9P2000.u */
	if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Create(req)
}

func (srv *Srv) createPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.opened = true
	}
}

func (srv *Srv) read(req *Req) {
	tc := req.Tc
	fid := req.Fid
	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	if (fid.Type & p.QTAUTH) != 0 {
		var n int

		rc := req.Tc
		err := p.InitRread(rc, tc.Count)
		if err != nil {
			req.RespondError(err)
			return
		}

		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err = op.AuthRead(fid, tc.Offset, rc.Data)
			if err != nil {
				req.RespondError(err)
				return
			}

			p.SetRreadCount(rc, uint32(n))
			req.Respond()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if (fid.Type & p.QTDIR) != 0 {
		if tc.Offset == 0 {
			fid.Diroffset = 0
		} else if tc.Offset != fid.Diroffset {
			req.RespondError(Ebadoffset)
			return
		}
	}

	(req.Conn.Srv.ops).(ReqOps).Read(req)
}

func (srv *Srv) readPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
		req.Fid.Diroffset += uint64(req.Rc.Count)
	}
}

func (srv *Srv) write(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if (fid.Type & p.QTAUTH) != 0 {
		tc := req.Tc
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
			if err != nil {
				req.RespondError(err)
			} else {
				req.RespondRwrite(uint32(n))
			}
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	(req.Conn.Srv.ops).(ReqOps).Write(req)
}

func (srv *Srv) clunk(req *Req) {
	fid := req.Fid
	if (fid.Type & p.QTAUTH) != 0 {
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			op.AuthDestroy(fid)
			req.RespondRclunk()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	(req.Conn.Srv.ops).(ReqOps).Clunk(req)
}

func (srv *Srv) clunkPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }

func (srv *Srv) removePost(req *Req) {
	if req.Rc != nil && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }

func (srv *Srv) wstat(req *Req) {
	/*
		fid := req.Fid
		d := &req.Tc.Dir
		if d.Type != uint16(0xFFFF) || d.Dev != uint32(0xFFFFFFFF) || d.Version != uint32(0xFFFFFFFF) ||
			d.Path != uint64(0xFFFFFFFFFFFFFFFF) {
			req.RespondError(Eperm)
			return
		}

		if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
			((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
			req.RespondError(Edirchange)
			return
		}
	*/

	(req.Conn.Srv.ops).(ReqOps).Wstat(req)
}
<commit_msg>srv: Another bug which caused "short buffer" for all Rreads on afids.<commit_after>// Copyright 2009 The Go9p Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package srv

import (
	"code.google.com/p/go9p/p"
)

func (srv *Srv) version(req *Req) {
	tc := req.Tc
	conn := req.Conn

	if tc.Msize < p.IOHDRSZ {
		req.RespondError(&p.Error{"msize too small", p.EINVAL})
		return
	}

	if tc.Msize < conn.Msize {
		conn.Msize = tc.Msize
	}

	conn.Dotu = tc.Version == "9P2000.u" && srv.Dotu
	ver := "9P2000"
	if conn.Dotu {
		ver = "9P2000.u"
	}

	/* make sure that the responses of all current requests will be ignored */
	conn.Lock()
	for tag, r := range conn.reqs {
		if tag == p.NOTAG {
			continue
		}

		for rr := r; rr != nil; rr = rr.next {
			rr.Lock()
			rr.status |= reqFlush
			rr.Unlock()
		}
	}
	conn.Unlock()

	req.RespondRversion(conn.Msize, ver)
}

func (srv *Srv) auth(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Afid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Afid = conn.FidNew(tc.Afid)
	if req.Afid == nil {
		req.RespondError(Einuse)
		return
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Afid.User = user
	req.Afid.Type = p.QTAUTH
	if aop, ok := (srv.ops).(AuthOps); ok {
		aqid, err := aop.AuthInit(req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
		} else {
			aqid.Type |= p.QTAUTH // just in case
			req.RespondRauth(aqid)
		}
	} else {
		req.RespondError(Enoauth)
	}

}

func (srv *Srv) authPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rauth {
		req.Afid.IncRef()
	}
}

func (srv *Srv) attach(req *Req) {
	tc := req.Tc
	conn := req.Conn
	if tc.Fid == p.NOFID {
		req.RespondError(Eunknownfid)
		return
	}

	req.Fid = conn.FidNew(tc.Fid)
	if req.Fid == nil {
		req.RespondError(Einuse)
		return
	}

	if tc.Afid != p.NOFID {
		req.Afid = conn.FidGet(tc.Afid)
		if req.Afid == nil {
			req.RespondError(Eunknownfid)
		}
	}

	var user p.User = nil
	if tc.Unamenum != p.NOUID || conn.Dotu {
		user = srv.Upool.Uid2User(int(tc.Unamenum))
	} else if tc.Uname != "" {
		user = srv.Upool.Uname2User(tc.Uname)
	}

	if user == nil {
		req.RespondError(Enouser)
		return
	}

	req.Fid.User = user
	if aop, ok := (srv.ops).(AuthOps); ok {
		err := aop.AuthCheck(req.Fid, req.Afid, tc.Aname)
		if err != nil {
			req.RespondError(err)
			return
		}
	}

	(srv.ops).(ReqOps).Attach(req)
}

func (srv *Srv) attachPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rattach {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.IncRef()
	}
}

func (srv *Srv) flush(req *Req) {
	conn := req.Conn
	tag := req.Tc.Oldtag
	p.PackRflush(req.Rc)
	conn.Lock()
	r := conn.reqs[tag]
	if r != nil {
		req.flushreq = r.flushreq
		r.flushreq = req
	}
	conn.Unlock()

	if r == nil {
		// there are no requests with that tag
		req.Respond()
		return
	}

	r.Lock()
	status := r.status
	if (status & (reqWork | reqSaved)) == 0 {
		/* the request is not worked on yet */
		r.status |= reqFlush
	}
	r.Unlock()

	if (status & (reqWork | reqSaved)) == 0 {
		r.Respond()
	} else {
		if op, ok := (srv.ops).(FlushOp); ok {
			op.Flush(r)
		}
	}
}

func (srv *Srv) walk(req *Req) {
	conn := req.Conn
	tc := req.Tc
	fid := req.Fid

	/* we can't walk regular files, only clone them */
	if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* we can't walk open files */
	if fid.opened {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Fid != tc.Newfid {
		req.Newfid = conn.FidNew(tc.Newfid)
		if req.Newfid == nil {
			req.RespondError(Einuse)
			return
		}

		req.Newfid.User = fid.User
		req.Newfid.Type = fid.Type
	} else {
		req.Newfid = req.Fid
		req.Newfid.IncRef()
	}

	(req.Conn.Srv.ops).(ReqOps).Walk(req)
}

func (srv *Srv) walkPost(req *Req) {
	rc := req.Rc
	if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
		return
	}

	n := len(rc.Wqid)
	if n > 0 {
		req.Newfid.Type = rc.Wqid[n-1].Type
	} else {
		req.Newfid.Type = req.Fid.Type
	}

	// Don't retain the fid if only a partial walk succeeded
	if n != len(req.Tc.Wname) {
		return
	}

	if req.Newfid.fid != req.Fid.fid {
		req.Newfid.IncRef()
	}
}

func (srv *Srv) open(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Open(req)
}

func (srv *Srv) openPost(req *Req) {
	if req.Fid != nil {
		req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
	}
}

func (srv *Srv) create(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if fid.opened {
		req.RespondError(Eopen)
		return
	}

	if (fid.Type & p.QTDIR) == 0 {
		req.RespondError(Enotdir)
		return
	}

	/* can't open directories for other than reading */
	if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
		req.RespondError(Eperm)
		return
	}

	/* can't create special files if not 9P2000.u */
	if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
		req.RespondError(Eperm)
		return
	}

	fid.Omode = tc.Mode
	(req.Conn.Srv.ops).(ReqOps).Create(req)
}

func (srv *Srv) createPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
		req.Fid.Type = req.Rc.Qid.Type
		req.Fid.opened = true
	}
}

func (srv *Srv) read(req *Req) {
	tc := req.Tc
	fid := req.Fid
	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	if (fid.Type & p.QTAUTH) != 0 {
		var n int

		rc := req.Rc
		err := p.InitRread(rc, tc.Count)
		if err != nil {
			req.RespondError(err)
			return
		}

		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err = op.AuthRead(fid, tc.Offset, rc.Data)
			if err != nil {
				req.RespondError(err)
				return
			}

			p.SetRreadCount(rc, uint32(n))
			req.Respond()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if (fid.Type & p.QTDIR) != 0 {
		if tc.Offset == 0 {
			fid.Diroffset = 0
		} else if tc.Offset != fid.Diroffset {
			req.RespondError(Ebadoffset)
			return
		}
	}

	(req.Conn.Srv.ops).(ReqOps).Read(req)
}

func (srv *Srv) readPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
		req.Fid.Diroffset += uint64(req.Rc.Count)
	}
}

func (srv *Srv) write(req *Req) {
	fid := req.Fid
	tc := req.Tc
	if (fid.Type & p.QTAUTH) != 0 {
		tc := req.Tc
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
			if err != nil {
				req.RespondError(err)
			} else {
				req.RespondRwrite(uint32(n))
			}
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
		req.RespondError(Ebaduse)
		return
	}

	if tc.Count+p.IOHDRSZ > req.Conn.Msize {
		req.RespondError(Etoolarge)
		return
	}

	(req.Conn.Srv.ops).(ReqOps).Write(req)
}

func (srv *Srv) clunk(req *Req) {
	fid := req.Fid
	if (fid.Type & p.QTAUTH) != 0 {
		if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
			op.AuthDestroy(fid)
			req.RespondRclunk()
		} else {
			req.RespondError(Enotimpl)
		}

		return
	}

	(req.Conn.Srv.ops).(ReqOps).Clunk(req)
}

func (srv *Srv) clunkPost(req *Req) {
	if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }

func (srv *Srv) removePost(req *Req) {
	if req.Rc != nil && req.Fid != nil {
		req.Fid.DecRef()
	}
}

func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }

func (srv *Srv) wstat(req *Req) {
	/*
		fid := req.Fid
		d := &req.Tc.Dir
		if d.Type != uint16(0xFFFF) || d.Dev != uint32(0xFFFFFFFF) || d.Version != uint32(0xFFFFFFFF) ||
			d.Path != uint64(0xFFFFFFFFFFFFFFFF) {
			req.RespondError(Eperm)
			return
		}

		if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
			((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
			req.RespondError(Edirchange)
			return
		}
	*/

	(req.Conn.Srv.ops).(ReqOps).Wstat(req)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"crypto/subtle"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/crypto/scrypt"

	"github.com/labstack/echo"
)

const (
	// SaltSize is the lenght of the salt string
	SaltSize = 32
	// HashSize is the lenght of the hash string
	HashSize = 64
)

// User holds the user response from user-store
type User struct {
	ID       int    `json:"id"`
	GroupID  int    `json:"group_id"`
	Username string `json:"username"`
	Password string `json:"password,omitempty"`
	Salt     string `json:"salt,omitempty"`
	Admin    bool   `json:"admin"`
}

// Validate vaildate all of the user's input
func (u *User) Validate() error {
	if u.Username == "" {
		return errors.New("User username is empty")
	}

	if u.Password == "" {
		return errors.New("User password is empty")
	}

	if u.GroupID == 0 {
		return errors.New("User group is empty")
	}

	return nil
}

// Map a user from a request's body and validates the input
func (u *User) Map(c echo.Context) *echo.HTTPError {
	body := c.Request().Body()
	data, err := ioutil.ReadAll(body)
	if err != nil {
		return ErrBadReqBody
	}

	err = json.Unmarshal(data, &u)
	if err != nil {
		return ErrBadReqBody
	}

	err = u.Validate()
	if err != nil {
		return ErrBadReqBody
	}

	return nil
}

// Redact removes all sensitive fields from the return data before outputting to the user
func (u *User) Redact() {
	u.Password = ""
	u.Salt = ""
}

// ValidPassword checks if a submitted password matches the users password hash
func (u *User) ValidPassword(pw string) bool {
	userpass, err := base64.StdEncoding.DecodeString(u.Password)
	if err != nil {
		return false
	}

	usersalt, err := base64.StdEncoding.DecodeString(u.Salt)
	if err != nil {
		return false
	}

	hash, err := scrypt.Key([]byte(pw), usersalt, 16384, 8, 1, HashSize)
	if err != nil {
		return false
	}

	// Compare in constant time to mitigate timing attacks
	if subtle.ConstantTimeCompare(userpass, hash) == 1 {
		return true
	}

	return false
}

func getUsersHandler(c echo.Context) error {
	var query string
	var users []User

	au := authenticatedUser(c)

	if !au.Admin {
		query = fmt.Sprintf(`{"group_id": %d}`, au.GroupID)
	}

	msg, err := n.Request("user.find", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &users)
	if err != nil {
		return ErrInternal
	}

	for i := 0; i < len(users); i++ {
		users[i].Redact()
	}

	return c.JSON(http.StatusOK, users)
}

func getUserHandler(c echo.Context) error {
	var query string
	var user User

	au := authenticatedUser(c)

	if au.Admin {
		query = fmt.Sprintf(`{"id": %s}`, c.Param("user"))
	} else {
		query = fmt.Sprintf(`{"id": %s, "group_id": %d}`, c.Param("user"), au.GroupID)
	}

	msg, err := n.Request("user.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &user)
	if err != nil {
		return ErrInternal
	}

	user.Redact()

	return c.JSON(http.StatusOK, user)
}

func createUserHandler(c echo.Context) error {
	var u User
	var created User
	var existing User

	if authenticatedUser(c).Admin != true {
		return ErrUnauthorized
	}

	if u.Map(c) != nil {
		return ErrBadReqBody
	}

	// Check if the group exists
	query := fmt.Sprintf(`{"id": %d}`, u.GroupID)
	msg, err := n.Request("group.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Check if the user exists
	query = fmt.Sprintf(`{"username": "%s"}`, u.Username)
	msg, err = n.Request("user.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	err = json.Unmarshal(msg.Data, &existing)
	if err != nil {
		return ErrInternal
	}

	if existing.ID != 0 {
		c.Response().Header().Add("Location", fmt.Sprintf("/users/%d", existing.ID))
		return ErrExists
	}

	// Create the user
	data, err := json.Marshal(u)
	if err != nil {
		return ErrInternal
	}

	msg, err = n.Request("user.set", data, 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &created)
	if err != nil {
		return ErrInternal
	}

	created.Redact()

	return c.JSON(http.StatusOK, created)
}

func updateUserHandler(c echo.Context) error {
	var u User
	var updated User
	var existing User

	if u.Map(c) != nil {
		return ErrBadReqBody
	}

	data, err := json.Marshal(u)
	if err != nil {
		return ErrInternal
	}

	// Check if authenticated user is admin or updating itself
	au := authenticatedUser(c)
	if au.Username != u.Username && au.Admin != true {
		return ErrUnauthorized
	}

	// Check user exists
	query := fmt.Sprintf(`{"id": %d}`, u.ID)
	msg, err := n.Request("user.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	err = json.Unmarshal(msg.Data, &existing)
	if err != nil {
		return ErrInternal
	}

	if existing.ID == 0 {
		return ErrNotFound
	}

	// Check a non-admin user is not trying to change their group
	if au.Admin != true && u.GroupID != existing.GroupID {
		return ErrUnauthorized
	}

	// update the user
	msg, err = n.Request("user.set", data, 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &updated)
	if err != nil {
		return ErrInternal
	}

	updated.Redact()

	return c.JSON(http.StatusOK, updated)
}

func deleteUserHandler(c echo.Context) error {
	au := authenticatedUser(c)
	if au.Admin != true {
		return ErrUnauthorized
	}

	query := fmt.Sprintf(`{"id": %s}`, c.Param("user"))
	msg, err := n.Request("user.del", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		fmt.Println(re.Error)
		return re.HTTPError
	}

	return c.String(http.StatusOK, "")
}
<commit_msg>Added oldpassword to the user struct<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"crypto/subtle"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/crypto/scrypt"

	"github.com/labstack/echo"
)

const (
	// SaltSize is the lenght of the salt string
	SaltSize = 32
	// HashSize is the lenght of the hash string
	HashSize = 64
)

// User holds the user response from user-store
type User struct {
	ID          int    `json:"id"`
	GroupID     int    `json:"group_id"`
	Username    string `json:"username"`
	Password    string `json:"password,omitempty"`
	OldPassword string `json:"oldpassword,omitempty"`
	Salt        string `json:"salt,omitempty"`
	Admin       bool   `json:"admin"`
}

// Validate vaildate all of the user's input
func (u *User) Validate() error {
	if u.Username == "" {
		return errors.New("User username is empty")
	}

	if u.Password == "" {
		return errors.New("User password is empty")
	}

	if u.GroupID == 0 {
		return errors.New("User group is empty")
	}

	return nil
}

// Map a user from a request's body and validates the input
func (u *User) Map(c echo.Context) *echo.HTTPError {
	body := c.Request().Body()
	data, err := ioutil.ReadAll(body)
	if err != nil {
		return ErrBadReqBody
	}

	err = json.Unmarshal(data, &u)
	if err != nil {
		return ErrBadReqBody
	}

	err = u.Validate()
	if err != nil {
		return ErrBadReqBody
	}

	return nil
}

// Redact removes all sensitive fields from the return data before outputting to the user
func (u *User) Redact() {
	u.Password = ""
	u.Salt = ""
}

// ValidPassword checks if a submitted password matches the users password hash
func (u *User) ValidPassword(pw string) bool {
	userpass, err := base64.StdEncoding.DecodeString(u.Password)
	if err != nil {
		return false
	}

	usersalt, err := base64.StdEncoding.DecodeString(u.Salt)
	if err != nil {
		return false
	}

	hash, err := scrypt.Key([]byte(pw), usersalt, 16384, 8, 1, HashSize)
	if err != nil {
		return false
	}

	// Compare in constant time to mitigate timing attacks
	if subtle.ConstantTimeCompare(userpass, hash) == 1 {
		return true
	}

	return false
}

func getUsersHandler(c echo.Context) error {
	var query string
	var users []User

	au := authenticatedUser(c)

	if !au.Admin {
		query = fmt.Sprintf(`{"group_id": %d}`, au.GroupID)
	}

	msg, err := n.Request("user.find", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &users)
	if err != nil {
		return ErrInternal
	}

	for i := 0; i < len(users); i++ {
		users[i].Redact()
	}

	return c.JSON(http.StatusOK, users)
}

func getUserHandler(c echo.Context) error {
	var query string
	var user User

	au := authenticatedUser(c)

	if au.Admin {
		query = fmt.Sprintf(`{"id": %s}`, c.Param("user"))
	} else {
		query = fmt.Sprintf(`{"id": %s, "group_id": %d}`, c.Param("user"), au.GroupID)
	}

	msg, err := n.Request("user.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &user)
	if err != nil {
		return ErrInternal
	}

	user.Redact()

	return c.JSON(http.StatusOK, user)
}

func createUserHandler(c echo.Context) error {
	var u User
	var created User
	var existing User

	if authenticatedUser(c).Admin != true {
		return ErrUnauthorized
	}

	if u.Map(c) != nil {
		return ErrBadReqBody
	}

	// Check if the group exists
	query := fmt.Sprintf(`{"id": %d}`, u.GroupID)
	msg, err := n.Request("group.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Check if the user exists
	query = fmt.Sprintf(`{"username": "%s"}`, u.Username)
	msg, err = n.Request("user.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	err = json.Unmarshal(msg.Data, &existing)
	if err != nil {
		return ErrInternal
	}

	if existing.ID != 0 {
		c.Response().Header().Add("Location", fmt.Sprintf("/users/%d", existing.ID))
		return ErrExists
	}

	// Create the user
	data, err := json.Marshal(u)
	if err != nil {
		return ErrInternal
	}

	msg, err = n.Request("user.set", data, 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &created)
	if err != nil {
		return ErrInternal
	}

	created.Redact()

	return c.JSON(http.StatusOK, created)
}

func updateUserHandler(c echo.Context) error {
	var u User
	var updated User
	var existing User

	if u.Map(c) != nil {
		return ErrBadReqBody
	}

	data, err := json.Marshal(u)
	if err != nil {
		return ErrInternal
	}

	// Check if authenticated user is admin or updating itself
	au := authenticatedUser(c)
	if au.Username != u.Username && au.Admin != true {
		return ErrUnauthorized
	}

	// Check user exists
	query := fmt.Sprintf(`{"id": %d}`, u.ID)
	msg, err := n.Request("user.get", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	err = json.Unmarshal(msg.Data, &existing)
	if err != nil {
		return ErrInternal
	}

	if existing.ID == 0 {
		return ErrNotFound
	}

	// Check a non-admin user is not trying to change their group
	if au.Admin != true && u.GroupID != existing.GroupID {
		return ErrUnauthorized
	}

	// update the user
	msg, err = n.Request("user.set", data, 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		return re.HTTPError
	}

	// Remove sensitive data
	err = json.Unmarshal(msg.Data, &updated)
	if err != nil {
		return ErrInternal
	}

	updated.Redact()

	return c.JSON(http.StatusOK, updated)
}

func deleteUserHandler(c echo.Context) error {
	au := authenticatedUser(c)
	if au.Admin != true {
		return ErrUnauthorized
	}

	query := fmt.Sprintf(`{"id": %s}`, c.Param("user"))
	msg, err := n.Request("user.del", []byte(query), 5*time.Second)
	if err != nil {
		return ErrGatewayTimeout
	}

	if re := responseErr(msg); re != nil {
		fmt.Println(re.Error)
		return re.HTTPError
	}

	return c.String(http.StatusOK, "")
}
<|endoftext|>


<commit_before>package consul

import (
	"fmt"
	"io"
	"log"
	"os"
	"strconv"
	"sync"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/agent/pool"
	"github.com/hashicorp/consul/agent/router"
	"github.com/hashicorp/consul/agent/structs"
	"github.com/hashicorp/consul/lib"
	"github.com/hashicorp/serf/serf"
	"golang.org/x/time/rate"
)

const (
	// clientRPCConnMaxIdle controls how long we keep an idle connection
	// open to a server.  127s was chosen as the first prime above 120s
	// (arbitrarily chose to use a prime) with the intent of reusing
	// connections who are used by once-a-minute cron(8) jobs *and* who
	// use a 60s jitter window (e.g. in vixie cron job execution can
	// drift by up to 59s per job, or 119s for a once-a-minute cron job).
	clientRPCConnMaxIdle = 127 * time.Second

	// clientMaxStreams controls how many idle streams we keep
	// open to a server
	clientMaxStreams = 32

	// serfEventBacklog is the maximum number of unprocessed Serf Events
	// that will be held in queue before new serf events block.  A
	// blocking serf event queue is a bad thing.
	serfEventBacklog = 256

	// serfEventBacklogWarning is the threshold at which point log
	// warnings will be emitted indicating a problem when processing serf
	// events.
	serfEventBacklogWarning = 200
)

// Client is Consul client which uses RPC to communicate with the
// services for service discovery, health checking, and DC forwarding.
type Client struct {
	config *Config

	// Connection pool to consul servers
	connPool *pool.ConnPool

	// routers is responsible for the selection and maintenance of
	// Consul servers this agent uses for RPC requests
	routers *router.Manager

	// rpcLimiter is used to rate limit the total number of RPCs initiated
	// from an agent.
	rpcLimiter *rate.Limiter

	// eventCh is used to receive events from the
	// serf cluster in the datacenter
	eventCh chan serf.Event

	// Logger uses the provided LogOutput
	logger *log.Logger

	// serf is the Serf cluster maintained inside the DC
	// which contains all the DC nodes
	serf *serf.Serf

	shutdown     bool
	shutdownCh   chan struct{}
	shutdownLock sync.Mutex

	// embedded struct to hold all the enterprise specific data
	EnterpriseClient
}

// NewClient is used to construct a new Consul client from the
// configuration, potentially returning an error
func NewClient(config *Config) (*Client, error) {
	return NewClientLogger(config, nil)
}

func NewClientLogger(config *Config, logger *log.Logger) (*Client, error) {
	// Check the protocol version
	if err := config.CheckProtocolVersion(); err != nil {
		return nil, err
	}

	// Check for a data directory!
	if config.DataDir == "" {
		return nil, fmt.Errorf("Config must provide a DataDir")
	}

	// Sanity check the ACLs
	if err := config.CheckACL(); err != nil {
		return nil, err
	}

	// Ensure we have a log output
	if config.LogOutput == nil {
		config.LogOutput = os.Stderr
	}

	// Create the tls Wrapper
	tlsWrap, err := config.tlsConfig().OutgoingTLSWrapper()
	if err != nil {
		return nil, err
	}

	// Create a logger
	if logger == nil {
		logger = log.New(config.LogOutput, "", log.LstdFlags)
	}

	connPool := &pool.ConnPool{
		SrcAddr:    config.RPCSrcAddr,
		LogOutput:  config.LogOutput,
		MaxTime:    clientRPCConnMaxIdle,
		MaxStreams: clientMaxStreams,
		TLSWrapper: tlsWrap,
		ForceTLS:   config.VerifyOutgoing,
	}

	// Create client
	c := &Client{
		config:     config,
		connPool:   connPool,
		rpcLimiter: rate.NewLimiter(config.RPCRate, config.RPCMaxBurst),
		eventCh:    make(chan serf.Event, serfEventBacklog),
		logger:     logger,
		shutdownCh: make(chan struct{}),
	}

	if err := c.initEnterprise(); err != nil {
		c.Shutdown()
		return nil, err
	}

	// Initialize the LAN Serf
	c.serf, err = c.setupSerf(config.SerfLANConfig,
		c.eventCh, serfLANSnapshot)
	if err != nil {
		c.Shutdown()
		return nil, fmt.Errorf("Failed to start lan serf: %v", err)
	}

	// Start maintenance task for servers
	c.routers = router.New(c.logger, c.shutdownCh, c.serf, c.connPool)
	go c.routers.Start()

	// Start LAN event handlers after the router is complete since the event
	// handlers depend on the router and the router depends on Serf.
	go c.lanEventHandler()

	if err := c.startEnterprise(); err != nil {
		c.Shutdown()
		return nil, err
	}

	return c, nil
}

// Shutdown is used to shutdown the client
func (c *Client) Shutdown() error {
	c.logger.Printf("[INFO] consul: shutting down client")
	c.shutdownLock.Lock()
	defer c.shutdownLock.Unlock()

	if c.shutdown {
		return nil
	}

	c.shutdown = true
	close(c.shutdownCh)

	if c.serf != nil {
		c.serf.Shutdown()
	}

	// Close the connection pool
	c.connPool.Shutdown()
	return nil
}

// Leave is used to prepare for a graceful shutdown
func (c *Client) Leave() error {
	c.logger.Printf("[INFO] consul: client starting leave")

	// Leave the LAN pool
	if c.serf != nil {
		if err := c.serf.Leave(); err != nil {
			c.logger.Printf("[ERR] consul: Failed to leave LAN Serf cluster: %v", err)
		}
	}
	return nil
}

// JoinLAN is used to have Consul client join the inner-DC pool
// The target address should be another node inside the DC
// listening on the Serf LAN address
func (c *Client) JoinLAN(addrs []string) (int, error) {
	return c.serf.Join(addrs, true)
}

// LocalMember is used to return the local node
func (c *Client) LocalMember() serf.Member {
	return c.serf.LocalMember()
}

// LANMembers is used to return the members of the LAN cluster
func (c *Client) LANMembers() []serf.Member {
	return c.serf.Members()
}

// LANMembersAllSegments returns members from all segments.
func (c *Client) LANMembersAllSegments() ([]serf.Member, error) {
	return c.serf.Members(), nil
}

// LANSegmentMembers only returns our own segment's members, because clients
// can't be in multiple segments.
func (c *Client) LANSegmentMembers(segment string) ([]serf.Member, error) {
	if segment == c.config.Segment {
		return c.LANMembers(), nil
	}

	return nil, fmt.Errorf("segment %q not found", segment)
}

// RemoveFailedNode is used to remove a failed node from the cluster
func (c *Client) RemoveFailedNode(node string) error {
	return c.serf.RemoveFailedNode(node)
}

// KeyManagerLAN returns the LAN Serf keyring manager
func (c *Client) KeyManagerLAN() *serf.KeyManager {
	return c.serf.KeyManager()
}

// Encrypted determines if gossip is encrypted
func (c *Client) Encrypted() bool {
	return c.serf.EncryptionEnabled()
}

// RPC is used to forward an RPC call to a consul server, or fail if no servers
func (c *Client) RPC(method string, args interface{}, reply interface{}) error {
	// This is subtle but we start measuring the time on the client side
	// right at the time of the first request, vs. on the first retry as
	// is done on the server side inside forward(). This is because the
	// servers may already be applying the RPCHoldTimeout up there, so by
	// starting the timer here we won't potentially double up the delay.
	// TODO (slackpad) Plumb a deadline here with a context.
	firstCheck := time.Now()

TRY:
	server := c.routers.FindServer()
	if server == nil {
		return structs.ErrNoServers
	}

	// Enforce the RPC limit.
	metrics.IncrCounter([]string{"client", "rpc"}, 1)
	if !c.rpcLimiter.Allow() {
		metrics.IncrCounter([]string{"client", "rpc", "exceeded"}, 1)
		return structs.ErrRPCRateExceeded
	}

	// Make the request.
	rpcErr := c.connPool.RPC(c.config.Datacenter, server.Addr, server.Version, method, server.UseTLS, args, reply)
	if rpcErr == nil {
		return nil
	}

	// Move off to another server, and see if we can retry.
	c.logger.Printf("[ERR] consul: %q RPC failed to server %s: %v", method, server.Addr, rpcErr)
	metrics.IncrCounter([]string{"client", "rpc", "failed"}, 1)
	c.routers.NotifyFailedServer(server)
	if retry := canRetry(args, rpcErr); !retry {
		return rpcErr
	}

	// We can wait a bit and retry!
	if time.Since(firstCheck) < c.config.RPCHoldTimeout {
		jitter := lib.RandomStagger(c.config.RPCHoldTimeout / jitterFraction)
		select {
		case <-time.After(jitter):
			goto TRY
		case <-c.shutdownCh:
		}
	}
	return rpcErr
}

// SnapshotRPC sends the snapshot request to one of the servers, reading from
// the streaming input and writing to the streaming output depending on the
// operation.
func (c *Client) SnapshotRPC(args *structs.SnapshotRequest, in io.Reader, out io.Writer,
	replyFn structs.SnapshotReplyFn) error {
	server := c.routers.FindServer()
	if server == nil {
		return structs.ErrNoServers
	}

	// Enforce the RPC limit.
	metrics.IncrCounter([]string{"client", "rpc"}, 1)
	if !c.rpcLimiter.Allow() {
		metrics.IncrCounter([]string{"client", "rpc", "exceeded"}, 1)
		return structs.ErrRPCRateExceeded
	}

	// Request the operation.
	var reply structs.SnapshotResponse
	snap, err := SnapshotRPC(c.connPool, c.config.Datacenter, server.Addr, server.UseTLS, args, in, &reply)
	if err != nil {
		return err
	}
	defer func() {
		if err := snap.Close(); err != nil {
			c.logger.Printf("[WARN] consul: Failed closing snapshot stream: %v", err)
		}
	}()

	// Let the caller peek at the reply.
	if replyFn != nil {
		if err := replyFn(&reply); err != nil {
			return nil
		}
	}

	// Stream the snapshot.
	if out != nil {
		if _, err := io.Copy(out, snap); err != nil {
			return fmt.Errorf("failed to stream snapshot: %v", err)
		}
	}

	return nil
}

// Stats is used to return statistics for debugging and insight
// for various sub-systems
func (c *Client) Stats() map[string]map[string]string {
	numServers := c.routers.NumServers()

	toString := func(v uint64) string {
		return strconv.FormatUint(v, 10)
	}
	stats := map[string]map[string]string{
		"consul": map[string]string{
			"server":        "false",
			"known_servers": toString(uint64(numServers)),
		},
		"serf_lan": c.serf.Stats(),
		"runtime":  runtimeStats(),
	}

	for outerKey, outerValue := range c.enterpriseStats() {
		if _, ok := stats[outerKey]; ok {
			for innerKey, innerValue := range outerValue {
				stats[outerKey][innerKey] = innerValue
			}
		} else {
			stats[outerKey] = outerValue
		}
	}

	return stats
}

// GetLANCoordinate returns the network coordinate of the current node, as
// maintained by Serf.
func (c *Client) GetLANCoordinate() (lib.CoordinateSet, error) {
	lan, err := c.serf.GetCoordinate()
	if err != nil {
		return nil, err
	}

	cs := lib.CoordinateSet{c.config.Segment: lan}
	return cs, nil
}
<commit_msg>Attach server.ID label to client.rpc.failed<commit_after>package consul

import (
	"fmt"
	"io"
	"log"
	"os"
	"strconv"
	"sync"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/agent/pool"
	"github.com/hashicorp/consul/agent/router"
	"github.com/hashicorp/consul/agent/structs"
	"github.com/hashicorp/consul/lib"
	"github.com/hashicorp/serf/serf"
	"golang.org/x/time/rate"
)

const (
	// clientRPCConnMaxIdle controls how long we keep an idle connection
	// open to a server.  127s was chosen as the first prime above 120s
	// (arbitrarily chose to use a prime) with the intent of reusing
	// connections who are used by once-a-minute cron(8) jobs *and* who
	// use a 60s jitter window (e.g. in vixie cron job execution can
	// drift by up to 59s per job, or 119s for a once-a-minute cron job).
	clientRPCConnMaxIdle = 127 * time.Second

	// clientMaxStreams controls how many idle streams we keep
	// open to a server
	clientMaxStreams = 32

	// serfEventBacklog is the maximum number of unprocessed Serf Events
	// that will be held in queue before new serf events block.  A
	// blocking serf event queue is a bad thing.
	serfEventBacklog = 256

	// serfEventBacklogWarning is the threshold at which point log
	// warnings will be emitted indicating a problem when processing serf
	// events.
	serfEventBacklogWarning = 200
)

// Client is Consul client which uses RPC to communicate with the
// services for service discovery, health checking, and DC forwarding.
type Client struct {
	config *Config

	// Connection pool to consul servers
	connPool *pool.ConnPool

	// routers is responsible for the selection and maintenance of
	// Consul servers this agent uses for RPC requests
	routers *router.Manager

	// rpcLimiter is used to rate limit the total number of RPCs initiated
	// from an agent.
	rpcLimiter *rate.Limiter

	// eventCh is used to receive events from the
	// serf cluster in the datacenter
	eventCh chan serf.Event

	// Logger uses the provided LogOutput
	logger *log.Logger

	// serf is the Serf cluster maintained inside the DC
	// which contains all the DC nodes
	serf *serf.Serf

	shutdown     bool
	shutdownCh   chan struct{}
	shutdownLock sync.Mutex

	// embedded struct to hold all the enterprise specific data
	EnterpriseClient
}

// NewClient is used to construct a new Consul client from the
// configuration, potentially returning an error
func NewClient(config *Config) (*Client, error) {
	return NewClientLogger(config, nil)
}

func NewClientLogger(config *Config, logger *log.Logger) (*Client, error) {
	// Check the protocol version
	if err := config.CheckProtocolVersion(); err != nil {
		return nil, err
	}

	// Check for a data directory!
	if config.DataDir == "" {
		return nil, fmt.Errorf("Config must provide a DataDir")
	}

	// Sanity check the ACLs
	if err := config.CheckACL(); err != nil {
		return nil, err
	}

	// Ensure we have a log output
	if config.LogOutput == nil {
		config.LogOutput = os.Stderr
	}

	// Create the tls Wrapper
	tlsWrap, err := config.tlsConfig().OutgoingTLSWrapper()
	if err != nil {
		return nil, err
	}

	// Create a logger
	if logger == nil {
		logger = log.New(config.LogOutput, "", log.LstdFlags)
	}

	connPool := &pool.ConnPool{
		SrcAddr:    config.RPCSrcAddr,
		LogOutput:  config.LogOutput,
		MaxTime:    clientRPCConnMaxIdle,
		MaxStreams: clientMaxStreams,
		TLSWrapper: tlsWrap,
		ForceTLS:   config.VerifyOutgoing,
	}

	// Create client
	c := &Client{
		config:     config,
		connPool:   connPool,
		rpcLimiter: rate.NewLimiter(config.RPCRate, config.RPCMaxBurst),
		eventCh:    make(chan serf.Event, serfEventBacklog),
		logger:     logger,
		shutdownCh: make(chan struct{}),
	}

	if err := c.initEnterprise(); err != nil {
		c.Shutdown()
		return nil, err
	}

	// Initialize the LAN Serf
	c.serf, err = c.setupSerf(config.SerfLANConfig,
		c.eventCh, serfLANSnapshot)
	if err != nil {
		c.Shutdown()
		return nil, fmt.Errorf("Failed to start lan serf: %v", err)
	}

	// Start maintenance task for servers
	c.routers = router.New(c.logger, c.shutdownCh, c.serf, c.connPool)
	go c.routers.Start()

	// Start LAN event handlers after the router is complete since the event
	// handlers depend on the router and the router depends on Serf.
	go c.lanEventHandler()

	if err := c.startEnterprise(); err != nil {
		c.Shutdown()
		return nil, err
	}

	return c, nil
}

// Shutdown is used to shutdown the client
func (c *Client) Shutdown() error {
	c.logger.Printf("[INFO] consul: shutting down client")
	c.shutdownLock.Lock()
	defer c.shutdownLock.Unlock()

	if c.shutdown {
		return nil
	}

	c.shutdown = true
	close(c.shutdownCh)

	if c.serf != nil {
		c.serf.Shutdown()
	}

	// Close the connection pool
	c.connPool.Shutdown()
	return nil
}

// Leave is used to prepare for a graceful shutdown
func (c *Client) Leave() error {
	c.logger.Printf("[INFO] consul: client starting leave")

	// Leave the LAN pool
	if c.serf != nil {
		if err := c.serf.Leave(); err != nil {
			c.logger.Printf("[ERR] consul: Failed to leave LAN Serf cluster: %v", err)
		}
	}
	return nil
}

// JoinLAN is used to have Consul client join the inner-DC pool
// The target address should be another node inside the DC
// listening on the Serf LAN address
func (c *Client) JoinLAN(addrs []string) (int, error) {
	return c.serf.Join(addrs, true)
}

// LocalMember is used to return the local node
func (c *Client) LocalMember() serf.Member {
	return c.serf.LocalMember()
}

// LANMembers is used to return the members of the LAN cluster
func (c *Client) LANMembers() []serf.Member {
	return c.serf.Members()
}

// LANMembersAllSegments returns members from all segments.
func (c *Client) LANMembersAllSegments() ([]serf.Member, error) {
	return c.serf.Members(), nil
}

// LANSegmentMembers only returns our own segment's members, because clients
// can't be in multiple segments.
func (c *Client) LANSegmentMembers(segment string) ([]serf.Member, error) {
	if segment == c.config.Segment {
		return c.LANMembers(), nil
	}

	return nil, fmt.Errorf("segment %q not found", segment)
}

// RemoveFailedNode is used to remove a failed node from the cluster
func (c *Client) RemoveFailedNode(node string) error {
	return c.serf.RemoveFailedNode(node)
}

// KeyManagerLAN returns the LAN Serf keyring manager
func (c *Client) KeyManagerLAN() *serf.KeyManager {
	return c.serf.KeyManager()
}

// Encrypted determines if gossip is encrypted
func (c *Client) Encrypted() bool {
	return c.serf.EncryptionEnabled()
}

// RPC is used to forward an RPC call to a consul server, or fail if no servers
func (c *Client) RPC(method string, args interface{}, reply interface{}) error {
	// This is subtle but we start measuring the time on the client side
	// right at the time of the first request, vs. on the first retry as
	// is done on the server side inside forward(). This is because the
	// servers may already be applying the RPCHoldTimeout up there, so by
	// starting the timer here we won't potentially double up the delay.
	// TODO (slackpad) Plumb a deadline here with a context.
	firstCheck := time.Now()

TRY:
	server := c.routers.FindServer()
	if server == nil {
		return structs.ErrNoServers
	}

	// Enforce the RPC limit.
	metrics.IncrCounter([]string{"client", "rpc"}, 1)
	if !c.rpcLimiter.Allow() {
		metrics.IncrCounter([]string{"client", "rpc", "exceeded"}, 1)
		return structs.ErrRPCRateExceeded
	}

	// Make the request.
	rpcErr := c.connPool.RPC(c.config.Datacenter, server.Addr, server.Version, method, server.UseTLS, args, reply)
	if rpcErr == nil {
		return nil
	}

	// Move off to another server, and see if we can retry.
	c.logger.Printf("[ERR] consul: %q RPC failed to server %s: %v", method, server.Addr, rpcErr)
	metrics.IncrCounterWithLabels([]string{"client", "rpc", "failed"}, 1, []metrics.Label{{Name: "server", Value: server.ID}})
	c.routers.NotifyFailedServer(server)
	if retry := canRetry(args, rpcErr); !retry {
		return rpcErr
	}

	// We can wait a bit and retry!
	if time.Since(firstCheck) < c.config.RPCHoldTimeout {
		jitter := lib.RandomStagger(c.config.RPCHoldTimeout / jitterFraction)
		select {
		case <-time.After(jitter):
			goto TRY
		case <-c.shutdownCh:
		}
	}
	return rpcErr
}

// SnapshotRPC sends the snapshot request to one of the servers, reading from
// the streaming input and writing to the streaming output depending on the
// operation.
func (c *Client) SnapshotRPC(args *structs.SnapshotRequest, in io.Reader, out io.Writer,
	replyFn structs.SnapshotReplyFn) error {
	server := c.routers.FindServer()
	if server == nil {
		return structs.ErrNoServers
	}

	// Enforce the RPC limit.
	metrics.IncrCounter([]string{"client", "rpc"}, 1)
	if !c.rpcLimiter.Allow() {
		metrics.IncrCounter([]string{"client", "rpc", "exceeded"}, 1)
		return structs.ErrRPCRateExceeded
	}

	// Request the operation.
	var reply structs.SnapshotResponse
	snap, err := SnapshotRPC(c.connPool, c.config.Datacenter, server.Addr, server.UseTLS, args, in, &reply)
	if err != nil {
		return err
	}
	defer func() {
		if err := snap.Close(); err != nil {
			c.logger.Printf("[WARN] consul: Failed closing snapshot stream: %v", err)
		}
	}()

	// Let the caller peek at the reply.
	if replyFn != nil {
		if err := replyFn(&reply); err != nil {
			return nil
		}
	}

	// Stream the snapshot.
	if out != nil {
		if _, err := io.Copy(out, snap); err != nil {
			return fmt.Errorf("failed to stream snapshot: %v", err)
		}
	}

	return nil
}

// Stats is used to return statistics for debugging and insight
// for various sub-systems
func (c *Client) Stats() map[string]map[string]string {
	numServers := c.routers.NumServers()

	toString := func(v uint64) string {
		return strconv.FormatUint(v, 10)
	}
	stats := map[string]map[string]string{
		"consul": map[string]string{
			"server":        "false",
			"known_servers": toString(uint64(numServers)),
		},
		"serf_lan": c.serf.Stats(),
		"runtime":  runtimeStats(),
	}

	for outerKey, outerValue := range c.enterpriseStats() {
		if _, ok := stats[outerKey]; ok {
			for innerKey, innerValue := range outerValue {
				stats[outerKey][innerKey] = innerValue
			}
		} else {
			stats[outerKey] = outerValue
		}
	}

	return stats
}

// GetLANCoordinate returns the network coordinate of the current node, as
// maintained by Serf.
func (c *Client) GetLANCoordinate() (lib.CoordinateSet, error) {
	lan, err := c.serf.GetCoordinate()
	if err != nil {
		return nil, err
	}

	cs := lib.CoordinateSet{c.config.Segment: lan}
	return cs, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"log"
	"math/big"
	"strings"
	"unicode/utf8"
)

func Abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func RandInt(n int) int {
	if n <= 0 {
		return 0
	}
	x, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
	if err != nil {
		log.Println(err, ":", n)
		return n / 2
	}
	return int(x.Int64())
}

func Min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func Max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func Indefinite(s string, upper bool) (text string) {
	if len(s) > 0 {
		r, _ := utf8.DecodeLastRuneInString(s)
		if r == 's' {
			if upper {
				return strings.ToUpper(s[0:1]) + s[1:]
			}
			return s
		}
		switch s[0] {
		case 'a', 'e', 'i', 'o', 'u':
			if upper {
				text = "An " + s
			} else {
				text = "an " + s
			}
		default:
			if upper {
				text = "A " + s
			} else {
				text = "a " + s
			}
		}
	}
	return text
}

func formatText(text string, width int) string {
	pbuf := bytes.Buffer{}
	wordbuf := bytes.Buffer{}
	col := 0
	wantspace := false
	wlen := 0
	for _, c := range text {
		// it's enough to test with just spaces for now
		//if unicode.IsSpace(c) && c != 0xa0 {
		if c == ' ' {
			if wlen == 0 {
				continue
			}
			if col+wlen > width {
				if wantspace {
					pbuf.WriteRune('\n')
					col = 0
				}
			} else if wantspace {
				pbuf.WriteRune(' ')
				col++
			}
			pbuf.Write(wordbuf.Bytes())
			col += wlen
			wordbuf.Reset()
			wlen = 0
			wantspace = true
			continue
		}
		wordbuf.WriteRune(c)
		wlen++
	}
	if wordbuf.Len() > 0 {
		if wantspace {
			if wlen+col > width {
				pbuf.WriteRune('\n')
			} else {
				pbuf.WriteRune(' ')
			}
		}
		pbuf.Write(wordbuf.Bytes())
	}
	return pbuf.String()
}
<commit_msg>fix correctly singular/plural stuff<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"log"
	"math/big"
	"strings"
)

func Abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func RandInt(n int) int {
	if n <= 0 {
		return 0
	}
	x, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
	if err != nil {
		log.Println(err, ":", n)
		return n / 2
	}
	return int(x.Int64())
}

func Min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func Max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func Indefinite(s string, upper bool) (text string) {
	if len(s) > 0 {
		if s == HarKarGauntlets.String() {
			if upper {
				return strings.ToUpper(s[0:1]) + s[1:]
			}
			return s
		}
		switch s[0] {
		case 'a', 'e', 'i', 'o', 'u':
			if upper {
				text = "An " + s
			} else {
				text = "an " + s
			}
		default:
			if upper {
				text = "A " + s
			} else {
				text = "a " + s
			}
		}
	}
	return text
}

func formatText(text string, width int) string {
	pbuf := bytes.Buffer{}
	wordbuf := bytes.Buffer{}
	col := 0
	wantspace := false
	wlen := 0
	for _, c := range text {
		// it's enough to test with just spaces for now
		//if unicode.IsSpace(c) && c != 0xa0 {
		if c == ' ' {
			if wlen == 0 {
				continue
			}
			if col+wlen > width {
				if wantspace {
					pbuf.WriteRune('\n')
					col = 0
				}
			} else if wantspace {
				pbuf.WriteRune(' ')
				col++
			}
			pbuf.Write(wordbuf.Bytes())
			col += wlen
			wordbuf.Reset()
			wlen = 0
			wantspace = true
			continue
		}
		wordbuf.WriteRune(c)
		wlen++
	}
	if wordbuf.Len() > 0 {
		if wantspace {
			if wlen+col > width {
				pbuf.WriteRune('\n')
			} else {
				pbuf.WriteRune(' ')
			}
		}
		pbuf.Write(wordbuf.Bytes())
	}
	return pbuf.String()
}
<|endoftext|>


<commit_before>// Copyright 2016 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// Package utils 一些常用的函数集合。
package utils

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
)

// MD5 将一段字符串转换成md5编码
func MD5(str string) string {
	m := md5.New()
	m.Write([]byte(str))
	return hex.EncodeToString(m.Sum(nil))
}

// FileExists 判断文件或是文件夹是否存在
func FileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

// TraceStack 返回调用者的堆栈信息
func TraceStack(msg interface{}, level int) ([]byte, error) {
	w := new(bytes.Buffer)
	var err error

	if msg != nil {
		_, err = fmt.Fprintln(w, msg)
		if err != nil {
			return nil, err
		}
	}

	ws := func(str string) {
		if err == nil {
			_, err = w.WriteString(str)
		}
	}

	for i := level; true; i++ {
		_, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}

		ws(file)
		ws(strconv.Itoa(line))
		ws("\n")
	}

	if err != nil {
		return nil, err
	}

	return w.Bytes(), nil
}

// SplitPath 将路径按分隔符分隔成字符串数组。比如：
//  /a/b/c  ==>  []string{"a", "b", "c"}
func SplitPath(path string) []string {
	vol := filepath.VolumeName(path)
	ret := make([]string, 0, 10)

	index := 0
	if len(vol) > 0 {
		ret = append(ret, vol)
		path = path[len(vol)+1:]
	}
	for i := 0; i < len(path); i++ {
		if os.IsPathSeparator(path[i]) {
			if i > index {
				ret = append(ret, path[index:i])
			}
			index = i + 1 // 过滤掉此符号
		}
	} // end for

	if len(path) > index {
		ret = append(ret, path[index:])
	}

	return ret
}
<commit_msg>分隔文件和行号<commit_after>// Copyright 2016 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// Package utils 一些常用的函数集合。
package utils

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
)

// MD5 将一段字符串转换成md5编码
func MD5(str string) string {
	m := md5.New()
	m.Write([]byte(str))
	return hex.EncodeToString(m.Sum(nil))
}

// FileExists 判断文件或是文件夹是否存在
func FileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

// TraceStack 返回调用者的堆栈信息
func TraceStack(msg interface{}, level int) ([]byte, error) {
	w := new(bytes.Buffer)
	var err error

	if msg != nil {
		_, err = fmt.Fprintln(w, msg)
		if err != nil {
			return nil, err
		}
	}

	ws := func(str string) {
		if err == nil {
			_, err = w.WriteString(str)
		}
	}

	for i := level; true; i++ {
		_, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}

		ws(file)
		ws(":")
		ws(strconv.Itoa(line))
		ws("\n")
	}

	if err != nil {
		return nil, err
	}

	return w.Bytes(), nil
}

// SplitPath 将路径按分隔符分隔成字符串数组。比如：
//  /a/b/c  ==>  []string{"a", "b", "c"}
func SplitPath(path string) []string {
	vol := filepath.VolumeName(path)
	ret := make([]string, 0, 10)

	index := 0
	if len(vol) > 0 {
		ret = append(ret, vol)
		path = path[len(vol)+1:]
	}
	for i := 0; i < len(path); i++ {
		if os.IsPathSeparator(path[i]) {
			if i > index {
				ret = append(ret, path[index:i])
			}
			index = i + 1 // 过滤掉此符号
		}
	} // end for

	if len(path) > index {
		ret = append(ret, path[index:])
	}

	return ret
}
<|endoftext|>


<commit_before>package agent

import (
	"errors"
	"fmt"
	"math/rand"
	"sync"
	"testing"

	"github.com/docker/swarmkit/api"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

type uniqueStatus struct {
	taskID string
	status *api.TaskStatus
}

func TestReporter(t *testing.T) {
	const ntasks = 100

	var (
		ctx      = context.Background()
		statuses = make(map[string]*api.TaskStatus) // destination map
		unique   = make(map[uniqueStatus]struct{})  // ensure we don't receive any status twice
		mu       sync.Mutex
		expected = make(map[string]*api.TaskStatus)
		wg       sync.WaitGroup
	)

	reporter := newStatusReporter(ctx, statusReporterFunc(func(ctx context.Context, taskID string, status *api.TaskStatus) error {
		if rand.Float64() > 0.9 {
			return errors.New("status send failed")
		}

		mu.Lock()
		defer mu.Unlock()

		key := uniqueStatus{taskID, status}
		// make sure we get the status only once.
		if _, ok := unique[key]; ok {
			t.Fatalf("encountered status twice")
		}

		if status.State == api.TaskStateCompleted {
			wg.Done()
		}

		unique[key] = struct{}{}
		if current, ok := statuses[taskID]; ok {
			if status.State <= current.State {
				return nil // only allow forward updates
			}
		}

		statuses[taskID] = status

		return nil
	}))

	wg.Add(ntasks) // statuses will be reported!

	for _, state := range []api.TaskState{
		api.TaskStateAccepted,
		api.TaskStatePreparing,
		api.TaskStateReady,
		api.TaskStateCompleted,
	} {
		for i := 0; i < ntasks; i++ {
			taskID, status := fmt.Sprint(i), &api.TaskStatus{State: state}
			expected[taskID] = status

			// simulate pounding this with a bunch of goroutines
			go func() {
				if err := reporter.UpdateTaskStatus(ctx, taskID, status); err != nil {
					t.Fatalf("sending should not fail: %v", err)
				}
			}()

		}
	}

	wg.Wait() // wait for the propagation
	assert.NoError(t, reporter.Close())
	mu.Lock()
	defer mu.Unlock()

	assert.Equal(t, expected, statuses)
}
<commit_msg>agent: do not call Fatalf in goroutine<commit_after>package agent

import (
	"errors"
	"fmt"
	"math/rand"
	"sync"
	"testing"

	"github.com/docker/swarmkit/api"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

type uniqueStatus struct {
	taskID string
	status *api.TaskStatus
}

func TestReporter(t *testing.T) {
	const ntasks = 100

	var (
		ctx      = context.Background()
		statuses = make(map[string]*api.TaskStatus) // destination map
		unique   = make(map[uniqueStatus]struct{})  // ensure we don't receive any status twice
		mu       sync.Mutex
		expected = make(map[string]*api.TaskStatus)
		wg       sync.WaitGroup
	)

	reporter := newStatusReporter(ctx, statusReporterFunc(func(ctx context.Context, taskID string, status *api.TaskStatus) error {
		if rand.Float64() > 0.9 {
			return errors.New("status send failed")
		}

		mu.Lock()
		defer mu.Unlock()

		key := uniqueStatus{taskID, status}
		// make sure we get the status only once.
		if _, ok := unique[key]; ok {
			t.Fatalf("encountered status twice")
		}

		if status.State == api.TaskStateCompleted {
			wg.Done()
		}

		unique[key] = struct{}{}
		if current, ok := statuses[taskID]; ok {
			if status.State <= current.State {
				return nil // only allow forward updates
			}
		}

		statuses[taskID] = status

		return nil
	}))

	wg.Add(ntasks) // statuses will be reported!

	for _, state := range []api.TaskState{
		api.TaskStateAccepted,
		api.TaskStatePreparing,
		api.TaskStateReady,
		api.TaskStateCompleted,
	} {
		for i := 0; i < ntasks; i++ {
			taskID, status := fmt.Sprint(i), &api.TaskStatus{State: state}
			expected[taskID] = status

			// simulate pounding this with a bunch of goroutines
			go func() {
				if err := reporter.UpdateTaskStatus(ctx, taskID, status); err != nil {
					assert.NoError(t, err, "sending should not fail")
				}
			}()

		}
	}

	wg.Wait() // wait for the propagation
	assert.NoError(t, reporter.Close())
	mu.Lock()
	defer mu.Unlock()

	assert.Equal(t, expected, statuses)
}
<|endoftext|>