<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/zenazn/goji/web"
)

type ScriptRequest struct {
	ID          int
	Script      string            `json:"script"`
	Args        []string          `json:"args"`
	Files       map[string]string `json:"files"`
	CallbackURL string            `json:"callback_url"`
}

// Handle the root route, also useful as a heartbeat.
func ServiceRoot(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		body, err := ioutil.ReadAll(r.Body)
		if err == nil {
			log.Info("Callback: %s", body)
		}
	}
	w.Write([]byte("."))
}

// Get a list of all the scripts in script folder.
func GetAllScripts(w http.ResponseWriter, r *http.Request) {

	// Open and parse whitelist
	p := path.Join(config.Worker.ScriptDir, config.Worker.WhiteList)
	file, err := os.Open(p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	scanner.Scan()
	list := make([]string, 0)
	for scanner.Scan() {
		list = append(list, fmt.Sprintf("\"%s\"", scanner.Text()))
	}
	var buf bytes.Buffer
	buf.WriteString("[")
	buf.WriteString(strings.Join(list, ", "))
	buf.WriteString("]")

	w.Header().Set("Content-Type", "application/json")
	w.Write(buf.Bytes())
}

// Reload the whitelist of scripts.
func ReloadScripts(w http.ResponseWriter, r *http.Request) {
	p := path.Join(config.Worker.ScriptDir, config.Worker.WhiteList)

	doneChan := make(chan *nsq.ProducerTransaction)
	err := producer.PublishAsync("reload", []byte(p), doneChan)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	<-doneChan

	var buf bytes.Buffer
	buf.WriteString("Reload request sent")

	w.Header().Set("Content-Type", "application/json")
	w.Write(buf.Bytes())
}

// Send details to queue for execution.
func RunScript(c web.C, w http.ResponseWriter, r *http.Request) {
	// Parse the request
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var sr ScriptRequest
	err = json.Unmarshal(body, &sr)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	id, err := getRedisID()
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	sr.ID = id
	sr.Script = c.URLParams["name"]

	// Queue up the request
	doneChan := make(chan *nsq.ProducerTransaction)
	data, err := json.Marshal(sr)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = producer.PublishAsync(config.Topic, data, doneChan)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	<-doneChan
	log.Info("Request queued as %d", sr.ID)

	w.Header().Set("Content-Type", "application/json")
	w.Write(data)
}

// Retrieve all logs for a specific script.
func GetAllLogs(c web.C, w http.ResponseWriter, r *http.Request) {
	conn := redisDB.Get()
	defer conn.Close()

	// LRANGE returns an array of json strings
	reply, err := redis.Strings(conn.Do("ZRANGE", c.URLParams["name"], 0, -1))
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var buf bytes.Buffer
	buf.WriteString("[")

	length := len(reply)
	if length > 0 {
		buf.WriteString(reply[length-1])
		for i := length - 2; i > 0; i-- {
			buf.WriteString(", ")
			buf.WriteString(reply[i])
		}
	}
	buf.WriteString("]")
	w.Header().Set("Content-Type", "application/json")
	w.Write(buf.Bytes())
}

// Retrieve a specific log of a specific script.
func GetLog(c web.C, w http.ResponseWriter, r *http.Request) {
	conn := redisDB.Get()
	defer conn.Close()

	script := c.URLParams["name"]
	id := c.URLParams["id"]

	reply, err := redis.Strings(conn.Do("ZRANGEBYSCORE", script, id, id))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(reply[0]))
}
<commit_msg>Fixed the JSON syntax for ScriptRequests<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/zenazn/goji/web"
)

type ScriptRequest struct {
	ID          int               `json:"id"`
	Script      string            `json:"script"`
	Args        []string          `json:"args,omitempty"`
	Files       map[string]string `json:"files,omitempty"`
	CallbackURL string            `json:"callback_url"`
}

// Handle the root route, also useful as a heartbeat.
func ServiceRoot(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		body, err := ioutil.ReadAll(r.Body)
		if err == nil {
			log.Info("Callback: %s", body)
		}
	}
	w.Write([]byte("."))
}

// Get a list of all the scripts in script folder.
func GetAllScripts(w http.ResponseWriter, r *http.Request) {

	// Open and parse whitelist
	p := path.Join(config.Worker.ScriptDir, config.Worker.WhiteList)
	file, err := os.Open(p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	scanner.Scan()
	list := make([]string, 0)
	for scanner.Scan() {
		list = append(list, fmt.Sprintf("\"%s\"", scanner.Text()))
	}
	var buf bytes.Buffer
	buf.WriteString("[")
	buf.WriteString(strings.Join(list, ", "))
	buf.WriteString("]")

	w.Header().Set("Content-Type", "application/json")
	w.Write(buf.Bytes())
}

// Reload the whitelist of scripts.
func ReloadScripts(w http.ResponseWriter, r *http.Request) {
	p := path.Join(config.Worker.ScriptDir, config.Worker.WhiteList)

	doneChan := make(chan *nsq.ProducerTransaction)
	err := producer.PublishAsync("reload", []byte(p), doneChan)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	<-doneChan

	var buf bytes.Buffer
	buf.WriteString("Reload request sent")

	w.Header().Set("Content-Type", "application/json")
	w.Write(buf.Bytes())
}

// Send details to queue for execution.
func RunScript(c web.C, w http.ResponseWriter, r *http.Request) {
	// Parse the request
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var sr ScriptRequest
	err = json.Unmarshal(body, &sr)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	id, err := getRedisID()
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	sr.ID = id
	sr.Script = c.URLParams["name"]

	// Queue up the request
	doneChan := make(chan *nsq.ProducerTransaction)
	data, err := json.Marshal(sr)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = producer.PublishAsync(config.Topic, data, doneChan)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	<-doneChan
	log.Info("Request queued as %d", sr.ID)

	w.Header().Set("Content-Type", "application/json")
	w.Write(data)
}

// Retrieve all logs for a specific script.
func GetAllLogs(c web.C, w http.ResponseWriter, r *http.Request) {
	conn := redisDB.Get()
	defer conn.Close()

	// LRANGE returns an array of json strings
	reply, err := redis.Strings(conn.Do("ZRANGE", c.URLParams["name"], 0, -1))
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var buf bytes.Buffer
	buf.WriteString("[")

	length := len(reply)
	if length > 0 {
		buf.WriteString(reply[length-1])
		for i := length - 2; i > 0; i-- {
			buf.WriteString(", ")
			buf.WriteString(reply[i])
		}
	}
	buf.WriteString("]")
	w.Header().Set("Content-Type", "application/json")
	w.Write(buf.Bytes())
}

// Retrieve a specific log of a specific script.
func GetLog(c web.C, w http.ResponseWriter, r *http.Request) {
	conn := redisDB.Get()
	defer conn.Close()

	script := c.URLParams["name"]
	id := c.URLParams["id"]

	reply, err := redis.Strings(conn.Do("ZRANGEBYSCORE", script, id, id))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(reply[0]))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/robustirc/robustirc/ircserver"
	"github.com/robustirc/robustirc/types"

	"github.com/gorilla/mux"
	"github.com/hashicorp/raft"
)

var (
	GetMessageRequests = make(map[string]GetMessageStats)
)

type GetMessageStats struct {
	Session types.RobustId
	Nick    string
	Started time.Time
}

func (stats GetMessageStats) StartedAndRelative() string {
	return stats.Started.Format("2006-01-02 15:04:05 -07:00") + " (" +
		time.Now().Round(time.Second).Sub(stats.Started.Round(time.Second)).String() + " ago)"
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error {
	return nil
}

func maybeProxyToLeader(w http.ResponseWriter, r *http.Request, body io.ReadCloser) {
	leader := node.Leader()
	if leader == nil {
		http.Error(w, fmt.Sprintf("No leader known. Please try another server."),
			http.StatusInternalServerError)
		return
	}
	u, err := url.Parse("https://" + leader.String())
	if err != nil {
		http.Error(w, fmt.Sprintf("url.Parse(): %v", err), http.StatusInternalServerError)
		return
	}
	log.Printf("Proxying request to leader %q\n", leader.String())
	location := *r.URL
	location.Host = leader.String()
	w.Header().Set("Content-Location", location.String())
	p := httputil.NewSingleHostReverseProxy(u)
	r.Body = body
	p.ServeHTTP(w, r)
}

func sessionForRequest(r *http.Request) (*ircserver.Session, types.RobustId, error) {
	idstr := mux.Vars(r)["sessionid"]
	id, err := strconv.ParseInt(idstr, 0, 64)
	if err != nil {
		return nil, types.RobustId{}, fmt.Errorf("Invalid session: %v", err)
	}

	session := types.RobustId{Id: id}
	s, ok := ircserver.GetSession(session)
	if !ok {
		return nil, types.RobustId{}, fmt.Errorf("No such session")
	}

	cookie := r.Header.Get("X-Session-Auth")
	if cookie == "" {
		return nil, types.RobustId{}, fmt.Errorf("No SessionAuth cookie set")
	}
	if cookie != s.Auth {
		return nil, types.RobustId{}, fmt.Errorf("Invalid SessionAuth cookie")
	}

	return s, session, nil
}

// handlePostMessage is called by the robustirc-brigde whenever a message should be
// posted. The handler blocks until either the data was written or an error
// occurred. If successful, it returns the unique id of the message.
func handlePostMessage(w http.ResponseWriter, r *http.Request) {
	s, session, err := sessionForRequest(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	type postMessageRequest struct {
		Data            string
		ClientMessageId int
	}

	var req postMessageRequest

	// We limit the amount of bytes read to 1024 to prevent reading overly long
	// requests in the first place. The IRC line length limit is 512 bytes, so
	// with 1024 bytes we have plenty of headroom to encode 512 bytes in JSON.
	//
	// We save a copy of the request in case we need to proxy it to the leader.
	var body bytes.Buffer
	rd := io.TeeReader(&io.LimitedReader{r.Body, 1024}, &body)
	if err := json.NewDecoder(rd).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// If we have already seen this message, we just reply with a canned response.
	if req.ClientMessageId == s.LastClientMessageId && s.LastPostMessageReply != nil {
		w.Header().Set("Content-Type", "application/json")
		w.Write(s.LastPostMessageReply)
		return
	}

	msg := types.NewRobustMessage(types.RobustIRCFromClient, session, req.Data)
	msg.ClientMessageId = req.ClientMessageId
	msgbytes, err := json.Marshal(msg)
	if err != nil {
		http.Error(w, fmt.Sprintf("Could not store message, cannot encode it as JSON: %v", err),
			http.StatusInternalServerError)
		return
	}

	f := node.Apply(msgbytes, 10*time.Second)
	if err := f.Error(); err != nil {
		if err == raft.ErrNotLeader {
			maybeProxyToLeader(w, r, nopCloser{&body})
			return
		}
		http.Error(w, fmt.Sprintf("Apply(): %v", err), http.StatusInternalServerError)
		return
	}

	s.LastPostMessageReply = msgbytes
	s.LastClientMessageId = req.ClientMessageId
	w.Header().Set("Content-Type", "application/json")
	w.Write(msgbytes)
}

func handleJoin(w http.ResponseWriter, r *http.Request) {
	log.Println("Join request from", r.RemoteAddr)
	if node.State() != raft.Leader {
		maybeProxyToLeader(w, r, r.Body)
		return
	}

	type joinRequest struct {
		Addr string
	}
	var req joinRequest

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		log.Println("Could not decode request:", err)
		http.Error(w, fmt.Sprintf("Could not decode your request"), 400)
		return
	}

	log.Printf("Adding peer %q to the network.\n", req.Addr)

	if err := node.AddPeer(&dnsAddr{req.Addr}).Error(); err != nil {
		log.Println("Could not add peer:", err)
		http.Error(w, "Could not add peer", 500)
		return
	}
}

func handleSnapshot(res http.ResponseWriter, req *http.Request) {
	log.Printf("snapshotting()\n")
	node.Snapshot()
	log.Println("snapshotted")
}

func handleGetMessages(w http.ResponseWriter, r *http.Request) {
	s, session, err := sessionForRequest(r)
	if err != nil {
		log.Printf("invalid session: %v", err)
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	remoteAddr := r.RemoteAddr
	GetMessageRequests[remoteAddr] = GetMessageStats{
		Session: session,
		Nick:    s.Nick,
		Started: time.Now(),
	}
	defer func() {
		delete(GetMessageRequests, remoteAddr)
	}()

	lastSeen := s.StartId
	lastSeenStr := r.FormValue("lastseen")
	if lastSeenStr != "0.0" {
		parts := strings.Split(lastSeenStr, ".")
		if len(parts) != 2 {
			log.Printf("cannot parse %q\n", lastSeenStr)
			http.Error(w, fmt.Sprintf("Malformed lastseen value (%q)", lastSeenStr),
				http.StatusInternalServerError)
			return
		}
		first, err := strconv.ParseInt(parts[0], 0, 64)
		if err != nil {
			log.Printf("cannot parse %q\n", lastSeenStr)
			http.Error(w, fmt.Sprintf("Malformed lastseen value (%q)", lastSeenStr),
				http.StatusInternalServerError)
			return
		}
		last, err := strconv.ParseInt(parts[1], 0, 64)
		if err != nil {
			log.Printf("cannot parse %q\n", lastSeenStr)
			http.Error(w, fmt.Sprintf("Malformed lastseen value (%q)", lastSeenStr),
				http.StatusInternalServerError)
			return
		}
		lastSeen = types.RobustId{
			Id:    first,
			Reply: last,
		}
		log.Printf("Trying to resume at %v\n", lastSeen)
	}

	enc := json.NewEncoder(w)
	for {
		msg := ircserver.GetMessage(lastSeen)
		s, ok := ircserver.GetSession(session)
		if !ok {
			// Session was deleted in the meanwhile.
			break
		}

		lastSeen = msg.Id

		interested := s.InterestedIn(msg)
		log.Printf("[DEBUG] Checking whether %+v is interested in %+v --> %v\n", s, msg, interested)
		if !interested {
			continue
		}

		if err := enc.Encode(msg); err != nil {
			log.Printf("Error encoding JSON: %v\n", err)
			return
		}

		if f, ok := w.(http.Flusher); ok {
			f.Flush()
		}
	}
}

func handleCreateSession(w http.ResponseWriter, r *http.Request) {
	b := make([]byte, 128)
	if _, err := rand.Read(b); err != nil {
		http.Error(w, fmt.Sprintf("Cannot generate SessionAuth cookie: %v", err), http.StatusInternalServerError)
		return
	}
	sessionauth := fmt.Sprintf("%x", b)
	msg := types.NewRobustMessage(types.RobustCreateSession, types.RobustId{}, sessionauth)
	// Cannot fail, no user input.
	msgbytes, _ := json.Marshal(msg)

	f := node.Apply(msgbytes, 10*time.Second)
	if err := f.Error(); err != nil {
		if err == raft.ErrNotLeader {
			maybeProxyToLeader(w, r, nopCloser{bytes.NewBuffer(nil)})
			return
		}
		http.Error(w, fmt.Sprintf("Apply(): %v", err), http.StatusInternalServerError)
		return
	}

	sessionid := fmt.Sprintf("0x%x", msg.Id.Id)

	w.Header().Set("Content-Type", "application/json")

	type createSessionReply struct {
		Sessionid   string
		Sessionauth string
		Prefix      string
	}

	if err := json.NewEncoder(w).Encode(createSessionReply{sessionid, sessionauth, *network}); err != nil {
		log.Printf("Could not send /session reply: %v\n", err)
	}
}

func handleDeleteSession(w http.ResponseWriter, r *http.Request) {
	_, session, err := sessionForRequest(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	type deleteSessionRequest struct {
		Quitmessage string
	}

	var req deleteSessionRequest
	var body bytes.Buffer
	rd := io.TeeReader(r.Body, &body)
	if err := json.NewDecoder(rd).Decode(&req); err != nil {
		http.Error(w, fmt.Sprintf("Could not decode request: %v", err), http.StatusInternalServerError)
		return
	}

	msg := types.NewRobustMessage(types.RobustDeleteSession, session, req.Quitmessage)
	// Cannot fail, no user input.
	msgbytes, _ := json.Marshal(msg)

	f := node.Apply(msgbytes, 10*time.Second)
	if err := f.Error(); err != nil {
		if err == raft.ErrNotLeader {
			maybeProxyToLeader(w, r, nopCloser{&body})
			return
		}
		http.Error(w, fmt.Sprintf("Apply(): %v", err), http.StatusInternalServerError)
		return
	}
}
<commit_msg>don’t fail the /join HTTP request when the peer is already known<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/robustirc/robustirc/ircserver"
	"github.com/robustirc/robustirc/types"

	"github.com/gorilla/mux"
	"github.com/hashicorp/raft"
)

var (
	GetMessageRequests = make(map[string]GetMessageStats)
)

type GetMessageStats struct {
	Session types.RobustId
	Nick    string
	Started time.Time
}

func (stats GetMessageStats) StartedAndRelative() string {
	return stats.Started.Format("2006-01-02 15:04:05 -07:00") + " (" +
		time.Now().Round(time.Second).Sub(stats.Started.Round(time.Second)).String() + " ago)"
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error {
	return nil
}

func maybeProxyToLeader(w http.ResponseWriter, r *http.Request, body io.ReadCloser) {
	leader := node.Leader()
	if leader == nil {
		http.Error(w, fmt.Sprintf("No leader known. Please try another server."),
			http.StatusInternalServerError)
		return
	}
	u, err := url.Parse("https://" + leader.String())
	if err != nil {
		http.Error(w, fmt.Sprintf("url.Parse(): %v", err), http.StatusInternalServerError)
		return
	}
	log.Printf("Proxying request to leader %q\n", leader.String())
	location := *r.URL
	location.Host = leader.String()
	w.Header().Set("Content-Location", location.String())
	p := httputil.NewSingleHostReverseProxy(u)
	r.Body = body
	p.ServeHTTP(w, r)
}

func sessionForRequest(r *http.Request) (*ircserver.Session, types.RobustId, error) {
	idstr := mux.Vars(r)["sessionid"]
	id, err := strconv.ParseInt(idstr, 0, 64)
	if err != nil {
		return nil, types.RobustId{}, fmt.Errorf("Invalid session: %v", err)
	}

	session := types.RobustId{Id: id}
	s, ok := ircserver.GetSession(session)
	if !ok {
		return nil, types.RobustId{}, fmt.Errorf("No such session")
	}

	cookie := r.Header.Get("X-Session-Auth")
	if cookie == "" {
		return nil, types.RobustId{}, fmt.Errorf("No SessionAuth cookie set")
	}
	if cookie != s.Auth {
		return nil, types.RobustId{}, fmt.Errorf("Invalid SessionAuth cookie")
	}

	return s, session, nil
}

// handlePostMessage is called by the robustirc-brigde whenever a message should be
// posted. The handler blocks until either the data was written or an error
// occurred. If successful, it returns the unique id of the message.
func handlePostMessage(w http.ResponseWriter, r *http.Request) {
	s, session, err := sessionForRequest(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	type postMessageRequest struct {
		Data            string
		ClientMessageId int
	}

	var req postMessageRequest

	// We limit the amount of bytes read to 1024 to prevent reading overly long
	// requests in the first place. The IRC line length limit is 512 bytes, so
	// with 1024 bytes we have plenty of headroom to encode 512 bytes in JSON.
	//
	// We save a copy of the request in case we need to proxy it to the leader.
	var body bytes.Buffer
	rd := io.TeeReader(&io.LimitedReader{r.Body, 1024}, &body)
	if err := json.NewDecoder(rd).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// If we have already seen this message, we just reply with a canned response.
	if req.ClientMessageId == s.LastClientMessageId && s.LastPostMessageReply != nil {
		w.Header().Set("Content-Type", "application/json")
		w.Write(s.LastPostMessageReply)
		return
	}

	msg := types.NewRobustMessage(types.RobustIRCFromClient, session, req.Data)
	msg.ClientMessageId = req.ClientMessageId
	msgbytes, err := json.Marshal(msg)
	if err != nil {
		http.Error(w, fmt.Sprintf("Could not store message, cannot encode it as JSON: %v", err),
			http.StatusInternalServerError)
		return
	}

	f := node.Apply(msgbytes, 10*time.Second)
	if err := f.Error(); err != nil {
		if err == raft.ErrNotLeader {
			maybeProxyToLeader(w, r, nopCloser{&body})
			return
		}
		http.Error(w, fmt.Sprintf("Apply(): %v", err), http.StatusInternalServerError)
		return
	}

	s.LastPostMessageReply = msgbytes
	s.LastClientMessageId = req.ClientMessageId
	w.Header().Set("Content-Type", "application/json")
	w.Write(msgbytes)
}

func handleJoin(w http.ResponseWriter, r *http.Request) {
	log.Println("Join request from", r.RemoteAddr)
	if node.State() != raft.Leader {
		maybeProxyToLeader(w, r, r.Body)
		return
	}

	type joinRequest struct {
		Addr string
	}
	var req joinRequest

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		log.Println("Could not decode request:", err)
		http.Error(w, fmt.Sprintf("Could not decode your request"), 400)
		return
	}

	log.Printf("Adding peer %q to the network.\n", req.Addr)

	if err := node.AddPeer(&dnsAddr{req.Addr}).Error(); err != nil && err != raft.ErrKnownPeer {
		log.Println("Could not add peer:", err)
		http.Error(w, "Could not add peer", 500)
		return
	}
}

func handleSnapshot(res http.ResponseWriter, req *http.Request) {
	log.Printf("snapshotting()\n")
	node.Snapshot()
	log.Println("snapshotted")
}

func handleGetMessages(w http.ResponseWriter, r *http.Request) {
	s, session, err := sessionForRequest(r)
	if err != nil {
		log.Printf("invalid session: %v", err)
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	remoteAddr := r.RemoteAddr
	GetMessageRequests[remoteAddr] = GetMessageStats{
		Session: session,
		Nick:    s.Nick,
		Started: time.Now(),
	}
	defer func() {
		delete(GetMessageRequests, remoteAddr)
	}()

	lastSeen := s.StartId
	lastSeenStr := r.FormValue("lastseen")
	if lastSeenStr != "0.0" {
		parts := strings.Split(lastSeenStr, ".")
		if len(parts) != 2 {
			log.Printf("cannot parse %q\n", lastSeenStr)
			http.Error(w, fmt.Sprintf("Malformed lastseen value (%q)", lastSeenStr),
				http.StatusInternalServerError)
			return
		}
		first, err := strconv.ParseInt(parts[0], 0, 64)
		if err != nil {
			log.Printf("cannot parse %q\n", lastSeenStr)
			http.Error(w, fmt.Sprintf("Malformed lastseen value (%q)", lastSeenStr),
				http.StatusInternalServerError)
			return
		}
		last, err := strconv.ParseInt(parts[1], 0, 64)
		if err != nil {
			log.Printf("cannot parse %q\n", lastSeenStr)
			http.Error(w, fmt.Sprintf("Malformed lastseen value (%q)", lastSeenStr),
				http.StatusInternalServerError)
			return
		}
		lastSeen = types.RobustId{
			Id:    first,
			Reply: last,
		}
		log.Printf("Trying to resume at %v\n", lastSeen)
	}

	enc := json.NewEncoder(w)
	for {
		msg := ircserver.GetMessage(lastSeen)
		s, ok := ircserver.GetSession(session)
		if !ok {
			// Session was deleted in the meanwhile.
			break
		}

		lastSeen = msg.Id

		interested := s.InterestedIn(msg)
		log.Printf("[DEBUG] Checking whether %+v is interested in %+v --> %v\n", s, msg, interested)
		if !interested {
			continue
		}

		if err := enc.Encode(msg); err != nil {
			log.Printf("Error encoding JSON: %v\n", err)
			return
		}

		if f, ok := w.(http.Flusher); ok {
			f.Flush()
		}
	}
}

func handleCreateSession(w http.ResponseWriter, r *http.Request) {
	b := make([]byte, 128)
	if _, err := rand.Read(b); err != nil {
		http.Error(w, fmt.Sprintf("Cannot generate SessionAuth cookie: %v", err), http.StatusInternalServerError)
		return
	}
	sessionauth := fmt.Sprintf("%x", b)
	msg := types.NewRobustMessage(types.RobustCreateSession, types.RobustId{}, sessionauth)
	// Cannot fail, no user input.
	msgbytes, _ := json.Marshal(msg)

	f := node.Apply(msgbytes, 10*time.Second)
	if err := f.Error(); err != nil {
		if err == raft.ErrNotLeader {
			maybeProxyToLeader(w, r, nopCloser{bytes.NewBuffer(nil)})
			return
		}
		http.Error(w, fmt.Sprintf("Apply(): %v", err), http.StatusInternalServerError)
		return
	}

	sessionid := fmt.Sprintf("0x%x", msg.Id.Id)

	w.Header().Set("Content-Type", "application/json")

	type createSessionReply struct {
		Sessionid   string
		Sessionauth string
		Prefix      string
	}

	if err := json.NewEncoder(w).Encode(createSessionReply{sessionid, sessionauth, *network}); err != nil {
		log.Printf("Could not send /session reply: %v\n", err)
	}
}

func handleDeleteSession(w http.ResponseWriter, r *http.Request) {
	_, session, err := sessionForRequest(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	type deleteSessionRequest struct {
		Quitmessage string
	}

	var req deleteSessionRequest
	var body bytes.Buffer
	rd := io.TeeReader(r.Body, &body)
	if err := json.NewDecoder(rd).Decode(&req); err != nil {
		http.Error(w, fmt.Sprintf("Could not decode request: %v", err), http.StatusInternalServerError)
		return
	}

	msg := types.NewRobustMessage(types.RobustDeleteSession, session, req.Quitmessage)
	// Cannot fail, no user input.
	msgbytes, _ := json.Marshal(msg)

	f := node.Apply(msgbytes, 10*time.Second)
	if err := f.Error(); err != nil {
		if err == raft.ErrNotLeader {
			maybeProxyToLeader(w, r, nopCloser{&body})
			return
		}
		http.Error(w, fmt.Sprintf("Apply(): %v", err), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
	"math/rand"
	"strings"
)

// Return the data in JSON format. This is the default return method.
func returnJson(obj interface{}, w http.ResponseWriter, h *http.Request) {
	// Don't cache json returns. This is to work around ie's weird caching behavior
	w.Header().Set("Cache-Control", "no-cache")
	// Set the content type to json
	w.Header().Set("Content-Type", "application/json")

	j, err := json.Marshal(obj)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	fmt.Fprint(w, string(j))
}

func defaultHandler(w http.ResponseWriter, h *http.Request) {
	fmt.Fprint(w, "cool, running")
}

// Return all memories
func allMemoryHandler(w http.ResponseWriter, h *http.Request) {
	returnJson(brain, w, h)
}

// Return a random memory
func randomMemoryHandler(w http.ResponseWriter, h *http.Request) {
	random_id := rand.Intn(brain.GetNextId()-1)
	m := brain.Memories[random_id]
	returnJson(m, w, h)
}

// Return a specific memory
func getMemoryHandler(w http.ResponseWriter, h *http.Request) {
	vars := mux.Vars(h)
	id_string := vars["id"]

	id, err := strconv.Atoi(id_string)
	if err != nil {
		fmt.Fprint(w, "Could not parse Id")
	}

	for _, v := range brain.Memories {
		if v.Id == id {
			returnJson(v, w, h)
		}
	}
}

// Add a memory
func addMemoryHandler(w http.ResponseWriter, h *http.Request) {
	var m Memory
	b := json.NewDecoder(h.Body)
	b.Decode(&m)

	memory := brain.Add(m)
	returnJson(memory, w, h)
}

func searchMemoryHandler(w http.ResponseWriter, h *http.Request) {
	vars := mux.Vars(h)
	term := vars["term"]

	var results []Memory

	for _, v := range brain.Memories {
		if strings.Contains(v.Text, term) {
			results = append(results, v)
		}
	}

	returnJson(results, w, h)
}

// Change a memory
func changeMemoryHandler(w http.ResponseWriter, h *http.Request) {
	var m Memory
	b := json.NewDecoder(h.Body)
	b.Decode(&m)

	memory := brain.Update(m)

	returnJson(memory, w, h)
}

// Remove a memory
func removeMemoryHandler(w http.ResponseWriter, h *http.Request) {
	returnJson(brain, w, h)
}
<commit_msg>Use the URL route to set the memory ID instead of using the posted ID<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
)

// Return the data in JSON format. This is the default return method.
func returnJson(obj interface{}, w http.ResponseWriter, h *http.Request) {
	// Don't cache json returns. This is to work around ie's weird caching behavior
	w.Header().Set("Cache-Control", "no-cache")
	// Set the content type to json
	w.Header().Set("Content-Type", "application/json")

	j, err := json.Marshal(obj)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	fmt.Fprint(w, string(j))
}

func defaultHandler(w http.ResponseWriter, h *http.Request) {
	fmt.Fprint(w, "cool, running")
}

// Return all memories
func allMemoryHandler(w http.ResponseWriter, h *http.Request) {
	returnJson(brain, w, h)
}

// Return a random memory
func randomMemoryHandler(w http.ResponseWriter, h *http.Request) {
	random_id := rand.Intn(brain.GetNextId() - 1)
	m := brain.Memories[random_id]
	returnJson(m, w, h)
}

// Return a specific memory
func getMemoryHandler(w http.ResponseWriter, h *http.Request) {
	vars := mux.Vars(h)
	id_string := vars["id"]

	id, err := strconv.Atoi(id_string)
	if err != nil {
		fmt.Fprint(w, "Could not parse Id")
	}

	for _, v := range brain.Memories {
		if v.Id == id {
			returnJson(v, w, h)
		}
	}
}

// Add a memory
func addMemoryHandler(w http.ResponseWriter, h *http.Request) {
	var m Memory
	b := json.NewDecoder(h.Body)
	b.Decode(&m)

	memory := brain.Add(m)
	returnJson(memory, w, h)
}

func searchMemoryHandler(w http.ResponseWriter, h *http.Request) {
	vars := mux.Vars(h)
	term := vars["term"]

	var results []Memory

	for _, v := range brain.Memories {
		if strings.Contains(v.Text, term) {
			results = append(results, v)
		}
	}

	returnJson(results, w, h)
}

// Change a memory
func changeMemoryHandler(w http.ResponseWriter, h *http.Request) {
	var m Memory
	b := json.NewDecoder(h.Body)
	b.Decode(&m)

	// The ID should come from the URL route, not the memory object that was posted
	vars := mux.Vars(h)
	mem_id_str := vars["id"]

	mem_id, err := strconv.Atoi(mem_id_str)
	if err != nil {
		panic("ID was not valid")
	}
	m.Id = mem_id

	memory := brain.Update(m)

	returnJson(memory, w, h)
}

// Remove a memory
func removeMemoryHandler(w http.ResponseWriter, h *http.Request) {
	returnJson(brain, w, h)
}
<|endoftext|>


<commit_before>package vmx

type Vhardware struct {
	Version int    `vmx:"version,omitempty"`
	Compat  string `vmx:"productcompatibility,omitempty"`
}

type Ethernet struct {
	VMXID                string
	StartConnected       bool   `vmx:"startconnected,omitempty"`
	Present              bool   `vmx:"present,omitempty"`
	ConnectionType       string `vmx:"connectiontype,omitempty"`
	VirtualDev           string `vmx:"virtualdev,omitempty"`
	WakeOnPcktRcv        bool   `vmx:"wakeonpcktrcv,omitempty"`
	AddressType          string `vmx:"addresstype,omitempty"`
	LinkStatePropagation bool   `vmx:"linkstatepropagation.enable,omitempty"`
	VNetwork             string `vmx:"vnet,omitempty"`
}

type Device struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Type           string `vmx:"devicetype,omitempty"`
	Filename       string `vmxl:"filename,omitempty"`
}

type SATADevice struct {
	Device
}

type SCSIDevice struct {
	Device
	PCISlot    int    `vmx:"pcislotnumber,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
}

type IDEDevice struct {
	Device
}

type USBDevice struct {
	VMXID   string
	Present bool   `vmx:"present,omitempty"`
	Speed   uint   `vmx:"speed,omitempty"`
	Type    string `vmx:"devicetype,omitempty"`
	Port    uint   `vmx:"port,omitempty"`
	Parent  string `vmx:"parent,omitmepty"`
}

type PowerType struct {
	PowerOff string `vmx:"poweroff,omitempty"`
	PowerOn  string `vmx:"poweron,omitempty"`
	Reset    string `vmx:"reset,omitempty"`
	Suspend  string `vmx:"suspend,omitempty"`
}

type Sound struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	Filename   string `vmx:"filename,omitempty"`
	Autodetect bool   `vmx:"autodetect,omitempty"`
}

type SerialPort struct {
	VMXID              string
	StartConnected     bool   `vmx:"startconnected,omitempty"`
	Present            bool   `vmx:"present,omitempty"`
	Filetype           string `vmx:"filetype,omitempty"`
	Filename           string `vmx:"filename,omitempty"`
	Autodetect         bool   `vmx:"autodetect,omitempty"`
	TryNoRxLoss        bool   `vmx:"trynorxloss,omitempty"`
	PipeEndpoint       string `vmx:"pipe.endpoint,omitempty"`
	AllowGuestConnCtrl bool   `vmx:"allowguestconnectioncontrol,omitempty"`
	HardwareFlowCtrl   bool   `vmx:"hardwareFlowControl,omitempty"`
}

type PCIBridge struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
	SlotNumber int    `vmx:"pcislotnumber,omitempty"`
	Functions  uint   `vmx:"functions,omitempty"`
}

type Tools struct {
	SyncTime      bool   `vmx:"synctime,omitempty"`
	UpgradePolicy string `vmx:"upgrade.policy,omitempty"`
	RemindInstall bool   `vmx:"remindinstall,omitempty"`
}

type UUID struct {
	Action string `vmx:"action,omitempty"`
	// Autogenerated, do not change
	Bios string `vmx:"bios,omitempty"`
	// Autogenerated, do not change
	Location string `vmx:"location,omitempty"`
}

type RemoteDisplay struct {
	VNCEnabled     bool   `vmx:"vnc.enabled,omitempty"`
	VNCPort        uint   `vmx:"vnc.port,omitempty"`
	VNCPassword    string `vmx:"vnc.password,omitempty"`
	VNCIPAddress   string `vmx:"vnc.ip,omitempty"`
	VNCKey         string `vmx:"vnc.key,omitempty"`
	VNCKeyMap      string `vmx:"vnc.keymap,omitempty"`
	VNCKeyMapFile  string `vmx:"vnc.keymapfile,omitempty"`
	VNCZlibLevel   uint   `vmx:"vnc.zliblevel,omitempty"`
	VNCWheelStep   string `vmx:"vncWheelStep,omitempty"`
	Depth          uint   `vmx:"depth,omitempty"`
	MaxConnections uint   `vmx:"maxconnections,omitempty"`
	MaxHeight      uint   `vmx:"maxheight,omitempty"`
	MaxWidth       uint   `vmx:"maxwidth,omitempty"`
}

type SharedFolder struct {
	VMXID       string
	Present     bool   `vmx:"present,omitempty"`
	Enabled     bool   `vmx:"enabled,omitempty"`
	ReadAccess  bool   `vmx:"readaccess,omitempty"`
	WriteAccess bool   `vmx:"writeaccess,omitempty"`
	HostPath    string `vmx:"hostpath,omitempty"`
	GuestName   string `vmx:"guestname,omitempty"`
	Expiration  string `vmx:"expiration,omitempty"`
}

type GUI struct {
	ExitAtPowerOff      bool `vmx:"exitatpoweroff,omitempty"`
	FullScreenAtPowerOn bool `vmx:"fullscreenatpoweron,omitempty"`
	PowerOnAtStartup    bool `vmx:"poweronatstartup,omitempty"`
	ExitOnCLIHalt       bool `vmx:"exitonclihlt,omitempty"`
}

type Isolation struct {
	// Disable shared folders
	HgfsDisable      bool `vmx:"tools.hgfs.disable,omitempty"`
	CopyDisable      bool `vmx:"tools.copy.disable,omitempty"`
	PasteDisable     bool `vmx:"tools.paste.disable,omitempty"`
	DragNDropDisable bool `vmx:"tools.dnd.disable,omitempty"`
}

type FloppyDevice struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	Filename       string `vmx:"filename,omitempty"`
	Filetype       string `vmx:"filetype,omitempty"`
	GuestControl   bool   `vmx:"allowGuestConnectionControl,omitempty"`
}

type VMCI struct {
	VMXID   string
	ID      string `vmx:"id,omitempty"`
	Present bool   `vmx:"present,omitempty"`
	PCISlot int    `vmx:"pcislotnumber,omitempty"`
}

type VirtualMachine struct {
	Encoding        string    `vmx:".encoding,omitempty"`
	ExtendedCfgFile string    `vmx:"extendedconfigfile,omitempty"`
	PowerType       PowerType `vmx:"powertype,omitempty"`
	Annotation      string    `vmx:"annotation,omitempty"`
	Vhardware       Vhardware `vmx:"virtualhw,omitempty"`
	Memsize         uint      `vmx:"memsize,omitempty"`
	NumvCPUs        uint      `vmx:"numvcpus,omitempty"`
	MemHotAdd       bool      `vmx:"mem.hotadd,omitempty"`
	VCPUHotAdd      bool      `vmx:"vcpu.hotadd,omitempty"`
	DisplayName     string    `vmx:"displayname,omitempty"`
	GuestOS         string    `vmx:"guestos,omitempty"`
	Autoanswer      bool      `vmx:"msg.autoanswer,omitempty"`
	Sound           Sound     `vmx:"sound,omitempty"`
	Tools           Tools     `vmx:"tools,omitempty"`
	NVRam           string    `vmx:"nvmram,omitempty"`
	UUID            UUID      `vmx:"uuid,omitempty"`
	CleanShutdown   bool      `vmx:"cleanshutdown,omitempty"`
	SoftPowerOff    bool      `vmx:"softpoweroff,omitempty"`
	VMCI            VMCI      `vmx:"vmci0,omitempty"`
	// Enable or not nested virtualiation
	VHVEnable     bool           `vmx:"vhv.enable,omitempty"`
	RemoteDisplay RemoteDisplay  `vmx:"remotedisplay,omitempty"`
	Isolation     Isolation      `vmx:"isolation,omitempty"`
	SharedFolders []SharedFolder `vmx:"sharedfolder,omitempty"`
	PCIBridges    []PCIBridge    `vmx:"pcibridge,omitempty"`
	SerialPorts   []SerialPort   `vmx:"serial,omitempty"`
	Ethernet      []Ethernet     `vmx:"ethernet,omitempty"`
	IDEDevices    []IDEDevice    `vmx:"ide,omitempty"`
	SCSIDevices   []SCSIDevice   `vmx:"scsi,omitempty"`
	SATADevices   []SATADevice   `vmx:"sata,omitempty"`
	USBDevices    []USBDevice    `vmx:"usb,omitempty"`
	FloppyDevices []FloppyDevice `vmx:"floppy,omitempty"`
}

// Bus type to use when attaching CD/DVD drives and disks.
type BusType string

// Disk controllers
const (
	IDE  BusType = "ide"
	SCSI BusType = "scsi"
	SATA BusType = "sata"
)

// FindDevice executes the given function p on all the devices of one of the
// given types until one of the calls returns true.
// FindDevice returns true only if one of the calls of p returned true.
func (vm VirtualMachine) FindDevice(p func(Device) bool, types ...BusType) bool {
	return vm.walkDevices(p, types...)
}

// WalkDevices executes the given function f on all the devices of one of the
// specified types.
func (vm VirtualMachine) WalkDevices(f func(Device), types ...BusType) {
	p := func(d Device) bool { f(d); return false }
	vm.walkDevices(p, types...)
}

func (vm VirtualMachine) walkDevices(p func(Device) bool, types ...BusType) bool {
	for _, t := range types {
		switch t {
		case SATA:
			for _, d := range vm.IDEDevices {
				if p(d.Device) {
					return true
				}
			}
		case IDE:
			for _, d := range vm.SCSIDevices {
				if p(d.Device) {
					return true
				}
			}
		case SCSI:
			for _, d := range vm.SATADevices {
				if p(d.Device) {
					return true
				}
			}
		}
	}
	return false
}
<commit_msg>no bus types is all bus types<commit_after>package vmx

type Vhardware struct {
	Version int    `vmx:"version,omitempty"`
	Compat  string `vmx:"productcompatibility,omitempty"`
}

type Ethernet struct {
	VMXID                string
	StartConnected       bool   `vmx:"startconnected,omitempty"`
	Present              bool   `vmx:"present,omitempty"`
	ConnectionType       string `vmx:"connectiontype,omitempty"`
	VirtualDev           string `vmx:"virtualdev,omitempty"`
	WakeOnPcktRcv        bool   `vmx:"wakeonpcktrcv,omitempty"`
	AddressType          string `vmx:"addresstype,omitempty"`
	LinkStatePropagation bool   `vmx:"linkstatepropagation.enable,omitempty"`
	VNetwork             string `vmx:"vnet,omitempty"`
}

type Device struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Type           string `vmx:"devicetype,omitempty"`
	Filename       string `vmxl:"filename,omitempty"`
}

type SATADevice struct {
	Device
}

type SCSIDevice struct {
	Device
	PCISlot    int    `vmx:"pcislotnumber,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
}

type IDEDevice struct {
	Device
}

type USBDevice struct {
	VMXID   string
	Present bool   `vmx:"present,omitempty"`
	Speed   uint   `vmx:"speed,omitempty"`
	Type    string `vmx:"devicetype,omitempty"`
	Port    uint   `vmx:"port,omitempty"`
	Parent  string `vmx:"parent,omitmepty"`
}

type PowerType struct {
	PowerOff string `vmx:"poweroff,omitempty"`
	PowerOn  string `vmx:"poweron,omitempty"`
	Reset    string `vmx:"reset,omitempty"`
	Suspend  string `vmx:"suspend,omitempty"`
}

type Sound struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	Filename   string `vmx:"filename,omitempty"`
	Autodetect bool   `vmx:"autodetect,omitempty"`
}

type SerialPort struct {
	VMXID              string
	StartConnected     bool   `vmx:"startconnected,omitempty"`
	Present            bool   `vmx:"present,omitempty"`
	Filetype           string `vmx:"filetype,omitempty"`
	Filename           string `vmx:"filename,omitempty"`
	Autodetect         bool   `vmx:"autodetect,omitempty"`
	TryNoRxLoss        bool   `vmx:"trynorxloss,omitempty"`
	PipeEndpoint       string `vmx:"pipe.endpoint,omitempty"`
	AllowGuestConnCtrl bool   `vmx:"allowguestconnectioncontrol,omitempty"`
	HardwareFlowCtrl   bool   `vmx:"hardwareFlowControl,omitempty"`
}

type PCIBridge struct {
	VMXID      string
	Present    bool   `vmx:"present,omitempty"`
	VirtualDev string `vmx:"virtualdev,omitempty"`
	SlotNumber int    `vmx:"pcislotnumber,omitempty"`
	Functions  uint   `vmx:"functions,omitempty"`
}

type Tools struct {
	SyncTime      bool   `vmx:"synctime,omitempty"`
	UpgradePolicy string `vmx:"upgrade.policy,omitempty"`
	RemindInstall bool   `vmx:"remindinstall,omitempty"`
}

type UUID struct {
	Action string `vmx:"action,omitempty"`
	// Autogenerated, do not change
	Bios string `vmx:"bios,omitempty"`
	// Autogenerated, do not change
	Location string `vmx:"location,omitempty"`
}

type RemoteDisplay struct {
	VNCEnabled     bool   `vmx:"vnc.enabled,omitempty"`
	VNCPort        uint   `vmx:"vnc.port,omitempty"`
	VNCPassword    string `vmx:"vnc.password,omitempty"`
	VNCIPAddress   string `vmx:"vnc.ip,omitempty"`
	VNCKey         string `vmx:"vnc.key,omitempty"`
	VNCKeyMap      string `vmx:"vnc.keymap,omitempty"`
	VNCKeyMapFile  string `vmx:"vnc.keymapfile,omitempty"`
	VNCZlibLevel   uint   `vmx:"vnc.zliblevel,omitempty"`
	VNCWheelStep   string `vmx:"vncWheelStep,omitempty"`
	Depth          uint   `vmx:"depth,omitempty"`
	MaxConnections uint   `vmx:"maxconnections,omitempty"`
	MaxHeight      uint   `vmx:"maxheight,omitempty"`
	MaxWidth       uint   `vmx:"maxwidth,omitempty"`
}

type SharedFolder struct {
	VMXID       string
	Present     bool   `vmx:"present,omitempty"`
	Enabled     bool   `vmx:"enabled,omitempty"`
	ReadAccess  bool   `vmx:"readaccess,omitempty"`
	WriteAccess bool   `vmx:"writeaccess,omitempty"`
	HostPath    string `vmx:"hostpath,omitempty"`
	GuestName   string `vmx:"guestname,omitempty"`
	Expiration  string `vmx:"expiration,omitempty"`
}

type GUI struct {
	ExitAtPowerOff      bool `vmx:"exitatpoweroff,omitempty"`
	FullScreenAtPowerOn bool `vmx:"fullscreenatpoweron,omitempty"`
	PowerOnAtStartup    bool `vmx:"poweronatstartup,omitempty"`
	ExitOnCLIHalt       bool `vmx:"exitonclihlt,omitempty"`
}

type Isolation struct {
	// Disable shared folders
	HgfsDisable      bool `vmx:"tools.hgfs.disable,omitempty"`
	CopyDisable      bool `vmx:"tools.copy.disable,omitempty"`
	PasteDisable     bool `vmx:"tools.paste.disable,omitempty"`
	DragNDropDisable bool `vmx:"tools.dnd.disable,omitempty"`
}

type FloppyDevice struct {
	VMXID          string
	Present        bool   `vmx:"present,omitempty"`
	StartConnected bool   `vmx:"startconnected,omitempty"`
	Autodetect     bool   `vmx:"autodetect,omitempty"`
	Filename       string `vmx:"filename,omitempty"`
	Filetype       string `vmx:"filetype,omitempty"`
	GuestControl   bool   `vmx:"allowGuestConnectionControl,omitempty"`
}

type VMCI struct {
	VMXID   string
	ID      string `vmx:"id,omitempty"`
	Present bool   `vmx:"present,omitempty"`
	PCISlot int    `vmx:"pcislotnumber,omitempty"`
}

type VirtualMachine struct {
	Encoding        string    `vmx:".encoding,omitempty"`
	ExtendedCfgFile string    `vmx:"extendedconfigfile,omitempty"`
	PowerType       PowerType `vmx:"powertype,omitempty"`
	Annotation      string    `vmx:"annotation,omitempty"`
	Vhardware       Vhardware `vmx:"virtualhw,omitempty"`
	Memsize         uint      `vmx:"memsize,omitempty"`
	NumvCPUs        uint      `vmx:"numvcpus,omitempty"`
	MemHotAdd       bool      `vmx:"mem.hotadd,omitempty"`
	VCPUHotAdd      bool      `vmx:"vcpu.hotadd,omitempty"`
	DisplayName     string    `vmx:"displayname,omitempty"`
	GuestOS         string    `vmx:"guestos,omitempty"`
	Autoanswer      bool      `vmx:"msg.autoanswer,omitempty"`
	Sound           Sound     `vmx:"sound,omitempty"`
	Tools           Tools     `vmx:"tools,omitempty"`
	NVRam           string    `vmx:"nvmram,omitempty"`
	UUID            UUID      `vmx:"uuid,omitempty"`
	CleanShutdown   bool      `vmx:"cleanshutdown,omitempty"`
	SoftPowerOff    bool      `vmx:"softpoweroff,omitempty"`
	VMCI            VMCI      `vmx:"vmci0,omitempty"`
	// Enable or not nested virtualiation
	VHVEnable     bool           `vmx:"vhv.enable,omitempty"`
	RemoteDisplay RemoteDisplay  `vmx:"remotedisplay,omitempty"`
	Isolation     Isolation      `vmx:"isolation,omitempty"`
	SharedFolders []SharedFolder `vmx:"sharedfolder,omitempty"`
	PCIBridges    []PCIBridge    `vmx:"pcibridge,omitempty"`
	SerialPorts   []SerialPort   `vmx:"serial,omitempty"`
	Ethernet      []Ethernet     `vmx:"ethernet,omitempty"`
	IDEDevices    []IDEDevice    `vmx:"ide,omitempty"`
	SCSIDevices   []SCSIDevice   `vmx:"scsi,omitempty"`
	SATADevices   []SATADevice   `vmx:"sata,omitempty"`
	USBDevices    []USBDevice    `vmx:"usb,omitempty"`
	FloppyDevices []FloppyDevice `vmx:"floppy,omitempty"`
}

// Bus type to use when attaching CD/DVD drives and disks.
type BusType string

// Disk controllers
const (
	IDE  BusType = "ide"
	SCSI BusType = "scsi"
	SATA BusType = "sata"
)

// FindDevice executes the given function p on all the devices of one of the
// given types until one of the calls returns true.
// FindDevice returns true only if one of the calls of p returned true.
func (vm VirtualMachine) FindDevice(p func(Device) bool, types ...BusType) bool {
	return vm.walkDevices(p, types...)
}

// WalkDevices executes the given function f on all the devices of one of the
// specified types.
func (vm VirtualMachine) WalkDevices(f func(Device), types ...BusType) {
	p := func(d Device) bool { f(d); return false }
	vm.walkDevices(p, types...)
}

func (vm VirtualMachine) walkDevices(p func(Device) bool, types ...BusType) bool {
	if len(types) == 0 {
		types = []BusType{SATA, IDE, SCSI}
	}
	for _, t := range types {
		switch t {
		case SATA:
			for _, d := range vm.IDEDevices {
				if p(d.Device) {
					return true
				}
			}
		case IDE:
			for _, d := range vm.SCSIDevices {
				if p(d.Device) {
					return true
				}
			}
		case SCSI:
			for _, d := range vm.SATADevices {
				if p(d.Device) {
					return true
				}
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/go-martini/martini"
    "github.com/martini-contrib/render"
    "github.com/martini-contrib/binding"
    "github.com/Lupino/collect/models"
    "mime/multipart"
    "net/http"
)

type FileForm struct {
    File *multipart.FileHeader `form:"file" binding:"required"`
}

type TagForm struct {
    Tag  string                `form:"tag"  binding:"required"`
}

type DatasetForm struct {
    FileForm
    TagForm
}

func api(mart *martini.ClassicMartini) {
    mart.Post(API + "/datasets", binding.Bind(DatasetForm{}), func(form DatasetForm, r render.Render) {
        var err error
        var file *models.File
        var tag *models.Tag
        var dataset *models.Dataset

        if file, err = uploadFile(form.File); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        if tag, err = saveTag(form.Tag); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        if dataset, err = saveDataset(file, tag, 0); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        r.JSON(http.StatusOK, map[string]*models.Dataset{"dataset": dataset})
    })

    mart.Post(API + "/upload", binding.Bind(FileForm{}), func(form FileForm, r render.Render) {
        var err error
        var file *models.File

        if file, err = uploadFile(form.File); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        r.JSON(http.StatusOK, map[string]*models.File{"file": file})
    })

    mart.Post(API + "/tags", binding.Bind(TagForm{}), func(form TagForm, r render.Render) {
        var err error
        var tag *models.Tag

        if tag, err = saveTag(form.Tag); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        r.JSON(http.StatusOK, map[string]*models.Tag{"file": tag})
    })
}
<commit_msg>update api matchs<commit_after>package main

import (
    "github.com/go-martini/martini"
    "github.com/martini-contrib/render"
    "github.com/martini-contrib/binding"
    "github.com/Lupino/collect/models"
    "mime/multipart"
    "net/http"
)

type FileForm struct {
    File *multipart.FileHeader `form:"file" binding:"required"`
}

type TagForm struct {
    Tag  string                `form:"tag"  binding:"required"`
}

type DatasetForm struct {
    FileForm
    TagForm
}

func api(mart *martini.ClassicMartini) {
    mart.Post(API + "/datasets/?", binding.Bind(DatasetForm{}), func(form DatasetForm, r render.Render) {
        var err error
        var file *models.File
        var tag *models.Tag
        var dataset *models.Dataset

        if file, err = uploadFile(form.File); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        if tag, err = saveTag(form.Tag); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        if dataset, err = saveDataset(file, tag, 0); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        r.JSON(http.StatusOK, map[string]*models.Dataset{"dataset": dataset})
    })

    mart.Post(API + "/upload/?", binding.Bind(FileForm{}), func(form FileForm, r render.Render) {
        var err error
        var file *models.File

        if file, err = uploadFile(form.File); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        r.JSON(http.StatusOK, map[string]*models.File{"file": file})
    })

    mart.Post(API + "/tags/?", binding.Bind(TagForm{}), func(form TagForm, r render.Render) {
        var err error
        var tag *models.Tag

        if tag, err = saveTag(form.Tag); err != nil {
            r.JSON(http.StatusInternalServerError, map[string]interface{}{"err": err.Error()})
        }

        r.JSON(http.StatusOK, map[string]*models.Tag{"file": tag})
    })
}
<|endoftext|>


<commit_before>package gochatwork

import (
	"encoding/json"
	"time"
)

// BaseURL ChatWork API endpooint URL
const BaseURL = `https://api.chatwork.com/v1`

// Me model
type Me struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	Title            string `json:"title"`
	URL              string `json:"url"`
	Introduction     string `json:"introduction"`
	Mail             string `json:"mail"`
	TelOrganization  string `json:"tel_organization"`
	TelExtension     string `json:"tel_extension"`
	TelMobile        string `json:"tel_mobile"`
	Skype            string `json:"skype"`
	Facebook         string `json:"facebook"`
	Twitter          string `json:"twitter"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Me GET "/me"
func (c *Client) Me() Me {
	ret := c.Get("/me", map[string]string{})
	var me Me
	json.Unmarshal(ret, &me)
	return me
}

// Status model
type Status struct {
	UnreadRoomNum  int `json:"unread_room_num"`
	MentionRoomNum int `json:"mention_room_num"`
	MytaskRoomNum  int `json:"mytask_room_num"`
	UnreadNum      int `json:"unread_num"`
	MentionNum     int `json:"mention_num"`
	MyTaskNum      int `json:"mytask_num"`
}

// MyStatus GET "/my/status"
func (c *Client) MyStatus() Status {
	ret := c.Get("/my/status", map[string]string{})
	var status Status
	json.Unmarshal(ret, &status)
	return status
}

// MyTask model
type MyTask struct {
	Task
	Room struct {
		Roomid   int    `json:"room_id"`
		Name     string `json:"name"`
		IconPath string `json:"icon_path"`
	}
}

// MyTasks GET "/my/tasks"
// params keys
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) MyTasks(params map[string]string) []MyTask {
	ret := c.Get("/my/tasks", params)
	var tasks []MyTask
	json.Unmarshal(ret, &tasks)
	return tasks
}

// Contact model
type Contact struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Contacts GET "/contacts"
func (c *Client) Contacts() []Contact {
	ret := c.Get("/contacts", map[string]string{})
	var contacts []Contact
	json.Unmarshal(ret, &contacts)
	return contacts
}

// Room model
type Room struct {
	RoomID         int    `json:"room_id"`
	Name           string `json:"name"`
	Type           string `json:"type"`
	Role           string `json:"role"`
	Sticky         bool   `json:"sticky"`
	UnreadNum      int    `json:"unread_num"`
	MentionNum     int    `json:"mention_num"`
	MytaskNum      int    `json:"mytask_num"`
	MessageNum     int    `json:"message_num"`
	FileNum        int    `json:"file_num"`
	TaskNum        int    `json:"task_num"`
	IconPath       string `json:"icon_path"`
	LastUpdateTime int64  `json:"last_update_time"`
}

// Rooms GET "/rooms"
func (c *Client) Rooms() []Room {
	ret := c.Get("/rooms", map[string]string{})
	var rooms []Room
	json.Unmarshal(ret, &rooms)
	return rooms
}

// Room GET "/rooms/{room_id}"
func (c *Client) Room(roomID string) Room {
	ret := c.Get("/rooms/"+roomID, map[string]string{})
	var room Room
	json.Unmarshal(ret, &room)
	return room
}

// CreateRoom POST "/rooms"
// params keys
//   * name
//   * members_admin_ids
//   - description
//   - icon_preset
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) CreateRoom(params map[string]string) []byte {
	return c.Post("/rooms", params)
}

// UpdateRoom PUT "/rooms/{room_id}"
// params keys
//   - description
//   - icon_preset
//   - name
func (c *Client) UpdateRoom(roomID string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomID, params)
}

// DeleteRoom DELETE "/rooms/{room_id}"
// params key
//   * action_type: [leave, delete]
func (c *Client) DeleteRoom(roomID string, params map[string]string) []byte {
	return c.Delete("/rooms/"+roomID, params)
}

// Member model
type Member struct {
	AccountID        int    `json:"account_id"`
	Role             string `json:"role"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// RoomMembers GET "/rooms/{room_id}/members"
func (c *Client) RoomMembers(roomID string) []Member {
	ret := c.Get("/rooms/"+roomID+"/members", map[string]string{})
	var members []Member
	json.Unmarshal(ret, &members)
	return members
}

// UpdateRoomMembers PUT "/rooms/{room_id}/members"
// params keys
//   * members_admin_ids
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) UpdateRoomMembers(roomID string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomID+"/members", params)
}

// Account model
type Account struct {
	AccountID      int    `json:"account_id"`
	Name           string `json:"name"`
	AvatarImageURL string `json:"avatar_image_url"`
}

// Message model
type Message struct {
	MessageID  int     `json:"message_id"`
	Account    Account `json:"account"`
	Body       string  `json:"body"`
	SendTime   int64   `json:"send_time"`
	UpdateTime int64   `json:"update_time"`
}

// SendDate time.Time representation of SendTime
func (m Message) SendDate() time.Time {
	return time.Unix(m.SendTime, 0)
}

// UpdateDate time.Time representation of UpdateTime
func (m Message) UpdateDate() time.Time {
	return time.Unix(m.UpdateTime, 0)
}

// Messages slice of Message
type Messages []Message

// RoomMessages GET "/rooms/{room_id}/messages"
func (c *Client) RoomMessages(roomID string, params map[string]string) Messages {
	ret := c.Get("/rooms/"+roomID+"/messages", params)
	var msgs Messages
	json.Unmarshal(ret, &msgs)
	return msgs
}

// PostRoomMessage POST "/rooms/{room_id}/messages"
func (c *Client) PostRoomMessage(roomID string, body string) []byte {
	return c.Post("/rooms/"+roomID+"/messages", map[string]string{"body": body})
}

// RoomMessage GET "/rooms/{room_id}/messages/{message_id}"
func (c *Client) RoomMessage(roomID, messageID string) Message {
	ret := c.Get("/rooms/"+roomID+"/messages/"+messageID, map[string]string{})
	var message Message
	json.Unmarshal(ret, &message)
	return message
}

// Task model
type Task struct {
	TaskID            int     `json:"task_id"`
	Account           Account `json:"account"`
	AssignedByAccount Account `json:"assigned_by_account"`
	MessageID         int     `json:"message_id"`
	Body              string  `json:"body"`
	LimitTime         int64   `json:"limit_time"`
	Status            string  `json:"status"`
}

// RoomTasks GET "/rooms/{room_id}/tasks"
// params keys
//  - account_id
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) RoomTasks(roomID string, params map[string]string) []Task {
	ret := c.Get("/rooms/"+roomID+"/tasks", params)
	var tasks []Task
	json.Unmarshal(ret, &tasks)
	return tasks
}

// PostRoomTask POST "/rooms/{room_id}/tasks"
// params keys
//   * body
//   * to_ids
//   - limit
func (c *Client) PostRoomTask(roomID string, params map[string]string) []byte {
	return c.Post("/rooms/"+roomID+"/tasks", params)
}

// RoomTask GET "/rooms/{room_id}/tasks/tasks_id"
func (c *Client) RoomTask(roomID, taskID string) Task {
	ret := c.Get("/rooms/"+roomID+"/tasks/"+taskID, map[string]string{})
	var task Task
	json.Unmarshal(ret, &task)
	return task
}

// File model
type File struct {
	FileID      int     `json:"file_id"`
	Account     Account `json:"account"`
	MessageID   int     `json:"message_id"`
	Filename    string  `json:"filename"`
	Filesize    int     `json:"filesize"`
	UploadTime  int64   `json:"upload_time"`
	DownloadURL string  `json:"download_url"`
}

// RoomFiles GET "/rooms/{room_id}/files/"
// params key
//   - account_id
func (c *Client) RoomFiles(roomID string, params map[string]string) []File {
	ret := c.Get("/rooms/"+roomID+"/files", params)
	var files []File
	json.Unmarshal(ret, &files)
	return files
}

// RoomFile GET "/rooms/{room_id}/files/{file_id}"
// params key
//   - create_download_url: ["0", "1"]
func (c *Client) RoomFile(roomID, fileID string, params map[string]string) File {
	ret := c.Get("/rooms/"+roomID+"/files/"+fileID, params)
	var file File
	json.Unmarshal(ret, &file)
	return file
}
<commit_msg>add convert method for date<commit_after>package gochatwork

import (
	"encoding/json"
	"time"
)

// BaseURL ChatWork API endpooint URL
const BaseURL = `https://api.chatwork.com/v1`

// Me model
type Me struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	Title            string `json:"title"`
	URL              string `json:"url"`
	Introduction     string `json:"introduction"`
	Mail             string `json:"mail"`
	TelOrganization  string `json:"tel_organization"`
	TelExtension     string `json:"tel_extension"`
	TelMobile        string `json:"tel_mobile"`
	Skype            string `json:"skype"`
	Facebook         string `json:"facebook"`
	Twitter          string `json:"twitter"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Me GET "/me"
func (c *Client) Me() Me {
	ret := c.Get("/me", map[string]string{})
	var me Me
	json.Unmarshal(ret, &me)
	return me
}

// Status model
type Status struct {
	UnreadRoomNum  int `json:"unread_room_num"`
	MentionRoomNum int `json:"mention_room_num"`
	MytaskRoomNum  int `json:"mytask_room_num"`
	UnreadNum      int `json:"unread_num"`
	MentionNum     int `json:"mention_num"`
	MyTaskNum      int `json:"mytask_num"`
}

// MyStatus GET "/my/status"
func (c *Client) MyStatus() Status {
	ret := c.Get("/my/status", map[string]string{})
	var status Status
	json.Unmarshal(ret, &status)
	return status
}

// MyTask model
type MyTask struct {
	Task
	Room struct {
		Roomid   int    `json:"room_id"`
		Name     string `json:"name"`
		IconPath string `json:"icon_path"`
	}
}

// MyTasks GET "/my/tasks"
// params keys
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) MyTasks(params map[string]string) []MyTask {
	ret := c.Get("/my/tasks", params)
	var tasks []MyTask
	json.Unmarshal(ret, &tasks)
	return tasks
}

// Contact model
type Contact struct {
	AccountID        int    `json:"account_id"`
	RoomID           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// Contacts GET "/contacts"
func (c *Client) Contacts() []Contact {
	ret := c.Get("/contacts", map[string]string{})
	var contacts []Contact
	json.Unmarshal(ret, &contacts)
	return contacts
}

// Room model
type Room struct {
	RoomID         int    `json:"room_id"`
	Name           string `json:"name"`
	Type           string `json:"type"`
	Role           string `json:"role"`
	Sticky         bool   `json:"sticky"`
	UnreadNum      int    `json:"unread_num"`
	MentionNum     int    `json:"mention_num"`
	MytaskNum      int    `json:"mytask_num"`
	MessageNum     int    `json:"message_num"`
	FileNum        int    `json:"file_num"`
	TaskNum        int    `json:"task_num"`
	IconPath       string `json:"icon_path"`
	LastUpdateTime int64  `json:"last_update_time"`
}

// Rooms GET "/rooms"
func (c *Client) Rooms() []Room {
	ret := c.Get("/rooms", map[string]string{})
	var rooms []Room
	json.Unmarshal(ret, &rooms)
	return rooms
}

// Room GET "/rooms/{room_id}"
func (c *Client) Room(roomID string) Room {
	ret := c.Get("/rooms/"+roomID, map[string]string{})
	var room Room
	json.Unmarshal(ret, &room)
	return room
}

// CreateRoom POST "/rooms"
// params keys
//   * name
//   * members_admin_ids
//   - description
//   - icon_preset
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) CreateRoom(params map[string]string) []byte {
	return c.Post("/rooms", params)
}

// UpdateRoom PUT "/rooms/{room_id}"
// params keys
//   - description
//   - icon_preset
//   - name
func (c *Client) UpdateRoom(roomID string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomID, params)
}

// DeleteRoom DELETE "/rooms/{room_id}"
// params key
//   * action_type: [leave, delete]
func (c *Client) DeleteRoom(roomID string, params map[string]string) []byte {
	return c.Delete("/rooms/"+roomID, params)
}

// Member model
type Member struct {
	AccountID        int    `json:"account_id"`
	Role             string `json:"role"`
	Name             string `json:"name"`
	ChatworkID       string `json:"chatwork_id"`
	OrganizationID   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageURL   string `json:"avatar_image_url"`
}

// RoomMembers GET "/rooms/{room_id}/members"
func (c *Client) RoomMembers(roomID string) []Member {
	ret := c.Get("/rooms/"+roomID+"/members", map[string]string{})
	var members []Member
	json.Unmarshal(ret, &members)
	return members
}

// UpdateRoomMembers PUT "/rooms/{room_id}/members"
// params keys
//   * members_admin_ids
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) UpdateRoomMembers(roomID string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomID+"/members", params)
}

// Account model
type Account struct {
	AccountID      int    `json:"account_id"`
	Name           string `json:"name"`
	AvatarImageURL string `json:"avatar_image_url"`
}

// Message model
type Message struct {
	MessageID  int     `json:"message_id"`
	Account    Account `json:"account"`
	Body       string  `json:"body"`
	SendTime   int64   `json:"send_time"`
	UpdateTime int64   `json:"update_time"`
}

// SendDate time.Time representation of SendTime
func (m Message) SendDate() time.Time {
	return time.Unix(m.SendTime, 0)
}

// UpdateDate time.Time representation of UpdateTime
func (m Message) UpdateDate() time.Time {
	return time.Unix(m.UpdateTime, 0)
}

// Messages slice of Message
type Messages []Message

// RoomMessages GET "/rooms/{room_id}/messages"
func (c *Client) RoomMessages(roomID string, params map[string]string) Messages {
	ret := c.Get("/rooms/"+roomID+"/messages", params)
	var msgs Messages
	json.Unmarshal(ret, &msgs)
	return msgs
}

// PostRoomMessage POST "/rooms/{room_id}/messages"
func (c *Client) PostRoomMessage(roomID string, body string) []byte {
	return c.Post("/rooms/"+roomID+"/messages", map[string]string{"body": body})
}

// RoomMessage GET "/rooms/{room_id}/messages/{message_id}"
func (c *Client) RoomMessage(roomID, messageID string) Message {
	ret := c.Get("/rooms/"+roomID+"/messages/"+messageID, map[string]string{})
	var message Message
	json.Unmarshal(ret, &message)
	return message
}

// Task model
type Task struct {
	TaskID            int     `json:"task_id"`
	Account           Account `json:"account"`
	AssignedByAccount Account `json:"assigned_by_account"`
	MessageID         int     `json:"message_id"`
	Body              string  `json:"body"`
	LimitTime         int64   `json:"limit_time"`
	Status            string  `json:"status"`
}

// LimitDate time.Time representation of LimitTime
func (t Task) LimitDate() time.Time {
	return time.Unix(t.LimitTime, 0)
}

// RoomTasks GET "/rooms/{room_id}/tasks"
// params keys
//  - account_id
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) RoomTasks(roomID string, params map[string]string) []Task {
	ret := c.Get("/rooms/"+roomID+"/tasks", params)
	var tasks []Task
	json.Unmarshal(ret, &tasks)
	return tasks
}

// PostRoomTask POST "/rooms/{room_id}/tasks"
// params keys
//   * body
//   * to_ids
//   - limit
func (c *Client) PostRoomTask(roomID string, params map[string]string) []byte {
	return c.Post("/rooms/"+roomID+"/tasks", params)
}

// RoomTask GET "/rooms/{room_id}/tasks/tasks_id"
func (c *Client) RoomTask(roomID, taskID string) Task {
	ret := c.Get("/rooms/"+roomID+"/tasks/"+taskID, map[string]string{})
	var task Task
	json.Unmarshal(ret, &task)
	return task
}

// File model
type File struct {
	FileID      int     `json:"file_id"`
	Account     Account `json:"account"`
	MessageID   int     `json:"message_id"`
	Filename    string  `json:"filename"`
	Filesize    int     `json:"filesize"`
	UploadTime  int64   `json:"upload_time"`
	DownloadURL string  `json:"download_url"`
}

// UploadDate time.Time representation of UploadTime
func (f File) UploadDate() time.Time {
	return time.Unix(f.UploadTime, 0)
}

// RoomFiles GET "/rooms/{room_id}/files/"
// params key
//   - account_id
func (c *Client) RoomFiles(roomID string, params map[string]string) []File {
	ret := c.Get("/rooms/"+roomID+"/files", params)
	var files []File
	json.Unmarshal(ret, &files)
	return files
}

// RoomFile GET "/rooms/{room_id}/files/{file_id}"
// params key
//   - create_download_url: ["0", "1"]
func (c *Client) RoomFile(roomID, fileID string, params map[string]string) File {
	ret := c.Get("/rooms/"+roomID+"/files/"+fileID, params)
	var file File
	json.Unmarshal(ret, &file)
	return file
}
<|endoftext|>


<commit_before>// Package atomix is a sequence-based Go-native audio mixer
package atomix

import (
	"time"

	"github.com/outrightmental/go-atomix/bind"
)

// VERSION # of this go-atomix source code
const VERSION = "0.0.2"

// Debug ON/OFF (ripples down to all sub-modules)
func Debug(isOn bool) {
	mixDebug(isOn)
}

// Configure the mixer frequency, format, channels & sample rate.
func Configure(spec bind.AudioSpec) {
	if spec.Freq == 0 {
		panic("Must specify Frequency")
	} else if spec.Format == 0 {
		panic("Must specify Format")
	} else if spec.Channels == 0 {
		panic("Must specify Channels")
	}
	bind.SetMixNextOutput(mixNextSample)
	mixSetSpec(spec)
}

// Teardown everything and release all memory.
func Teardown() {
	mixTeardown()
}

// Cleanup approximately once per second to conserve memory.
func Cleanup() {
	mixCleanup()
}

// Spec for the mixer, which may include callback functions, e.g. go-sdl2
func Spec() *bind.AudioSpec {
	return mixSpec
}

// SetFire to represent a single audio source playing at a specific time in the future (in time.Duration from play start), with sustain time.Duration, volume from 0 to 1, and pan from -1 to +1
func SetFire(source string, begin time.Duration, sustain time.Duration, volume float64, pan float64) *Fire {
	return mixSetFire(source, begin, sustain, volume, pan)
}

// SetSoundsPath prefix
func SetSoundsPath(prefix string) {
	mixSetSoundsPath(prefix)
}

// Start the mixer now
func Start() {
	mixStartAt(time.Now())
}

// StartAt a specific time in the future
func StartAt(t time.Time) {
	mixStartAt(t)
}

// GetStartTime the mixer was started at
func GetStartTime() time.Time {
	return mixGetStartTime()
}

// OpenAudio begins streaming to the bound output audio interface, via a callback function
func OpenAudio() {
	bind.OpenAudio(mixSpec)
}
<commit_msg>bump version to 0.0.3<commit_after>// Package atomix is a sequence-based Go-native audio mixer
package atomix

import (
	"time"

	"github.com/outrightmental/go-atomix/bind"
)

// VERSION # of this go-atomix source code
const VERSION = "0.0.3"

// Debug ON/OFF (ripples down to all sub-modules)
func Debug(isOn bool) {
	mixDebug(isOn)
}

// Configure the mixer frequency, format, channels & sample rate.
func Configure(spec bind.AudioSpec) {
	if spec.Freq == 0 {
		panic("Must specify Frequency")
	} else if spec.Format == 0 {
		panic("Must specify Format")
	} else if spec.Channels == 0 {
		panic("Must specify Channels")
	}
	bind.SetMixNextOutput(mixNextSample)
	mixSetSpec(spec)
}

// Teardown everything and release all memory.
func Teardown() {
	mixTeardown()
}

// Cleanup approximately once per second to conserve memory.
func Cleanup() {
	mixCleanup()
}

// Spec for the mixer, which may include callback functions, e.g. go-sdl2
func Spec() *bind.AudioSpec {
	return mixSpec
}

// SetFire to represent a single audio source playing at a specific time in the future (in time.Duration from play start), with sustain time.Duration, volume from 0 to 1, and pan from -1 to +1
func SetFire(source string, begin time.Duration, sustain time.Duration, volume float64, pan float64) *Fire {
	return mixSetFire(source, begin, sustain, volume, pan)
}

// SetSoundsPath prefix
func SetSoundsPath(prefix string) {
	mixSetSoundsPath(prefix)
}

// Start the mixer now
func Start() {
	mixStartAt(time.Now())
}

// StartAt a specific time in the future
func StartAt(t time.Time) {
	mixStartAt(t)
}

// GetStartTime the mixer was started at
func GetStartTime() time.Time {
	return mixGetStartTime()
}

// OpenAudio begins streaming to the bound output audio interface, via a callback function
func OpenAudio() {
	bind.OpenAudio(mixSpec)
}
<|endoftext|>


<commit_before>package builtin

import (
	"log"
	"sync"

	"github.com/oleiade/lane"

	. "github.com/wanliu/flow/builtin/ai"
	. "github.com/wanliu/flow/context"

	config "github.com/wanliu/flow/builtin/config"
	flow "github.com/wanliu/goflow"
)

func NewApiAi() interface{} {
	return new(ApiAi)
}

type ApiAi struct {
	flow.Component

	MultiField

	sync.RWMutex

	token     string
	sessionId string
	proxyUrl  string

	CtxQueue *lane.Queue
	TxtQueue *lane.Queue

	Echo      <-chan bool
	In        <-chan string
	Token     <-chan string
	SessionId <-chan string
	ProxyUrl  <-chan string
	Out       chan<- Context
	Ctx       <-chan Context
}

func (c *ApiAi) Init() {
	c.CtxQueue = lane.NewQueue()
	c.TxtQueue = lane.NewQueue()
}

func (c *ApiAi) OnIn(input string) {
	// c.SetValue(config.ValueKeyText, input)
	c.Lock()
	c.TxtQueue.Enqueue(input)
	c.Unlock()

	c.SendQuery()
}

func (c *ApiAi) OnToken(token string) {
	c.token = token
}

func (c *ApiAi) OnSessionId(sessionId string) {
	c.sessionId = sessionId
}

func (c *ApiAi) OnProxyUrl(proxy string) {
	c.proxyUrl = proxy
}

func (c *ApiAi) OnCtx(ctx Context) {
	// c.SetValue(config.ValueKeyCtx, ctx)
	c.Lock()
	c.CtxQueue.Enqueue(ctx)
	c.Unlock()

	c.SendQuery()
}

func (c *ApiAi) SendQuery() {
	c.RLock()

	for c.CtxQueue.Head() != nil && c.TxtQueue.Head() != nil {
		txt := c.TxtQueue.Dequeue().(string)
		ctx := c.CtxQueue.Dequeue().(Context)

		res, err := ApiAiQuery(txt, c.token, c.sessionId, c.proxyUrl)

		ctx.SetValue(config.CtxkeyResult, res)

		intent := res.Metadata.IntentName
		score := res.Score
		query := res.ResolvedQuery

		if err != nil {
			log.Printf("意图解析失败:" + err.Error())
		} else {
			log.Printf("意图解析\"%s\" -> %s 准确度: %2.2f%%", query, intent, score*100)
		}

		c.Out <- ctx
	}

	c.RUnlock()
}
<commit_msg>use mutex instead of rwmutex<commit_after>package builtin

import (
	"log"
	"sync"

	"github.com/oleiade/lane"

	. "github.com/wanliu/flow/builtin/ai"
	. "github.com/wanliu/flow/context"

	config "github.com/wanliu/flow/builtin/config"
	flow "github.com/wanliu/goflow"
)

func NewApiAi() interface{} {
	return new(ApiAi)
}

type ApiAi struct {
	flow.Component

	MultiField

	sync.Mutex

	token     string
	sessionId string
	proxyUrl  string

	CtxQueue *lane.Queue
	TxtQueue *lane.Queue

	Echo      <-chan bool
	In        <-chan string
	Token     <-chan string
	SessionId <-chan string
	ProxyUrl  <-chan string
	Out       chan<- Context
	Ctx       <-chan Context
}

func (c *ApiAi) Init() {
	c.CtxQueue = lane.NewQueue()
	c.TxtQueue = lane.NewQueue()
}

func (c *ApiAi) OnIn(input string) {
	// c.SetValue(config.ValueKeyText, input)
	c.Lock()
	c.TxtQueue.Enqueue(input)
	c.Unlock()

	c.SendQuery()
}

func (c *ApiAi) OnToken(token string) {
	c.token = token
}

func (c *ApiAi) OnSessionId(sessionId string) {
	c.sessionId = sessionId
}

func (c *ApiAi) OnProxyUrl(proxy string) {
	c.proxyUrl = proxy
}

func (c *ApiAi) OnCtx(ctx Context) {
	// c.SetValue(config.ValueKeyCtx, ctx)
	c.Lock()
	c.CtxQueue.Enqueue(ctx)
	c.Unlock()

	c.SendQuery()
}

func (c *ApiAi) SendQuery() {
	c.Lock()

	for c.CtxQueue.Head() != nil && c.TxtQueue.Head() != nil {
		txt := c.TxtQueue.Dequeue().(string)
		ctx := c.CtxQueue.Dequeue().(Context)

		res, err := ApiAiQuery(txt, c.token, c.sessionId, c.proxyUrl)

		ctx.SetValue(config.CtxkeyResult, res)

		intent := res.Metadata.IntentName
		score := res.Score
		query := res.ResolvedQuery

		if err != nil {
			log.Printf("意图解析失败:" + err.Error())
		} else {
			log.Printf("意图解析\"%s\" -> %s 准确度: %2.2f%%", query, intent, score*100)
		}

		c.Out <- ctx
	}

	c.Unlock()
}
<|endoftext|>


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

// Package cluster provides types and functions for management of Docker
// clusters, scheduling container operations among hosts running Docker
// (nodes).
package cluster

import (
	"errors"
	"github.com/fsouza/go-dockerclient"
	"net/http"
	"reflect"
	"sync"
)

var (
	// ErrUnknownNode is the error returned when an unknown node is stored in the
	// storage. This error means some kind of inconsistence between the storage and
	// the cluster.
	ErrUnknownNode = errors.New("Unknown node")

	// ErrImmutableCluster is the error returned by Register when the cluster is
	// immutable, meaning that no new nodes can be registered.
	ErrImmutableCluster = errors.New("Immutable cluster")

	errStorageDisabled = errors.New("Storage is disabled")
)

// ContainerStorage provides methods to store and retrieve information about
// the relation between the node and the container. It can be easily
// represented as a key-value storage.
//
// The relevant information is: in which host the given container is running?
type ContainerStorage interface {
	StoreContainer(container, host string) error
	RetrieveContainer(container string) (host string, err error)
	RemoveContainer(container string) error
}

// ImageStorage works like ContainerStorage, but stores information about
// images and hosts.
type ImageStorage interface {
	StoreImage(image, host string) error
	RetrieveImage(image string) (host string, err error)
	RemoveImage(image string) error
}

type NodeStorage interface {
	StoreNode(id, address string) error
	RetrieveNode(id string) (string, error)
	RetrieveNodes() ([]Node, error)
	RemoveNode(id string) error
}

type Storage interface {
	ContainerStorage
	ImageStorage
	NodeStorage
}

// Node represents a host running Docker. Each node has an ID and an address
// (in the form <scheme>://<host>:<port>/).
type Node struct {
	ID      string
	Address string
}

// Cluster is the basic type of the package. It manages internal nodes, and
// provide methods for interaction with those nodes, like CreateContainer,
// which creates a container in one node of the cluster.
type Cluster struct {
	scheduler Scheduler

	stor  Storage
	mutex sync.RWMutex
}

// New creates a new Cluster, composed by the given nodes.
//
// The parameter Scheduler defines the scheduling strategy, and cannot change.
// It is optional, when set to nil, the cluster will use a round robin strategy
// defined internaly.
// The parameter storage is the storage the cluster instance will use.
func New(scheduler Scheduler, storage Storage, nodes ...Node) (*Cluster, error) {
	var (
		c   Cluster
		err error
	)
	c.stor = storage
	c.scheduler = scheduler
	if scheduler == nil {
		c.scheduler = &roundRobin{lastUsed: -1, stor: storage}
	}
	if len(nodes) > 0 {
		for _, n := range nodes {
			err = c.Register(map[string]string{"address": n.Address, "ID": n.ID})
			if err != nil {
				return &c, err
			}
		}
	}
	return &c, err
}

// Register adds new nodes to the cluster.
func (c *Cluster) Register(params map[string]string) error {
	if r, ok := c.scheduler.(Registrable); ok {
		return r.Register(params)
	}
	return ErrImmutableCluster
}

// Unregister removes nodes from the cluster.
func (c *Cluster) Unregister(params map[string]string) error {
	if r, ok := c.scheduler.(Registrable); ok {
		return r.Unregister(params)
	}
	return ErrImmutableCluster
}

func (c *Cluster) Nodes() ([]Node, error) {
	return c.scheduler.Nodes()
}

func (c *Cluster) storage() Storage {
	c.mutex.RLock()
	defer c.mutex.RUnlock()
	return c.stor
}

type nodeFunc func(node) (interface{}, error)

func (c *Cluster) runOnNodes(fn nodeFunc, errNotFound error, wait bool) (interface{}, error) {
	nodes, err := c.scheduler.Nodes()
	if err != nil {
		return nil, err
	}
	var wg sync.WaitGroup
	finish := make(chan int8, len(nodes))
	errChan := make(chan error, len(nodes))
	result := make(chan interface{}, len(nodes))
	for _, n := range nodes {
		wg.Add(1)
		client, _ := docker.NewClient(n.Address)
		go func(n node) {
			defer wg.Done()
			value, err := fn(n)
			if err == nil {
				result <- value
			} else if e, ok := err.(*docker.Error); ok && e.Status == http.StatusNotFound {
				return
			} else if !reflect.DeepEqual(err, errNotFound) {
				errChan <- err
			}
		}(node{id: n.ID, Client: client})
	}
	if wait {
		wg.Wait()
		select {
		case value := <-result:
			return value, nil
		case err := <-errChan:
			return nil, err
		default:
			return nil, errNotFound
		}
	}
	go func() {
		wg.Wait()
		close(finish)
	}()
	select {
	case value := <-result:
		return value, nil
	case err := <-errChan:
		return nil, err
	case <-finish:
		select {
		case value := <-result:
			return value, nil
		default:
			return nil, errNotFound
		}
	}
}

func (c *Cluster) getNode(retrieveFn func(Storage) (string, error)) (node, error) {
	var n node
	storage := c.storage()
	if storage == nil {
		return n, errStorageDisabled
	}
	id, err := retrieveFn(storage)
	if err != nil {
		return n, err
	}
	nodes, err := c.scheduler.Nodes()
	if err != nil {
		return n, err
	}
	for _, nd := range nodes {
		if nd.ID == id {
			client, _ := docker.NewClient(nd.Address)
			return node{id: nd.ID, Client: client, edp: nd.Address}, nil
		}
	}
	return n, ErrUnknownNode
}
<commit_msg>cluster: receive a Node in StoreNode<commit_after>// Copyright 2014 docker-cluster authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package cluster provides types and functions for management of Docker
// clusters, scheduling container operations among hosts running Docker
// (nodes).
package cluster

import (
	"errors"
	"github.com/fsouza/go-dockerclient"
	"net/http"
	"reflect"
	"sync"
)

var (
	// ErrUnknownNode is the error returned when an unknown node is stored in the
	// storage. This error means some kind of inconsistence between the storage and
	// the cluster.
	ErrUnknownNode = errors.New("Unknown node")

	// ErrImmutableCluster is the error returned by Register when the cluster is
	// immutable, meaning that no new nodes can be registered.
	ErrImmutableCluster = errors.New("Immutable cluster")

	errStorageDisabled = errors.New("Storage is disabled")
)

// ContainerStorage provides methods to store and retrieve information about
// the relation between the node and the container. It can be easily
// represented as a key-value storage.
//
// The relevant information is: in which host the given container is running?
type ContainerStorage interface {
	StoreContainer(container, host string) error
	RetrieveContainer(container string) (host string, err error)
	RemoveContainer(container string) error
}

// ImageStorage works like ContainerStorage, but stores information about
// images and hosts.
type ImageStorage interface {
	StoreImage(image, host string) error
	RetrieveImage(image string) (host string, err error)
	RemoveImage(image string) error
}

type NodeStorage interface {
	StoreNode(node Node) error
	RetrieveNode(id string) (string, error)
	RetrieveNodes() ([]Node, error)
	RemoveNode(id string) error
}

type Storage interface {
	ContainerStorage
	ImageStorage
	NodeStorage
}

// Node represents a host running Docker. Each node has an ID and an address
// (in the form <scheme>://<host>:<port>/).
type Node struct {
	ID      string
	Address string
}

// Cluster is the basic type of the package. It manages internal nodes, and
// provide methods for interaction with those nodes, like CreateContainer,
// which creates a container in one node of the cluster.
type Cluster struct {
	scheduler Scheduler

	stor  Storage
	mutex sync.RWMutex
}

// New creates a new Cluster, composed by the given nodes.
//
// The parameter Scheduler defines the scheduling strategy, and cannot change.
// It is optional, when set to nil, the cluster will use a round robin strategy
// defined internaly.
// The parameter storage is the storage the cluster instance will use.
func New(scheduler Scheduler, storage Storage, nodes ...Node) (*Cluster, error) {
	var (
		c   Cluster
		err error
	)
	c.stor = storage
	c.scheduler = scheduler
	if scheduler == nil {
		c.scheduler = &roundRobin{lastUsed: -1, stor: storage}
	}
	if len(nodes) > 0 {
		for _, n := range nodes {
			err = c.Register(map[string]string{"address": n.Address, "ID": n.ID})
			if err != nil {
				return &c, err
			}
		}
	}
	return &c, err
}

// Register adds new nodes to the cluster.
func (c *Cluster) Register(params map[string]string) error {
	if r, ok := c.scheduler.(Registrable); ok {
		return r.Register(params)
	}
	return ErrImmutableCluster
}

// Unregister removes nodes from the cluster.
func (c *Cluster) Unregister(params map[string]string) error {
	if r, ok := c.scheduler.(Registrable); ok {
		return r.Unregister(params)
	}
	return ErrImmutableCluster
}

func (c *Cluster) Nodes() ([]Node, error) {
	return c.scheduler.Nodes()
}

func (c *Cluster) storage() Storage {
	c.mutex.RLock()
	defer c.mutex.RUnlock()
	return c.stor
}

type nodeFunc func(node) (interface{}, error)

func (c *Cluster) runOnNodes(fn nodeFunc, errNotFound error, wait bool) (interface{}, error) {
	nodes, err := c.scheduler.Nodes()
	if err != nil {
		return nil, err
	}
	var wg sync.WaitGroup
	finish := make(chan int8, len(nodes))
	errChan := make(chan error, len(nodes))
	result := make(chan interface{}, len(nodes))
	for _, n := range nodes {
		wg.Add(1)
		client, _ := docker.NewClient(n.Address)
		go func(n node) {
			defer wg.Done()
			value, err := fn(n)
			if err == nil {
				result <- value
			} else if e, ok := err.(*docker.Error); ok && e.Status == http.StatusNotFound {
				return
			} else if !reflect.DeepEqual(err, errNotFound) {
				errChan <- err
			}
		}(node{id: n.ID, Client: client})
	}
	if wait {
		wg.Wait()
		select {
		case value := <-result:
			return value, nil
		case err := <-errChan:
			return nil, err
		default:
			return nil, errNotFound
		}
	}
	go func() {
		wg.Wait()
		close(finish)
	}()
	select {
	case value := <-result:
		return value, nil
	case err := <-errChan:
		return nil, err
	case <-finish:
		select {
		case value := <-result:
			return value, nil
		default:
			return nil, errNotFound
		}
	}
}

func (c *Cluster) getNode(retrieveFn func(Storage) (string, error)) (node, error) {
	var n node
	storage := c.storage()
	if storage == nil {
		return n, errStorageDisabled
	}
	id, err := retrieveFn(storage)
	if err != nil {
		return n, err
	}
	nodes, err := c.scheduler.Nodes()
	if err != nil {
		return n, err
	}
	for _, nd := range nodes {
		if nd.ID == id {
			client, _ := docker.NewClient(nd.Address)
			return node{id: nd.ID, Client: client, edp: nd.Address}, nil
		}
	}
	return n, ErrUnknownNode
}
<|endoftext|>


<commit_before>package porterstemmer

import (
	"bufio"
	"os"
	"strings"
    "testing"
)

func TestStem(t *testing.T) {

	vocFileName := "testdata/voc.txt"
	vocFd, err := os.Open(vocFileName)
	if nil != err {
		t.Errorf("Could NOT open testdata file: [%s]. Received error: [%v]", vocFileName, err)
/////// RETURN
		return
	}
	defer vocFd.Close()

	voc := bufio.NewReaderSize(vocFd, 1024)

	outFileName := "testdata/output.txt"
	outFd, err := os.Open(outFileName)
	if nil != err {
		t.Errorf("Could NOT open testdata file: [%s]. Received error: [%v]", outFileName, err)
/////// RETURN
		return
	}
	defer outFd.Close()

	out := bufio.NewReaderSize(outFd, 1024)

	for {

		vocS, err := voc.ReadString('\n')
		if nil != err {
	/////// BREAK
			break
		}

		vocS = strings.Trim(vocS, "\n\r\t ")

		expected, err := out.ReadString('\n')
		if nil != err {
			t.Errorf("Received unexpected error when trying to read a line from [%s]. Received error: [%v]", outFileName, err)
	/////// BREAK
			break

		}

		expected = strings.Trim(expected, "\n\r\t ")

		actual := StemString(vocS)
		if expected != actual {
			t.Errorf("Input: [%s] -> Actual: [%s]. Expected: [%s]", vocS, actual, expected)
		}
	}
}
<commit_msg>"TestStem" -> "TestStemSting"<commit_after>package porterstemmer

import (
	"bufio"
	"os"
	"strings"
    "testing"
)

func TestStemString(t *testing.T) {

	vocFileName := "testdata/voc.txt"
	vocFd, err := os.Open(vocFileName)
	if nil != err {
		t.Errorf("Could NOT open testdata file: [%s]. Received error: [%v]", vocFileName, err)
/////// RETURN
		return
	}
	defer vocFd.Close()

	voc := bufio.NewReaderSize(vocFd, 1024)

	outFileName := "testdata/output.txt"
	outFd, err := os.Open(outFileName)
	if nil != err {
		t.Errorf("Could NOT open testdata file: [%s]. Received error: [%v]", outFileName, err)
/////// RETURN
		return
	}
	defer outFd.Close()

	out := bufio.NewReaderSize(outFd, 1024)

	for {

		vocS, err := voc.ReadString('\n')
		if nil != err {
	/////// BREAK
			break
		}

		vocS = strings.Trim(vocS, "\n\r\t ")

		expected, err := out.ReadString('\n')
		if nil != err {
			t.Errorf("Received unexpected error when trying to read a line from [%s]. Received error: [%v]", outFileName, err)
	/////// BREAK
			break

		}

		expected = strings.Trim(expected, "\n\r\t ")

		actual := StemString(vocS)
		if expected != actual {
			t.Errorf("Input: [%s] -> Actual: [%s]. Expected: [%s]", vocS, actual, expected)
		}
	}
}
<|endoftext|>