<commit_before>/*
Package system runs system-level testing of rqlite. This includes testing of single nodes, and multi-node clusters.
*/
package system

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func Test_SingleNode(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     string
		expected string
		execute  bool
	}{
		{
			stmt:     `CREATE TABLE foo (id integer not null primary key, name text)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO foo(name) VALUES("fiona")`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO bar(name) VALUES("fiona")`,
			expected: `{"results":[{"error":"no such table: bar"}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT blah blah`,
			expected: `{"results":[{"error":"near \"blah\": syntax error"}]}`,
			execute:  true,
		},
		{
			stmt:     `SELECT * FROM foo`,
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"],"values":[[1,"fiona"]]}]}`,
			execute:  false,
		},
		{
			stmt:     `DROP TABLE bar`,
			expected: `{"results":[{"error":"no such table: bar"}]}`,
			execute:  true,
		},
		{
			stmt:     `DROP TABLE foo`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.Execute(tt.stmt)
		} else {
			r, err = node.Query(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

func Test_SingleNodeMulti(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     string
		expected string
		execute  bool
	}{
		{
			stmt:     `CREATE TABLE foo (id integer not null primary key, name text)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `CREATE TABLE bar (id integer not null primary key, sequence integer)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO foo(name) VALUES("fiona")`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO foo(name) VALUES("declan")`,
			expected: `{"results":[{"last_insert_id":2,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO bar(sequence) VALUES(5)`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.Execute(tt.stmt)
		} else {
			r, err = node.Query(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}

	r, err := node.QueryMulti([]string{"SELECT * FROM foo", "SELECT * FROM bar"})
	if err != nil {
		t.Fatalf("failed to run multiple queries: %s", err.Error())
	}
	if r != `{"results":[{"columns":["id","name"],"types":["integer","text"],"values":[[1,"fiona"],[2,"declan"]]},{"columns":["id","sequence"],"types":["integer","integer"],"values":[[1,5]]}]}` {
		t.Fatalf("test received wrong result got %s", r)
	}
}

func Test_SingleParameterizedNode(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     []interface{}
		expected string
		execute  bool
	}{
		{
			stmt:     []interface{}{"CREATE TABLE foo (id integer not null primary key, name text, age integer)"},
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     []interface{}{"INSERT INTO foo(name, age) VALUES(?, ?)", "fiona", 20},
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     []interface{}{"SELECT * FROM foo WHERE NAME=?", "fiona"},
			expected: `{"results":[{"columns":["id","name","age"],"types":["integer","text","integer"],"values":[[1,"fiona",20]]}]}`,
			execute:  false,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.ExecuteParameterized(tt.stmt)
		} else {
			r, err = node.QueryParameterized(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

// Test_SingleNodeSQLInjection demonstrates that using the non-parameterized API is vulnerable to
// SQL injection attacks.
func Test_SingleNodeSQLInjection(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     string
		expected string
		execute  bool
	}{
		{
			stmt:     `CREATE TABLE foo (id integer not null primary key, name text)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `SELECT * FROM foo WHERE name="baz"`,
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
		{
			stmt:     fmt.Sprintf(`SELECT * FROM foo WHERE name=%s`, `"baz";DROP TABLE FOO`),
			expected: `{"results":[{}]}`,
			execute:  false,
		},
		{
			stmt:     `SELECT * FROM foo`,
			expected: `{"results":[{"error":"no such table: foo"}]}`,
			execute:  false,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.Execute(tt.stmt)
		} else {
			r, err = node.Query(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

// Test_SingleNodeNoSQLInjection demonstrates that using the parameterized API protects
// against SQL injection attacks.
func Test_SingleNodeNoSQLInjection(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     []interface{}
		expected string
		execute  bool
	}{
		{
			stmt:     []interface{}{"CREATE TABLE foo (id integer not null primary key, name text)"},
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     []interface{}{`SELECT * FROM foo WHERE name="baz"`},
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
		{
			stmt:     []interface{}{`SELECT * FROM foo WHERE name=?`, `"baz";DROP TABLE FOO`},
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
		{
			stmt:     []interface{}{`SELECT * FROM foo`},
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.ExecuteParameterized(tt.stmt)
		} else {
			r, err = node.QueryParameterized(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

func Test_SingleNodeRestart(t *testing.T) {
	// Deprovision of a node deletes the node's dir, so make a copy first.
	srcdir := filepath.Join("testdata", "v5.6.0-data")
	destdir := mustTempDir()
	if err := os.Remove(destdir); err != nil {
		t.Fatalf("failed to remove dest dir: %s", err)
	}
	if err := copyDir(srcdir, destdir); err != nil {
		t.Fatalf("failed to copy node test directory: %s", err)
	}

	node := mustNodeEncrypted(destdir, true, false, false, "node1")
	defer node.Deprovision()
	if _, err := node.WaitForLeader(); err != nil {
		t.Fatal("node never became leader")
	}

	// Let's wait a few seconds to be sure logs are applied.
	n := 0
	for {
		time.Sleep(1 * time.Second)

		r, err := node.QueryNoneConsistency(`SELECT * FROM foo`)
		if err != nil {
			t.Fatalf("query failed: %s", err)
		}

		expected := `{"results":[{"columns":["id","name","age"],"types":["integer","text","integer"],"values":[[1,"fiona",20]]}]}`
		if r != expected && n == 10 {
			t.Fatalf(`query received wrong result, got: %s exp: %s`, r, expected)
		} else {
			break // Test successful!
		}

		n++
	}
}

func Test_SingleNodeCoverage(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	// Access endpoints to ensure the code is covered.
	var err error
	var str string

	str, err = node.Status()
	if err != nil {
		t.Fatalf("failed to access status endpoint: %s", err.Error())
	}
	if !isJSON(str) {
		t.Fatalf("output from status endpoint is not valid JSON: %s", str)
	}

	str, err = node.Expvar()
	if err != nil {
		t.Fatalf("failed to access expvar endpoint: %s", err.Error())
	}
	if !isJSON(str) {
		t.Fatalf("output from expvar endpoint is not valid JSON: %s", str)
	}
}
<commit_msg>Fix restart test logic<commit_after>/*
Package system runs system-level testing of rqlite. This includes testing of single nodes, and multi-node clusters.
*/
package system

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func Test_SingleNode(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     string
		expected string
		execute  bool
	}{
		{
			stmt:     `CREATE TABLE foo (id integer not null primary key, name text)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO foo(name) VALUES("fiona")`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO bar(name) VALUES("fiona")`,
			expected: `{"results":[{"error":"no such table: bar"}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT blah blah`,
			expected: `{"results":[{"error":"near \"blah\": syntax error"}]}`,
			execute:  true,
		},
		{
			stmt:     `SELECT * FROM foo`,
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"],"values":[[1,"fiona"]]}]}`,
			execute:  false,
		},
		{
			stmt:     `DROP TABLE bar`,
			expected: `{"results":[{"error":"no such table: bar"}]}`,
			execute:  true,
		},
		{
			stmt:     `DROP TABLE foo`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.Execute(tt.stmt)
		} else {
			r, err = node.Query(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

func Test_SingleNodeMulti(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     string
		expected string
		execute  bool
	}{
		{
			stmt:     `CREATE TABLE foo (id integer not null primary key, name text)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `CREATE TABLE bar (id integer not null primary key, sequence integer)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO foo(name) VALUES("fiona")`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO foo(name) VALUES("declan")`,
			expected: `{"results":[{"last_insert_id":2,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     `INSERT INTO bar(sequence) VALUES(5)`,
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.Execute(tt.stmt)
		} else {
			r, err = node.Query(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}

	r, err := node.QueryMulti([]string{"SELECT * FROM foo", "SELECT * FROM bar"})
	if err != nil {
		t.Fatalf("failed to run multiple queries: %s", err.Error())
	}
	if r != `{"results":[{"columns":["id","name"],"types":["integer","text"],"values":[[1,"fiona"],[2,"declan"]]},{"columns":["id","sequence"],"types":["integer","integer"],"values":[[1,5]]}]}` {
		t.Fatalf("test received wrong result got %s", r)
	}
}

func Test_SingleParameterizedNode(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     []interface{}
		expected string
		execute  bool
	}{
		{
			stmt:     []interface{}{"CREATE TABLE foo (id integer not null primary key, name text, age integer)"},
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     []interface{}{"INSERT INTO foo(name, age) VALUES(?, ?)", "fiona", 20},
			expected: `{"results":[{"last_insert_id":1,"rows_affected":1}]}`,
			execute:  true,
		},
		{
			stmt:     []interface{}{"SELECT * FROM foo WHERE NAME=?", "fiona"},
			expected: `{"results":[{"columns":["id","name","age"],"types":["integer","text","integer"],"values":[[1,"fiona",20]]}]}`,
			execute:  false,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.ExecuteParameterized(tt.stmt)
		} else {
			r, err = node.QueryParameterized(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

// Test_SingleNodeSQLInjection demonstrates that using the non-parameterized API is vulnerable to
// SQL injection attacks.
func Test_SingleNodeSQLInjection(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     string
		expected string
		execute  bool
	}{
		{
			stmt:     `CREATE TABLE foo (id integer not null primary key, name text)`,
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     `SELECT * FROM foo WHERE name="baz"`,
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
		{
			stmt:     fmt.Sprintf(`SELECT * FROM foo WHERE name=%s`, `"baz";DROP TABLE FOO`),
			expected: `{"results":[{}]}`,
			execute:  false,
		},
		{
			stmt:     `SELECT * FROM foo`,
			expected: `{"results":[{"error":"no such table: foo"}]}`,
			execute:  false,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.Execute(tt.stmt)
		} else {
			r, err = node.Query(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

// Test_SingleNodeNoSQLInjection demonstrates that using the parameterized API protects
// against SQL injection attacks.
func Test_SingleNodeNoSQLInjection(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	tests := []struct {
		stmt     []interface{}
		expected string
		execute  bool
	}{
		{
			stmt:     []interface{}{"CREATE TABLE foo (id integer not null primary key, name text)"},
			expected: `{"results":[{}]}`,
			execute:  true,
		},
		{
			stmt:     []interface{}{`SELECT * FROM foo WHERE name="baz"`},
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
		{
			stmt:     []interface{}{`SELECT * FROM foo WHERE name=?`, `"baz";DROP TABLE FOO`},
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
		{
			stmt:     []interface{}{`SELECT * FROM foo`},
			expected: `{"results":[{"columns":["id","name"],"types":["integer","text"]}]}`,
			execute:  false,
		},
	}

	for i, tt := range tests {
		var r string
		var err error
		if tt.execute {
			r, err = node.ExecuteParameterized(tt.stmt)
		} else {
			r, err = node.QueryParameterized(tt.stmt)
		}
		if err != nil {
			t.Fatalf(`test %d failed "%s": %s`, i, tt.stmt, err.Error())
		}
		if r != tt.expected {
			t.Fatalf(`test %d received wrong result "%s" got: %s exp: %s`, i, tt.stmt, r, tt.expected)
		}
	}
}

func Test_SingleNodeRestart(t *testing.T) {
	// Deprovision of a node deletes the node's dir, so make a copy first.
	srcdir := filepath.Join("testdata", "v5.6.0-data")
	destdir := mustTempDir()
	if err := os.Remove(destdir); err != nil {
		t.Fatalf("failed to remove dest dir: %s", err)
	}
	if err := copyDir(srcdir, destdir); err != nil {
		t.Fatalf("failed to copy node test directory: %s", err)
	}

	node := mustNodeEncrypted(destdir, true, false, false, "node1")
	defer node.Deprovision()
	if _, err := node.WaitForLeader(); err != nil {
		t.Fatal("node never became leader")
	}

	// Let's wait a few seconds to be sure logs are applied.
	n := 0
	for {
		time.Sleep(1 * time.Second)

		r, err := node.QueryNoneConsistency(`SELECT * FROM foo`)
		if err != nil {
			t.Fatalf("query failed: %s", err)
		}

		expected := `{"results":[{"columns":["id","name","age"],"types":["integer","text","integer"],"values":[[1,"fiona",20]]}]}`
		if r != expected {
			if n == 10 {
				t.Fatalf(`query received wrong result, got: %s exp: %s`, r, expected)
			}
		} else {
			break // Test successful!
		}

		n++
	}
}

func Test_SingleNodeCoverage(t *testing.T) {
	node := mustNewLeaderNode()
	defer node.Deprovision()

	// Access endpoints to ensure the code is covered.
	var err error
	var str string

	str, err = node.Status()
	if err != nil {
		t.Fatalf("failed to access status endpoint: %s", err.Error())
	}
	if !isJSON(str) {
		t.Fatalf("output from status endpoint is not valid JSON: %s", str)
	}

	str, err = node.Expvar()
	if err != nil {
		t.Fatalf("failed to access expvar endpoint: %s", err.Error())
	}
	if !isJSON(str) {
		t.Fatalf("output from expvar endpoint is not valid JSON: %s", str)
	}
}
<|endoftext|>


<commit_before>package gapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
)

type Folder struct {
	Id    int64  `json:"id"`
	Uid   string `json:"uid"`
	Title string `json:"title"`
}

func (c *Client) Folders() ([]Folder, error) {
	folders := make([]Folder, 0)

	req, err := c.newRequest("GET", "/api/folders/", nil, nil)
	if err != nil {
		return folders, err
	}
	resp, err := c.Do(req)
	if err != nil {
		return folders, err
	}
	if resp.StatusCode != 200 {
		return folders, errors.New(resp.Status)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return folders, err
	}
	err = json.Unmarshal(data, &folders)
	return folders, err
}

func (c *Client) Folder(id int64) (Folder, error) {
	folder := Folder{}
	req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/%d", id), nil, nil)
	if err != nil {
		return folder, err
	}
	resp, err := c.Do(req)
	if err != nil {
		return folder, err
	}
	if resp.StatusCode != 200 {
		return folder, errors.New(resp.Status)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return folder, err
	}
	err = json.Unmarshal(data, &folder)
	return folder, err
}

func (c *Client) NewFolder(title string) (Folder, error) {
	folder := Folder{}
	dataMap := map[string]string{
		"title": title,
	}
	data, err := json.Marshal(dataMap)
	req, err := c.newRequest("POST", "/api/folders", nil, bytes.NewBuffer(data))
	if err != nil {
		return folder, err
	}
	resp, err := c.Do(req)
	if err != nil {
		return folder, err
	}
	if resp.StatusCode != 200 {
		return folder, errors.New(resp.Status)
	}
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return folder, err
	}
	err = json.Unmarshal(data, &folder)
	if err != nil {
		return folder, err
	}
	return folder, err
}

func (c *Client) UpdateFolder(id string, name string) error {
	dataMap := map[string]string{
		"name": name,
	}
	data, err := json.Marshal(dataMap)
	req, err := c.newRequest("PUT", fmt.Sprintf("/api/folders/%s", id), nil, bytes.NewBuffer(data))
	if err != nil {
		return err
	}
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	return err
}

func (c *Client) DeleteFolder(id string) error {
	req, err := c.newRequest("DELETE", fmt.Sprintf("/api/folders/%s", id), nil, nil)
	if err != nil {
		return err
	}
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	return err
}
<commit_msg>use folder id api endpoint for finding folder by id<commit_after>package gapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
)

type Folder struct {
	Id    int64  `json:"id"`
	Uid   string `json:"uid"`
	Title string `json:"title"`
}

func (c *Client) Folders() ([]Folder, error) {
	folders := make([]Folder, 0)

	req, err := c.newRequest("GET", "/api/folders/", nil, nil)
	if err != nil {
		return folders, err
	}
	resp, err := c.Do(req)
	if err != nil {
		return folders, err
	}
	if resp.StatusCode != 200 {
		return folders, errors.New(resp.Status)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return folders, err
	}
	err = json.Unmarshal(data, &folders)
	return folders, err
}

func (c *Client) Folder(id int64) (*Folder, error) {
	folder := &Folder{}
	req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/id/%d", id), nil, nil)
	if err != nil {
		return folder, err
	}
	resp, err := c.Do(req)
	if err != nil {
		return folder, err
	}
	if resp.StatusCode != 200 {
		return folder, errors.New(resp.Status)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return folder, err
	}
	err = json.Unmarshal(data, &folder)
	return folder, err
}

func (c *Client) NewFolder(title string) (Folder, error) {
	folder := Folder{}
	dataMap := map[string]string{
		"title": title,
	}
	data, err := json.Marshal(dataMap)
	req, err := c.newRequest("POST", "/api/folders", nil, bytes.NewBuffer(data))
	if err != nil {
		return folder, err
	}
	resp, err := c.Do(req)
	if err != nil {
		return folder, err
	}
	if resp.StatusCode != 200 {
		data, _ = ioutil.ReadAll(resp.Body)
		return folder, fmt.Errorf("status: %s body: %s", resp.Status, data)
	}
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return folder, err
	}
	err = json.Unmarshal(data, &folder)
	if err != nil {
		return folder, err
	}
	return folder, err
}

func (c *Client) UpdateFolder(id string, name string) error {
	dataMap := map[string]string{
		"name": name,
	}
	data, err := json.Marshal(dataMap)
	req, err := c.newRequest("PUT", fmt.Sprintf("/api/folders/%s", id), nil, bytes.NewBuffer(data))
	if err != nil {
		return err
	}
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	return err
}

func (c *Client) DeleteFolder(id string) error {
	req, err := c.newRequest("DELETE", fmt.Sprintf("/api/folders/%s", id), nil, nil)
	if err != nil {
		return err
	}
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(resp.Status)
	}
	return err
}
<|endoftext|>


<commit_before>package diagnose

import (
	"context"
	"fmt"
	"io"
	"time"

	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"
)

const (
	warningEventName        = "warning"
	skippedEventName        = "skipped"
	actionKey               = "actionKey"
	spotCheckOkEventName    = "spot-check-ok"
	spotCheckWarnEventName  = "spot-check-warn"
	spotCheckErrorEventName = "spot-check-error"
	errorMessageKey         = attribute.Key("error.message")
	nameKey                 = attribute.Key("name")
	messageKey              = attribute.Key("message")
)

var (
	MainSection = trace.WithAttributes(attribute.Key("diagnose").String("main-section"))
)

var diagnoseSession = struct{}{}
var noopTracer = trace.NewNoopTracerProvider().Tracer("vault-diagnose")

type testFunction func(context.Context) error

type Session struct {
	tc     *TelemetryCollector
	tracer trace.Tracer
	tp     *sdktrace.TracerProvider
	skip   map[string]bool
}

// New initializes a Diagnose tracing session.  In particular this wires a TelemetryCollector, which
// synchronously receives and tracks OpenTelemetry spans in order to provide a tree structure of results
// when the outermost span ends.
func New(w io.Writer) *Session {
	tc := NewTelemetryCollector(w)
	//so, _ := stdout.NewExporter(stdout.WithPrettyPrint())
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		//sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(so)),
		sdktrace.WithSpanProcessor(tc),
	)
	tracer := tp.Tracer("vault-diagnose")
	sess := &Session{
		tp:     tp,
		tc:     tc,
		tracer: tracer,
		skip:   make(map[string]bool),
	}
	return sess
}

func (s *Session) SetSkipList(ls []string) {
	for _, e := range ls {
		s.skip[e] = true
	}
}

// IsSkipped returns true if skipName is present in the skip list.  Can be used in combination with Skip to mark a
// span skipped and conditionally skip some logic.
func (s *Session) IsSkipped(skipName string) bool {
	return s.skip[skipName]
}

// Context returns a new context with a defined diagnose session
func Context(ctx context.Context, sess *Session) context.Context {
	return context.WithValue(ctx, diagnoseSession, sess)
}

// CurrentSession retrieves the active diagnose session from the context, or nil if none.
func CurrentSession(ctx context.Context) *Session {
	sessionCtxVal := ctx.Value(diagnoseSession)
	if sessionCtxVal != nil {

		return sessionCtxVal.(*Session)

	}
	return nil
}

// Finalize ends the Diagnose session, returning the root of the result tree.  This will be empty until
// the outermost span ends.
func (s *Session) Finalize(ctx context.Context) *Result {
	s.tp.ForceFlush(ctx)
	return s.tc.RootResult
}

// StartSpan starts a "diagnose" span, which is really just an OpenTelemetry Tracing span.
func StartSpan(ctx context.Context, spanName string, options ...trace.SpanOption) (context.Context, trace.Span) {
	session := CurrentSession(ctx)
	if session != nil {
		return session.tracer.Start(ctx, spanName, options...)
	} else {
		return noopTracer.Start(ctx, spanName, options...)
	}
}

// Fail records a failure in the current span
func Fail(ctx context.Context, message string) {
	span := trace.SpanFromContext(ctx)
	span.SetStatus(codes.Error, message)
}

// Error records an error in the current span (but unlike Fail, doesn't set the overall span status to Error)
func Error(ctx context.Context, err error, options ...trace.EventOption) error {
	span := trace.SpanFromContext(ctx)
	span.RecordError(err, options...)
	return err
}

// Skipped marks the current span skipped
func Skipped(ctx context.Context) {
	span := trace.SpanFromContext(ctx)
	span.AddEvent(skippedEventName)
}

// Warn records a warning on the current span
func Warn(ctx context.Context, msg string) {
	span := trace.SpanFromContext(ctx)
	span.AddEvent(warningEventName, trace.WithAttributes(messageKey.String(msg)))
}

// SpotOk adds an Ok result without adding a new Span.  This should be used for instantaneous checks with no
// possible sub-spans
func SpotOk(ctx context.Context, checkName, message string, options ...trace.EventOption) {
	addSpotCheckResult(ctx, spotCheckOkEventName, checkName, message, options...)
}

// SpotWarn adds a Warning result without adding a new Span.  This should be used for instantaneous checks with no
// possible sub-spans
func SpotWarn(ctx context.Context, checkName, message string, options ...trace.EventOption) {
	addSpotCheckResult(ctx, spotCheckWarnEventName, checkName, message, options...)
}

// SpotError adds an Error result without adding a new Span.  This should be used for instantaneous checks with no
// possible sub-spans
func SpotError(ctx context.Context, checkName string, err error, options ...trace.EventOption) error {
	var message string
	if err != nil {
		message = err.Error()
	}
	addSpotCheckResult(ctx, spotCheckErrorEventName, checkName, message, options...)
	return err
}

func addSpotCheckResult(ctx context.Context, eventName, checkName, message string, options ...trace.EventOption) {
	span := trace.SpanFromContext(ctx)
	attrs := append(options, trace.WithAttributes(nameKey.String(checkName)))
	if message != "" {
		attrs = append(attrs, trace.WithAttributes(messageKey.String(message)))
	}
	span.AddEvent(eventName, attrs...)
}

func SpotCheck(ctx context.Context, checkName string, f func() error) error {
	err := f()
	if err != nil {
		SpotError(ctx, checkName, err)
		return err
	} else {
		SpotOk(ctx, checkName, "")
	}
	return nil
}

// Test creates a new named span, and executes the provided function within it.  If the function returns an error,
// the span is considered to have failed.
func Test(ctx context.Context, spanName string, function testFunction, options ...trace.SpanOption) error {
	ctx, span := StartSpan(ctx, spanName, options...)
	defer span.End()

	err := function(ctx)
	if err != nil {
		span.SetStatus(codes.Error, err.Error())
	}
	return err
}

// WithTimeout wraps a context consuming function, and when called, returns an error if the sub-function does not
// complete within the timeout, e.g.
//
// diagnose.Test(ctx, "my-span", diagnose.WithTimeout(5 * time.Second, myTestFunc))
func WithTimeout(d time.Duration, f testFunction) testFunction {
	return func(ctx context.Context) error {
		rch := make(chan error)
		t := time.NewTimer(d)
		defer t.Stop()
		go f(ctx)
		select {
		case <-t.C:
			return fmt.Errorf("timed out after %s", d.String())
		case err := <-rch:
			return err
		}
	}
}

// Skippable wraps a Test function with logic that will not run the test if the skipName
// was in the session's skip list
func Skippable(skipName string, f testFunction) testFunction {
	return func(ctx context.Context) error {
		session := CurrentSession(ctx)
		if session != nil {
			if !session.IsSkipped(skipName) {
				return f(ctx)
			} else {
				Skipped(ctx)
			}
		}
		return nil
	}
}
<commit_msg>Add a Success helper to set successful spans' messages (#11621)<commit_after>package diagnose

import (
	"context"
	"fmt"
	"io"
	"time"

	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"
)

const (
	warningEventName        = "warning"
	skippedEventName        = "skipped"
	actionKey               = "actionKey"
	spotCheckOkEventName    = "spot-check-ok"
	spotCheckWarnEventName  = "spot-check-warn"
	spotCheckErrorEventName = "spot-check-error"
	errorMessageKey         = attribute.Key("error.message")
	nameKey                 = attribute.Key("name")
	messageKey              = attribute.Key("message")
)

var (
	MainSection = trace.WithAttributes(attribute.Key("diagnose").String("main-section"))
)

var diagnoseSession = struct{}{}
var noopTracer = trace.NewNoopTracerProvider().Tracer("vault-diagnose")

type testFunction func(context.Context) error

type Session struct {
	tc     *TelemetryCollector
	tracer trace.Tracer
	tp     *sdktrace.TracerProvider
	skip   map[string]bool
}

// New initializes a Diagnose tracing session.  In particular this wires a TelemetryCollector, which
// synchronously receives and tracks OpenTelemetry spans in order to provide a tree structure of results
// when the outermost span ends.
func New(w io.Writer) *Session {
	tc := NewTelemetryCollector(w)
	//so, _ := stdout.NewExporter(stdout.WithPrettyPrint())
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		//sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(so)),
		sdktrace.WithSpanProcessor(tc),
	)
	tracer := tp.Tracer("vault-diagnose")
	sess := &Session{
		tp:     tp,
		tc:     tc,
		tracer: tracer,
		skip:   make(map[string]bool),
	}
	return sess
}

func (s *Session) SetSkipList(ls []string) {
	for _, e := range ls {
		s.skip[e] = true
	}
}

// IsSkipped returns true if skipName is present in the skip list.  Can be used in combination with Skip to mark a
// span skipped and conditionally skip some logic.
func (s *Session) IsSkipped(skipName string) bool {
	return s.skip[skipName]
}

// Context returns a new context with a defined diagnose session
func Context(ctx context.Context, sess *Session) context.Context {
	return context.WithValue(ctx, diagnoseSession, sess)
}

// CurrentSession retrieves the active diagnose session from the context, or nil if none.
func CurrentSession(ctx context.Context) *Session {
	sessionCtxVal := ctx.Value(diagnoseSession)
	if sessionCtxVal != nil {

		return sessionCtxVal.(*Session)

	}
	return nil
}

// Finalize ends the Diagnose session, returning the root of the result tree.  This will be empty until
// the outermost span ends.
func (s *Session) Finalize(ctx context.Context) *Result {
	s.tp.ForceFlush(ctx)
	return s.tc.RootResult
}

// StartSpan starts a "diagnose" span, which is really just an OpenTelemetry Tracing span.
func StartSpan(ctx context.Context, spanName string, options ...trace.SpanOption) (context.Context, trace.Span) {
	session := CurrentSession(ctx)
	if session != nil {
		return session.tracer.Start(ctx, spanName, options...)
	} else {
		return noopTracer.Start(ctx, spanName, options...)
	}
}

// Success sets the span to Successful (overriding any previous status) and sets the message to the input.
func Success(ctx context.Context, message string) {
	span := trace.SpanFromContext(ctx)
	span.SetStatus(codes.Ok, message)
}

// Fail records a failure in the current span
func Fail(ctx context.Context, message string) {
	span := trace.SpanFromContext(ctx)
	span.SetStatus(codes.Error, message)
}

// Error records an error in the current span (but unlike Fail, doesn't set the overall span status to Error)
func Error(ctx context.Context, err error, options ...trace.EventOption) error {
	span := trace.SpanFromContext(ctx)
	span.RecordError(err, options...)
	return err
}

// Skipped marks the current span skipped
func Skipped(ctx context.Context) {
	span := trace.SpanFromContext(ctx)
	span.AddEvent(skippedEventName)
}

// Warn records a warning on the current span
func Warn(ctx context.Context, msg string) {
	span := trace.SpanFromContext(ctx)
	span.AddEvent(warningEventName, trace.WithAttributes(messageKey.String(msg)))
}

// SpotOk adds an Ok result without adding a new Span.  This should be used for instantaneous checks with no
// possible sub-spans
func SpotOk(ctx context.Context, checkName, message string, options ...trace.EventOption) {
	addSpotCheckResult(ctx, spotCheckOkEventName, checkName, message, options...)
}

// SpotWarn adds a Warning result without adding a new Span.  This should be used for instantaneous checks with no
// possible sub-spans
func SpotWarn(ctx context.Context, checkName, message string, options ...trace.EventOption) {
	addSpotCheckResult(ctx, spotCheckWarnEventName, checkName, message, options...)
}

// SpotError adds an Error result without adding a new Span.  This should be used for instantaneous checks with no
// possible sub-spans
func SpotError(ctx context.Context, checkName string, err error, options ...trace.EventOption) error {
	var message string
	if err != nil {
		message = err.Error()
	}
	addSpotCheckResult(ctx, spotCheckErrorEventName, checkName, message, options...)
	return err
}

func addSpotCheckResult(ctx context.Context, eventName, checkName, message string, options ...trace.EventOption) {
	span := trace.SpanFromContext(ctx)
	attrs := append(options, trace.WithAttributes(nameKey.String(checkName)))
	if message != "" {
		attrs = append(attrs, trace.WithAttributes(messageKey.String(message)))
	}
	span.AddEvent(eventName, attrs...)
}

func SpotCheck(ctx context.Context, checkName string, f func() error) error {
	err := f()
	if err != nil {
		SpotError(ctx, checkName, err)
		return err
	} else {
		SpotOk(ctx, checkName, "")
	}
	return nil
}

// Test creates a new named span, and executes the provided function within it.  If the function returns an error,
// the span is considered to have failed.
func Test(ctx context.Context, spanName string, function testFunction, options ...trace.SpanOption) error {
	ctx, span := StartSpan(ctx, spanName, options...)
	defer span.End()

	err := function(ctx)
	if err != nil {
		span.SetStatus(codes.Error, err.Error())
	}
	return err
}

// WithTimeout wraps a context consuming function, and when called, returns an error if the sub-function does not
// complete within the timeout, e.g.
//
// diagnose.Test(ctx, "my-span", diagnose.WithTimeout(5 * time.Second, myTestFunc))
func WithTimeout(d time.Duration, f testFunction) testFunction {
	return func(ctx context.Context) error {
		rch := make(chan error)
		t := time.NewTimer(d)
		defer t.Stop()
		go f(ctx)
		select {
		case <-t.C:
			return fmt.Errorf("timed out after %s", d.String())
		case err := <-rch:
			return err
		}
	}
}

// Skippable wraps a Test function with logic that will not run the test if the skipName
// was in the session's skip list
func Skippable(skipName string, f testFunction) testFunction {
	return func(ctx context.Context) error {
		session := CurrentSession(ctx)
		if session != nil {
			if !session.IsSkipped(skipName) {
				return f(ctx)
			} else {
				Skipped(ctx)
			}
		}
		return nil
	}
}
<|endoftext|>


<commit_before>package class

import . "github.com/zxh0/jvm.go/jvmgo/any"

// todo
// cannot use package 'native' because of cycle import!
var registry = map[string]Any{}
var registerNatives Any

func SetRegisterNatives(_registerNatives Any) {
	registerNatives = _registerNatives
}

func RegisterNativeMethod(className, methodName, methodDescriptor string, method Any) {
	key := className + "~" + methodName + "~" + methodDescriptor
	registry[key] = method
}

func findNativeMethod(method *Method) Any {
	if method.IsRegisterNatives() {
		return registerNatives
	}

	key := method.class.name + "~" + method.name + "~" + method.descriptor
	if method, ok := registry[key]; ok {
		return method
	} else {
		panic("native method not found: " + key)
	}
}
<commit_msg>detect duplicate keys<commit_after>package class

import . "github.com/zxh0/jvm.go/jvmgo/any"

// todo
// cannot use package 'native' because of cycle import!
var registry = map[string]Any{}
var registerNatives Any

func SetRegisterNatives(_registerNatives Any) {
	registerNatives = _registerNatives
}

func RegisterNativeMethod(className, methodName, methodDescriptor string, method Any) {
	key := className + "~" + methodName + "~" + methodDescriptor
	registry[key] = method

	if _, ok := registry[key]; !ok {
		registry[key] = method
	} else {
		panic("native method:" + key + " has been registered !")
	}

}

func findNativeMethod(method *Method) Any {
	if method.IsRegisterNatives() {
		return registerNatives
	}

	key := method.class.name + "~" + method.name + "~" + method.descriptor
	if method, ok := registry[key]; ok {
		return method
	} else {
		panic("native method not found: " + key)
	}
}
<|endoftext|>


<commit_before>package backend

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"path/filepath"

	"github.com/kpango/glg"
)

var (
	TARGET_PREFIX string = *flag.String("prefix", "", "Use to find service from dir")
	TARGET_SUFFIX string = *flag.String("suffix", "", "Use to find service from dir")
	TARGET_FILE   string = *flag.String("filename", "Makefile", "This file name is used for `go run` command")
)

func loadServicesConfiguration() (error, bool) {
	allServices = make(map[string]*service)
	raw, err := ioutil.ReadFile("services.json")
	if err != nil {
		return err, false
	}
	err = json.Unmarshal(raw, &allServices)
	if err != nil {
		return err, false
	}
	for key, val := range allServices {
		if val.Target == "" {
			glg.Warnf("Field `target` is not provided for %v service", key)
			delete(allServices, key)
		} else {
			val.Name = key
		}
	}
	return nil, false
}

func init() {
	err, fatal := loadServicesConfiguration()
	if err != nil {
		glg.Errorf("Can't load services: %v.", err)
		if fatal {
			os.Exit(1)
		}
	}
}

func RestartAllServices(args ...string) {
	StopAllServices()
	err, fatal := loadServicesConfiguration()
	if err != nil {
		glg.Errorf("Can't load services: %v.", err)
		if fatal {
			os.Exit(1)
		}
	}
	StartAllServices(args...)
}

func RestartService(svcName string) {
	StopService(svcName)
	svc := GetService(svcName)
	if svc != nil {
		svc.Start()
	}
}

func isTargetExist(target string) bool {
	fileInfo, err := os.Stat(target)
	if os.IsNotExist(err) || fileInfo.IsDir() {
		return false
	}
	return true
}

func svcByTargetName(target string) (*service, error) {
	if !isTargetExist(target) {
		return nil, errors.New("service does not exist")
	}
	return &service{
		Target: target,
	}, nil
}

// Ищет сервис в соседних директориях
// Запускаемый файл должен называться `main.go`
func svcByNameFromDir(svcName string) (*service, error) {
	println(filepath.Join(TARGET_PREFIX, svcName, TARGET_SUFFIX, TARGET_FILE))
	svc, err := svcByTargetName(filepath.Join(TARGET_PREFIX, svcName, TARGET_SUFFIX, TARGET_FILE))
	if err != nil {
		return nil, err
	}
	svc.Name = svcName
	return svc, nil
}

func findService(svcName string) (*service, error) {
	svc, exist := allServices[svcName]
	if !exist {
		svc, err := svcByNameFromDir(svcName)
		if err != nil {
			return nil, fmt.Errorf("Can't find service %v.", svcName)
		}
		allServices[svcName] = svc
		return svc, nil
	} else {
		return svc, nil
	}
}

func GetService(svcName string, args ...string) *service {
	svc, err := findService(svcName)
	if err != nil {
		glg.Warn(err)
		return nil
	}
	err = svc.SetupService(args...)
	if err != nil {
		glg.Errorf("Can't create service: %v", err)
		return nil
	}
	return svc
}

func StartAllServices(args ...string) {
	for _, svc := range allServices {
		if svc.IsRunning {
			glg.Infof("%v already started.", svc.Name)
		} else {
			svc := GetService(svc.Name, args...)
			if svc != nil {
				svc.Start()
			}
		}
	}
}

func StopAllServices() {
	for _, svc := range allServices {
		svc.Stop()
	}
}

func StopService(svcName string) {
	svc, exist := allServices[svcName]
	if !exist {
		glg.Warnf("Can't find service %v.", svcName)
	} else {
		svc.Stop()
	}
}

func KillAllServices() {
	for _, svc := range allServices {
		svc.Kill()
	}
}

func KillService(svcName string) {
	svc, exist := allServices[svcName]
	if !exist {
		glg.Warnf("Can't find service %v.", svcName)
	} else {
		svc.Kill()
	}
}
<commit_msg>fix start all<commit_after>package backend

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"path/filepath"

	"github.com/kpango/glg"
)

var (
	TARGET_PREFIX string = *flag.String("prefix", "", "Use to find service from dir")
	TARGET_SUFFIX string = *flag.String("suffix", "", "Use to find service from dir")
	TARGET_FILE   string = *flag.String("filename", "Makefile", "This file name is used for `go run` command")
)

func loadServicesConfiguration() (error, bool) {
	allServices = make(map[string]*service)
	raw, err := ioutil.ReadFile("services.json")
	if err != nil {
		return err, false
	}
	err = json.Unmarshal(raw, &allServices)
	if err != nil {
		return err, false
	}
	for key, val := range allServices {
		if val.Target == "" {
			glg.Warnf("Field `target` is not provided for %v service", key)
			delete(allServices, key)
		} else {
			val.Name = key
		}
	}
	return nil, false
}

func init() {
	err, fatal := loadServicesConfiguration()
	if err != nil {
		glg.Errorf("Can't load services: %v.", err)
		if fatal {
			os.Exit(1)
		}
	}
}

func RestartAllServices(args ...string) {
	StopAllServices()
	err, fatal := loadServicesConfiguration()
	if err != nil {
		glg.Errorf("Can't load services: %v.", err)
		if fatal {
			os.Exit(1)
		}
	}
	StartAllServices(args...)
}

func RestartService(svcName string) {
	StopService(svcName)
	svc := GetService(svcName)
	if svc != nil {
		svc.Start()
	}
}

func isTargetExist(target string) bool {
	fileInfo, err := os.Stat(target)
	if os.IsNotExist(err) || fileInfo.IsDir() {
		return false
	}
	return true
}

func svcByTargetName(target string) (*service, error) {
	if !isTargetExist(target) {
		return nil, errors.New("service does not exist")
	}
	return &service{
		Target: target,
	}, nil
}

// Ищет сервис в соседних директориях
// Запускаемый файл должен называться `main.go`
func svcByNameFromDir(svcName string) (*service, error) {
	println(filepath.Join(TARGET_PREFIX, svcName, TARGET_SUFFIX, TARGET_FILE))
	svc, err := svcByTargetName(filepath.Join(TARGET_PREFIX, svcName, TARGET_SUFFIX, TARGET_FILE))
	if err != nil {
		return nil, err
	}
	svc.Name = svcName
	return svc, nil
}

func findService(svcName string) (*service, error) {
	svc, exist := allServices[svcName]
	if !exist {
		svc, err := svcByNameFromDir(svcName)
		if err != nil {
			return nil, fmt.Errorf("Can't find service %v.", svcName)
		}
		allServices[svcName] = svc
		return svc, nil
	} else {
		return svc, nil
	}
}

func GetService(svcName string, args ...string) *service {
	svc, err := findService(svcName)
	if err != nil {
		glg.Warn(err)
		return nil
	}
	err = svc.SetupService(args...)
	if err != nil {
		glg.Errorf("Can't create service: %v", err)
		return nil
	}
	return svc
}

func StartAllServices(args ...string) {
	for _, svc := range allServices {
		if svc.IsRunning {
			glg.Infof("%v already started.", svc.Name)
		} else {
			svc := GetService(svc.Name, args...)
			if svc != nil {
				go svc.Start()
			}
		}
	}
}

func StopAllServices() {
	for _, svc := range allServices {
		svc.Stop()
	}
}

func StopService(svcName string) {
	svc, exist := allServices[svcName]
	if !exist {
		glg.Warnf("Can't find service %v.", svcName)
	} else {
		svc.Stop()
	}
}

func KillAllServices() {
	for _, svc := range allServices {
		svc.Kill()
	}
}

func KillService(svcName string) {
	svc, exist := allServices[svcName]
	if !exist {
		glg.Warnf("Can't find service %v.", svcName)
	} else {
		svc.Kill()
	}
}
<|endoftext|>


<commit_before>package app

import (
	"github.com/gorilla/mux"
	"net/http"
	"github.com/Zenika/MARCEL/backend/medias"
	"github.com/rs/cors"
	"log"
	"os"
	//"github.com/Zenika/MARCEL/backend/plugins"
	"github.com/Zenika/MARCEL/backend/apidoc"
)

//current version of the API
const MARCEL_API_VERSION = "1"

var logFileName string = os.Getenv("MARCEL_LOG_FILE")
var logFile *os.File

type App struct {
	Router http.Handler

	mediaService medias.MediaService
}

func (a *App) Initialize() {

	a.initializeLog()

	a.initializeData()

	a.initializeRoutes()
}

func (a *App) Run(addr string) {
	log.Fatal(http.ListenAndServe(addr, a.Router))
	log.Printf("Server is started and listening on port %v", addr)

	defer logFile.Close()

	select {}
}

func (a *App) initializeRoutes() {

	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		// AllowedOrigins:   []string{"http://localhost:*"},
		AllowedMethods:   []string{"GET", "POST", "DELETE", "OPTION", "PUT"},
		AllowCredentials: true,
	})

	r := mux.NewRouter()
	s := r.PathPrefix("/api/v" + MARCEL_API_VERSION).Subrouter()
	s.HandleFunc("/medias", a.mediaService.GetAllHandler).Methods("GET")
	s.HandleFunc("/medias/config", a.mediaService.GetConfigHandler).Methods("GET")
	s.HandleFunc("/medias/create", a.mediaService.CreateHandler).Methods("GET")
	s.HandleFunc("/medias/{idMedia:[0-9]*}", a.mediaService.GetHandler).Methods("GET")
	s.HandleFunc("/medias/{idMedia:[0-9]*}", a.mediaService.PostHandler).Methods("POST")
	r.HandleFunc("/swagger.json", apidoc.GetConfigHandler).Methods("GET")

	a.Router = c.Handler(r)
}

func (a *App) initializeLog() {
	if len(logFileName) == 0 {
		logFileName = "marcel.log"
	}
	var err error = nil
	logFile, err = os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal(err)
	}
	log.SetOutput(logFile)
}

func (a *App) initializeData() {

	//Load plugins list from DB
	//plugins.LoadPluginsCatalog()

	//Load Medias configuration from DB
	a.mediaService = medias.NewMediaService()
	a.mediaService.GetMediaManager().LoadMedias()
}
<commit_msg>[Fix] Remove attribute for POST media<commit_after>package app

import (
	"github.com/gorilla/mux"
	"net/http"
	"github.com/Zenika/MARCEL/backend/medias"
	"github.com/rs/cors"
	"log"
	"os"
	//"github.com/Zenika/MARCEL/backend/plugins"
	"github.com/Zenika/MARCEL/backend/apidoc"
)

//current version of the API
const MARCEL_API_VERSION = "1"

var logFileName string = os.Getenv("MARCEL_LOG_FILE")
var logFile *os.File

type App struct {
	Router http.Handler

	mediaService medias.MediaService
}

func (a *App) Initialize() {

	a.initializeLog()

	a.initializeData()

	a.initializeRoutes()
}

func (a *App) Run(addr string) {
	log.Fatal(http.ListenAndServe(addr, a.Router))
	log.Printf("Server is started and listening on port %v", addr)

	defer logFile.Close()

	select {}
}

func (a *App) initializeRoutes() {

	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		// AllowedOrigins:   []string{"http://localhost:*"},
		AllowedMethods:   []string{"GET", "POST", "DELETE", "OPTION", "PUT"},
		AllowCredentials: true,
	})

	r := mux.NewRouter()
	s := r.PathPrefix("/api/v" + MARCEL_API_VERSION).Subrouter()
	s.HandleFunc("/medias", a.mediaService.GetAllHandler).Methods("GET")
	s.HandleFunc("/medias/config", a.mediaService.GetConfigHandler).Methods("GET")
	s.HandleFunc("/medias/create", a.mediaService.CreateHandler).Methods("GET")
	s.HandleFunc("/medias/{idMedia:[0-9]*}", a.mediaService.GetHandler).Methods("GET")
	s.HandleFunc("/medias", a.mediaService.PostHandler).Methods("POST")
	r.HandleFunc("/swagger.json", apidoc.GetConfigHandler).Methods("GET")

	a.Router = c.Handler(r)
}

func (a *App) initializeLog() {
	if len(logFileName) == 0 {
		logFileName = "marcel.log"
	}
	var err error = nil
	logFile, err = os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal(err)
	}
	log.SetOutput(logFile)
}

func (a *App) initializeData() {

	//Load plugins list from DB
	//plugins.LoadPluginsCatalog()

	//Load Medias configuration from DB
	a.mediaService = medias.NewMediaService()
	a.mediaService.GetMediaManager().LoadMedias()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
)

func init() {
	// No Favicon this is an API Server. But god forbid you actually use this in a browser.
	http.Handle("/favicon.ico", http.NotFoundHandler())

	// http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello!")
}
<commit_msg>Base backend<commit_after>package main

import (
	"fmt"
	"net/http"
)

func init() {
	// No Favicon this is an API Server. But god forbid you actually use this in a browser.
	http.Handle("/favicon.ico", http.NotFoundHandler())
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 registry

import (
	"time"

	"github.com/jacobsa/comeback/blob"
)

type Registry interface {
	// Record that the named backup job has completed.
	RecordBackup(j CompletedJob) (err error)

	// Return a list of the most recent completed backups.
	ListRecentBackups() (jobs []CompletedJob, err error)

	// Find a particular completed job by start time.
	FindBackup(startTime time.Time) (job CompletedJob, err error)
}

// A record in the backup registry describing a successful backup job.
type CompletedJob struct {
	// The time at which the backup was started.
	StartTime time.Time

	// The name of the backup job.
	Name string

	// The score representing the contents of the backup.
	Score blob.Score
}
<commit_msg>ListRecentBackups -> ListBackups<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 registry

import (
	"time"

	"github.com/jacobsa/comeback/blob"
)

type Registry interface {
	// Record that the named backup job has completed.
	RecordBackup(j CompletedJob) (err error)

	// Return a list of all completed backups.
	ListBackups() (jobs []CompletedJob, err error)

	// Find a particular completed job by start time.
	FindBackup(startTime time.Time) (job CompletedJob, err error)
}

// A record in the backup registry describing a successful backup job.
type CompletedJob struct {
	// The time at which the backup was started.
	StartTime time.Time

	// The name of the backup job.
	Name string

	// The score representing the contents of the backup.
	Score blob.Score
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"reflect"
	"testing"
)

func testIconsFindHelper(terms []string) icons {
	return newIcons().find(terms)
}

func TestIcons_iconsYamlPath_TestEnv(t *testing.T) {
	actual := iconsYamlPath()
	expected := "workflow/icons.yml"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_iconsYamlPath_ProductionEnv(t *testing.T) {
	resetEnv := setTestEnvHelper("FAW_ICONS_YAML_PATH", "")
	defer resetEnv()

	actual := iconsYamlPath()
	expected := "icons.yml"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_iconsReadYaml(t *testing.T) {
	path := "workflow/icons.yml"
	actual, _ := iconsReadYaml(path)

	expected, _ := ioutil.ReadFile(path)
	if !reflect.DeepEqual(actual, expected) {
		t.Error("failed to read file")
	}
}

func TestIcons_iconsReadYaml_Error(t *testing.T) {
	path := ""
	_, err := iconsReadYaml(path)

	if err == nil {
		t.Error("expected error, but nil")
	}
}

func TestIcons_iconsUnmarshalYaml(t *testing.T) {
	b := []byte(`
icons:
  - name:       Glass
    id:         glass
    unicode:    f000
    created:    1.0
    filter:
      - martini
`)
	actual, _ := iconsUnmarshalYaml(b)

	icon := icon{
		Name:    "Glass",
		ID:      "glass",
		Unicode: "f000",
		Created: "1.0",
		Filter:  []string{"martini"},
	}
	expected := iconsYaml{icons{icon}}
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_AllIcons(t *testing.T) {
	fi := testIconsFindHelper([]string{""})

	actual := len(fi)
	expected := 519
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_ZeroIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{"foo-bar-baz"})

	actual := len(fi)
	expected := 0
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_OneIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{"github-square"})

	actual := len(fi)
	expected := 1
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_TwoIcons(t *testing.T) {
	fi := testIconsFindHelper([]string{"github-"})

	actual := len(fi)
	expected := 2
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_FirstIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{""})

	actual := fi[0].ID
	expected := "adjust"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_LastIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{""})

	actual := fi[len(fi)-1].ID
	expected := "youtube-square"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_TaxiIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{"taxi"})

	actual := fi[0].Name
	expected := "Taxi"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].ID
	expected = "taxi"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Unicode
	expected = "f1ba"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Created
	expected = "4.1"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Aliases[0]
	expected = "cab"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Filter[0]
	expected = "vehicle"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Categories[0]
	expected = "Web Application Icons"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_Aliases(t *testing.T) {
	fi := testIconsFindHelper([]string{"navicon"})

	actual := fi[0].ID
	expected := "bars"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	if len(fi) != 1 {
		t.Errorf("expected %v to eq %v", len(fi), 1)
	}
}
<commit_msg>Fix tests (Font Awesome 4.4.0)<commit_after>package main

import (
	"io/ioutil"
	"reflect"
	"testing"
)

func testIconsFindHelper(terms []string) icons {
	return newIcons().find(terms)
}

func TestIcons_iconsYamlPath_TestEnv(t *testing.T) {
	actual := iconsYamlPath()
	expected := "workflow/icons.yml"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_iconsYamlPath_ProductionEnv(t *testing.T) {
	resetEnv := setTestEnvHelper("FAW_ICONS_YAML_PATH", "")
	defer resetEnv()

	actual := iconsYamlPath()
	expected := "icons.yml"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_iconsReadYaml(t *testing.T) {
	path := "workflow/icons.yml"
	actual, _ := iconsReadYaml(path)

	expected, _ := ioutil.ReadFile(path)
	if !reflect.DeepEqual(actual, expected) {
		t.Error("failed to read file")
	}
}

func TestIcons_iconsReadYaml_Error(t *testing.T) {
	path := ""
	_, err := iconsReadYaml(path)

	if err == nil {
		t.Error("expected error, but nil")
	}
}

func TestIcons_iconsUnmarshalYaml(t *testing.T) {
	b := []byte(`
icons:
  - name:       Glass
    id:         glass
    unicode:    f000
    created:    1.0
    filter:
      - martini
`)
	actual, _ := iconsUnmarshalYaml(b)

	icon := icon{
		Name:    "Glass",
		ID:      "glass",
		Unicode: "f000",
		Created: "1.0",
		Filter:  []string{"martini"},
	}
	expected := iconsYaml{icons{icon}}
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_AllIcons(t *testing.T) {
	fi := testIconsFindHelper([]string{""})

	actual := len(fi)
	expected := 585
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_ZeroIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{"foo-bar-baz"})

	actual := len(fi)
	expected := 0
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_OneIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{"github-square"})

	actual := len(fi)
	expected := 1
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_TwoIcons(t *testing.T) {
	fi := testIconsFindHelper([]string{"github-"})

	actual := len(fi)
	expected := 2
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_FirstIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{""})

	actual := fi[0].ID
	expected := "500px"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_LastIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{""})

	actual := fi[len(fi)-1].ID
	expected := "youtube-square"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_TaxiIcon(t *testing.T) {
	fi := testIconsFindHelper([]string{"taxi"})

	actual := fi[0].Name
	expected := "Taxi"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].ID
	expected = "taxi"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Unicode
	expected = "f1ba"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Created
	expected = "4.1"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Aliases[0]
	expected = "cab"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Filter[0]
	expected = "vehicle"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	actual = fi[0].Categories[0]
	expected = "Web Application Icons"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}
}

func TestIcons_find_Aliases(t *testing.T) {
	fi := testIconsFindHelper([]string{"navicon"})

	actual := fi[0].ID
	expected := "bars"
	if actual != expected {
		t.Errorf("expected %v to eq %v", actual, expected)
	}

	if len(fi) != 1 {
		t.Errorf("expected %v to eq %v", len(fi), 1)
	}
}
<|endoftext|>


<commit_before>package imageserver_test

import (
	. "github.com/pierrre/imageserver"
	"github.com/pierrre/imageserver/testdata"
	"reflect"
	"testing"
)

func TestImage(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		newImage, err := NewImageUnmarshalBinary(data)
		if err != nil {
			t.Fatal(err)
		}

		if !reflect.DeepEqual(newImage, image) {
			t.Fatal("image not equals")
		}
	}
}

func TestImageUnmarshalBinaryError(t *testing.T) {
	_, err := NewImageUnmarshalBinary(nil)
	if err == nil {
		t.Fatal("no error")
	}
}
<commit_msg>100% test coverage on Image<commit_after>package imageserver_test

import (
	. "github.com/pierrre/imageserver"
	"github.com/pierrre/imageserver/testdata"
	"reflect"
	"testing"
)

func TestImage(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		newImage, err := NewImageUnmarshalBinary(data)
		if err != nil {
			t.Fatal(err)
		}

		if !reflect.DeepEqual(newImage, image) {
			t.Fatal("image not equals")
		}
	}
}

func TestImageUnmarshalBinaryError(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		index := -1 // Always truncate 1 byte
		for _, offset := range []int{
			4,
			len(image.Format),
			4,
			len(image.Data),
		} {
			index += offset
			errorData := data[0:index]
			_, err = NewImageUnmarshalBinary(errorData)
			if err == nil {
				t.Fatal("no error")
			}
		}
	}
}
<|endoftext|>


<commit_before>package postgres

import (
	"bytes"
	"database/sql/driver"
	"encoding/gob"
	"encoding/hex"
	"fmt"
	"strings"
)

type sessionValues map[string]interface{}

func init() {
	gob.Register(sessionValues{})
}

// Value() converts a product into a string suitable for the SQL database
//
// It encodes the data using Gob, then converts to a hex string suitable for the
// bytea type
func (p sessionValues) Value() (driver.Value, error) {
	buf := bytes.Buffer{}
	encoder := gob.NewEncoder(&buf)
	err := encoder.Encode(p)
	if err != nil {
		return nil, err
	}

	return `E'\\x` + hex.EncodeToString(buf.Bytes()) + `'`, nil
}

// Scan() pulls the product out of the SQL database
//
// It expects the data to be in a bytea field, and encoded using GOB
func (p sessionValues) Scan(src interface{}) error {
	if src == nil {
		return nil
	}

	b, ok := src.([]uint8)
	if !ok {
		return fmt.Errorf("expected session values to be a byte array")
	}

	bs := string(b)
	if strings.HasPrefix(bs, `E'\\x`) && strings.HasSuffix(bs, `'`) {
		bs = bs[5 : len(bs)-1]

		g, err := hex.DecodeString(bs)
		if err != nil {
			return err
		}
		buf := bytes.NewBuffer(g)
		decoder := gob.NewDecoder(buf)
		return decoder.Decode(&p)
	}
	return fmt.Errorf("session value does not have correct form.  received %s", bs)
}
<commit_msg>Subtle tweak for postgres sessions<commit_after>package postgres

import (
	"bytes"
	"database/sql/driver"
	"encoding/gob"
	"encoding/hex"
	"fmt"
	"strings"
)

type sessionValues map[string]interface{}

func init() {
	gob.Register(sessionValues{})
	// Register this as well as is used by oAuth code
	gob.Register(map[string]interface{}{})
}

// Value() converts a product into a string suitable for the SQL database
//
// It encodes the data using Gob, then converts to a hex string suitable for the
// bytea type
func (p sessionValues) Value() (driver.Value, error) {
	buf := bytes.Buffer{}
	encoder := gob.NewEncoder(&buf)
	err := encoder.Encode(p)
	if err != nil {
		return nil, err
	}

	return `E'\\x` + hex.EncodeToString(buf.Bytes()) + `'`, nil
}

// Scan() pulls the product out of the SQL database
//
// It expects the data to be in a bytea field, and encoded using GOB
func (p sessionValues) Scan(src interface{}) error {
	if src == nil {
		return nil
	}

	b, ok := src.([]uint8)
	if !ok {
		return fmt.Errorf("expected session values to be a byte array")
	}

	bs := string(b)
	if strings.HasPrefix(bs, `E'\\x`) && strings.HasSuffix(bs, `'`) {
		bs = bs[5 : len(bs)-1]

		g, err := hex.DecodeString(bs)
		if err != nil {
			return err
		}
		buf := bytes.NewBuffer(g)
		decoder := gob.NewDecoder(buf)
		return decoder.Decode(&p)
	}
	return fmt.Errorf("session value does not have correct form.  received %s", bs)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"path/filepath"
	"strings"

	"github.com/diginatu/nagome/nicolive"
)

// ProceedNicoliveEvent is struct for proceeding nico events from nicolive packeage.
type ProceedNicoliveEvent struct {
	cv     *CommentViewer
	userDB *nicolive.UserDB
}

// NewProceedNicoliveEvent makes new ProceedNicoliveEvent and returns it.
func NewProceedNicoliveEvent(cv *CommentViewer) *ProceedNicoliveEvent {
	udb, err := nicolive.NewUserDB(filepath.Join(App.SavePath, userDBFileName))
	if err != nil {
		log.Fatalln(err)
	}
	return &ProceedNicoliveEvent{
		cv:     cv,
		userDB: udb,
	}
}

func (p *ProceedNicoliveEvent) getUserName(id string, useAPI bool) (*nicolive.User, error) {
	u, err := p.userDB.Fetch(id)
	if err != nil {
		return nil, err
	}
	if useAPI {
		if u == nil {
			u, nerr := nicolive.FetchUserInfo(id, p.cv.Ac)
			if nerr != nil {
				return nil, nerr
			}
			err := p.userDB.Store(u)
			if err != nil {
				return nil, err
			}
			return u, nil
		}
	}
	return u, nil
}

func (p *ProceedNicoliveEvent) proceedComment(ev *nicolive.Event) {
	cm, _ := ev.Content.(nicolive.Comment)
	ct := CtCommentGot{
		No:            cm.No,
		Date:          cm.Date,
		UserID:        cm.UserID,
		Raw:           cm.Comment,
		IsPremium:     cm.IsPremium,
		IsBroadcaster: cm.IsCommand,
		IsStaff:       cm.IsStaff,
		IsAnonymity:   cm.IsAnonymity,
		Score:         cm.Score,
	}

	// user info
	useAPI := p.cv.Settings.UserNameGet && cm.Date.After(p.cv.Cmm.ConnectedTm) && !cm.IsAnonymity && !cm.IsCommand
	u, err := p.getUserName(cm.UserID, useAPI)
	if err != nil {
		log.Println(err)
	}
	if u != nil {
		ct.UserName = u.Name
		ct.UserThumbnailURL = u.ThumbnailURL
	}
	if cm.IsCommand {
		ct.UserName = "Broadcaster"
	}

	ct.Comment = strings.Replace(cm.Comment, "\n", "
", -1)
	p.cv.Evch <- NewMessageMust(DomainComment, CommCommentGot, ct)
}

// ProceedNicoEvent will receive events and emits it.
func (p *ProceedNicoliveEvent) ProceedNicoEvent(ev *nicolive.Event) {
	switch ev.Type {
	case nicolive.EventTypeCommentGot:
		p.proceedComment(ev)

	case nicolive.EventTypeCommentOpen:
		p.cv.Evch <- NewMessageMust(DomainUI, CommUIClearComments, nil)
		lv := ev.Content.(*nicolive.LiveWaku)
		log.Println(lv)
		ct := CtNagomeBroadOpen{
			BroadID:     lv.BroadID,
			Title:       lv.Stream.Title,
			Description: lv.Stream.Description,
			CommunityID: lv.Stream.CommunityID,
			OwnerID:     lv.Stream.OwnerID,
			OwnerName:   lv.Stream.OwnerName,
			OwnerBroad:  lv.OwnerBroad,
			OpenTime:    lv.Stream.OpenTime,
			StartTime:   lv.Stream.StartTime,
			EndTime:     lv.Stream.EndTime,
		}
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeBroadOpen, ct)

	case nicolive.EventTypeCommentClose:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeBroadClose, nil)

	case nicolive.EventTypeHeartBeatGot:
		hb := ev.Content.(*nicolive.HeartbeatValue)
		ct := CtNagomeBroadInfo{hb.WatchCount, hb.CommentCount}
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeBroadInfo, ct)

	case nicolive.EventTypeCommentSend:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeCommentSend, nil)

	case nicolive.EventTypeCommentErr:
		nerr := ev.Content.(nicolive.Error)
		p.cv.CreateEvNewDialog(CtUIDialogTypeWarn, nerr.TypeString(), nerr.Description())

	case nicolive.EventTypeAntennaOpen:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeAntennaOpen, nil)

	case nicolive.EventTypeAntennaClose:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeAntennaClose, nil)

	case nicolive.EventTypeAntennaErr:
		log.Println(ev)

	case nicolive.EventTypeAntennaGot:
		ai := ev.Content.(*nicolive.AntennaItem)
		ct := CtAntennaGot{ai.BroadID, ai.CommunityID, ai.UserID}
		p.cv.Evch <- NewMessageMust(DomainAntenna, CommAntennaGot, ct)

	default:
		log.Println(ev)
	}
}
<commit_msg>limit on getting user name using API<commit_after>package main

import (
	"log"
	"path/filepath"
	"strings"
	"time"

	"github.com/diginatu/nagome/nicolive"
)

const (
	userNameAPITimesAMinute = 6
)

// ProceedNicoliveEvent is struct for proceeding nico events from nicolive packeage.
type ProceedNicoliveEvent struct {
	cv                  *CommentViewer
	userDB              *nicolive.UserDB
	userNameAPITimes    int
	userNameAPIFastTime time.Time
}

// NewProceedNicoliveEvent makes new ProceedNicoliveEvent and returns it.
func NewProceedNicoliveEvent(cv *CommentViewer) *ProceedNicoliveEvent {
	udb, err := nicolive.NewUserDB(filepath.Join(App.SavePath, userDBFileName))
	if err != nil {
		log.Fatalln(err)
	}
	return &ProceedNicoliveEvent{
		cv:     cv,
		userDB: udb,
	}
}

func (p *ProceedNicoliveEvent) getUserName(id string, useAPI bool) (*nicolive.User, error) {
	u, err := p.userDB.Fetch(id)
	if err != nil {
		return nil, err
	}
	if u != nil {
		return u, nil
	}

	if useAPI {
		// reset API limit
		if time.Now().After(p.userNameAPIFastTime.Add(time.Minute)) {
			p.userNameAPIFastTime = time.Now()
			p.userNameAPITimes = userNameAPITimesAMinute
		}
		log.Println(p.userNameAPITimes)
		if p.userNameAPITimes > 0 {
			u, nerr := nicolive.FetchUserInfo(id, p.cv.Ac)
			if nerr != nil {
				return nil, nerr
			}
			p.userNameAPITimes--
			err := p.userDB.Store(u)
			if err != nil {
				return nil, err
			}
			return u, nil
		}
	}
	return u, nil
}

func (p *ProceedNicoliveEvent) proceedComment(ev *nicolive.Event) {
	cm, _ := ev.Content.(nicolive.Comment)
	ct := CtCommentGot{
		No:            cm.No,
		Date:          cm.Date,
		UserID:        cm.UserID,
		Raw:           cm.Comment,
		IsPremium:     cm.IsPremium,
		IsBroadcaster: cm.IsCommand,
		IsStaff:       cm.IsStaff,
		IsAnonymity:   cm.IsAnonymity,
		Score:         cm.Score,
	}

	// user info
	useAPI := p.cv.Settings.UserNameGet && cm.Date.After(p.cv.Cmm.ConnectedTm) && !cm.IsAnonymity && !cm.IsCommand
	u, err := p.getUserName(cm.UserID, useAPI)
	if err != nil {
		log.Println(err)
	}
	if u != nil {
		ct.UserName = u.Name
		ct.UserThumbnailURL = u.ThumbnailURL
	}
	if cm.IsCommand {
		ct.UserName = "Broadcaster"
	}

	ct.Comment = strings.Replace(cm.Comment, "\n", "
", -1)
	p.cv.Evch <- NewMessageMust(DomainComment, CommCommentGot, ct)
}

// ProceedNicoEvent will receive events and emits it.
func (p *ProceedNicoliveEvent) ProceedNicoEvent(ev *nicolive.Event) {
	switch ev.Type {
	case nicolive.EventTypeCommentGot:
		p.proceedComment(ev)

	case nicolive.EventTypeCommentOpen:
		p.cv.Evch <- NewMessageMust(DomainUI, CommUIClearComments, nil)
		lv := ev.Content.(*nicolive.LiveWaku)
		log.Println(lv)
		ct := CtNagomeBroadOpen{
			BroadID:     lv.BroadID,
			Title:       lv.Stream.Title,
			Description: lv.Stream.Description,
			CommunityID: lv.Stream.CommunityID,
			OwnerID:     lv.Stream.OwnerID,
			OwnerName:   lv.Stream.OwnerName,
			OwnerBroad:  lv.OwnerBroad,
			OpenTime:    lv.Stream.OpenTime,
			StartTime:   lv.Stream.StartTime,
			EndTime:     lv.Stream.EndTime,
		}
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeBroadOpen, ct)

	case nicolive.EventTypeCommentClose:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeBroadClose, nil)

	case nicolive.EventTypeHeartBeatGot:
		hb := ev.Content.(*nicolive.HeartbeatValue)
		ct := CtNagomeBroadInfo{hb.WatchCount, hb.CommentCount}
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeBroadInfo, ct)

	case nicolive.EventTypeCommentSend:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeCommentSend, nil)

	case nicolive.EventTypeCommentErr:
		nerr := ev.Content.(nicolive.Error)
		p.cv.CreateEvNewDialog(CtUIDialogTypeWarn, nerr.TypeString(), nerr.Description())

	case nicolive.EventTypeAntennaOpen:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeAntennaOpen, nil)

	case nicolive.EventTypeAntennaClose:
		p.cv.Evch <- NewMessageMust(DomainNagome, CommNagomeAntennaClose, nil)

	case nicolive.EventTypeAntennaErr:
		log.Println(ev)

	case nicolive.EventTypeAntennaGot:
		ai := ev.Content.(*nicolive.AntennaItem)
		ct := CtAntennaGot{ai.BroadID, ai.CommunityID, ai.UserID}
		p.cv.Evch <- NewMessageMust(DomainAntenna, CommAntennaGot, ct)

	default:
		log.Println(ev)
	}
}
<|endoftext|>


<commit_before>package html2text

import (
	"regexp"
	"testing"
)

func TestText(t *testing.T) {
	testCases := []struct {
		input string
		expr  string
	}{
		{
			`

   New repository

`,
			`/new`,
		},
		{
			`hi

	hello google

	test
List:

Foo

Barsoap

Baz

`,
			`hi

hello
https://google.com
test

List:

foo
http://www.microshwhat.com/bar/soapy

Baz`,
		},
		// Malformed input html.
		{
			`hi

			hello google

			test
List:

Foo

Bar

Baz

		`,
			`hi hello
https://google.com
test

List:

foo
/\n[ \t]+bar/baz

Baz`,
		},
	}

	for _, testCase := range testCases {
		text, err := FromString(testCase.input)
		if err != nil {
			t.Error(err)
		}
		if expr := regexp.MustCompile(testCase.expr); !expr.MatchString(text) {
			t.Errorf("Input did not match expression\nInput:\n>>>>\n%s\n<<<<\n\nOutput:\n>>>>\n%s\n<<<<\n\nExpression: %s\n", testCase.input, text, expr.String())
		} else {
			t.Logf("input:\n\n%s\n\n\n\noutput:\n\n%s\n", testCase.input, text)
		}
	}
}
<commit_msg>Update tests<commit_after>package html2text

import (
	"testing"
)

func TestText(t *testing.T) {
	testCases := []struct {
		input string
		expr  string
	}{
		{
			`

   New repository

`,
			"*   (http://www.microshwhat.com/bar/soapy/new)[New repository]",
		},
		{
			`hi

	hello google

	test
List:

Foo

Barsoap

Baz

`,
			"hi \n\n hello  (https://google.com)[google] \n\n test\n\nList: \n\n    *  (foo)[Foo] \n    *  (http://www.microshwhat.com/bar/soapy)[Barsoap] \n    * Baz",
		},
		// Malformed input html.
		{
			`hi

			hello google

			test
List:

Foo

Bar

Baz

		`,
			"hi hello  (https://google.com)[google] test\n\nList: \n\n    *  (foo)[Foo] \n    *  (http://www.microshwhat.com/bar/soapy/bar/baz)[Bar] \n    * Baz",
		},
	}

	for _, testCase := range testCases {
		text, err := FromString(testCase.input, "http://www.microshwhat.com/bar/soapy", OmitClasses|OmitIds|OmitRoles)
		if err != nil {
			t.Error(err)
		}

		if testCase.expr != text {
			t.Errorf("Input did not match expression\nInput:\n>>>>\n@@%s@@\n<<<<\n\nOutput:\n>>>>\n##%s##\n<<<<\n\nExpression: ^^%s^^\n", testCase.input, text, testCase.expr)
		} else {
			t.Logf("input:\n\n%s\n\n\n\noutput:\n\n%s\n", testCase.input, text)
		}
	}
}
<|endoftext|>


<commit_before>package framesweb

import (
	"bufio"
	"errors"
	"net"
	"net/http"

	"github.com/dustin/frames"
)

// A RoundTripper over frames.
type FramesRoundTripper struct {
	Dialer frames.ChannelDialer
}

func (f *FramesRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	c, err := f.Dialer.Dial()
	if err != nil {
		return nil, err
	}
	defer c.Close()

	err = req.Write(c)
	if err != nil {
		return nil, err
	}

	b := bufio.NewReader(c)
	return http.ReadResponse(b, req)
}

// Get an HTTP client that maintains a persistent frames connection.
func NewFramesClient(n, addr string) (*http.Client, error) {
	c, err := net.Dial(n, addr)
	if err != nil {
		return nil, err
	}

	frt := &FramesRoundTripper{
		Dialer: frames.NewClient(c),
	}

	hc := &http.Client{
		Transport: frt,
	}

	return hc, nil
}

// Close the frames client.
func CloseFramesClient(hc *http.Client) error {
	if frt, ok := hc.Transport.(*FramesRoundTripper); ok {
		return frt.Dialer.Close()
	}
	return errors.New("Not a frames client")
}
<commit_msg>Close the channel when the client closes the body.<commit_after>package framesweb

import (
	"bufio"
	"errors"
	"io"
	"net"
	"net/http"

	"github.com/dustin/frames"
)

// A RoundTripper over frames.
type FramesRoundTripper struct {
	Dialer frames.ChannelDialer
	err    error
}

type channelBodyCloser struct {
	rc io.ReadCloser
	c  io.Closer
}

func (c *channelBodyCloser) Read(b []byte) (int, error) {
	return c.rc.Read(b)
}

func (c *channelBodyCloser) Close() error {
	c.rc.Close()
	return c.c.Close()
}

func (f *FramesRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	if f.err != nil {
		return nil, f.err
	}

	c, err := f.Dialer.Dial()
	if err != nil {
		f.err = err
		return nil, err
	}

	err = req.Write(c)
	if err != nil {
		f.err = err
		c.Close()
		return nil, err
	}

	b := bufio.NewReader(c)
	res, err := http.ReadResponse(b, req)
	if err != nil {
		f.err = err
	}
	res.Body = &channelBodyCloser{res.Body, c}
	return res, err
}

// Get an HTTP client that maintains a persistent frames connection.
func NewFramesClient(n, addr string) (*http.Client, error) {
	c, err := net.Dial(n, addr)
	if err != nil {
		return nil, err
	}

	frt := &FramesRoundTripper{
		Dialer: frames.NewClient(c),
	}

	hc := &http.Client{
		Transport: frt,
	}

	return hc, nil
}

// Close the frames client.
func CloseFramesClient(hc *http.Client) error {
	if frt, ok := hc.Transport.(*FramesRoundTripper); ok {
		return frt.Dialer.Close()
	}
	return errors.New("Not a frames client")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	nxcli "github.com/jaracil/nxcli"
	nexus "github.com/jaracil/nxcli/nxcore"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	app      = kingpin.New("cli", "Nexus command line interface")
	serverIP = app.Flag("server", "Server address.").Default("127.0.0.1:1717").Short('s').String()
	timeout  = app.Flag("timeout", "Execution timeout").Default("60").Short('t').Int()
	user     = app.Flag("user", "Nexus username").Short('u').Default("test").String()
	pass     = app.Flag("pass", "Nexus password").Default("test").Short('p').String()

	///

	shell = app.Command("shell", "Interactive shell")

	///

	login     = app.Command("login", "Tests to login with an username/password and exits")
	loginName = login.Arg("username", "username").Required().String()
	loginPass = login.Arg("password", "password").Required().String()

	///

	push       = app.Command("push", "Execute a task.push rpc call on Nexus")
	pushMethod = push.Arg("method", "Method to call").Required().String()
	pushParams = push.Arg("params", "parameters").StringMap()

	pull       = app.Command("pull", "Execute a task.pull rpc call on Nexus")
	pullMethod = pull.Arg("prefix", "Method to call").Required().String()

	///

	pipeCmd = app.Command("pipe", "Pipe tasks")

	pipeRead = pipeCmd.Command("read", "Create and read from a pipe. It will be destroyed on exit")

	pipeWrite     = pipeCmd.Command("open", "Open a pipe and send data")
	pipeWriteId   = pipeWrite.Arg("pipeId", "ID of the pipe to write to").Required().String()
	pipeWriteData = pipeWrite.Arg("data", "Data to write to the pipe").Required().Strings()

	///

	userCmd = app.Command("user", "user management")

	userCreate     = userCmd.Command("create", "Create a new user")
	userCreateName = userCreate.Arg("username", "username").Required().String()
	userCreatePass = userCreate.Arg("password", "password").Required().String()

	userDelete     = userCmd.Command("delete", "Delete an user")
	userDeleteName = userDelete.Arg("username", "username").Required().String()

	userPass     = userCmd.Command("passwd", "Change an user password")
	userPassName = userPass.Arg("username", "username").Required().String()
	userPassPass = userPass.Arg("password", "password").Required().String()

	///

	tagsCmd = app.Command("tags", "tags management")

	tagsSet       = tagsCmd.Command("set", "Set tags for an user on a prefix. Tags is a map[string]string in the form tag:value")
	tagsSetUser   = tagsSet.Arg("user", "user").Required().String()
	tagsSetPrefix = tagsSet.Arg("prefix", "prefix").Required().String()
	tagsSetTags   = tagsSet.Arg("tags", "tag:value").Required().StringMap()

	tagsDel       = tagsCmd.Command("del", "delete tags for an user on a prefix. Tags is a list of space separated strings")
	tagsDelUser   = tagsDel.Arg("user", "user").Required().String()
	tagsDelPrefix = tagsDel.Arg("prefix", "prefix").Required().String()
	tagsDelTags   = tagsDel.Arg("tags", "tag:value").Required().Strings()

	//

	chanCmd = app.Command("topic", "Topics management")

	chanSub     = chanCmd.Command("sub", "Subscribe a pipe to a topic")
	chanSubPipe = chanSub.Arg("pipe", "pipe id to subscribe").Required().String()
	chanSubChan = chanSub.Arg("topic", "Topic to subscribe to").Required().String()

	chanUnsub     = chanCmd.Command("unsub", "Unsubscribe a pipe from a topic")
	chanUnsubPipe = chanUnsub.Arg("pipe", "pipe id to subscribe").Required().String()
	chanUnsubChan = chanUnsub.Arg("topic", "Topic to subscribe to").Required().String()

	chanPub     = chanCmd.Command("pub", "Publish a message to a topic")
	chanPubChan = chanPub.Arg("topic", "Topic to subscribe to").Required().String()
	chanPubMsg  = chanPub.Arg("data", "Data to send").Required().Strings()
)

func main() {

	// Enable -h as HelpFlag
	app.HelpFlag.Short('h')
	app.UsageTemplate(kingpin.CompactUsageTemplate)

	parsed := kingpin.MustParse(app.Parse(os.Args[1:]))

	if nc, err := nxcli.Dial(*serverIP, nil); err == nil {
		if _, err := nc.Login(*user, *pass); err != nil {
			log.Println("Couldn't login:", err)
			return
		} else {
			log.Println("Logged as", *user)
		}

		execCmd(nc, parsed)
	} else {
		log.Println("Cannot connect to", *serverIP)
	}
}

func execCmd(nc *nexus.NexusConn, parsed string) {
	switch parsed {

	case login.FullCommand():
		if _, err := nc.Login(*loginName, *loginPass); err != nil {
			log.Println("Couldn't login:", err)
			return
		} else {
			log.Println("Logged as", *loginName)
			user = loginName
		}

	case push.FullCommand():
		if ret, err := nc.TaskPush(*pushMethod, *pushParams, time.Second*time.Duration(*timeout)); err != nil {
			log.Println("Error:", err)
			return
		} else {
			b, _ := json.MarshalIndent(ret, "", "  ")
			log.Println("Result:")
			if s, err := strconv.Unquote(string(b)); err == nil {
				fmt.Println(s)
			} else {
				fmt.Println(string(b))
			}
		}

	case pull.FullCommand():
		log.Println("Pulling", *pullMethod)
		ret, err := nc.TaskPull(*pullMethod, time.Second*time.Duration(*timeout))
		if err != nil {
			log.Println("Error:", err)
			return
		} else {
			b, _ := json.MarshalIndent(ret, "", "  ")
			fmt.Println(string(b))
		}

		fmt.Printf("[R]esult or [E]rror? ")

		stdin := bufio.NewScanner(os.Stdin)

		if stdin.Scan() && strings.HasPrefix(strings.ToLower(stdin.Text()), "e") {
			fmt.Printf("Code: ")
			stdin.Scan()
			code, _ := strconv.Atoi(stdin.Text())

			fmt.Printf("Message: ")
			stdin.Scan()
			msg := stdin.Text()

			fmt.Printf("Data: ")
			stdin.Scan()
			data := stdin.Text()

			ret.SendError(code, msg, data)

		} else {
			fmt.Printf("Result: ")
			if stdin.Scan() {
				ret.SendResult(stdin.Text())
			} else {
				ret.SendResult("dummy response")
			}
		}

	case pipeWrite.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *pipeWriteData = []string{} }()

		if pipe, err := nc.PipeOpen(*pipeWriteId); err != nil {
			log.Println(err)
			return
		} else {

			if _, err := pipe.Write(*pipeWriteData); err != nil {
				log.Println(err)
				return
			} else {
				log.Println("Sent!")
			}
		}

	case pipeRead.FullCommand():
		popts := nexus.PipeOpts{Length: 100}

		if pipe, err := nc.PipeCreate(&popts); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("Pipe created:", pipe.Id())
			for {
				if pdata, err := pipe.Read(10, time.Second*time.Duration(*timeout)); err != nil {
					log.Println(err)
					time.Sleep(time.Second)
				} else {
					for _, msg := range pdata.Msgs {
						log.Println("Got:", msg.Msg, msg.Count)
					}
					fmt.Printf("There are %d messages left in the pipe and %d drops\n", pdata.Waiting, pdata.Drops)
				}
			}
		}

	case userCreate.FullCommand():
		log.Printf("Creating user \"%s\" with password \"%s\"", *userCreateName, *userCreatePass)
		if _, err := nc.UserCreate(*userCreateName, *userCreatePass); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case userDelete.FullCommand():
		log.Printf("Deleting user \"%s\"", *userDeleteName)

		if _, err := nc.UserDelete(*userDeleteName); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case userPass.FullCommand():
		if _, err := nc.UserSetPass(*userPassName, *userPassPass); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case tagsSet.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *tagsSetTags = make(map[string]string) }()

		var tags map[string]interface{}
		if b, err := json.Marshal(*tagsSetTags); err == nil {
			if json.Unmarshal(b, &tags) != nil {
				log.Println("Error parsing tags")
				return
			}
		}

		log.Printf("Setting tags: %v on %s@%s", tags, *tagsSetUser, *tagsSetPrefix)
		if _, err := nc.UserSetTags(*tagsSetUser, *tagsSetPrefix, tags); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case tagsDel.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *tagsDelTags = []string{} }()

		if _, err := nc.UserDelTags(*tagsDelUser, *tagsDelPrefix, *tagsDelTags); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case shell.FullCommand():

		args := os.Args[1:]
		for k, v := range args {
			if v == shell.FullCommand() {
				args = append(args[:k], args[k+1:]...)
			}
		}

		s := bufio.NewScanner(os.Stdin)
		fmt.Printf("%s@%s >> ", *user, *serverIP)
		for s.Scan() {
			cmd, err := app.Parse(append(args, strings.Split(s.Text(), " ")...))
			if err == nil {
				if cmd != shell.FullCommand() {
					parsed := kingpin.MustParse(cmd, err)
					execCmd(nc, parsed)
				}
			} else {
				log.Println(err)
			}
			fmt.Printf("%s@%s >> ", *user, *serverIP)
		}

		if err := s.Err(); err != nil {
			log.Fatalln("reading standard input:", err)
		}

	case chanSub.FullCommand():
		if pipe, err := nc.PipeOpen(*chanSubPipe); err != nil {
			log.Println(err)
			return
		} else {
			if _, err := nc.TopicSubscribe(pipe, *chanSubChan); err != nil {
				log.Println(err)
				return
			} else {
				log.Println("OK")
			}
		}

	case chanUnsub.FullCommand():
		if pipe, err := nc.PipeOpen(*chanSubPipe); err != nil {
			log.Println(err)
			return
		} else {
			if _, err := nc.TopicUnsubscribe(pipe, *chanUnsubChan); err != nil {
				log.Println(err)
				return
			} else {
				log.Println("OK")
			}
		}

	case chanPub.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *chanPubMsg = []string{} }()

		fmt.Println(*chanPubMsg)
		if res, err := nc.TopicPublish(*chanPubChan, *chanPubMsg); err != nil {
			log.Println(err)
			return
		} else {
			log.Println(res)

		}
	}
}
<commit_msg>demos, cli: Fix adding tags with @<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	nxcli "github.com/jaracil/nxcli"
	nexus "github.com/jaracil/nxcli/nxcore"
	"github.com/nayarsystems/kingpin"
)

var (
	app      = kingpin.New("cli", "Nexus command line interface")
	serverIP = app.Flag("server", "Server address.").Default("127.0.0.1:1717").Short('s').String()
	timeout  = app.Flag("timeout", "Execution timeout").Default("60").Short('t').Int()
	user     = app.Flag("user", "Nexus username").Short('u').Default("test").String()
	pass     = app.Flag("pass", "Nexus password").Default("test").Short('p').String()

	///

	shell = app.Command("shell", "Interactive shell")

	///

	login     = app.Command("login", "Tests to login with an username/password and exits")
	loginName = login.Arg("username", "username").Required().String()
	loginPass = login.Arg("password", "password").Required().String()

	///

	push       = app.Command("push", "Execute a task.push rpc call on Nexus")
	pushMethod = push.Arg("method", "Method to call").Required().String()
	pushParams = push.Arg("params", "parameters").StringMap()

	pull       = app.Command("pull", "Execute a task.pull rpc call on Nexus")
	pullMethod = pull.Arg("prefix", "Method to call").Required().String()

	///

	pipeCmd = app.Command("pipe", "Pipe tasks")

	pipeRead = pipeCmd.Command("read", "Create and read from a pipe. It will be destroyed on exit")

	pipeWrite     = pipeCmd.Command("open", "Open a pipe and send data")
	pipeWriteId   = pipeWrite.Arg("pipeId", "ID of the pipe to write to").Required().String()
	pipeWriteData = pipeWrite.Arg("data", "Data to write to the pipe").Required().Strings()

	///

	userCmd = app.Command("user", "user management")

	userCreate     = userCmd.Command("create", "Create a new user")
	userCreateName = userCreate.Arg("username", "username").Required().String()
	userCreatePass = userCreate.Arg("password", "password").Required().String()

	userDelete     = userCmd.Command("delete", "Delete an user")
	userDeleteName = userDelete.Arg("username", "username").Required().String()

	userPass     = userCmd.Command("passwd", "Change an user password")
	userPassName = userPass.Arg("username", "username").Required().String()
	userPassPass = userPass.Arg("password", "password").Required().String()

	///

	tagsCmd = app.Command("tags", "tags management")

	tagsSet       = tagsCmd.Command("set", "Set tags for an user on a prefix. Tags is a map like 'tag:value tag2:value2'")
	tagsSetUser   = tagsSet.Arg("user", "user").Required().String()
	tagsSetPrefix = tagsSet.Arg("prefix", "prefix").Required().String()
	tagsSetTags   = tagsSet.Arg("tags", "tag:value").StringMapIface()

	tagsSetJ         = tagsCmd.Command("setj", "Set tags for an user on a prefix. Tags is a json dict like: { 'tag': value }")
	tagsSetJUser     = tagsSetJ.Arg("user", "user").Required().String()
	tagsSetJPrefix   = tagsSetJ.Arg("prefix", "prefix").Required().String()
	tagsSetJTagsJson = tagsSetJ.Arg("tags", "{'@task.push': true}").Required().String()

	tagsDel       = tagsCmd.Command("del", "delete tags for an user on a prefix. Tags is a list of space separated strings")
	tagsDelUser   = tagsDel.Arg("user", "user").Required().String()
	tagsDelPrefix = tagsDel.Arg("prefix", "prefix").Required().String()
	tagsDelTags   = tagsDel.Arg("tags", "tag1 tag2 tag3").Required().Strings()

	//

	chanCmd = app.Command("topic", "Topics management")

	chanSub     = chanCmd.Command("sub", "Subscribe a pipe to a topic")
	chanSubPipe = chanSub.Arg("pipe", "pipe id to subscribe").Required().String()
	chanSubChan = chanSub.Arg("topic", "Topic to subscribe to").Required().String()

	chanUnsub     = chanCmd.Command("unsub", "Unsubscribe a pipe from a topic")
	chanUnsubPipe = chanUnsub.Arg("pipe", "pipe id to subscribe").Required().String()
	chanUnsubChan = chanUnsub.Arg("topic", "Topic to subscribe to").Required().String()

	chanPub     = chanCmd.Command("pub", "Publish a message to a topic")
	chanPubChan = chanPub.Arg("topic", "Topic to subscribe to").Required().String()
	chanPubMsg  = chanPub.Arg("data", "Data to send").Required().Strings()
)

func main() {

	// Enable -h as HelpFlag
	app.HelpFlag.Short('h')
	//	/app.UsageTemplate(kingpin.CompactUsageTemplate)

	parsed := kingpin.MustParse(app.Parse(os.Args[1:]))

	if nc, err := nxcli.Dial(*serverIP, nil); err == nil {
		if _, err := nc.Login(*user, *pass); err != nil {
			log.Println("Couldn't login:", err)
			return
		} else {
			log.Println("Logged as", *user)
		}

		execCmd(nc, parsed)
	} else {
		log.Println("Cannot connect to", *serverIP)
	}
}

func execCmd(nc *nexus.NexusConn, parsed string) {
	switch parsed {

	case login.FullCommand():
		if _, err := nc.Login(*loginName, *loginPass); err != nil {
			log.Println("Couldn't login:", err)
			return
		} else {
			log.Println("Logged as", *loginName)
			user = loginName
		}

	case push.FullCommand():
		if ret, err := nc.TaskPush(*pushMethod, *pushParams, time.Second*time.Duration(*timeout)); err != nil {
			log.Println("Error:", err)
			return
		} else {
			b, _ := json.MarshalIndent(ret, "", "  ")
			log.Println("Result:")
			if s, err := strconv.Unquote(string(b)); err == nil {
				fmt.Println(s)
			} else {
				fmt.Println(string(b))
			}
		}

	case pull.FullCommand():
		log.Println("Pulling", *pullMethod)
		ret, err := nc.TaskPull(*pullMethod, time.Second*time.Duration(*timeout))
		if err != nil {
			log.Println("Error:", err)
			return
		} else {
			b, _ := json.MarshalIndent(ret, "", "  ")
			fmt.Println(string(b))
		}

		fmt.Printf("[R]esult or [E]rror? ")

		stdin := bufio.NewScanner(os.Stdin)

		if stdin.Scan() && strings.HasPrefix(strings.ToLower(stdin.Text()), "e") {
			fmt.Printf("Code: ")
			stdin.Scan()
			code, _ := strconv.Atoi(stdin.Text())

			fmt.Printf("Message: ")
			stdin.Scan()
			msg := stdin.Text()

			fmt.Printf("Data: ")
			stdin.Scan()
			data := stdin.Text()

			ret.SendError(code, msg, data)

		} else {
			fmt.Printf("Result: ")
			if stdin.Scan() {
				ret.SendResult(stdin.Text())
			} else {
				ret.SendResult("dummy response")
			}
		}

	case pipeWrite.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *pipeWriteData = []string{} }()

		if pipe, err := nc.PipeOpen(*pipeWriteId); err != nil {
			log.Println(err)
			return
		} else {

			if _, err := pipe.Write(*pipeWriteData); err != nil {
				log.Println(err)
				return
			} else {
				log.Println("Sent!")
			}
		}

	case pipeRead.FullCommand():
		popts := nexus.PipeOpts{Length: 100}

		if pipe, err := nc.PipeCreate(&popts); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("Pipe created:", pipe.Id())
			for {
				if pdata, err := pipe.Read(10, time.Second*time.Duration(*timeout)); err != nil {
					log.Println(err)
					time.Sleep(time.Second)
				} else {
					for _, msg := range pdata.Msgs {
						log.Println("Got:", msg.Msg, msg.Count)
					}
					fmt.Printf("There are %d messages left in the pipe and %d drops\n", pdata.Waiting, pdata.Drops)
				}
			}
		}

	case userCreate.FullCommand():
		log.Printf("Creating user \"%s\" with password \"%s\"", *userCreateName, *userCreatePass)
		if _, err := nc.UserCreate(*userCreateName, *userCreatePass); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case userDelete.FullCommand():
		log.Printf("Deleting user \"%s\"", *userDeleteName)

		if _, err := nc.UserDelete(*userDeleteName); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case userPass.FullCommand():
		if _, err := nc.UserSetPass(*userPassName, *userPassPass); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case tagsSet.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *tagsSetTags = make(map[string]interface{}) }()

		var tags map[string]interface{}
		if b, err := json.Marshal(*tagsSetTags); err == nil {
			if json.Unmarshal(b, &tags) != nil {
				log.Println("Error parsing tags")
				return
			}
		}

		log.Printf("Setting tags: %v on %s@%s", tags, *tagsSetUser, *tagsSetPrefix)
		if _, err := nc.UserSetTags(*tagsSetUser, *tagsSetPrefix, tags); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case tagsSetJ.FullCommand():
		// Clean afterwards in case we are looping on shell mode

		var tags map[string]interface{}
		if json.Unmarshal([]byte(*tagsSetJTagsJson), &tags) != nil {
			log.Println("Error parsing tags json:", *tagsSetJTagsJson)
			return
		}

		log.Printf("Setting tags: %v on %s@%s", tags, *tagsSetJUser, *tagsSetJPrefix)
		if _, err := nc.UserSetTags(*tagsSetJUser, *tagsSetJPrefix, tags); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case tagsDel.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *tagsDelTags = []string{} }()

		if _, err := nc.UserDelTags(*tagsDelUser, *tagsDelPrefix, *tagsDelTags); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("OK")
		}

	case shell.FullCommand():

		args := os.Args[1:]
		for k, v := range args {
			if v == shell.FullCommand() {
				args = append(args[:k], args[k+1:]...)
			}
		}

		s := bufio.NewScanner(os.Stdin)
		fmt.Printf("%s@%s >> ", *user, *serverIP)
		for s.Scan() {
			cmd, err := app.Parse(append(args, strings.Split(s.Text(), " ")...))
			if err == nil {
				if cmd != shell.FullCommand() {
					parsed := kingpin.MustParse(cmd, err)
					execCmd(nc, parsed)
				}
			} else {
				log.Println(err)
			}
			fmt.Printf("%s@%s >> ", *user, *serverIP)
		}

		if err := s.Err(); err != nil {
			log.Fatalln("reading standard input:", err)
		}

	case chanSub.FullCommand():
		if pipe, err := nc.PipeOpen(*chanSubPipe); err != nil {
			log.Println(err)
			return
		} else {
			if _, err := nc.TopicSubscribe(pipe, *chanSubChan); err != nil {
				log.Println(err)
				return
			} else {
				log.Println("OK")
			}
		}

	case chanUnsub.FullCommand():
		if pipe, err := nc.PipeOpen(*chanSubPipe); err != nil {
			log.Println(err)
			return
		} else {
			if _, err := nc.TopicUnsubscribe(pipe, *chanUnsubChan); err != nil {
				log.Println(err)
				return
			} else {
				log.Println("OK")
			}
		}

	case chanPub.FullCommand():
		// Clean afterwards in case we are looping on shell mode
		defer func() { *chanPubMsg = []string{} }()

		if res, err := nc.TopicPublish(*chanPubChan, *chanPubMsg); err != nil {
			log.Println(err)
			return
		} else {
			log.Println("Result:", res)

		}
	}
}
<|endoftext|>