<commit_before>package nexus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
)

// Accesses a Nexus instance. The default Client should work for the newest Nexus versions. Older Nexus versions may
// need or benefit from a specific client.
type Client interface {
	// Returns all artifacts in this Nexus which satisfy the given criteria.
	Artifacts(criteria Criteria) ([]*Artifact, error)

	// Returns all repositories in this Nexus.
	Repositories() ([]*Repository, error)
}

// Represents a Nexus v2.x instance. It's the default Client implementation.
type Nexus2x struct {
	Url string
}

// Creates a new Nexus client, using the default Client implementation.
func New(url string) Client {
	return &Nexus2x{Url: url}
}

// builds the proper URL with parameters for GET-ing
func (nexus *Nexus2x) fullUrlFor(query string, filter map[string]string) string {
	params := []string{}

	for k, v := range filter {
		params = append(params, k+"="+v)
	}

	if len(params) == 0 {
		return nexus.Url + "/" + query
	} else {
		return nexus.Url + "/" + query + "?" + strings.Join(params, "&")
	}
}

// does the actual legwork, going to Nexus e validating the response
func (nexus *Nexus2x) fetch(url string, params map[string]string) (*http.Response, error) {
	get, err := http.NewRequest("GET", nexus.fullUrlFor(url, params), nil)
	if err != nil {
		return nil, err
	}

	get.Header.Add("Accept", "application/json")

	// go for it!
	response, err := http.DefaultClient.Do(get)
	if err != nil {
		return nil, err
	}

	// for us, 4xx are 5xx are errors, so we need to validate the response
	if 400 <= response.StatusCode && response.StatusCode < 600 {
		return response, &BadResponseError{Url: nexus.Url, StatusCode: response.StatusCode, Status: response.Status}
	}

	// everything alright, carry on
	return response, err
}

func bodyToBytes(body io.ReadCloser) ([]byte, error) {
	buf := new(bytes.Buffer)
	if _, err := buf.ReadFrom(body); err != nil {
		return nil, err
	}
	defer body.Close() // don't forget to Close() body at the end!

	return buf.Bytes(), nil
}

// Artifacts

type artifactSearchResponse struct {
	TotalCount int
	Data       []struct {
		GroupId      string
		ArtifactId   string
		Version      string
		ArtifactHits []struct {
			ArtifactLinks []struct {
				Extension  string
				Classifier string
			}
		}
	}
}

func extractArtifactPayloadFrom(body []byte) (*artifactSearchResponse, error) {
	var payload *artifactSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractArtifactsFrom(payload *artifactSearchResponse) []*Artifact {
	var artifacts = []*Artifact{}

	for _, artifact := range payload.Data {
		g := artifact.GroupId
		a := artifact.ArtifactId
		v := artifact.Version

		for _, hit := range artifact.ArtifactHits {
			for _, link := range hit.ArtifactLinks {
				e := link.Extension
				c := link.Classifier

				artifacts = append(artifacts, &Artifact{g, a, v, c, e})
			}
		}
	}

	return artifacts
}

// returns all artifacts which pass the given filter. The expected keys in filter are the flags Nexus' REST API
// accepts, with the same semantics.
func (nexus *Nexus2x) readArtifactsWhere(filter map[string]string) ([]*Artifact, error) {
	// This implementation is slightly tricky. As artifactSearchResponse shows, Nexus always wraps the artifacts in a
	// GAV structure. This structure doesn't mean that within the wrapper are *all* the artifacts within that GAV, or
	// that the next page won't repeat artifacts if an incomplete GAV was returned earlier.
	//
	// On top of that, I haven't quite figured out how Nexus is counting artifacts for paging purposes. POMs don't
	// seem to count as artifacts, except when the project has a 'pom' packaging (which I can't know without opening
	// every POM), but the math still doesn't quite come together. So I adopted a conservative estimate.

	from := 0
	offset := 0
	started := false              // do-while can sometimes be useful
	artifacts := newArtifactSet() // acumulates the artifacts

	for offset != 0 || !started {
		started = true // do-while can sometimes be useful

		from = from + offset
		filter["from"] = strconv.Itoa(from)

		resp, err := nexus.fetch("service/local/lucene/search", filter)
		if err != nil {
			return nil, err
		}

		body, err := bodyToBytes(resp.Body)
		if err != nil {
			return nil, err
		}

		payload, err := extractArtifactPayloadFrom(body)
		if err != nil {
			return nil, err
		}

		// extract and store the artifacts. The set ensures we ignore repeated artifacts.
		artifacts.add(extractArtifactsFrom(payload))

		// a lower bound for the number of artifacts returned, since every GAV holds at least one artifact.
		// There will be some repetitions, but artifacts takes care of that.
		offset = len(payload.Data)
	}

	return artifacts.data, nil
}

// returns the first-level directories in the given repository
func (nexus *Nexus2x) firstLevelDirsOf(repositoryId string) ([]string, error) {
	// XXX Don't forget the ending /, or the response is always XML!
	resp, err := nexus.fetch("service/local/repositories/"+repositoryId+"/content/", nil)
	if err != nil {
		return nil, err
	}

	// fill payload with the given response
	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	var payload *struct {
		Data []struct {
			Leaf bool
			Text string
		}
	}

	err = json.Unmarshal([]byte(body), &payload)
	if err != nil {
		return nil, err
	}

	// extract the directories from payload
	result := []string{}
	for _, dir := range payload.Data {
		if !dir.Leaf {
			result = append(result, dir.Text)
		}
	}

	return result, nil
}

func (nexus *Nexus2x) readArtifactsFrom(repositoryId string) ([]*Artifact, error) {
	// This function also has some tricky details. In the olden days (around version 1.8 or so), one could get all the
	// artifacts in a given repository searching only for *. This has been disabled in the newer versions, without any
	// official alternative for "give me everything you have". So, the solution adopted here is:
	// 1) get the first level directories in repositoryId
	// 2) for every directory 'dir', search filtering for a groupId 'dir*' and the repository ID
	// 3) accumulate the results in an artifactSet to avoid duplicates (e.g. the results in common* appear also in com*)
	//
	// This way I can ensure that all artifacts were found.

	result := newArtifactSet()

	// 1)
	dirs, err := nexus.firstLevelDirsOf(repositoryId)
	if err != nil {
		return nil, err
	}

	for _, dir := range dirs {
		// 2)
		artifacts, err := nexus.readArtifactsWhere(map[string]string{"g": dir + "*", "repositoryId": repositoryId})
		if err != nil {
			return nil, err
		}

		// 3)
		result.add(artifacts)
	}

	return result.data, nil
}

func (nexus *Nexus2x) Artifacts(criteria Criteria) ([]*Artifact, error) {
	params := criteria.Parameters()

	if len(params) == 0 {
		return nil, fmt.Errorf("Full search isn't supported!")
	}

	if len(params) == 1 {
		if repoId, ok := params["repositoryId"]; ok {
			return nexus.readArtifactsFrom(repoId)
		}
	}

	return nexus.readArtifactsWhere(params)
}

// Repositories

type repoSearchResponse struct {
	Data []struct {
		Id         string
		Name       string
		RepoType   string
		RepoPolicy string
		Format     string
		RemoteUri  string
	}
}

func extractRepoPayloadFrom(body []byte) (*repoSearchResponse, error) {
	var payload *repoSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractReposFrom(payload *repoSearchResponse) []*Repository {
	result := []*Repository{}

	for _, repo := range payload.Data {
		newRepo := &Repository{
			Id:        repo.Id,
			Name:      repo.Name,
			Type:      repo.RepoType,
			Format:    repo.Format,
			Policy:    repo.RepoPolicy,
			RemoteURI: repo.RemoteUri,
		}

		result = append(result, newRepo)
	}

	return result
}

func (nexus *Nexus2x) Repositories() ([]*Repository, error) {
	resp, err := nexus.fetch("service/local/repositories", nil)
	if err != nil {
		return nil, err
	}

	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	payload, err := extractRepoPayloadFrom(body)
	if err != nil {
		return nil, err
	}

	return extractReposFrom(payload), nil
}
<commit_msg>Some extra comment touches.<commit_after>package nexus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
)

// Accesses a Nexus instance. The default Client should work for the newest Nexus versions. Older Nexus versions may
// need or benefit from a specific client.
type Client interface {
	// Returns all artifacts in this Nexus which satisfy the given criteria.
	Artifacts(criteria Criteria) ([]*Artifact, error)

	// Returns all repositories in this Nexus.
	Repositories() ([]*Repository, error)
}

// Represents a Nexus v2.x instance. It's the default Client implementation.
type Nexus2x struct {
	Url string
}

// Creates a new Nexus client, using the default Client implementation.
func New(url string) Client {
	return &Nexus2x{Url: url}
}

// builds the proper URL with parameters for GET-ing
func (nexus *Nexus2x) fullUrlFor(query string, filter map[string]string) string {
	params := []string{}

	for k, v := range filter {
		params = append(params, k+"="+v)
	}

	if len(params) == 0 {
		return nexus.Url + "/" + query
	} else {
		return nexus.Url + "/" + query + "?" + strings.Join(params, "&")
	}
}

// does the actual legwork, going to Nexus e validating the response
func (nexus *Nexus2x) fetch(url string, params map[string]string) (*http.Response, error) {
	get, err := http.NewRequest("GET", nexus.fullUrlFor(url, params), nil)
	if err != nil {
		return nil, err
	}

	get.Header.Add("Accept", "application/json")

	// go for it!
	response, err := http.DefaultClient.Do(get)
	if err != nil {
		return nil, err
	}

	// for us, 4xx are 5xx are errors, so we need to validate the response
	if 400 <= response.StatusCode && response.StatusCode < 600 {
		return response, &BadResponseError{Url: nexus.Url, StatusCode: response.StatusCode, Status: response.Status}
	}

	// everything alright, carry on
	return response, err
}

func bodyToBytes(body io.ReadCloser) ([]byte, error) {
	buf := new(bytes.Buffer)
	if _, err := buf.ReadFrom(body); err != nil {
		return nil, err
	}
	defer body.Close() // don't forget to Close() body at the end!

	return buf.Bytes(), nil
}

// Artifacts

type artifactSearchResponse struct {
	TotalCount int
	Data       []struct {
		GroupId      string
		ArtifactId   string
		Version      string
		ArtifactHits []struct {
			ArtifactLinks []struct {
				Extension  string
				Classifier string
			}
		}
	}
}

func extractArtifactPayloadFrom(body []byte) (*artifactSearchResponse, error) {
	var payload *artifactSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractArtifactsFrom(payload *artifactSearchResponse) []*Artifact {
	var artifacts = []*Artifact{}

	for _, artifact := range payload.Data {
		g := artifact.GroupId
		a := artifact.ArtifactId
		v := artifact.Version

		for _, hit := range artifact.ArtifactHits {
			for _, link := range hit.ArtifactLinks {
				e := link.Extension
				c := link.Classifier

				artifacts = append(artifacts, &Artifact{g, a, v, c, e})
			}
		}
	}

	return artifacts
}

// returns all artifacts which pass the given filter. The expected keys in filter are the flags Nexus' REST API
// accepts, with the same semantics.
func (nexus *Nexus2x) readArtifactsWhere(filter map[string]string) ([]*Artifact, error) {
	// This implementation is slightly tricky. As artifactSearchResponse shows, Nexus always wraps the artifacts in a
	// GAV structure. This structure doesn't mean that within the wrapper are *all* the artifacts within that GAV, or
	// that the next page won't repeat artifacts if an incomplete GAV was returned earlier.
	//
	// On top of that, I haven't quite figured out how Nexus is counting artifacts for paging purposes. POMs don't
	// seem to count as artifacts, except when the project has a 'pom' packaging (which I can't know for sure without
	// GET-ing every POM), but the math still doesn't quite come together. So I took a conservative approach, which
	// forces a sequential algorithm. This search can be parallelized if the paging problem is solved.

	from := 0
	offset := 0
	started := false              // do-while can sometimes be useful
	artifacts := newArtifactSet() // acumulates the artifacts

	for offset != 0 || !started {
		started = true // do-while can sometimes be useful

		from = from + offset
		filter["from"] = strconv.Itoa(from)

		resp, err := nexus.fetch("service/local/lucene/search", filter)
		if err != nil {
			return nil, err
		}

		body, err := bodyToBytes(resp.Body)
		if err != nil {
			return nil, err
		}

		payload, err := extractArtifactPayloadFrom(body)
		if err != nil {
			return nil, err
		}

		// extract and store the artifacts. The set ensures we ignore repeated artifacts.
		artifacts.add(extractArtifactsFrom(payload))

		// a lower bound for the number of artifacts returned, since every GAV holds at least one artifact.
		// There will be some repetitions, but artifacts takes care of that.
		offset = len(payload.Data)
	}

	return artifacts.data, nil
}

// returns the first-level directories in the given repository
func (nexus *Nexus2x) firstLevelDirsOf(repositoryId string) ([]string, error) {
	// XXX Don't forget the ending /, or the response is always XML!
	resp, err := nexus.fetch("service/local/repositories/"+repositoryId+"/content/", nil)
	if err != nil {
		return nil, err
	}

	// fill payload with the given response
	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	var payload *struct {
		Data []struct {
			Leaf bool
			Text string
		}
	}

	err = json.Unmarshal([]byte(body), &payload)
	if err != nil {
		return nil, err
	}

	// extract the directories from payload
	result := []string{}
	for _, dir := range payload.Data {
		if !dir.Leaf {
			result = append(result, dir.Text)
		}
	}

	return result, nil
}

func (nexus *Nexus2x) readArtifactsFrom(repositoryId string) ([]*Artifact, error) {
	// This function also has some tricky details. In the olden days (around version 1.8 or so), one could get all the
	// artifacts in a given repository by searching for *. This has been disabled in the newer versions, without any
	// official alternative for "give me everything you have". So, the solution adopted here is:
	// 1) get the first level directories in repositoryId
	// 2) for every directory 'dir', do a search filtering for the groupId 'dir*' and the repository ID
	// 3) accumulate the results in an artifactSet to avoid duplicates (e.g. the results in common* appear also in com*)

	result := newArtifactSet()

	// 1)
	dirs, err := nexus.firstLevelDirsOf(repositoryId)
	if err != nil {
		return nil, err
	}

	for _, dir := range dirs {
		// 2)
		artifacts, err := nexus.readArtifactsWhere(map[string]string{"g": dir + "*", "repositoryId": repositoryId})
		if err != nil {
			return nil, err
		}

		// 3)
		result.add(artifacts)
	}

	return result.data, nil
}

// Errors out on a full search (n.Artifacts(CriteriaEmpty)).
func (nexus *Nexus2x) Artifacts(criteria Criteria) ([]*Artifact, error) {
	params := criteria.Parameters()

	if len(params) == 0 {
		return nil, fmt.Errorf("Full search isn't supported!")
	}

	if len(params) == 1 {
		if repoId, ok := params["repositoryId"]; ok {
			return nexus.readArtifactsFrom(repoId)
		}
	}

	return nexus.readArtifactsWhere(params)
}

// Repositories

type repoSearchResponse struct {
	Data []struct {
		Id         string
		Name       string
		RepoType   string
		RepoPolicy string
		Format     string
		RemoteUri  string
	}
}

func extractRepoPayloadFrom(body []byte) (*repoSearchResponse, error) {
	var payload *repoSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractReposFrom(payload *repoSearchResponse) []*Repository {
	result := []*Repository{}

	for _, repo := range payload.Data {
		newRepo := &Repository{
			Id:        repo.Id,
			Name:      repo.Name,
			Type:      repo.RepoType,
			Format:    repo.Format,
			Policy:    repo.RepoPolicy,
			RemoteURI: repo.RemoteUri,
		}

		result = append(result, newRepo)
	}

	return result
}

func (nexus *Nexus2x) Repositories() ([]*Repository, error) {
	resp, err := nexus.fetch("service/local/repositories", nil)
	if err != nil {
		return nil, err
	}

	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	payload, err := extractRepoPayloadFrom(body)
	if err != nil {
		return nil, err
	}

	return extractReposFrom(payload), nil
}
<|endoftext|>


<commit_before>package suggest_test

import (
	"github.com/Symantec/scotty/suggest"
	"reflect"
	"testing"
)

func TestEngine(t *testing.T) {
	engine := suggest.NewEngine()
	engine.Add("A")
	engine.Add("Hi")
	engine.Add("Hello")
	engine.Add("Suggest")
	engine.Add("A")
	engine.Add("Hi")
	engine.Add("Hello")
	engine.Add("Suggest")
	engine.Await()
	assertValueDeepEquals(
		t, []string{"Hello", "Hi"}, engine.Suggest(3, "H"))
	assertValueDeepEquals(
		t, []string{"Hello", "Hi"}, engine.Suggest(2, "H"))
	assertValueDeepEquals(
		t, []string{"Hello"}, engine.Suggest(1, "H"))
	assertValueDeepEquals(
		t, []string{"Hello", "Hi"}, engine.Suggest(0, "H"))
	assertValueDeepEquals(
		t, []string{"A", "Hello", "Hi", "Suggest"}, engine.Suggest(0, ""))
	assertValueEquals(t, 0, len(engine.Suggest(0, "J")))
	assertValueEquals(t, 0, len(engine.Suggest(5, "J")))

}

func TestConstEngine(t *testing.T) {
	engine := suggest.NewSuggester(
		"log", "logger", "loggest", "a", "an", "and", "aback")
	assertValueDeepEquals(
		t, []string{"log", "logger", "loggest"}, engine.Suggest(0, "log"))
	assertValueDeepEquals(
		t, []string{"log", "logger", "loggest"}, engine.Suggest(3, "log"))
	assertValueDeepEquals(
		t, []string{"log", "logger"}, engine.Suggest(2, "log"))
	assertValueDeepEquals(
		t, []string{"log"}, engine.Suggest(1, "log"))
	assertValueDeepEquals(
		t, []string{"logger", "loggest"}, engine.Suggest(2, "logg"))
	assertValueDeepEquals(
		t, []string{"a", "an", "and", "aback"}, engine.Suggest(0, "a"))
	assertValueDeepEquals(
		t, []string{"a", "an", "and", "aback"}, engine.Suggest(0, "a"))
	assertValueDeepEquals(
		t, []string{"aback"}, engine.Suggest(0, "ab"))
	assertValueEquals(t, 0, len(engine.Suggest(0, "abc")))
	assertValueEquals(t, 0, len(engine.Suggest(0, "m")))
	assertValueEquals(t, 0, len(engine.Suggest(5, "m")))

}
func assertValueEquals(
	t *testing.T, expected, actual interface{}) bool {
	if expected != actual {
		t.Errorf("Expected %v, got %v", expected, actual)
		return false
	}
	return true
}

func assertValueDeepEquals(
	t *testing.T, expected, actual interface{}) bool {
	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("Expected %v, got %v", expected, actual)
		return false
	}
	return true
}
<commit_msg>Add a few more tests.<commit_after>package suggest_test

import (
	"github.com/Symantec/scotty/suggest"
	"reflect"
	"testing"
)

func TestEngine(t *testing.T) {
	engine := suggest.NewEngine()
	assertValueEquals(t, 0, len(engine.Suggest(0, "")))
	engine.Add("A")
	engine.Add("Hi")
	engine.Add("Hello")
	engine.Add("Suggest")
	engine.Add("A")
	engine.Add("Hi")
	engine.Add("Hello")
	engine.Add("Suggest")
	engine.Await()
	assertValueDeepEquals(
		t, []string{"Hello", "Hi"}, engine.Suggest(3, "H"))
	assertValueDeepEquals(
		t, []string{"Hello", "Hi"}, engine.Suggest(2, "H"))
	assertValueDeepEquals(
		t, []string{"Hello"}, engine.Suggest(1, "H"))
	assertValueDeepEquals(
		t, []string{"Hello", "Hi"}, engine.Suggest(0, "H"))
	assertValueDeepEquals(
		t, []string{"A", "Hello", "Hi", "Suggest"}, engine.Suggest(0, ""))
	assertValueEquals(t, 0, len(engine.Suggest(0, "J")))
	assertValueEquals(t, 0, len(engine.Suggest(5, "J")))

}

func TestConstEngine(t *testing.T) {
	engine := suggest.NewSuggester(
		"log", "logger", "loggest", "a", "an", "and", "aback")
	assertValueDeepEquals(
		t, []string{"log", "logger", "loggest"}, engine.Suggest(0, "log"))
	assertValueDeepEquals(
		t, []string{"log", "logger", "loggest"}, engine.Suggest(3, "log"))
	assertValueDeepEquals(
		t, []string{"log", "logger"}, engine.Suggest(2, "log"))
	assertValueDeepEquals(
		t, []string{"log"}, engine.Suggest(1, "log"))
	assertValueDeepEquals(
		t, []string{"logger", "loggest"}, engine.Suggest(2, "logg"))
	assertValueDeepEquals(
		t, []string{"a", "an", "and", "aback"}, engine.Suggest(0, "a"))
	assertValueDeepEquals(
		t, []string{"a", "an", "and", "aback"}, engine.Suggest(0, "a"))
	assertValueDeepEquals(
		t, []string{"aback"}, engine.Suggest(0, "ab"))
	assertValueDeepEquals(
		t, []string{"log", "logger"}, engine.Suggest(2, ""))
	assertValueDeepEquals(
		t, []string{"log", "logger", "loggest", "a", "an", "and", "aback"},
		engine.Suggest(0, ""))
	assertValueEquals(t, 0, len(engine.Suggest(0, "abc")))
	assertValueEquals(t, 0, len(engine.Suggest(0, "m")))
	assertValueEquals(t, 0, len(engine.Suggest(5, "m")))

}

func TestNilEngine(t *testing.T) {
	engine := suggest.NewSuggester()
	assertValueEquals(t, 0, len(engine.Suggest(0, "")))
	assertValueEquals(t, 0, len(engine.Suggest(0, "a")))
	assertValueEquals(t, 0, len(engine.Suggest(2, "a")))
}

func assertValueEquals(
	t *testing.T, expected, actual interface{}) bool {
	if expected != actual {
		t.Errorf("Expected %v, got %v", expected, actual)
		return false
	}
	return true
}

func assertValueDeepEquals(
	t *testing.T, expected, actual interface{}) bool {
	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("Expected %v, got %v", expected, actual)
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package models

import (
	"strconv"
	"errors"

	"../app"
)

const (
	insertDomain = `
	INSERT INTO domains (name, url, status, created_at, updated_at)
	VALUES(?, ?, 1, NOW(), NOW()) ON DUPLICATE KEY UPDATE
	name = VALUES(name)
	`

	checkDomain = `
	SELECT COUNT(*) as count FROM domains WHERE name LIKE ? OR url LIKE ?
	`

	selectAllDomains = `
	SELECT id, name, url, status, updated_at
	FROM domains
	LIMIT ?
	OFFSET ?
	`
	countAllDomains = `
	SELECT COUNT(*) as count
	FROM domains
	`

	deleteDomain = `
	DELETE FROM domains WHERE id = ?
	`

	selectDomain = `
	SELECT id, name, url, status, updated_at FROM domains WHERE id = ?
	`
)

type Domain struct {
	ID        int        `form:"id" json:"id"`
	Name      string     `form:"name" json:"name"`
	Url       string     `form:"url" json:"url"`
	Status    int        `form:"status" json:"status"`
	Updated   string     `form:"updated_at" json:"updated_at"`
	Ftps      []Ftp      `form:"ftp" json:"ftp"`
	Databases []Database `form:"database" json:"database"`
}

// Добавление домена
func CreateDomain(name, url string) (string, error) {
	if CheckDomain(name, url) {
		res, err := app.Exec(insertDomain, name, url)

		id, err := res.LastInsertId()
		if err != nil {
			return "", err
		}
		return strconv.FormatInt(id, 10), nil
	} else {
		err := errors.New("Domain was already created!")
		return "", err
	}
}

// Список доменов
func AllDomains(param string) (domains []Domain, count int, err error) {
	limit := 15
	page, _ := strconv.Atoi(param)
	offset := (page - 1) * limit

	rows, err := app.Query(selectAllDomains, limit, offset)

	row, _ := app.Query(countAllDomains)

	allDomain := app.CountRows(row)

	pages := allDomain / limit

	if err != nil {
		return domains, pages, err
	}

	defer rows.Close()
	for rows.Next() {
		d := Domain{}
		err = rows.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, pages, err
		}
		domains = append(domains, d)
	}
	err = rows.Err()
	return domains, pages, err
}

// Удаление домена
func DeleteDomain(id int) (bool, error) {
	_, err := app.Exec(deleteDomain, id)

	if err == nil {
		return true, nil
	} else {
		return false, err
	}
}

// Получение конкретного домена
func GetDomain(param int) (domains []Domain, err error) {
	row, err := app.Query(selectDomain, param)
	defer row.Close()

	ftp, err := SelectFtps(param)
	mysql, err := SelectDatabases(param)

	for row.Next() {
		d := Domain{}
		err = row.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, err
		}

		d.Ftps = ftp
		d.Databases = mysql
		domains = append(domains, d)
	}
	err = row.Err()

	return domains, err
}

func CheckDomain(name, url string) bool {
	res, _ := app.Query(checkDomain, name, url)

	if app.CountRows(res) >= 1 {
		return false
	} else {
		return true
	}
}
<commit_msg>Update domains.go<commit_after>package models

import (
	"strconv"
	"errors"

	"../app"
)

const (
	insertDomain = `
	INSERT INTO domains (name, url, status, created_at, updated_at)
	VALUES(?, ?, 1, NOW(), NOW()) ON DUPLICATE KEY UPDATE
	name = VALUES(name)
	`

	checkDomain = `
	SELECT COUNT(*) as count FROM domains WHERE name LIKE ? OR url LIKE ?
	`

	selectAllDomains = `
	SELECT id, name, url, status, updated_at
	FROM domains
	LIMIT ?
	OFFSET ?
	`
	countAllDomains = `
	SELECT COUNT(*) as count
	FROM domains
	`

	deleteDomain = `
	DELETE FROM domains WHERE id = ?
	`

	selectDomain = `
	SELECT id, name, url, status, updated_at FROM domains WHERE id = ?
	`
)

type Domain struct {
	ID        int        `form:"id" json:"id"`
	Name      string     `form:"name" json:"name"`
	Url       string     `form:"url" json:"url"`
	Status    int        `form:"status" json:"status"`
	Updated   string     `form:"updated_at" json:"updated_at"`
	Ftps      []Ftp      `form:"ftp" json:"ftp"`
	Databases []Database `form:"database" json:"database"`
	Hostings  []Hosting  `form:"hosting" json:"hosting"`
	Admins    []Admin    `form:"admin" json:"admin"`
}

// Добавление домена
func CreateDomain(name, url string) (string, error) {
	if CheckDomain(name, url) {
		res, err := app.Exec(insertDomain, name, url)

		id, err := res.LastInsertId()
		if err != nil {
			return "", err
		}
		return strconv.FormatInt(id, 10), nil
	} else {
		err := errors.New("Domain was already created!")
		return "", err
	}
}

// Список доменов
func AllDomains(param string) (domains []Domain, count int, err error) {
	limit := 15
	page, _ := strconv.Atoi(param)
	offset := (page - 1) * limit

	rows, err := app.Query(selectAllDomains, limit, offset)

	row, _ := app.Query(countAllDomains)

	allDomain := app.CountRows(row)

	pages := allDomain / limit

	if err != nil {
		return domains, pages, err
	}

	defer rows.Close()
	for rows.Next() {
		d := Domain{}
		err = rows.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, pages, err
		}
		domains = append(domains, d)
	}
	err = rows.Err()
	return domains, pages, err
}

// Удаление домена
func DeleteDomain(id int) (bool, error) {
	_, err := app.Exec(deleteDomain, id)

	if err == nil {
		return true, nil
	} else {
		return false, err
	}
}

// Получение конкретного домена
func GetDomain(param int) (domains []Domain, err error) {
	row, err := app.Query(selectDomain, param)
	defer row.Close()

	ftp, err := SelectFtps(param)
	mysql, err := SelectDatabases(param)

	for row.Next() {
		d := Domain{}
		err = row.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, err
		}

		d.Ftps = ftp
		d.Databases = mysql
		domains = append(domains, d)
	}
	err = row.Err()

	return domains, err
}

func CheckDomain(name, url string) bool {
	res, _ := app.Query(checkDomain, name, url)

	if app.CountRows(res) >= 1 {
		return false
	} else {
		return true
	}
}
<|endoftext|>


<commit_before>package orm

import (
	"fmt"
	"gnd.la/orm/driver"
	"gnd.la/orm/query"
)

type Query struct {
	orm       *Orm
	model     *joinModel
	methods   []*driver.Methods
	jtype     JoinType
	q         query.Q
	limit     int
	offset    int
	sortField string
	sortDir   int
	depth     int
	err       error
}

func (q *Query) ensureTable(f string) error {
	if q.model == nil {
		fmt.Errorf("no table selected, set one with Table() before calling %s()", f)
	}
	return nil
}

// Table sets the table for the query. If the table was
// previously set, it's overridden. Rather than using
// strings to select tables, a Table object (which is
// returned from Register) is used. This way is not
// possible to mistype a table name, which avoids lots
// of errors.
func (q *Query) Table(t *Table) *Query {
	q.model = t.model
	return q
}

// Join sets the default join type for this query. If not
// specifed, an INNER JOIN is performed. Note that not all
// drivers support RIGHT joins (e.g. sqlite).
func (q *Query) Join(jt JoinType) *Query {
	q.jtype = jt
	return q
}

// Filter adds another condition to the query. In other
// words, it ANDs the previous condition with the one passed in.
func (q *Query) Filter(qu query.Q) *Query {
	if qu != nil {
		if q.q == nil {
			q.q = qu
		} else {
			switch x := q.q.(type) {
			case *query.And:
				x.Conditions = append(x.Conditions, qu)
			default:
				q.q = And(q.q, qu)
			}
		}
	}
	return q
}

// Limit sets the maximum number of results
// for the query.
func (q *Query) Limit(limit int) *Query {
	q.limit = limit
	return q
}

// Offset sets the offset for the query.
func (q *Query) Offset(offset int) *Query {
	q.offset = offset
	return q
}

// Sort sets the field and direction used for sorting
// this query.
func (q *Query) Sort(field string, dir Sort) *Query {
	q.sortField = field
	q.sortDir = int(dir)
	return q
}

// One fetches the first result for this query. If there
// are no results, it returns ErrNotFound.
func (q *Query) One(out ...interface{}) error {
	iter := q.iter(1)
	if iter.Next(out...) {
		// Must close the iter manually, because we're not
		// reaching the end.
		iter.Close()
		return nil
	}
	if err := iter.Err(); err != nil {
		return err
	}
	return ErrNotFound
}

// Exists returns wheter a result with the specified query
// exists.
func (q *Query) Exists() (bool, error) {
	if err := q.ensureTable("Exists"); err != nil {
		return false, err
	}
	q.orm.numQueries++
	return q.orm.driver.Exists(q.model, q.q)
}

// Iter returns an Iter object which lets you
// iterate over the results produced by the
// query.
func (q *Query) Iter() *Iter {
	return q.iter(q.limit)
}

// Count returns the number of results for the query. Note that
// you have to set the table manually before calling Count().
func (q *Query) Count() (uint64, error) {
	if err := q.ensureTable("Count"); err != nil {
		return 0, err
	}
	q.orm.numQueries++
	return q.orm.driver.Count(q.model, q.q, q.limit, q.offset)
}

// MustCount works like Count, but panics if there's an error.
func (q *Query) MustCount() uint64 {
	c, err := q.Count()
	if err != nil {
		panic(err)
	}
	return c
}

func (q *Query) SetDepth(depth int) {
	q.depth = depth
}

// Clone returns a copy of the query.
func (q *Query) Clone() *Query {
	return &Query{
		orm:       q.orm,
		model:     q.model,
		q:         q.q,
		limit:     q.limit,
		offset:    q.offset,
		sortField: q.sortField,
		sortDir:   q.sortDir,
		depth:     q.depth,
		err:       q.err,
	}
}

func (q *Query) iter(limit int) *Iter {
	return &Iter{
		q:     q,
		limit: limit,
		err:   q.err,
	}
}

func (q *Query) exec(limit int) driver.Iter {
	q.orm.numQueries++
	return q.orm.conn.Query(q.model, q.q, limit, q.offset, q.sortDir, q.sortField)
}
<commit_msg>Remove depth field in Query<commit_after>package orm

import (
	"fmt"
	"gnd.la/orm/driver"
	"gnd.la/orm/query"
)

type Query struct {
	orm       *Orm
	model     *joinModel
	methods   []*driver.Methods
	jtype     JoinType
	q         query.Q
	limit     int
	offset    int
	sortField string
	sortDir   int
	err       error
}

func (q *Query) ensureTable(f string) error {
	if q.model == nil {
		fmt.Errorf("no table selected, set one with Table() before calling %s()", f)
	}
	return nil
}

// Table sets the table for the query. If the table was
// previously set, it's overridden. Rather than using
// strings to select tables, a Table object (which is
// returned from Register) is used. This way is not
// possible to mistype a table name, which avoids lots
// of errors.
func (q *Query) Table(t *Table) *Query {
	q.model = t.model
	return q
}

// Join sets the default join type for this query. If not
// specifed, an INNER JOIN is performed. Note that not all
// drivers support RIGHT joins (e.g. sqlite).
func (q *Query) Join(jt JoinType) *Query {
	q.jtype = jt
	return q
}

// Filter adds another condition to the query. In other
// words, it ANDs the previous condition with the one passed in.
func (q *Query) Filter(qu query.Q) *Query {
	if qu != nil {
		if q.q == nil {
			q.q = qu
		} else {
			switch x := q.q.(type) {
			case *query.And:
				x.Conditions = append(x.Conditions, qu)
			default:
				q.q = And(q.q, qu)
			}
		}
	}
	return q
}

// Limit sets the maximum number of results
// for the query.
func (q *Query) Limit(limit int) *Query {
	q.limit = limit
	return q
}

// Offset sets the offset for the query.
func (q *Query) Offset(offset int) *Query {
	q.offset = offset
	return q
}

// Sort sets the field and direction used for sorting
// this query.
func (q *Query) Sort(field string, dir Sort) *Query {
	q.sortField = field
	q.sortDir = int(dir)
	return q
}

// One fetches the first result for this query. If there
// are no results, it returns ErrNotFound.
func (q *Query) One(out ...interface{}) error {
	iter := q.iter(1)
	if iter.Next(out...) {
		// Must close the iter manually, because we're not
		// reaching the end.
		iter.Close()
		return nil
	}
	if err := iter.Err(); err != nil {
		return err
	}
	return ErrNotFound
}

// Exists returns wheter a result with the specified query
// exists.
func (q *Query) Exists() (bool, error) {
	if err := q.ensureTable("Exists"); err != nil {
		return false, err
	}
	q.orm.numQueries++
	return q.orm.driver.Exists(q.model, q.q)
}

// Iter returns an Iter object which lets you
// iterate over the results produced by the
// query.
func (q *Query) Iter() *Iter {
	return q.iter(q.limit)
}

// Count returns the number of results for the query. Note that
// you have to set the table manually before calling Count().
func (q *Query) Count() (uint64, error) {
	if err := q.ensureTable("Count"); err != nil {
		return 0, err
	}
	q.orm.numQueries++
	return q.orm.driver.Count(q.model, q.q, q.limit, q.offset)
}

// MustCount works like Count, but panics if there's an error.
func (q *Query) MustCount() uint64 {
	c, err := q.Count()
	if err != nil {
		panic(err)
	}
	return c
}

// Clone returns a copy of the query.
func (q *Query) Clone() *Query {
	return &Query{
		orm:       q.orm,
		model:     q.model,
		q:         q.q,
		limit:     q.limit,
		offset:    q.offset,
		sortField: q.sortField,
		sortDir:   q.sortDir,
		err:       q.err,
	}
}

func (q *Query) iter(limit int) *Iter {
	return &Iter{
		q:     q,
		limit: limit,
		err:   q.err,
	}
}

func (q *Query) exec(limit int) driver.Iter {
	q.orm.numQueries++
	return q.orm.conn.Query(q.model, q.q, limit, q.offset, q.sortDir, q.sortField)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) SAS Institute, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package rpmutils

import "sort"

type NEVRA struct {
	Name    string
	Epoch   string
	Version string
	Release string
	Arch    string
}

func NEVRAcmp(a NEVRA, b NEVRA) int {
	if res := Vercmp(a.Epoch, b.Epoch); res != 0 {
		return res
	}
	if res := Vercmp(a.Version, b.Version); res != 0 {
		return res
	}
	if res := Vercmp(a.Release, b.Release); res != 0 {
		return res
	}
	return 0
}

type NEVRASlice []NEVRA

func (s NEVRASlice) Len() int {
	return len(s)
}

func (s NEVRASlice) Less(i, j int) bool {
	return NEVRAcmp(s[i], s[j]) == -1
}

func (s NEVRASlice) Swap(i, j int) {
	n := s[i]
	s[i] = s[j]
	s[j] = n
}

func (s NEVRASlice) Sort() {
	sort.Sort(s)
}
<commit_msg>Add string method for printing NEVRAs (BAREOS-1127)<commit_after>/*
 * Copyright (c) SAS Institute, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package rpmutils

import "sort"

type NEVRA struct {
	Name    string
	Epoch   string
	Version string
	Release string
	Arch    string
}

func (nevra *NEVRA) String() string {
	return fmt.Sprintf("%s-%s:%s-%s.%s.rpm", nevra.Name, nevra.Epoch, nevra.Version, nevra.Release, nevra.Archi)
}

func NEVRAcmp(a NEVRA, b NEVRA) int {
	if res := Vercmp(a.Epoch, b.Epoch); res != 0 {
		return res
	}
	if res := Vercmp(a.Version, b.Version); res != 0 {
		return res
	}
	if res := Vercmp(a.Release, b.Release); res != 0 {
		return res
	}
	return 0
}

type NEVRASlice []NEVRA

func (s NEVRASlice) Len() int {
	return len(s)
}

func (s NEVRASlice) Less(i, j int) bool {
	return NEVRAcmp(s[i], s[j]) == -1
}

func (s NEVRASlice) Swap(i, j int) {
	n := s[i]
	s[i] = s[j]
	s[j] = n
}

func (s NEVRASlice) Sort() {
	sort.Sort(s)
}
<|endoftext|>


<commit_before>package express

import (
	"encoding/json"
	"log"

	"github.com/gopherjs/gopherjs/js"
)

//Request is the idiomatic (!) go type for a http request
type Request struct {
	Body        []byte              `json:"body,omitempty"`
	Path        string              `json:"path,omitempty"`
	Method      string              `json:"method,omitempty"`
	Host        string              `json:"host,omitempty"`
	IPAddresses []string            `json:"ips,omitempty"`
	IPAddress   string              `json:"ip,omitempty"`
	Params      map[string][]string `json:"params,omitempty"`
	Headers     map[string]string   `json:"headers,omitempty"`
	Query       map[string][]string `json:"query,omitempty"`
	Cookies     map[string][]string `json:"cookies,omitempty"`
	Raw         *js.Object          `json:"cookies,omit"`
}

//ParseRequest wraps a (express request) javascript object into what we need
func NewRequest(req *js.Object) Request {
	params, err := convertToMapOfStringSlices(nil)

	if err != nil {
		log.Println("params: " + err.Error())
	}

	query, err := convertToMapOfStringSlices(req.Get("query").Interface())

	if err != nil {
		log.Println("query: " + err.Error())
	}

	cookies, err := convertToMapOfStringSlices(req.Get("cookies").Interface())

	if err != nil {
		log.Println("cookies: " + err.Error())
	}

	body, err := convertToBytes(req.Get("body").Interface())

	if err != nil {
		log.Println("body: " + err.Error())
	}

	ips, err := convertToStringSlice(req.Get("ips").Interface())

	if err != nil {
		log.Println("ips: " + err.Error())
	}

	headers, err := convertToMapOfStrings(req.Get("headers").Interface())

	if err != nil {
		log.Println("headers: " + err.Error())
	}

	var path string
	pathObject := req.Get("path")

	if pathObject == nil {
		path = "/"
	} else {
		path = pathObject.String()
	}

	return Request{
		IPAddress:   req.Get("ip").String(),
		Host:        req.Get("hostname").String(),
		Method:      req.Get("method").String(),
		Path:        path,
		IPAddresses: ips,
		Headers:     headers,
		Params:      params,
		Body:        body,
		Query:       query,
		Cookies:     cookies,
		Raw:         req,
	}
}

//JSON is returns a STRING; not bytes
func (r Request) JSON() []byte {
	byt, err := json.Marshal(r)
	if err != nil {
		panic(err)
	}
	return byt
}
<commit_msg>Add some more fields<commit_after>package express

import (
	"encoding/json"
	"log"

	"github.com/gopherjs/gopherjs/js"
)

//Request is the idiomatic (!) go type for a http request
type Request struct {
	Body        []byte              `json:"body,omitempty"`
	Path        string              `json:"path,omitempty"`
	Protocol    string              `json:"protocol,omitempty"`
	SubDomains  []string            `json:"subdomains,omitempty"`
	Method      string              `json:"method,omitempty"`
	Host        string              `json:"host,omitempty"`
	IPAddresses []string            `json:"ips,omitempty"`
	IPAddress   string              `json:"ip,omitempty"`
	Params      map[string][]string `json:"params,omitempty"`
	Headers     map[string]string   `json:"headers,omitempty"`
	Query       map[string][]string `json:"query,omitempty"`
	Cookies     map[string][]string `json:"cookies,omitempty"`
	Raw         *js.Object          `json:"cookies,omit"`
}

//ParseRequest wraps a (express request) javascript object into what we need
func NewRequest(req *js.Object) Request {
	params, err := convertToMapOfStringSlices(nil)

	if err != nil {
		log.Println("params: " + err.Error())
	}

	query, err := convertToMapOfStringSlices(req.Get("query").Interface())

	if err != nil {
		log.Println("query: " + err.Error())
	}

	cookies, err := convertToMapOfStringSlices(req.Get("cookies").Interface())

	if err != nil {
		log.Println("cookies: " + err.Error())
	}

	body, err := convertToBytes(req.Get("body").Interface())

	if err != nil {
		log.Println("body: " + err.Error())
	}

	ips, err := convertToStringSlice(req.Get("ips").Interface())

	if err != nil {
		log.Println("ips: " + err.Error())
	}

	headers, err := convertToMapOfStrings(req.Get("headers").Interface())

	if err != nil {
		log.Println("headers: " + err.Error())
	}

	subDomains, err := convertToStringSlice(req.Get("subdomains").Interface())

	if err != nil {
		log.Println("subdomains: " + err.Error())
	}

	var path string
	pathObject := req.Get("path")

	if pathObject == nil {
		path = "/"
	} else {
		path = pathObject.String()
	}

	return Request{
		IPAddress:   req.Get("ip").String(),
		Host:        req.Get("hostname").String(),
		Method:      req.Get("method").String(),
		Protocol:    req.Get("protocol").String(),
		SubDomains:  subDomains,
		Path:        path,
		IPAddresses: ips,
		Headers:     headers,
		Params:      params,
		Body:        body,
		Query:       query,
		Cookies:     cookies,
		Raw:         req,
	}
}

//JSON is returns a STRING; not bytes
func (r Request) JSON() []byte {
	byt, err := json.Marshal(r)
	if err != nil {
		panic(err)
	}
	return byt
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Serge Gebhardt. All rights reserved.
//
// Use of this source code is governed by the ISC
// license that can be found in the LICENSE file.

package acd

import (
	"fmt"
	"net/http"
	"net/url"
	"reflect"

	"errors"
	"github.com/google/go-querystring/query"
)

// NodesService provides access to the nodes in the Amazon Cloud Drive API.
//
// See: https://developer.amazon.com/public/apis/experience/cloud-drive/content/nodes
type NodesService struct {
	client *Client
}

// Gets the root folder of the Amazon Cloud Drive.
func (s *NodesService) GetRoot() (*Folder, *http.Response, error) {
	opts := &NodeListOptions{Filters: "kind:FOLDER AND isRoot:true"}

	roots, resp, err := s.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(roots) < 1 {
		return nil, resp, errors.New("No root found")
	}

	return &Folder{&roots[0]}, resp, nil
}

// Gets the list of all nodes.
func (s *NodesService) GetAllNodes(opts *NodeListOptions) ([]Node, *http.Response, error) {
	return s.listAllNodes("nodes", opts)
}

// Gets a list of nodes, up until the limit (either default or the one set in opts).
func (s *NodesService) GetNodes(opts *NodeListOptions) ([]Node, *http.Response, error) {
	return s.listNodes("nodes", opts)
}

func (s *NodesService) listAllNodes(url string, opts *NodeListOptions) ([]Node, *http.Response, error) {
	// Need opts to maintain state (NodeListOptions.reachedEnd)
	if opts == nil {
		opts = &NodeListOptions{}
	}

	result := make([]Node, 0, 200)

	for {
		nodes, resp, err := s.listNodes(url, opts)
		if err != nil {
			return result, resp, err
		}
		if nodes == nil {
			break
		}

		result = append(result, nodes...)
	}

	return result, nil, nil
}

func (s *NodesService) listNodes(url string, opts *NodeListOptions) ([]Node, *http.Response, error) {
	if opts.reachedEnd {
		return nil, nil, nil
	}

	url, err := addOptions(url, opts)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url, nil)
	if err != nil {
		return nil, nil, err
	}

	nodeList := &nodeListInternal{}
	resp, err := s.client.Do(req, nodeList)
	if err != nil {
		return nil, resp, err
	}

	if nodeList.NextToken != nil {
		opts.StartToken = *nodeList.NextToken
	} else {
		opts.reachedEnd = true
	}

	nodes := nodeList.Data
	// iterate over index since iterating over value would create a copy
	for i := range nodes {
		nodes[i].service = s
	}

	return nodes, resp, nil
}

type nodeListInternal struct {
	Count     *uint64 `json:"count"`
	NextToken *string `json:"nextToken"`
	Data      []Node  `json:"data"`
}

// Node represents a digital asset on the Amazon Cloud Drive, including files
// and folders, in a parent-child relationship. A node contains only metadata
// (e.g. folder) or it contains metadata and content (e.g. file).
type Node struct {
	Id   *string `json:"id"`
	Name *string `json:"name"`
	Kind *string `json:"kind"`

	service *NodesService
}

func (n *Node) Typed() interface{} {
	var result interface{}

	if n.Kind == nil {
		result = n
	} else {
		switch *n.Kind {
		case "FOLDER":
			result = &Folder{n}
		case "FILE":
			result = &File{n}
		default:
			result = n
		}
	}

	return result
}

// Represents a file and contains only metadata.
type File struct {
	*Node
}

// Represents a folder and contains only metadata.
type Folder struct {
	*Node
}

// Gets the list of all children.
func (f *Folder) GetAllChildren(opts *NodeListOptions) ([]Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listAllNodes(url, opts)
}

// Gets a list of children, up until the limit (either default or the one set in opts).
func (f *Folder) GetChildren(opts *NodeListOptions) ([]Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listNodes(url, opts)
}

// Gets the subfolder by name. It is an error if not exactly one subfolder is found.
func (f *Folder) GetSubfolder(name string) (*Folder, *http.Response, error) {
	filter := "kind:FOLDER AND parents:" + *f.Id + " AND name:" + name
	opts := &NodeListOptions{Filters: filter}

	folders, resp, err := f.service.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(folders) < 1 {
		return nil, resp, errors.New(fmt.Sprintf("No subfolder '%s' found", name))
	}
	if len(folders) > 1 {
		return nil, resp, errors.New(fmt.Sprintf("Too many subfolders '%s' found (%v)",
			name, len(folders)))
	}

	return &Folder{&folders[0]}, resp, nil
}

// NodeListOptions holds the options when getting a list of nodes, such as the filter,
// sorting and pagination.
type NodeListOptions struct {
	Limit   uint   `url:"limit,omitempty"`
	Filters string `url:"filters,omitempty"`
	Sort    string `url:"sort,omitempty"`

	// Token where to start for next page (internal)
	StartToken string `url:"startToken,omitempty"`
	reachedEnd bool
}

// addOptions adds the parameters in opts as URL query parameters to s.  opts
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opts interface{}) (string, error) {
	v := reflect.ValueOf(opts)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opts)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}
<commit_msg>Navigate from folder to file (closes #12)<commit_after>// Copyright (c) 2015 Serge Gebhardt. All rights reserved.
//
// Use of this source code is governed by the ISC
// license that can be found in the LICENSE file.

package acd

import (
	"fmt"
	"net/http"
	"net/url"
	"reflect"

	"errors"
	"github.com/google/go-querystring/query"
)

// NodesService provides access to the nodes in the Amazon Cloud Drive API.
//
// See: https://developer.amazon.com/public/apis/experience/cloud-drive/content/nodes
type NodesService struct {
	client *Client
}

// Gets the root folder of the Amazon Cloud Drive.
func (s *NodesService) GetRoot() (*Folder, *http.Response, error) {
	opts := &NodeListOptions{Filters: "kind:FOLDER AND isRoot:true"}

	roots, resp, err := s.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(roots) < 1 {
		return nil, resp, errors.New("No root found")
	}

	return &Folder{&roots[0]}, resp, nil
}

// Gets the list of all nodes.
func (s *NodesService) GetAllNodes(opts *NodeListOptions) ([]Node, *http.Response, error) {
	return s.listAllNodes("nodes", opts)
}

// Gets a list of nodes, up until the limit (either default or the one set in opts).
func (s *NodesService) GetNodes(opts *NodeListOptions) ([]Node, *http.Response, error) {
	return s.listNodes("nodes", opts)
}

func (s *NodesService) listAllNodes(url string, opts *NodeListOptions) ([]Node, *http.Response, error) {
	// Need opts to maintain state (NodeListOptions.reachedEnd)
	if opts == nil {
		opts = &NodeListOptions{}
	}

	result := make([]Node, 0, 200)

	for {
		nodes, resp, err := s.listNodes(url, opts)
		if err != nil {
			return result, resp, err
		}
		if nodes == nil {
			break
		}

		result = append(result, nodes...)
	}

	return result, nil, nil
}

func (s *NodesService) listNodes(url string, opts *NodeListOptions) ([]Node, *http.Response, error) {
	if opts.reachedEnd {
		return nil, nil, nil
	}

	url, err := addOptions(url, opts)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url, nil)
	if err != nil {
		return nil, nil, err
	}

	nodeList := &nodeListInternal{}
	resp, err := s.client.Do(req, nodeList)
	if err != nil {
		return nil, resp, err
	}

	if nodeList.NextToken != nil {
		opts.StartToken = *nodeList.NextToken
	} else {
		opts.reachedEnd = true
	}

	nodes := nodeList.Data
	// iterate over index since iterating over value would create a copy
	for i := range nodes {
		nodes[i].service = s
	}

	return nodes, resp, nil
}

type nodeListInternal struct {
	Count     *uint64 `json:"count"`
	NextToken *string `json:"nextToken"`
	Data      []Node  `json:"data"`
}

// Node represents a digital asset on the Amazon Cloud Drive, including files
// and folders, in a parent-child relationship. A node contains only metadata
// (e.g. folder) or it contains metadata and content (e.g. file).
type Node struct {
	Id   *string `json:"id"`
	Name *string `json:"name"`
	Kind *string `json:"kind"`

	service *NodesService
}

func (n *Node) Typed() interface{} {
	var result interface{}

	if n.Kind == nil {
		result = n
	} else {
		switch *n.Kind {
		case "FOLDER":
			result = &Folder{n}
		case "FILE":
			result = &File{n}
		default:
			result = n
		}
	}

	return result
}

// Represents a file and contains only metadata.
type File struct {
	*Node
}

// Represents a folder and contains only metadata.
type Folder struct {
	*Node
}

// Gets the list of all children.
func (f *Folder) GetAllChildren(opts *NodeListOptions) ([]Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listAllNodes(url, opts)
}

// Gets a list of children, up until the limit (either default or the one set in opts).
func (f *Folder) GetChildren(opts *NodeListOptions) ([]Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listNodes(url, opts)
}

// Gets the subfolder by name. It is an error if not exactly one subfolder is found.
func (f *Folder) GetFolder(name string) (*Folder, *http.Response, error) {
	filter := "kind:FOLDER AND parents:" + *f.Id + " AND name:" + name
	opts := &NodeListOptions{Filters: filter}

	nodes, resp, err := f.service.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(nodes) < 1 {
		return nil, resp, errors.New(fmt.Sprintf("No folder '%s' found", name))
	}
	if len(nodes) > 1 {
		return nil, resp, errors.New(fmt.Sprintf("Too many folders '%s' found (%v)",
			name, len(nodes)))
	}

	return &Folder{&nodes[0]}, resp, nil
}

// Gets the file by name. It is an error if not exactly one file is found.
func (f *Folder) GetFile(name string) (*File, *http.Response, error) {
	filter := "kind:FILE AND parents:" + *f.Id + " AND name:" + name
	opts := &NodeListOptions{Filters: filter}

	nodes, resp, err := f.service.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(nodes) < 1 {
		return nil, resp, errors.New(fmt.Sprintf("No file '%s' found", name))
	}
	if len(nodes) > 1 {
		return nil, resp, errors.New(fmt.Sprintf("Too many files '%s' found (%v)",
			name, len(nodes)))
	}

	return &File{&nodes[0]}, resp, nil
}

// NodeListOptions holds the options when getting a list of nodes, such as the filter,
// sorting and pagination.
type NodeListOptions struct {
	Limit   uint   `url:"limit,omitempty"`
	Filters string `url:"filters,omitempty"`
	Sort    string `url:"sort,omitempty"`

	// Token where to start for next page (internal)
	StartToken string `url:"startToken,omitempty"`
	reachedEnd bool
}

// addOptions adds the parameters in opts as URL query parameters to s.  opts
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opts interface{}) (string, error) {
	v := reflect.ValueOf(opts)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opts)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}
<|endoftext|>


<commit_before>package redis

import (
	"strconv"
	"strings"
	"time"

	"github.com/elastic/libbeat/common"
	"github.com/elastic/libbeat/common/streambuf"
	"github.com/elastic/libbeat/logp"
)

type parser struct {
	parseOffset int
	// bytesReceived int
	message *redisMessage
}

type redisMessage struct {
	Ts time.Time

	TcpTuple     common.TcpTuple
	CmdlineTuple *common.CmdlineTuple
	Direction    uint8

	IsRequest bool
	IsError   bool
	Message   string
	Method    string
	Path      string
	Size      int

	next *redisMessage
}

const (
	START = iota
	BULK_ARRAY
	SIMPLE_MESSAGE
)

// Keep sorted for future command addition
var redisCommands = map[string]struct{}{
	"APPEND":           struct{}{},
	"AUTH":             struct{}{},
	"BGREWRITEAOF":     struct{}{},
	"BGSAVE":           struct{}{},
	"BITCOUNT":         struct{}{},
	"BITOP":            struct{}{},
	"BITPOS":           struct{}{},
	"BLPOP":            struct{}{},
	"BRPOP":            struct{}{},
	"BRPOPLPUSH":       struct{}{},
	"CLIENT GETNAME":   struct{}{},
	"CLIENT KILL":      struct{}{},
	"CLIENT LIST":      struct{}{},
	"CLIENT PAUSE":     struct{}{},
	"CLIENT SETNAME":   struct{}{},
	"CONFIG GET":       struct{}{},
	"CONFIG RESETSTAT": struct{}{},
	"CONFIG REWRITE":   struct{}{},
	"CONFIG SET":       struct{}{},
	"DBSIZE":           struct{}{},
	"DEBUG OBJECT":     struct{}{},
	"DEBUG SEGFAULT":   struct{}{},
	"DECR":             struct{}{},
	"DECRBY":           struct{}{},
	"DEL":              struct{}{},
	"DISCARD":          struct{}{},
	"DUMP":             struct{}{},
	"ECHO":             struct{}{},
	"EVAL":             struct{}{},
	"EVALSHA":          struct{}{},
	"EXEC":             struct{}{},
	"EXISTS":           struct{}{},
	"EXPIRE":           struct{}{},
	"EXPIREAT":         struct{}{},
	"FLUSHALL":         struct{}{},
	"FLUSHDB":          struct{}{},
	"GET":              struct{}{},
	"GETBIT":           struct{}{},
	"GETRANGE":         struct{}{},
	"GETSET":           struct{}{},
	"HDEL":             struct{}{},
	"HEXISTS":          struct{}{},
	"HGET":             struct{}{},
	"HGETALL":          struct{}{},
	"HINCRBY":          struct{}{},
	"HINCRBYFLOAT":     struct{}{},
	"HKEYS":            struct{}{},
	"HLEN":             struct{}{},
	"HMGET":            struct{}{},
	"HMSET":            struct{}{},
	"HSCAN":            struct{}{},
	"HSET":             struct{}{},
	"HSETINX":          struct{}{},
	"HVALS":            struct{}{},
	"INCR":             struct{}{},
	"INCRBY":           struct{}{},
	"INCRBYFLOAT":      struct{}{},
	"INFO":             struct{}{},
	"KEYS":             struct{}{},
	"LASTSAVE":         struct{}{},
	"LINDEX":           struct{}{},
	"LINSERT":          struct{}{},
	"LLEN":             struct{}{},
	"LPOP":             struct{}{},
	"LPUSH":            struct{}{},
	"LPUSHX":           struct{}{},
	"LRANGE":           struct{}{},
	"LREM":             struct{}{},
	"LSET":             struct{}{},
	"LTRIM":            struct{}{},
	"MGET":             struct{}{},
	"MIGRATE":          struct{}{},
	"MONITOR":          struct{}{},
	"MOVE":             struct{}{},
	"MSET":             struct{}{},
	"MSETNX":           struct{}{},
	"MULTI":            struct{}{},
	"OBJECT":           struct{}{},
	"PERSIST":          struct{}{},
	"PEXPIRE":          struct{}{},
	"PEXPIREAT":        struct{}{},
	"PFADD":            struct{}{},
	"PFCOUNT":          struct{}{},
	"PFMERGE":          struct{}{},
	"PING":             struct{}{},
	"PSETEX":           struct{}{},
	"PSUBSCRIBE":       struct{}{},
	"PTTL":             struct{}{},
	"PUBLISH":          struct{}{},
	"PUBSUB":           struct{}{},
	"PUNSUBSCRIBE":     struct{}{},
	"QUIT":             struct{}{},
	"RANDOMKEY":        struct{}{},
	"RENAME":           struct{}{},
	"RENAMENX":         struct{}{},
	"RESTORE":          struct{}{},
	"RPOP":             struct{}{},
	"RPOPLPUSH":        struct{}{},
	"RPUSH":            struct{}{},
	"RPUSHX":           struct{}{},
	"SADD":             struct{}{},
	"SAVE":             struct{}{},
	"SCAN":             struct{}{},
	"SCARD":            struct{}{},
	"SCRIPT EXISTS":    struct{}{},
	"SCRIPT FLUSH":     struct{}{},
	"SCRIPT KILL":      struct{}{},
	"SCRIPT LOAD":      struct{}{},
	"SDIFF":            struct{}{},
	"SDIFFSTORE":       struct{}{},
	"SELECT":           struct{}{},
	"SET":              struct{}{},
	"SETBIT":           struct{}{},
	"SETEX":            struct{}{},
	"SETNX":            struct{}{},
	"SETRANGE":         struct{}{},
	"SHUTDOWN":         struct{}{},
	"SINTER":           struct{}{},
	"SINTERSTORE":      struct{}{},
	"SISMEMBER":        struct{}{},
	"SLAVEOF":          struct{}{},
	"SLOWLOG":          struct{}{},
	"SMEMBERS":         struct{}{},
	"SMOVE":            struct{}{},
	"SORT":             struct{}{},
	"SPOP":             struct{}{},
	"SRANDMEMBER":      struct{}{},
	"SREM":             struct{}{},
	"SSCAN":            struct{}{},
	"STRLEN":           struct{}{},
	"SUBSCRIBE":        struct{}{},
	"SUNION":           struct{}{},
	"SUNIONSTORE":      struct{}{},
	"SYNC":             struct{}{},
	"TIME":             struct{}{},
	"TTL":              struct{}{},
	"TYPE":             struct{}{},
	"UNSUBSCRIBE":      struct{}{},
	"UNWATCH":          struct{}{},
	"WATCH":            struct{}{},
	"ZADD":             struct{}{},
	"ZCARD":            struct{}{},
	"ZCOUNT":           struct{}{},
	"ZINCRBY":          struct{}{},
	"ZINTERSTORE":      struct{}{},
	"ZRANGE":           struct{}{},
	"ZRANGEBYSCORE":    struct{}{},
	"ZRANK":            struct{}{},
	"ZREM":             struct{}{},
	"ZREMRANGEBYLEX":   struct{}{},
	"ZREMRANGEBYRANK":  struct{}{},
	"ZREMRANGEBYSCORE": struct{}{},
	"ZREVRANGE":        struct{}{},
	"ZREVRANGEBYSCORE": struct{}{},
	"ZREVRANK":         struct{}{},
	"ZSCAN":            struct{}{},
	"ZSCORE":           struct{}{},
	"ZUNIONSTORE":      struct{}{},
}

func isRedisCommand(key string) bool {
	_, exists := redisCommands[strings.ToUpper(key)]
	return exists
}

func (p *parser) reset() {
	p.parseOffset = 0
	p.message = nil
}

func (parser *parser) parse(buf *streambuf.Buffer) (bool, bool) {
	snapshot := buf.Snapshot()

	content, iserror, ok, complete := parser.dispatch(0, buf)
	if !ok || !complete {
		// on error or incomplete message drop all parsing progress, due to
		// parse not being statefull among multiple calls
		// => parser needs to restart parsing all content
		buf.Restore(snapshot)
		return ok, complete
	}

	parser.message.IsError = iserror
	parser.message.Size = buf.BufferConsumed()
	parser.message.Message = content
	return true, true
}

func (p *parser) dispatch(depth int, buf *streambuf.Buffer) (string, bool, bool, bool) {
	if buf.Len() == 0 {
		return "", false, true, false
	}

	var value string
	var iserror, ok, complete bool
	snapshot := buf.Snapshot()

	switch buf.Bytes()[0] {
	case '*':
		value, iserror, ok, complete = p.parseArray(depth, buf)
	case '$':
		value, ok, complete = p.parseString(buf)
	case ':':
		value, ok, complete = p.parseInt(buf)
	case '+':
		value, ok, complete = p.parseSimpleString(buf)
	case '-':
		iserror = true
		value, ok, complete = p.parseSimpleString(buf)
	default:
		debug("Unexpected message starting with %s", buf.Bytes()[0])
		return "", false, false, false
	}

	if !ok || !complete {
		buf.Restore(snapshot)
	}
	return value, iserror, ok, complete
}

func (p *parser) parseInt(buf *streambuf.Buffer) (string, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return "", true, false
	}

	number := string(line[1:])
	if _, err := strconv.ParseInt(number, 10, 64); err != nil {
		logp.Err("Failed to read integer reply: %s", err)
	}

	return number, true, true
}

func (p *parser) parseSimpleString(buf *streambuf.Buffer) (string, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return "", true, false
	}

	return string(line[1:]), true, true
}

func (p *parser) parseString(buf *streambuf.Buffer) (string, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return "", true, false
	}

	if len(line) == 3 && line[1] == '-' && line[2] == '1' {
		return "nil", true, true
	}

	length, err := strconv.ParseInt(string(line[1:]), 10, 64)
	if err != nil {
		logp.Err("Failed to read bulk message: %s", err)
		return "", false, false
	}

	content, err := buf.CollectWithSuffix(int(length), []byte("\r\n"))
	if err != nil {
		if err != streambuf.ErrNoMoreBytes {
			return "", false, false
		}
		return "", true, false
	}

	return string(content), true, true
}

func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (string, bool, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		debug("End of line not found, waiting for more data")
		return "", false, false, false
	}
	debug("line %s: %d", line, buf.BufferConsumed())

	if len(line) == 3 && line[1] == '-' && line[2] == '1' {
		return "nil", false, true, true
	}

	if len(line) == 2 && line[1] == '0' {
		return "[]", false, true, true
	}

	count, err := strconv.ParseInt(string(line[1:]), 10, 64)
	if err != nil {
		logp.Err("Failed to read number of bulk messages: %s", err)
		return "", false, false, false
	}
	if count < 0 {
		return "nil", false, true, true
	}

	content := make([]string, 0, count)
	// read sub elements

	iserror := false
	for i := 0; i < int(count); i++ {
		var value string
		var ok, complete bool

		value, iserror, ok, complete := p.dispatch(depth+1, buf)
		if !ok || !complete {
			debug("Array incomplete")
			return "", iserror, ok, complete
		}

		content = append(content, value)
	}

	if depth == 0 && isRedisCommand(content[0]) { // we've got a request
		p.message.IsRequest = true
		p.message.Method = content[0]
	}

	var value string
	if depth == 0 && p.message.IsRequest {
		value = strings.Join(content, " ")
	} else {
		value = "[" + strings.Join(content, ", ") + "]"
	}
	return value, iserror, true, true
}
<commit_msg>Set redis request path<commit_after>package redis

import (
	"strconv"
	"strings"
	"time"

	"github.com/elastic/libbeat/common"
	"github.com/elastic/libbeat/common/streambuf"
	"github.com/elastic/libbeat/logp"
)

type parser struct {
	parseOffset int
	// bytesReceived int
	message *redisMessage
}

type redisMessage struct {
	Ts time.Time

	TcpTuple     common.TcpTuple
	CmdlineTuple *common.CmdlineTuple
	Direction    uint8

	IsRequest bool
	IsError   bool
	Message   string
	Method    string
	Path      string
	Size      int

	next *redisMessage
}

const (
	START = iota
	BULK_ARRAY
	SIMPLE_MESSAGE
)

// Keep sorted for future command addition
var redisCommands = map[string]struct{}{
	"APPEND":           struct{}{},
	"AUTH":             struct{}{},
	"BGREWRITEAOF":     struct{}{},
	"BGSAVE":           struct{}{},
	"BITCOUNT":         struct{}{},
	"BITOP":            struct{}{},
	"BITPOS":           struct{}{},
	"BLPOP":            struct{}{},
	"BRPOP":            struct{}{},
	"BRPOPLPUSH":       struct{}{},
	"CLIENT GETNAME":   struct{}{},
	"CLIENT KILL":      struct{}{},
	"CLIENT LIST":      struct{}{},
	"CLIENT PAUSE":     struct{}{},
	"CLIENT SETNAME":   struct{}{},
	"CONFIG GET":       struct{}{},
	"CONFIG RESETSTAT": struct{}{},
	"CONFIG REWRITE":   struct{}{},
	"CONFIG SET":       struct{}{},
	"DBSIZE":           struct{}{},
	"DEBUG OBJECT":     struct{}{},
	"DEBUG SEGFAULT":   struct{}{},
	"DECR":             struct{}{},
	"DECRBY":           struct{}{},
	"DEL":              struct{}{},
	"DISCARD":          struct{}{},
	"DUMP":             struct{}{},
	"ECHO":             struct{}{},
	"EVAL":             struct{}{},
	"EVALSHA":          struct{}{},
	"EXEC":             struct{}{},
	"EXISTS":           struct{}{},
	"EXPIRE":           struct{}{},
	"EXPIREAT":         struct{}{},
	"FLUSHALL":         struct{}{},
	"FLUSHDB":          struct{}{},
	"GET":              struct{}{},
	"GETBIT":           struct{}{},
	"GETRANGE":         struct{}{},
	"GETSET":           struct{}{},
	"HDEL":             struct{}{},
	"HEXISTS":          struct{}{},
	"HGET":             struct{}{},
	"HGETALL":          struct{}{},
	"HINCRBY":          struct{}{},
	"HINCRBYFLOAT":     struct{}{},
	"HKEYS":            struct{}{},
	"HLEN":             struct{}{},
	"HMGET":            struct{}{},
	"HMSET":            struct{}{},
	"HSCAN":            struct{}{},
	"HSET":             struct{}{},
	"HSETINX":          struct{}{},
	"HVALS":            struct{}{},
	"INCR":             struct{}{},
	"INCRBY":           struct{}{},
	"INCRBYFLOAT":      struct{}{},
	"INFO":             struct{}{},
	"KEYS":             struct{}{},
	"LASTSAVE":         struct{}{},
	"LINDEX":           struct{}{},
	"LINSERT":          struct{}{},
	"LLEN":             struct{}{},
	"LPOP":             struct{}{},
	"LPUSH":            struct{}{},
	"LPUSHX":           struct{}{},
	"LRANGE":           struct{}{},
	"LREM":             struct{}{},
	"LSET":             struct{}{},
	"LTRIM":            struct{}{},
	"MGET":             struct{}{},
	"MIGRATE":          struct{}{},
	"MONITOR":          struct{}{},
	"MOVE":             struct{}{},
	"MSET":             struct{}{},
	"MSETNX":           struct{}{},
	"MULTI":            struct{}{},
	"OBJECT":           struct{}{},
	"PERSIST":          struct{}{},
	"PEXPIRE":          struct{}{},
	"PEXPIREAT":        struct{}{},
	"PFADD":            struct{}{},
	"PFCOUNT":          struct{}{},
	"PFMERGE":          struct{}{},
	"PING":             struct{}{},
	"PSETEX":           struct{}{},
	"PSUBSCRIBE":       struct{}{},
	"PTTL":             struct{}{},
	"PUBLISH":          struct{}{},
	"PUBSUB":           struct{}{},
	"PUNSUBSCRIBE":     struct{}{},
	"QUIT":             struct{}{},
	"RANDOMKEY":        struct{}{},
	"RENAME":           struct{}{},
	"RENAMENX":         struct{}{},
	"RESTORE":          struct{}{},
	"RPOP":             struct{}{},
	"RPOPLPUSH":        struct{}{},
	"RPUSH":            struct{}{},
	"RPUSHX":           struct{}{},
	"SADD":             struct{}{},
	"SAVE":             struct{}{},
	"SCAN":             struct{}{},
	"SCARD":            struct{}{},
	"SCRIPT EXISTS":    struct{}{},
	"SCRIPT FLUSH":     struct{}{},
	"SCRIPT KILL":      struct{}{},
	"SCRIPT LOAD":      struct{}{},
	"SDIFF":            struct{}{},
	"SDIFFSTORE":       struct{}{},
	"SELECT":           struct{}{},
	"SET":              struct{}{},
	"SETBIT":           struct{}{},
	"SETEX":            struct{}{},
	"SETNX":            struct{}{},
	"SETRANGE":         struct{}{},
	"SHUTDOWN":         struct{}{},
	"SINTER":           struct{}{},
	"SINTERSTORE":      struct{}{},
	"SISMEMBER":        struct{}{},
	"SLAVEOF":          struct{}{},
	"SLOWLOG":          struct{}{},
	"SMEMBERS":         struct{}{},
	"SMOVE":            struct{}{},
	"SORT":             struct{}{},
	"SPOP":             struct{}{},
	"SRANDMEMBER":      struct{}{},
	"SREM":             struct{}{},
	"SSCAN":            struct{}{},
	"STRLEN":           struct{}{},
	"SUBSCRIBE":        struct{}{},
	"SUNION":           struct{}{},
	"SUNIONSTORE":      struct{}{},
	"SYNC":             struct{}{},
	"TIME":             struct{}{},
	"TTL":              struct{}{},
	"TYPE":             struct{}{},
	"UNSUBSCRIBE":      struct{}{},
	"UNWATCH":          struct{}{},
	"WATCH":            struct{}{},
	"ZADD":             struct{}{},
	"ZCARD":            struct{}{},
	"ZCOUNT":           struct{}{},
	"ZINCRBY":          struct{}{},
	"ZINTERSTORE":      struct{}{},
	"ZRANGE":           struct{}{},
	"ZRANGEBYSCORE":    struct{}{},
	"ZRANK":            struct{}{},
	"ZREM":             struct{}{},
	"ZREMRANGEBYLEX":   struct{}{},
	"ZREMRANGEBYRANK":  struct{}{},
	"ZREMRANGEBYSCORE": struct{}{},
	"ZREVRANGE":        struct{}{},
	"ZREVRANGEBYSCORE": struct{}{},
	"ZREVRANK":         struct{}{},
	"ZSCAN":            struct{}{},
	"ZSCORE":           struct{}{},
	"ZUNIONSTORE":      struct{}{},
}

func isRedisCommand(key string) bool {
	_, exists := redisCommands[strings.ToUpper(key)]
	return exists
}

func (p *parser) reset() {
	p.parseOffset = 0
	p.message = nil
}

func (parser *parser) parse(buf *streambuf.Buffer) (bool, bool) {
	snapshot := buf.Snapshot()

	content, iserror, ok, complete := parser.dispatch(0, buf)
	if !ok || !complete {
		// on error or incomplete message drop all parsing progress, due to
		// parse not being statefull among multiple calls
		// => parser needs to restart parsing all content
		buf.Restore(snapshot)
		return ok, complete
	}

	parser.message.IsError = iserror
	parser.message.Size = buf.BufferConsumed()
	parser.message.Message = content
	return true, true
}

func (p *parser) dispatch(depth int, buf *streambuf.Buffer) (string, bool, bool, bool) {
	if buf.Len() == 0 {
		return "", false, true, false
	}

	var value string
	var iserror, ok, complete bool
	snapshot := buf.Snapshot()

	switch buf.Bytes()[0] {
	case '*':
		value, iserror, ok, complete = p.parseArray(depth, buf)
	case '$':
		value, ok, complete = p.parseString(buf)
	case ':':
		value, ok, complete = p.parseInt(buf)
	case '+':
		value, ok, complete = p.parseSimpleString(buf)
	case '-':
		iserror = true
		value, ok, complete = p.parseSimpleString(buf)
	default:
		debug("Unexpected message starting with %s", buf.Bytes()[0])
		return "", false, false, false
	}

	if !ok || !complete {
		buf.Restore(snapshot)
	}
	return value, iserror, ok, complete
}

func (p *parser) parseInt(buf *streambuf.Buffer) (string, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return "", true, false
	}

	number := string(line[1:])
	if _, err := strconv.ParseInt(number, 10, 64); err != nil {
		logp.Err("Failed to read integer reply: %s", err)
	}

	return number, true, true
}

func (p *parser) parseSimpleString(buf *streambuf.Buffer) (string, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return "", true, false
	}

	return string(line[1:]), true, true
}

func (p *parser) parseString(buf *streambuf.Buffer) (string, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return "", true, false
	}

	if len(line) == 3 && line[1] == '-' && line[2] == '1' {
		return "nil", true, true
	}

	length, err := strconv.ParseInt(string(line[1:]), 10, 64)
	if err != nil {
		logp.Err("Failed to read bulk message: %s", err)
		return "", false, false
	}

	content, err := buf.CollectWithSuffix(int(length), []byte("\r\n"))
	if err != nil {
		if err != streambuf.ErrNoMoreBytes {
			return "", false, false
		}
		return "", true, false
	}

	return string(content), true, true
}

func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (string, bool, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		debug("End of line not found, waiting for more data")
		return "", false, false, false
	}
	debug("line %s: %d", line, buf.BufferConsumed())

	if len(line) == 3 && line[1] == '-' && line[2] == '1' {
		return "nil", false, true, true
	}

	if len(line) == 2 && line[1] == '0' {
		return "[]", false, true, true
	}

	count, err := strconv.ParseInt(string(line[1:]), 10, 64)
	if err != nil {
		logp.Err("Failed to read number of bulk messages: %s", err)
		return "", false, false, false
	}
	if count < 0 {
		return "nil", false, true, true
	}

	content := make([]string, 0, count)
	// read sub elements

	iserror := false
	for i := 0; i < int(count); i++ {
		var value string
		var ok, complete bool

		value, iserror, ok, complete := p.dispatch(depth+1, buf)
		if !ok || !complete {
			debug("Array incomplete")
			return "", iserror, ok, complete
		}

		content = append(content, value)
	}

	if depth == 0 && isRedisCommand(content[0]) { // we've got a request
		p.message.IsRequest = true
		p.message.Method = content[0]
		p.message.Path = content[1]
	}

	var value string
	if depth == 0 && p.message.IsRequest {
		value = strings.Join(content, " ")
	} else {
		value = "[" + strings.Join(content, ", ") + "]"
	}
	return value, iserror, true, true
}
<|endoftext|>


<commit_before>package one

import (
	"fmt"
	"github.com/megamsys/libgo/action"
	constants "github.com/megamsys/libgo/utils"
	lb "github.com/megamsys/vertice/logbox"
	"github.com/megamsys/vertice/provision/one/machine"
	"io/ioutil"
)

var createImage = action.Action{
	Name: "create-rawimage-iso",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CreateImage(args.provisioner)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusCreating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		err := mach.RemoveImage(args.provisioner)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DESTORYING, lb.ERROR, fmt.Sprintf("  removing err image %s", err.Error())))
		}
	},
}

var removeImage = action.Action{
	Name: "remove-rawimage-iso",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.RemoveImage(args.provisioner)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusCreating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateImage = action.Action{
	Name: "update-rawimage-id",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateImage()
		if err != nil {
			return mach, err
		}
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateImageStatus = action.Action{
	Name: "update-rawimage-status",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateImageStatus()
		if err != nil {
			return mach, err
		}
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var createDatablockImage = action.Action{
	Name: "create-datablock",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CreateDatablock(args.provisioner, args.box)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusDataBlockCreating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		err := mach.RemoveDatablock(args.provisioner)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DESTORYING, lb.ERROR, fmt.Sprintf("  removing err datablock %s", err.Error())))
		}
	},
}

var updateMarketplaceImageId = action.Action{
	Name: "update-marketplace-block-id",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateMarketImageId()
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusDataBlockCreated
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var createInstanceForCustomize = action.Action{
	Name: "create-instance-to-customize",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CreateInstance(args.provisioner, args.box)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusLaunching
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		fmt.Fprintf(args.writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  removing instance %s", ctx.CauseOf.Error())))
		err := mach.Remove(args.provisioner)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  removing err instance %s", err.Error())))
		}
	},
}

var attachDatablockImage = action.Action{
	Name: "attach-datablock-image-to-vm",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.AttachDatablock(args.provisioner, args.box)
		if err != nil {
			return mach, err
		}
		mach.Status = mach.Status
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateMarketplaceStatus = action.Action{
	Name: "update-marketplaces-status",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateMarketplaceStatus()
		if err != nil {
			return mach, err
		}
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		mach.Status = constants.StatusPreError
		err := mach.UpdateMarketplaceError(ctx.CauseOf)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  failure update marketplace status  %s", err.Error())))
		}
	},
}

var waitUntillVmReady = action.Action{
	Name: "update-for-vm-running",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.MarketplaceInstanceState(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusLaunched
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var getMarketplaceVncPost = action.Action{
	Name: "get-vnc-host-ip-port",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.GetMarketplaceVNC(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusVncHostUpdating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateMarketplaceVnc = action.Action{
	Name: "update-vnc-host-ip-port",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateMarketplaceVNC()
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusVncHostUpdated
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var stopMachineIfRunning = action.Action{
	Name: "update-vnc-host-ip-port",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.StopMarkplaceInstance(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error stop machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageSaving
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var waitForsaveImage = action.Action{
	Name: "wait-for-save-image",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CheckSaveImage(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageSaved
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var makeImageAsPersistent = action.Action{
	Name: "make-image-as-persistent",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.ImagePersistent(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageReady
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var removeInstance = action.Action{
	Name: "remove-instance-vm",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.RemoveInstance(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageReady
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}
<commit_msg>go vet<commit_after>package one

import (
	"fmt"
	"github.com/megamsys/libgo/action"
	constants "github.com/megamsys/libgo/utils"
	lb "github.com/megamsys/vertice/logbox"
	"github.com/megamsys/vertice/provision/one/machine"
	"io/ioutil"
)

var createImage = action.Action{
	Name: "create-rawimage-iso",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CreateImage(args.provisioner)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusCreating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		err := mach.RemoveImage(args.provisioner)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DESTORYING, lb.ERROR, fmt.Sprintf("  removing err image %s", err.Error())))
		}
	},
}

var removeImage = action.Action{
	Name: "remove-rawimage-iso",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.RemoveImage(args.provisioner)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusCreating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateImage = action.Action{
	Name: "update-rawimage-id",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateImage()
		if err != nil {
			return mach, err
		}
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateImageStatus = action.Action{
	Name: "update-rawimage-status",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateImageStatus()
		if err != nil {
			return mach, err
		}
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var createDatablockImage = action.Action{
	Name: "create-datablock",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CreateDatablock(args.provisioner, args.box)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusDataBlockCreating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		err := mach.RemoveDatablock(args.provisioner)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DESTORYING, lb.ERROR, fmt.Sprintf("  removing err datablock %s", err.Error())))
		}
	},
}

var updateMarketplaceImageId = action.Action{
	Name: "update-marketplace-block-id",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateMarketImageId()
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusDataBlockCreated
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var createInstanceForCustomize = action.Action{
	Name: "create-instance-to-customize",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CreateInstance(args.provisioner, args.box)
		if err != nil {
			return mach, err
		}
		mach.Status = constants.StatusLaunching
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		fmt.Fprintf(args.writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  removing instance %s", ctx.CauseOf.Error())))
		err := mach.Remove(args.provisioner)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  removing err instance %s", err.Error())))
		}
	},
}

var attachDatablockImage = action.Action{
	Name: "attach-datablock-image-to-vm",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.AttachDatablock(args.provisioner, args.box)
		if err != nil {
			return mach, err
		}
		mach.Status = mach.StatusDataBlockCreated
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateMarketplaceStatus = action.Action{
	Name: "update-marketplaces-status",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateMarketplaceStatus()
		if err != nil {
			return mach, err
		}
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
		mach := ctx.FWResult.(machine.Machine)
		args := ctx.Params[0].(runMachineActionsArgs)
		mach.Status = constants.StatusPreError
		err := mach.UpdateMarketplaceError(ctx.CauseOf)
		if err != nil {
			fmt.Fprintf(args.writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  failure update marketplace status  %s", err.Error())))
		}
	},
}

var waitUntillVmReady = action.Action{
	Name: "update-for-vm-running",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.MarketplaceInstanceState(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusLaunched
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var getMarketplaceVncPost = action.Action{
	Name: "get-vnc-host-ip-port",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.GetMarketplaceVNC(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusVncHostUpdating
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var updateMarketplaceVnc = action.Action{
	Name: "update-vnc-host-ip-port",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.UpdateMarketplaceVNC()
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusVncHostUpdated
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var stopMachineIfRunning = action.Action{
	Name: "update-vnc-host-ip-port",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.StopMarkplaceInstance(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error stop machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageSaving
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var waitForsaveImage = action.Action{
	Name: "wait-for-save-image",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.CheckSaveImage(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageSaved
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var makeImageAsPersistent = action.Action{
	Name: "make-image-as-persistent",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.ImagePersistent(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageReady
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var removeInstance = action.Action{
	Name: "remove-instance-vm",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		args := ctx.Params[0].(runMachineActionsArgs)
		mach := ctx.Previous.(machine.Machine)
		writer := args.writer
		if writer == nil {
			writer = ioutil.Discard
		}
		err := mach.RemoveInstance(args.provisioner)
		if err != nil {
			fmt.Fprintf(writer, lb.W(lb.DEPLOY, lb.ERROR, fmt.Sprintf("  error start machine ( %s)", args.box.GetFullName())))
			return nil, err
		}
		mach.Status = constants.StatusImageReady
		return mach, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}
<|endoftext|>