<commit_before>package brain

import (
	"encoding/json"
	"io"

	"github.com/BytemarkHosting/bytemark-client/lib/output"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
	"github.com/BytemarkHosting/bytemark-client/lib/util"
)

//MigrationJobModification represents the modifications possible on a migration job
type MigrationJobModification struct {
	Cancel  MigrationJobLocations `json:"cancel,omitempty"`
	Options MigrationJobOptions   `json:"options,omitempty"`
}

// MigrationJobQueue is a list of disc IDs that are still to be migrated as
// part of a migration job.
type MigrationJobQueue struct {
	Discs []int `json:"discs,omitempty"`
}

// MigrationJobLocations represents source or target locations for a migration
// job. Discs, pools and tails maybe represented by ID number, label or UUID.
type MigrationJobLocations struct {
	Discs []util.NumberOrString `json:"discs,omitempty"`
	Pools []util.NumberOrString `json:"pools,omitempty"`
	Tails []util.NumberOrString `json:"tails,omitempty"`
}

// MigrationJobDestinations represents available desintations for a migration
// job. Unlike MigrationJobLocations, these are represented using ID number
// only.
type MigrationJobDestinations struct {
	Pools []int `json:"pools,omitempty"`
}

// MigrationJobOptions represents options on a migration job.
type MigrationJobOptions struct {
	Priority int `json:"priority,omitempty"`
}

// MigrationJobDiscStatus represents the current status of a migration job.
// Each entry is a list of disc IDs indicating the fate of discs that
// have been removed from the queue.
type MigrationJobDiscStatus struct {
	Done      []int `json:"done,omitempty"`
	Errored   []int `json:"errored,omitempty"`
	Cancelled []int `json:"cancelled,omitempty"`
	Skipped   []int `json:"skipped,omitempty"`
}

// MigrationJobStatus captures the status of a migration job, currently only
// discs.
type MigrationJobStatus struct {
	Discs MigrationJobDiscStatus `json:"discs,omitempty"`
}

// MigrationJobSpec is a specification of a migration job to be created
type MigrationJobSpec struct {
	Options      MigrationJobOptions   `json:"options,omitempty"`
	Sources      MigrationJobLocations `json:"sources,omitempty"`
	Destinations MigrationJobLocations `json:"destinations,omitempty"`
}

// MigrationJob is a representation of a migration job.
type MigrationJob struct {
	ID           int                      `json:"id,omitempty"`
	Args         MigrationJobSpec         `json:"args,omitempty"`
	Queue        MigrationJobQueue        `json:"queue,omitempty"`
	Destinations MigrationJobDestinations `json:"destinations,omitempty"`
	Status       MigrationJobStatus       `json:"status,omitempty"`
	Priority     int                      `json:"priority,omitempty"`
	StartedAt    string                   `json:"started_at,omitempty"`
	FinishedAt   string                   `json:"finished_at,omitempty"`
	CreatedAt    string                   `json:"created_at,omitempty"`
	UpdatedAt    string                   `json:"updated_at,omitempty"`
}

// DefaultFields returns the list of default fields to feed to github.com/BytemarkHosting/row.From for this type.
func (mj MigrationJob) DefaultFields(f output.Format) string {
	return "ID, Queue, Destinations, Status, Priority, StartedAt, FinishedAt, CreatedAt, UpdatedAt"
}

// PrettyPrint formats a MigrationJobQueue for display
func (mjq MigrationJobQueue) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{ define "migration_job_queue_full" }}
{{- with .Discs }}
     discs:
{{- range . }}
       • {{.}}
{{- end }}
{{- end -}}
{{- end -}}{{- define "migration_job_queue_sgl" -}}{{ range .Discs }} {{.}}{{ end }}{{- end -}}`
	return prettyprint.Run(wr, template, "migration_job_queue"+string(detail), mjq)
}

// PrettyPrint formats a MigrationJobStatus for display
func (mjs MigrationJobStatus) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{- define "migration_job_status_full" -}}
{{- with .Discs -}}
{{- with .Done }}
     done:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- with .Errored }}
     errored:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- with .Cancelled }}
     cancelled:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- with .Skipped }}
     skipped:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- end -}}
{{- end -}}`
	return prettyprint.Run(wr, template, "migration_job_status"+string(detail), mjs)
}

// PrettyPrint outputs a nice human-readable overview of the migration
func (mj MigrationJob) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{ define "migration_job_full" }} ▸ {{ .ID }}
{{ with .Queue }}   queue: {{ prettysprint . "_full" }}
{{ end -}}{{- with .Status }}   status: {{ prettysprint . "_full" }}
{{ end -}}{{- with .Priority }}   priority: {{ . }}
{{ end -}}{{- with .StartedAt }}   started_at: {{ . }}
{{ end -}}{{- with .FinishedAt }}   finished_at: {{ . }}
{{ end -}}{{- with .CreatedAt }}   created_at: {{ . }}
{{ end -}}{{- with .UpdatedAt }}   updated_at: {{ . }}
{{ end -}}{{- end -}}{{- define "migration_job_medium" }} ▸ {{ .ID }} queue:{{ prettysprint .Queue "_sgl" }}
{{- end -}}{{- define "migration_job_sgl" -}}{{ template "migration_job_medium" . }}{{- end -}}`
	return prettyprint.Run(wr, template, "migration_job"+string(detail), mj)
}

// DefaultFields appeases quality tests
func (x MigrationJobDestinations) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobDestinations) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (x MigrationJobDiscStatus) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobDiscStatus) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (x MigrationJobLocations) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobLocations) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (x MigrationJobOptions) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobOptions) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (mjq MigrationJobQueue) DefaultFields(f output.Format) string {
	return ""
}

// DefaultFields appeases quality tests
func (x MigrationJobSpec) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobSpec) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (mjs MigrationJobStatus) DefaultFields(f output.Format) string {
	return ""
}
<commit_msg>removed unused package<commit_after>package brain

import (
	"io"

	"github.com/BytemarkHosting/bytemark-client/lib/output"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
	"github.com/BytemarkHosting/bytemark-client/lib/util"
)

//MigrationJobModification represents the modifications possible on a migration job
type MigrationJobModification struct {
	Cancel  MigrationJobLocations `json:"cancel,omitempty"`
	Options MigrationJobOptions   `json:"options,omitempty"`
}

// MigrationJobQueue is a list of disc IDs that are still to be migrated as
// part of a migration job.
type MigrationJobQueue struct {
	Discs []int `json:"discs,omitempty"`
}

// MigrationJobLocations represents source or target locations for a migration
// job. Discs, pools and tails maybe represented by ID number, label or UUID.
type MigrationJobLocations struct {
	Discs []util.NumberOrString `json:"discs,omitempty"`
	Pools []util.NumberOrString `json:"pools,omitempty"`
	Tails []util.NumberOrString `json:"tails,omitempty"`
}

// MigrationJobDestinations represents available desintations for a migration
// job. Unlike MigrationJobLocations, these are represented using ID number
// only.
type MigrationJobDestinations struct {
	Pools []int `json:"pools,omitempty"`
}

// MigrationJobOptions represents options on a migration job.
type MigrationJobOptions struct {
	Priority int `json:"priority,omitempty"`
}

// MigrationJobDiscStatus represents the current status of a migration job.
// Each entry is a list of disc IDs indicating the fate of discs that
// have been removed from the queue.
type MigrationJobDiscStatus struct {
	Done      []int `json:"done,omitempty"`
	Errored   []int `json:"errored,omitempty"`
	Cancelled []int `json:"cancelled,omitempty"`
	Skipped   []int `json:"skipped,omitempty"`
}

// MigrationJobStatus captures the status of a migration job, currently only
// discs.
type MigrationJobStatus struct {
	Discs MigrationJobDiscStatus `json:"discs,omitempty"`
}

// MigrationJobSpec is a specification of a migration job to be created
type MigrationJobSpec struct {
	Options      MigrationJobOptions   `json:"options,omitempty"`
	Sources      MigrationJobLocations `json:"sources,omitempty"`
	Destinations MigrationJobLocations `json:"destinations,omitempty"`
}

// MigrationJob is a representation of a migration job.
type MigrationJob struct {
	ID           int                      `json:"id,omitempty"`
	Args         MigrationJobSpec         `json:"args,omitempty"`
	Queue        MigrationJobQueue        `json:"queue,omitempty"`
	Destinations MigrationJobDestinations `json:"destinations,omitempty"`
	Status       MigrationJobStatus       `json:"status,omitempty"`
	Priority     int                      `json:"priority,omitempty"`
	StartedAt    string                   `json:"started_at,omitempty"`
	FinishedAt   string                   `json:"finished_at,omitempty"`
	CreatedAt    string                   `json:"created_at,omitempty"`
	UpdatedAt    string                   `json:"updated_at,omitempty"`
}

// DefaultFields returns the list of default fields to feed to github.com/BytemarkHosting/row.From for this type.
func (mj MigrationJob) DefaultFields(f output.Format) string {
	return "ID, Queue, Destinations, Status, Priority, StartedAt, FinishedAt, CreatedAt, UpdatedAt"
}

// PrettyPrint formats a MigrationJobQueue for display
func (mjq MigrationJobQueue) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{ define "migration_job_queue_full" }}
{{- with .Discs }}
     discs:
{{- range . }}
       • {{.}}
{{- end }}
{{- end -}}
{{- end -}}{{- define "migration_job_queue_sgl" -}}{{ range .Discs }} {{.}}{{ end }}{{- end -}}`
	return prettyprint.Run(wr, template, "migration_job_queue"+string(detail), mjq)
}

// PrettyPrint formats a MigrationJobStatus for display
func (mjs MigrationJobStatus) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{- define "migration_job_status_full" -}}
{{- with .Discs -}}
{{- with .Done }}
     done:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- with .Errored }}
     errored:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- with .Cancelled }}
     cancelled:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- with .Skipped }}
     skipped:
    {{- range . }}
       • {{.}}
    {{- end }}
{{- end -}}
{{- end -}}
{{- end -}}`
	return prettyprint.Run(wr, template, "migration_job_status"+string(detail), mjs)
}

// PrettyPrint outputs a nice human-readable overview of the migration
func (mj MigrationJob) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{ define "migration_job_full" }} ▸ {{ .ID }}
{{ with .Queue }}   queue: {{ prettysprint . "_full" }}
{{ end -}}{{- with .Status }}   status: {{ prettysprint . "_full" }}
{{ end -}}{{- with .Priority }}   priority: {{ . }}
{{ end -}}{{- with .StartedAt }}   started_at: {{ . }}
{{ end -}}{{- with .FinishedAt }}   finished_at: {{ . }}
{{ end -}}{{- with .CreatedAt }}   created_at: {{ . }}
{{ end -}}{{- with .UpdatedAt }}   updated_at: {{ . }}
{{ end -}}{{- end -}}{{- define "migration_job_medium" }} ▸ {{ .ID }} queue:{{ prettysprint .Queue "_sgl" }}
{{- end -}}{{- define "migration_job_sgl" -}}{{ template "migration_job_medium" . }}{{- end -}}`
	return prettyprint.Run(wr, template, "migration_job"+string(detail), mj)
}

// DefaultFields appeases quality tests
func (x MigrationJobDestinations) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobDestinations) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (x MigrationJobDiscStatus) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobDiscStatus) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (x MigrationJobLocations) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobLocations) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (x MigrationJobOptions) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobOptions) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (mjq MigrationJobQueue) DefaultFields(f output.Format) string {
	return ""
}

// DefaultFields appeases quality tests
func (x MigrationJobSpec) DefaultFields(f output.Format) string {
	return ""
}

// PrettyPrint appeases quality tests
func (x MigrationJobSpec) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	return nil
}

// DefaultFields appeases quality tests
func (mjs MigrationJobStatus) DefaultFields(f output.Format) string {
	return ""
}
<|endoftext|>


<commit_before>package api

import (
	"net/http"

	log "github.com/Sirupsen/logrus"
)

func (r *Server) purge(w http.ResponseWriter, req *http.Request) {
	apps, err := r.db.ListApps()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	cmps, err := r.db.ListComposes()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	go func() {
		// remove apps
		for _, app := range apps {
			var appId = app.ID

			tasks, err := r.db.ListTasks(appId)
			if err != nil {
				log.Errorf("Purge() list app %s tasks error: %v", appId, err)
				continue
			}

			versions, err := r.db.ListVersions(appId)
			if err != nil {
				log.Errorf("Purge() list app %s versions error: %v", appId, err)
				continue
			}

			if err = r.delApp(appId, tasks, versions); err != nil {
				log.Errorf("Purge() delte app %s error: %v", appId, err)
				continue
			}
		}

		// remove composes
		for _, cmp := range cmps {
			if err := r.db.DeleteCompose(cmp.ID); err != nil {
				log.Errorf("Purege() remove db compose %s error: %v", cmp.ID, err)
				continue
			}
		}
	}()

	writeJSON(w, http.StatusNoContent, "")
}
<commit_msg>bugfix for purge to prevent task to be rescheduled.<commit_after>package api

import (
	"net/http"

	"github.com/Dataman-Cloud/swan/types"
	log "github.com/Sirupsen/logrus"
)

func (r *Server) purge(w http.ResponseWriter, req *http.Request) {
	apps, err := r.db.ListApps()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	cmps, err := r.db.ListComposes()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	go func() {
		// remove apps
		for _, app := range apps {
			var appId = app.ID

			tasks, err := r.db.ListTasks(appId)
			if err != nil {
				log.Errorf("Purge() list app %s tasks error: %v", appId, err)
				continue
			}

			versions, err := r.db.ListVersions(appId)
			if err != nil {
				log.Errorf("Purge() list app %s versions error: %v", appId, err)
				continue
			}
			// mark app op status
			if err := r.memoAppStatus(appId, types.OpStatusDeleting, ""); err != nil {
				log.Errorf("Purge() update app opstatus to deleting got error: %v", err)
				continue
			}

			if err = r.delApp(appId, tasks, versions); err != nil {
				log.Errorf("Purge() delte app %s error: %v", appId, err)
				continue
			}
		}

		// remove composes
		for _, cmp := range cmps {
			if err := r.db.DeleteCompose(cmp.ID); err != nil {
				log.Errorf("Purege() remove db compose %s error: %v", cmp.ID, err)
				continue
			}
		}
	}()

	writeJSON(w, http.StatusNoContent, "")
}
<|endoftext|>


<commit_before>package gofakeit

import (
	"fmt"
	"testing"
)

func TestGenerate(t *testing.T) {
	var numTests int = 100

	for i := 0; i < numTests; i++ {
		Generate("{name.first} {name.last} {contact.email} #?#?#?")
	}
}

func ExampleGenerate() {
	fmt.Println(Generate("{name.first} {name.last} lives at {address.number} {address.street_name} {address.street_suffix}"))
	// Output: Estell Fay lives at 54407 Plaza berg
}

func BenchmarkGenerate(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Generate("{name.first} {name.last} {contact.email} #?#?#?")
	}
}
<commit_msg>generate - added seeded.<commit_after>package gofakeit

import (
	"fmt"
	"testing"
)

func TestGenerate(t *testing.T) {
	var numTests int = 100

	for i := 0; i < numTests; i++ {
		Generate("{name.first} {name.last} {contact.email} #?#?#?")
	}
}

func ExampleGenerate() {
	Seed(11)
	fmt.Println(Generate("{name.first} {name.last} lives at {address.number} {address.street_name} {address.street_suffix}"))
	// Output: Markus Moen lives at 715 Garden mouth
}

func BenchmarkGenerate(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Generate("{name.first} {name.last} {contact.email} #?#?#?")
	}
}
<|endoftext|>


<commit_before>package webcam

import (
	"encoding/base64"
	"fmt"
	"strconv"

	"github.com/project-flogo/core/activity"
	"github.com/project-flogo/core/data/metadata"
	"gocv.io/x/gocv"
)

func init() {
	_ = activity.Register(&Activity{}, New)
}

var activityMd = activity.ToMetadata(&Output{})

// Activity is a kafka activity
type Activity struct {
	deviceID    int
	imageWidth  int
	imageHeight int
}

// New create a new  activity
func New(ctx activity.InitContext) (activity.Activity, error) {
	settings := &Settings{}
	ctx.Logger().Info("Settings done.")

	err := metadata.MapToStruct(ctx.Settings(), settings, true)
	if err != nil {
		return nil, err
	}

	deviceID, err := strconv.Atoi(settings.DeviceID)
	ctx.Logger().Info("deviceID has been set: ", deviceID)

	imageWidth := settings.ImageWidth
	imageHeight := settings.ImageHeigth

	ctx.Logger().Info("Image resolution has been set to: ", imageWidth, "x", imageHeight)

	act := &Activity{deviceID: deviceID, imageWidth: imageWidth, imageHeight: imageHeight}
	return act, nil
}

// Metadata returns the metadata for the kafka activity
func (*Activity) Metadata() *activity.Metadata {
	return activityMd
}

// Eval implements the evaluation of the kafka activity
func (act *Activity) Eval(ctx activity.Context) (done bool, err error) {
	//settings := &Settings{}

	webcam, err := gocv.OpenVideoCapture(act.deviceID)

	webcam.Set(gocv.VideoCaptureFrameWidth, float64(act.imageWidth))
	webcam.Set(gocv.VideoCaptureFrameHeight, float64(act.imageHeight))

	if err != nil {
		fmt.Printf("Error opening video capture device: %v\n", act.deviceID)
		return
	}
	defer webcam.Close()

	img := gocv.NewMat()
	defer img.Close()

	ctx.Logger().Info("Webcam is taking a picture...")
	if ok := webcam.Read(&img); !ok {
		fmt.Printf("cannot read device %v\n", act.deviceID)
		return
	}
	if img.Empty() {
		fmt.Printf("no image on device %v\n", act.deviceID)
		return
	}
	ctx.Logger().Info("Done. Image captured.")

	imgByte := img.ToBytes()
	//ctx.Logger().Info(imgByte)
	//gocv.IMWrite("test.png", img) //just for debug

	base64String := base64.StdEncoding.EncodeToString(imgByte)

	output := &Output{}
	output.Image = imgByte
	output.Base64String = base64String
	output.Status = "OK"

	/*
		if ctx.Logger().DebugEnabled() {
			ctx.Logger().Debugf("Kafka message [%v] sent successfully on partition [%d] and offset [%d]",
				input.Message, partition, offset)
		}
	*/

	err = ctx.SetOutputObject(output)
	if err != nil {
		return false, err
	}

	return true, nil
}
<commit_msg>added PNG compression<commit_after>package webcam

import (
	"encoding/base64"
	"fmt"
	"strconv"

	"github.com/project-flogo/core/activity"
	"github.com/project-flogo/core/data/metadata"
	"gocv.io/x/gocv"
)

func init() {
	_ = activity.Register(&Activity{}, New)
}

var activityMd = activity.ToMetadata(&Output{})

// Activity is a kafka activity
type Activity struct {
	deviceID    int
	imageWidth  int
	imageHeight int
}

// New create a new  activity
func New(ctx activity.InitContext) (activity.Activity, error) {
	settings := &Settings{}
	ctx.Logger().Info("Settings done.")

	err := metadata.MapToStruct(ctx.Settings(), settings, true)
	if err != nil {
		return nil, err
	}

	deviceID, err := strconv.Atoi(settings.DeviceID)
	ctx.Logger().Info("deviceID has been set: ", deviceID)

	imageWidth := settings.ImageWidth
	imageHeight := settings.ImageHeigth

	ctx.Logger().Info("Image resolution has been set to: ", imageWidth, "x", imageHeight)

	act := &Activity{deviceID: deviceID, imageWidth: imageWidth, imageHeight: imageHeight}
	return act, nil
}

// Metadata returns the metadata for the kafka activity
func (*Activity) Metadata() *activity.Metadata {
	return activityMd
}

// Eval implements the evaluation of the kafka activity
func (act *Activity) Eval(ctx activity.Context) (done bool, err error) {
	//settings := &Settings{}

	webcam, err := gocv.OpenVideoCapture(act.deviceID)

	webcam.Set(gocv.VideoCaptureFrameWidth, float64(act.imageWidth))
	webcam.Set(gocv.VideoCaptureFrameHeight, float64(act.imageHeight))

	if err != nil {
		fmt.Printf("Error opening video capture device: %v\n", act.deviceID)
		return
	}
	defer webcam.Close()

	img := gocv.NewMat()
	defer img.Close()

	ctx.Logger().Info("Webcam is taking a picture...")
	if ok := webcam.Read(&img); !ok {
		fmt.Printf("cannot read device %v\n", act.deviceID)
		return
	}
	if img.Empty() {
		fmt.Printf("no image on device %v\n", act.deviceID)
		return
	}
	ctx.Logger().Info("Done. Image captured.")

	imgByte := img.ToBytes()
	//ctx.Logger().Info(imgByte)
	//gocv.IMWrite("test.png", img) //just for debug

	buff, err := gocv.IMEncodeWithParams(gocv.PNGFileExt, img, []int{gocv.IMWritePngCompression, 10})

	//gocv.IMEncodeWithParams(gocv.JPEGFileExt, img, []int{gocv.IMWriteJpegQuality, quality})

	base64String := base64.StdEncoding.EncodeToString(buff)

	output := &Output{}
	output.Image = imgByte
	output.Base64String = base64String
	output.Status = "OK"

	/*
		if ctx.Logger().DebugEnabled() {
			ctx.Logger().Debugf("Kafka message [%v] sent successfully on partition [%d] and offset [%d]",
				input.Message, partition, offset)
		}
	*/

	err = ctx.SetOutputObject(output)
	if err != nil {
		return false, err
	}

	return true, nil
}
<|endoftext|>


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

package main

import (
	"errors"
	"fmt"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/exec"
	"io/ioutil"
	"net/http"
	"os"
)

type pluginInstall struct{}

func (pluginInstall) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin-install",
		Usage:   "plugin-install <plugin-name> <plugin-url>",
		Desc:    "Install tsuru plugins.",
		MinArgs: 2,
	}
}

func (c *pluginInstall) Run(context *cmd.Context, client *cmd.Client) error {
	pluginsDir := cmd.JoinWithUserDir(".tsuru", "plugins")
	err := filesystem().MkdirAll(pluginsDir, 0755)
	if err != nil {
		return err
	}
	pluginName := context.Args[0]
	pluginUrl := context.Args[1]
	pluginPath := cmd.JoinWithUserDir(".tsuru", "plugins", pluginName)
	file, err := filesystem().OpenFile(pluginPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
	if err != nil {
		return err
	}
	resp, err := http.Get(pluginUrl)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	n, err := file.Write(data)
	if err != nil {
		return err
	}
	if n != len(data) {
		return errors.New("Failed to install plugin.")
	}
	fmt.Fprintf(context.Stdout, `Plugin "%s" successfully installed!`+"\n", pluginName)
	return nil
}

type plugin struct{}

func (plugin) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin",
		Usage:   "plugin <plugin-name> [<args>]",
		Desc:    "Execute tsuru plugins.",
		MinArgs: 1,
	}
}

func (c *plugin) Run(context *cmd.Context, client *cmd.Client) error {
	pluginName := context.Args[0]
	pluginPath := cmd.JoinWithUserDir(".tsuru", "plugins", pluginName)
	target, err := cmd.ReadTarget()
	if err != nil {
		return err
	}
	token, err := cmd.ReadToken()
	if err != nil {
		return err
	}
	envs := []string{
		fmt.Sprintf("TSURU_TARGET=%s", target),
		fmt.Sprintf("TSURU_TOKEN=%s", token),
	}
	opts := exec.ExecuteOptions{
		Cmd:    pluginPath,
		Args:   context.Args[1:],
		Stdout: context.Stdout,
		Stderr: context.Stderr,
		Envs:   envs,
	}
	return executor().Execute(opts)
}

type pluginRemove struct{}

func (pluginRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin-remove",
		Usage:   "plugin-remove <plugin-name>",
		Desc:    "Remove tsuru plugins.",
		MinArgs: 1,
	}
}

func (c *pluginRemove) Run(context *cmd.Context, client *cmd.Client) error {
	pluginName := context.Args[0]
	pluginPath := cmd.JoinWithUserDir(".tsuru", "plugins", pluginName)
	err := filesystem().Remove(pluginPath)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, `Plugin "%s" successfully removed!`+"\n", pluginName)
	return nil
}

type pluginList struct{}

func (pluginList) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin-list",
		Usage:   "plugin-list",
		Desc:    "List installed tsuru plugins.",
		MinArgs: 0,
	}
}

func (c *pluginList) Run(context *cmd.Context, client *cmd.Client) error {
	pluginsPath := cmd.JoinWithUserDir(".tsuru", "plugins")
	plugins, _ := ioutil.ReadDir(pluginsPath)
	for _, p := range plugins {
		fmt.Println(p.Name())
	}
	return nil
}
<commit_msg>plugin: provide stdin in command execution<commit_after>// Copyright 2014 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"fmt"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/exec"
	"io/ioutil"
	"net/http"
	"os"
)

type pluginInstall struct{}

func (pluginInstall) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin-install",
		Usage:   "plugin-install <plugin-name> <plugin-url>",
		Desc:    "Install tsuru plugins.",
		MinArgs: 2,
	}
}

func (c *pluginInstall) Run(context *cmd.Context, client *cmd.Client) error {
	pluginsDir := cmd.JoinWithUserDir(".tsuru", "plugins")
	err := filesystem().MkdirAll(pluginsDir, 0755)
	if err != nil {
		return err
	}
	pluginName := context.Args[0]
	pluginUrl := context.Args[1]
	pluginPath := cmd.JoinWithUserDir(".tsuru", "plugins", pluginName)
	file, err := filesystem().OpenFile(pluginPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
	if err != nil {
		return err
	}
	resp, err := http.Get(pluginUrl)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	n, err := file.Write(data)
	if err != nil {
		return err
	}
	if n != len(data) {
		return errors.New("Failed to install plugin.")
	}
	fmt.Fprintf(context.Stdout, `Plugin "%s" successfully installed!`+"\n", pluginName)
	return nil
}

type plugin struct{}

func (plugin) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin",
		Usage:   "plugin <plugin-name> [<args>]",
		Desc:    "Execute tsuru plugins.",
		MinArgs: 1,
	}
}

func (c *plugin) Run(context *cmd.Context, client *cmd.Client) error {
	pluginName := context.Args[0]
	pluginPath := cmd.JoinWithUserDir(".tsuru", "plugins", pluginName)
	target, err := cmd.ReadTarget()
	if err != nil {
		return err
	}
	token, err := cmd.ReadToken()
	if err != nil {
		return err
	}
	envs := []string{
		fmt.Sprintf("TSURU_TARGET=%s", target),
		fmt.Sprintf("TSURU_TOKEN=%s", token),
	}
	opts := exec.ExecuteOptions{
		Cmd:    pluginPath,
		Args:   context.Args[1:],
		Stdout: context.Stdout,
		Stderr: context.Stderr,
		Stdin:  context.Stdin,
		Envs:   envs,
	}
	return executor().Execute(opts)
}

type pluginRemove struct{}

func (pluginRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin-remove",
		Usage:   "plugin-remove <plugin-name>",
		Desc:    "Remove tsuru plugins.",
		MinArgs: 1,
	}
}

func (c *pluginRemove) Run(context *cmd.Context, client *cmd.Client) error {
	pluginName := context.Args[0]
	pluginPath := cmd.JoinWithUserDir(".tsuru", "plugins", pluginName)
	err := filesystem().Remove(pluginPath)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, `Plugin "%s" successfully removed!`+"\n", pluginName)
	return nil
}

type pluginList struct{}

func (pluginList) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "plugin-list",
		Usage:   "plugin-list",
		Desc:    "List installed tsuru plugins.",
		MinArgs: 0,
	}
}

func (c *pluginList) Run(context *cmd.Context, client *cmd.Client) error {
	pluginsPath := cmd.JoinWithUserDir(".tsuru", "plugins")
	plugins, _ := ioutil.ReadDir(pluginsPath)
	for _, p := range plugins {
		fmt.Println(p.Name())
	}
	return nil
}
<|endoftext|>


<commit_before>package hawser

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cheggaaa/pb"
	"github.com/rubyist/tracerx"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path/filepath"
)

const (
	gitMediaType     = "application/vnd.git-media"
	gitMediaMetaType = gitMediaType + "+json; charset=utf-8"
)

type linkMeta struct {
	Links map[string]*link `json:"_links,omitempty"`
}

func (l *linkMeta) Rel(name string) (*link, bool) {
	if l.Links == nil {
		return nil, false
	}

	lnk, ok := l.Links[name]
	return lnk, ok
}

type link struct {
	Href   string            `json:"href"`
	Header map[string]string `json:"header,omitempty"`
}

type UploadRequest struct {
	OidPath      string
	Filename     string
	CopyCallback CopyCallback
}

func Download(oidPath string) (io.ReadCloser, int64, *WrappedError) {
	oid := filepath.Base(oidPath)
	req, creds, err := clientRequest("GET", oid)
	if err != nil {
		return nil, 0, Error(err)
	}

	req.Header.Set("Accept", gitMediaType)
	res, wErr := doRequest(req, creds)

	if wErr != nil {
		return nil, 0, wErr
	}

	contentType := res.Header.Get("Content-Type")
	if contentType == "" {
		wErr = Error(errors.New("Empty Content-Type"))
		setErrorResponseContext(wErr, res)
		return nil, 0, wErr
	}

	ok, headerSize, wErr := validateMediaHeader(contentType, res.Body)
	if !ok {
		setErrorResponseContext(wErr, res)
		return nil, 0, wErr
	}

	return res.Body, res.ContentLength - int64(headerSize), nil
}

func Upload(oidPath, filename string, cb CopyCallback) *WrappedError {
	linkMeta, status, err := callPost(oidPath, filename)
	if err != nil && status != 302 {
		return Errorf(err, "Error starting file upload.")
	}

	oid := filepath.Base(oidPath)

	switch status {
	case 200: // object exists on the server
	case 405, 302:
		// Do the old style OPTIONS + PUT
		status, wErr := callOptions(oidPath)
		if wErr != nil {
			return wErr
		}

		if status != 200 {
			err = callPut(oidPath, filename, cb)
			if err != nil {
				return Errorf(err, "Error uploading file %s (%s)", filename, oid)
			}
		}
	case 202:
		// the server responded with hypermedia links to upload and verify the object.
		err = callExternalPut(oidPath, filename, linkMeta, cb)
		if err != nil {
			return Errorf(err, "Error uploading file %s (%s)", filename, oid)
		}
	default:
		return Errorf(err, "Unexpected HTTP response: %d", status)
	}

	return nil
}

func callOptions(filehash string) (int, *WrappedError) {
	oid := filepath.Base(filehash)
	_, err := os.Stat(filehash)
	if err != nil {
		return 0, Errorf(err, "Internal object does not exist: %s", filehash)
	}

	tracerx.Printf("api_options: %s", oid)
	req, creds, err := clientRequest("OPTIONS", oid)
	if err != nil {
		return 0, Errorf(err, "Unable to build OPTIONS request for %s", oid)
	}

	res, wErr := doRequest(req, creds)
	if wErr != nil {
		return 0, wErr
	}
	tracerx.Printf("api_options_status: %d", res.StatusCode)

	return res.StatusCode, nil
}

func callPut(filehash, filename string, cb CopyCallback) *WrappedError {
	if filename == "" {
		filename = filehash
	}

	oid := filepath.Base(filehash)
	file, err := os.Open(filehash)
	if err != nil {
		return Errorf(err, "Internal object does not exist: %s", filehash)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return Errorf(err, "Internal object does not exist: %s", filehash)
	}

	req, creds, err := clientRequest("PUT", oid)
	if err != nil {
		return Errorf(err, "Unable to build PUT request for %s", oid)
	}

	fileSize := stat.Size()
	reader := &CallbackReader{
		C:         cb,
		TotalSize: fileSize,
		Reader:    file,
	}

	bar := pb.StartNew(int(fileSize))
	bar.SetUnits(pb.U_BYTES)
	bar.Start()

	req.Header.Set("Content-Type", gitMediaType)
	req.Header.Set("Accept", gitMediaMetaType)
	req.Body = ioutil.NopCloser(bar.NewProxyReader(reader))
	req.ContentLength = fileSize

	fmt.Printf("Sending %s\n", filename)

	tracerx.Printf("api_put: %s %s", oid, filename)
	res, wErr := doRequest(req, creds)
	tracerx.Printf("api_put_status: %d", res.StatusCode)

	return wErr
}

func callExternalPut(filehash, filename string, lm *linkMeta, cb CopyCallback) *WrappedError {
	if lm == nil {
		return Errorf(errors.New("No hypermedia links provided"),
			"Error attempting to PUT %s", filename)
	}

	link, ok := lm.Rel("upload")
	if !ok {
		return Errorf(errors.New("No upload link provided"),
			"Error attempting to PUT %s", filename)
	}

	file, err := os.Open(filehash)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	fileSize := stat.Size()
	reader := &CallbackReader{
		C:         cb,
		TotalSize: fileSize,
		Reader:    file,
	}

	req, err := http.NewRequest("PUT", link.Href, nil)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	for h, v := range link.Header {
		req.Header.Set(h, v)
	}

	bar := pb.StartNew(int(fileSize))
	bar.SetUnits(pb.U_BYTES)
	bar.Start()

	req.Body = ioutil.NopCloser(bar.NewProxyReader(reader))
	req.ContentLength = fileSize

	tracerx.Printf("external_put: %s %s", filepath.Base(filehash), req.URL)
	res, err := DoHTTP(Config, req)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	tracerx.Printf("external_put_status: %d", res.StatusCode)

	// Run the verify callback
	if cb, ok := lm.Rel("verify"); ok {
		oid := filepath.Base(filehash)

		cbreq, err := http.NewRequest("POST", cb.Href, nil)
		if err != nil {
			return Error(err)
		}
		for h, v := range cb.Header {
			cbreq.Header.Set(h, v)
		}

		d := fmt.Sprintf(`{"oid":"%s", "size":%d}`, oid, fileSize)
		cbreq.Body = ioutil.NopCloser(bytes.NewBufferString(d))

		tracerx.Printf("verify: %s %s", oid, cb.Href)
		cbres, err := DoHTTP(Config, cbreq)
		if err != nil {
			return Errorf(err, "Error attempting to verify %s", filename)
		}
		tracerx.Printf("verify_status: %d", cbres.StatusCode)
	}

	return nil
}

func callPost(filehash, filename string) (*linkMeta, int, *WrappedError) {
	oid := filepath.Base(filehash)
	req, creds, err := clientRequest("POST", "")
	if err != nil {
		return nil, 0, Errorf(err, "Error attempting to POST %s", filename)
	}

	file, err := os.Open(filehash)
	if err != nil {
		return nil, 0, Errorf(err, "Error attempting to POST %s", filename)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return nil, 0, Errorf(err, "Error attempting to POST %s", filename)
	}
	fileSize := stat.Size()

	d := fmt.Sprintf(`{"oid":"%s", "size":%d}`, oid, fileSize)
	req.Body = ioutil.NopCloser(bytes.NewBufferString(d))

	req.Header.Set("Accept", gitMediaMetaType)

	tracerx.Printf("api_post: %s %s", oid, filename)
	res, wErr := doRequest(req, creds)
	if wErr != nil {
		return nil, 0, wErr
	}
	tracerx.Printf("api_post_status: %d", res.StatusCode)

	if res.StatusCode == 202 {
		lm := &linkMeta{}
		dec := json.NewDecoder(res.Body)
		err := dec.Decode(lm)
		if err != nil {
			return nil, res.StatusCode, Errorf(err, "Error decoding JSON from %s %s.", req.Method, req.URL)
		}

		return lm, res.StatusCode, nil
	}

	return nil, res.StatusCode, nil
}

func validateMediaHeader(contentType string, reader io.Reader) (bool, int, *WrappedError) {
	mediaType, params, err := mime.ParseMediaType(contentType)
	var headerSize int

	if err != nil {
		return false, headerSize, Errorf(err, "Invalid Media Type: %s", contentType)
	}

	if mediaType == gitMediaType {

		givenHeader, ok := params["header"]
		if !ok {
			return false, headerSize, Error(fmt.Errorf("Missing Git Media header in %s", contentType))
		}

		fullGivenHeader := "--" + givenHeader + "\n"
		headerSize = len(fullGivenHeader)

		header := make([]byte, headerSize)
		_, err = io.ReadAtLeast(reader, header, len(fullGivenHeader))
		if err != nil {
			return false, headerSize, Errorf(err, "Error reading response body.")
		}

		if string(header) != fullGivenHeader {
			return false, headerSize, Error(fmt.Errorf("Invalid header: %s expected, got %s", fullGivenHeader, header))
		}
	}
	return true, headerSize, nil
}

func doRequest(req *http.Request, creds Creds) (*http.Response, *WrappedError) {
	res, err := DoHTTP(Config, req)

	var wErr *WrappedError

	if err == RedirectError {
		err = nil
	}

	if err == nil {
		if creds != nil {
			saveCredentials(creds, res)
		}

		wErr = handleResponseError(res)
	} else if res.StatusCode != 302 { // hack for pre-release
		wErr = Errorf(err, "Error sending HTTP request to %s", req.URL.String())
	}

	if wErr != nil {
		if res != nil {
			setErrorResponseContext(wErr, res)
		} else {
			setErrorRequestContext(wErr, req)
		}
	}

	return res, wErr
}

func handleResponseError(res *http.Response) *WrappedError {
	if res.StatusCode < 400 || res.StatusCode == 405 {
		return nil
	}

	var wErr *WrappedError
	apiErr := &ClientError{}
	dec := json.NewDecoder(res.Body)
	if err := dec.Decode(apiErr); err != nil {
		wErr = Errorf(err, "Error decoding JSON from response")
	} else {
		var msg string
		switch res.StatusCode {
		case 401, 403:
			msg = fmt.Sprintf("Authorization error: %s\nCheck that you have proper access to the repository.", res.Request.URL)
		case 404:
			msg = fmt.Sprintf("Repository not found: %s\nCheck that it exists and that you have proper access to it.", res.Request.URL)
		default:
			msg = fmt.Sprintf("Invalid response: %d", res.StatusCode)
		}

		wErr = Errorf(apiErr, msg)
	}

	if res.StatusCode < 500 {
		wErr.Panic = false
	}

	return wErr
}

func saveCredentials(creds Creds, res *http.Response) {
	if res.StatusCode < 300 {
		execCreds(creds, "approve")
		return
	}

	if res.StatusCode < 405 {
		execCreds(creds, "reject")
	}
}

var hiddenHeaders = map[string]bool{
	"Authorization": true,
}

func setErrorRequestContext(err *WrappedError, req *http.Request) {
	err.Set("Endpoint", Config.Endpoint())
	err.Set("URL", fmt.Sprintf("%s %s", req.Method, req.URL.String()))
	setErrorHeaderContext(err, "Response", req.Header)
}

func setErrorResponseContext(err *WrappedError, res *http.Response) {
	err.Set("Status", res.Status)
	setErrorHeaderContext(err, "Request", res.Header)
	setErrorRequestContext(err, res.Request)
}

func setErrorHeaderContext(err *WrappedError, prefix string, head http.Header) {
	for key, _ := range head {
		contextKey := fmt.Sprintf("%s:%s", prefix, key)
		if _, skip := hiddenHeaders[key]; skip {
			err.Set(contextKey, "--")
		} else {
			err.Set(contextKey, head.Get(key))
		}
	}
}

func clientRequest(method, oid string) (*http.Request, Creds, error) {
	u := Config.ObjectUrl(oid)
	req, err := http.NewRequest(method, u.String(), nil)
	req.Header.Set("User-Agent", UserAgent)
	if err == nil {
		creds, err := credentials(u)
		if err != nil {
			return req, nil, err
		}

		token := fmt.Sprintf("%s:%s", creds["username"], creds["password"])
		auth := "Basic " + base64.URLEncoding.EncodeToString([]byte(token))
		req.Header.Set("Authorization", auth)
		return req, creds, nil
	}

	return req, nil, err
}

type ClientError struct {
	Message   string `json:"message"`
	RequestId string `json:"request_id,omitempty"`
}

func (e *ClientError) Error() string {
	return e.Message
}
<commit_msg>get/set credentials for external put and verify requests<commit_after>package hawser

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cheggaaa/pb"
	"github.com/rubyist/tracerx"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path/filepath"
)

const (
	gitMediaType     = "application/vnd.git-media"
	gitMediaMetaType = gitMediaType + "+json; charset=utf-8"
)

type linkMeta struct {
	Links map[string]*link `json:"_links,omitempty"`
}

func (l *linkMeta) Rel(name string) (*link, bool) {
	if l.Links == nil {
		return nil, false
	}

	lnk, ok := l.Links[name]
	return lnk, ok
}

type link struct {
	Href   string            `json:"href"`
	Header map[string]string `json:"header,omitempty"`
}

type UploadRequest struct {
	OidPath      string
	Filename     string
	CopyCallback CopyCallback
}

func Download(oidPath string) (io.ReadCloser, int64, *WrappedError) {
	oid := filepath.Base(oidPath)
	req, creds, err := request("GET", oid)
	if err != nil {
		return nil, 0, Error(err)
	}

	req.Header.Set("Accept", gitMediaType)
	res, wErr := doRequest(req, creds)

	if wErr != nil {
		return nil, 0, wErr
	}

	contentType := res.Header.Get("Content-Type")
	if contentType == "" {
		wErr = Error(errors.New("Empty Content-Type"))
		setErrorResponseContext(wErr, res)
		return nil, 0, wErr
	}

	ok, headerSize, wErr := validateMediaHeader(contentType, res.Body)
	if !ok {
		setErrorResponseContext(wErr, res)
		return nil, 0, wErr
	}

	return res.Body, res.ContentLength - int64(headerSize), nil
}

func Upload(oidPath, filename string, cb CopyCallback) *WrappedError {
	linkMeta, status, err := callPost(oidPath, filename)
	if err != nil && status != 302 {
		return Errorf(err, "Error starting file upload.")
	}

	oid := filepath.Base(oidPath)

	switch status {
	case 200: // object exists on the server
	case 405, 302:
		// Do the old style OPTIONS + PUT
		status, wErr := callOptions(oidPath)
		if wErr != nil {
			return wErr
		}

		if status != 200 {
			err = callPut(oidPath, filename, cb)
			if err != nil {
				return Errorf(err, "Error uploading file %s (%s)", filename, oid)
			}
		}
	case 202:
		// the server responded with hypermedia links to upload and verify the object.
		err = callExternalPut(oidPath, filename, linkMeta, cb)
		if err != nil {
			return Errorf(err, "Error uploading file %s (%s)", filename, oid)
		}
	default:
		return Errorf(err, "Unexpected HTTP response: %d", status)
	}

	return nil
}

func callOptions(filehash string) (int, *WrappedError) {
	oid := filepath.Base(filehash)
	_, err := os.Stat(filehash)
	if err != nil {
		return 0, Errorf(err, "Internal object does not exist: %s", filehash)
	}

	tracerx.Printf("api_options: %s", oid)
	req, creds, err := request("OPTIONS", oid)
	if err != nil {
		return 0, Errorf(err, "Unable to build OPTIONS request for %s", oid)
	}

	res, wErr := doRequest(req, creds)
	if wErr != nil {
		return 0, wErr
	}
	tracerx.Printf("api_options_status: %d", res.StatusCode)

	return res.StatusCode, nil
}

func callPut(filehash, filename string, cb CopyCallback) *WrappedError {
	if filename == "" {
		filename = filehash
	}

	oid := filepath.Base(filehash)
	file, err := os.Open(filehash)
	if err != nil {
		return Errorf(err, "Internal object does not exist: %s", filehash)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return Errorf(err, "Internal object does not exist: %s", filehash)
	}

	req, creds, err := request("PUT", oid)
	if err != nil {
		return Errorf(err, "Unable to build PUT request for %s", oid)
	}

	fileSize := stat.Size()
	reader := &CallbackReader{
		C:         cb,
		TotalSize: fileSize,
		Reader:    file,
	}

	bar := pb.StartNew(int(fileSize))
	bar.SetUnits(pb.U_BYTES)
	bar.Start()

	req.Header.Set("Content-Type", gitMediaType)
	req.Header.Set("Accept", gitMediaMetaType)
	req.Body = ioutil.NopCloser(bar.NewProxyReader(reader))
	req.ContentLength = fileSize

	fmt.Printf("Sending %s\n", filename)

	tracerx.Printf("api_put: %s %s", oid, filename)
	res, wErr := doRequest(req, creds)
	tracerx.Printf("api_put_status: %d", res.StatusCode)

	return wErr
}

func callExternalPut(filehash, filename string, lm *linkMeta, cb CopyCallback) *WrappedError {
	if lm == nil {
		return Errorf(errors.New("No hypermedia links provided"),
			"Error attempting to PUT %s", filename)
	}

	link, ok := lm.Rel("upload")
	if !ok {
		return Errorf(errors.New("No upload link provided"),
			"Error attempting to PUT %s", filename)
	}

	file, err := os.Open(filehash)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	fileSize := stat.Size()
	reader := &CallbackReader{
		C:         cb,
		TotalSize: fileSize,
		Reader:    file,
	}

	req, err := http.NewRequest("PUT", link.Href, nil)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	for h, v := range link.Header {
		req.Header.Set(h, v)
	}

	creds, err := getRequestCreds(req)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}

	bar := pb.StartNew(int(fileSize))
	bar.SetUnits(pb.U_BYTES)
	bar.Start()

	req.Body = ioutil.NopCloser(bar.NewProxyReader(reader))
	req.ContentLength = fileSize

	tracerx.Printf("external_put: %s %s", filepath.Base(filehash), req.URL)
	res, err := DoHTTP(Config, req)
	if err != nil {
		return Errorf(err, "Error attempting to PUT %s", filename)
	}
	tracerx.Printf("external_put_status: %d", res.StatusCode)
	saveCredentials(creds, res)

	// Run the verify callback
	if cb, ok := lm.Rel("verify"); ok {
		oid := filepath.Base(filehash)

		verifyReq, err := http.NewRequest("POST", cb.Href, nil)
		if err != nil {
			return Errorf(err, "Error attempting to verify %s", filename)
		}

		for h, v := range cb.Header {
			verifyReq.Header.Set(h, v)
		}

		verifyCreds, err := getRequestCreds(req)
		if err != nil {
			return Errorf(err, "Error attempting to verify %s", filename)
		}

		d := fmt.Sprintf(`{"oid":"%s", "size":%d}`, oid, fileSize)
		verifyReq.Body = ioutil.NopCloser(bytes.NewBufferString(d))

		tracerx.Printf("verify: %s %s", oid, cb.Href)
		verifyRes, err := DoHTTP(Config, verifyReq)
		if err != nil {
			return Errorf(err, "Error attempting to verify %s", filename)
		}
		tracerx.Printf("verify_status: %d", verifyRes.StatusCode)
		saveCredentials(verifyCreds, verifyRes)
	}

	return nil
}

func callPost(filehash, filename string) (*linkMeta, int, *WrappedError) {
	oid := filepath.Base(filehash)
	req, creds, err := request("POST", "")
	if err != nil {
		return nil, 0, Errorf(err, "Error attempting to POST %s", filename)
	}

	file, err := os.Open(filehash)
	if err != nil {
		return nil, 0, Errorf(err, "Error attempting to POST %s", filename)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return nil, 0, Errorf(err, "Error attempting to POST %s", filename)
	}
	fileSize := stat.Size()

	d := fmt.Sprintf(`{"oid":"%s", "size":%d}`, oid, fileSize)
	req.Body = ioutil.NopCloser(bytes.NewBufferString(d))

	req.Header.Set("Accept", gitMediaMetaType)

	tracerx.Printf("api_post: %s %s", oid, filename)
	res, wErr := doRequest(req, creds)
	if wErr != nil {
		return nil, 0, wErr
	}
	tracerx.Printf("api_post_status: %d", res.StatusCode)

	if res.StatusCode == 202 {
		lm := &linkMeta{}
		dec := json.NewDecoder(res.Body)
		err := dec.Decode(lm)
		if err != nil {
			return nil, res.StatusCode, Errorf(err, "Error decoding JSON from %s %s.", req.Method, req.URL)
		}

		return lm, res.StatusCode, nil
	}

	return nil, res.StatusCode, nil
}

func validateMediaHeader(contentType string, reader io.Reader) (bool, int, *WrappedError) {
	mediaType, params, err := mime.ParseMediaType(contentType)
	var headerSize int

	if err != nil {
		return false, headerSize, Errorf(err, "Invalid Media Type: %s", contentType)
	}

	if mediaType == gitMediaType {

		givenHeader, ok := params["header"]
		if !ok {
			return false, headerSize, Error(fmt.Errorf("Missing Git Media header in %s", contentType))
		}

		fullGivenHeader := "--" + givenHeader + "\n"
		headerSize = len(fullGivenHeader)

		header := make([]byte, headerSize)
		_, err = io.ReadAtLeast(reader, header, len(fullGivenHeader))
		if err != nil {
			return false, headerSize, Errorf(err, "Error reading response body.")
		}

		if string(header) != fullGivenHeader {
			return false, headerSize, Error(fmt.Errorf("Invalid header: %s expected, got %s", fullGivenHeader, header))
		}
	}
	return true, headerSize, nil
}

func doRequest(req *http.Request, creds Creds) (*http.Response, *WrappedError) {
	res, err := DoHTTP(Config, req)

	var wErr *WrappedError

	if err == RedirectError {
		err = nil
	}

	if err == nil {
		if creds != nil {
			saveCredentials(creds, res)
		}

		wErr = handleResponseError(res)
	} else if res.StatusCode != 302 { // hack for pre-release
		wErr = Errorf(err, "Error sending HTTP request to %s", req.URL.String())
	}

	if wErr != nil {
		if res != nil {
			setErrorResponseContext(wErr, res)
		} else {
			setErrorRequestContext(wErr, req)
		}
	}

	return res, wErr
}

func handleResponseError(res *http.Response) *WrappedError {
	if res.StatusCode < 400 || res.StatusCode == 405 {
		return nil
	}

	var wErr *WrappedError
	apiErr := &ClientError{}
	dec := json.NewDecoder(res.Body)
	if err := dec.Decode(apiErr); err != nil {
		wErr = Errorf(err, "Error decoding JSON from response")
	} else {
		var msg string
		switch res.StatusCode {
		case 401, 403:
			msg = fmt.Sprintf("Authorization error: %s\nCheck that you have proper access to the repository.", res.Request.URL)
		case 404:
			msg = fmt.Sprintf("Repository not found: %s\nCheck that it exists and that you have proper access to it.", res.Request.URL)
		default:
			msg = fmt.Sprintf("Invalid response: %d", res.StatusCode)
		}

		wErr = Errorf(apiErr, msg)
	}

	if res.StatusCode < 500 {
		wErr.Panic = false
	}

	return wErr
}

func saveCredentials(creds Creds, res *http.Response) {
	if creds == nil {
		return
	}

	if res.StatusCode < 300 {
		execCreds(creds, "approve")
		return
	}

	if res.StatusCode < 405 {
		execCreds(creds, "reject")
	}
}

var hiddenHeaders = map[string]bool{
	"Authorization": true,
}

func setErrorRequestContext(err *WrappedError, req *http.Request) {
	err.Set("Endpoint", Config.Endpoint())
	err.Set("URL", fmt.Sprintf("%s %s", req.Method, req.URL.String()))
	setErrorHeaderContext(err, "Response", req.Header)
}

func setErrorResponseContext(err *WrappedError, res *http.Response) {
	err.Set("Status", res.Status)
	setErrorHeaderContext(err, "Request", res.Header)
	setErrorRequestContext(err, res.Request)
}

func setErrorHeaderContext(err *WrappedError, prefix string, head http.Header) {
	for key, _ := range head {
		contextKey := fmt.Sprintf("%s:%s", prefix, key)
		if _, skip := hiddenHeaders[key]; skip {
			err.Set(contextKey, "--")
		} else {
			err.Set(contextKey, head.Get(key))
		}
	}
}

func request(method, oid string) (*http.Request, Creds, error) {
	u := Config.ObjectUrl(oid)
	req, err := http.NewRequest(method, u.String(), nil)
	req.Header.Set("User-Agent", UserAgent)
	if err == nil {
		creds, err := getRequestCreds(req)
		return req, creds, err
	}

	return req, nil, err
}

func getRequestCreds(req *http.Request) (Creds, error) {
	if _, ok := req.Header["Authorization"]; ok {
		return nil, nil
	}

	creds, err := credentials(req.URL)
	if err != nil {
		return nil, err
	}

	token := fmt.Sprintf("%s:%s", creds["username"], creds["password"])
	auth := "Basic " + base64.URLEncoding.EncodeToString([]byte(token))
	req.Header.Set("Authorization", auth)
	return creds, nil
}

type ClientError struct {
	Message   string `json:"message"`
	RequestId string `json:"request_id,omitempty"`
}

func (e *ClientError) Error() string {
	return e.Message
}
<|endoftext|>


<commit_before>package health

import (
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

// CheckFun is a wrapper around Check using callback functions.
func CheckFun(service string, onUp func(), onDown func(),
	pollDelay time.Duration, timeout time.Duration,
	quit <-chan struct{}) {
	updates := make(chan bool)
	Check(service, pollDelay, timeout, updates, quit)
	go func() {
		for {
			up, ok := <-updates
			if !ok {
				return
			}
			if up {
				onUp()
			} else {
				onDown()
			}
		}
	}()
}

// Check runs asynchronous health checking.  The updates channel
// receives updates on the health state of the backend.  Write to the
// quit channel to kill the health checker.
//
// Check assumes that the backend is unhealthy initially, and becomes
// unhealthy (if it was not already so) when it is killed.
func Check(
	healthService string,
	pollDelay time.Duration,
	timeout time.Duration,
	updates chan<- bool,
	quit <-chan struct{},
) {
	go check(healthService, pollDelay, timeout, updates, quit)
}

func check(
	healthService string,
	pollDelay time.Duration,
	timeout time.Duration,
	updates chan<- bool,
	quit <-chan struct{},
) {
	healthy := false
	defer func() {
		if healthy {
			updates <- false
		}
		close(updates)
	}()

	start := time.Now()
	ticker := time.NewTicker(pollDelay)
	defer ticker.Stop()

	for {
		select {
		case <-quit:
			return
		case t := <-ticker.C:
			if health(healthService) {
				start = t
				if !healthy {
					healthy = true
					updates <- true
				}
			}

			if healthy && t.After(start.Add(timeout)) {
				healthy = false
				updates <- false
			}
		}
	}
}

// health checks the given health service
func health(healthService string) bool {
	resp, _ := http.Get(healthService)
	bytes, _ := ioutil.ReadAll(resp.Body)

	resp.Body.Close()

	if resp == nil {
		return false
	}

	if strings.Contains(string(bytes), "healthy") {
		return true
	}

	return false
}
<commit_msg>Make health check fail on timeout or http error<commit_after>package health

import (
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

// CheckFun is a wrapper around Check using callback functions.
func CheckFun(service string, onUp func(), onDown func(),
	pollDelay time.Duration, timeout time.Duration,
	quit <-chan struct{}) {
	updates := make(chan bool)
	Check(service, pollDelay, timeout, updates, quit)
	go func() {
		for {
			up, ok := <-updates
			if !ok {
				return
			}
			if up {
				onUp()
			} else {
				onDown()
			}
		}
	}()
}

// Check runs asynchronous health checking.  The updates channel
// receives updates on the health state of the backend.  Write to the
// quit channel to kill the health checker.
//
// Check assumes that the backend is unhealthy initially, and becomes
// unhealthy (if it was not already so) when it is killed.
func Check(
	healthService string,
	pollDelay time.Duration,
	timeout time.Duration,
	updates chan<- bool,
	quit <-chan struct{},
) {
	go check(healthService, pollDelay, timeout, updates, quit)
}

func check(
	healthService string,
	pollDelay time.Duration,
	timeout time.Duration,
	updates chan<- bool,
	quit <-chan struct{},
) {
	healthy := false
	defer func() {
		if healthy {
			updates <- false
		}
		close(updates)
	}()

	start := time.Now()
	ticker := time.NewTicker(pollDelay)
	defer ticker.Stop()

	for {
		select {
		case <-quit:
			return
		case t := <-ticker.C:
			if health(healthService) {
				start = t
				if !healthy {
					healthy = true
					updates <- true
				}
			}

			if healthy && t.After(start.Add(timeout)) {
				healthy = false
				updates <- false
			}
		}
	}
}

// health checks the given health service
func health(healthService string) bool {
	const timeout = time.Duration(3 * time.Second)

	client := http.Client{
		Timeout: timeout,
	}

	resp, err := client.Get(healthService)
	// Check if timeout or HTTP error
	if resp == nil && err != nil {
		return false
	}

	bytes, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if strings.Contains(string(bytes), "healthy") {
		return true
	}

	return false
}
<|endoftext|>


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

package builder

import (
	"fmt"
	"reflect"
	"testing"
)

func TestBuilderCond(t *testing.T) {
	var cases = []struct {
		cond Cond
		sql  string
		args []interface{}
	}{
		{
			Eq{"a": 1}.And(Like{"b", "c"}).Or(Eq{"a": 2}.And(Like{"b", "g"})),
			"(a=? AND b LIKE ?) OR (a=? AND b LIKE ?)",
			[]interface{}{1, "%c%", 2, "%g%"},
		},
		{
			Eq{"a": 1}.Or(Like{"b", "c"}).And(Eq{"a": 2}.Or(Like{"b", "g"})),
			"(a=? OR b LIKE ?) AND (a=? OR b LIKE ?)",
			[]interface{}{1, "%c%", 2, "%g%"},
		},
		{
			Eq{"d": []string{"e", "f"}},
			"d IN (?,?)",
			[]interface{}{"e", "f"},
		},
		{
			Neq{"d": []string{"e", "f"}},
			"d NOT IN (?,?)",
			[]interface{}{"e", "f"},
		},
		{
			Lt{"d": 3},
			"d<?",
			[]interface{}{3},
		},
		{
			Lte{"d": 3},
			"d<=?",
			[]interface{}{3},
		},
		{
			Gt{"d": 3},
			"d>?",
			[]interface{}{3},
		},
		{
			Gte{"d": 3},
			"d>=?",
			[]interface{}{3},
		},
		{
			Between{"d", 0, 2},
			"d BETWEEN ? AND ?",
			[]interface{}{0, 2},
		},
		{
			IsNull{"d"},
			"d IS NULL",
			[]interface{}{},
		},
		{
			NotIn("a", 1, 2).And(NotIn("b", "c", "d")),
			"a NOT IN (?,?) AND b NOT IN (?,?)",
			[]interface{}{1, 2, "c", "d"},
		},
		{
			In("a", 1, 2).Or(In("b", "c", "d")),
			"a IN (?,?) OR b IN (?,?)",
			[]interface{}{1, 2, "c", "d"},
		},
		{
			In("a", []int{1, 2}).Or(In("b", []string{"c", "d"})),
			"a IN (?,?) OR b IN (?,?)",
			[]interface{}{1, 2, "c", "d"},
		},
		{
			In("a", Expr("select id from x where name > ?", "b")),
			"a IN (select id from x where name > ?)",
			[]interface{}{"b"},
		},
		{
			NotIn("a", Expr("select id from x where name > ?", "b")),
			"a NOT IN (select id from x where name > ?)",
			[]interface{}{"b"},
		},
		{
			Or(Eq{"a": 1, "b": 2}, Eq{"c": 3, "d": 4}),
			"(a=? AND b=?) OR (c=? AND d=?)",
			[]interface{}{1, 2, 3, 4},
		},
	}

	for _, k := range cases {
		sql, args, err := ToSQL(k.cond)
		if err != nil {
			t.Error(err)
			return
		}
		if sql != k.sql {
			t.Error("want", k.sql, "get", sql)
			return
		}
		fmt.Println(sql)

		if !(len(args) == 0 && len(k.args) == 0) {
			if !reflect.DeepEqual(args, k.args) {
				t.Error("want", k.args, "get", args)
				return
			}
		}
		fmt.Println(args)
	}
}

func TestBuilderSelect(t *testing.T) {
	sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}

func TestBuilderInsert(t *testing.T) {
	sql, args, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}

func TestBuilderUpdate(t *testing.T) {
	sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)

	sql, args, err = Update(Eq{"a": 2, "b": Incr(1)}).From("table2").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)

	sql, args, err = Update(Eq{"a": 2, "b": Incr(1), "c": Decr(1), "d": Expr("select count(*) from table2")}).From("table2").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}

func TestBuilderDelete(t *testing.T) {
	sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}
<commit_msg>ignore random failed tests<commit_after>// Copyright 2016 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package builder

import (
	"fmt"
	"reflect"
	"testing"
)

func TestBuilderCond(t *testing.T) {
	var cases = []struct {
		cond Cond
		sql  string
		args []interface{}
	}{
		{
			Eq{"a": 1}.And(Like{"b", "c"}).Or(Eq{"a": 2}.And(Like{"b", "g"})),
			"(a=? AND b LIKE ?) OR (a=? AND b LIKE ?)",
			[]interface{}{1, "%c%", 2, "%g%"},
		},
		{
			Eq{"a": 1}.Or(Like{"b", "c"}).And(Eq{"a": 2}.Or(Like{"b", "g"})),
			"(a=? OR b LIKE ?) AND (a=? OR b LIKE ?)",
			[]interface{}{1, "%c%", 2, "%g%"},
		},
		{
			Eq{"d": []string{"e", "f"}},
			"d IN (?,?)",
			[]interface{}{"e", "f"},
		},
		{
			Neq{"d": []string{"e", "f"}},
			"d NOT IN (?,?)",
			[]interface{}{"e", "f"},
		},
		{
			Lt{"d": 3},
			"d<?",
			[]interface{}{3},
		},
		{
			Lte{"d": 3},
			"d<=?",
			[]interface{}{3},
		},
		{
			Gt{"d": 3},
			"d>?",
			[]interface{}{3},
		},
		{
			Gte{"d": 3},
			"d>=?",
			[]interface{}{3},
		},
		{
			Between{"d", 0, 2},
			"d BETWEEN ? AND ?",
			[]interface{}{0, 2},
		},
		{
			IsNull{"d"},
			"d IS NULL",
			[]interface{}{},
		},
		{
			NotIn("a", 1, 2).And(NotIn("b", "c", "d")),
			"a NOT IN (?,?) AND b NOT IN (?,?)",
			[]interface{}{1, 2, "c", "d"},
		},
		{
			In("a", 1, 2).Or(In("b", "c", "d")),
			"a IN (?,?) OR b IN (?,?)",
			[]interface{}{1, 2, "c", "d"},
		},
		{
			In("a", []int{1, 2}).Or(In("b", []string{"c", "d"})),
			"a IN (?,?) OR b IN (?,?)",
			[]interface{}{1, 2, "c", "d"},
		},
		{
			In("a", Expr("select id from x where name > ?", "b")),
			"a IN (select id from x where name > ?)",
			[]interface{}{"b"},
		},
		{
			NotIn("a", Expr("select id from x where name > ?", "b")),
			"a NOT IN (select id from x where name > ?)",
			[]interface{}{"b"},
		},
		// FIXME: since map will not gurantee the sequence, this may be failed random
		/*{
			Or(Eq{"a": 1, "b": 2}, Eq{"c": 3, "d": 4}),
			"(a=? AND b=?) OR (c=? AND d=?)",
			[]interface{}{1, 2, 3, 4},
		},*/
	}

	for _, k := range cases {
		sql, args, err := ToSQL(k.cond)
		if err != nil {
			t.Error(err)
			return
		}
		if sql != k.sql {
			t.Error("want", k.sql, "get", sql)
			return
		}
		fmt.Println(sql)

		if !(len(args) == 0 && len(k.args) == 0) {
			if !reflect.DeepEqual(args, k.args) {
				t.Error("want", k.args, "get", args)
				return
			}
		}
		fmt.Println(args)
	}
}

func TestBuilderSelect(t *testing.T) {
	sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}

func TestBuilderInsert(t *testing.T) {
	sql, args, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}

func TestBuilderUpdate(t *testing.T) {
	sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)

	sql, args, err = Update(Eq{"a": 2, "b": Incr(1)}).From("table2").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)

	sql, args, err = Update(Eq{"a": 2, "b": Incr(1), "c": Decr(1), "d": Expr("select count(*) from table2")}).From("table2").Where(Eq{"a": 1}).ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}

func TestBuilderDelete(t *testing.T) {
	sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
	if err != nil {
		t.Error(err)
		return
	}
	fmt.Println(sql, args)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/chrishenry/geonosis/geonosis/client"
	"github.com/chrishenry/geonosis/geonosis/image"
	dc "github.com/fsouza/go-dockerclient"
	"github.com/labstack/echo"
	mw "github.com/labstack/echo/middleware"
	"html/template"
	"io"
	"log"
	"net/http"
)

type (
	// Template provides HTML template rendering
	Template struct {
		templates *template.Template
	}

	// user struct {
	// 	ID   string `json:"id"`
	// 	Name string `json:"name"`
	// }
)

// Template provides HTML template rendering
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

// Handlers
func createDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment POST\n")
}

func getDeployment(c *echo.Context) error {
	docker := client.NewDockerClient()
	containers, err := docker.Client.ListContainers(dc.ListContainersOptions{All: false})
	if err != nil {
		log.Fatal(err)
	}

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

func updateDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment PATCH\n")
}

func deleteDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment DELETE\n")
}

func getImage(c *echo.Context) error {

	r := c.Request()

	var source string = ""
	var returnimages []image.MyAPIImages

	if len(r.URL.Query()["source"]) == 0 {
		source = "local"
	} else {
		source = r.URL.Query()["source"][0]
	}

	fmt.Println("source: ", source)

	if source == "local" {
		returnimages = image.GetLocalImage(client.NewDockerClient())
	}

	return c.JSON(http.StatusOK, returnimages)

}

func main() {

	// Echo instance
	e := echo.New()

	// Debug mode
	e.SetDebug(true)

	// Middleware
	e.Use(mw.Logger())
	e.Use(mw.Recover())

	// Routes
	e.Index("public/index.html")

	// Image Routes
	e.Get("/v1/images", getImage)

	// Deployment Routes
	e.Post("/v1/deployments", createDeployment)
	e.Get("/v1/deployments", getDeployment)
	e.Get("/v1/deployments/:id", getDeployment)
	e.Patch("/v1/deployments/:id", updateDeployment)
	e.Delete("/v1/deployments/:id", deleteDeployment)

	// Start server
	e.Run(":1323")
}
<commit_msg>Launch containers.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/chrishenry/geonosis/geonosis/client"
	"github.com/chrishenry/geonosis/geonosis/image"
	dc "github.com/fsouza/go-dockerclient"
	"github.com/labstack/echo"
	mw "github.com/labstack/echo/middleware"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

type (
	// Template provides HTML template rendering
	Template struct {
		templates *template.Template
	}

	// user struct {
	// 	ID   string `json:"id"`
	// 	Name string `json:"name"`
	// }
)

// Template provides HTML template rendering
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

type test_struct struct {
	Image string
	Name  string
	Cmd   []string
	Env   []string
}

// Handlers
func createDeployment(c *echo.Context) error {

	r := c.Request()
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(body))
	var t test_struct
	err = json.Unmarshal(body, &t)
	if err != nil {
		panic(err)
	}
	fmt.Println(t.Image)

	docker := client.NewDockerClient()

	cmd := t.Cmd
	if len(t.Cmd) == 0 {
		cmd = nil
	}

	env := t.Env
	if len(t.Env) == 0 {
		env = nil
	}

	createContConf := dc.Config{
		Image: t.Image,
		Cmd:   cmd,
		Env:   env,
	}

	createContHostConfig := dc.HostConfig{}

	createContOps := dc.CreateContainerOptions{
		Name:       t.Name,
		Config:     &createContConf,
		HostConfig: &createContHostConfig,
	}

	container, err := docker.Client.CreateContainer(createContOps)
	if err != nil {
		panic(err)
	}

	fmt.Printf("\ncontainer = %s\n", container)

	err = docker.Client.StartContainer(container.ID, nil)
	if err != nil {
		panic(err)
	}

	return c.String(http.StatusOK, "Deployment POST\n")
}

func getDeployment(c *echo.Context) error {
	docker := client.NewDockerClient()
	containers, err := docker.Client.ListContainers(dc.ListContainersOptions{All: false})
	if err != nil {
		log.Fatal(err)
	}

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

func updateDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment PATCH\n")
}

func deleteDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment DELETE\n")
}

func getImage(c *echo.Context) error {

	r := c.Request()

	var source string = ""
	var returnimages []image.MyAPIImages

	if len(r.URL.Query()["source"]) == 0 {
		source = "local"
	} else {
		source = r.URL.Query()["source"][0]
	}

	fmt.Println("source: ", source)

	if source == "local" {
		returnimages = image.GetLocalImage(client.NewDockerClient())
	}

	return c.JSON(http.StatusOK, returnimages)

}

func main() {

	// Echo instance
	e := echo.New()

	// Debug mode
	e.SetDebug(true)

	// Middleware
	e.Use(mw.Logger())
	e.Use(mw.Recover())

	// Routes
	e.Index("public/index.html")

	// Image Routes
	e.Get("/v1/images", getImage)

	// Deployment Routes
	e.Post("/v1/deployments", createDeployment)
	e.Get("/v1/deployments", getDeployment)
	e.Get("/v1/deployments/:id", getDeployment)
	e.Patch("/v1/deployments/:id", updateDeployment)
	e.Delete("/v1/deployments/:id", deleteDeployment)

	// Start server
	e.Run(":1323")
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/serbe/ncp"
)

var (
	urls = []string{
		"/forum/viewforum.php?f=218", // Зарубежные Новинки (HD*Rip/LQ, DVDRip)
		// "/forum/viewforum.php?f=221", // Отечественные Фильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		// "/forum/viewforum.php?f=225", // Зарубежные Фильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		// "/forum/viewforum.php?f=230", // Отечественные Мультфильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		// "/forum/viewforum.php?f=231", // Зарубежные Мультфильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		// "/forum/viewforum.php?f=270", // Отечественные Новинки (HD*Rip/LQ, DVDRip)
		// "/forum/viewforum.php?f=319", // Зарубежная Классика (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		// "/forum/viewforum.php?f=320", // Отечественная Классика (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
	}
)

func (a *App) get() error {
	var (
		err error
		i   int
	)
	for _, parseurl := range urls {
		topics, err := a.net.ParseForumTree(parseurl)
		if err != nil {
			log.Println("ParseForumTree ", parseurl, err)
			return err
		}
		for _, topic := range topics {
			_, err := a.getTorrentByHref(topic.Href)
			if err != nil {
				film, err := a.net.ParseTopic(topic)
				if err == nil {
					i++
					film = a.checkName(film)
					_, err = a.createTorrent(film)
					if err != nil {
						log.Println("createTorrent ", err)
					}
				} else {
					log.Println("ParseTopic ", err)
				}
			}
		}
	}
	if i > 0 {
		log.Println("Adding", i, "new films")
	} else {
		log.Println("No adding new films")
	}
	return err
}

func (a *App) update() error {
	var (
		i        int
		err      error
		torrents []Torrent
	)

	torrents, err = a.getWithDownload()
	if err != nil {
		return err
	}
	for _, tor := range torrents {
		var topic ncp.Topic
		topic.Href = tor.Href
		f, err := a.net.ParseTopic(topic)
		if err == nil {
			if f.NNM != tor.NNM || f.Seeders != tor.Seeders || f.Leechers != tor.Leechers || f.Torrent != tor.Torrent {
				i++
				a.updateTorrent(tor.ID, f)
			}
		} else {
			return err
		}
	}
	if i > 0 {
		log.Println("Update", i, "movies")
	} else {
		log.Println("No movies update")
	}
	return nil
}

func (a *App) name() error {
	var i int
	movies, err := a.getMovies()
	if err != nil {
		return err
	}
	for _, movie := range movies {
		if movie.Name == strings.ToUpper(movie.Name) {
			lowerName, err := a.getUpperName(movie)
			if err == nil {
				i++
				a.updateName(movie.ID, lowerName)
			}
		}
	}
	if i > 0 {
		log.Println(i, "name fixed")
	} else {
		log.Println("No fixed names")
	}
	return nil
}

func (a *App) rating() error {
	var (
		i int
	)
	movies, err := a.getNoRating()
	if err != nil {
		return err
	}
	for _, movie := range movies {
		if movie.Kinopoisk == 0 || movie.IMDb == 0 || movie.Duration == "" {
			kp, err := a.getRating(movie)
			if err == nil {
				i++
				_ = a.updateRating(movie, kp)
			}
		}
	}
	if i > 0 {
		log.Println(i, "ratings update")
	} else {
		log.Println("No update ratings")
	}
	return nil
}

func (a *App) poster() error {
	var (
		i     int
		files []string
	)
	movies, err := a.getMovies()
	if err != nil {
		return err
	}
	filesInDir, _ := ioutil.ReadDir(a.hd)
	for _, file := range filesInDir {
		files = append(files, file.Name())
	}
	for _, movie := range movies {
		if movie.PosterURL != "" {
			if movie.Poster != "" {
				if !existsFile(a.hd + movie.Poster) {
					poster, err := a.getPoster(movie.PosterURL)
					if err == nil {
						i++
						err = a.updatePoster(movie, poster)
						if err != nil {
							log.Println("updatePoster ", poster, err)
						}
					} else {
						log.Println("getPoster ", poster, err)
					}
				} else {
					files = deleteFromSlice(files, movie.Poster)
				}
			} else {
				poster, err := a.getPoster(movie.PosterURL)
				if err == nil {
					i++
					_ = a.updatePoster(movie, poster)
				}
			}
		} else {
			tor, err := a.getTorrentByMovieID(movie.ID)
			if err == nil {
				var topic ncp.Topic
				topic.Href = tor.Href
				tempFilm, err := a.net.ParseTopic(topic)
				if err == nil {
					if tempFilm.Poster != "" {
						err = a.updatePosterURL(movie, tempFilm.Poster)
						if err == nil {
							poster, err := a.getPoster(tempFilm.Poster)
							if err == nil {
								i++
								_ = a.updatePoster(movie, poster)
							}
						}
					}
				}
			}
		}
	}
	for _, file := range files {
		_ = os.Remove(a.hd + file)
	}
	if i > 0 {
		log.Println(i, "posters update")
	} else {
		log.Println("No update posters")
	}
	if len(files) > 0 {
		log.Println("Remove", len(files), "unused images")
	}
	return nil
}
<commit_msg>enable more subforums<commit_after>package main

import (
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/serbe/ncp"
)

var (
	urls = []string{
		"/forum/viewforum.php?f=218", // Зарубежные Новинки (HD*Rip/LQ, DVDRip)
		"/forum/viewforum.php?f=221", // Отечественные Фильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		"/forum/viewforum.php?f=225", // Зарубежные Фильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		"/forum/viewforum.php?f=230", // Отечественные Мультфильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		"/forum/viewforum.php?f=231", // Зарубежные Мультфильмы (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		"/forum/viewforum.php?f=270", // Отечественные Новинки (HD*Rip/LQ, DVDRip)
		"/forum/viewforum.php?f=319", // Зарубежная Классика (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
		"/forum/viewforum.php?f=320", // Отечественная Классика (HD*Rip/LQ, DVDRip, SATRip, VHSRip)
	}
)

func (a *App) get() error {
	var (
		err error
		i   int
	)
	for _, parseurl := range urls {
		topics, err := a.net.ParseForumTree(parseurl)
		if err != nil {
			log.Println("ParseForumTree ", parseurl, err)
			return err
		}
		for _, topic := range topics {
			_, err := a.getTorrentByHref(topic.Href)
			if err != nil {
				film, err := a.net.ParseTopic(topic)
				if err == nil {
					i++
					film = a.checkName(film)
					_, err = a.createTorrent(film)
					if err != nil {
						log.Println("createTorrent ", err)
					}
				} else {
					log.Println("ParseTopic ", err)
				}
			}
		}
	}
	if i > 0 {
		log.Println("Adding", i, "new films")
	} else {
		log.Println("No adding new films")
	}
	return err
}

func (a *App) update() error {
	var (
		i        int
		err      error
		torrents []Torrent
	)

	torrents, err = a.getWithDownload()
	if err != nil {
		return err
	}
	for _, tor := range torrents {
		var topic ncp.Topic
		topic.Href = tor.Href
		f, err := a.net.ParseTopic(topic)
		if err == nil {
			if f.NNM != tor.NNM || f.Seeders != tor.Seeders || f.Leechers != tor.Leechers || f.Torrent != tor.Torrent {
				i++
				a.updateTorrent(tor.ID, f)
			}
		} else {
			return err
		}
	}
	if i > 0 {
		log.Println("Update", i, "movies")
	} else {
		log.Println("No movies update")
	}
	return nil
}

func (a *App) name() error {
	var i int
	movies, err := a.getMovies()
	if err != nil {
		return err
	}
	for _, movie := range movies {
		if movie.Name == strings.ToUpper(movie.Name) {
			lowerName, err := a.getUpperName(movie)
			if err == nil {
				i++
				a.updateName(movie.ID, lowerName)
			}
		}
	}
	if i > 0 {
		log.Println(i, "name fixed")
	} else {
		log.Println("No fixed names")
	}
	return nil
}

func (a *App) rating() error {
	var (
		i int
	)
	movies, err := a.getNoRating()
	if err != nil {
		return err
	}
	for _, movie := range movies {
		if movie.Kinopoisk == 0 || movie.IMDb == 0 || movie.Duration == "" {
			kp, err := a.getRating(movie)
			if err == nil {
				i++
				_ = a.updateRating(movie, kp)
			}
		}
	}
	if i > 0 {
		log.Println(i, "ratings update")
	} else {
		log.Println("No update ratings")
	}
	return nil
}

func (a *App) poster() error {
	var (
		i     int
		files []string
	)
	movies, err := a.getMovies()
	if err != nil {
		return err
	}
	filesInDir, _ := ioutil.ReadDir(a.hd)
	for _, file := range filesInDir {
		files = append(files, file.Name())
	}
	for _, movie := range movies {
		if movie.PosterURL != "" {
			if movie.Poster != "" {
				if !existsFile(a.hd + movie.Poster) {
					poster, err := a.getPoster(movie.PosterURL)
					if err == nil {
						i++
						err = a.updatePoster(movie, poster)
						if err != nil {
							log.Println("updatePoster ", poster, err)
						}
					} else {
						log.Println("getPoster ", poster, err)
					}
				} else {
					files = deleteFromSlice(files, movie.Poster)
				}
			} else {
				poster, err := a.getPoster(movie.PosterURL)
				if err == nil {
					i++
					_ = a.updatePoster(movie, poster)
				}
			}
		} else {
			tor, err := a.getTorrentByMovieID(movie.ID)
			if err == nil {
				var topic ncp.Topic
				topic.Href = tor.Href
				tempFilm, err := a.net.ParseTopic(topic)
				if err == nil {
					if tempFilm.Poster != "" {
						err = a.updatePosterURL(movie, tempFilm.Poster)
						if err == nil {
							poster, err := a.getPoster(tempFilm.Poster)
							if err == nil {
								i++
								_ = a.updatePoster(movie, poster)
							}
						}
					}
				}
			}
		}
	}
	for _, file := range files {
		_ = os.Remove(a.hd + file)
	}
	if i > 0 {
		log.Println(i, "posters update")
	} else {
		log.Println("No update posters")
	}
	if len(files) > 0 {
		log.Println("Remove", len(files), "unused images")
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"cloud.google.com/go/datastore"
	"errors"
	"fmt"
	"strconv"
	"strings"
)

type commandStart botCommand

func (commandRequest *commandStart) Handle() error {
	message := "Привет! Я бот-хуебот.\n" +
		"Я буду хуифицировать некоторые из ваших фраз.\n" +
		"Сейчас режим вежливости %s\n" +
		"За подробностями в /help."
	switchDatastoreBool(commandRequest.request, "Stopped", false)
	if gentleMap[commandRequest.request.updateMessage.Chat.ID] {
		message = fmt.Sprintf(message, "включен")
	} else {
		message = fmt.Sprintf(message, "отключен")
	}
	commandRequest.request.answer(message)
	return nil
}

type commandStop botCommand

func (commandRequest *commandStop) Handle() error {
	switchDatastoreBool(commandRequest.request, "Stopped", true)
	commandRequest.request.answer("Выключаюсь")
	return nil
}

type commandHelp botCommand

func (commandRequest *commandHelp) Handle() error {
	commandRequest.request.answer(
		"Вежливый режим:\n" +
			"  Для включения используйте команду /gentle\n" +
			"  Для отключения - /hardcore\n" +
			"Частота ответов: /delay N, где N - любое любое натуральное число\n" +
			"Число хуифицируемых слов: /amount N, где N - от 1 до 10\n" +
			"Для остановки используйте /stop")
	return nil
}

type commandDelay botCommand

func (commandRequest *commandDelay) Handle() error {
	command := strings.Fields(commandRequest.request.updateMessage.Text)
	if len(command) < 2 {
		currentDelayMessage := "Сейчас я пропускаю случайное число сообщений от 0 до "
		if currentDelay, ok := customDelayMap[commandRequest.request.updateMessage.Chat.ID]; ok {
			currentDelayMessage += strconv.Itoa(currentDelay)
		} else {
			currentDelayMessage += "4"
		}
		commandRequest.request.answer(currentDelayMessage)
		return nil
	}
	commandArg := command[len(command)-1]
	tryDelay, err := strconv.Atoi(commandArg)
	if err != nil || tryDelay < 1 || tryDelay > 1000000 {
		commandRequest.request.answer("Неправильный аргумент, отправьте `/delay N`, где N любое натуральное число меньше 1000000")
		return nil
	}
	commandRequest.request.customDelay.Delay = tryDelay
	if _, err := datastoreClient.Put(commandRequest.request.ctx, commandRequest.request.customDelayKey, &commandRequest.request.customDelay); err != nil {
		commandRequest.request.answerErrorWithLog("Не удалось сохранить, отправьте еще раз `/delay N`, где N любое натуральное число меньше 1000000", err)
		return nil
	}
	customDelayMap[commandRequest.request.updateMessage.Chat.ID] = commandRequest.request.customDelay.Delay
	commandRequest.request.answer("Я буду пропускать случайное число сообщений от 0 до " + commandArg)
	delete(delayMap, commandRequest.request.updateMessage.Chat.ID)
	return nil
}

func switchDatastoreBool(request *requestInfo, dsName string, value bool) {
	var localCache map[int64]bool
	var resultStruct *DatastoreBool
	var dsKey *datastore.Key
	switch dsName {
	case "Gentle":
		localCache = gentleMap
		resultStruct = &request.gentleStruct
		dsKey = request.gentleKey
	case "Stopped":
		localCache = stoppedMap
		resultStruct = &request.stoppedStruct
		dsKey = request.stoppedKey
	default:
		return
	}

	localCache[request.updateMessage.Chat.ID] = value
	resultStruct.Value = value
	if _, err := datastoreClient.Put(request.ctx, dsKey, resultStruct); err != nil {
		request.logWarn(err)
	}
}

type commandHardcore botCommand

func (commandRequest *commandHardcore) Handle() error {
	switchDatastoreBool(commandRequest.request, "Gentle", false)
	commandRequest.request.answer("Вежливый режим отключен.\nЧтобы включить его, используйте команду /gentle")
	return nil
}

type commandGentle botCommand

func (commandRequest *commandGentle) Handle() error {
	switchDatastoreBool(commandRequest.request, "Gentle", true)
	commandRequest.request.answer("Вежливый режим включен.\nЧтобы отключить его, используйте команду /hardcore")
	return nil
}

type commandAmount botCommand

func (commandRequest *commandAmount) Handle() error {
	command := strings.Fields(commandRequest.request.updateMessage.Text)
	if len(command) < 2 {
		currentWordsAmount := 1
		if currentAmount, ok := wordsAmountMap[commandRequest.request.updateMessage.Chat.ID]; ok {
			currentWordsAmount = currentAmount
		}
		commandRequest.request.answer("Сейчас я хуифицирую случайное число слов от 1 до " + strconv.Itoa(currentWordsAmount))
		return nil
	}
	commandArg := command[len(command)-1]
	tryWordsAmount, err := strconv.Atoi(commandArg)
	if err != nil || tryWordsAmount < 1 || tryWordsAmount > 10 {
		commandRequest.request.answer("Неправильный аргумент, отправьте `/amount N`, где N любое натуральное число не больше 10")
		return nil
	}
	commandRequest.request.wordsAmountStruct.Value = tryWordsAmount
	if _, err := datastoreClient.Put(commandRequest.request.ctx, commandRequest.request.wordsAmountKey, &commandRequest.request.wordsAmountStruct); err != nil {
		commandRequest.request.answerErrorWithLog("Не удалось сохранить, отправьте еще раз `/amount N`, где N любое натуральное число не больше 10", err)
		return nil
	}
	wordsAmountMap[commandRequest.request.updateMessage.Chat.ID] = commandRequest.request.wordsAmountStruct.Value
	commandRequest.request.answer("Я буду хуифицировать случайное число слов от 1 до " + strconv.Itoa(commandRequest.request.wordsAmountStruct.Value))
	return nil
}

type commandNotFound botCommand

func (commandRequest *commandNotFound) Handle() error {
	return errors.New("Команда не найдена")
}
<commit_msg>Add GitHub link<commit_after>package main

import (
	"cloud.google.com/go/datastore"
	"errors"
	"fmt"
	"strconv"
	"strings"
)

type commandStart botCommand

func (commandRequest *commandStart) Handle() error {
	message := "Привет! Я бот-хуебот.\n" +
		"Я буду хуифицировать некоторые из ваших фраз.\n" +
		"Сейчас режим вежливости %s\n" +
		"За подробностями в /help."
	switchDatastoreBool(commandRequest.request, "Stopped", false)
	if gentleMap[commandRequest.request.updateMessage.Chat.ID] {
		message = fmt.Sprintf(message, "включен")
	} else {
		message = fmt.Sprintf(message, "отключен")
	}
	commandRequest.request.answer(message)
	return nil
}

type commandStop botCommand

func (commandRequest *commandStop) Handle() error {
	switchDatastoreBool(commandRequest.request, "Stopped", true)
	commandRequest.request.answer("Выключаюсь")
	return nil
}

type commandHelp botCommand

func (commandRequest *commandHelp) Handle() error {
	commandRequest.request.answer(
		"Вежливый режим:\n" +
			"  Для включения используйте команду /gentle\n" +
			"  Для отключения - /hardcore\n" +
			"Частота ответов: /delay N, где N - любое любое натуральное число\n" +
			"Число хуифицируемых слов: /amount N, где N - от 1 до 10\n" +
			"Для остановки используйте /stop\n\n" +
			"По вопросам: https://github.com/m-messiah/xye-bot/issues")
	return nil
}

type commandDelay botCommand

func (commandRequest *commandDelay) Handle() error {
	command := strings.Fields(commandRequest.request.updateMessage.Text)
	if len(command) < 2 {
		currentDelayMessage := "Сейчас я пропускаю случайное число сообщений от 0 до "
		if currentDelay, ok := customDelayMap[commandRequest.request.updateMessage.Chat.ID]; ok {
			currentDelayMessage += strconv.Itoa(currentDelay)
		} else {
			currentDelayMessage += "4"
		}
		commandRequest.request.answer(currentDelayMessage)
		return nil
	}
	commandArg := command[len(command)-1]
	tryDelay, err := strconv.Atoi(commandArg)
	if err != nil || tryDelay < 1 || tryDelay > 1000000 {
		commandRequest.request.answer("Неправильный аргумент, отправьте `/delay N`, где N любое натуральное число меньше 1000000")
		return nil
	}
	commandRequest.request.customDelay.Delay = tryDelay
	if _, err := datastoreClient.Put(commandRequest.request.ctx, commandRequest.request.customDelayKey, &commandRequest.request.customDelay); err != nil {
		commandRequest.request.answerErrorWithLog("Не удалось сохранить, отправьте еще раз `/delay N`, где N любое натуральное число меньше 1000000", err)
		return nil
	}
	customDelayMap[commandRequest.request.updateMessage.Chat.ID] = commandRequest.request.customDelay.Delay
	commandRequest.request.answer("Я буду пропускать случайное число сообщений от 0 до " + commandArg)
	delete(delayMap, commandRequest.request.updateMessage.Chat.ID)
	return nil
}

func switchDatastoreBool(request *requestInfo, dsName string, value bool) {
	var localCache map[int64]bool
	var resultStruct *DatastoreBool
	var dsKey *datastore.Key
	switch dsName {
	case "Gentle":
		localCache = gentleMap
		resultStruct = &request.gentleStruct
		dsKey = request.gentleKey
	case "Stopped":
		localCache = stoppedMap
		resultStruct = &request.stoppedStruct
		dsKey = request.stoppedKey
	default:
		return
	}

	localCache[request.updateMessage.Chat.ID] = value
	resultStruct.Value = value
	if _, err := datastoreClient.Put(request.ctx, dsKey, resultStruct); err != nil {
		request.logWarn(err)
	}
}

type commandHardcore botCommand

func (commandRequest *commandHardcore) Handle() error {
	switchDatastoreBool(commandRequest.request, "Gentle", false)
	commandRequest.request.answer("Вежливый режим отключен.\nЧтобы включить его, используйте команду /gentle")
	return nil
}

type commandGentle botCommand

func (commandRequest *commandGentle) Handle() error {
	switchDatastoreBool(commandRequest.request, "Gentle", true)
	commandRequest.request.answer("Вежливый режим включен.\nЧтобы отключить его, используйте команду /hardcore")
	return nil
}

type commandAmount botCommand

func (commandRequest *commandAmount) Handle() error {
	command := strings.Fields(commandRequest.request.updateMessage.Text)
	if len(command) < 2 {
		currentWordsAmount := 1
		if currentAmount, ok := wordsAmountMap[commandRequest.request.updateMessage.Chat.ID]; ok {
			currentWordsAmount = currentAmount
		}
		commandRequest.request.answer("Сейчас я хуифицирую случайное число слов от 1 до " + strconv.Itoa(currentWordsAmount))
		return nil
	}
	commandArg := command[len(command)-1]
	tryWordsAmount, err := strconv.Atoi(commandArg)
	if err != nil || tryWordsAmount < 1 || tryWordsAmount > 10 {
		commandRequest.request.answer("Неправильный аргумент, отправьте `/amount N`, где N любое натуральное число не больше 10")
		return nil
	}
	commandRequest.request.wordsAmountStruct.Value = tryWordsAmount
	if _, err := datastoreClient.Put(commandRequest.request.ctx, commandRequest.request.wordsAmountKey, &commandRequest.request.wordsAmountStruct); err != nil {
		commandRequest.request.answerErrorWithLog("Не удалось сохранить, отправьте еще раз `/amount N`, где N любое натуральное число не больше 10", err)
		return nil
	}
	wordsAmountMap[commandRequest.request.updateMessage.Chat.ID] = commandRequest.request.wordsAmountStruct.Value
	commandRequest.request.answer("Я буду хуифицировать случайное число слов от 1 до " + strconv.Itoa(commandRequest.request.wordsAmountStruct.Value))
	return nil
}

type commandNotFound botCommand

func (commandRequest *commandNotFound) Handle() error {
	return errors.New("Команда не найдена")
}
<|endoftext|>


<commit_before>package sirius

type Extension interface {
	Run(Message) (error, MessageAction)
}

type CfgExtension interface {
	Run(Message, ExtensionConfig) (error, MessageAction)
}

type cfg_int int
type cfg_bool bool
type cfg_float float64
type cfg_list []string

type EID string

type ExtensionLoader interface {
	Load(EID) Extension
}

type ExtensionConfig map[string]interface{}

type InvalidConfig struct {
	Key string
	msg string
}

func (ic InvalidConfig) Error() string {
	return ic.msg
}

func (cfg ExtensionConfig) read(key string, def interface{}) interface{} {
	if val, ok := cfg[key]; ok {
		return val
	}

	return def
}

func (cfg ExtensionConfig) integer(key string, def int) cfg_int {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case int:
			return cfg_int(b)
		}
	}

	return cfg_int(def)
}

func (cfg ExtensionConfig) boolean(key string, def bool) cfg_bool {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case bool:
			return cfg_bool(b)
		case int:
			// Require explicit 0 or 1
			if b == 0 {
				return cfg_bool(false)
			} else if b == 1 {
				return cfg_bool(true)
			}
		}
	}

	return cfg_bool(def)
}

func (cfg ExtensionConfig) float(key string, def float64) cfg_float {
	if val, ok := cfg[key]; ok {
		switch f := val.(type) {
		case float32:
			return cfg_float(f)
		case float64:
			return cfg_float(f)
		}
	}

	return cfg_float(def)
}

func (cfg ExtensionConfig) list(key string, def []string) cfg_list {
	if val, ok := cfg[key]; ok {
		switch l := val.(type) {
		case []string:
			return cfg_list(l)
		}

	}

	return def
}
<commit_msg>Remove unnecessary type aliases<commit_after>package sirius

type Extension interface {
	Run(Message) (error, MessageAction)
}

type CfgExtension interface {
	Run(Message, ExtensionConfig) (error, MessageAction)
}

type cfg_int int
type cfg_bool bool
type cfg_float float64
type cfg_list []string

type EID string

type ExtensionLoader interface {
	Load(EID) Extension
}

type ExtensionConfig map[string]interface{}

type InvalidConfig struct {
	Key string
	msg string
}

func (ic InvalidConfig) Error() string {
	return ic.msg
}

func (cfg ExtensionConfig) read(key string, def interface{}) interface{} {
	if val, ok := cfg[key]; ok {
		return val
	}

	return def
}

func (cfg ExtensionConfig) integer(key string, def int) cfg_int {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case int:
			return b
		}
	}

	return def
}

func (cfg ExtensionConfig) boolean(key string, def bool) cfg_bool {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case bool:
			return b
		case int:
			// Require explicit 0 or 1
			if b == 0 {
				return false
			} else if b == 1 {
				return true
			}
		}
	}

	return def
}

func (cfg ExtensionConfig) float(key string, def float64) cfg_float {
	if val, ok := cfg[key]; ok {
		switch f := val.(type) {
		case float32:
			return float64(f)
		case float64:
			return f
		}
	}

	return def
}

func (cfg ExtensionConfig) list(key string, def []string) cfg_list {
	if val, ok := cfg[key]; ok {
		switch l := val.(type) {
		case []string:
			return l
		}

	}

	return def
}
<|endoftext|>