<commit_before>package cb

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

	"github.com/couchbase/go-couchbase"
)

var (
	cbb                       *couchbase.Bucket
	n1ql                      *http.Client
	queryURL, scanConsistency string
)

// InitDatabase initializes Couchbase Server client and HTTP client for N1QL
// queries.
func InitDatabase(hostname string, consistency string) error {
	baseURL := fmt.Sprintf("http://%s:8091/", hostname)

	c, err := couchbase.ConnectWithAuthCreds(baseURL, "default", "")
	if err != nil {
		return err
	}

	pool, err := c.GetPool("default")
	if err != nil {
		return err
	}

	cbb, err = pool.GetBucket("default")
	if err != nil {
		return err
	}

	t := &http.Transport{MaxIdleConnsPerHost: 10240}
	n1ql = &http.Client{Transport: t}

	queryURL = fmt.Sprintf("http://%s:8093/query", hostname)

	scanConsistency = consistency

	return nil
}

// Insert adds new documents to Couchbase Server bucket using SET operation.
func Insert(_ int64, key string, value interface{}) error {
	return cbb.Set(key, 0, value)
}

type n1qlQuery struct {
	Prepared        string        `json:"prepared"`
	Args            []interface{} `json:"args"`
	ScanConsistency string        `json:"scan_consistency"`
}

func executeQuery(q *n1qlQuery) error {
	b, err := json.Marshal(q)
	if err != nil {
		return err
	}
	j := bytes.NewReader(b)

	resp, err := n1ql.Post(queryURL, "application/json", j)
	defer resp.Body.Close()

	if err != nil {
		return err
	}

	if _, err = ioutil.ReadAll(resp.Body); err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		return errors.New("bad response")
	}

	return nil
}

// Query finds matching documents using prepared N1QL statements.
func Query(_ int64, field string, arg interface{}) error {
	// FIXME: support different queries and multiple arguments
	q := n1qlQuery{"by_" + field, []interface{}{arg}, scanConsistency}

	return executeQuery(&q)
}
<commit_msg>Use "/query/service" endpoint instead of "/query"<commit_after>package cb

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

	"github.com/couchbase/go-couchbase"
)

const (
	bucketName = "default"
)

var (
	cbb                       *couchbase.Bucket
	n1ql                      *http.Client
	queryURL, scanConsistency string
)

// InitDatabase initializes Couchbase Server client and HTTP client for N1QL
// queries.
func InitDatabase(hostname string, consistency string) error {
	baseURL := fmt.Sprintf("http://%s:8091/", hostname)

	c, err := couchbase.ConnectWithAuthCreds(baseURL, "default", "")
	if err != nil {
		return err
	}

	pool, err := c.GetPool("default")
	if err != nil {
		return err
	}

	cbb, err = pool.GetBucket(bucketName)
	if err != nil {
		return err
	}

	t := &http.Transport{MaxIdleConnsPerHost: 10240}
	n1ql = &http.Client{Transport: t}

	queryURL = fmt.Sprintf("http://%s:8093/query/service", hostname)

	scanConsistency = consistency

	return nil
}

// Insert adds new documents to Couchbase Server bucket using SET operation.
func Insert(_ int64, key string, value interface{}) error {
	return cbb.Set(key, 0, value)
}

type n1qlQuery struct {
	Prepared        string        `json:"prepared"`
	Args            []interface{} `json:"args"`
	ScanConsistency string        `json:"scan_consistency"`
}

func executeQuery(q *n1qlQuery) error {
	b, err := json.Marshal(q)
	if err != nil {
		return err
	}
	j := bytes.NewReader(b)

	resp, err := n1ql.Post(queryURL, "application/json", j)
	defer resp.Body.Close()

	if err != nil {
		return err
	}

	if _, err = ioutil.ReadAll(resp.Body); err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		return errors.New("bad response")
	}

	return nil
}

// Query finds matching documents using prepared N1QL statements.
func Query(_ int64, field string, arg interface{}) error {
	// FIXME: support different queries and multiple arguments
	q := n1qlQuery{"by_" + field, []interface{}{arg}, scanConsistency}

	return executeQuery(&q)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/gcfg"
	"database/sql"
	"flag"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/streadway/amqp"
	"log"
	"net/http"
	"strconv"
	"time"
)

var (
	debugging = flag.Bool("d", false, "turn on debug messages")
	cfg       struct {
		DB struct {
			Driver string
			Dsn    string
			Table  string
		}
		RabbitMQ struct {
			Uri      string
			Exchange string
		}
		HTTP struct {
			Host string
			Port string
		}
	}

	db      *sql.DB
	broker  *amqp.Connection
	channel *amqp.Channel
	wakeUp  = make(chan int, 1)
)

type Job struct {
	routingKey string
	body       string
	interval   uint // Seconds
	nextRun    time.Time
	state      string
}

func debug(args ...interface{}) {
	if *debugging {
		log.Println(args...)
	}
}

// hadleSchedule is the web server endpoint for path: /schedule
func handleSchedule(w http.ResponseWriter, r *http.Request) {
	routingKey, body, interval_s :=
		r.FormValue("routing_key"), r.FormValue("body"), r.FormValue("interval")
	debug("/schedule", routingKey, body)

	interval, err := strconv.ParseInt(interval_s, 10, 64)
	if err != nil {
		panic(err)
	}

	next_run := time.Now().UTC().Add(time.Duration(interval) * time.Second)
	_, err = db.Exec("INSERT INTO "+cfg.DB.Table+" "+
		"(routing_key, body, `interval`, next_run, state) "+
		"VALUES(?, ?, ?, ?, 'WAITING') "+
		"ON DUPLICATE KEY UPDATE `interval`=?",
		routingKey, body, interval, next_run, interval)
	if err != nil {
		panic(err)
	}

	// Wake up the publisher.
	//
	// publisher() may be sleeping for the next job on the queue
	// at the time we schedule a new Job. Let it wake up so it can
	// re-fetch the new Job from the front of the queue.
	//
	// The code below is an idiom for non-blocking send to a channel.
	select {
	case wakeUp <- 1:
		debug("Sent wakeup signal")
	default:
		debug("Skipped wakeup signal")
	}
}

// handleCancel is the web server endpoint for path: /cancel
func handleCancel(w http.ResponseWriter, r *http.Request) {
	routingKey, body := r.FormValue("routing_key"), r.FormValue("body")
	debug("/cancel", routingKey, body)

	_, err := db.Exec("DELETE FROM "+cfg.DB.Table+" "+
		"WHERE routing_key=? AND body=?", routingKey, body)
	if err != nil {
		panic(err)
	}
}

// front returns the first job to be run in the queue.
func front() (*Job, error) {
	j := Job{}
	row := db.QueryRow("SELECT routing_key, body, `interval`, next_run, state " +
		"FROM " + cfg.DB.Table + " " +
		"WHERE next_run = (" +
		"SELECT MIN(next_run) FROM " + cfg.DB.Table + ")")
	err := row.Scan(&j.routingKey, &j.body, &j.interval, &j.nextRun, &j.state)
	if err != nil {
		return nil, err
	}
	return &j, nil
}

// Delete deletes the Job j from the queue.
func (j *Job) Delete() error {
	_, err := db.Exec("DELETE FROM "+cfg.DB.Table+" "+
		"WHERE routing_key=? AND body=?",
		j.routingKey, j.body)
	if err != nil {
		return err
	}
	return nil
}

// Publish sends a message to exchange defined in the config and
// updates the Job's state to RUNNING on the database.
func (j *Job) Publish() error {
	debug("publish", *j)

	// Send a message to the broker
	err := channel.Publish(cfg.RabbitMQ.Exchange, j.routingKey, false, false, amqp.Publishing{
		Headers: amqp.Table{
			"interval":     j.interval,
			"published_at": time.Now().UTC(),
		},
		ContentType:     "application/octet-stream",
		ContentEncoding: "",
		Body:            []byte(j.body),
		DeliveryMode:    amqp.Persistent,
		Priority:        0,
	})
	if err != nil {
		return err
	}

	// Update state from database
	_, err = db.Exec("UPDATE "+cfg.DB.Table+" "+
		"SET state=RUNNING "+
		"WHERE routing_key=? AND body=?",
		j.routingKey, j.body)
	if err != nil {
		return err
	}
	return nil
}

// Remaining returns the duration until the job's next scheduled time.
func (j *Job) Remaining() time.Duration {
	return -time.Since(j.nextRun)
}

// publisher runs a loop that reads the next Job from the queue and publishes it.
func publisher() {
	for {
		job, err := front()
		if err != nil {
			fmt.Println(err)
			debug("Waiting wakeup signal")
			<-wakeUp
			debug("Got wakeup signal")
			continue
		}
		debug("Next job:", job, "Remaining:", job.Remaining())

		now := time.Now().UTC()
		if job.nextRun.After(now) {
			// Wait until the next Job time or
			// the webserver's /schedule handler wakes us up
			select {
			case <-time.After(job.Remaining()):
			case <-wakeUp:
				continue
			}
		} else {
			// It's time to publish the Job
			job.Publish()
			err = job.Delete()
			if err != nil {
				log.Println(err)
			}
		}

	}
}

func main() {
	flag.Parse()

	// Read config
	err := gcfg.ReadFileInto(&cfg, "dalga.ini")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Read config: ", cfg)

	// Connect to database
	db, err = sql.Open(cfg.DB.Driver, cfg.DB.Dsn)
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Connected to DB")

	// Connect to RabbitMQ
	broker, err = amqp.Dial(cfg.RabbitMQ.Uri)
	if err != nil {
		log.Fatal(err)
	}
	channel, err = broker.Channel()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Connected to RabbitMQ")

	// Run publisher
	go publisher()

	// Start HTTP server
	addr := cfg.HTTP.Host + ":" + cfg.HTTP.Port
	http.HandleFunc("/schedule", handleSchedule)
	http.HandleFunc("/cancel", handleCancel)
	http.ListenAndServe(addr, nil)
}
<commit_msg>add more debug messages<commit_after>package main

import (
	"code.google.com/p/gcfg"
	"database/sql"
	"flag"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/streadway/amqp"
	"log"
	"net/http"
	"strconv"
	"time"
)

var (
	debugging = flag.Bool("d", false, "turn on debug messages")
	cfg       struct {
		DB struct {
			Driver string
			Dsn    string
			Table  string
		}
		RabbitMQ struct {
			Uri      string
			Exchange string
		}
		HTTP struct {
			Host string
			Port string
		}
	}

	db      *sql.DB
	broker  *amqp.Connection
	channel *amqp.Channel
	wakeUp  = make(chan int, 1)
)

type Job struct {
	routingKey string
	body       string
	interval   uint // Seconds
	nextRun    time.Time
	state      string
}

func debug(args ...interface{}) {
	if *debugging {
		log.Println(args...)
	}
}

// hadleSchedule is the web server endpoint for path: /schedule
func handleSchedule(w http.ResponseWriter, r *http.Request) {
	routingKey, body, interval_s :=
		r.FormValue("routing_key"), r.FormValue("body"), r.FormValue("interval")
	debug("/schedule", routingKey, body)

	interval, err := strconv.ParseInt(interval_s, 10, 64)
	if err != nil {
		panic(err)
	}

	next_run := time.Now().UTC().Add(time.Duration(interval) * time.Second)
	_, err = db.Exec("INSERT INTO "+cfg.DB.Table+" "+
		"(routing_key, body, `interval`, next_run, state) "+
		"VALUES(?, ?, ?, ?, 'WAITING') "+
		"ON DUPLICATE KEY UPDATE `interval`=?",
		routingKey, body, interval, next_run, interval)
	if err != nil {
		panic(err)
	}

	// Wake up the publisher.
	//
	// publisher() may be sleeping for the next job on the queue
	// at the time we schedule a new Job. Let it wake up so it can
	// re-fetch the new Job from the front of the queue.
	//
	// The code below is an idiom for non-blocking send to a channel.
	select {
	case wakeUp <- 1:
		debug("Sent wakeup signal")
	default:
		debug("Skipped wakeup signal")
	}
}

// handleCancel is the web server endpoint for path: /cancel
func handleCancel(w http.ResponseWriter, r *http.Request) {
	routingKey, body := r.FormValue("routing_key"), r.FormValue("body")
	debug("/cancel", routingKey, body)

	_, err := db.Exec("DELETE FROM "+cfg.DB.Table+" "+
		"WHERE routing_key=? AND body=?", routingKey, body)
	if err != nil {
		panic(err)
	}
}

// front returns the first job to be run in the queue.
func front() (*Job, error) {
	j := Job{}
	row := db.QueryRow("SELECT routing_key, body, `interval`, next_run, state " +
		"FROM " + cfg.DB.Table + " " +
		"WHERE next_run = (" +
		"SELECT MIN(next_run) FROM " + cfg.DB.Table + ")")
	err := row.Scan(&j.routingKey, &j.body, &j.interval, &j.nextRun, &j.state)
	if err != nil {
		return nil, err
	}
	return &j, nil
}

// Delete deletes the Job j from the queue.
func (j *Job) Delete() error {
	_, err := db.Exec("DELETE FROM "+cfg.DB.Table+" "+
		"WHERE routing_key=? AND body=?",
		j.routingKey, j.body)
	if err != nil {
		return err
	}
	return nil
}

// Publish sends a message to exchange defined in the config and
// updates the Job's state to RUNNING on the database.
func (j *Job) Publish() error {
	debug("publish", *j)

	// Send a message to the broker
	err := channel.Publish(cfg.RabbitMQ.Exchange, j.routingKey, false, false, amqp.Publishing{
		Headers: amqp.Table{
			"interval":     j.interval,
			"published_at": time.Now().UTC(),
		},
		ContentType:     "application/octet-stream",
		ContentEncoding: "",
		Body:            []byte(j.body),
		DeliveryMode:    amqp.Persistent,
		Priority:        0,
	})
	if err != nil {
		return err
	}

	// Update state from database
	_, err = db.Exec("UPDATE "+cfg.DB.Table+" "+
		"SET state=RUNNING "+
		"WHERE routing_key=? AND body=?",
		j.routingKey, j.body)
	if err != nil {
		return err
	}
	return nil
}

// Remaining returns the duration until the job's next scheduled time.
func (j *Job) Remaining() time.Duration {
	return -time.Since(j.nextRun)
}

// publisher runs a loop that reads the next Job from the queue and publishes it.
func publisher() {
	for {
		job, err := front()
		if err != nil {
			fmt.Println(err)
			debug("Waiting wakeup signal")
			<-wakeUp
			debug("Got wakeup signal")
			continue
		}
		debug("Next job:", job, "Remaining:", job.Remaining())

		now := time.Now().UTC()
		if job.nextRun.After(now) {
			// Wait until the next Job time or
			// the webserver's /schedule handler wakes us up
			debug("Sleeping for job:", job.Remaining())
			select {
			case <-time.After(job.Remaining()):
				debug("Job sleep time finished")
			case <-wakeUp:
				debug("Woke up by webserver")
				continue
			}
		} else {
			// It's time to publish the Job
			job.Publish()
			err = job.Delete()
			if err != nil {
				log.Println(err)
			}
		}

	}
}

func main() {
	flag.Parse()

	// Read config
	err := gcfg.ReadFileInto(&cfg, "dalga.ini")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Read config: ", cfg)

	// Connect to database
	db, err = sql.Open(cfg.DB.Driver, cfg.DB.Dsn)
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Connected to DB")

	// Connect to RabbitMQ
	broker, err = amqp.Dial(cfg.RabbitMQ.Uri)
	if err != nil {
		log.Fatal(err)
	}
	channel, err = broker.Channel()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Connected to RabbitMQ")

	// Run publisher
	go publisher()

	// Start HTTP server
	addr := cfg.HTTP.Host + ":" + cfg.HTTP.Port
	http.HandleFunc("/schedule", handleSchedule)
	http.HandleFunc("/cancel", handleCancel)
	http.ListenAndServe(addr, nil)
}
<|endoftext|>


<commit_before>package slack

import (
	"context"
	"errors"
	"fmt"
	"net/url"
)

type adminResponse struct {
	OK    bool   `json:"ok"`
	Error string `json:"error"`
}

func adminRequest(ctx context.Context, client httpClient, method string, teamName string, values url.Values, d debug) (*adminResponse, error) {
	adminResponse := &adminResponse{}
	err := parseAdminResponse(ctx, client, method, teamName, values, adminResponse, d)
	if err != nil {
		return nil, err
	}

	if !adminResponse.OK {
		return nil, errors.New(adminResponse.Error)
	}

	return adminResponse, nil
}

// DisableUser disabled a user account, given a user ID
func (api *Client) DisableUser(teamName string, uid string) error {
	return api.DisableUserContext(context.Background(), teamName, uid)
}

// DisableUserContext disabled a user account, given a user ID with a custom context
func (api *Client) DisableUserContext(ctx context.Context, teamName string, uid string) error {
	values := url.Values{
		"user":       {uid},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setInactive", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to disable user with id '%s': %s", uid, err)
	}

	return nil
}

// InviteGuest invites a user to Slack as a single-channel guest
func (api *Client) InviteGuest(teamName, channel, firstName, lastName, emailAddress string) error {
	return api.InviteGuestContext(context.Background(), teamName, channel, firstName, lastName, emailAddress)
}

// InviteGuestContext invites a user to Slack as a single-channel guest with a custom context
func (api *Client) InviteGuestContext(ctx context.Context, teamName, channel, firstName, lastName, emailAddress string) error {
	values := url.Values{
		"email":            {emailAddress},
		"channels":         {channel},
		"first_name":       {firstName},
		"last_name":        {lastName},
		"ultra_restricted": {"1"},
		"token":            {api.token},
		"resend":           {"true"},
		"set_active":       {"true"},
		"_attempts":        {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to invite single-channel guest: %s", err)
	}

	return nil
}

// InviteRestricted invites a user to Slack as a restricted account
func (api *Client) InviteRestricted(teamName, channel, firstName, lastName, emailAddress string) error {
	return api.InviteRestrictedContext(context.Background(), teamName, channel, firstName, lastName, emailAddress)
}

// InviteRestrictedContext invites a user to Slack as a restricted account with a custom context
func (api *Client) InviteRestrictedContext(ctx context.Context, teamName, channel, firstName, lastName, emailAddress string) error {
	values := url.Values{
		"email":      {emailAddress},
		"channels":   {channel},
		"first_name": {firstName},
		"last_name":  {lastName},
		"restricted": {"1"},
		"token":      {api.token},
		"resend":     {"true"},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to restricted account: %s", err)
	}

	return nil
}

// InviteToTeam invites a user to a Slack team
func (api *Client) InviteToTeam(teamName, firstName, lastName, emailAddress string) error {
	return api.InviteToTeamContext(context.Background(), teamName, firstName, lastName, emailAddress)
}

// InviteToTeamContext invites a user to a Slack team with a custom context
func (api *Client) InviteToTeamContext(ctx context.Context, teamName, firstName, lastName, emailAddress string) error {
	values := url.Values{
		"email":      {emailAddress},
		"first_name": {firstName},
		"last_name":  {lastName},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to invite to team: %s", err)
	}

	return nil
}

// SetRegular enables the specified user
func (api *Client) SetRegular(teamName, user string) error {
	return api.SetRegularContext(context.Background(), teamName, user)
}

// SetRegularContext enables the specified user with a custom context
func (api *Client) SetRegularContext(ctx context.Context, teamName, user string) error {
	values := url.Values{
		"user":       {user},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setRegular", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to change the user (%s) to a regular user: %s", user, err)
	}

	return nil
}

// SendSSOBindingEmail sends an SSO binding email to the specified user
func (api *Client) SendSSOBindingEmail(teamName, user string) error {
	return api.SendSSOBindingEmailContext(context.Background(), teamName, user)
}

// SendSSOBindingEmailContext sends an SSO binding email to the specified user with a custom context
func (api *Client) SendSSOBindingEmailContext(ctx context.Context, teamName, user string) error {
	values := url.Values{
		"user":       {user},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "sendSSOBind", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to send SSO binding email for user (%s): %s", user, err)
	}

	return nil
}

// SetUltraRestricted converts a user into a single-channel guest
func (api *Client) SetUltraRestricted(teamName, uid, channel string) error {
	return api.SetUltraRestrictedContext(context.Background(), teamName, uid, channel)
}

// SetUltraRestrictedContext converts a user into a single-channel guest with a custom context
func (api *Client) SetUltraRestrictedContext(ctx context.Context, teamName, uid, channel string) error {
	values := url.Values{
		"user":       {uid},
		"channel":    {channel},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setUltraRestricted", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to ultra-restrict account: %s", err)
	}

	return nil
}

// SetRestricted converts a user into a restricted account
func (api *Client) SetRestricted(teamName, uid string) error {
	return api.SetRestrictedContext(context.Background(), teamName, uid)
}

// SetRestrictedContext converts a user into a restricted account with a custom context
func (api *Client) SetRestrictedContext(ctx context.Context, teamName, uid string) error {
	values := url.Values{
		"user":       {uid},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setRestricted", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to restrict account: %s", err)
	}

	return nil
}
<commit_msg>Add missing 'channels' field for setRestricted<commit_after>package slack

import (
	"context"
	"errors"
	"fmt"
	"net/url"
	"strings"
)

type adminResponse struct {
	OK    bool   `json:"ok"`
	Error string `json:"error"`
}

func adminRequest(ctx context.Context, client httpClient, method string, teamName string, values url.Values, d debug) (*adminResponse, error) {
	adminResponse := &adminResponse{}
	err := parseAdminResponse(ctx, client, method, teamName, values, adminResponse, d)
	if err != nil {
		return nil, err
	}

	if !adminResponse.OK {
		return nil, errors.New(adminResponse.Error)
	}

	return adminResponse, nil
}

// DisableUser disabled a user account, given a user ID
func (api *Client) DisableUser(teamName string, uid string) error {
	return api.DisableUserContext(context.Background(), teamName, uid)
}

// DisableUserContext disabled a user account, given a user ID with a custom context
func (api *Client) DisableUserContext(ctx context.Context, teamName string, uid string) error {
	values := url.Values{
		"user":       {uid},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setInactive", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to disable user with id '%s': %s", uid, err)
	}

	return nil
}

// InviteGuest invites a user to Slack as a single-channel guest
func (api *Client) InviteGuest(teamName, channel, firstName, lastName, emailAddress string) error {
	return api.InviteGuestContext(context.Background(), teamName, channel, firstName, lastName, emailAddress)
}

// InviteGuestContext invites a user to Slack as a single-channel guest with a custom context
func (api *Client) InviteGuestContext(ctx context.Context, teamName, channel, firstName, lastName, emailAddress string) error {
	values := url.Values{
		"email":            {emailAddress},
		"channels":         {channel},
		"first_name":       {firstName},
		"last_name":        {lastName},
		"ultra_restricted": {"1"},
		"token":            {api.token},
		"resend":           {"true"},
		"set_active":       {"true"},
		"_attempts":        {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to invite single-channel guest: %s", err)
	}

	return nil
}

// InviteRestricted invites a user to Slack as a restricted account
func (api *Client) InviteRestricted(teamName, channel, firstName, lastName, emailAddress string) error {
	return api.InviteRestrictedContext(context.Background(), teamName, channel, firstName, lastName, emailAddress)
}

// InviteRestrictedContext invites a user to Slack as a restricted account with a custom context
func (api *Client) InviteRestrictedContext(ctx context.Context, teamName, channel, firstName, lastName, emailAddress string) error {
	values := url.Values{
		"email":      {emailAddress},
		"channels":   {channel},
		"first_name": {firstName},
		"last_name":  {lastName},
		"restricted": {"1"},
		"token":      {api.token},
		"resend":     {"true"},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to restricted account: %s", err)
	}

	return nil
}

// InviteToTeam invites a user to a Slack team
func (api *Client) InviteToTeam(teamName, firstName, lastName, emailAddress string) error {
	return api.InviteToTeamContext(context.Background(), teamName, firstName, lastName, emailAddress)
}

// InviteToTeamContext invites a user to a Slack team with a custom context
func (api *Client) InviteToTeamContext(ctx context.Context, teamName, firstName, lastName, emailAddress string) error {
	values := url.Values{
		"email":      {emailAddress},
		"first_name": {firstName},
		"last_name":  {lastName},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to invite to team: %s", err)
	}

	return nil
}

// SetRegular enables the specified user
func (api *Client) SetRegular(teamName, user string) error {
	return api.SetRegularContext(context.Background(), teamName, user)
}

// SetRegularContext enables the specified user with a custom context
func (api *Client) SetRegularContext(ctx context.Context, teamName, user string) error {
	values := url.Values{
		"user":       {user},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setRegular", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to change the user (%s) to a regular user: %s", user, err)
	}

	return nil
}

// SendSSOBindingEmail sends an SSO binding email to the specified user
func (api *Client) SendSSOBindingEmail(teamName, user string) error {
	return api.SendSSOBindingEmailContext(context.Background(), teamName, user)
}

// SendSSOBindingEmailContext sends an SSO binding email to the specified user with a custom context
func (api *Client) SendSSOBindingEmailContext(ctx context.Context, teamName, user string) error {
	values := url.Values{
		"user":       {user},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "sendSSOBind", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to send SSO binding email for user (%s): %s", user, err)
	}

	return nil
}

// SetUltraRestricted converts a user into a single-channel guest
func (api *Client) SetUltraRestricted(teamName, uid, channel string) error {
	return api.SetUltraRestrictedContext(context.Background(), teamName, uid, channel)
}

// SetUltraRestrictedContext converts a user into a single-channel guest with a custom context
func (api *Client) SetUltraRestrictedContext(ctx context.Context, teamName, uid, channel string) error {
	values := url.Values{
		"user":       {uid},
		"channel":    {channel},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
	}

	_, err := adminRequest(ctx, api.httpclient, "setUltraRestricted", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to ultra-restrict account: %s", err)
	}

	return nil
}

// SetRestricted converts a user into a restricted account
func (api *Client) SetRestricted(teamName, uid string, channelIds ...string) error {
	return api.SetRestrictedContext(context.Background(), teamName, uid, channelIds...)
}

// SetRestrictedContext converts a user into a restricted account with a custom context
func (api *Client) SetRestrictedContext(ctx context.Context, teamName, uid string, channelIds ...string) error {
	values := url.Values{
		"user":       {uid},
		"token":      {api.token},
		"set_active": {"true"},
		"_attempts":  {"1"},
		"channels":   {strings.Join(channelIds, ",")},
	}

	_, err := adminRequest(ctx, api.httpclient, "setRestricted", teamName, values, api)
	if err != nil {
		return fmt.Errorf("Failed to restrict account: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package lzb

import (
	"errors"
	"fmt"
	"io"
)

// OpFinder enables the support of multiple different OpFinder
// algorithms.
type OpFinder interface {
	findOps(s *State, all bool) ([]operation, error)
	fmt.Stringer
}

// Writer produces an LZMA stream. EOS requests Close to write an
// end-of-stream marker.
type Writer struct {
	state    *State
	eos      bool
	OpFinder OpFinder
	re       *rangeEncoder
	buf      *buffer
	closed   bool
}

// NewWriter creates a new writer instance.
func NewWriter(pw io.Writer, p Parameters) (w *Writer, err error) {
	if err = verifyParameters(&p); err != nil {
		return
	}
	buf, err := newBuffer(p.BufferSize + p.DictSize)
	if err != nil {
		return nil, err
	}
	d, err := newHashDict(buf, buf.bottom, p.DictSize)
	if err != nil {
		return nil, err
	}
	d.sync()
	state := NewState(p.Properties(), d)
	w = &Writer{
		state:    state,
		eos:      !p.SizeInHeader || p.EOS,
		buf:      d.buf,
		re:       newRangeEncoder(pw),
		OpFinder: Greedy,
	}
	return w, nil
}

// writeLiteral writes a literal into the operation stream
func (w *Writer) writeLiteral(l lit) error {
	var err error
	state, state2, _ := w.state.states()
	if err = w.state.isMatch[state2].Encode(w.re, 0); err != nil {
		return err
	}
	litState := w.state.litState()
	match := w.state.dict.byteAt(int64(w.state.rep[0]) + 1)
	err = w.state.litCodec.Encode(w.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	w.state.updateStateLiteral()
	return nil
}

// iverson implements the Iverson operator as proposed by Donald Knuth in his
// book Concrete Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a repetition operation into the operation stream
func (w *Writer) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		return errors.New("distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(MinLength <= m.n && m.n <= MaxLength) &&
		!(dist == w.state.rep[0] && m.n == 1) {
		return errors.New("length out of range")
	}
	state, state2, posState := w.state.states()
	if err = w.state.isMatch[state2].Encode(w.re, 1); err != nil {
		return err
	}
	var g int
	for g = 0; g < 4; g++ {
		if w.state.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = w.state.isRep[state].Encode(w.re, b); err != nil {
		return err
	}
	n := uint32(m.n - MinLength)
	if b == 0 {
		// simple match
		w.state.rep[3], w.state.rep[2], w.state.rep[1], w.state.rep[0] = w.state.rep[2],
			w.state.rep[1], w.state.rep[0], dist
		w.state.updateStateMatch()
		if err = w.state.lenCodec.Encode(w.re, n, posState); err != nil {
			return err
		}
		return w.state.distCodec.Encode(w.re, dist, n)
	}
	b = iverson(g != 0)
	if err = w.state.isRepG0[state].Encode(w.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.n != 1)
		if err = w.state.isRepG0Long[state2].Encode(w.re, b); err != nil {
			return err
		}
		if b == 0 {
			w.state.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = w.state.isRepG1[state].Encode(w.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = w.state.isRepG2[state].Encode(w.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				w.state.rep[3] = w.state.rep[2]
			}
			w.state.rep[2] = w.state.rep[1]
		}
		w.state.rep[1] = w.state.rep[0]
		w.state.rep[0] = dist
	}
	w.state.updateStateRep()
	return w.state.repLenCodec.Encode(w.re, n, posState)
}

// writeOp writes an operation value into the stream. It checks whether there
// is still enough space available using an upper limit for the size required.
func (w *Writer) writeOp(op operation) error {
	var err error
	switch x := op.(type) {
	case match:
		err = w.writeMatch(x)
	case lit:
		err = w.writeLiteral(x)
	}
	if err != nil {
		return err
	}
	return w.discard(op)
}

// discard processes an operation after it has been written into the
// compressed LZMA street by moving the dictionary head forward.
func (w *Writer) discard(op operation) error {
	k := op.Len()
	n, err := w.state.dict.(*hashDict).move(k)
	if err != nil {
		return fmt.Errorf("operation %s: move %d error %s", op, k, err)
	}
	if n < k {
		return fmt.Errorf("operation %s: move %d incomplete", op, k)
	}
	return nil
}

// compress does the actual compression. If all is set all data
// available will be compressed.
func (w *Writer) compress(all bool) error {
	ops, err := w.OpFinder.findOps(w.state, all)
	if err != nil {
		return err
	}
	for _, op := range ops {
		if err = w.writeOp(op); err != nil {
			return err
		}
	}
	w.state.dict.(*hashDict).sync()
	return nil
}

// errWriterClosed indicates that a writer has been closed once before.
var errWriterClosed = errors.New("writer is closed")

// Write puts the provided data into the writer.
func (w *Writer) Write(p []byte) (n int, err error) {
	if w.closed {
		return 0, errWriterClosed
	}
	for len(p) > 0 {
		var k int
		k, err = w.buf.Write(p)
		n += k
		if err != errLimit {
			return
		}
		p = p[k:]
		if err = w.compress(false); err != nil {
			return
		}
	}
	return
}

// This operation will be encoded to indicate that the stream has ended.
var eosMatch = match{distance: maxDistance, n: MinLength}

// Close closes the writer.
func (w *Writer) Close() (err error) {
	if w.closed {
		return errWriterClosed
	}
	w.closed = true
	if err = w.compress(true); err != nil {
		return err
	}
	if w.eos {
		if err = w.writeMatch(eosMatch); err != nil {
			return err
		}
	}
	if err = w.re.Close(); err != nil {
		return err
	}
	return nil
}
<commit_msg>lub: minor change in lzb.NewWriter<commit_after>package lzb

import (
	"errors"
	"fmt"
	"io"
)

// OpFinder enables the support of multiple different OpFinder
// algorithms.
type OpFinder interface {
	findOps(s *State, all bool) ([]operation, error)
	fmt.Stringer
}

// Writer produces an LZMA stream. EOS requests Close to write an
// end-of-stream marker.
type Writer struct {
	state    *State
	eos      bool
	OpFinder OpFinder
	re       *rangeEncoder
	buf      *buffer
	closed   bool
}

// NewWriter creates a new writer instance.
func NewWriter(pw io.Writer, p Parameters) (w *Writer, err error) {
	if err = verifyParameters(&p); err != nil {
		return
	}
	buf, err := newBuffer(p.BufferSize + p.DictSize)
	if err != nil {
		return nil, err
	}
	d, err := newHashDict(buf, buf.bottom, p.DictSize)
	if err != nil {
		return nil, err
	}
	d.sync()
	state := NewState(p.Properties(), d)
	w = &Writer{
		state:    state,
		eos:      !p.SizeInHeader || p.EOS,
		buf:      buf,
		re:       newRangeEncoder(pw),
		OpFinder: Greedy,
	}
	return w, nil
}

// writeLiteral writes a literal into the operation stream
func (w *Writer) writeLiteral(l lit) error {
	var err error
	state, state2, _ := w.state.states()
	if err = w.state.isMatch[state2].Encode(w.re, 0); err != nil {
		return err
	}
	litState := w.state.litState()
	match := w.state.dict.byteAt(int64(w.state.rep[0]) + 1)
	err = w.state.litCodec.Encode(w.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	w.state.updateStateLiteral()
	return nil
}

// iverson implements the Iverson operator as proposed by Donald Knuth in his
// book Concrete Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a repetition operation into the operation stream
func (w *Writer) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		return errors.New("distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(MinLength <= m.n && m.n <= MaxLength) &&
		!(dist == w.state.rep[0] && m.n == 1) {
		return errors.New("length out of range")
	}
	state, state2, posState := w.state.states()
	if err = w.state.isMatch[state2].Encode(w.re, 1); err != nil {
		return err
	}
	var g int
	for g = 0; g < 4; g++ {
		if w.state.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = w.state.isRep[state].Encode(w.re, b); err != nil {
		return err
	}
	n := uint32(m.n - MinLength)
	if b == 0 {
		// simple match
		w.state.rep[3], w.state.rep[2], w.state.rep[1], w.state.rep[0] = w.state.rep[2],
			w.state.rep[1], w.state.rep[0], dist
		w.state.updateStateMatch()
		if err = w.state.lenCodec.Encode(w.re, n, posState); err != nil {
			return err
		}
		return w.state.distCodec.Encode(w.re, dist, n)
	}
	b = iverson(g != 0)
	if err = w.state.isRepG0[state].Encode(w.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.n != 1)
		if err = w.state.isRepG0Long[state2].Encode(w.re, b); err != nil {
			return err
		}
		if b == 0 {
			w.state.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = w.state.isRepG1[state].Encode(w.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = w.state.isRepG2[state].Encode(w.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				w.state.rep[3] = w.state.rep[2]
			}
			w.state.rep[2] = w.state.rep[1]
		}
		w.state.rep[1] = w.state.rep[0]
		w.state.rep[0] = dist
	}
	w.state.updateStateRep()
	return w.state.repLenCodec.Encode(w.re, n, posState)
}

// writeOp writes an operation value into the stream. It checks whether there
// is still enough space available using an upper limit for the size required.
func (w *Writer) writeOp(op operation) error {
	var err error
	switch x := op.(type) {
	case match:
		err = w.writeMatch(x)
	case lit:
		err = w.writeLiteral(x)
	}
	if err != nil {
		return err
	}
	return w.discard(op)
}

// discard processes an operation after it has been written into the
// compressed LZMA street by moving the dictionary head forward.
func (w *Writer) discard(op operation) error {
	k := op.Len()
	n, err := w.state.dict.(*hashDict).move(k)
	if err != nil {
		return fmt.Errorf("operation %s: move %d error %s", op, k, err)
	}
	if n < k {
		return fmt.Errorf("operation %s: move %d incomplete", op, k)
	}
	return nil
}

// compress does the actual compression. If all is set all data
// available will be compressed.
func (w *Writer) compress(all bool) error {
	ops, err := w.OpFinder.findOps(w.state, all)
	if err != nil {
		return err
	}
	for _, op := range ops {
		if err = w.writeOp(op); err != nil {
			return err
		}
	}
	w.state.dict.(*hashDict).sync()
	return nil
}

// errWriterClosed indicates that a writer has been closed once before.
var errWriterClosed = errors.New("writer is closed")

// Write puts the provided data into the writer.
func (w *Writer) Write(p []byte) (n int, err error) {
	if w.closed {
		return 0, errWriterClosed
	}
	for len(p) > 0 {
		var k int
		k, err = w.buf.Write(p)
		n += k
		if err != errLimit {
			return
		}
		p = p[k:]
		if err = w.compress(false); err != nil {
			return
		}
	}
	return
}

// This operation will be encoded to indicate that the stream has ended.
var eosMatch = match{distance: maxDistance, n: MinLength}

// Close closes the writer.
func (w *Writer) Close() (err error) {
	if w.closed {
		return errWriterClosed
	}
	w.closed = true
	if err = w.compress(true); err != nil {
		return err
	}
	if w.eos {
		if err = w.writeMatch(eosMatch); err != nil {
			return err
		}
	}
	if err = w.re.Close(); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package gost

import (
	"bytes"
	"errors"
	"fmt"
	"net"

	"github.com/go-log/log"
)

var (
	// ErrEmptyChain is an error that implies the chain is empty.
	ErrEmptyChain = errors.New("empty chain")
)

// Chain is a proxy chain that holds a list of proxy nodes.
type Chain struct {
	nodeGroups []*NodeGroup
}

// NewChain creates a proxy chain with a list of proxy nodes.
func NewChain(nodes ...Node) *Chain {
	chain := &Chain{}
	for _, node := range nodes {
		chain.nodeGroups = append(chain.nodeGroups, NewNodeGroup(node))
	}
	return chain
}

// Nodes returns the proxy nodes that the chain holds.
// If a node is a node group, the first node in the group will be returned.
func (c *Chain) Nodes() (nodes []Node) {
	for _, group := range c.nodeGroups {
		if ns := group.Nodes(); len(ns) > 0 {
			nodes = append(nodes, ns[0])
		}
	}
	return
}

// NodeGroups returns the list of node group.
func (c *Chain) NodeGroups() []*NodeGroup {
	return c.nodeGroups
}

// LastNode returns the last node of the node list.
// If the chain is empty, an empty node is returns.
// If the last node is a node group, the first node in the group will be returned.
func (c *Chain) LastNode() Node {
	if c.IsEmpty() {
		return Node{}
	}
	last := c.nodeGroups[len(c.nodeGroups)-1]
	return last.nodes[0]
}

// LastNodeGroup returns the last group of the group list.
func (c *Chain) LastNodeGroup() *NodeGroup {
	if c.IsEmpty() {
		return nil
	}
	return c.nodeGroups[len(c.nodeGroups)-1]
}

// AddNode appends the node(s) to the chain.
func (c *Chain) AddNode(nodes ...Node) {
	if c == nil {
		return
	}
	for _, node := range nodes {
		c.nodeGroups = append(c.nodeGroups, NewNodeGroup(node))
	}
}

// AddNodeGroup appends the group(s) to the chain.
func (c *Chain) AddNodeGroup(groups ...*NodeGroup) {
	if c == nil {
		return
	}
	for _, group := range groups {
		c.nodeGroups = append(c.nodeGroups, group)
	}
}

// IsEmpty checks if the chain is empty.
// An empty chain means that there is no proxy node or node group in the chain.
func (c *Chain) IsEmpty() bool {
	return c == nil || len(c.nodeGroups) == 0
}

// Dial connects to the target address addr through the chain.
// If the chain is empty, it will use the net.Dial directly.
func (c *Chain) Dial(addr string) (net.Conn, error) {
	if c.IsEmpty() {
		return net.Dial("tcp", addr)
	}

	route, err := c.selectRoute()
	if err != nil {
		return nil, err
	}

	conn, err := c.getConn(route)
	if err != nil {
		return nil, err
	}

	cc, err := route.LastNode().Client.Connect(conn, addr)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return cc, nil
}

// Conn obtains a handshaked connection to the last node of the chain.
// If the chain is empty, it returns an ErrEmptyChain error.
func (c *Chain) Conn() (conn net.Conn, err error) {
	route, err := c.selectRoute()
	if err != nil {
		return nil, err
	}
	conn, err = c.getConn(route)
	return
}

func (c *Chain) getConn(route *Chain) (conn net.Conn, err error) {
	if route.IsEmpty() {
		err = ErrEmptyChain
		return
	}
	nodes := route.Nodes()
	node := nodes[0]

	cn, err := node.Client.Dial(node.Addr, node.DialOptions...)
	if err != nil {
		return
	}

	cn, err = node.Client.Handshake(cn, node.HandshakeOptions...)
	if err != nil {
		return
	}

	preNode := node
	for _, node := range nodes[1:] {
		var cc net.Conn
		cc, err = preNode.Client.Connect(cn, node.Addr)
		if err != nil {
			cn.Close()
			return
		}
		cc, err = node.Client.Handshake(cc, node.HandshakeOptions...)
		if err != nil {
			cn.Close()
			return
		}
		cn = cc
		preNode = node
	}

	conn = cn
	return
}

func (c *Chain) selectRoute() (route *Chain, err error) {
	buf := bytes.Buffer{}
	route = NewChain()
	for _, group := range c.nodeGroups {
		selector := group.Selector
		if selector == nil {
			selector = &defaultSelector{}
		}
		// select node from node group
		node, err := selector.Select(group.Nodes(), group.Options...)
		if err != nil {
			return nil, err
		}
		if _, err := selectIP(&node); err != nil {
			return nil, err
		}
		buf.WriteString(fmt.Sprintf("%d@%s -> ", node.ID, node.Addr))

		if node.Client.Transporter.Multiplex() {
			node.DialOptions = append(node.DialOptions,
				ChainDialOption(route),
			)
			route = NewChain() // cutoff the chain for multiplex
		}
		route.AddNode(node)
	}
	log.Log("select route:", buf.String())
	return
}

func selectIP(node *Node) (string, error) {
	s := node.IPSelector
	if s == nil {
		s = &RandomIPSelector{}
	}
	// select IP from IP list
	ip, err := s.Select(node.IPs)
	if err != nil {
		return "", err
	}
	if ip != "" {
		// override the original address
		node.Addr = ip
		node.HandshakeOptions = append(node.HandshakeOptions, AddrHandshakeOption(node.Addr))
	}
	return node.Addr, nil
}
<commit_msg>fix chain route<commit_after>package gost

import (
	"bytes"
	"errors"
	"fmt"
	"net"

	"github.com/go-log/log"
)

var (
	// ErrEmptyChain is an error that implies the chain is empty.
	ErrEmptyChain = errors.New("empty chain")
)

// Chain is a proxy chain that holds a list of proxy nodes.
type Chain struct {
	isRoute    bool
	nodeGroups []*NodeGroup
}

// NewChain creates a proxy chain with a list of proxy nodes.
func NewChain(nodes ...Node) *Chain {
	chain := &Chain{}
	for _, node := range nodes {
		chain.nodeGroups = append(chain.nodeGroups, NewNodeGroup(node))
	}
	return chain
}

func newRoute(nodes ...Node) *Chain {
	chain := NewChain(nodes...)
	chain.isRoute = true
	return chain
}

// Nodes returns the proxy nodes that the chain holds.
// If a node is a node group, the first node in the group will be returned.
func (c *Chain) Nodes() (nodes []Node) {
	for _, group := range c.nodeGroups {
		if ns := group.Nodes(); len(ns) > 0 {
			nodes = append(nodes, ns[0])
		}
	}
	return
}

// NodeGroups returns the list of node group.
func (c *Chain) NodeGroups() []*NodeGroup {
	return c.nodeGroups
}

// LastNode returns the last node of the node list.
// If the chain is empty, an empty node is returns.
// If the last node is a node group, the first node in the group will be returned.
func (c *Chain) LastNode() Node {
	if c.IsEmpty() {
		return Node{}
	}
	last := c.nodeGroups[len(c.nodeGroups)-1]
	return last.nodes[0]
}

// LastNodeGroup returns the last group of the group list.
func (c *Chain) LastNodeGroup() *NodeGroup {
	if c.IsEmpty() {
		return nil
	}
	return c.nodeGroups[len(c.nodeGroups)-1]
}

// AddNode appends the node(s) to the chain.
func (c *Chain) AddNode(nodes ...Node) {
	if c == nil {
		return
	}
	for _, node := range nodes {
		c.nodeGroups = append(c.nodeGroups, NewNodeGroup(node))
	}
}

// AddNodeGroup appends the group(s) to the chain.
func (c *Chain) AddNodeGroup(groups ...*NodeGroup) {
	if c == nil {
		return
	}
	for _, group := range groups {
		c.nodeGroups = append(c.nodeGroups, group)
	}
}

// IsEmpty checks if the chain is empty.
// An empty chain means that there is no proxy node or node group in the chain.
func (c *Chain) IsEmpty() bool {
	return c == nil || len(c.nodeGroups) == 0
}

// Dial connects to the target address addr through the chain.
// If the chain is empty, it will use the net.Dial directly.
func (c *Chain) Dial(addr string) (net.Conn, error) {
	if c.IsEmpty() {
		return net.Dial("tcp", addr)
	}

	route, err := c.selectRoute()
	if err != nil {
		return nil, err
	}

	conn, err := c.getConn(route)
	if err != nil {
		return nil, err
	}

	cc, err := route.LastNode().Client.Connect(conn, addr)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return cc, nil
}

// Conn obtains a handshaked connection to the last node of the chain.
// If the chain is empty, it returns an ErrEmptyChain error.
func (c *Chain) Conn() (conn net.Conn, err error) {
	route, err := c.selectRoute()
	if err != nil {
		return nil, err
	}
	conn, err = c.getConn(route)
	return
}

func (c *Chain) getConn(route *Chain) (conn net.Conn, err error) {
	if route.IsEmpty() {
		err = ErrEmptyChain
		return
	}
	nodes := route.Nodes()
	node := nodes[0]

	cn, err := node.Client.Dial(node.Addr, node.DialOptions...)
	if err != nil {
		return
	}

	cn, err = node.Client.Handshake(cn, node.HandshakeOptions...)
	if err != nil {
		return
	}

	preNode := node
	for _, node := range nodes[1:] {
		var cc net.Conn
		cc, err = preNode.Client.Connect(cn, node.Addr)
		if err != nil {
			cn.Close()
			return
		}
		cc, err = node.Client.Handshake(cc, node.HandshakeOptions...)
		if err != nil {
			cn.Close()
			return
		}
		cn = cc
		preNode = node
	}

	conn = cn
	return
}

func (c *Chain) selectRoute() (route *Chain, err error) {
	if c.isRoute {
		return c, nil
	}

	buf := bytes.Buffer{}
	route = newRoute()
	for _, group := range c.nodeGroups {
		selector := group.Selector
		if selector == nil {
			selector = &defaultSelector{}
		}
		// select node from node group
		node, err := selector.Select(group.Nodes(), group.Options...)
		if err != nil {
			return nil, err
		}
		if _, err := selectIP(&node); err != nil {
			return nil, err
		}
		buf.WriteString(fmt.Sprintf("%d@%s -> ", node.ID, node.Addr))

		if node.Client.Transporter.Multiplex() {
			node.DialOptions = append(node.DialOptions,
				ChainDialOption(route),
			)
			route = newRoute() // cutoff the chain for multiplex
		}
		route.AddNode(node)
	}
	log.Log("select route:", buf.String())
	return
}

func selectIP(node *Node) (string, error) {
	s := node.IPSelector
	if s == nil {
		s = &RandomIPSelector{}
	}
	// select IP from IP list
	ip, err := s.Select(node.IPs)
	if err != nil {
		return "", err
	}
	if ip != "" {
		// override the original address
		node.Addr = ip
		node.HandshakeOptions = append(node.HandshakeOptions, AddrHandshakeOption(node.Addr))
	}
	return node.Addr, nil
}
<|endoftext|>


<commit_before>// Copyright 2014, Hǎiliàng Wáng. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package query

import (
	"regexp"

	. "h12.me/html-query/expr"
)

func (n *Node) Is(cs ...Checker) bool {
	return And(cs...)(n.InternalNode()) != nil
}

func (n *Node) Find(cs ...Checker) *Node {
	return NewNode(Find(cs...)(&n.n))
}

func (n *Node) FindNext(cs ...Checker) *Node {
	return NewNode(FindSibling(cs...)(&n.n))
}

func (n *Node) FindChild(cs ...Checker) *Node {
	return NewNode(FindChild(cs...)(&n.n))
}

func (n *Node) find(c Checker, cs []Checker) *Node {
	if n == nil {
		return nil
	}
	return n.Find(append([]Checker{c}, cs...)...)
}

func (n *Node) NextSibling() *Node {
	if n == nil {
		return nil
	}
	return NewNode(NextSibling(&n.n))
}

func (n *Node) PrevSibling() *Node {
	if n == nil {
		return nil
	}
	return NewNode(PrevSibling(&n.n))
}

func (n *Node) Parent() *Node {
	if n == nil {
		return nil
	}
	return NewNode(Parent(&n.n))
}

func (n *Node) Children(cs ...Checker) NodeIter {
	if n == nil {
		return NodeIter{nil}
	}
	return NodeIter{Children(&n.n, cs...)}
}

func (n *Node) Descendants(cs ...Checker) NodeIter {
	if n == nil {
		return NodeIter{nil}
	}
	return NodeIter{Descendants(&n.n, cs...)}
}

func (n *Node) Ahref(cs ...Checker) *Node {
	if n == nil {
		return nil
	}
	return n.find(Ahref, cs)
}

func (n *Node) TextNode(pat string) *TextNodeNode {
	if n == nil {
		return nil
	}
	rx := regexp.MustCompile(pat)
	cs := []Checker{Text_(rx)}
	return NewTextNodeNode(n.find(TextNode, cs), rx)
}

func also(c Checker, cs []Checker) []Checker {
	return append([]Checker{c}, cs...)
}
<commit_msg>check nil before Find & FindNext.<commit_after>// Copyright 2014, Hǎiliàng Wáng. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package query

import (
	"regexp"

	. "h12.me/html-query/expr"
)

func (n *Node) Is(cs ...Checker) bool {
	return And(cs...)(n.InternalNode()) != nil
}

func (n *Node) Find(cs ...Checker) *Node {
	if n == nil {
		return nil
	}
	return NewNode(Find(cs...)(&n.n))
}

func (n *Node) FindNext(cs ...Checker) *Node {
	if n == nil {
		return nil
	}
	return NewNode(FindSibling(cs...)(&n.n))
}

func (n *Node) FindChild(cs ...Checker) *Node {
	return NewNode(FindChild(cs...)(&n.n))
}

func (n *Node) find(c Checker, cs []Checker) *Node {
	if n == nil {
		return nil
	}
	return n.Find(append([]Checker{c}, cs...)...)
}

func (n *Node) NextSibling() *Node {
	if n == nil {
		return nil
	}
	return NewNode(NextSibling(&n.n))
}

func (n *Node) PrevSibling() *Node {
	if n == nil {
		return nil
	}
	return NewNode(PrevSibling(&n.n))
}

func (n *Node) Parent() *Node {
	if n == nil {
		return nil
	}
	return NewNode(Parent(&n.n))
}

func (n *Node) Children(cs ...Checker) NodeIter {
	if n == nil {
		return NodeIter{nil}
	}
	return NodeIter{Children(&n.n, cs...)}
}

func (n *Node) Descendants(cs ...Checker) NodeIter {
	if n == nil {
		return NodeIter{nil}
	}
	return NodeIter{Descendants(&n.n, cs...)}
}

func (n *Node) Ahref(cs ...Checker) *Node {
	if n == nil {
		return nil
	}
	return n.find(Ahref, cs)
}

func (n *Node) TextNode(pat string) *TextNodeNode {
	if n == nil {
		return nil
	}
	rx := regexp.MustCompile(pat)
	cs := []Checker{Text_(rx)}
	return NewTextNodeNode(n.find(TextNode, cs), rx)
}

func also(c Checker, cs []Checker) []Checker {
	return append([]Checker{c}, cs...)
}
<|endoftext|>


<commit_before>// Package check allows data validation of values in different types
package check

import (
	"fmt"
	"reflect"
	"strings"
)

var (
	// ErrorMessages contains default error messages
	ErrorMessages = map[string]string{
		"nonZero":     "value cannot be empty",
		"before":      "%v is not before %v",
		"after":       "%v is not after %v",
		"lowerThan":   "%v is not lower than %v",
		"greaterThan": "%v is not greater than %v",
		"minChar":     "too short, minimum %v characters",
		"maxChar":     "too long, minimum %v characters",
		"email":       "'%v' is an invalid email address",
		"regex":       "'%v' does not match '%v'",
		"uuid":        "'%v' is an invalid uuid",
	}
)

// Validator is an interface for constraint types with a method of validate()
type Validator interface {
	// Validate check value against constraints
	Validate(v interface{}) Error
}

// Struct allows validation of structs
type Struct map[string]Validator

// Validate execute validation using the validators.
func (s Struct) Validate(v interface{}) StructError {
	val := reflect.ValueOf(v)

	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if val.Kind() != reflect.Struct {
		panic("not a struct")
	}

	e := StructError{}
	for fieldname, validator := range s {
		field := val.FieldByName(fieldname)

		if field.Kind() == reflect.Invalid {
			panic("invalid struct field name \""+fieldname+"\".")
		}

		if err := validator.Validate(field.Interface()); err != nil {
			if _, ok := e[fieldname]; !ok {
				e[fieldname] = make([]Error, 0)
			}

			e[fieldname] = append(e[fieldname], err)
		}
	}

	return e
}

// Composite allows adding multiple validators to the same value
type Composite []Validator

// Validate implements Validator
func (c Composite) Validate(v interface{}) Error {
	e := ValidationError{
		errorMap: make(map[string][]interface{}),
	}
	for _, validator := range c {
		if err := validator.Validate(v); err != nil {
			errMap := err.ErrorMap()
			for msg, params := range errMap {
				e.errorMap[msg] = params
			}
		}
	}

	if len(e.errorMap) == 0 {
		return nil
	}

	return e
}

// Error is the default validation error. The Params() method returns the params
// to be used in error messages
type Error interface {
	Error() string
	ErrorMap() map[string][]interface{}
}

// ValidationError implements Error
type ValidationError struct {
	errorMap map[string][]interface{}
}

func (e ValidationError) Error() string {
	var errs []string
	for msg := range e.errorMap {
		errs = append(errs, msg)
	}

	return strings.Join(errs, "; ")
}

// ErrorMap returns the error map
func (e ValidationError) ErrorMap() map[string][]interface{} { return e.errorMap }

// NewValidationError create and return a ValidationError
func NewValidationError(key string, params ...interface{}) *ValidationError {
	return &ValidationError{
		map[string][]interface{}{
			key: params,
		},
	}
}

// StructError is a map with validation errors
type StructError map[string][]Error

// HasErrors return true if the ErrorMap has errors
func (e StructError) HasErrors() bool {
	return len(e) > 0
}

// GetErrorsByKey return all errors for a specificed key
func (e StructError) GetErrorsByKey(key string) ([]Error, bool) {
	v, ok := e[key]
	return v, ok
}

// ToMessages convert StructError to a map of field and their validation key with proper error messages
func (e StructError) ToMessages() map[string]map[string]string {
	errMessages := make(map[string]map[string]string)

	for field, validationErrors := range e {
		errMessages[field] = make(map[string]string)
		for _, err := range validationErrors {
			for key, params := range err.ErrorMap() {
				msg, ok := ErrorMessages[key]
				if !ok {
					errMessages[field][key] = "invalid data"
				} else {
					if len(params) > 0 {
						errMessages[field][key] = fmt.Sprintf(msg, params...)
					} else {
						errMessages[field][key] = msg
					}
				}
			}
		}
	}

	return errMessages
}

// NonEmpty check that the value is not a zeroed value depending on its type
type NonEmpty struct{}

// Validate value to not be a zeroed value, return error and empty slice of strings
func (validator NonEmpty) Validate(v interface{}) Error {
	t := reflect.TypeOf(v)

	switch t.Kind() {
	default:
		if reflect.DeepEqual(reflect.Zero(t).Interface(), v) {
			return NewValidationError("nonZero")
		}
	case reflect.Array, reflect.Slice, reflect.Map, reflect.Chan, reflect.String:
		if reflect.ValueOf(v).Len() == 0 {
			return NewValidationError("nonZero")
		}
	}

	return nil
}
<commit_msg>Make StructError implements the error interface<commit_after>// Package check allows data validation of values in different types
package check

import (
	"fmt"
	"reflect"
	"strings"
)

var (
	// ErrorMessages contains default error messages
	ErrorMessages = map[string]string{
		"nonZero":     "value cannot be empty",
		"before":      "%v is not before %v",
		"after":       "%v is not after %v",
		"lowerThan":   "%v is not lower than %v",
		"greaterThan": "%v is not greater than %v",
		"minChar":     "too short, minimum %v characters",
		"maxChar":     "too long, minimum %v characters",
		"email":       "'%v' is an invalid email address",
		"regex":       "'%v' does not match '%v'",
		"uuid":        "'%v' is an invalid uuid",
	}
)

// Validator is an interface for constraint types with a method of validate()
type Validator interface {
	// Validate check value against constraints
	Validate(v interface{}) Error
}

// Struct allows validation of structs
type Struct map[string]Validator

// Validate execute validation using the validators.
func (s Struct) Validate(v interface{}) StructError {
	val := reflect.ValueOf(v)

	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if val.Kind() != reflect.Struct {
		panic("not a struct")
	}

	e := StructError{}
	for fieldname, validator := range s {
		field := val.FieldByName(fieldname)

		if field.Kind() == reflect.Invalid {
			panic("invalid struct field name \"" + fieldname + "\".")
		}

		if err := validator.Validate(field.Interface()); err != nil {
			if _, ok := e[fieldname]; !ok {
				e[fieldname] = make([]Error, 0)
			}

			e[fieldname] = append(e[fieldname], err)
		}
	}

	return e
}

// Composite allows adding multiple validators to the same value
type Composite []Validator

// Validate implements Validator
func (c Composite) Validate(v interface{}) Error {
	e := ValidationError{
		errorMap: make(map[string][]interface{}),
	}
	for _, validator := range c {
		if err := validator.Validate(v); err != nil {
			errMap := err.ErrorMap()
			for msg, params := range errMap {
				e.errorMap[msg] = params
			}
		}
	}

	if len(e.errorMap) == 0 {
		return nil
	}

	return e
}

// Error is the default validation error. The Params() method returns the params
// to be used in error messages
type Error interface {
	Error() string
	ErrorMap() map[string][]interface{}
}

// ValidationError implements Error
type ValidationError struct {
	errorMap map[string][]interface{}
}

func (e ValidationError) Error() string {
	var errs []string
	for msg := range e.errorMap {
		errs = append(errs, msg)
	}

	return strings.Join(errs, "; ")
}

// ErrorMap returns the error map
func (e ValidationError) ErrorMap() map[string][]interface{} { return e.errorMap }

// NewValidationError create and return a ValidationError
func NewValidationError(key string, params ...interface{}) *ValidationError {
	return &ValidationError{
		map[string][]interface{}{
			key: params,
		},
	}
}

// StructError is a map with validation errors
type StructError map[string][]Error

// HasErrors return true if the ErrorMap has errors
func (e StructError) HasErrors() bool {
	return len(e) > 0
}

// Error satisfy error interface. Will return a concatenated
// strings of errors separated by "\n"
func (e StructError) Error() string {
	var s []string
	for _, v := range e {
		for _, err := range v {
			s = append(s, err.Error())
		}
	}

	return strings.Join(s, "\n")
}

// GetErrorsByKey return all errors for a specificed key
func (e StructError) GetErrorsByKey(key string) ([]Error, bool) {
	v, ok := e[key]
	return v, ok
}

// ToMessages convert StructError to a map of field and their validation key with proper error messages
func (e StructError) ToMessages() map[string]map[string]string {
	errMessages := make(map[string]map[string]string)

	for field, validationErrors := range e {
		errMessages[field] = make(map[string]string)
		for _, err := range validationErrors {
			for key, params := range err.ErrorMap() {
				msg, ok := ErrorMessages[key]
				if !ok {
					errMessages[field][key] = "invalid data"
				} else {
					if len(params) > 0 {
						errMessages[field][key] = fmt.Sprintf(msg, params...)
					} else {
						errMessages[field][key] = msg
					}
				}
			}
		}
	}

	return errMessages
}

// NonEmpty check that the value is not a zeroed value depending on its type
type NonEmpty struct{}

// Validate value to not be a zeroed value, return error and empty slice of strings
func (validator NonEmpty) Validate(v interface{}) Error {
	t := reflect.TypeOf(v)

	switch t.Kind() {
	default:
		if reflect.DeepEqual(reflect.Zero(t).Interface(), v) {
			return NewValidationError("nonZero")
		}
	case reflect.Array, reflect.Slice, reflect.Map, reflect.Chan, reflect.String:
		if reflect.ValueOf(v).Len() == 0 {
			return NewValidationError("nonZero")
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package models

import (
	"time"
)

type Bucket struct {
	ID    int64
	Title string

	Files []*File `xorm:"-"`

	Created time.Time `xorm:"created"`
	Updated time.Time `xorm:"updated"`
}

func BucketCreate(title string) (*Bucket, error) {
	buck := new(Bucket)
	buck.Title = title

	e := Save(buck)

	return buck, e
}

func BucketGet(id int64) (*Bucket, error) {
	var (
		e     error
		buck  = new(Bucket)
		files []*File
	)
	_, e = x.Id(id).Get(buck)
	if e != nil {
		return nil, e
	}
	e = x.Where("bucket_id = ?", id).Find(&files)
	if e != nil {
		return nil, e
	}
	buck.Files = files
	return buck, e
}

func BucketList(limit int, offsets ...int) (res []*Bucket, err error) {
	err = x.Limit(limit, offsets...).OrderBy("id desc").Find(&res)
	return res, err
}
<commit_msg>change id fold<commit_after>package models

import (
	"time"
)

type Bucket struct {
	Id    int64
	Title string

	Files []*File `xorm:"-"`

	Created time.Time `xorm:"created"`
	Updated time.Time `xorm:"updated"`
}

func BucketCreate(title string) (*Bucket, error) {
	buck := new(Bucket)
	buck.Title = title

	e := Save(buck)

	return buck, e
}

func BucketGet(id int64) (*Bucket, error) {
	var (
		e     error
		buck  = new(Bucket)
		files []*File
	)
	_, e = x.Id(id).Get(buck)
	if e != nil {
		return nil, e
	}
	e = x.Where("bucket_id = ?", id).Find(&files)
	if e != nil {
		return nil, e
	}
	buck.Files = files
	return buck, e
}

func BucketList(limit int, offsets ...int) (res []*Bucket, err error) {
	err = x.Limit(limit, offsets...).OrderBy("id desc").Find(&res)
	return res, err
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const (
	// The HTTP method used for each test
	HTTP_METHOD = "OPTIONS"
	// Check the URL every 3 seconds
	CHECK_INTERVAL = 3
	// If the test keeps the same state for 1 hour, stop it
	CHECK_DURATION = 3600
	// Check every 1 minute if we break the check
	CHECK_BREAK_INTERVAL = 60
	// Connection timeout is 3 seconds by default
	CONNECTION_TIMEOUT = 3
	// IO timeout applies after the connection
	IO_TIMEOUT = 3
	// User-Agent for all tests
	USER_AGENT = "dotCloud-HealthCheck/1.0 go/1.0.3"
)

var (
	httpClient         *http.Client
	httpMethod         string
	checkInterval      time.Duration
	checkDuration      = time.Duration(CHECK_DURATION) * time.Second
	checkBreakInterval = time.Duration(CHECK_BREAK_INTERVAL) * time.Second
	connectionTimeout  time.Duration
	ioTimeout          time.Duration
	userAgent          string
)

type Check struct {
	BackendUrl         string
	BackendId          int
	BackendGroupLength int
	FrontendKey        string

	// Goroutine unique signature
	routineSig string

	// Called when backend dies
	deadCallback func()
	// Called when the backend comes back to life
	aliveCallback func()
	// Called every CHECK_BREAK_INTERVAL to stop the routine if returned true
	checkIfBreakCallback func() bool
	// Called when the check exits
	exitCallback func()
}

func NewCheck(line string) (*Check, error) {
	parts := strings.Split(strings.TrimSpace(line), ";")
	if len(parts) != 4 {
		return nil, errors.New("Invalid check line")
	}
	backendId, _ := strconv.Atoi(parts[2])
	backendGroupLength, _ := strconv.Atoi(parts[3])
	c := &Check{BackendUrl: parts[1], BackendId: backendId,
		BackendGroupLength: backendGroupLength, FrontendKey: parts[0]}
	return c, nil
}

func (c *Check) SetDeadCallback(callback func()) {
	c.deadCallback = callback
}

func (c *Check) SetAliveCallback(callback func()) {
	c.aliveCallback = callback
}

func (c *Check) SetCheckIfBreakCallback(callback func() bool) {
	c.checkIfBreakCallback = callback
}

func (c *Check) SetExitCallback(callback func()) {
	c.exitCallback = callback
}

func (c *Check) doHttpRequest() {
	if httpClient == nil {
		httpDial := func(proto string, addr string) (net.Conn, error) {
			conn, err := net.DialTimeout(proto, addr, connectionTimeout)
			if err != nil {
				return nil, err
			}
			conn.SetDeadline(time.Now().Add(ioTimeout))
			return conn, nil
		}
		transport := &http.Transport{
			DisableKeepAlives: true,
			Dial:              httpDial,
		}
		httpClient = &http.Client{Transport: transport}
	}
	req, _ := http.NewRequest(httpMethod, c.BackendUrl, nil)
	req.Header.Add("User-Agent", userAgent)
	fmt.Printf("REQUEST -> %#v\n", req)
}

func (c *Check) PingUrl() {
	// Current status, true for alive, false for dead
	var (
		testError       string
		lastDeadCall    time.Time
		lastStateChange = time.Now()
		status          = false
		newStatus       = true
		i               = time.Duration(0)
	)
	for {
		req, _ := http.NewRequest(httpMethod, c.BackendUrl, nil)
		req.Header.Add("User-Agent", userAgent)
		fmt.Printf("REQUEST -> %#v\n", req)
		resp, err := httpClient.Do(req)
		if err != nil {
			// TCP error
			newStatus = false
			testError = fmt.Sprintf("TCP error on %s: %#v",
				c.BackendUrl, err.Error())
		} else {
			// No TCP error, checking HTTP code
			if resp.StatusCode >= 500 && resp.StatusCode < 600 &&
				resp.StatusCode != 503 {
				newStatus = false
				testError = fmt.Sprintf("HTTP error on %s: %#v",
					c.BackendUrl, resp.StatusCode)
			} else {
				newStatus = true
			}
		}
		if resp != nil && resp.Body != nil {
			resp.Body.Close()
		}
		// Check if the status changed before updating Redis
		if newStatus != status {
			lastStateChange = time.Now()
			if newStatus == true {
				log.Printf("%s is back online\n", c.BackendUrl)
				if c.aliveCallback != nil {
					c.aliveCallback()
				}
				lastDeadCall = time.Time{}
			} else {
				log.Println(testError)
				if c.deadCallback != nil {
					c.deadCallback()
				}
				lastDeadCall = time.Now()
			}
		} else if newStatus == false {
			// Backend is still dead. Mark it as dead every 30 seconds to keep
			// it dead despite the Redis TTL
			if lastDeadCall.IsZero() == false &&
				time.Since(lastDeadCall) >=
					(time.Duration(30)*time.Second) {
				if c.deadCallback != nil {
					c.deadCallback()
				}
				lastDeadCall = time.Now()
			}
		}
		status = newStatus
		time.Sleep(checkInterval)
		i += checkInterval
		// At longer interval, we check if still have the lock on the backend
		if i >= checkBreakInterval {
			if c.checkIfBreakCallback != nil &&
				c.checkIfBreakCallback() == true {
				log.Printf("Lost the lock for %s\n", c.BackendUrl)
				break
			}
			// Let's see if the check is in the same state for a while
			if time.Since(lastStateChange) >= checkDuration {
				log.Printf("%s stayed in the same state for a long time\n",
					c.BackendUrl)
				break
			}
			i = time.Duration(0)
		}
	}
	if c.exitCallback != nil {
		c.exitCallback()
	}
}
<commit_msg>Restored http check (broken by last push)<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const (
	// The HTTP method used for each test
	HTTP_METHOD = "OPTIONS"
	// Check the URL every 3 seconds
	CHECK_INTERVAL = 3
	// If the test keeps the same state for 1 hour, stop it
	CHECK_DURATION = 3600
	// Check every 1 minute if we break the check
	CHECK_BREAK_INTERVAL = 60
	// Connection timeout is 3 seconds by default
	CONNECTION_TIMEOUT = 3
	// IO timeout applies after the connection
	IO_TIMEOUT = 3
	// User-Agent for all tests
	USER_AGENT = "dotCloud-HealthCheck/1.0 go/1.0.3"
)

var (
	httpClient         *http.Client
	httpMethod         string
	checkInterval      time.Duration
	checkDuration      = time.Duration(CHECK_DURATION) * time.Second
	checkBreakInterval = time.Duration(CHECK_BREAK_INTERVAL) * time.Second
	connectionTimeout  time.Duration
	ioTimeout          time.Duration
	userAgent          string
)

type Check struct {
	BackendUrl         string
	BackendId          int
	BackendGroupLength int
	FrontendKey        string

	// Goroutine unique signature
	routineSig string

	// Called when backend dies
	deadCallback func()
	// Called when the backend comes back to life
	aliveCallback func()
	// Called every CHECK_BREAK_INTERVAL to stop the routine if returned true
	checkIfBreakCallback func() bool
	// Called when the check exits
	exitCallback func()
}

func NewCheck(line string) (*Check, error) {
	parts := strings.Split(strings.TrimSpace(line), ";")
	if len(parts) != 4 {
		return nil, errors.New("Invalid check line")
	}
	backendId, _ := strconv.Atoi(parts[2])
	backendGroupLength, _ := strconv.Atoi(parts[3])
	c := &Check{BackendUrl: parts[1], BackendId: backendId,
		BackendGroupLength: backendGroupLength, FrontendKey: parts[0]}
	return c, nil
}

func (c *Check) SetDeadCallback(callback func()) {
	c.deadCallback = callback
}

func (c *Check) SetAliveCallback(callback func()) {
	c.aliveCallback = callback
}

func (c *Check) SetCheckIfBreakCallback(callback func() bool) {
	c.checkIfBreakCallback = callback
}

func (c *Check) SetExitCallback(callback func()) {
	c.exitCallback = callback
}

func (c *Check) doHttpRequest() (*http.Response, error) {
	if httpClient == nil {
		httpDial := func(proto string, addr string) (net.Conn, error) {
			conn, err := net.DialTimeout(proto, addr, connectionTimeout)
			if err != nil {
				return nil, err
			}
			conn.SetDeadline(time.Now().Add(ioTimeout))
			return conn, nil
		}
		transport := &http.Transport{
			DisableKeepAlives: true,
			Dial:              httpDial,
		}
		httpClient = &http.Client{Transport: transport}
	}
	req, _ := http.NewRequest(httpMethod, c.BackendUrl, nil)
	req.Header.Add("User-Agent", userAgent)
	fmt.Printf("REQUEST -> %#v\n", req)
	return httpClient.Do(req)
}

func (c *Check) PingUrl() {
	// Current status, true for alive, false for dead
	var (
		testError       string
		lastDeadCall    time.Time
		lastStateChange = time.Now()
		status          = false
		newStatus       = true
		i               = time.Duration(0)
	)
	for {
		resp, err := c.doHttpRequest()
		if err != nil {
			// TCP error
			newStatus = false
			testError = fmt.Sprintf("TCP error on %s: %#v",
				c.BackendUrl, err.Error())
		} else {
			// No TCP error, checking HTTP code
			if resp.StatusCode >= 500 && resp.StatusCode < 600 &&
				resp.StatusCode != 503 {
				newStatus = false
				testError = fmt.Sprintf("HTTP error on %s: %#v",
					c.BackendUrl, resp.StatusCode)
			} else {
				newStatus = true
			}
		}
		if resp != nil && resp.Body != nil {
			resp.Body.Close()
		}
		// Check if the status changed before updating Redis
		if newStatus != status {
			lastStateChange = time.Now()
			if newStatus == true {
				log.Printf("%s is back online\n", c.BackendUrl)
				if c.aliveCallback != nil {
					c.aliveCallback()
				}
				lastDeadCall = time.Time{}
			} else {
				log.Println(testError)
				if c.deadCallback != nil {
					c.deadCallback()
				}
				lastDeadCall = time.Now()
			}
		} else if newStatus == false {
			// Backend is still dead. Mark it as dead every 30 seconds to keep
			// it dead despite the Redis TTL
			if lastDeadCall.IsZero() == false &&
				time.Since(lastDeadCall) >=
					(time.Duration(30)*time.Second) {
				if c.deadCallback != nil {
					c.deadCallback()
				}
				lastDeadCall = time.Now()
			}
		}
		status = newStatus
		time.Sleep(checkInterval)
		i += checkInterval
		// At longer interval, we check if still have the lock on the backend
		if i >= checkBreakInterval {
			if c.checkIfBreakCallback != nil &&
				c.checkIfBreakCallback() == true {
				log.Printf("Lost the lock for %s\n", c.BackendUrl)
				break
			}
			// Let's see if the check is in the same state for a while
			if time.Since(lastStateChange) >= checkDuration {
				log.Printf("%s stayed in the same state for a long time\n",
					c.BackendUrl)
				break
			}
			i = time.Duration(0)
		}
	}
	if c.exitCallback != nil {
		c.exitCallback()
	}
}
<|endoftext|>


<commit_before>package dog

import (
	"io/ioutil"

	"github.com/ghodss/yaml"
)

func ParseDogfile(d []byte) (tm TaskMap, err error) {
	var tasks []Task

	err = yaml.Unmarshal(d, &tasks)
	if err != nil {
		return
	}

	tm = make(TaskMap)
	for _, t := range tasks {
		if _, ok := tm[t.Name]; ok {
			// TODO (duplicated task name) fail and return a non-nil error
		} else {
			tm[t.Name] = t
		}
	}

	return
}

// LoadDogFile finds a Dogfile in disk, parses YAML and returns a map
func LoadDogFile() (tm TaskMap, err error) {
	var dat []byte

	dat, err = ioutil.ReadFile("Dogfile.yml")
	if err != nil {
		return
	}

	tm, err = ParseDogfile(dat)
	if err != nil {
		return
	}

	return
}
<commit_msg>Allow multiple Dogfiles per directory (#19)<commit_after>package dog

import (
	"io/ioutil"
	"os"
	"regexp"

	"github.com/ghodss/yaml"
)

func ParseDogfile(d []byte) (tm TaskMap, err error) {
	var tasks []Task

	err = yaml.Unmarshal(d, &tasks)
	if err != nil {
		return
	}

	tm = make(TaskMap)
	for _, t := range tasks {
		if _, ok := tm[t.Name]; ok {
			// TODO (duplicated task name) fail and return a non-nil error
		} else {
			tm[t.Name] = t
		}
	}

	return
}

// LoadDogFile finds a Dogfile in disk, parses YAML and returns a map
func LoadDogFile() (tm TaskMap, err error) {
	const validDogfileName = "^(Dogfile|🐕)"
	var dogfiles []os.FileInfo
	var d []byte

	files, err := ioutil.ReadDir(".")
	if err != nil {
		return
	}

	for _, file := range files {
		var match bool
		match, err = regexp.MatchString(validDogfileName, file.Name())
		if err != nil {
			return
		}

		if match {
			dogfiles = append(dogfiles, file)
		}
	}

	for _, dogfile := range dogfiles {
		var fileData []byte
		fileData, err = ioutil.ReadFile(dogfile.Name())
		if err != nil {
			return
		}
		d = append(d, fileData...)
	}

	tm, err = ParseDogfile(d)
	if err != nil {
		return
	}

	return
}
<|endoftext|>


<commit_before>// Metrics output to newrelic.
// based on https://github.com/yvasiyarov/gorelic
package newrelic_tigertonic

import (
	"errors"
	"log"

	"github.com/rcrowley/go-metrics"
	"github.com/yvasiyarov/newrelic_platform_go"
)

const (
	// DefaultNewRelicPollInterval - how often we will report metrics to NewRelic.
	// Recommended values is 60 seconds
	DefaultNewRelicPollInterval = 10

	// DefaultPollIntervalInSeconds - how often we will get  statistic
	// Default value is - every 10 seconds
	DefaultPollIntervalInSeconds = 10

	//DefaultAgentGuid is plugin ID in NewRelic.
	//You should not change it unless you want to create your own plugin.
	DefaultAgentGuid = "com.rounds.TigerTonic"

	//CurrentAgentVersion is plugin version
	CurrentAgentVersion = "0.0.1"

	//DefaultAgentName in NewRelic GUI. You can change it.
	DefaultAgentName = "TigerTonic"
)

//Agent - is NewRelic agent implementation.
//Agent start separate go routine which will report data to NewRelic
type Agent struct {
	NewrelicName         string
	NewrelicLicense      string
	NewrelicPollInterval int
	PollInterval         int
	Verbose              bool
	AgentGUID            string
	AgentVersion         string
	plugin               *newrelic_platform_go.NewrelicPlugin
}

//NewAgent build new Agent objects.
func NewAgent() *Agent {
	agent := &Agent{
		NewrelicName:         DefaultAgentName,
		NewrelicPollInterval: DefaultNewRelicPollInterval,
		Verbose:              false,
		PollInterval:         DefaultPollIntervalInSeconds,
		AgentGUID:            DefaultAgentGuid,
		AgentVersion:         CurrentAgentVersion,
	}
	return agent
}

//Run initialize Agent instance and start harvest go routine
func (agent *Agent) Run() error {
	if agent.NewrelicLicense == "" {
		return errors.New("please, pass a valid newrelic license key")
	}

	agent.plugin = newrelic_platform_go.NewNewrelicPlugin(agent.AgentVersion, agent.NewrelicLicense, agent.NewrelicPollInterval)
	component := newrelic_platform_go.NewPluginComponent(agent.NewrelicName, agent.AgentGUID)
	agent.plugin.AddComponent(component)
	registry := metrics.DefaultRegistry
	registry.Each(func(name string, i interface{}) {
		switch metric := i.(type) {
		case metrics.Timer:
			addTimerMericsToComponent(component, metric, name)
		case metrics.Counter:
			addCounterMericsToComponent(component, metric, name)

		}
	})

	agent.plugin.Verbose = agent.Verbose
	go agent.plugin.Run()
	return nil
}

//Print debug messages
func (agent *Agent) debug(msg string) {
	if agent.Verbose {
		log.Println(msg)
	}
}
<commit_msg>Changed DefaultNewRelicPollInterval to 60<commit_after>// Metrics output to newrelic.
// based on https://github.com/yvasiyarov/gorelic
package newrelic_tigertonic

import (
	"errors"
	"log"

	"github.com/rcrowley/go-metrics"
	"github.com/yvasiyarov/newrelic_platform_go"
)

const (
	// DefaultNewRelicPollInterval - how often we will report metrics to NewRelic.
	// Recommended values is 60 seconds
	DefaultNewRelicPollInterval = 60

	// DefaultPollIntervalInSeconds - how often we will get  statistic
	// Default value is - every 10 seconds
	DefaultPollIntervalInSeconds = 10

	//DefaultAgentGuid is plugin ID in NewRelic.
	//You should not change it unless you want to create your own plugin.
	DefaultAgentGuid = "com.rounds.TigerTonic"

	//CurrentAgentVersion is plugin version
	CurrentAgentVersion = "0.0.1"

	//DefaultAgentName in NewRelic GUI. You can change it.
	DefaultAgentName = "TigerTonic"
)

//Agent - is NewRelic agent implementation.
//Agent start separate go routine which will report data to NewRelic
type Agent struct {
	NewrelicName         string
	NewrelicLicense      string
	NewrelicPollInterval int
	PollInterval         int
	Verbose              bool
	AgentGUID            string
	AgentVersion         string
	plugin               *newrelic_platform_go.NewrelicPlugin
}

//NewAgent build new Agent objects.
func NewAgent() *Agent {
	agent := &Agent{
		NewrelicName:         DefaultAgentName,
		NewrelicPollInterval: DefaultNewRelicPollInterval,
		Verbose:              false,
		PollInterval:         DefaultPollIntervalInSeconds,
		AgentGUID:            DefaultAgentGuid,
		AgentVersion:         CurrentAgentVersion,
	}
	return agent
}

//Run initialize Agent instance and start harvest go routine
func (agent *Agent) Run() error {
	if agent.NewrelicLicense == "" {
		return errors.New("please, pass a valid newrelic license key")
	}

	agent.plugin = newrelic_platform_go.NewNewrelicPlugin(agent.AgentVersion, agent.NewrelicLicense, agent.NewrelicPollInterval)
	component := newrelic_platform_go.NewPluginComponent(agent.NewrelicName, agent.AgentGUID)
	agent.plugin.AddComponent(component)
	registry := metrics.DefaultRegistry
	registry.Each(func(name string, i interface{}) {
		switch metric := i.(type) {
		case metrics.Timer:
			addTimerMericsToComponent(component, metric, name)
		case metrics.Counter:
			addCounterMericsToComponent(component, metric, name)

		}
	})

	agent.plugin.Verbose = agent.Verbose
	go agent.plugin.Run()
	return nil
}

//Print debug messages
func (agent *Agent) debug(msg string) {
	if agent.Verbose {
		log.Println(msg)
	}
}
<|endoftext|>