<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/drone/drone-template-lib/template"
)

const (
	// DroneIconURL default drone logo url
	DroneIconURL = "https://c1.staticflickr.com/5/4236/34957940160_435d83114f_z.jpg"
	// DroneDesc default drone description
	DroneDesc = "Powered by Drone Discord Plugin"
)

type (
	// GitHub information.
	GitHub struct {
		Workflow  string
		Workspace string
		Action    string
		EventName string
		EventPath string
	}

	// Repo information.
	Repo struct {
		FullName  string
		Namespace string
		Name      string
	}

	// Commit information.
	Commit struct {
		Sha     string
		Ref     string
		Branch  string
		Link    string
		Author  string
		Avatar  string
		Email   string
		Message string
	}

	// Build information.
	Build struct {
		Tag      string
		Event    string
		Number   int
		Status   string
		Link     string
		Started  float64
		Finished float64
		PR       string
		DeployTo string
	}

	// Config for the plugin.
	Config struct {
		WebhookID    string
		WebhookToken string
		Color        string
		Message      []string
		File         []string
		Drone        bool
		GitHub       bool
	}

	// EmbedFooterObject for Embed Footer Structure.
	EmbedFooterObject struct {
		Text    string `json:"text"`
		IconURL string `json:"icon_url"`
	}

	// EmbedAuthorObject for Embed Author Structure
	EmbedAuthorObject struct {
		Name    string `json:"name"`
		URL     string `json:"url"`
		IconURL string `json:"icon_url"`
	}

	// EmbedFieldObject for Embed Field Structure
	EmbedFieldObject struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}

	// EmbedObject is for Embed Structure
	EmbedObject struct {
		Title       string             `json:"title"`
		Description string             `json:"description"`
		URL         string             `json:"url"`
		Color       int                `json:"color"`
		Footer      EmbedFooterObject  `json:"footer"`
		Author      EmbedAuthorObject  `json:"author"`
		Fields      []EmbedFieldObject `json:"fields"`
	}

	// Payload struct
	Payload struct {
		Wait      bool          `json:"wait"`
		Content   string        `json:"content"`
		Username  string        `json:"username"`
		AvatarURL string        `json:"avatar_url"`
		TTS       bool          `json:"tts"`
		Embeds    []EmbedObject `json:"embeds"`
	}

	// Plugin values.
	Plugin struct {
		GitHub  GitHub
		Repo    Repo
		Build   Build
		Config  Config
		Payload Payload
		Commit  Commit
	}
)

func templateMessage(t string, plugin Plugin) (string, error) {
	return template.RenderTrim(t, plugin)
}

// Creates a new file upload http request with optional extra params
// https://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(paramName, filepath.Base(path))
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)

	for key, val := range params {
		_ = writer.WriteField(key, val)
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", uri, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, err
}

// Exec executes the plugin.
func (p *Plugin) Exec() error {
	if p.Config.WebhookID == "" || p.Config.WebhookToken == "" {
		return errors.New("missing discord config")
	}

	if len(p.Config.Message) == 0 {
		object := p.Template()
		p.Payload.Embeds = []EmbedObject{object}
		err := p.SendMessage()
		if err != nil {
			return err
		}
	}

	if len(p.Config.Message) > 0 {
		for _, m := range p.Config.Message {
			txt, err := templateMessage(m, *p)
			if err != nil {
				return err
			}

			if len(p.Config.Color) != 0 {
				object := p.DefaultTemplate(txt)
				p.Payload.Embeds = append(p.Payload.Embeds, object)
			} else {
				p.Payload.Content = txt
				err = p.SendMessage()
				if err != nil {
					return err
				}
			}
		}

		if len(p.Payload.Embeds) > 0 {
			err := p.SendMessage()
			if err != nil {
				return err
			}
		}
	}

	for _, f := range p.Config.File {
		err := p.SendFile(f)
		if err != nil {
			return err
		}
	}

	return nil
}

// SendFile upload file to discord
func (p *Plugin) SendFile(file string) error {
	webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
	extraParams := map[string]string{}

	if p.Payload.Username != "" {
		extraParams["username"] = p.Payload.Username
	}

	if p.Payload.AvatarURL != "" {
		extraParams["avatar_url"] = p.Payload.AvatarURL
	}

	if p.Payload.TTS {
		extraParams["tts"] = "true"
	}

	request, err := newfileUploadRequest(
		webhookURL,
		extraParams,
		"file",
		file,
	)
	if err != nil {
		return err
	}
	client := &http.Client{}
	_, err = client.Do(request)
	if err != nil {
		return err
	}

	return nil
}

// SendMessage to send discord message.
func (p *Plugin) SendMessage() error {
	webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
	b := new(bytes.Buffer)
	if err := json.NewEncoder(b).Encode(p.Payload); err != nil {
		return err
	}
	_, err := http.Post(webhookURL, "application/json; charset=utf-8", b)

	if err != nil {
		return err
	}

	return nil
}

// DefaultTemplate is plugin default template for Drone CI.
func (p *Plugin) DefaultTemplate(title string) EmbedObject {
	return EmbedObject{
		Title: title,
		Color: p.Color(),
	}
}

// Template is plugin default template for Drone CI or GitHub Action.
func (p *Plugin) Template() EmbedObject {
	if p.Config.GitHub {
		message := fmt.Sprintf("%s/%s triggered by %s (%s)",
			p.Repo.FullName,
			p.GitHub.Workflow,
			p.Repo.Namespace,
			p.GitHub.EventName,
		)

		return EmbedObject{
			Title: message,
			Color: p.Color(),
			Footer: EmbedFooterObject{
				Text:    DroneDesc,
				IconURL: DroneIconURL,
			},
		}
	}

	description := ""
	switch p.Build.Event {
	case "push":
		description = fmt.Sprintf("%s pushed to %s", p.Commit.Author, p.Commit.Branch)
	case "pull_request":
		branch := ""
		if p.Commit.Ref != "" {
			branch = p.Commit.Ref
		} else {
			branch = p.Commit.Branch
		}
		description = fmt.Sprintf("%s updated pull request %s", p.Commit.Author, branch)
	case "tag":
		description = fmt.Sprintf("%s pushed tag %s", p.Commit.Author, p.Commit.Branch)
	}

	return EmbedObject{
		Title:       p.Commit.Message,
		Description: description,
		URL:         p.Build.Link,
		Color:       p.Color(),
		Author: EmbedAuthorObject{
			Name:    p.Commit.Author,
			IconURL: p.Commit.Avatar,
		},
		Footer: EmbedFooterObject{
			Text:    DroneDesc,
			IconURL: DroneIconURL,
		},
	}
}

// Clear reset to default
func (p *Plugin) Clear() {
	// clear content field.
	p.Payload.Content = ""
	p.Payload.Embeds = []EmbedObject{}
}

// Color code of the embed
func (p *Plugin) Color() int {
	if p.Config.Color != "" {
		p.Config.Color = strings.Replace(p.Config.Color, "#", "", -1)
		if s, err := strconv.ParseInt(p.Config.Color, 16, 32); err == nil {
			return int(s)
		}
	}

	switch p.Build.Status {
	case "success":
		// green
		return 0x1ac600
	case "failure", "error", "killed":
		// red
		return 0xff3232
	default:
		// yellow
		return 0xffd930
	}
}
<commit_msg>debug<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/drone/drone-template-lib/template"
)

const (
	// DroneIconURL default drone logo url
	DroneIconURL = "https://c1.staticflickr.com/5/4236/34957940160_435d83114f_z.jpg"
	// DroneDesc default drone description
	DroneDesc = "Powered by Drone Discord Plugin"
)

type (
	// GitHub information.
	GitHub struct {
		Workflow  string
		Workspace string
		Action    string
		EventName string
		EventPath string
	}

	// Repo information.
	Repo struct {
		FullName  string
		Namespace string
		Name      string
	}

	// Commit information.
	Commit struct {
		Sha     string
		Ref     string
		Branch  string
		Link    string
		Author  string
		Avatar  string
		Email   string
		Message string
	}

	// Build information.
	Build struct {
		Tag      string
		Event    string
		Number   int
		Status   string
		Link     string
		Started  float64
		Finished float64
		PR       string
		DeployTo string
	}

	// Config for the plugin.
	Config struct {
		WebhookID    string
		WebhookToken string
		Color        string
		Message      []string
		File         []string
		Drone        bool
		GitHub       bool
	}

	// EmbedFooterObject for Embed Footer Structure.
	EmbedFooterObject struct {
		Text    string `json:"text"`
		IconURL string `json:"icon_url"`
	}

	// EmbedAuthorObject for Embed Author Structure
	EmbedAuthorObject struct {
		Name    string `json:"name"`
		URL     string `json:"url"`
		IconURL string `json:"icon_url"`
	}

	// EmbedFieldObject for Embed Field Structure
	EmbedFieldObject struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}

	// EmbedObject is for Embed Structure
	EmbedObject struct {
		Title       string             `json:"title"`
		Description string             `json:"description"`
		URL         string             `json:"url"`
		Color       int                `json:"color"`
		Footer      EmbedFooterObject  `json:"footer"`
		Author      EmbedAuthorObject  `json:"author"`
		Fields      []EmbedFieldObject `json:"fields"`
	}

	// Payload struct
	Payload struct {
		Wait      bool          `json:"wait"`
		Content   string        `json:"content"`
		Username  string        `json:"username"`
		AvatarURL string        `json:"avatar_url"`
		TTS       bool          `json:"tts"`
		Embeds    []EmbedObject `json:"embeds"`
	}

	// Plugin values.
	Plugin struct {
		GitHub  GitHub
		Repo    Repo
		Build   Build
		Config  Config
		Payload Payload
		Commit  Commit
	}
)

func templateMessage(t string, plugin Plugin) (string, error) {
	return template.RenderTrim(t, plugin)
}

// Creates a new file upload http request with optional extra params
// https://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(paramName, filepath.Base(path))
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)

	for key, val := range params {
		_ = writer.WriteField(key, val)
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", uri, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, err
}

// Exec executes the plugin.
func (p *Plugin) Exec() error {
	if p.Config.WebhookID == "" || p.Config.WebhookToken == "" {
		return errors.New("missing discord config")
	}

	if len(p.Config.Message) == 0 {
		object := p.Template()
		p.Payload.Embeds = []EmbedObject{object}
		err := p.SendMessage()
		if err != nil {
			return err
		}
	}

	if len(p.Config.Message) > 0 {
		for _, m := range p.Config.Message {
			txt, err := templateMessage(m, *p)
			if err != nil {
				return err
			}

			if len(p.Config.Color) != 0 {
				object := p.DefaultTemplate(txt)
				p.Payload.Embeds = append(p.Payload.Embeds, object)
			} else {
				p.Payload.Content = txt
				err = p.SendMessage()
				if err != nil {
					return err
				}
			}
		}

		if len(p.Payload.Embeds) > 0 {
			err := p.SendMessage()
			if err != nil {
				return err
			}
		}
	}

	fmt.Println(p.Config.File)
	fmt.Println(len(p.Config.File))
	for _, f := range p.Config.File {
		err := p.SendFile(f)
		if err != nil {
			return err
		}
	}

	return nil
}

// SendFile upload file to discord
func (p *Plugin) SendFile(file string) error {
	webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
	extraParams := map[string]string{}

	if p.Payload.Username != "" {
		extraParams["username"] = p.Payload.Username
	}

	if p.Payload.AvatarURL != "" {
		extraParams["avatar_url"] = p.Payload.AvatarURL
	}

	if p.Payload.TTS {
		extraParams["tts"] = "true"
	}

	request, err := newfileUploadRequest(
		webhookURL,
		extraParams,
		"file",
		file,
	)
	if err != nil {
		return err
	}
	client := &http.Client{}
	_, err = client.Do(request)
	if err != nil {
		return err
	}

	return nil
}

// SendMessage to send discord message.
func (p *Plugin) SendMessage() error {
	webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
	b := new(bytes.Buffer)
	if err := json.NewEncoder(b).Encode(p.Payload); err != nil {
		return err
	}
	_, err := http.Post(webhookURL, "application/json; charset=utf-8", b)

	if err != nil {
		return err
	}

	return nil
}

// DefaultTemplate is plugin default template for Drone CI.
func (p *Plugin) DefaultTemplate(title string) EmbedObject {
	return EmbedObject{
		Title: title,
		Color: p.Color(),
	}
}

// Template is plugin default template for Drone CI or GitHub Action.
func (p *Plugin) Template() EmbedObject {
	if p.Config.GitHub {
		message := fmt.Sprintf("%s/%s triggered by %s (%s)",
			p.Repo.FullName,
			p.GitHub.Workflow,
			p.Repo.Namespace,
			p.GitHub.EventName,
		)

		return EmbedObject{
			Title: message,
			Color: p.Color(),
			Footer: EmbedFooterObject{
				Text:    DroneDesc,
				IconURL: DroneIconURL,
			},
		}
	}

	description := ""
	switch p.Build.Event {
	case "push":
		description = fmt.Sprintf("%s pushed to %s", p.Commit.Author, p.Commit.Branch)
	case "pull_request":
		branch := ""
		if p.Commit.Ref != "" {
			branch = p.Commit.Ref
		} else {
			branch = p.Commit.Branch
		}
		description = fmt.Sprintf("%s updated pull request %s", p.Commit.Author, branch)
	case "tag":
		description = fmt.Sprintf("%s pushed tag %s", p.Commit.Author, p.Commit.Branch)
	}

	return EmbedObject{
		Title:       p.Commit.Message,
		Description: description,
		URL:         p.Build.Link,
		Color:       p.Color(),
		Author: EmbedAuthorObject{
			Name:    p.Commit.Author,
			IconURL: p.Commit.Avatar,
		},
		Footer: EmbedFooterObject{
			Text:    DroneDesc,
			IconURL: DroneIconURL,
		},
	}
}

// Clear reset to default
func (p *Plugin) Clear() {
	// clear content field.
	p.Payload.Content = ""
	p.Payload.Embeds = []EmbedObject{}
}

// Color code of the embed
func (p *Plugin) Color() int {
	if p.Config.Color != "" {
		p.Config.Color = strings.Replace(p.Config.Color, "#", "", -1)
		if s, err := strconv.ParseInt(p.Config.Color, 16, 32); err == nil {
			return int(s)
		}
	}

	switch p.Build.Status {
	case "success":
		// green
		return 0x1ac600
	case "failure", "error", "killed":
		// red
		return 0xff3232
	default:
		// yellow
		return 0xffd930
	}
}
<|endoftext|>


<commit_before>package sqlstmt

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strings"

	"github.com/jjeffery/sqlstmt/private/column"
	"github.com/jjeffery/sqlstmt/private/scanner"
)

var errNotImplemented = errors.New("not implemented")

// InsertRowStmt inserts a single row. It is safe for concurrent
// access by multiple goroutines.
type InsertRowStmt struct {
	commonStmt
	autoIncrColumn *column.Info
}

// NewInsertRowStmt returns a new InsertRowStmt for the given
// row and SQL.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are inferred
// from DefaultSchema.
func NewInsertRowStmt(row interface{}, sql string) *InsertRowStmt {
	return newInsertRowStmt(DefaultSchema, row, sql)
}

func newInsertRowStmt(schema *Schema, row interface{}, sql string) *InsertRowStmt {
	stmt := &InsertRowStmt{}
	sql = checkSQL(sql, insertFormat)
	stmt.err = stmt.prepareExecRow(schema, row, sql)

	for _, col := range stmt.columns {
		if col.AutoIncrement {
			stmt.autoIncrColumn = col
			break
		}
	}

	if stmt.autoIncrColumn != nil {
		// Some DBs allow the auto-increment column to be specified.
		// Work out if this statement is doing this.
		for _, col := range stmt.inputs {
			if col == stmt.autoIncrColumn {
				// this statement is setting the auto-increment column explicitly
				stmt.autoIncrColumn = nil
				break
			}
		}
	}

	return stmt
}

// Exec executes the insert statement using the row as arguments.
func (stmt *InsertRowStmt) Exec(db Execer, row interface{}) error {
	// field for setting the auto-increment value
	var field reflect.Value
	if stmt.autoIncrColumn != nil {
		rowVal := reflect.ValueOf(row)
		field = stmt.autoIncrColumn.Index.ValueRW(rowVal)
		if !field.CanSet() {
			return fmt.Errorf("cannot set auto-increment value for type %s", rowVal.Type().Name())
		}
	}

	result, err := stmt.doExec(db, row)
	if err != nil {
		return err
	}

	if field.IsValid() {
		n, err := result.LastInsertId()
		if err != nil {
			return err
		}
		// TODO: could catch a panic here if the type is not int8, 1nt16, int32, int64
		field.SetInt(n)
	}
	return nil
}

// ExecRowStmt updates or deletes a single row. It is safe for concurrent
// access by multiple goroutines.
type ExecRowStmt struct {
	commonStmt
}

// NewUpdateRowStmt returns a new ExecRowStmt for updating a single row.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are obtained from DefaultSchema.
func NewUpdateRowStmt(row interface{}, sql string) *ExecRowStmt {
	return newUpdateRowStmt(DefaultSchema, row, sql)
}

func newUpdateRowStmt(schema *Schema, row interface{}, sql string) *ExecRowStmt {
	stmt := &ExecRowStmt{}
	sql = checkSQL(sql, updateFormat)
	stmt.err = stmt.prepareExecRow(schema, row, sql)
	return stmt
}

// NewDeleteRowStmt returns a new ExecRowStmt for deleting a single
// row.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are obtained from DefaultSchema.
func NewDeleteRowStmt(row interface{}, sql string) *ExecRowStmt {
	return newDeleteRowStmt(DefaultSchema, row, sql)
}

func newDeleteRowStmt(schema *Schema, row interface{}, sql string) *ExecRowStmt {
	stmt := &ExecRowStmt{}
	sql = checkSQL(sql, deleteFormat)
	stmt.err = stmt.prepareExecRow(schema, row, sql)
	return stmt
}

// Exec executes the statement using the row as arguments. Returns the
// number of rows affected.
func (stmt *ExecRowStmt) Exec(db Execer, row interface{}) (int, error) {
	result, err := stmt.doExec(db, row)
	if err != nil {
		return 0, err
	}

	n, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(n), nil
}

// GetRowStmt executes a query that returns a single row.
// It is safe for concurrent access by multiple goroutines.
type GetRowStmt struct {
	commonStmt
}

// NewGetRowStmt returns a new GetRowStmt for the given
// row and SQL.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are obtained
// from DefaultSchema.
func NewGetRowStmt(row interface{}, sql string) *GetRowStmt {
	return newGetRowStmt(DefaultSchema, row, sql)
}

func newGetRowStmt(schema *Schema, row interface{}, sql string) *GetRowStmt {
	stmt := &GetRowStmt{}
	sql = checkSQL(sql, getFormat)
	stmt.err = stmt.prepareCommon(schema, row, sql)
	return stmt
}

// Get a single row into dest based on the fields populated in dest.
func (stmt *GetRowStmt) Get(db Queryer, dest interface{}) (int, error) {
	errorPtrType := func() error {
		expectedTypeName := stmt.expectedTypeName()
		return fmt.Errorf("expected dest to be *%s", expectedTypeName)
	}

	destValue := reflect.ValueOf(dest)

	if destValue.Kind() != reflect.Ptr {
		return 0, errorPtrType()
	}
	if destValue.IsNil() {
		return 0, errors.New("nil pointer passed")
	}

	rowValue := reflect.Indirect(destValue)
	rowType := rowValue.Type()
	if rowType != stmt.rowType {
		return 0, errorPtrType()
	}

	args, err := stmt.getArgs(dest)
	if err != nil {
		return 0, nil
	}

	if stmt.Logger != nil {
		msg := fmt.Sprintf("query=%q, args=%v\n", stmt.query, args)
		stmt.Logger.Print(msg)
	}
	rows, err := db.Query(stmt.query, args...)
	if err != nil {
		return 0, err
	}
	defer rows.Close()

	scanValues := make([]interface{}, len(stmt.outputs))

	if !rows.Next() {
		// no rows returned
		return 0, nil
	}

	for i, col := range stmt.outputs {
		cellValue := col.Index.ValueRW(rowValue)
		scanValues[i] = cellValue.Addr().Interface()
	}
	err = rows.Scan(scanValues...)
	if err != nil {
		return 0, err
	}

	return 1, nil
}

// SelectStmt executes a query that returns multiple rows.
// It is safe for concurrent access by multiple goroutines.
type SelectStmt struct {
	commonStmt
}

// NewSelectStmt returns a new SelectStmt for the given
// row and SQL. The dialect and naming conventions are obtained
// from DefaultSchema.
func NewSelectStmt(row interface{}, sql string) *SelectStmt {
	return newSelectStmt(DefaultSchema, row, sql)
}

func newSelectStmt(schema *Schema, row interface{}, sql string) *SelectStmt {
	stmt := &SelectStmt{}
	sql = checkSQL(sql, selectFormat)
	stmt.err = stmt.prepareCommon(schema, row, sql)
	if stmt.err == nil && len(stmt.inputs) > 0 {
		stmt.err = errors.New("unexpected inputs in query")
	}
	return stmt
}

// Select executes the statement's query and returns the resulting
// rows in the slice pointed to by dest. The args are for any
// placeholder parameters in the query.
func (stmt *SelectStmt) Select(db Queryer, dest interface{}, args ...interface{}) error {
	destValue := reflect.ValueOf(dest)

	if destValue.Kind() != reflect.Ptr {
		return stmt.errorSliceType()
	}
	if destValue.IsNil() {
		return errors.New("Select: nil pointer passed as dest")
	}

	sliceValue := reflect.Indirect(destValue)
	sliceType := sliceValue.Type()
	if sliceType.Kind() != reflect.Slice {
		return stmt.errorSliceType()
	}

	rowType := sliceType.Elem()
	isPtr := rowType.Kind() == reflect.Ptr
	if isPtr {
		rowType = rowType.Elem()
	}
	if rowType != stmt.rowType {
		return stmt.errorSliceType()
	}

	rows, err := db.Query(stmt.query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	scanValues := make([]interface{}, len(stmt.columns))

	for rows.Next() {
		rowValuePtr := reflect.New(rowType)
		rowValue := reflect.Indirect(rowValuePtr)
		for i, col := range stmt.columns {
			cellValue := col.Index.ValueRW(rowValue)
			scanValues[i] = cellValue.Addr().Interface()
		}
		err = rows.Scan(scanValues...)
		if err != nil {
			return err
		}
		if isPtr {
			sliceValue.Set(reflect.Append(sliceValue, rowValuePtr))
		} else {
			sliceValue.Set(reflect.Append(sliceValue, rowValue))
		}
	}

	return rows.Err()
}

func (stmt *SelectStmt) errorSliceType() error {
	expectedType := stmt.expectedTypeName()
	return fmt.Errorf("Expected dest to be pointer to []%s or []*%s", expectedType, expectedType)
}

type commonStmt struct {
	// Logger is used for diagnostic logging.
	Logger Logger

	rowType    reflect.Type
	query      string
	dialect    Dialect
	convention Convention
	columns    []*column.Info
	inputs     []*column.Info
	outputs    []*column.Info
	err        error
}

// String prints the SQL query associated with the statement.
func (stmt *commonStmt) String() string {
	return stmt.query
}

func (stmt *commonStmt) prepareCommon(schema *Schema, row interface{}, sql string) error {
	stmt.rowType = reflect.TypeOf(row)
	if stmt.rowType.Kind() == reflect.Ptr {
		stmt.rowType = stmt.rowType.Elem()
	}
	stmt.columns = column.ListForType(stmt.rowType)
	stmt.convention = schema.convention()
	stmt.dialect = schema.dialect()
	stmt.Logger = schema.Logger
	if err := stmt.scanSQL(sql); err != nil {
		return err
	}
	if stmt.Logger != nil {
		msg := fmt.Sprintf("prepared=%q", stmt.query)
		stmt.Logger.Print(msg)
	}
	return nil
}

func (stmt *commonStmt) prepareExecRow(schema *Schema, row interface{}, sql string) error {
	if err := stmt.prepareCommon(schema, row, sql); err != nil {
		return err
	}
	if len(stmt.outputs) > 0 {
		return errors.New("unexpected query columns in exec statement")
	}
	return nil
}

func (stmt *commonStmt) addColumns(cols columnsT) {
	if cols.clause.isInput() {
		for _, col := range cols.filtered() {
			stmt.inputs = append(stmt.inputs, col)
		}
	} else if cols.clause.isOutput() {
		for _, col := range cols.filtered() {
			stmt.outputs = append(stmt.outputs, col)
		}
	}
}

// counter is used for keeping track of placeholders
type counter int

func (c *counter) Next() int {
	*c++
	return int(*c)
}

func (stmt *commonStmt) scanSQL(query string) error {
	query = strings.TrimSpace(query)
	scan := scanner.New(strings.NewReader(query))
	var counter counter
	columns := newColumns(stmt.columns, stmt.convention, stmt.dialect, counter.Next)
	var insertColumns *columnsT
	var clause sqlClause
	var buf bytes.Buffer
	for {
		tok, lit := scan.Scan()
		if tok == scanner.EOF {
			break
		}
		switch tok {
		case scanner.WS:
			buf.WriteRune(' ')
		case scanner.COMMENT:
			// strip comment
		case scanner.LITERAL, scanner.OP:
			buf.WriteString(lit)
		case scanner.PLACEHOLDER:
			buf.WriteString(stmt.dialect.Placeholder(counter.Next()))
		case scanner.IDENT:
			if lit[0] == '{' {
				if !clause.acceptsColumns() {
					// invalid place to insert columns
					return fmt.Errorf("cannot expand %q in %q clause", lit, clause)
				}
				lit = strings.TrimSpace(scanner.Unquote(lit))
				if clause == clauseInsertValues {
					if lit != "" {
						return fmt.Errorf("columns for %q clause always match the %q clause",
							clause, clauseInsertColumns)
					}
					if insertColumns == nil {
						return fmt.Errorf("cannot expand %q clause because %q clause is missing",
							clause, clauseInsertColumns)
					}

					// change the clause but keep the filter and generate string
					cols := *insertColumns
					cols.clause = clause
					buf.WriteString(cols.String())
					stmt.addColumns(cols)
				} else {
					cols, err := columns.Parse(clause, lit)
					if err != nil {
						return fmt.Errorf("cannot expand %q in %q clause: %v", lit, clause, err)
					}
					buf.WriteString(cols.String())
					stmt.addColumns(cols)
					if clause == clauseInsertColumns {
						insertColumns = &cols
					}
				}
			} else if scanner.IsQuoted(lit) {
				lit = scanner.Unquote(lit)
				buf.WriteString(stmt.dialect.Quote(lit))
			} else {
				buf.WriteString(lit)

				// an unquoted identifer might be an SQL keyword
				clause = clause.nextClause(lit)
			}
		}
	}
	stmt.query = buf.String()
	return nil
}

func (stmt commonStmt) doExec(db Execer, row interface{}) (sql.Result, error) {
	if stmt.err != nil {
		return nil, stmt.err
	}
	args, err := stmt.getArgs(row)
	if err != nil {
		return nil, err
	}
	if stmt.Logger != nil {
		msg := fmt.Sprintf("query=%q, args=%v\n", stmt.query, args)
		stmt.Logger.Print(msg)
	}
	return db.Exec(stmt.query, args...)
}

func (stmt commonStmt) getArgs(row interface{}) ([]interface{}, error) {
	if stmt.err != nil {
		return nil, stmt.err
	}

	var args []interface{}

	rowVal := reflect.ValueOf(row)
	for rowVal.Type().Kind() == reflect.Ptr {
		rowVal = rowVal.Elem()
	}
	if rowVal.Type() != stmt.rowType {
		expectedType := stmt.expectedTypeName()
		return nil, fmt.Errorf("expected type %s or *(%s)", expectedType, expectedType)
	}

	for _, input := range stmt.inputs {
		args = append(args, input.Index.ValueRO(rowVal).Interface())
	}

	return args, nil
}

func (stmt commonStmt) expectedTypeName() string {
	return fmt.Sprintf("%s.%s", stmt.rowType.PkgPath(), stmt.rowType.Name())
}
<commit_msg>Fix bug in stmt.go<commit_after>package sqlstmt

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strings"

	"github.com/jjeffery/sqlstmt/private/column"
	"github.com/jjeffery/sqlstmt/private/scanner"
)

var errNotImplemented = errors.New("not implemented")

// InsertRowStmt inserts a single row. It is safe for concurrent
// access by multiple goroutines.
type InsertRowStmt struct {
	commonStmt
	autoIncrColumn *column.Info
}

// NewInsertRowStmt returns a new InsertRowStmt for the given
// row and SQL.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are inferred
// from DefaultSchema.
func NewInsertRowStmt(row interface{}, sql string) *InsertRowStmt {
	return newInsertRowStmt(DefaultSchema, row, sql)
}

func newInsertRowStmt(schema *Schema, row interface{}, sql string) *InsertRowStmt {
	stmt := &InsertRowStmt{}
	sql = checkSQL(sql, insertFormat)
	stmt.err = stmt.prepareExecRow(schema, row, sql)

	for _, col := range stmt.columns {
		if col.AutoIncrement {
			stmt.autoIncrColumn = col
			break
		}
	}

	if stmt.autoIncrColumn != nil {
		// Some DBs allow the auto-increment column to be specified.
		// Work out if this statement is doing this.
		for _, col := range stmt.inputs {
			if col == stmt.autoIncrColumn {
				// this statement is setting the auto-increment column explicitly
				stmt.autoIncrColumn = nil
				break
			}
		}
	}

	return stmt
}

// Exec executes the insert statement using the row as arguments.
func (stmt *InsertRowStmt) Exec(db Execer, row interface{}) error {
	// field for setting the auto-increment value
	var field reflect.Value
	if stmt.autoIncrColumn != nil {
		rowVal := reflect.ValueOf(row)
		field = stmt.autoIncrColumn.Index.ValueRW(rowVal)
		if !field.CanSet() {
			return fmt.Errorf("cannot set auto-increment value for type %s", rowVal.Type().Name())
		}
	}

	result, err := stmt.doExec(db, row)
	if err != nil {
		return err
	}

	if field.IsValid() {
		n, err := result.LastInsertId()
		if err != nil {
			return err
		}
		// TODO: could catch a panic here if the type is not int8, 1nt16, int32, int64
		field.SetInt(n)
	}
	return nil
}

// ExecRowStmt updates or deletes a single row. It is safe for concurrent
// access by multiple goroutines.
type ExecRowStmt struct {
	commonStmt
}

// NewUpdateRowStmt returns a new ExecRowStmt for updating a single row.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are obtained from DefaultSchema.
func NewUpdateRowStmt(row interface{}, sql string) *ExecRowStmt {
	return newUpdateRowStmt(DefaultSchema, row, sql)
}

func newUpdateRowStmt(schema *Schema, row interface{}, sql string) *ExecRowStmt {
	stmt := &ExecRowStmt{}
	sql = checkSQL(sql, updateFormat)
	stmt.err = stmt.prepareExecRow(schema, row, sql)
	return stmt
}

// NewDeleteRowStmt returns a new ExecRowStmt for deleting a single
// row.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are obtained from DefaultSchema.
func NewDeleteRowStmt(row interface{}, sql string) *ExecRowStmt {
	return newDeleteRowStmt(DefaultSchema, row, sql)
}

func newDeleteRowStmt(schema *Schema, row interface{}, sql string) *ExecRowStmt {
	stmt := &ExecRowStmt{}
	sql = checkSQL(sql, deleteFormat)
	stmt.err = stmt.prepareExecRow(schema, row, sql)
	return stmt
}

// Exec executes the statement using the row as arguments. Returns the
// number of rows affected.
func (stmt *ExecRowStmt) Exec(db Execer, row interface{}) (int, error) {
	result, err := stmt.doExec(db, row)
	if err != nil {
		return 0, err
	}

	n, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(n), nil
}

// GetRowStmt executes a query that returns a single row.
// It is safe for concurrent access by multiple goroutines.
type GetRowStmt struct {
	commonStmt
}

// NewGetRowStmt returns a new GetRowStmt for the given
// row and SQL.
// It is safe for concurrent access by multiple goroutines.
// The dialect and naming conventions are obtained
// from DefaultSchema.
func NewGetRowStmt(row interface{}, sql string) *GetRowStmt {
	return newGetRowStmt(DefaultSchema, row, sql)
}

func newGetRowStmt(schema *Schema, row interface{}, sql string) *GetRowStmt {
	stmt := &GetRowStmt{}
	sql = checkSQL(sql, getFormat)
	stmt.err = stmt.prepareCommon(schema, row, sql)
	return stmt
}

// Get a single row into dest based on the fields populated in dest.
func (stmt *GetRowStmt) Get(db Queryer, dest interface{}) (int, error) {
	errorPtrType := func() error {
		expectedTypeName := stmt.expectedTypeName()
		return fmt.Errorf("expected dest to be *%s", expectedTypeName)
	}

	destValue := reflect.ValueOf(dest)

	if destValue.Kind() != reflect.Ptr {
		return 0, errorPtrType()
	}
	if destValue.IsNil() {
		return 0, errors.New("nil pointer passed")
	}

	rowValue := reflect.Indirect(destValue)
	rowType := rowValue.Type()
	if rowType != stmt.rowType {
		return 0, errorPtrType()
	}

	args, err := stmt.getArgs(dest)
	if err != nil {
		return 0, err
	}

	if stmt.Logger != nil {
		msg := fmt.Sprintf("query=%q, args=%v\n", stmt.query, args)
		stmt.Logger.Print(msg)
	}
	rows, err := db.Query(stmt.query, args...)
	if err != nil {
		return 0, err
	}
	defer rows.Close()

	scanValues := make([]interface{}, len(stmt.outputs))

	if !rows.Next() {
		// no rows returned
		return 0, nil
	}

	for i, col := range stmt.outputs {
		cellValue := col.Index.ValueRW(rowValue)
		scanValues[i] = cellValue.Addr().Interface()
	}
	err = rows.Scan(scanValues...)
	if err != nil {
		return 0, err
	}

	return 1, nil
}

// SelectStmt executes a query that returns multiple rows.
// It is safe for concurrent access by multiple goroutines.
type SelectStmt struct {
	commonStmt
}

// NewSelectStmt returns a new SelectStmt for the given
// row and SQL. The dialect and naming conventions are obtained
// from DefaultSchema.
func NewSelectStmt(row interface{}, sql string) *SelectStmt {
	return newSelectStmt(DefaultSchema, row, sql)
}

func newSelectStmt(schema *Schema, row interface{}, sql string) *SelectStmt {
	stmt := &SelectStmt{}
	sql = checkSQL(sql, selectFormat)
	stmt.err = stmt.prepareCommon(schema, row, sql)
	if stmt.err == nil && len(stmt.inputs) > 0 {
		stmt.err = errors.New("unexpected inputs in query")
	}
	return stmt
}

// Select executes the statement's query and returns the resulting
// rows in the slice pointed to by dest. The args are for any
// placeholder parameters in the query.
func (stmt *SelectStmt) Select(db Queryer, dest interface{}, args ...interface{}) error {
	destValue := reflect.ValueOf(dest)

	if destValue.Kind() != reflect.Ptr {
		return stmt.errorSliceType()
	}
	if destValue.IsNil() {
		return errors.New("Select: nil pointer passed as dest")
	}

	sliceValue := reflect.Indirect(destValue)
	sliceType := sliceValue.Type()
	if sliceType.Kind() != reflect.Slice {
		return stmt.errorSliceType()
	}

	rowType := sliceType.Elem()
	isPtr := rowType.Kind() == reflect.Ptr
	if isPtr {
		rowType = rowType.Elem()
	}
	if rowType != stmt.rowType {
		return stmt.errorSliceType()
	}

	rows, err := db.Query(stmt.query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	scanValues := make([]interface{}, len(stmt.columns))

	for rows.Next() {
		rowValuePtr := reflect.New(rowType)
		rowValue := reflect.Indirect(rowValuePtr)
		for i, col := range stmt.columns {
			cellValue := col.Index.ValueRW(rowValue)
			scanValues[i] = cellValue.Addr().Interface()
		}
		err = rows.Scan(scanValues...)
		if err != nil {
			return err
		}
		if isPtr {
			sliceValue.Set(reflect.Append(sliceValue, rowValuePtr))
		} else {
			sliceValue.Set(reflect.Append(sliceValue, rowValue))
		}
	}

	return rows.Err()
}

func (stmt *SelectStmt) errorSliceType() error {
	expectedType := stmt.expectedTypeName()
	return fmt.Errorf("Expected dest to be pointer to []%s or []*%s", expectedType, expectedType)
}

type commonStmt struct {
	// Logger is used for diagnostic logging.
	Logger Logger

	rowType    reflect.Type
	query      string
	dialect    Dialect
	convention Convention
	columns    []*column.Info
	inputs     []*column.Info
	outputs    []*column.Info
	err        error
}

// String prints the SQL query associated with the statement.
func (stmt *commonStmt) String() string {
	return stmt.query
}

func (stmt *commonStmt) prepareCommon(schema *Schema, row interface{}, sql string) error {
	stmt.rowType = reflect.TypeOf(row)
	if stmt.rowType.Kind() == reflect.Ptr {
		stmt.rowType = stmt.rowType.Elem()
	}
	stmt.columns = column.ListForType(stmt.rowType)
	stmt.convention = schema.convention()
	stmt.dialect = schema.dialect()
	stmt.Logger = schema.Logger
	if err := stmt.scanSQL(sql); err != nil {
		return err
	}
	if stmt.Logger != nil {
		msg := fmt.Sprintf("prepared=%q", stmt.query)
		stmt.Logger.Print(msg)
	}
	return nil
}

func (stmt *commonStmt) prepareExecRow(schema *Schema, row interface{}, sql string) error {
	if err := stmt.prepareCommon(schema, row, sql); err != nil {
		return err
	}
	if len(stmt.outputs) > 0 {
		return errors.New("unexpected query columns in exec statement")
	}
	return nil
}

func (stmt *commonStmt) addColumns(cols columnsT) {
	if cols.clause.isInput() {
		for _, col := range cols.filtered() {
			stmt.inputs = append(stmt.inputs, col)
		}
	} else if cols.clause.isOutput() {
		for _, col := range cols.filtered() {
			stmt.outputs = append(stmt.outputs, col)
		}
	}
}

// counter is used for keeping track of placeholders
type counter int

func (c *counter) Next() int {
	*c++
	return int(*c)
}

func (stmt *commonStmt) scanSQL(query string) error {
	query = strings.TrimSpace(query)
	scan := scanner.New(strings.NewReader(query))
	var counter counter
	columns := newColumns(stmt.columns, stmt.convention, stmt.dialect, counter.Next)
	var insertColumns *columnsT
	var clause sqlClause
	var buf bytes.Buffer
	for {
		tok, lit := scan.Scan()
		if tok == scanner.EOF {
			break
		}
		switch tok {
		case scanner.WS:
			buf.WriteRune(' ')
		case scanner.COMMENT:
			// strip comment
		case scanner.LITERAL, scanner.OP:
			buf.WriteString(lit)
		case scanner.PLACEHOLDER:
			buf.WriteString(stmt.dialect.Placeholder(counter.Next()))
		case scanner.IDENT:
			if lit[0] == '{' {
				if !clause.acceptsColumns() {
					// invalid place to insert columns
					return fmt.Errorf("cannot expand %q in %q clause", lit, clause)
				}
				lit = strings.TrimSpace(scanner.Unquote(lit))
				if clause == clauseInsertValues {
					if lit != "" {
						return fmt.Errorf("columns for %q clause always match the %q clause",
							clause, clauseInsertColumns)
					}
					if insertColumns == nil {
						return fmt.Errorf("cannot expand %q clause because %q clause is missing",
							clause, clauseInsertColumns)
					}

					// change the clause but keep the filter and generate string
					cols := *insertColumns
					cols.clause = clause
					buf.WriteString(cols.String())
					stmt.addColumns(cols)
				} else {
					cols, err := columns.Parse(clause, lit)
					if err != nil {
						return fmt.Errorf("cannot expand %q in %q clause: %v", lit, clause, err)
					}
					buf.WriteString(cols.String())
					stmt.addColumns(cols)
					if clause == clauseInsertColumns {
						insertColumns = &cols
					}
				}
			} else if scanner.IsQuoted(lit) {
				lit = scanner.Unquote(lit)
				buf.WriteString(stmt.dialect.Quote(lit))
			} else {
				buf.WriteString(lit)

				// an unquoted identifer might be an SQL keyword
				clause = clause.nextClause(lit)
			}
		}
	}
	stmt.query = buf.String()
	return nil
}

func (stmt commonStmt) doExec(db Execer, row interface{}) (sql.Result, error) {
	if stmt.err != nil {
		return nil, stmt.err
	}
	args, err := stmt.getArgs(row)
	if err != nil {
		return nil, err
	}
	if stmt.Logger != nil {
		msg := fmt.Sprintf("query=%q, args=%v\n", stmt.query, args)
		stmt.Logger.Print(msg)
	}
	return db.Exec(stmt.query, args...)
}

func (stmt commonStmt) getArgs(row interface{}) ([]interface{}, error) {
	if stmt.err != nil {
		return nil, stmt.err
	}

	var args []interface{}

	rowVal := reflect.ValueOf(row)
	for rowVal.Type().Kind() == reflect.Ptr {
		rowVal = rowVal.Elem()
	}
	if rowVal.Type() != stmt.rowType {
		expectedType := stmt.expectedTypeName()
		return nil, fmt.Errorf("expected type %s or *(%s)", expectedType, expectedType)
	}

	for _, input := range stmt.inputs {
		args = append(args, input.Index.ValueRO(rowVal).Interface())
	}

	return args, nil
}

func (stmt commonStmt) expectedTypeName() string {
	return fmt.Sprintf("%s.%s", stmt.rowType.PkgPath(), stmt.rowType.Name())
}
<|endoftext|>


<commit_before>package blync

import (
	"fmt"
	"github.com/boombuler/hid"
	"os"
)

const (
	blyncVendorId  = 0x0E53
	blyncProductId = 0x2517
)

const (
	BlinkOff    = 0x00
	BlinkFast   = 0x46
	BlinkMedium = 0x64
	BlinkSlow   = 0x96
)

var Red = [3]byte{0xFF, 0x00, 0x00}
var Green = [3]byte{0x00, 0xFF, 0x00}
var Blue = [3]byte{0x00, 0x00, 0xFF}

type BlyncLight struct {
	devices []hid.Device
	bytes   []byte
}

func NewBlyncLight() (blync BlyncLight) {
	blync.devices = findDevices()
	blync.bytes = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0xFF}
	return
}

func findDevices() []hid.Device {
	devices := []hid.Device{}
	deviceInfos := hid.Devices()
	for {
		info, more := <-deviceInfos
		if more {
			device, error := info.Open()
			if error != nil {
				fmt.Println(error)
			}
			if !isBlyncDevice(*info) {
				fmt.Printf("%s %s is not a BlyncLight device.\n", info.Manufacturer, info.Product)
			} else {
				devices = append(devices, device)
				fmt.Printf("%s %s is a BlyncLight device.\n", info.Manufacturer, info.Product)
			}
		} else {
			break
		}
	}
	if len(devices) == 0 {
		fmt.Println("No BlyncLights found.")
		os.Exit(1)
	}
	return devices
}

func isBlyncDevice(deviceInfo hid.DeviceInfo) bool {
	// TODO from forums: "Blync creates 2 HID devices and the only way to find out the right device is the MaxFeatureReportLength = 0"
	if deviceInfo.VendorId == blyncVendorId && deviceInfo.ProductId == blyncProductId && deviceInfo.FeatureReportLength == 0 {
		return true
	}
	return false
}

func (b BlyncLight) sendFeatureReport() {
	for _, device := range b.devices {
		error := device.Write(b.bytes)
		if error != nil {
			fmt.Println(error)
		}
	}
}

func (b BlyncLight) Close() {
	b.Reset()
	for _, device := range b.devices {
		device.Close()
	}
}

func (b BlyncLight) Reset() {
	b.bytes = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0xFF}
	b.sendFeatureReport()
}

// color[0] = r
// color[1] = g
// color[2] = b
func (b BlyncLight) SetColor(color [3]byte) {
	b.bytes[1] = color[0]
	b.bytes[2] = color[2] // They reverse g and b
	b.bytes[3] = color[1]
	b.sendFeatureReport()
}

func (b BlyncLight) SetBlinkRate(rate byte) {
	b.bytes[4] = rate
	b.sendFeatureReport()
}

//16-30 play a tune single time
//49-59 plays never ending versions of the tunes
func (b BlyncLight) Play(mp3 byte) {
	b.bytes[5] = mp3
	b.sendFeatureReport()
}

func (b BlyncLight) StopPlay() {
	b.bytes[5] = 0x00
	b.sendFeatureReport()
}
<commit_msg>Removed an outdated TODO<commit_after>package blync

import (
	"fmt"
	"github.com/boombuler/hid"
	"os"
)

const (
	blyncVendorId  = 0x0E53
	blyncProductId = 0x2517
)

const (
	BlinkOff    = 0x00
	BlinkFast   = 0x46
	BlinkMedium = 0x64
	BlinkSlow   = 0x96
)

var Red = [3]byte{0xFF, 0x00, 0x00}
var Green = [3]byte{0x00, 0xFF, 0x00}
var Blue = [3]byte{0x00, 0x00, 0xFF}

type BlyncLight struct {
	devices []hid.Device
	bytes   []byte
}

func NewBlyncLight() (blync BlyncLight) {
	blync.devices = findDevices()
	blync.bytes = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0xFF}
	return
}

func findDevices() []hid.Device {
	devices := []hid.Device{}
	deviceInfos := hid.Devices()
	for {
		info, more := <-deviceInfos
		if more {
			device, error := info.Open()
			if error != nil {
				fmt.Println(error)
			}
			if !isBlyncDevice(*info) {
				fmt.Printf("%s %s is not a BlyncLight device.\n", info.Manufacturer, info.Product)
			} else {
				devices = append(devices, device)
				fmt.Printf("%s %s is a BlyncLight device.\n", info.Manufacturer, info.Product)
			}
		} else {
			break
		}
	}
	if len(devices) == 0 {
		fmt.Println("No BlyncLights found.")
		os.Exit(1)
	}
	return devices
}

func isBlyncDevice(deviceInfo hid.DeviceInfo) bool {
	// from forums: "Blync creates 2 HID devices and the only way to find out the right device is the MaxFeatureReportLength = 0"
	if deviceInfo.VendorId == blyncVendorId && deviceInfo.ProductId == blyncProductId && deviceInfo.FeatureReportLength == 0 {
		return true
	}
	return false
}

func (b BlyncLight) sendFeatureReport() {
	for _, device := range b.devices {
		error := device.Write(b.bytes)
		if error != nil {
			fmt.Println(error)
		}
	}
}

func (b BlyncLight) Close() {
	b.Reset()
	for _, device := range b.devices {
		device.Close()
	}
}

func (b BlyncLight) Reset() {
	b.bytes = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0xFF}
	b.sendFeatureReport()
}

// color[0] = r
// color[1] = g
// color[2] = b
func (b BlyncLight) SetColor(color [3]byte) {
	b.bytes[1] = color[0]
	b.bytes[2] = color[2] // They reverse g and b
	b.bytes[3] = color[1]
	b.sendFeatureReport()
}

func (b BlyncLight) SetBlinkRate(rate byte) {
	b.bytes[4] = rate
	b.sendFeatureReport()
}

//16-30 play a tune single time
//49-59 plays never ending versions of the tunes
func (b BlyncLight) Play(mp3 byte) {
	b.bytes[5] = mp3
	b.sendFeatureReport()
}

func (b BlyncLight) StopPlay() {
	b.bytes[5] = 0x00
	b.sendFeatureReport()
}
<|endoftext|>


<commit_before>package main

import "github.com/docker/go-dockercloud/dockercloud"
import "github.com/aws/aws-sdk-go/service/ec2"
import "github.com/aws/aws-sdk-go/aws/session"
import "log"
import "os"
import "strings"

/*
 * Return an environment variable. If it's not set - crash
 */
func getEnv(name string) string {
	value := os.Getenv(name)

	if len(value) == 0 {
		panic("Please set " + name + " variable")
	}

	return value
}

/*
 * Returns an array of public IP addresses
 */
func getNodeIps() []string {
	nodeList, err := dockercloud.ListNodes()

	if err != nil {
  		panic(err)
	}

	log.Println("Received public IP list from Docker Cloud")

	nodeIps := make([]string, 0)

	if len(nodeList.Objects) == 0 {
		log.Println("There are no nodes in your Docker Cloud account yet")
	}

	for i := 0; i < len(nodeList.Objects); i++ {
		if len(nodeList.Objects[i].Public_ip) > 0 {
			nodeIps = append(nodeIps, nodeList.Objects[i].Public_ip + "/32")
		}
    }

    return nodeIps
}

/*
 * Infinite loop - listening to Docker Cloud events
 */
func listenToEvents() {
	log.Println("Listening to Docker Cloud events")

	c := make(chan dockercloud.Event)
	e := make(chan error)

	go dockercloud.Events(c, e)

	for {
    	select {
        	case event := <-c:
            	log.Println(event)
	        case err := <-e:
    	        log.Println(err)
    	}
	}
}

/*
 * Rewrite inbound rules for the security group
 */
func modifySecurityGroup(groupId string, ips []string) {
	var newRules ec2.AuthorizeSecurityGroupIngressInput
	var oldRules ec2.RevokeSecurityGroupIngressInput
    var allProtocol string = "-1"

    log.Println("Flushing security group... ")

	svc := ec2.New(session.New())
    newRules.GroupId = &groupId
    oldRules.GroupId = &groupId

	params := &ec2.DescribeSecurityGroupsInput{ GroupIds: []*string{ &groupId }}
	resp, err := svc.DescribeSecurityGroups(params)

	for i := 0; i < len(resp.SecurityGroups[0].IpPermissions); i++ {
		existing := resp.SecurityGroups[0].IpPermissions[i]
		oldRules.IpPermissions = append(oldRules.IpPermissions, existing)
    }

	_, err = svc.RevokeSecurityGroupIngress(&oldRules)
	if err == nil {
		log.Println("success")
	}

	log.Println("Adding current node IPs to the group... ")

	// Add AWS internal network
	ips = append(ips, "10.0.0.0/8")

	for i := 0; i < len(ips); i++ {
	    entry := new(ec2.IpPermission)
    	entry.IpProtocol = &allProtocol
	    entry.IpRanges = []*ec2.IpRange{{CidrIp: &ips[i]}}
    	newRules.IpPermissions = append(newRules.IpPermissions, entry)
	}

    _, err = svc.AuthorizeSecurityGroupIngress(&newRules)
    if err != nil {
		panic(err)
	}

	log.Println("success")
}

/*
 * Initialize Docker Cloud SDK
 */
func initDockerCloud() {
	dockercloud.User = getEnv("DOCKER_CLOUD_USER")
	dockercloud.ApiKey = getEnv("DOCKER_CLOUD_KEY")

	if len(os.Getenv("DOCKER_CLOUD_NAMESPACE")) > 0 {
		dockercloud.Namespace = os.Getenv("DOCKER_CLOUD_NAMESPACE")
	}
}

/*
 * Main block
 */
func main() {
	initDockerCloud()

	groups := strings.split(getEnv("AWS_SG_ID"), ',')

	for i := 0; i < len(groups); i++ {
		modifySecurityGroup(groups[i], getNodeIps())
	}

	listenToEvents()
}
<commit_msg>r Typo<commit_after>package main

import "github.com/docker/go-dockercloud/dockercloud"
import "github.com/aws/aws-sdk-go/service/ec2"
import "github.com/aws/aws-sdk-go/aws/session"
import "log"
import "os"
import "strings"

/*
 * Return an environment variable. If it's not set - crash
 */
func getEnv(name string) string {
	value := os.Getenv(name)

	if len(value) == 0 {
		panic("Please set " + name + " variable")
	}

	return value
}

/*
 * Returns an array of public IP addresses
 */
func getNodeIps() []string {
	nodeList, err := dockercloud.ListNodes()

	if err != nil {
  		panic(err)
	}

	log.Println("Received public IP list from Docker Cloud")

	nodeIps := make([]string, 0)

	if len(nodeList.Objects) == 0 {
		log.Println("There are no nodes in your Docker Cloud account yet")
	}

	for i := 0; i < len(nodeList.Objects); i++ {
		if len(nodeList.Objects[i].Public_ip) > 0 {
			nodeIps = append(nodeIps, nodeList.Objects[i].Public_ip + "/32")
		}
    }

    return nodeIps
}

/*
 * Infinite loop - listening to Docker Cloud events
 */
func listenToEvents() {
	log.Println("Listening to Docker Cloud events")

	c := make(chan dockercloud.Event)
	e := make(chan error)

	go dockercloud.Events(c, e)

	for {
    	select {
        	case event := <-c:
            	log.Println(event)
	        case err := <-e:
    	        log.Println(err)
    	}
	}
}

/*
 * Rewrite inbound rules for the security group
 */
func modifySecurityGroup(groupId string, ips []string) {
	var newRules ec2.AuthorizeSecurityGroupIngressInput
	var oldRules ec2.RevokeSecurityGroupIngressInput
    var allProtocol string = "-1"

    log.Println("Flushing security group... ")

	svc := ec2.New(session.New())
    newRules.GroupId = &groupId
    oldRules.GroupId = &groupId

	params := &ec2.DescribeSecurityGroupsInput{ GroupIds: []*string{ &groupId }}
	resp, err := svc.DescribeSecurityGroups(params)

	for i := 0; i < len(resp.SecurityGroups[0].IpPermissions); i++ {
		existing := resp.SecurityGroups[0].IpPermissions[i]
		oldRules.IpPermissions = append(oldRules.IpPermissions, existing)
    }

	_, err = svc.RevokeSecurityGroupIngress(&oldRules)
	if err == nil {
		log.Println("success")
	}

	log.Println("Adding current node IPs to the group... ")

	// Add AWS internal network
	ips = append(ips, "10.0.0.0/8")

	for i := 0; i < len(ips); i++ {
	    entry := new(ec2.IpPermission)
    	entry.IpProtocol = &allProtocol
	    entry.IpRanges = []*ec2.IpRange{{CidrIp: &ips[i]}}
    	newRules.IpPermissions = append(newRules.IpPermissions, entry)
	}

    _, err = svc.AuthorizeSecurityGroupIngress(&newRules)
    if err != nil {
		panic(err)
	}

	log.Println("success")
}

/*
 * Initialize Docker Cloud SDK
 */
func initDockerCloud() {
	dockercloud.User = getEnv("DOCKER_CLOUD_USER")
	dockercloud.ApiKey = getEnv("DOCKER_CLOUD_KEY")

	if len(os.Getenv("DOCKER_CLOUD_NAMESPACE")) > 0 {
		dockercloud.Namespace = os.Getenv("DOCKER_CLOUD_NAMESPACE")
	}
}

/*
 * Main block
 */
func main() {
	initDockerCloud()

	groups := strings.Split(getEnv("AWS_SG_ID"), ',')

	for i := 0; i < len(groups); i++ {
		modifySecurityGroup(groups[i], getNodeIps())
	}

	listenToEvents()
}
<|endoftext|>


<commit_before>package requests

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-requests/requests/options"
)

var (
	registeredOptions = map[string]OptionFunc{
		"required":  OptionFunc(options.Required),
		"default":   OptionFunc(options.Default),
		"immutable": OptionFunc(options.Immutable),
	}

	optionDefaults map[string]string
	fallbackTags   []string
)

// FallbackTags returns a list of tag names that are used as fallbacks
// to locate field names.  See AddFallbackTag for more details.
func FallbackTags() []string {
	if fallbackTags == nil {
		fallbackTags = make([]string, 0, 5)
	}
	return fallbackTags
}

// AddFallbackTag adds a tag name to the list of fallback tag names to
// use when locating a field name.  For example, if you use the "db"
// tag and find yourself duplicating the name in both the "db" and
// "request" tags as follows:
//
//     type Example struct {
//         User `db:"user_id" request:"user_id"`
//     }
//
// Then you could update your code to the following:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         User `db:"user_id"`
//     }
//
// Fallback tags will only be added once - duplicates will be ignored.
// Fallbacks will be used in the order that they are added, so if you
// add "db" before "response" (as an example), the "db" tag will be
// preferred over the "response" tag as a fallback.
//
// In all cases, the "request" tag will be preferred over anything
// else.  However, an empty name (but non-empty options) will cause
// the fallbacks to be used, as in the following example:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         // Use the name from the DB, but add the 'required' option
//         // for requests.
//         User `db:"user_id" request:",required"`
//     }
func AddFallbackTag(newTag string) {
	tags := FallbackTags()
	for _, tag := range tags {
		if tag == newTag {
			return
		}
	}
	fallbackTags = append(tags, newTag)
}

// OptionDefaults returns a list of default values for options.  See
// SetOptionDefault for more details.
func OptionDefaults() map[string]string {
	if optionDefaults == nil {
		optionDefaults = make(map[string]string)
	}
	return optionDefaults
}

// SetOptionDefault sets an option to default to a value.  By default,
// OptionFuncs that are excluded from a field's options are never
// called, but if you set a default for that option, it will always be
// called with the default value if the option is not provided on the
// struct field.  An example:
//
//     func init() {
//         SetOptionDefault("required", "true")
//     }
//
//     type Example struct {
//         // user_id will be required in the request
//         User `db:user_id`
//
//         // description will be optional in the request
//         Description `request:",required=false"`
//     }
func SetOptionDefault(option, value string) {
	OptionDefaults()[option] = value
}

// An OptionFunc is a function which takes a field's original value,
// new value (from a request), and a string of option values (anything
// to the right of the = sign in a field's tag option), and returns
// the final new value (parsed from the request value) and any errors encountered.
type OptionFunc func(originalValue, requestValue interface{}, optionValue string) (convertedValue interface{}, err error)

type tagOption struct {
	name  string
	value string
}

func (option tagOption) function() OptionFunc {
	function, _ := registeredOptions[option.name]
	return function
}

// RegisterOption can be used to register functions that should be
// called for struct fields with matching option strings.  For
// example:
//
//     RegisterOption("allow-empty", func(value interface{}, optionValue string) (interface{}, error) {
//         if optionValue == "false" {
//             if value == nil || value.(string) == "" {
//                 return nil, errors.New("Cannot be empty")
//             }
//         }
//         return value, nil
//     })
//
//     type Example struct {
//         Name `request:",allow-empty=false"`
//     }
//
// Any options without a value (e.g. request:",non-empty") will have
// their value set to "true".
//
// An error will be returned if an OptionFunc is already registered
// for the provided name.
func RegisterOption(name string, optionFunc OptionFunc) error {
	if _, ok := registeredOptions[name]; ok {
		return fmt.Errorf(`An OptionFunc is already registered for "%s"`, name)
	}
	registeredOptions[name] = optionFunc
	return nil
}

// ApplyOptions will attempt to apply any OptionFunc values registered
// with RegisterOption to a struct field.  If any of the OptionFuncs
// return an error, the process will immediately return a nil value
// and the returned error.
func ApplyOptions(field reflect.StructField, orig, input interface{}) (value interface{}, optionErr error) {
	value = input
	for _, option := range tagOptions(field) {
		optionFunc := option.function()
		if optionFunc == nil {
			return nil, fmt.Errorf(`Could not find a registered OptionFunc for option "%s"`, option.name)
		}
		if value, optionErr = optionFunc(orig, value, option.value); optionErr != nil {
			return nil, optionErr
		}
	}
	return
}

func tagOptions(field reflect.StructField) []*tagOption {
	tag := field.Tag.Get("request")
	options := make([]*tagOption, 0, len(optionDefaults)+5)
	for startIdx := strings.IndexRune(tag, ','); startIdx >= 0; startIdx = strings.IndexRune(tag[startIdx:], ',') {
		// Skip over the ',' character
		startIdx++
		endIdx := strings.IndexRune(tag[startIdx:], ',')
		if endIdx < 0 {
			endIdx = len(tag)
		}
		optionNameEnd := strings.IndexRune(tag[startIdx:endIdx], '=')
		optionNameStart := optionNameEnd + 1
		if optionNameEnd < 0 {
			optionNameEnd = endIdx
			optionNameStart = endIdx
		}

		option := new(tagOption)
		option.name = tag[startIdx:optionNameEnd]
		option.value = tag[optionNameStart:endIdx]
		if option.value == "" {
			option.value = "true"
		}
		options = append(options, option)
	}

	for name, defaultValue := range optionDefaults {
		useDefault := true
		for _, option := range options {
			if name == option.name {
				useDefault = false
				break
			}
		}
		if useDefault {
			options = append(options, &tagOption{
				name:  name,
				value: defaultValue,
			})
		}
	}
	return options
}

func name(field reflect.StructField) string {
	name := nameFromTag(field, "request")
	for fallback := 0; len(name) == 0 && fallback < len(fallbackTags); fallback++ {
		name = nameFromTag(field, fallbackTags[fallback])
	}
	if len(name) == 0 {
		name = strings.ToLower(field.Name)
	}
	return name
}

func nameFromTag(field reflect.StructField, tagName string) string {
	name := field.Tag.Get(tagName)
	nameEnd := strings.IndexRune(name, ',')
	if nameEnd == -1 {
		return name
	}
	return name[:nameEnd]
}
<commit_msg>Fixed tagOptions to satisfy test<commit_after>package requests

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-requests/requests/options"
)

var (
	registeredOptions = map[string]OptionFunc{
		"required":  OptionFunc(options.Required),
		"default":   OptionFunc(options.Default),
		"immutable": OptionFunc(options.Immutable),
	}

	optionDefaults map[string]string
	fallbackTags   []string
)

// FallbackTags returns a list of tag names that are used as fallbacks
// to locate field names.  See AddFallbackTag for more details.
func FallbackTags() []string {
	if fallbackTags == nil {
		fallbackTags = make([]string, 0, 5)
	}
	return fallbackTags
}

// AddFallbackTag adds a tag name to the list of fallback tag names to
// use when locating a field name.  For example, if you use the "db"
// tag and find yourself duplicating the name in both the "db" and
// "request" tags as follows:
//
//     type Example struct {
//         User `db:"user_id" request:"user_id"`
//     }
//
// Then you could update your code to the following:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         User `db:"user_id"`
//     }
//
// Fallback tags will only be added once - duplicates will be ignored.
// Fallbacks will be used in the order that they are added, so if you
// add "db" before "response" (as an example), the "db" tag will be
// preferred over the "response" tag as a fallback.
//
// In all cases, the "request" tag will be preferred over anything
// else.  However, an empty name (but non-empty options) will cause
// the fallbacks to be used, as in the following example:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         // Use the name from the DB, but add the 'required' option
//         // for requests.
//         User `db:"user_id" request:",required"`
//     }
func AddFallbackTag(newTag string) {
	tags := FallbackTags()
	for _, tag := range tags {
		if tag == newTag {
			return
		}
	}
	fallbackTags = append(tags, newTag)
}

// OptionDefaults returns a list of default values for options.  See
// SetOptionDefault for more details.
func OptionDefaults() map[string]string {
	if optionDefaults == nil {
		optionDefaults = make(map[string]string)
	}
	return optionDefaults
}

// SetOptionDefault sets an option to default to a value.  By default,
// OptionFuncs that are excluded from a field's options are never
// called, but if you set a default for that option, it will always be
// called with the default value if the option is not provided on the
// struct field.  An example:
//
//     func init() {
//         SetOptionDefault("required", "true")
//     }
//
//     type Example struct {
//         // user_id will be required in the request
//         User `db:user_id`
//
//         // description will be optional in the request
//         Description `request:",required=false"`
//     }
func SetOptionDefault(option, value string) {
	OptionDefaults()[option] = value
}

// An OptionFunc is a function which takes a field's original value,
// new value (from a request), and a string of option values (anything
// to the right of the = sign in a field's tag option), and returns
// the final new value (parsed from the request value) and any errors encountered.
type OptionFunc func(originalValue, requestValue interface{}, optionValue string) (convertedValue interface{}, err error)

type tagOption struct {
	name  string
	value string
}

func (option tagOption) function() OptionFunc {
	function, _ := registeredOptions[option.name]
	return function
}

// RegisterOption can be used to register functions that should be
// called for struct fields with matching option strings.  For
// example:
//
//     RegisterOption("allow-empty", func(value interface{}, optionValue string) (interface{}, error) {
//         if optionValue == "false" {
//             if value == nil || value.(string) == "" {
//                 return nil, errors.New("Cannot be empty")
//             }
//         }
//         return value, nil
//     })
//
//     type Example struct {
//         Name `request:",allow-empty=false"`
//     }
//
// Any options without a value (e.g. request:",non-empty") will have
// their value set to "true".
//
// An error will be returned if an OptionFunc is already registered
// for the provided name.
func RegisterOption(name string, optionFunc OptionFunc) error {
	if _, ok := registeredOptions[name]; ok {
		return fmt.Errorf(`An OptionFunc is already registered for "%s"`, name)
	}
	registeredOptions[name] = optionFunc
	return nil
}

// ApplyOptions will attempt to apply any OptionFunc values registered
// with RegisterOption to a struct field.  If any of the OptionFuncs
// return an error, the process will immediately return a nil value
// and the returned error.
func ApplyOptions(field reflect.StructField, orig, input interface{}) (value interface{}, optionErr error) {
	value = input
	for _, option := range tagOptions(field) {
		optionFunc := option.function()
		if optionFunc == nil {
			return nil, fmt.Errorf(`Could not find a registered OptionFunc for option "%s"`, option.name)
		}
		if value, optionErr = optionFunc(orig, value, option.value); optionErr != nil {
			return nil, optionErr
		}
	}
	return
}

func tagOptions(field reflect.StructField) []*tagOption {
	remaining := field.Tag.Get("request")
	options := make([]*tagOption, 0, len(optionDefaults)+5)
	for startIdx := strings.IndexRune(remaining, ','); startIdx >= 0; startIdx = strings.IndexRune(remaining, ',') {
		// Skip over the ',' character
		startIdx++
		endIdx := strings.IndexRune(remaining[startIdx:], ',')
		if endIdx < 0 {
			endIdx = len(remaining)
		} else {
			endIdx += startIdx
		}
		currentOption := remaining[startIdx:endIdx]
		remaining = remaining[endIdx:]

		optionNameEnd := strings.IndexRune(currentOption, '=')
		optionNameStart := optionNameEnd + 1
		if optionNameEnd < 0 {
			optionNameEnd = len(currentOption)
			optionNameStart = len(currentOption)
		}

		option := new(tagOption)
		option.name = currentOption[:optionNameEnd]
		option.value = currentOption[optionNameStart:]
		if option.value == "" {
			option.value = "true"
		}
		options = append(options, option)
	}

	for name, defaultValue := range optionDefaults {
		useDefault := true
		for _, option := range options {
			if name == option.name {
				useDefault = false
				break
			}
		}
		if useDefault {
			options = append(options, &tagOption{
				name:  name,
				value: defaultValue,
			})
		}
	}
	return options
}

func name(field reflect.StructField) string {
	name := nameFromTag(field, "request")
	for fallback := 0; len(name) == 0 && fallback < len(fallbackTags); fallback++ {
		name = nameFromTag(field, fallbackTags[fallback])
	}
	if len(name) == 0 {
		name = strings.ToLower(field.Name)
	}
	return name
}

func nameFromTag(field reflect.StructField, tagName string) string {
	name := field.Tag.Get(tagName)
	nameEnd := strings.IndexRune(name, ',')
	if nameEnd == -1 {
		return name
	}
	return name[:nameEnd]
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "net/http"
import "encoding/json"
import "io/ioutil"
import "golang.org/x/net/websocket"
import "sync/atomic"
import "log"
import "os"
import "strings"
import "gopkg.in/dougEfresh/gtoggl.v8"

var counter uint64

type responseSelf struct {
	Id string `json:"id"`
}

type responseRtmStart struct {
	Ok    bool         `json:"ok,omitEmpty"`
	Error string       `json:"error,omitEmpty"`
	Url   string       `json:"url,omitEmpty"`
	Self  responseSelf `json:"self,omitEmpty"`
	User  string       `json:"user,omitEmpty"`
}

func slackStart(token string) (wsurl, id string, err error) {
	url := fmt.Sprintf("https://slack.com/api/rtm.start?token=%s", token)
	resp, err := http.Get(url)
	if err != nil {
		return
	}

	if resp.StatusCode != 200 {
		err = fmt.Errorf("API request failed with code %d", resp.StatusCode)
		return
	}
	fmt.Println(json.MarshalIndent(resp.Body, "", "    "))
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	var respObj responseRtmStart
	err = json.Unmarshal(body, &respObj)
	if err != nil {
		return
	}

	if !respObj.Ok {
		err = fmt.Errorf("Slack error: %s", respObj.Errorgopkg.in/dougEfresh/gtoggl.v8)
		return
	}

	wsurl = respObj.Url
	id = respObj.Self.Id
	return
}

type Message struct {
	Id      uint64 `json:"id"`
	Type    string `json:"type"`
	Channel string `json:"channel"`
	Text    string `json:"text"`
}

func getMessage(ws *websocket.Conn) (m Message, err error) {
	err = websocket.JSON.Receive(ws, &m)
	return
}

func postMessage(ws *websocket.Conn, m Message) error {
	m.Id = atomic.AddUint64(&counter, 1)
	return websocket.JSON.Send(ws, m)
}

func slackConnect(token string) (*websocket.Conn, string) {
	wsurl, id, err := slackStart(token)

	if err != nil {
		log.Fatal(err)
	}

	ws, err := websocket.Dial(wsurl, "", "https://api.slack.com")
	if err != nil {
		log.Fatal(err)
	}

	return ws, id

}

func pingTogglApi(apiKey string) error {
	tc, err := gtoggl.NewClient(apiKey)
	if err == nil {
		panic(err)
	}

}

func executeCommand(userMap map[string]string, userId string, parts []string) string {
	if parts[1] == "register" && len(parts) == 3 {
		userMap[userId] = parts[2]
		err = pingTogglApi(parts[2])
	}
}

func main() {
	userTogglMap := make(map[string]string)
	if len(os.Args) != 2 {
		fmt.Printf("usage: togglbot slack-bot-token")
		os.Exit(1)
	}

	ws, id := slackConnect(os.Args[1])
	fmt.Println("TogglBot ready, ^C exits")

	for {
		m, err := getMessage(ws)

		if err != nil {
			log.Fatal(err)
		}

		if m.Type == "message" && strings.HasPrefix(m.Text, "<@"+id+">") {
			//Try to parse it into a message
			parts := strings.Fields(m.Text)
			if len(parts) == 2 || len(parts) == 3 {
				go func(m Message) {
					m.Text = executeCommand(userMap)
					postMessage(ws, m)
				}(m)
			} else {
				m.Text = fmt.Sprintf("sorry, that does not compute!\n")
				fmt.Println(m.Text)
				//postMessage(ws, m)
			}

		}

	}

}
<commit_msg>drops in new dependencies, support register, start, stop. Currently stop is buggy, may have to fork the toggl library<commit_after>package main

import "fmt"
import "log"
import "os"
import "errors"
import "strings"
import "github.com/nlopes/slack"
import "github.com/gedex/go-toggl/toggl"

func pingTogglApi(apiKey string) error {
	tc := toggl.NewClient(apiKey)
	ws, err := tc.Workspaces.List()
	if err != nil {
		fmt.Println(os.Stderr, "Error: %s\n", err)
		return err
	}
	fmt.Println(ws)
	return nil
}

func stopTimer(apiKey string) (*toggl.TimeEntry, error) {
	tc := toggl.NewClient(apiKey)
	sessionId, ok := sessionMap[apiKey]
	if !ok {
		return nil, errors.New("no timer started!")
	}
	te, err := tc.TimeEntries.Stop(sessionId)
	if err != nil {
		return nil, err
	}
	return te, nil
}

func startTimer(apiKey string, pid int) *toggl.TimeEntry {
	tc := toggl.NewClient(apiKey)
	te := &toggl.TimeEntry{
		ProjectID:   pid,
		CreatedWith: "TogglBot",
	}
	tec, err := tc.TimeEntries.Start(te)
	if err != nil {
		fmt.Println(err)
	}
	sessionMap[apiKey] = tec.ID
	return tec
}

func getProjectWithName(apiKey, projectName string) int {
	tc := toggl.NewClient(apiKey)
	me, err := tc.Users.Me(true)
	var retVal int
	if err != nil {
		fmt.Println(err)
	}
	for _, project := range me.Projects {
		fmt.Println(project.Name)
		if strings.EqualFold(project.Name, projectName) {
			retVal = project.ID
		}
	}
	fmt.Println("FOUND PROJECT WITH NAME: " + projectName + ", id is: " + string(retVal))
	return retVal

}

type BotCommand struct {
	Channel string
	Event   *slack.MessageEvent
	UserId  string
}

type ReplyChannel struct {
	Channel      string
	Attachment   *slack.Attachment
	DisplayTitle string
}

var (
	api               *slack.Client
	botCommandChannel chan *BotCommand
	botReplyChannel   chan ReplyChannel
	botId             string
	userMap           map[string]string
	sessionMap        map[string]int
)

func handleBotCommands(replyChannel chan ReplyChannel) {
	commands := map[string]string{
		"register": "Register yourself with togglbot. `@togglbot register MY_TOGGL_API_KEY`",
		"start":    "Start a timer for a given project and description. `@togglbot start <PROJECT_NAME> <EVERYTHING_ELSE_IS_DESCRIPTION>`",
		"stop":     "Stops any current timer session. `@togglbot stop`",
		"track":    "adds a toggl entry to a project for a given time range. `@togglbot track icancope 9am-5pm`",
	}

	var reply ReplyChannel

	for {
		incomingCommand := <-botCommandChannel
		commandArray := strings.Fields(incomingCommand.Event.Text)
		reply.Channel = incomingCommand.Channel
		switch commandArray[1] {

		case "help":
			reply.DisplayTitle = "Help!"
			fields := make([]slack.AttachmentField, 0)
			for k, v := range commands {
				fields = append(fields, slack.AttachmentField{
					Title: "<bot> " + k,
					Value: v,
				})
			}
			attachment := &slack.Attachment{
				Pretext:    "TogglBot Command List",
				Color:      "#B733FF",
				Fields:     fields,
				MarkdownIn: []string{"fields"},
			}
			reply.Attachment = attachment
			fmt.Println("SENDING REPLY TO CHANNEL")
			replyChannel <- reply

		case "register":
			togglApiKey := commandArray[2]
			err := pingTogglApi(togglApiKey)
			if err != nil {
				reply.DisplayTitle = "Failed to register. Bad api key?"
			} else {
				userMap[incomingCommand.Event.User] = togglApiKey
				reply.DisplayTitle = "Successfully registered!"
			}
			replyChannel <- reply

		case "start":
			togglApiKey, ok := userMap[incomingCommand.Event.User]
			if !ok {
				reply.DisplayTitle = "You have not registered with togglbot yet. Try @togglbot register API_KEY_HERE"
				replyChannel <- reply
				break
			}
			project := commandArray[2]
			pid := getProjectWithName(togglApiKey, project)
			fmt.Printf("%v", pid)
			startTimer(togglApiKey, pid)
			reply.DisplayTitle = "Timer started! *get back to work peon*"
			replyChannel <- reply
		case "stop":
			togglApiKey, ok := userMap[incomingCommand.Event.User]
			if !ok {
				reply.DisplayTitle = "You have not registered with togglbot yet. Try @togglbot register API_KEY_HERE"
				replyChannel <- reply
				break
			}
			te, err := stopTimer(togglApiKey)
			if err != nil {
				reply.DisplayTitle = "couldn't stop timer: " + err.Error()
				replyChannel <- reply
				break
			}
			reply.DisplayTitle = fmt.Sprintf("Timer Stopped. Worked for %v minutes on %v", te.Duration, te.ProjectID)
			replyChannel <- reply
		}
	}
}

func handleBotReplies() {
	for {
		reply := <-botReplyChannel
		params := slack.PostMessageParameters{}
		params.AsUser = true
		if reply.Attachment != nil {
			params.Attachments = []slack.Attachment{*reply.Attachment}
		}
		_, _, err := api.PostMessage(reply.Channel, reply.DisplayTitle, params)
		if err != nil {
			log.Fatal(err)
		}
	}
}

func main() {
	if len(os.Args) != 2 {
		fmt.Printf("usage: togglbot slack-bot-token")
		os.Exit(1)
	}
	userMap = make(map[string]string)
	sessionMap = make(map[string]int)
	token := os.Args[1]
	api = slack.New(token)
	api.SetDebug(true)
	rtm := api.NewRTM()

	botCommandChannel = make(chan *BotCommand)
	botReplyChannel = make(chan ReplyChannel)
	go rtm.ManageConnection()
	go handleBotCommands(botReplyChannel)
	go handleBotReplies()
	go fmt.Println("TogglBot ready, ^C exits")
Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch event := msg.Data.(type) {
			case *slack.ConnectedEvent:
				botId = event.Info.User.ID
			case *slack.MessageEvent:
				var channelInfo *slack.Channel
				var channelName string
				if strings.HasPrefix(event.Channel, "D") {
					channelInfo = &slack.Channel{slack.groupConversation{
						Name: event.Channel,
					}}
				}

				botCommand := &BotCommand{
					Channel: channelInfo,
					Event:   event,
					UserId:  event.User,
				}

				if event.Type == "message" && strings.HasPrefix(event.Text, "<@"+botId+">") {
					fmt.Println("FOUND COMMAND")
					botCommandChannel <- botCommand
				}
			case *slack.RTMError:
				fmt.Printf("ERROR: %s\n", event.Error())
			case *slack.InvalidAuthEvent:
				fmt.Printf("Invalid credentials")
				break Loop
			default:
				fmt.Printf("\n")
			}
		}
	}

}
<|endoftext|>


<commit_before>package gocql

import (
	"fmt"
	"math"
	"strconv"
	"sync/atomic"
)

// scyllaSupported represents Scylla connection options as sent in SUPPORTED
// frame.
type scyllaSupported struct {
	shard     int
	nrShards  int
	msbIgnore uint64
}

func parseSupported(supported map[string][]string) scyllaSupported {
	const (
		scyllaShard             = "SCYLLA_SHARD"
		scyllaNrShards          = "SCYLLA_NR_SHARDS"
		scyllaPartitioner       = "SCYLLA_PARTITIONER"
		scyllaShardingAlgorithm = "SCYLLA_SHARDING_ALGORITHM"
		scyllaShardingIgnoreMSB = "SCYLLA_SHARDING_IGNORE_MSB"
	)

	var (
		si  scyllaSupported
		err error
	)

	if s, ok := supported[scyllaShard]; ok {
		if si.shard, err = strconv.Atoi(s[0]); err != nil {
			if GoCQLDebug {
				Logger.Printf("scylla: failed to parse %s value %v: %s", scyllaShard, s, err)
			}
		}
	}
	if s, ok := supported[scyllaNrShards]; ok {
		if si.nrShards, err = strconv.Atoi(s[0]); err != nil {
			if GoCQLDebug {
				Logger.Printf("scylla: failed to parse %s value %v: %s", scyllaNrShards, s, err)
			}
		}
	}
	if s, ok := supported[scyllaShardingIgnoreMSB]; ok {
		if si.msbIgnore, err = strconv.ParseUint(s[0], 10, 64); err != nil {
			if GoCQLDebug {
				Logger.Printf("scylla: failed to parse %s value %v: %s", scyllaShardingIgnoreMSB, s, err)
			}
		}
	}

	var (
		partitioner string
		algorithm   string
	)
	if s, ok := supported[scyllaPartitioner]; ok {
		partitioner = s[0]
	}
	if s, ok := supported[scyllaShardingAlgorithm]; ok {
		algorithm = s[0]
	}

	if partitioner != "org.apache.cassandra.dht.Murmur3Partitioner" || algorithm != "biased-token-round-robin" || si.nrShards == 0 || si.msbIgnore == 0 {
		if GoCQLDebug {
			Logger.Printf("scylla: unsupported sharding configuration")
		}
		return scyllaSupported{}
	}

	return si
}

// isScyllaConn checks if conn is suitable for scyllaConnPicker.
func isScyllaConn(conn *Conn) bool {
	s := parseSupported(conn.supported)
	return s.nrShards != 0
}

// scyllaConnPicker is a specialised ConnPicker that selects connections based
// on token trying to get connection to a shard containing the given token.
// A list of excess connections is maintained to allow for lazy removal of.
// excess connections. Keeping excess connections open helps reaching equilibrium
// faster since the likelihood of hitting the same shard decreases with the number
// of connections to the shard.
type scyllaConnPicker struct {
	conns       []*Conn
	excessConns []*Conn
	nrConns     int
	nrShards    int
	msbIgnore   uint64
	pos         int32
}

func newScyllaConnPicker(conn *Conn) *scyllaConnPicker {
	s := parseSupported(conn.supported)
	if s.nrShards == 0 {
		panic(fmt.Sprintf("scylla: %s not a sharded connection", conn.Address()))
	}

	if GoCQLDebug {
		Logger.Printf("scylla: %s sharding options %+v", conn.Address(), s)
	}

	return &scyllaConnPicker{
		nrShards:  s.nrShards,
		msbIgnore: s.msbIgnore,
	}
}

func (p *scyllaConnPicker) Remove(conn *Conn) {
	s := parseSupported(conn.supported)
	if s.nrShards == 0 {
		// It is possible for Remove to be called before the connection is added to the pool.
		// Ignoring these connections here is safe.
		if GoCQLDebug {
			Logger.Printf("scylla: %s has unknown sharding state, ignoring it", conn.Address())
		}
		return
	}
	if GoCQLDebug {
		Logger.Printf("scylla: %s remove shard %d connection", conn.Address(), s.shard)
	}

	if p.conns[s.shard] != nil {
		p.conns[s.shard] = nil
		p.nrConns--
	}
}

func (p *scyllaConnPicker) Close() {
	conns := p.conns
	p.conns = nil
	for _, conn := range conns {
		if conn != nil {
			conn.Close()
		}
	}
}

func (p *scyllaConnPicker) Size() (int, int) {
	return p.nrConns, p.nrShards - p.nrConns
}

func (p *scyllaConnPicker) Pick(t token) *Conn {
	if len(p.conns) == 0 {
		return nil
	}

	if t == nil {
		idx := int(atomic.AddInt32(&p.pos, 1))
		for i := 0; i < len(p.conns); i++ {
			if conn := p.conns[(idx+i)%len(p.conns)]; conn != nil {
				return conn
			}
		}
		return nil
	}

	mmt, ok := t.(murmur3Token)
	// double check if that's murmur3 token
	if !ok {
		return nil
	}

	idx := p.shardOf(mmt)
	return p.conns[idx]
}

func (p *scyllaConnPicker) shardOf(token murmur3Token) int {
	shards := uint64(p.nrShards)
	z := uint64(token+math.MinInt64) << p.msbIgnore
	lo := z & 0xffffffff
	hi := (z >> 32) & 0xffffffff
	mul1 := lo * shards
	mul2 := hi * shards
	sum := (mul1 >> 32) + mul2
	return int(sum >> 32)
}

func (p *scyllaConnPicker) Put(conn *Conn) {
	const maxExcessConnsFactor = 10

	s := parseSupported(conn.supported)
	if s.nrShards == 0 {
		panic(fmt.Sprintf("scylla: %s not a sharded connection", conn.Address()))
	}

	if s.nrShards != len(p.conns) {
		if s.nrShards != p.nrShards {
			panic(fmt.Sprintf("scylla: %s invalid number of shards", conn.Address()))
		}
		conns := p.conns
		p.conns = make([]*Conn, s.nrShards, s.nrShards)
		copy(p.conns, conns)
	}
	if c := p.conns[s.shard]; c != nil {
		p.excessConns = append(p.excessConns, conn)
		if len(p.excessConns) > maxExcessConnsFactor*p.nrShards {
			if gocqlDebug {
				Logger.Printf("scylla: excess connections limit reached (%d)", maxExcessConnsFactor*p.nrShards)
			}
			p.closeExcessConns()
		}
		return
	}
	p.conns[s.shard] = conn
	p.nrConns++
	if p.nrConns >= p.nrShards {
		// We have reached one connection to each shard and
		// it's time to close the excess connections.
		p.closeExcessConns()
	}
	if GoCQLDebug {
		Logger.Printf("scylla: %s put shard %d connection total: %d missing: %d", conn.Address(), s.shard, p.nrConns, p.nrShards-p.nrConns)
	}
}

// closeExcessConns closes the excess connections and clears
// the excessConns slice. This function needs to be called
// in a goroutine safe context, i.e. when the external pool
// write lock is held or other synchronization is needed.
func (p *scyllaConnPicker) closeExcessConns() {
	if gocqlDebug {
		Logger.Printf("scylla: closing %d excess connections", len(p.excessConns))
	}
	for _, c := range p.excessConns {
		c.Close()
	}
	p.excessConns = nil
}
<commit_msg>scylla: give out random connections before pool equilibrium<commit_after>package gocql

import (
	"fmt"
	"math"
	"strconv"
	"sync/atomic"
)

// scyllaSupported represents Scylla connection options as sent in SUPPORTED
// frame.
type scyllaSupported struct {
	shard     int
	nrShards  int
	msbIgnore uint64
}

func parseSupported(supported map[string][]string) scyllaSupported {
	const (
		scyllaShard             = "SCYLLA_SHARD"
		scyllaNrShards          = "SCYLLA_NR_SHARDS"
		scyllaPartitioner       = "SCYLLA_PARTITIONER"
		scyllaShardingAlgorithm = "SCYLLA_SHARDING_ALGORITHM"
		scyllaShardingIgnoreMSB = "SCYLLA_SHARDING_IGNORE_MSB"
	)

	var (
		si  scyllaSupported
		err error
	)

	if s, ok := supported[scyllaShard]; ok {
		if si.shard, err = strconv.Atoi(s[0]); err != nil {
			if GoCQLDebug {
				Logger.Printf("scylla: failed to parse %s value %v: %s", scyllaShard, s, err)
			}
		}
	}
	if s, ok := supported[scyllaNrShards]; ok {
		if si.nrShards, err = strconv.Atoi(s[0]); err != nil {
			if GoCQLDebug {
				Logger.Printf("scylla: failed to parse %s value %v: %s", scyllaNrShards, s, err)
			}
		}
	}
	if s, ok := supported[scyllaShardingIgnoreMSB]; ok {
		if si.msbIgnore, err = strconv.ParseUint(s[0], 10, 64); err != nil {
			if GoCQLDebug {
				Logger.Printf("scylla: failed to parse %s value %v: %s", scyllaShardingIgnoreMSB, s, err)
			}
		}
	}

	var (
		partitioner string
		algorithm   string
	)
	if s, ok := supported[scyllaPartitioner]; ok {
		partitioner = s[0]
	}
	if s, ok := supported[scyllaShardingAlgorithm]; ok {
		algorithm = s[0]
	}

	if partitioner != "org.apache.cassandra.dht.Murmur3Partitioner" || algorithm != "biased-token-round-robin" || si.nrShards == 0 || si.msbIgnore == 0 {
		if GoCQLDebug {
			Logger.Printf("scylla: unsupported sharding configuration")
		}
		return scyllaSupported{}
	}

	return si
}

// isScyllaConn checks if conn is suitable for scyllaConnPicker.
func isScyllaConn(conn *Conn) bool {
	s := parseSupported(conn.supported)
	return s.nrShards != 0
}

// scyllaConnPicker is a specialised ConnPicker that selects connections based
// on token trying to get connection to a shard containing the given token.
// A list of excess connections is maintained to allow for lazy closing of
// connections to already opened shards. Keeping excess connections open helps
// reaching equilibrium faster since the likelihood of hitting the same shard
// decreases with the number of connections to the shard.
type scyllaConnPicker struct {
	conns       []*Conn
	excessConns []*Conn
	nrConns     int
	nrShards    int
	msbIgnore   uint64
	pos         int32
}

func newScyllaConnPicker(conn *Conn) *scyllaConnPicker {
	s := parseSupported(conn.supported)
	if s.nrShards == 0 {
		panic(fmt.Sprintf("scylla: %s not a sharded connection", conn.Address()))
	}

	if GoCQLDebug {
		Logger.Printf("scylla: %s sharding options %+v", conn.Address(), s)
	}

	return &scyllaConnPicker{
		nrShards:  s.nrShards,
		msbIgnore: s.msbIgnore,
	}
}

func (p *scyllaConnPicker) Remove(conn *Conn) {
	s := parseSupported(conn.supported)
	if s.nrShards == 0 {
		// It is possible for Remove to be called before the connection is added to the pool.
		// Ignoring these connections here is safe.
		if GoCQLDebug {
			Logger.Printf("scylla: %s has unknown sharding state, ignoring it", conn.Address())
		}
		return
	}
	if GoCQLDebug {
		Logger.Printf("scylla: %s remove shard %d connection", conn.Address(), s.shard)
	}

	if p.conns[s.shard] != nil {
		p.conns[s.shard] = nil
		p.nrConns--
	}
}

func (p *scyllaConnPicker) Close() {
	conns := p.conns
	p.conns = nil
	for _, conn := range conns {
		if conn != nil {
			conn.Close()
		}
	}
}

func (p *scyllaConnPicker) Size() (int, int) {
	return p.nrConns, p.nrShards - p.nrConns
}

func (p *scyllaConnPicker) Pick(t token) *Conn {
	if len(p.conns) == 0 {
		return nil
	}

	if t == nil {
		return p.randomConn()
	}

	mmt, ok := t.(murmur3Token)
	// double check if that's murmur3 token
	if !ok {
		return nil
	}

	idx := p.shardOf(mmt)
	if c := p.conns[idx]; c != nil {
		// We have this shard's connection
		// so let's give it to the caller.
		return c
	}
	return p.randomConn()
}

func (p *scyllaConnPicker) shardOf(token murmur3Token) int {
	shards := uint64(p.nrShards)
	z := uint64(token+math.MinInt64) << p.msbIgnore
	lo := z & 0xffffffff
	hi := (z >> 32) & 0xffffffff
	mul1 := lo * shards
	mul2 := hi * shards
	sum := (mul1 >> 32) + mul2
	return int(sum >> 32)
}

func (p *scyllaConnPicker) Put(conn *Conn) {
	const maxExcessConnsFactor = 10

	s := parseSupported(conn.supported)
	if s.nrShards == 0 {
		panic(fmt.Sprintf("scylla: %s not a sharded connection", conn.Address()))
	}

	if s.nrShards != len(p.conns) {
		if s.nrShards != p.nrShards {
			panic(fmt.Sprintf("scylla: %s invalid number of shards", conn.Address()))
		}
		conns := p.conns
		p.conns = make([]*Conn, s.nrShards, s.nrShards)
		copy(p.conns, conns)
	}
	if c := p.conns[s.shard]; c != nil {
		p.excessConns = append(p.excessConns, conn)
		if len(p.excessConns) > maxExcessConnsFactor*p.nrShards {
			if gocqlDebug {
				Logger.Printf("scylla: excess connections limit reached (%d)", maxExcessConnsFactor*p.nrShards)
			}
			p.closeExcessConns()
		}
		return
	}
	p.conns[s.shard] = conn
	p.nrConns++
	if p.nrConns >= p.nrShards {
		// We have reached one connection to each shard and
		// it's time to close the excess connections.
		p.closeExcessConns()
	}
	if GoCQLDebug {
		Logger.Printf("scylla: %s put shard %d connection total: %d missing: %d", conn.Address(), s.shard, p.nrConns, p.nrShards-p.nrConns)
	}
}

// closeExcessConns closes the excess connections and clears
// the excessConns slice. This function needs to be called
// in a goroutine safe context, i.e. when the external pool
// write lock is held or other synchronization is needed.
func (p *scyllaConnPicker) closeExcessConns() {
	if gocqlDebug {
		Logger.Printf("scylla: closing %d excess connections", len(p.excessConns))
	}
	for _, c := range p.excessConns {
		c.Close()
	}
	p.excessConns = nil
}

func (p *scyllaConnPicker) randomConn() *Conn {
	idx := int(atomic.AddInt32(&p.pos, 1))
	for i := 0; i < len(p.conns); i++ {
		if conn := p.conns[(idx+i)%len(p.conns)]; conn != nil {
			return conn
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-uuid/uuid"
	"github.com/clawio/service.auth/lib"
	pb "github.com/clawio/service.localstore.prop/proto"
	"github.com/jinzhu/gorm"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"path"
	"time"
)

const (
	dirPerm = 0755
)

var (
	unauthenticatedError = grpc.Errorf(codes.Unauthenticated, "identity not found")
	permissionDenied     = grpc.Errorf(codes.PermissionDenied, "access denied")
)

type newServerParams struct {
	dsn          string
	db           *gorm.DB
	sharedSecret string
}

func newServer(p *newServerParams) (*server, error) {

	db, err := newDB("mysql", p.dsn)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	db.LogMode(true)

	err = db.AutoMigrate(&record{}).Error
	if err != nil {
		log.Error(err)
		return nil, err
	}

	log.Infof("automigration applied")

	s := &server{}
	s.p = p
	s.db = db
	return s, nil
}

type server struct {
	p  *newServerParams
	db *gorm.DB
}

func (s *server) Get(ctx context.Context, req *pb.GetReq) (*pb.Record, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Record{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	rec := &pb.Record{}
	err = s.db.Where("path=?", p).First(rec).Error
	// TODO(labkode) If record is not found putted. This will happen on storages with DAS
	if err != nil {
		log.Error(err)
		return rec, err
	}

	return rec, nil
}

func (s *server) Put(ctx context.Context, req *pb.PutReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	var id string
	var etag = uuid.New()
	var mtime = time.Now().Unix()

	r, err := s.getByPath(p)
	if err != nil {
		log.Error(err)
		if err == gorm.RecordNotFound {
			id = uuid.New()
		} else {
			return &pb.Void{}, err
		}
	} else {
		id = r.ID
	}

	log.Infof("record has %s", r.String())

	err = s.db.Exec(`INSERT INTO records (id,path,checksum, e_tag, m_time) VALUES (?,?,?,?,?)
  				ON DUPLICATE KEY UPDATE checksum=VALUES(checksum), e_tag=VALUES(e_tag), m_time=VALUES(m_time)`,
		id, p, req.Checksum, etag, mtime).Error

	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("putted record into db")

	return &pb.Void{}, nil
}

func (s *server) getByPath(path string) (*record, error) {

	r := &record{}
	err := s.db.Where("path=?", path).First(r).Error
	return r, err
}
<commit_msg>Fixed misplaced proto record<commit_after>package main

import (
	"code.google.com/p/go-uuid/uuid"
	"github.com/clawio/service.auth/lib"
	pb "github.com/clawio/service.localstore.prop/proto"
	"github.com/jinzhu/gorm"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"path"
	"time"
)

const (
	dirPerm = 0755
)

var (
	unauthenticatedError = grpc.Errorf(codes.Unauthenticated, "identity not found")
	permissionDenied     = grpc.Errorf(codes.PermissionDenied, "access denied")
)

type newServerParams struct {
	dsn          string
	db           *gorm.DB
	sharedSecret string
}

func newServer(p *newServerParams) (*server, error) {

	db, err := newDB("mysql", p.dsn)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	db.LogMode(true)

	err = db.AutoMigrate(&record{}).Error
	if err != nil {
		log.Error(err)
		return nil, err
	}

	log.Infof("automigration applied")

	s := &server{}
	s.p = p
	s.db = db
	return s, nil
}

type server struct {
	p  *newServerParams
	db *gorm.DB
}

func (s *server) Get(ctx context.Context, req *pb.GetReq) (*pb.Record, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Record{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	rec, err := s.getByPath(p)
	// TODO(labkode) If record is not found put it. This will happen on storages with DAS
	if err != nil {
		log.Error(err)
		return &pb.Record{}, err
	}

	r := &pb.Record{}
	r.Id = rec.ID
	r.Path = rec.Path
	r.Etag = rec.ETag
	r.Modified = rec.MTime
	r.Checksum = rec.Checksum
	return r, nil
}

func (s *server) Put(ctx context.Context, req *pb.PutReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	var id string
	var etag = uuid.New()
	var mtime = time.Now().Unix()

	r, err := s.getByPath(p)
	if err != nil {
		log.Error(err)
		if err == gorm.RecordNotFound {
			id = uuid.New()
		} else {
			return &pb.Void{}, err
		}
	} else {
		id = r.ID
	}

	log.Infof("record has %s", r.String())

	err = s.db.Exec(`INSERT INTO records (id,path,checksum, e_tag, m_time) VALUES (?,?,?,?,?)
  				ON DUPLICATE KEY UPDATE checksum=VALUES(checksum), e_tag=VALUES(e_tag), m_time=VALUES(m_time)`,
		id, p, req.Checksum, etag, mtime).Error

	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("putted record into db")

	return &pb.Void{}, nil
}

func (s *server) getByPath(path string) (*record, error) {

	r := &record{}
	err := s.db.Where("path=?", path).First(r).Error
	return r, err
}
<|endoftext|>


<commit_before>package null

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"reflect"
	"time"
)

// Time is a nullable time.Time. It supports SQL and JSON serialization.
// It will marshal to null if null.
type Time struct {
	Time  time.Time
	Valid bool
}

// Scan implements the Scanner interface.
func (t *Time) Scan(value interface{}) error {
	var err error
	switch x := value.(type) {
	case time.Time:
		t.Time = x
	case nil:
		t.Valid = false
		return nil
	default:
		err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
	}
	t.Valid = err == nil
	return err
}

// Value implements the driver Valuer interface.
func (t Time) Value() (driver.Value, error) {
	if !t.Valid {
		return nil, nil
	}
	return t.Time, nil
}

// NewTime creates a new Time.
func NewTime(t time.Time, valid bool) Time {
	return Time{
		Time:  t,
		Valid: valid,
	}
}

// TimeFrom creates a new Time that will always be valid.
func TimeFrom(t time.Time) Time {
	return NewTime(t, true)
}

// TimeFromPtr creates a new Time that will be null if t is nil.
func TimeFromPtr(t *time.Time) Time {
	if t == nil {
		var ti time.Time
		return NewTime(ti, false)
	}
	return NewTime(*t, true)
}

// MarshalJSON implements json.Marshaler.
// It will encode null if this time is null.
func (t Time) MarshalJSON() ([]byte, error) {
	if !t.Valid {
		return []byte("null"), nil
	}
	return json.Marshal(t.Time)
}

// UnmarshalJSON implements json.Unmarshaler.
// It supports string, map[string]interface{},
// and null input.
func (t *Time) UnmarshalJSON(data []byte) error {
	var err error
	var v interface{}
	if err = json.Unmarshal(data, &v); err != nil {
		return err
	}
	switch x := v.(type) {
	case string:
		err = t.Time.UnmarshalJSON(data)
	case map[string]interface{}:
		ti, tiOK := x["Time"].(string)
		valid, validOK := x["Valid"].(bool)
		if !tiOK || !validOK {
			err = fmt.Errorf("json: unmarshalling map[string]interface{} into Go value of type null.Time requires key \"Time\" to be of type string and key \"Valid\" to be of type bool; found %T and %T, respectively", x["Time"], x["Valid"])
			break
		}
		err = t.Time.UnmarshalJSON([]byte(`"` + ti + `"`))
		t.Valid = valid
		if err == nil && t.Valid == false {
			return nil // Return here to prevent `Valid` from being set to true based on nil error below.
		}
	case nil:
		t.Valid = false
		return nil
	default:
		err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
	}
	t.Valid = err == nil
	return err
}

// SetValid changes this Time's value and sets it to be non-null.
func (t *Time) SetValid(v time.Time) {
	t.Time = v
	t.Valid = true
}

// Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null.
func (t Time) Ptr() *time.Time {
	if !t.Valid {
		return nil
	}
	return &t.Time
}
<commit_msg>Minor tweaks to null.Time UnmarshalJSON<commit_after>package null

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"reflect"
	"time"
)

// Time is a nullable time.Time. It supports SQL and JSON serialization.
// It will marshal to null if null.
type Time struct {
	Time  time.Time
	Valid bool
}

// Scan implements the Scanner interface.
func (t *Time) Scan(value interface{}) error {
	var err error
	switch x := value.(type) {
	case time.Time:
		t.Time = x
	case nil:
		t.Valid = false
		return nil
	default:
		err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
	}
	t.Valid = err == nil
	return err
}

// Value implements the driver Valuer interface.
func (t Time) Value() (driver.Value, error) {
	if !t.Valid {
		return nil, nil
	}
	return t.Time, nil
}

// NewTime creates a new Time.
func NewTime(t time.Time, valid bool) Time {
	return Time{
		Time:  t,
		Valid: valid,
	}
}

// TimeFrom creates a new Time that will always be valid.
func TimeFrom(t time.Time) Time {
	return NewTime(t, true)
}

// TimeFromPtr creates a new Time that will be null if t is nil.
func TimeFromPtr(t *time.Time) Time {
	if t == nil {
		var ti time.Time
		return NewTime(ti, false)
	}
	return NewTime(*t, true)
}

// MarshalJSON implements json.Marshaler.
// It will encode null if this time is null.
func (t Time) MarshalJSON() ([]byte, error) {
	if !t.Valid {
		return []byte("null"), nil
	}
	return json.Marshal(t.Time)
}

// UnmarshalJSON implements json.Unmarshaler.
// It supports string, map[string]interface{},
// and null input.
func (t *Time) UnmarshalJSON(data []byte) error {
	var err error
	var v interface{}
	if err = json.Unmarshal(data, &v); err != nil {
		return err
	}
	switch x := v.(type) {
	case string:
		err = t.Time.UnmarshalJSON(data)
	case map[string]interface{}:
		ti, tiOK := x["Time"].(string)
		valid, validOK := x["Valid"].(bool)
		if !tiOK || !validOK {
			return fmt.Errorf("json: unmarshalling JSON object into Go value of type null.Time requires key \"Time\" to be of type string and key \"Valid\" to be of type bool; found %T and %T, respectively", x["Time"], x["Valid"])
		}
		err = t.Time.UnmarshalJSON([]byte(`"` + ti + `"`))
		t.Valid = valid
		return err
	case nil:
		t.Valid = false
		return nil
	default:
		err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
	}
	t.Valid = err == nil
	return err
}

// SetValid changes this Time's value and sets it to be non-null.
func (t *Time) SetValid(v time.Time) {
	t.Time = v
	t.Valid = true
}

// Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null.
func (t Time) Ptr() *time.Time {
	if !t.Valid {
		return nil
	}
	return &t.Time
}
<|endoftext|>