<commit_before>// proxy bridges between IRC clients (RFC1459) and fancyirc servers.
//
// Proxy instances are supposed to be long-running, and ideally as close to the
// IRC client as possible, e.g. on the same machine. When running on the same
// machine, there should not be any network problems between the IRC client and
// the proxy. Network problems between the proxy and a fancyirc network are
// handled transparently.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"

	"fancyirc/types"

	"github.com/sorcix/irc"
)

var (
	serversList = flag.String("servers",
		"localhost:8001",
		"(comma-separated) list of host:port network addresses of the server(s) to connect to")

	listen = flag.String("listen",
		"localhost:6667",
		"host:port to listen on for IRC connections")

	serversMu     sync.RWMutex
	currentMaster string
	allServers    []string
)

const (
	pathCreateSession = "/robustirc/v1/session"
	pathDeleteSession = "/robustirc/v1/%s"
	pathPostMessage   = "/robustirc/v1/%s/message"
	pathGetMessages   = "/robustirc/v1/%s/messages?lastseen=%s"
)

// TODO(secure): persistent state:
// - the last known server(s) in the network. added to *servers
// - for resuming sessions (later): the last seen message id, perhaps setup messages (JOINs, MODEs, …)
// for hosted mode, this state is stored per-nickname, ideally encrypted with password

// servers returns all configured servers, with the last-known master prepended.
func servers() []string {
	serversMu.RLock()
	defer serversMu.RUnlock()
	return append([]string{currentMaster}, allServers...)
}

func sendFancyMessage(logPrefix, sessionauth, method string, targets []string, path string, data []byte) (*http.Response, error) {
	var (
		resp   *http.Response
		target string
	)
	for {
		var soonest time.Duration
		target = ""
		for target == "" {
			target, soonest = nextCandidate(targets)
			if target == "" {
				log.Printf("%s Waiting %v for back-off time to expire…\n", logPrefix, soonest)
				time.Sleep(soonest)
			}
		}

		log.Printf("%s targets = %v, candidate = %s\n", logPrefix, targets, target)

		var err error
		req, err := http.NewRequest(method, fmt.Sprintf("https://%s%s", target, path), bytes.NewBuffer(data))
		if err != nil {
			return nil, err
		}
		req.Header.Set("X-Session-Auth", sessionauth)
		req.Header.Set("Content-Type", "application/json")
		resp, err = http.DefaultClient.Do(req)

		if err != nil {
			log.Printf("%s %v\n", logPrefix, err)
			serverFailed(target)
			continue
		}

		if resp.StatusCode == http.StatusTemporaryRedirect {
			loc := resp.Header.Get("Location")
			if loc == "" {
				return nil, fmt.Errorf("Redirect has no Location header")
			}
			u, err := url.Parse(loc)
			if err != nil {
				return nil, fmt.Errorf("Could not parse redirection %q: %v", loc, err)
			}

			resp.Body.Close()

			log.Printf("%s %q redirects us to %q\n", logPrefix, target, u.Host)

			// Even though the server did not actually fail, it did not answer our
			// request either. To prevent hammering it, mark it as failed for
			// back-off purposes.
			serverFailed(target)
			targets = append([]string{u.Host}, targets...)
			continue
		}

		if resp.StatusCode != 200 {
			data, _ := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			log.Printf("%s sendFancyMessage(%q) failed with %v: %s", logPrefix, path, resp.Status, string(data))
			serverFailed(target)
			continue
		}

		break
	}
	log.Printf("%s ->fancy: %q\n", logPrefix, string(data))

	serversMu.Lock()
	currentMaster = target
	serversMu.Unlock()
	return resp, nil
}

func sendIRCMessage(logPrefix string, ircConn *irc.Conn, msg irc.Message) {
	if err := ircConn.Encode(&msg); err != nil {
		log.Printf("%s Error sending IRC message %q: %v. Closing connection.\n", logPrefix, msg.Bytes(), err)
		// This leads to an error in .Decode(), terminating the handleIRC goroutine.
		ircConn.Close()
		return
	}
	log.Printf("%s ->irc: %q\n", logPrefix, msg.Bytes())
}

func createFancySession(logPrefix string) (session string, sessionauth string, prefix irc.Prefix, err error) {
	var resp *http.Response
	resp, err = sendFancyMessage(logPrefix, "", "POST", servers(), pathCreateSession, []byte{})
	if err != nil {
		return
	}
	defer resp.Body.Close()

	type createSessionReply struct {
		Sessionid   string
		Sessionauth string
		Prefix      string
	}

	var createreply createSessionReply

	if err = json.NewDecoder(resp.Body).Decode(&createreply); err != nil {
		return
	}

	session = createreply.Sessionid
	sessionauth = createreply.Sessionauth
	prefix = irc.Prefix{Name: createreply.Prefix}
	return
}

func deleteFancySession(logPrefix, sessionauth, session string, quitmsg string) error {
	type deleteSessionRequest struct {
		Quitmessage string
	}
	b, err := json.Marshal(deleteSessionRequest{Quitmessage: quitmsg})
	if err != nil {
		return err
	}
	resp, err := sendFancyMessage(logPrefix, sessionauth, "DELETE", servers(), fmt.Sprintf(pathDeleteSession, session), b)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	log.Printf("%s deleted session\n", logPrefix)

	return nil
}

func handleIRC(conn net.Conn) {
	var (
		logPrefix       = conn.RemoteAddr().String()
		ircConn         = irc.NewConn(conn)
		ircErrors       = make(chan error)
		ircMessages     = make(chan irc.Message)
		fancyMessages   = make(chan string)
		stopGetMessages = make(chan bool)

		ircPrefix   irc.Prefix
		session     string
		sessionauth string
		quitmsg     string
		done        bool
		pingSent    bool
		err         error
	)

	session, sessionauth, ircPrefix, err = createFancySession(logPrefix)
	if err != nil {
		log.Printf("%s Could not create RobustIRC session: %v\n", logPrefix, err)
		sendIRCMessage(logPrefix, ircConn, irc.Message{
			Command:  "ERROR",
			Trailing: fmt.Sprintf("Could not create RobustIRC session: %v", err),
		})

		ircConn.Close()
		return
	}

	go func() {
		for {
			message, err := ircConn.Decode()
			if err != nil {
				ircErrors <- err
				return
			}
			log.Printf("%s <-irc: %q\n", logPrefix, message.Bytes())
			ircMessages <- *message
		}
	}()

	go func() {
		var lastSeen types.FancyId

		for !done {
			host, resp := getMessages(logPrefix, sessionauth, session, lastSeen)

			// We set the host as currentMaster, not because the host is the
			// master, but because it is reachable. When sending messages, we will
			// either reach the master by chance or get redirected, at which point
			// we update currentMaster.
			serversMu.Lock()
			currentMaster = host
			serversMu.Unlock()

			dec := json.NewDecoder(resp.Body)
			msgchan := make(chan types.FancyMessage)
			errchan := make(chan error)

			go func() {
				for {
					var msg types.FancyMessage
					if err := dec.Decode(&msg); err != nil {
						errchan <- err
						return
					}
					msgchan <- msg
				}
			}()

		Readloop:
			for !done {
				select {
				case err := <-errchan:
					log.Printf("%s Protocol error on %q: Could not decode response chunk as JSON: %v\n", logPrefix, host, err)
					serverFailed(host)
					break Readloop

				case <-time.After(1 * time.Minute):
					log.Printf("%s Timeout (60s) on GetMessages, reconnecting…\n", logPrefix)
					serverFailed(host)
					break Readloop

				case <-stopGetMessages:
					log.Printf("%s GetMessages aborted.\n", logPrefix)
					break Readloop

				case msg := <-msgchan:
					if msg.Type == types.FancyPing {
						serversMu.Lock()
						allServers = msg.Servers
						currentMaster = msg.Currentmaster
						serversMu.Unlock()
						log.Printf("received ping (%+v). Servers are now %v\n", msg, servers())
					} else if msg.Type == types.FancyIRCToClient {
						log.Printf("%s <-fancy: %q\n", logPrefix, msg.Data)
						fancyMessages <- msg.Data
						lastSeen = msg.Id
					}
				}
			}
			resp.Body.Close()
		}

		close(fancyMessages)
	}()

	// Cancel the GetMessages goroutine, read all remaining messages to prevent
	// goroutine hangs, then delete the session.
	defer func() {
		stopGetMessages <- true
		for _ = range fancyMessages {
		}

		if err := deleteFancySession(logPrefix, sessionauth, session, quitmsg); err != nil {
			log.Printf("%s Could not delete session: %v\n", logPrefix, err)
		}
	}()

	for {
		select {
		case <-time.After(1 * time.Minute):
			// After no traffic in either direction for 1 minute, we send a PING
			// message. If a PING message was already sent, this means that we did
			// not receive a PONG message, so we close the connection with at
			// timeout.
			if pingSent {
				quitmsg = "ping timeout"
				ircConn.Close()
			} else {
				sendIRCMessage(logPrefix, ircConn, irc.Message{
					Prefix:  &ircPrefix,
					Command: irc.PING,
					Params:  []string{"robustirc.proxy"},
				})
			}

		case err := <-ircErrors:
			log.Printf("Error in IRC client connection: %v\n", err)
			done = true
			return

		case msg := <-fancyMessages:
			if _, err := fmt.Fprintf(conn, "%s\n", msg); err != nil {
				log.Fatal(err)
			}

		case message := <-ircMessages:
			switch message.Command {
			case irc.PONG:
				log.Printf("%s received PONG reply.\n", logPrefix)
				pingSent = false
			case irc.PING:
				sendIRCMessage(logPrefix, ircConn, irc.Message{
					Prefix:  &ircPrefix,
					Command: irc.PONG,
					Params:  message.Params,
				})
			case irc.QUIT:
				quitmsg = message.Trailing
				ircConn.Close()
			default:
				resp, err := sendFancyMessage(logPrefix, sessionauth, "POST", servers(), fmt.Sprintf(pathPostMessage, session), message.Bytes())
				if err != nil {
					// TODO(secure): what should we do here?
					log.Printf("message could not be sent: %v\n", err)
				}
				resp.Body.Close()
			}
		}
	}
}

func main() {
	flag.Parse()

	rand.Seed(time.Now().Unix())

	// Start with any server. Will be overwritten later.
	allServers = strings.Split(*serversList, ",")
	if len(allServers) == 0 {
		log.Fatalf("Invalid -servers value (%q). Need at least one server.\n", *serversList)
	}
	currentMaster = allServers[0]

	ln, err := net.Listen("tcp", *listen)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("RobustIRC IRC bridge listening on %q\n", *listen)

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Printf("Could not accept IRC client connection: %v\n", err)
			continue
		}
		go handleIRC(conn)
	}
}
<commit_msg>speak json in postmessage, limit number of bytes to 1024<commit_after>// proxy bridges between IRC clients (RFC1459) and fancyirc servers.
//
// Proxy instances are supposed to be long-running, and ideally as close to the
// IRC client as possible, e.g. on the same machine. When running on the same
// machine, there should not be any network problems between the IRC client and
// the proxy. Network problems between the proxy and a fancyirc network are
// handled transparently.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"

	"fancyirc/types"

	"github.com/sorcix/irc"
)

var (
	serversList = flag.String("servers",
		"localhost:8001",
		"(comma-separated) list of host:port network addresses of the server(s) to connect to")

	listen = flag.String("listen",
		"localhost:6667",
		"host:port to listen on for IRC connections")

	serversMu     sync.RWMutex
	currentMaster string
	allServers    []string
)

const (
	pathCreateSession = "/robustirc/v1/session"
	pathDeleteSession = "/robustirc/v1/%s"
	pathPostMessage   = "/robustirc/v1/%s/message"
	pathGetMessages   = "/robustirc/v1/%s/messages?lastseen=%s"
)

// TODO(secure): persistent state:
// - the last known server(s) in the network. added to *servers
// - for resuming sessions (later): the last seen message id, perhaps setup messages (JOINs, MODEs, …)
// for hosted mode, this state is stored per-nickname, ideally encrypted with password

// servers returns all configured servers, with the last-known master prepended.
func servers() []string {
	serversMu.RLock()
	defer serversMu.RUnlock()
	return append([]string{currentMaster}, allServers...)
}

func sendFancyMessage(logPrefix, sessionauth, method string, targets []string, path string, data []byte) (*http.Response, error) {
	var (
		resp   *http.Response
		target string
	)
	for {
		var soonest time.Duration
		target = ""
		for target == "" {
			target, soonest = nextCandidate(targets)
			if target == "" {
				log.Printf("%s Waiting %v for back-off time to expire…\n", logPrefix, soonest)
				time.Sleep(soonest)
			}
		}

		log.Printf("%s targets = %v, candidate = %s\n", logPrefix, targets, target)

		var err error
		req, err := http.NewRequest(method, fmt.Sprintf("https://%s%s", target, path), bytes.NewBuffer(data))
		if err != nil {
			return nil, err
		}
		req.Header.Set("X-Session-Auth", sessionauth)
		req.Header.Set("Content-Type", "application/json")
		resp, err = http.DefaultClient.Do(req)

		if err != nil {
			log.Printf("%s %v\n", logPrefix, err)
			serverFailed(target)
			continue
		}

		if resp.StatusCode == http.StatusTemporaryRedirect {
			loc := resp.Header.Get("Location")
			if loc == "" {
				return nil, fmt.Errorf("Redirect has no Location header")
			}
			u, err := url.Parse(loc)
			if err != nil {
				return nil, fmt.Errorf("Could not parse redirection %q: %v", loc, err)
			}

			resp.Body.Close()

			log.Printf("%s %q redirects us to %q\n", logPrefix, target, u.Host)

			// Even though the server did not actually fail, it did not answer our
			// request either. To prevent hammering it, mark it as failed for
			// back-off purposes.
			serverFailed(target)
			targets = append([]string{u.Host}, targets...)
			continue
		}

		if resp.StatusCode != 200 {
			data, _ := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			log.Printf("%s sendFancyMessage(%q) failed with %v: %s", logPrefix, path, resp.Status, string(data))
			serverFailed(target)
			continue
		}

		break
	}
	log.Printf("%s ->fancy: %q\n", logPrefix, string(data))

	serversMu.Lock()
	currentMaster = target
	serversMu.Unlock()
	return resp, nil
}

func sendIRCMessage(logPrefix string, ircConn *irc.Conn, msg irc.Message) {
	if err := ircConn.Encode(&msg); err != nil {
		log.Printf("%s Error sending IRC message %q: %v. Closing connection.\n", logPrefix, msg.Bytes(), err)
		// This leads to an error in .Decode(), terminating the handleIRC goroutine.
		ircConn.Close()
		return
	}
	log.Printf("%s ->irc: %q\n", logPrefix, msg.Bytes())
}

func createFancySession(logPrefix string) (session string, sessionauth string, prefix irc.Prefix, err error) {
	var resp *http.Response
	resp, err = sendFancyMessage(logPrefix, "", "POST", servers(), pathCreateSession, []byte{})
	if err != nil {
		return
	}
	defer resp.Body.Close()

	type createSessionReply struct {
		Sessionid   string
		Sessionauth string
		Prefix      string
	}

	var createreply createSessionReply

	if err = json.NewDecoder(resp.Body).Decode(&createreply); err != nil {
		return
	}

	session = createreply.Sessionid
	sessionauth = createreply.Sessionauth
	prefix = irc.Prefix{Name: createreply.Prefix}
	return
}

func deleteFancySession(logPrefix, sessionauth, session string, quitmsg string) error {
	type deleteSessionRequest struct {
		Quitmessage string
	}
	b, err := json.Marshal(deleteSessionRequest{Quitmessage: quitmsg})
	if err != nil {
		return err
	}
	resp, err := sendFancyMessage(logPrefix, sessionauth, "DELETE", servers(), fmt.Sprintf(pathDeleteSession, session), b)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("got %v, expected 200", resp.Status)
	}

	log.Printf("%s deleted session\n", logPrefix)

	return nil
}

func handleIRC(conn net.Conn) {
	var (
		logPrefix       = conn.RemoteAddr().String()
		ircConn         = irc.NewConn(conn)
		ircErrors       = make(chan error)
		ircMessages     = make(chan irc.Message)
		fancyMessages   = make(chan string)
		stopGetMessages = make(chan bool)

		ircPrefix   irc.Prefix
		session     string
		sessionauth string
		quitmsg     string
		done        bool
		pingSent    bool
		err         error
	)

	session, sessionauth, ircPrefix, err = createFancySession(logPrefix)
	if err != nil {
		log.Printf("%s Could not create RobustIRC session: %v\n", logPrefix, err)
		sendIRCMessage(logPrefix, ircConn, irc.Message{
			Command:  "ERROR",
			Trailing: fmt.Sprintf("Could not create RobustIRC session: %v", err),
		})

		ircConn.Close()
		return
	}

	go func() {
		for {
			message, err := ircConn.Decode()
			if err != nil {
				ircErrors <- err
				return
			}
			log.Printf("%s <-irc: %q\n", logPrefix, message.Bytes())
			ircMessages <- *message
		}
	}()

	go func() {
		var lastSeen types.FancyId

		for !done {
			host, resp := getMessages(logPrefix, sessionauth, session, lastSeen)

			// We set the host as currentMaster, not because the host is the
			// master, but because it is reachable. When sending messages, we will
			// either reach the master by chance or get redirected, at which point
			// we update currentMaster.
			serversMu.Lock()
			currentMaster = host
			serversMu.Unlock()

			dec := json.NewDecoder(resp.Body)
			msgchan := make(chan types.FancyMessage)
			errchan := make(chan error)

			go func() {
				for {
					var msg types.FancyMessage
					if err := dec.Decode(&msg); err != nil {
						errchan <- err
						return
					}
					msgchan <- msg
				}
			}()

		Readloop:
			for !done {
				select {
				case err := <-errchan:
					log.Printf("%s Protocol error on %q: Could not decode response chunk as JSON: %v\n", logPrefix, host, err)
					serverFailed(host)
					break Readloop

				case <-time.After(1 * time.Minute):
					log.Printf("%s Timeout (60s) on GetMessages, reconnecting…\n", logPrefix)
					serverFailed(host)
					break Readloop

				case <-stopGetMessages:
					log.Printf("%s GetMessages aborted.\n", logPrefix)
					break Readloop

				case msg := <-msgchan:
					if msg.Type == types.FancyPing {
						serversMu.Lock()
						allServers = msg.Servers
						currentMaster = msg.Currentmaster
						serversMu.Unlock()
						log.Printf("received ping (%+v). Servers are now %v\n", msg, servers())
					} else if msg.Type == types.FancyIRCToClient {
						log.Printf("%s <-fancy: %q\n", logPrefix, msg.Data)
						fancyMessages <- msg.Data
						lastSeen = msg.Id
					}
				}
			}
			resp.Body.Close()
		}

		close(fancyMessages)
	}()

	// Cancel the GetMessages goroutine, read all remaining messages to prevent
	// goroutine hangs, then delete the session.
	defer func() {
		stopGetMessages <- true
		for _ = range fancyMessages {
		}

		if err := deleteFancySession(logPrefix, sessionauth, session, quitmsg); err != nil {
			log.Printf("%s Could not delete session: %v\n", logPrefix, err)
		}
	}()

	for {
		select {
		case <-time.After(1 * time.Minute):
			// After no traffic in either direction for 1 minute, we send a PING
			// message. If a PING message was already sent, this means that we did
			// not receive a PONG message, so we close the connection with at
			// timeout.
			if pingSent {
				quitmsg = "ping timeout"
				ircConn.Close()
			} else {
				sendIRCMessage(logPrefix, ircConn, irc.Message{
					Prefix:  &ircPrefix,
					Command: irc.PING,
					Params:  []string{"robustirc.proxy"},
				})
			}

		case err := <-ircErrors:
			log.Printf("Error in IRC client connection: %v\n", err)
			done = true
			return

		case msg := <-fancyMessages:
			if _, err := fmt.Fprintf(conn, "%s\n", msg); err != nil {
				log.Fatal(err)
			}

		case message := <-ircMessages:
			switch message.Command {
			case irc.PONG:
				log.Printf("%s received PONG reply.\n", logPrefix)
				pingSent = false
			case irc.PING:
				sendIRCMessage(logPrefix, ircConn, irc.Message{
					Prefix:  &ircPrefix,
					Command: irc.PONG,
					Params:  message.Params,
				})
			case irc.QUIT:
				quitmsg = message.Trailing
				ircConn.Close()
			default:
				type postMessageRequest struct {
					Data string
				}

				b, err := json.Marshal(postMessageRequest{Data: string(message.Bytes())})
				if err != nil {
					log.Printf("Message could not be encoded as JSON: %v\n", err)
					sendIRCMessage(logPrefix, ircConn, irc.Message{
						Prefix: &ircPrefix,
						Command: irc.ERROR,
						Trailing: fmt.Sprintf("Message could not be encoded as JSON: %v", err),
					})
					ircConn.Close()
					break
				}

				resp, err := sendFancyMessage(logPrefix, sessionauth, "POST", servers(), fmt.Sprintf(pathPostMessage, session), b)
				if err != nil {
					// TODO(secure): what should we do here?
					log.Printf("message could not be sent: %v\n", err)
				}
				resp.Body.Close()
			}
		}
	}
}

func main() {
	flag.Parse()

	rand.Seed(time.Now().Unix())

	// Start with any server. Will be overwritten later.
	allServers = strings.Split(*serversList, ",")
	if len(allServers) == 0 {
		log.Fatalf("Invalid -servers value (%q). Need at least one server.\n", *serversList)
	}
	currentMaster = allServers[0]

	ln, err := net.Listen("tcp", *listen)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("RobustIRC IRC bridge listening on %q\n", *listen)

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Printf("Could not accept IRC client connection: %v\n", err)
			continue
		}
		go handleIRC(conn)
	}
}
<|endoftext|>


<commit_before>// weed volume
package weedo

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type Volume struct {
	Url       string
	PublicUrl string
}

func NewVolume(url, publicUrl string) *Volume {
	if !strings.HasPrefix(url, "http:") {
		url = "http://" + url
	}
	if !strings.HasPrefix(publicUrl, "http:") {
		publicUrl = "http://" + publicUrl
	}
	return &Volume{
		Url:       url,
		PublicUrl: publicUrl,
	}
}

// Upload File
func (v *Volume) Upload(fid string, version int, filename, mimeType string, file io.Reader) (size int64, err error) {
	url := v.Url + "/" + fid
	if version > 0 {
		url = url + "_" + strconv.Itoa(version)
	}

	formData, contentType, err := makeFormData(filename, mimeType, file)
	if err != nil {
		return
	}

	resp, err := upload(url, contentType, formData)
	if err == nil {
		size = resp.Size
	}

	return
}

// Upload File Directly
func (v *Volume) Submit(filename, mimeType string, file io.Reader) (fid string, size int64, err error) {
	data, contentType, err := makeFormData(filename, mimeType, file)
	if err != nil {
		return
	}
	resp, err := upload(v.Url+"/submit", contentType, data)
	if err == nil {
		fid = resp.Fid
		size = resp.Size
	}

	return
}

// Delete File
func (v *Volume) Delete(fid string, count int) (err error) {
	if count <= 0 {
		count = 1
	}

	url := v.Url + "/" + fid
	if err := del(url); err != nil {
		return err
	}

	for i := 1; i < count; i++ {
		if err := del(url + "_" + strconv.Itoa(i)); err != nil {
			log.Println(err)
		}
	}

	return nil
}

func (v *Volume) AssignVolume(volumeId uint64, replica string) error {
	values := url.Values{}
	values.Set("volume", strconv.FormatUint(volumeId, 10))
	if len(replica) > 0 {
		values.Set("replication", replica)
	}

	_, err := http.Get(v.Url + "/admin/assign_volume?" + values.Encode())
	return err
}

type volumeStatus struct {
	Version string
	volumes []volume
	Error   string
}

type volume struct {
	Id               uint64
	Size             uint64
	RepType          string
	Version          int
	FileCount        uint64
	DeleteCount      uint64
	DeletedByteCount uint64
	ReadOnly         bool
}

// Check Volume Server Status
func (v *Volume) Status() (err error) {
	url := v.Url
	if !strings.HasPrefix(url, "http://") {
		url = "http://" + url
	}
	resp, err := http.Get(url + "/status")
	if err != nil {
		return
	}

	defer resp.Body.Close()

	status := new(volumeStatus)
	decoder := json.NewDecoder(resp.Body)
	if err = decoder.Decode(status); err != nil {
		log.Println(err)
		return
	}

	if status.Error != "" {
		err = errors.New(status.Error)
		log.Println(err)
		return
	}
	return
}
<commit_msg>fix wrong url<commit_after>// weed volume
package weedo

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type Volume struct {
	Url       string
	PublicUrl string
}

func NewVolume(url, publicUrl string) *Volume {
	if !strings.HasPrefix(url, "http:") {
		url = "http://" + url
	}
	if !strings.HasPrefix(publicUrl, "http:") {
		publicUrl = "http://" + publicUrl
	}
	return &Volume{
		Url:       url,
		PublicUrl: publicUrl,
	}
}

// Upload File
func (v *Volume) Upload(fid string, version int, filename, mimeType string, file io.Reader) (size int64, err error) {
	url := v.PublicUrl + "/" + fid
	if version > 0 {
		url = url + "_" + strconv.Itoa(version)
	}

	formData, contentType, err := makeFormData(filename, mimeType, file)
	if err != nil {
		return
	}

	resp, err := upload(url, contentType, formData)
	if err == nil {
		size = resp.Size
	}

	return
}

// Upload File Directly
func (v *Volume) Submit(filename, mimeType string, file io.Reader) (fid string, size int64, err error) {
	data, contentType, err := makeFormData(filename, mimeType, file)
	if err != nil {
		return
	}
	resp, err := upload(v.PublicUrl+"/submit", contentType, data)
	if err == nil {
		fid = resp.Fid
		size = resp.Size
	}

	return
}

// Delete File
func (v *Volume) Delete(fid string, count int) (err error) {
	if count <= 0 {
		count = 1
	}

	url := v.PublicUrl + "/" + fid
	if err := del(url); err != nil {
		return err
	}

	for i := 1; i < count; i++ {
		if err := del(url + "_" + strconv.Itoa(i)); err != nil {
			log.Println(err)
		}
	}

	return nil
}

func (v *Volume) AssignVolume(volumeId uint64, replica string) error {
	values := url.Values{}
	values.Set("volume", strconv.FormatUint(volumeId, 10))
	if len(replica) > 0 {
		values.Set("replication", replica)
	}

	_, err := http.Get(v.PublicUrl + "/admin/assign_volume?" + values.Encode())
	return err
}

type volumeStatus struct {
	Version string
	volumes []volume
	Error   string
}

type volume struct {
	Id               uint64
	Size             uint64
	RepType          string
	Version          int
	FileCount        uint64
	DeleteCount      uint64
	DeletedByteCount uint64
	ReadOnly         bool
}

// Check Volume Server Status
func (v *Volume) Status() (err error) {
	url := v.PublicUrl
	if !strings.HasPrefix(url, "http://") {
		url = "http://" + url
	}
	resp, err := http.Get(url + "/status")
	if err != nil {
		return
	}

	defer resp.Body.Close()

	status := new(volumeStatus)
	decoder := json.NewDecoder(resp.Body)
	if err = decoder.Decode(status); err != nil {
		log.Println(err)
		return
	}

	if status.Error != "" {
		err = errors.New(status.Error)
		log.Println(err)
		return
	}
	return
}
<|endoftext|>


<commit_before>package medtronic

import (
	"log"
	"time"
)

const (
	Wakeup CommandCode = 0x5D
)

func (pump *Pump) Wakeup() {
	pump.Model()
	if pump.Error() == nil {
		return
	}
	log.Printf("waking pump")
	const (
		// Older pumps should have RF enabled to increase the
		// frequency with which they listen for wakeups.
		numWakeups = 75
		xmitDelay  = 35 * time.Millisecond
	)
	packet := commandPacket(Wakeup, nil)
	for i := 0; i < numWakeups; i++ {
		pump.Radio.Send(packet)
		time.Sleep(xmitDelay)
	}
	n := pump.Retries()
	pump.SetRetries(1)
	defer pump.SetRetries(n)
	t := pump.Timeout()
	pump.SetTimeout(10 * time.Second)
	defer pump.SetTimeout(t)
	pump.Execute(Wakeup, nil)
}
<commit_msg>Clear error after no response<commit_after>package medtronic

import (
	"log"
	"time"
)

const (
	Wakeup CommandCode = 0x5D
)

func (pump *Pump) Wakeup() {
	pump.Model()
	if pump.Error() == nil {
		return
	}
	pump.SetError(nil)
	log.Printf("waking pump")
	const (
		// Older pumps should have RF enabled to increase the
		// frequency with which they listen for wakeups.
		numWakeups = 100
		xmitDelay  = 10 * time.Millisecond
	)
	packet := commandPacket(Wakeup, nil)
	for i := 0; i < numWakeups; i++ {
		pump.Radio.Send(packet)
		time.Sleep(xmitDelay)
	}
	n := pump.Retries()
	pump.SetRetries(1)
	defer pump.SetRetries(n)
	t := pump.Timeout()
	pump.SetTimeout(10 * time.Second)
	defer pump.SetTimeout(t)
	pump.Execute(Wakeup, nil)
}
<|endoftext|>


<commit_before>// Copyright 2019 The Hugo Authors. All rights reserved.
// Some functions in this file (see comments) is based on the Go source code,
// copyright The Go Authors and  governed by a BSD-style license.
//
// 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 hreflect contains reflect helpers.
package hreflect

import (
	"reflect"

	"github.com/gohugoio/hugo/common/types"
)

// TODO(bep) replace the private versions in /tpl with these.
// IsInt returns whether the given kind is a number.
func IsNumber(kind reflect.Kind) bool {
	return IsInt(kind) || IsUint(kind) || IsFloat(kind)
}

// IsInt returns whether the given kind is an int.
func IsInt(kind reflect.Kind) bool {
	switch kind {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return true
	default:
		return false
	}
}

// IsUint returns whether the given kind is an uint.
func IsUint(kind reflect.Kind) bool {
	switch kind {
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return true
	default:
		return false
	}
}

// IsFloat returns whether the given kind is a float.
func IsFloat(kind reflect.Kind) bool {
	switch kind {
	case reflect.Float32, reflect.Float64:
		return true
	default:
		return false
	}
}

// IsTruthful returns whether in represents a truthful value.
// See IsTruthfulValue
func IsTruthful(in interface{}) bool {
	switch v := in.(type) {
	case reflect.Value:
		return IsTruthfulValue(v)
	default:
		return IsTruthfulValue(reflect.ValueOf(in))
	}
}

var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()

// IsTruthfulValue returns whether the given value has a meaningful truth value.
// This is based on template.IsTrue in Go's stdlib, but also considers
// IsZero and any interface value will be unwrapped before it's considered
// for truthfulness.
//
// Based on:
// https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L306
func IsTruthfulValue(val reflect.Value) (truth bool) {
	val = indirectInterface(val)

	if !val.IsValid() {
		// Something like var x interface{}, never set. It's a form of nil.
		return
	}

	if val.Type().Implements(zeroType) {
		return !val.Interface().(types.Zeroer).IsZero()
	}

	switch val.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		truth = val.Len() > 0
	case reflect.Bool:
		truth = val.Bool()
	case reflect.Complex64, reflect.Complex128:
		truth = val.Complex() != 0
	case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
		truth = !val.IsNil()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		truth = val.Int() != 0
	case reflect.Float32, reflect.Float64:
		truth = val.Float() != 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		truth = val.Uint() != 0
	case reflect.Struct:
		truth = true // Struct values are always true.
	default:
		return
	}

	return
}

// Based on: https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L931
func indirectInterface(v reflect.Value) reflect.Value {
	if v.Kind() != reflect.Interface {
		return v
	}
	if v.IsNil() {
		return reflect.Value{}
	}
	return v.Elem()
}
<commit_msg>Correct function name in comment<commit_after>// Copyright 2019 The Hugo Authors. All rights reserved.
// Some functions in this file (see comments) is based on the Go source code,
// copyright The Go Authors and  governed by a BSD-style license.
//
// 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 hreflect contains reflect helpers.
package hreflect

import (
	"reflect"

	"github.com/gohugoio/hugo/common/types"
)

// TODO(bep) replace the private versions in /tpl with these.
// IsNumber returns whether the given kind is a number.
func IsNumber(kind reflect.Kind) bool {
	return IsInt(kind) || IsUint(kind) || IsFloat(kind)
}

// IsInt returns whether the given kind is an int.
func IsInt(kind reflect.Kind) bool {
	switch kind {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return true
	default:
		return false
	}
}

// IsUint returns whether the given kind is an uint.
func IsUint(kind reflect.Kind) bool {
	switch kind {
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return true
	default:
		return false
	}
}

// IsFloat returns whether the given kind is a float.
func IsFloat(kind reflect.Kind) bool {
	switch kind {
	case reflect.Float32, reflect.Float64:
		return true
	default:
		return false
	}
}

// IsTruthful returns whether in represents a truthful value.
// See IsTruthfulValue
func IsTruthful(in interface{}) bool {
	switch v := in.(type) {
	case reflect.Value:
		return IsTruthfulValue(v)
	default:
		return IsTruthfulValue(reflect.ValueOf(in))
	}
}

var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()

// IsTruthfulValue returns whether the given value has a meaningful truth value.
// This is based on template.IsTrue in Go's stdlib, but also considers
// IsZero and any interface value will be unwrapped before it's considered
// for truthfulness.
//
// Based on:
// https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L306
func IsTruthfulValue(val reflect.Value) (truth bool) {
	val = indirectInterface(val)

	if !val.IsValid() {
		// Something like var x interface{}, never set. It's a form of nil.
		return
	}

	if val.Type().Implements(zeroType) {
		return !val.Interface().(types.Zeroer).IsZero()
	}

	switch val.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		truth = val.Len() > 0
	case reflect.Bool:
		truth = val.Bool()
	case reflect.Complex64, reflect.Complex128:
		truth = val.Complex() != 0
	case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
		truth = !val.IsNil()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		truth = val.Int() != 0
	case reflect.Float32, reflect.Float64:
		truth = val.Float() != 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		truth = val.Uint() != 0
	case reflect.Struct:
		truth = true // Struct values are always true.
	default:
		return
	}

	return
}

// Based on: https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L931
func indirectInterface(v reflect.Value) reflect.Value {
	if v.Kind() != reflect.Interface {
		return v
	}
	if v.IsNil() {
		return reflect.Value{}
	}
	return v.Elem()
}
<|endoftext|>


<commit_before>package maker

import (
	"strings"
	"testing"
)

func check(value, pattern string, t *testing.T) {
	if value != pattern {
		t.Fatalf("Value %s did not match expected pattern %s", value, pattern)
	}
}

func TestLines(t *testing.T) {
	docs := []string{`// TestMethod is great`}
	code := `func TestMethod() string {return "I am great"}`
	method := Method{Code: code, Docs: docs}
	lines := method.Lines()
	check(lines[0], "// TestMethod is great", t)
	check(lines[1], "func TestMethod() string {return \"I am great\"}", t)
}

func TestParseStruct(t *testing.T) {
	src := []byte(`package main

	    import (
		"fmt"
	    )

	    // Person ...
	    type Person struct {
		name string
	    }

	    // Name ...
	    func (p *Person) Name() string {
		return p.name
	    }`)
	methods, imports := ParseStruct(src, "Person", true)
	check(methods[0].Code, "Name() string", t)
	imp := imports[0]
	trimmedImp := strings.TrimSpace(imp)
	expected := "\"fmt\""
	check(trimmedImp, expected, t)
}

func Test
<commit_msg>Delete a trailing beginning of another test case<commit_after>package maker

import (
	"strings"
	"testing"
)

func check(value, pattern string, t *testing.T) {
	if value != pattern {
		t.Fatalf("Value %s did not match expected pattern %s", value, pattern)
	}
}

func TestLines(t *testing.T) {
	docs := []string{`// TestMethod is great`}
	code := `func TestMethod() string {return "I am great"}`
	method := Method{Code: code, Docs: docs}
	lines := method.Lines()
	check(lines[0], "// TestMethod is great", t)
	check(lines[1], "func TestMethod() string {return \"I am great\"}", t)
}

func TestParseStruct(t *testing.T) {
	src := []byte(`package main

	    import (
		"fmt"
	    )

	    // Person ...
	    type Person struct {
		name string
	    }

	    // Name ...
	    func (p *Person) Name() string {
		return p.name
	    }`)
	methods, imports := ParseStruct(src, "Person", true)
	check(methods[0].Code, "Name() string", t)
	imp := imports[0]
	trimmedImp := strings.TrimSpace(imp)
	expected := "\"fmt\""
	check(trimmedImp, expected, t)
}
<|endoftext|>


<commit_before>package fileutil

import (
	"fmt"
	"github.com/APTrust/easy-store/util/platform"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

type FileSystemIterator struct {
	rootPath string
	files    []string
	index    int
}

func NewFileSystemIterator(pathToDir string) (*FileSystemIterator, error) {
	if !filepath.IsAbs(pathToDir) {
		return nil, fmt.Errorf("Path '%s' must be absolute.", pathToDir)
	}
	var stat os.FileInfo
	var err error
	if stat, err = os.Stat(pathToDir); os.IsNotExist(err) {
		return nil, fmt.Errorf("Directory '%s' does not exist.", pathToDir)
	}
	if !stat.IsDir() {
		return nil, fmt.Errorf("Path '%s' is not a directory.", pathToDir)
	}
	files, err := RecursiveFileList(pathToDir)
	if err != nil {
		return nil, err
	}
	return &FileSystemIterator{
		rootPath: pathToDir,
		files:    files,
		index:    -1,
	}, nil
}

// Close is a no-op. It's here so that FileSystemIterator can adhere
// to the ReadIterator interface.
func (iter *FileSystemIterator) Close() {
	return
}

// Returns an open reader for the next file, along with a FileSummary.
// Returns io.EOF when it reaches the last file.
// The caller is responsible for closing the reader.
func (iter *FileSystemIterator) Next() (io.ReadCloser, *FileSummary, error) {
	iter.index += 1
	if iter.index >= len(iter.files) {
		return nil, nil, io.EOF
	}
	filePath := iter.files[iter.index]
	var stat os.FileInfo
	var err error
	if stat, err = os.Stat(filePath); os.IsNotExist(err) {
		return nil, nil, fmt.Errorf("File '%s' does not exist.", filePath)
	}
	fileMode := stat.Mode()
	fs := &FileSummary{
		RelPath:       strings.Replace(filePath, iter.rootPath+string(os.PathSeparator), "", 1),
		Mode:          fileMode,
		Size:          stat.Size(),
		ModTime:       stat.ModTime(),
		IsDir:         stat.IsDir(),
		IsRegularFile: fileMode.IsRegular(),
	}
	uid, gid := platform.FileOwnerAndGroup(stat)
	fs.Uid = uid
	fs.Gid = gid
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fs, fmt.Errorf("Cannot read file '%s': %v", filePath, err)
	}
	return file, fs, nil
}

// OpenFile opens the file at filePath, and returns an open reader for it.
// It's the caller's job to close the reader. Param filePath should
// be the relative path of the file within the bag. Will return a
// nil ReadCloser and an error if file is not found.
func (iter *FileSystemIterator) OpenFile(filePath string) (io.ReadCloser, error) {
	fullPath := filepath.Join(iter.rootPath, filePath)
	if !FileExists(fullPath) {
		return nil, fmt.Errorf("File %s does not exist", fullPath)
	}
	return os.Open(fullPath)
}

// FindMatchingFiles returns a list of files whose names match
// the supplied regular expression. Note that this returns the relative
// path of the file within the bag. To get the full (absolute) path in
// the file system, you'll to prepend this iterator's root directory.
func (iter *FileSystemIterator) FindMatchingFiles(regex *regexp.Regexp) ([]string, error) {
	matches := make([]string, 0)
	checkFile := func(pathToFile string, info os.FileInfo, err error) error {
		relFilePath := strings.Replace(pathToFile, iter.rootPath, "", 1)
		if strings.HasPrefix(relFilePath, string(os.PathSeparator)) {
			relFilePath = strings.Replace(relFilePath, string(os.PathSeparator), "", 1)
		}
		if regex.MatchString(relFilePath) {
			matches = append(matches, relFilePath)
		}
		return nil
	}
	err := filepath.Walk(iter.rootPath, checkFile)
	return matches, err
}

// Returns the last component of the path that this iterator is traversing.
// That will be a slice of strings, with exactly one item. We return a slice
// instead of a string to maintain API compatibility with the ReadIterator
// interface.
func (iter *FileSystemIterator) GetTopLevelDirNames() []string {
	// cleanRootPath removes "C:" or "\\host\share" from Windows paths
	cleanRootPath := strings.Replace(iter.rootPath, filepath.VolumeName(iter.rootPath), "", 1)
	pathParts := strings.Split(cleanRootPath, string(os.PathSeparator))
	topLevelDirs := make([]string, 1)
	topLevelDirs[0] = pathParts[len(pathParts)-1]
	return topLevelDirs
}
<commit_msg>Convert Windows path to proper RelPath in FileSystemIterator<commit_after>package fileutil

import (
	"fmt"
	"github.com/APTrust/easy-store/util/platform"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

type FileSystemIterator struct {
	rootPath string
	files    []string
	index    int
}

func NewFileSystemIterator(pathToDir string) (*FileSystemIterator, error) {
	if !filepath.IsAbs(pathToDir) {
		return nil, fmt.Errorf("Path '%s' must be absolute.", pathToDir)
	}
	var stat os.FileInfo
	var err error
	if stat, err = os.Stat(pathToDir); os.IsNotExist(err) {
		return nil, fmt.Errorf("Directory '%s' does not exist.", pathToDir)
	}
	if !stat.IsDir() {
		return nil, fmt.Errorf("Path '%s' is not a directory.", pathToDir)
	}
	files, err := RecursiveFileList(pathToDir)
	if err != nil {
		return nil, err
	}
	return &FileSystemIterator{
		rootPath: pathToDir,
		files:    files,
		index:    -1,
	}, nil
}

// Close is a no-op. It's here so that FileSystemIterator can adhere
// to the ReadIterator interface.
func (iter *FileSystemIterator) Close() {
	return
}

// Returns an open reader for the next file, along with a FileSummary.
// Returns io.EOF when it reaches the last file.
// The caller is responsible for closing the reader.
func (iter *FileSystemIterator) Next() (io.ReadCloser, *FileSummary, error) {
	iter.index += 1
	if iter.index >= len(iter.files) {
		return nil, nil, io.EOF
	}
	filePath := iter.files[iter.index]
	var stat os.FileInfo
	var err error
	if stat, err = os.Stat(filePath); os.IsNotExist(err) {
		return nil, nil, fmt.Errorf("File '%s' does not exist.", filePath)
	}
	relPath := strings.Replace(filePath, iter.rootPath+string(os.PathSeparator), "", 1)
	if runtime.GOOS == "windows" {
		relPath = strings.Replace(relPath, "\\", "/", -1)
	}
	fileMode := stat.Mode()
	fs := &FileSummary{
		RelPath:       relPath,
		Mode:          fileMode,
		Size:          stat.Size(),
		ModTime:       stat.ModTime(),
		IsDir:         stat.IsDir(),
		IsRegularFile: fileMode.IsRegular(),
	}
	uid, gid := platform.FileOwnerAndGroup(stat)
	fs.Uid = uid
	fs.Gid = gid
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fs, fmt.Errorf("Cannot read file '%s': %v", filePath, err)
	}
	return file, fs, nil
}

// OpenFile opens the file at filePath, and returns an open reader for it.
// It's the caller's job to close the reader. Param filePath should
// be the relative path of the file within the bag. Will return a
// nil ReadCloser and an error if file is not found.
func (iter *FileSystemIterator) OpenFile(filePath string) (io.ReadCloser, error) {
	fullPath := filepath.Join(iter.rootPath, filePath)
	if !FileExists(fullPath) {
		return nil, fmt.Errorf("File %s does not exist", fullPath)
	}
	return os.Open(fullPath)
}

// FindMatchingFiles returns a list of files whose names match
// the supplied regular expression. Note that this returns the relative
// path of the file within the bag. To get the full (absolute) path in
// the file system, you'll to prepend this iterator's root directory.
func (iter *FileSystemIterator) FindMatchingFiles(regex *regexp.Regexp) ([]string, error) {
	matches := make([]string, 0)
	checkFile := func(pathToFile string, info os.FileInfo, err error) error {
		relFilePath := strings.Replace(pathToFile, iter.rootPath, "", 1)
		if strings.HasPrefix(relFilePath, string(os.PathSeparator)) {
			relFilePath = strings.Replace(relFilePath, string(os.PathSeparator), "", 1)
		}
		if regex.MatchString(relFilePath) {
			matches = append(matches, relFilePath)
		}
		return nil
	}
	err := filepath.Walk(iter.rootPath, checkFile)
	return matches, err
}

// Returns the last component of the path that this iterator is traversing.
// That will be a slice of strings, with exactly one item. We return a slice
// instead of a string to maintain API compatibility with the ReadIterator
// interface.
func (iter *FileSystemIterator) GetTopLevelDirNames() []string {
	// cleanRootPath removes "C:" or "\\host\share" from Windows paths
	cleanRootPath := strings.Replace(iter.rootPath, filepath.VolumeName(iter.rootPath), "", 1)
	pathParts := strings.Split(cleanRootPath, string(os.PathSeparator))
	topLevelDirs := make([]string, 1)
	topLevelDirs[0] = pathParts[len(pathParts)-1]
	return topLevelDirs
}
<|endoftext|>


<commit_before>package device

import (
	"encoding/json"
	"github.com/Comcast/webpa-common/httperror"
	"github.com/Comcast/webpa-common/logging"
	"net/http"
)

// NewConnectHandler produces an http.Handler that allows devices to connect
// to a specific Manager.
func NewConnectHandler(manager Manager, logger logging.Logger) http.Handler {
	if logger == nil {
		logger = logging.DefaultLogger()
	}

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		device, err := manager.Connect(response, request, nil)
		if err != nil {
			logger.Error("Failed to connect device: %s", err)
		} else {
			logger.Debug("Connected device: %s", device.ID())
		}
	})
}

// NewDeviceListHandler returns an http.Handler that renders a JSON listing
// of the devices within a manager.
func NewDeviceListHandler(manager Manager, timeLayout string) http.Handler {
	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		devices := make(map[ID][]map[string]interface{})
		manager.VisitAll(func(device Interface) {
			entry := map[string]interface{}{
				"connectedAt": device.ConnectedAt().Format(timeLayout),
			}

			convey := device.Convey()
			if convey != nil && len(convey.decoded) > 0 {
				entry["convey"] = convey.decoded
			}

			key := device.ID()
			devices[key] = append(devices[key], entry)
		})

		data, err := json.Marshal(devices)
		if err != nil {
			httperror.Write(response, err)
			return
		}

		response.Header().Set("Content-Type", "application/json")
		response.Write(data)
	})
}
<commit_msg>Allow custom response headers when creating the connect handler<commit_after>package device

import (
	"encoding/json"
	"github.com/Comcast/webpa-common/httperror"
	"github.com/Comcast/webpa-common/logging"
	"net/http"
)

// NewConnectHandler produces an http.Handler that allows devices to connect
// to a specific Manager.
func NewConnectHandler(manager Manager, responseHeader http.Header, logger logging.Logger) http.Handler {
	if logger == nil {
		logger = logging.DefaultLogger()
	}

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		device, err := manager.Connect(response, request, responseHeader)
		if err != nil {
			logger.Error("Failed to connect device: %s", err)
		} else {
			logger.Debug("Connected device: %s", device.ID())
		}
	})
}

// NewDeviceListHandler returns an http.Handler that renders a JSON listing
// of the devices within a manager.
func NewDeviceListHandler(manager Manager, timeLayout string) http.Handler {
	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		devices := make(map[ID][]map[string]interface{})
		manager.VisitAll(func(device Interface) {
			entry := map[string]interface{}{
				"connectedAt": device.ConnectedAt().Format(timeLayout),
			}

			convey := device.Convey()
			if convey != nil && len(convey.decoded) > 0 {
				entry["convey"] = convey.decoded
			}

			key := device.ID()
			devices[key] = append(devices[key], entry)
		})

		data, err := json.Marshal(devices)
		if err != nil {
			httperror.Write(response, err)
			return
		}

		response.Header().Set("Content-Type", "application/json")
		response.Write(data)
	})
}
<|endoftext|>


<commit_before>package nuage_v3_2

import (
	"encoding/json"
	"fmt"
	"nuage"

	log "github.com/Sirupsen/logrus"
)

func (orglist *EnterpriseSlice) EnterprisesList(c *nuage.Connection) error {

	log.Debug("Entering: EnterpriseList")

	// XXX - Alternative
	// var orgs []Enterprise

	reply, err := nuage.ListEnterprises(c)
	if err != nil {
		log.Debugf("EnterpriseList: Unable to obtain Enterprise list: %s ", err)
		return err
	}

	// XXX - Alternative
	// err = json.Unmarshal(reply, &orgs)
	err = json.Unmarshal(reply, orglist)

	if err != nil {
		log.Debugf("EnterpriseList: Unable to decode JSON payload: %s ", err)
		return err
	}

	//// var orgs []Enterprise
	////
	//// orgs = *orglist
	////
	//// for i, v := range orgs {
	//// 	jsonorg, _ := json.MarshalIndent(v, "", "\t")
	//// 	fmt.Printf("\n\n ===> Org nr [%d]: [%s] <=== \n%#s\n", i, orgs[i].Name, string(jsonorg))
	//// }

	// XXX - Alternative: This effeticvely converts "EnterpriseSlice" to "[]Enterprise"
	// *orglist = orgs

	// log.Fatal("\n\n KABOOM ?? Yes Rico, KABOOM..\n\n")

	return nil
}

// Enterprise Delete
func (org *Enterprise) EnterpriseDelete(c *nuage.Connection) error {

	// XXX -- this will mutate the receiver

	err := org.EnterpriseGet(c)

	if err != nil {
		log.Debugf("EnterpriseDelete: Unable to delete Enterprise with name %s . Error: %s ", org.Name, err)
		return err
	}

	_, err = nuage.DeleteEnterprise(c, org.ID)

	if err != nil {
		log.Debugf("EnterpriseDelete: Unable to delete Enterprise with name %s . Error: %s ", org.Name, err)
		return err
	}

	log.Debugf("EnterpriseDelete: Deleteing Enterprise [%s] with ID: [%s] ", org.Name, org.ID)

	return nil

}

// Assumes that the method receiver was allocated using "new(Enterprise)", initialized accordingly (name + description).  Relies on lower level / API version indep ListEnterprises
func (org *Enterprise) EnterpriseCreate(c *nuage.Connection) error {

	// It has to be an array since the reply from the server is as an array of JSON objects, and we use it for decoding as well
	var myorg [1]Enterprise

	myorg[0].Name = org.Name

	if org.Description == "" {
		// Default Enterpise Description unless one is specified
		myorg[0].Description = "Created by Golang API driver"
	} else {
		myorg[0].Description = org.Description
	}

	jsonorg, _ := json.MarshalIndent(myorg[0], "", "\t")

	// Quick and dirty alternative: Just build a JSON object with "name" and "description" fields
	// jsonorg := "      {\"name\":\"" + name + "\",\"description\":\"Created by Golang API client\"}      "

	reply, err := nuage.CreateEnterprise(c, jsonorg)

	if err != nil {
		log.Debugf("EnterpriseCreate: Unable to create Enterprise with name: %s . Error: %s ", org.Name, err)
		return err
	}

	err = json.Unmarshal(reply, &myorg)

	if err != nil {
		log.Debugf("EnterpriseCreate: Unable to decode JSON payload: %s ", err)
		return err
	}

	// XXX -- Mutate the method receiver
	*org = myorg[0]
	return nil

}

// Assumes that the method receiver was allocated using "new(Enterprise)" with name (org.Name) or ID (org.ID) initialized.  Relies on lower level / API version indep ListEnterprises
func (org *Enterprise) EnterpriseGet(c *nuage.Connection) error {

	reply, err := nuage.ListEnterprises(c)

	if err != nil {
		log.Debugf("EnterpriseGet: Unable to obtain Enterprise list: %s ", err)
		return err
	}

	// XXX -- Need an []Enterprise since the answer is an array of JSON objects (with a single member)
	var orgs []Enterprise
	err = json.Unmarshal(reply, &orgs)

	if err != nil {
		log.Debugf("EnterpriseGet: Unable to decode JSON payload: %s ", err)
		return err
	}

	for _, v := range orgs {
		if org.Name == v.Name || org.ID == v.ID {
			// XXX -- Mutate the method receiver
			*org = v
			return nil
		}
	}

	err = fmt.Errorf("EnterpriseGet: Unable to find Enterprise with name: %s", org.Name)
	return err

}
<commit_msg>Fixed typos<commit_after>package nuage_v3_2

import (
	"encoding/json"
	"fmt"

	nuage "github.com/FlorianOtel/nuage"

	log "github.com/Sirupsen/logrus"
)

func (orglist *EnterpriseSlice) EnterprisesList(c *nuage.Connection) error {

	log.Debug("Entering: EnterpriseList")

	// XXX - Alternative
	// var orgs []Enterprise

	reply, err := nuage.ListEnterprises(c)
	if err != nil {
		log.Debugf("EnterpriseList: Unable to obtain Enterprise list: %s ", err)
		return err
	}

	// XXX - Alternative
	// err = json.Unmarshal(reply, &orgs)
	err = json.Unmarshal(reply, orglist)

	if err != nil {
		log.Debugf("EnterpriseList: Unable to decode JSON payload: %s ", err)
		return err
	}

	//// var orgs []Enterprise
	////
	//// orgs = *orglist
	////
	//// for i, v := range orgs {
	//// 	jsonorg, _ := json.MarshalIndent(v, "", "\t")
	//// 	fmt.Printf("\n\n ===> Org nr [%d]: [%s] <=== \n%#s\n", i, orgs[i].Name, string(jsonorg))
	//// }

	// XXX - Alternative: This effeticvely converts "EnterpriseSlice" to "[]Enterprise"
	// *orglist = orgs

	// log.Fatal("\n\n KABOOM ?? Yes Rico, KABOOM..\n\n")

	return nil
}

// Enterprise Delete
func (org *Enterprise) EnterpriseDelete(c *nuage.Connection) error {

	// XXX -- this will mutate the receiver

	err := org.EnterpriseGet(c)

	if err != nil {
		log.Debugf("EnterpriseDelete: Unable to delete Enterprise with name %s . Error: %s ", org.Name, err)
		return err
	}

	_, err = nuage.DeleteEnterprise(c, org.ID)

	if err != nil {
		log.Debugf("EnterpriseDelete: Unable to delete Enterprise with name %s . Error: %s ", org.Name, err)
		return err
	}

	log.Debugf("EnterpriseDelete: Deleteing Enterprise [%s] with ID: [%s] ", org.Name, org.ID)

	return nil

}

// Assumes that the method receiver was allocated using "new(Enterprise)", initialized accordingly (name + description).  Relies on lower level / API version indep ListEnterprises
func (org *Enterprise) EnterpriseCreate(c *nuage.Connection) error {

	// It has to be an array since the reply from the server is as an array of JSON objects, and we use it for decoding as well
	var myorg [1]Enterprise

	myorg[0].Name = org.Name

	if org.Description == "" {
		// Default Enterpise Description unless one is specified
		myorg[0].Description = "Created by Golang API driver"
	} else {
		myorg[0].Description = org.Description
	}

	jsonorg, _ := json.MarshalIndent(myorg[0], "", "\t")

	// Quick and dirty alternative: Just build a JSON object with "name" and "description" fields
	// jsonorg := "      {\"name\":\"" + name + "\",\"description\":\"Created by Golang API client\"}      "

	reply, err := nuage.CreateEnterprise(c, jsonorg)

	if err != nil {
		log.Debugf("EnterpriseCreate: Unable to create Enterprise with name: %s . Error: %s ", org.Name, err)
		return err
	}

	err = json.Unmarshal(reply, &myorg)

	if err != nil {
		log.Debugf("EnterpriseCreate: Unable to decode JSON payload: %s ", err)
		return err
	}

	// XXX -- Mutate the method receiver
	*org = myorg[0]
	return nil

}

// Assumes that the method receiver was allocated using "new(Enterprise)" with name (org.Name) or ID (org.ID) initialized.  Relies on lower level / API version indep ListEnterprises
func (org *Enterprise) EnterpriseGet(c *nuage.Connection) error {

	reply, err := nuage.ListEnterprises(c)

	if err != nil {
		log.Debugf("EnterpriseGet: Unable to obtain Enterprise list: %s ", err)
		return err
	}

	// XXX -- Need an []Enterprise since the answer is an array of JSON objects (with a single member)
	var orgs []Enterprise
	err = json.Unmarshal(reply, &orgs)

	if err != nil {
		log.Debugf("EnterpriseGet: Unable to decode JSON payload: %s ", err)
		return err
	}

	for _, v := range orgs {
		if org.Name == v.Name || org.ID == v.ID {
			// XXX -- Mutate the method receiver
			*org = v
			return nil
		}
	}

	err = fmt.Errorf("EnterpriseGet: Unable to find Enterprise with name: %s", org.Name)
	return err

}
<|endoftext|>


<commit_before>// Copyright 2017, TCN Inc.
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of TCN Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package templates

const SpannerUnaryMethodTemplate = `{{define "spanner_unary_method"}}// spanner unary select {{.GetName}}
func (s* {{.GetServiceName}}Impl) {{.GetName}} (ctx context.Context, req *{{.GetInputType}}) (*{{.GetOutputType}}, error) {
{{if .Spanner.IsSelect}}{{template "spanner_unary_select" .}}{{end}}
{{if .Spanner.IsUpdate}}{{template "spanner_unary_update" .}}{{end}}
{{if .Spanner.IsInsert}}{{template "spanner_unary_insert" .}}{{end}}
{{if .Spanner.IsDelete}}{{template "spanner_unary_delete" .}}{{end}}
{{end}}`

const SpannerUnarySelectTemplate = `{{define "spanner_unary_select"}}
	var err error
	var (
{{range $field, $type := .GetFieldsWithLocalTypesFor .GetOutputTypeStruct}}
		{{$field}} {{$type}}{{end}}
	)

	{{template "declare_spanner_arg_map" .}}

	//stmt := spanner.Statement{SQL: "{ {.Spanner.Query} }", Params: params}
	stmt := spanner.Statement{SQL: "{{.Spanner.Query}}", Params: params}
	tx := s.SpannerDB.Single()
	defer tx.Close()
	iter := tx.Query(ctx, stmt)
	defer iter.Stop()
	row, err := iter.Next()
	if err == iterator.Done {
		return nil, grpc.Errorf(codes.NotFound, "no rows found")
	} else if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}

	// scan our values out of the row
	{{range $index, $t := .GetTypeDescArrayForStruct .GetOutputTypeStruct}}
	{{if $t.IsMapped}}
	gcv := new(spanner.GenericColumnValue)
	err = row.ColumnByName("{{$t.ProtoName}}", gcv)
	if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}
	err = {{$t.Name}}.SpannerScan(gcv)
	if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}
	{{else}}
	err = row.ColumnByName("{{$t.ProtoName}}", &{{$t.Name}})
	if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}
	{{end}}{{end}}

	_, err = iter.Next()
	if err != iterator.Done {
		fmt.Println("Unary select that returns more than one row..")
	}
	//res := &{ {.GetOutputType} }{
	res := &{{.GetOutputType}}{
	{{range $field, $type := .GetTypeDescForFieldsInStruct .GetOutputTypeStruct}}
	{{$field}}: {{template "addr" $type}}{{template "base" $type}}{{template "mapping" $type}},{{end}}
	}
	return res, nil
}
{{end}}`

const SpannerUnaryInsertTemplate = `{{define "spanner_unary_insert"}}
	var err error
	{{template "declare_spanner_arg_slice" .}}

	muts := make([]*spanner.Mutation, 1)
	muts[0] = spanner.Insert("{{.Spanner.TableName}}", {{.Spanner.InsertColsAsString}}, params)
	_, err = s.SpannerDB.Apply(ctx, muts)
	if err != nil {
		if strings.Contains(err.Error(), "already exists") {
			return nil, grpc.Errorf(codes.AlreadyExists, err.Error())
		} else {
			return nil, grpc.Errorf(codes.Unknown, err.Error())
		}
	}
	res := &{{.GetOutputType}}{}

	return res, nil
}
{{end}}`

const SpannerUnaryUpdateTemplate = `{{define "spanner_unary_update"}}
	var err error
	{{template "declare_spanner_arg_map" .}}

	muts := make([]*spanner.Mutation, 1)
	muts[0] = spanner.UpdateMap("{{.Spanner.TableName}}", params)
	_, err = s.SpannerDB.Apply(ctx, muts)
	if err != nil {
		if strings.Contains(err.Error(), "already exists") {
			return nil, grpc.Errorf(codes.AlreadyExists, err.Error())
		} else {
			return nil, grpc.Errorf(codes.Unknown, err.Error())
		}
	}
	res := &{{.GetOutputType}}{}

	return res, nil
}
{{end}}`

const SpannerUnaryDeleteTemplate = `{{define "spanner_unary_delete"}}
	var err error
{{template "declare_spanner_delete_key" .}}

	muts := make([]*spanner.Mutation, 1)
	muts[0] = spanner.DeleteKeyRange({{.Spanner.TableName}}, key)
	_, err = s.SpannerDB.Apply(ctx, muts)
	if err != nil {
		if strings.Contains(err.Error(), "does not exist") {
			return nil, grpc.Errorf(codes.NotFound, err.Error())
		}
	}
	res := &{{.GetOutputType}}{}

	return res, nil
}
{{end}}`

const SpannerClientStreamingMethodTemplate = `{{define "spanner_client_streaming_method"}}// spanner client streaming {{.GetName}}
func (s *{{.GetServiceName}}Impl) {{.GetName}}(stream {{.GetServiceName}}_{{.GetName}}Server) error {
	var totalAffected int64
	var err error
	muts := make([]*spanner.Mutation, 0)
	for {
		req, err := stream.Recv()
		if err == io.EOF {
			break
		} else if err  != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		totalAffected += 1

		{{if .Spanner.IsInsert}}{{template "spanner_client_streaming_insert" .}}{{end}}
		{{if .Spanner.IsUpdate}}{{template "spanner_client_streaming_update" .}}{{end}}
		{{if .Spanner.IsDelete}}{{template "spanner_client_streaming_delete" .}}{{end}}
		//In the future, we might do apply if muts gets really big,  but for now,
		// we only do one apply on the database with all the records stored in muts
	}
	_, err = s.SpannerDB.Apply(context.Background(), muts)
	if err != nil {
		if strings.Contains(err.Error(), "already exists") {
			return grpc.Errorf(codes.AlreadyExists, err.Error())
		} else {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
	}
	stream.SendAndClose(&{{.GetOutputType}}{Count: totalAffected})
	return nil
}
{{end}}`

const SpannerClientStreamingUpdateTemplate = `{{define "spanner_client_streaming_update"}}//spanner client streaming update
{{template "declare_spanner_arg_map" .}}

muts = append(muts, spanner.UpdateMap("{{.Spanner.TableName}}", params))
{{end}}`

const SpannerClientStreamingInsertTemplate = `{{define "spanner_client_streaming_insert"}}//spanner client streaming insert
{{template "declare_spanner_arg_slice" .}}

	muts = append(muts, spanner.Insert("{{.Spanner.TableName}}", {{.Spanner.InsertColsAsString}}, params))
{{end}}`

const SpannerClientStreamingDeleteTemplate = `{{define "spanner_client_streaming_delete"}}//spanner client streaming delete
{{template "declare_spanner_delete_key" .}}

	muts = append(muts, spanner.DeleteKeyRange({{.Spanner.TableName}}, key))
{{end}}`

const SpannerServerStreamingMethodTemplate = `{{define "spanner_server_streaming_method"}}// spanner server streaming {{.GetName}}
func (s *{{.GetServiceName}}Impl) {{.GetName}}(req *{{.GetInputType}}, stream {{.GetServiceName}}_{{.GetName}}Server) error {
	var (
	{{range $field, $type := .GetFieldsWithLocalTypesFor .GetOutputTypeStruct}}
		{{$field}} {{$type}}{{end}}
	)
	{{if ne (len .Spanner.QueryArgs) 0}}
	var err error
	{{end}}

	{{template "declare_spanner_arg_map" .}}

	stmt := spanner.Statement{SQL: "{{.Spanner.Query}}", Params: params}
	tx := s.SpannerDB.Single()
	defer tx.Close()
	iter := tx.Query(context.Background(), stmt)
	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			break
		} else if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}

		// scan our values out of the row
		{{range $index, $t := .GetTypeDescArrayForStruct .GetOutputTypeStruct}}
		{{if $t.IsMapped}}
		gcv := new(spanner.GenericColumnValue)
		err = row.ColumnByName("{{$t.ProtoName}}", gcv)
		if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		err = {{$t.Name}}.SpannerScan(gcv)
		if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		{{else}}
		err = row.ColumnByName("{{$t.ProtoName}}", &{{$t.Name}})
		if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		{{end}}{{end}}
		res := &{{.GetOutputType}}{
		{{range $field, $type := .GetTypeDescForFieldsInStruct .GetOutputTypeStruct}}
		{{$field}}: {{template "addr" $type}}{{template "base" $type}}{{template "mapping" $type}},{{end}}
		}
		stream.Send(res)
	}
	return  nil
}
{{end}}`

const SpannerBidiStreamingMethodTemplate = `{{define "spanner_bidi_streaming_method"}}// spanner bidi streaming {{.GetName}}
unimplemented
{{end}}`

const SpannerHelperTemplates = `
{{define "type_desc_to_def_map"}}
{{if .IsMapped}}
	conv, err = {{.GoName}}{}.ToSpanner(req.{{.Name}}).SpannerValue()
{{else}}
	conv = req.{{.Name}}
{{end}}{{end}}

{{define "type_desc_to_def_slice"}}
{{if .IsMapped}}
	conv, err = {{.GoName}}{}.ToSpanner(req.{{.Name}}).SpannerValue()
{{else}}
	conv = req.{{.Name}}
{{end}}{{end}}

{{define "return_err_on_method"}}
	if err != nil {
{{if .IsUnary}}
		return nil, grpc.Errorf(codes.Unknown, err.Error())
{{else}}
		return grpc.Errorf(codes.Unknown, err.Error())
{{end}}
	}
{{end}}

{{define "declare_spanner_arg_map"}}
{{$method := .}}
	params := make(map[string]interface{})
{{if gt (len .Spanner.OptionArguments) 0}}
	var conv interface{}
{{end}}
{{range $key, $val := .Spanner.QueryArgs}}
{{if $val.IsFieldValue}}
	{{template "type_desc_to_def_map" $val.Field}}
	{{template "return_err_on_method" $method}}
	params["{{$val.Name}}"] = conv
{{else}}
{{if $val.IsValue}}
	conv = {{$val.Value}}
	params["{{$val.Name}}"] = conv
{{end}}
{{end}}{{end}}
{{end}}

{{define "declare_spanner_arg_slice"}}
{{$method := .}}
	params := make([]interface{}, 0)
{{if gt (len .Spanner.OptionArguments) 0}}
	var conv interface{}
{{end}}

{{range $index, $val := .Spanner.QueryArgs}}
{{if $val.IsFieldValue}}
	{{template "type_desc_to_def_slice" $val.Field}}
	{{template "return_err_on_method" $method}}
	params = append(params, conv)
{{else}}
{{if $val.IsValue}}
	params = append(params, {{$val.Value}})
{{end}}
{{end}}{{end}}
{{end}}

{{define "declare_spanner_delete_key"}}
{{$method := .}}
	start := make([]interface{}, 0)
	end := make([]interface{}, 0)
{{if gt (len .Spanner.OptionArguments) 0}}
	var conv interface{}
{{end}}
{{range $index, $arg := .Spanner.KeyRangeDesc.Start}}
{{if $arg.IsFieldValue}}
{{template "type_desc_to_def_slice" $arg.Field}}
{{template "return_err_on_method" $method}}
	start = append(start, conv)
{{else}}
	start = append(start, {{$arg.Value}})
{{end}}{{end}}
{{range $index, $arg := .Spanner.KeyRangeDesc.End}}
{{if $arg.IsFieldValue}}
{{template "type_desc_to_def_slice" $arg.Field}}
{{template "return_err_on_method" $method}}
	end = append(end, conv)
{{else}}
{{if $arg.IsValue}}
	end = append(end, {{$arg.Value}})
{{end}}
{{end}}{{end}}
	key := spanner.KeyRange{
		Start: start,
		End: end,
		Kind: {{.Spanner.KeyRangeDesc.Kind}},
	}
{{end}}

`
<commit_msg>fixed template<commit_after>// Copyright 2017, TCN Inc.
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of TCN Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package templates

const SpannerUnaryMethodTemplate = `{{define "spanner_unary_method"}}// spanner unary select {{.GetName}}
func (s* {{.GetServiceName}}Impl) {{.GetName}} (ctx context.Context, req *{{.GetInputType}}) (*{{.GetOutputType}}, error) {
{{if .Spanner.IsSelect}}{{template "spanner_unary_select" .}}{{end}}
{{if .Spanner.IsUpdate}}{{template "spanner_unary_update" .}}{{end}}
{{if .Spanner.IsInsert}}{{template "spanner_unary_insert" .}}{{end}}
{{if .Spanner.IsDelete}}{{template "spanner_unary_delete" .}}{{end}}
{{end}}`

const SpannerUnarySelectTemplate = `{{define "spanner_unary_select"}}
	var err error
	var (
{{range $field, $type := .GetFieldsWithLocalTypesFor .GetOutputTypeStruct}}
		{{$field}} {{$type}}{{end}}
	)

	{{template "declare_spanner_arg_map" .}}

	//stmt := spanner.Statement{SQL: "{ {.Spanner.Query} }", Params: params}
	stmt := spanner.Statement{SQL: "{{.Spanner.Query}}", Params: params}
	tx := s.SpannerDB.Single()
	defer tx.Close()
	iter := tx.Query(ctx, stmt)
	defer iter.Stop()
	row, err := iter.Next()
	if err == iterator.Done {
		return nil, grpc.Errorf(codes.NotFound, "no rows found")
	} else if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}

	// scan our values out of the row
	{{range $index, $t := .GetTypeDescArrayForStruct .GetOutputTypeStruct}}
	{{if $t.IsMapped}}
	gcv := new(spanner.GenericColumnValue)
	err = row.ColumnByName("{{$t.ProtoName}}", gcv)
	if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}
	err = {{$t.Name}}.SpannerScan(gcv)
	if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}
	{{else}}
	err = row.ColumnByName("{{$t.ProtoName}}", &{{$t.Name}})
	if err != nil {
		return nil, grpc.Errorf(codes.Unknown, err.Error())
	}
	{{end}}{{end}}

	_, err = iter.Next()
	if err != iterator.Done {
		fmt.Println("Unary select that returns more than one row..")
	}
	//res := &{ {.GetOutputType} }{
	res := &{{.GetOutputType}}{
	{{range $field, $type := .GetTypeDescForFieldsInStruct .GetOutputTypeStruct}}
	{{$field}}: {{template "addr" $type}}{{template "base" $type}}{{template "mapping" $type}},{{end}}
	}
	return res, nil
}
{{end}}`

const SpannerUnaryInsertTemplate = `{{define "spanner_unary_insert"}}
	var err error
	{{template "declare_spanner_arg_slice" .}}

	muts := make([]*spanner.Mutation, 1)
	muts[0] = spanner.Insert("{{.Spanner.TableName}}", {{.Spanner.InsertColsAsString}}, params)
	_, err = s.SpannerDB.Apply(ctx, muts)
	if err != nil {
		if strings.Contains(err.Error(), "already exists") {
			return nil, grpc.Errorf(codes.AlreadyExists, err.Error())
		} else {
			return nil, grpc.Errorf(codes.Unknown, err.Error())
		}
	}
	res := &{{.GetOutputType}}{}

	return res, nil
}
{{end}}`

const SpannerUnaryUpdateTemplate = `{{define "spanner_unary_update"}}
	var err error
	{{template "declare_spanner_arg_map" .}}

	muts := make([]*spanner.Mutation, 1)
	muts[0] = spanner.UpdateMap("{{.Spanner.TableName}}", params)
	_, err = s.SpannerDB.Apply(ctx, muts)
	if err != nil {
		if strings.Contains(err.Error(), "already exists") {
			return nil, grpc.Errorf(codes.AlreadyExists, err.Error())
		} else {
			return nil, grpc.Errorf(codes.Unknown, err.Error())
		}
	}
	res := &{{.GetOutputType}}{}

	return res, nil
}
{{end}}`

const SpannerUnaryDeleteTemplate = `{{define "spanner_unary_delete"}}
	var err error
{{template "declare_spanner_delete_key" .}}

	muts := make([]*spanner.Mutation, 1)
	muts[0] = spanner.DeleteKeyRange({{.Spanner.TableName}}, key)
	_, err = s.SpannerDB.Apply(ctx, muts)
	if err != nil {
		if strings.Contains(err.Error(), "does not exist") {
			return nil, grpc.Errorf(codes.NotFound, err.Error())
		}
	}
	res := &{{.GetOutputType}}{}

	return res, nil
}
{{end}}`

const SpannerClientStreamingMethodTemplate = `{{define "spanner_client_streaming_method"}}// spanner client streaming {{.GetName}}
func (s *{{.GetServiceName}}Impl) {{.GetName}}(stream {{.GetServiceName}}_{{.GetName}}Server) error {
	var totalAffected int64
	var err error
	muts := make([]*spanner.Mutation, 0)
	for {
		req, err := stream.Recv()
		if err == io.EOF {
			break
		} else if err  != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		totalAffected += 1

		{{if .Spanner.IsInsert}}{{template "spanner_client_streaming_insert" .}}{{end}}
		{{if .Spanner.IsUpdate}}{{template "spanner_client_streaming_update" .}}{{end}}
		{{if .Spanner.IsDelete}}{{template "spanner_client_streaming_delete" .}}{{end}}
		//In the future, we might do apply if muts gets really big,  but for now,
		// we only do one apply on the database with all the records stored in muts
	}
	_, err = s.SpannerDB.Apply(context.Background(), muts)
	if err != nil {
		if strings.Contains(err.Error(), "already exists") {
			return grpc.Errorf(codes.AlreadyExists, err.Error())
		} else {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
	}
	stream.SendAndClose(&{{.GetOutputType}}{Count: totalAffected})
	return nil
}
{{end}}`

const SpannerClientStreamingUpdateTemplate = `{{define "spanner_client_streaming_update"}}//spanner client streaming update
{{template "declare_spanner_arg_map" .}}

muts = append(muts, spanner.UpdateMap("{{.Spanner.TableName}}", params))
{{end}}`

const SpannerClientStreamingInsertTemplate = `{{define "spanner_client_streaming_insert"}}//spanner client streaming insert
{{template "declare_spanner_arg_slice" .}}

	muts = append(muts, spanner.Insert("{{.Spanner.TableName}}", {{.Spanner.InsertColsAsString}}, params))
{{end}}`

const SpannerClientStreamingDeleteTemplate = `{{define "spanner_client_streaming_delete"}}//spanner client streaming delete
{{template "declare_spanner_delete_key" .}}

	muts = append(muts, spanner.DeleteKeyRange({{.Spanner.TableName}}, key))
{{end}}`

const SpannerServerStreamingMethodTemplate = `{{define "spanner_server_streaming_method"}}// spanner server streaming {{.GetName}}
func (s *{{.GetServiceName}}Impl) {{.GetName}}(req *{{.GetInputType}}, stream {{.GetServiceName}}_{{.GetName}}Server) error {
	var (
	{{range $field, $type := .GetFieldsWithLocalTypesFor .GetOutputTypeStruct}}
		{{$field}} {{$type}}{{end}}
	)
	{{if ne (len .Spanner.QueryArgs) 0}}
	var err error
	{{end}}

	{{template "declare_spanner_arg_map" .}}

	stmt := spanner.Statement{SQL: "{{.Spanner.Query}}", Params: params}
	tx := s.SpannerDB.Single()
	defer tx.Close()
	iter := tx.Query(context.Background(), stmt)
	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			break
		} else if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}

		// scan our values out of the row
		{{range $index, $t := .GetTypeDescArrayForStruct .GetOutputTypeStruct}}
		{{if $t.IsMapped}}
		gcv := new(spanner.GenericColumnValue)
		err = row.ColumnByName("{{$t.ProtoName}}", gcv)
		if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		err = {{$t.Name}}.SpannerScan(gcv)
		if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		{{else}}
		err = row.ColumnByName("{{$t.ProtoName}}", &{{$t.Name}})
		if err != nil {
			return grpc.Errorf(codes.Unknown, err.Error())
		}
		{{end}}{{end}}
		res := &{{.GetOutputType}}{
		{{range $field, $type := .GetTypeDescForFieldsInStruct .GetOutputTypeStruct}}
		{{$field}}: {{template "addr" $type}}{{template "base" $type}}{{template "mapping" $type}},{{end}}
		}
		stream.Send(res)
	}
	return  nil
}
{{end}}`

const SpannerBidiStreamingMethodTemplate = `{{define "spanner_bidi_streaming_method"}}// spanner bidi streaming {{.GetName}}
unimplemented
{{end}}`

const SpannerHelperTemplates = `
{{define "type_desc_to_def_map"}}
{{if .IsMapped}}
	conv, err = {{.GoName}}{}.ToSpanner(req.{{.Name}}).SpannerValue()
{{else}}
	conv = req.{{.Name}}
{{end}}{{end}}

{{define "type_desc_to_def_slice"}}
{{if .IsMapped}}
	conv, err = {{.GoName}}{}.ToSpanner(req.{{.Name}}).SpannerValue()
{{else}}
	conv = req.{{.Name}}
{{end}}{{end}}

{{define "return_err_on_method"}}
	if err != nil {
{{if .IsUnary}}
		return nil, grpc.Errorf(codes.Unknown, err.Error())
{{else}}
		return grpc.Errorf(codes.Unknown, err.Error())
{{end}}
	}
{{end}}

{{define "declare_spanner_arg_map"}}
{{$method := .}}
	params := make(map[string]interface{})
{{if gt (len .Spanner.OptionArguments) 0}}
	var conv interface{}
{{end}}
{{range $key, $val := .Spanner.QueryArgs}}
{{if $val.IsFieldValue}}
	{{template "type_desc_to_def_map" $val.Field}}
	{{template "return_err_on_method" $method}}
	params["{{$val.Name}}"] = conv
{{else}}
{{if $val.IsValue}}
	conv = {{$val.Value}}
	params["{{$val.Name}}"] = conv
{{end}}
{{end}}{{end}}
{{end}}

{{define "declare_spanner_arg_slice"}}
{{$method := .}}
	params := make([]interface{}, 0)
{{if gt (len .Spanner.OptionArguments) 0}}
	var conv interface{}
{{end}}

{{range $index, $val := .Spanner.QueryArgs}}
{{if $val.IsFieldValue}}
	{{template "type_desc_to_def_slice" $val.Field}}
	{{template "return_err_on_method" $method}}
	params = append(params, conv)
{{else}}
{{if $val.IsValue}}
	params = append(params, {{$val.Value}})
{{end}}
{{end}}{{end}}
{{end}}

{{define "declare_spanner_delete_key"}}
{{$method := .}}
	start := make([]interface{}, 0)
	end := make([]interface{}, 0)
{{if gt (len .Spanner.OptionArguments) 0}}
	var conv interface{}
{{end}}
{{range $index, $arg := .Spanner.KeyRangeDesc.Start}}
{{if $arg.IsFieldValue}}
{{template "type_desc_to_def_slice" $arg.Field}}
{{template "return_err_on_method" $method}}
	start = append(start, conv)
{{else}}
	start = append(start, {{$arg.Value}})
{{end}}{{end}}
{{range $index, $arg := .Spanner.KeyRangeDesc.End}}
{{if $arg.IsFieldValue}}
{{template "type_desc_to_def_slice" $arg.Field}}
{{template "return_err_on_method" $method}}
	end = append(end, conv)
{{else}}
{{if $arg.IsValue}}
	end = append(end, {{$arg.Value}})
{{end}}
{{end}}{{end}}
	key := spanner.KeyRange{
		Start: start,
		End: end,
		Kind: spanner.{{.Spanner.KeyRangeDesc.Kind}},
	}
{{end}}

`
<|endoftext|>


<commit_before>package mph2o

import (
	"bytes"
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestGraphDefinition(t *testing.T) {
	var h2o H2OPlugin

	graphdef := h2o.GraphDefinition()
	if len(graphdef) != 17 {
		t.Errorf("GetTempfilename: %d should be 17", len(graphdef))
	}
}

func TestParse(t *testing.T) {
	var h2o H2OPlugin
	stub := `{
 "server-version": "2.3.0-DEV",
 "openssl-version": "LibreSSL 2.4.5",
 "current-time": "01/Dec/2017:08:18:16 +0000",
 "restart-time": "01/Dec/2017:08:13:28 +0000",
 "uptime": 288,
 "generation": null,
 "connections": 1,
 "max-connections": 1024,
 "listeners": 4,
 "worker-threads": 2,
 "num-sessions": 14,
 "requests": [
  {"host": "10.0.2.2", "user": null, "at": "20171201T081816.181999+0000", "method": "GET", "path": "/server-status/json", "query": "", "protocol": "HTTP/2", "referer": null, "user-agent": "curl/7.54.0", "connect-time": "0.065440", "request-header-time": "0", "request-body-time": "0", "request-total-time": "0", "process-time": null, "response-time": null, "connection-id": "13", "ssl.protocol-version": "TLSv1.2", "ssl.session-reused": "0", "ssl.cipher": "ECDHE-RSA-CHACHA20-POLY1305-OLD", "ssl.cipher-bits": "256", "ssl.session-ticket": null, "http1.request-index": null, "http2.stream-id": "1", "http2.priority.received.exclusive": "0", "http2.priority.received.parent": "0", "http2.priority.received.weight": "16", "http2.priority.actual.parent": "0", "http2.priority.actual.weight": "16", "authority": "localhost:8443"}
 ],
 "status-errors.400": 0,
 "status-errors.403": 0,
 "status-errors.404": 2,
 "status-errors.405": 0,
 "status-errors.416": 0,
 "status-errors.417": 0,
 "status-errors.500": 0,
 "status-errors.502": 0,
 "status-errors.503": 0,
 "http2-errors.protocol": 0,
 "http2-errors.internal": 0,
 "http2-errors.flow-control": 0,
 "http2-errors.settings-timeout": 0,
 "http2-errors.stream-closed": 0,
 "http2-errors.frame-size": 0,
 "http2-errors.refused-stream": 0,
 "http2-errors.cancel": 0,
 "http2-errors.compression": 0,
 "http2-errors.connect": 0,
 "http2-errors.enhance-your-calm": 0,
 "http2-errors.inadequate-security": 0,
 "http2.read-closed": 3,
 "http2.write-closed": 0
,
 "connect-time-0": 0,
 "connect-time-25": 0,
 "connect-time-50": 0,
 "connect-time-75": 0,
 "connect-time-99": 0
, "header-time-0": 0,
 "header-time-25": 0,
 "header-time-50": 0,
 "header-time-75": 0,
 "header-time-99": 0
, "body-time-0": 0,
 "body-time-25": 0,
 "body-time-50": 0,
 "body-time-75": 0,
 "body-time-99": 0
, "request-total-time-0": 0,
 "request-total-time-25": 0,
 "request-total-time-50": 0,
 "request-total-time-75": 0,
 "request-total-time-99": 0
, "process-time-0": 0,
 "process-time-25": 0,
 "process-time-50": 0,
 "process-time-75": 0,
 "process-time-99": 0
, "response-time-0": 0,
 "response-time-25": 0,
 "response-time-50": 0,
 "response-time-75": 0,
 "response-time-99": 0
, "duration-0": 0,
 "duration-25": 0,
 "duration-50": 0,
 "duration-75": 0,
 "duration-99": 0
,
 "requests": [
  {"host": "10.0.2.2", "user": null, "at": "20171201T081816.181999+0000", "method": "GET", "path": "/server-status/json", "query": "", "protocol": "HTTP/2", "referer": null, "user-agent": "curl/7.54.0", "connect-time": "0.065440", "request-header-time": "0", "request-body-time": "0", "request-total-time": "0", "process-time": null, "response-time": null, "connection-id": "13", "ssl.protocol-version": "TLSv1.2", "ssl.session-reused": "0", "ssl.cipher": "ECDHE-RSA-CHACHA20-POLY1305-OLD", "ssl.cipher-bits": "256", "ssl.session-ticket": null, "http1.request-index": null, "http2.stream-id": "1", "http2.priority.received.exclusive": "0", "http2.priority.received.parent": "0", "http2.priority.received.weight": "16", "http2.priority.actual.parent": "0", "http2.priority.actual.weight": "16", "authority": "localhost:8443"}
 ],
 "status-errors.400": 0,
 "status-errors.403": 0,
 "status-errors.404": 2,
 "status-errors.405": 0,
 "status-errors.416": 0,
 "status-errors.417": 0,
 "status-errors.500": 0,
 "status-errors.502": 0,
 "status-errors.503": 0,
 "http2-errors.protocol": 0,
 "http2-errors.internal": 0,
 "http2-errors.flow-control": 0,
 "http2-errors.settings-timeout": 0,
 "http2-errors.stream-closed": 0,
 "http2-errors.frame-size": 0,
 "http2-errors.refused-stream": 0,
 "http2-errors.cancel": 0,
 "http2-errors.compression": 0,
 "http2-errors.connect": 0,
 "http2-errors.enhance-your-calm": 0,
 "http2-errors.inadequate-security": 0,
 "http2.read-closed": 3,
 "http2.write-closed": 0
,
 "connect-time-0": 0,
 "connect-time-25": 0,
 "connect-time-50": 0,
 "connect-time-75": 0,
 "connect-time-99": 0
, "header-time-0": 0,
 "header-time-25": 0,
 "header-time-50": 0,
 "header-time-75": 0,
 "header-time-99": 0
, "body-time-0": 0,
 "body-time-25": 0,
 "body-time-50": 0,
 "body-time-75": 0,
 "body-time-99": 0
, "request-total-time-0": 0,
 "request-total-time-25": 0,
 "request-total-time-50": 0,
 "request-total-time-75": 0,
 "request-total-time-99": 0
, "process-time-0": 0,
 "process-time-25": 0,
 "process-time-50": 0,
 "process-time-75": 0,
 "process-time-99": 0
, "response-time-0": 0,
 "response-time-25": 0,
 "response-time-50": 0,
 "response-time-75": 0,
 "response-time-99": 0
, "duration-0": 0,
 "duration-25": 0,
 "duration-50": 0,
 "duration-75": 0,
 "duration-99": 0
}`

	h2oStats := bytes.NewBufferString(stub)

	stat, err := h2o.parseStats(h2oStats)
	fmt.Println(stat)
	assert.Nil(t, err)
	assert.EqualValues(t, 288, stat["uptime"])
	assert.EqualValues(t, 1, stat["requests"])
	assert.EqualValues(t, 1, stat["connections"])
	assert.EqualValues(t, 2, stat["status-errors_404"])
	assert.EqualValues(t, 3, stat["http2_read-closed"])
	assert.EqualValues(t, 0, stat["connect-time-25"])
}
<commit_msg>Change bytes.NewBufferString to strings.NewReader<commit_after>package mph2o

import (
	"fmt"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestGraphDefinition(t *testing.T) {
	var h2o H2OPlugin

	graphdef := h2o.GraphDefinition()
	if len(graphdef) != 17 {
		t.Errorf("GetTempfilename: %d should be 17", len(graphdef))
	}
}

func TestParse(t *testing.T) {
	var h2o H2OPlugin
	stub := `{
 "server-version": "2.3.0-DEV",
 "openssl-version": "LibreSSL 2.4.5",
 "current-time": "01/Dec/2017:08:18:16 +0000",
 "restart-time": "01/Dec/2017:08:13:28 +0000",
 "uptime": 288,
 "generation": null,
 "connections": 1,
 "max-connections": 1024,
 "listeners": 4,
 "worker-threads": 2,
 "num-sessions": 14,
 "requests": [
  {"host": "10.0.2.2", "user": null, "at": "20171201T081816.181999+0000", "method": "GET", "path": "/server-status/json", "query": "", "protocol": "HTTP/2", "referer": null, "user-agent": "curl/7.54.0", "connect-time": "0.065440", "request-header-time": "0", "request-body-time": "0", "request-total-time": "0", "process-time": null, "response-time": null, "connection-id": "13", "ssl.protocol-version": "TLSv1.2", "ssl.session-reused": "0", "ssl.cipher": "ECDHE-RSA-CHACHA20-POLY1305-OLD", "ssl.cipher-bits": "256", "ssl.session-ticket": null, "http1.request-index": null, "http2.stream-id": "1", "http2.priority.received.exclusive": "0", "http2.priority.received.parent": "0", "http2.priority.received.weight": "16", "http2.priority.actual.parent": "0", "http2.priority.actual.weight": "16", "authority": "localhost:8443"}
 ],
 "status-errors.400": 0,
 "status-errors.403": 0,
 "status-errors.404": 2,
 "status-errors.405": 0,
 "status-errors.416": 0,
 "status-errors.417": 0,
 "status-errors.500": 0,
 "status-errors.502": 0,
 "status-errors.503": 0,
 "http2-errors.protocol": 0,
 "http2-errors.internal": 0,
 "http2-errors.flow-control": 0,
 "http2-errors.settings-timeout": 0,
 "http2-errors.stream-closed": 0,
 "http2-errors.frame-size": 0,
 "http2-errors.refused-stream": 0,
 "http2-errors.cancel": 0,
 "http2-errors.compression": 0,
 "http2-errors.connect": 0,
 "http2-errors.enhance-your-calm": 0,
 "http2-errors.inadequate-security": 0,
 "http2.read-closed": 3,
 "http2.write-closed": 0
,
 "connect-time-0": 0,
 "connect-time-25": 0,
 "connect-time-50": 0,
 "connect-time-75": 0,
 "connect-time-99": 0
, "header-time-0": 0,
 "header-time-25": 0,
 "header-time-50": 0,
 "header-time-75": 0,
 "header-time-99": 0
, "body-time-0": 0,
 "body-time-25": 0,
 "body-time-50": 0,
 "body-time-75": 0,
 "body-time-99": 0
, "request-total-time-0": 0,
 "request-total-time-25": 0,
 "request-total-time-50": 0,
 "request-total-time-75": 0,
 "request-total-time-99": 0
, "process-time-0": 0,
 "process-time-25": 0,
 "process-time-50": 0,
 "process-time-75": 0,
 "process-time-99": 0
, "response-time-0": 0,
 "response-time-25": 0,
 "response-time-50": 0,
 "response-time-75": 0,
 "response-time-99": 0
, "duration-0": 0,
 "duration-25": 0,
 "duration-50": 0,
 "duration-75": 0,
 "duration-99": 0
,
 "requests": [
  {"host": "10.0.2.2", "user": null, "at": "20171201T081816.181999+0000", "method": "GET", "path": "/server-status/json", "query": "", "protocol": "HTTP/2", "referer": null, "user-agent": "curl/7.54.0", "connect-time": "0.065440", "request-header-time": "0", "request-body-time": "0", "request-total-time": "0", "process-time": null, "response-time": null, "connection-id": "13", "ssl.protocol-version": "TLSv1.2", "ssl.session-reused": "0", "ssl.cipher": "ECDHE-RSA-CHACHA20-POLY1305-OLD", "ssl.cipher-bits": "256", "ssl.session-ticket": null, "http1.request-index": null, "http2.stream-id": "1", "http2.priority.received.exclusive": "0", "http2.priority.received.parent": "0", "http2.priority.received.weight": "16", "http2.priority.actual.parent": "0", "http2.priority.actual.weight": "16", "authority": "localhost:8443"}
 ],
 "status-errors.400": 0,
 "status-errors.403": 0,
 "status-errors.404": 2,
 "status-errors.405": 0,
 "status-errors.416": 0,
 "status-errors.417": 0,
 "status-errors.500": 0,
 "status-errors.502": 0,
 "status-errors.503": 0,
 "http2-errors.protocol": 0,
 "http2-errors.internal": 0,
 "http2-errors.flow-control": 0,
 "http2-errors.settings-timeout": 0,
 "http2-errors.stream-closed": 0,
 "http2-errors.frame-size": 0,
 "http2-errors.refused-stream": 0,
 "http2-errors.cancel": 0,
 "http2-errors.compression": 0,
 "http2-errors.connect": 0,
 "http2-errors.enhance-your-calm": 0,
 "http2-errors.inadequate-security": 0,
 "http2.read-closed": 3,
 "http2.write-closed": 0
,
 "connect-time-0": 0,
 "connect-time-25": 0,
 "connect-time-50": 0,
 "connect-time-75": 0,
 "connect-time-99": 0
, "header-time-0": 0,
 "header-time-25": 0,
 "header-time-50": 0,
 "header-time-75": 0,
 "header-time-99": 0
, "body-time-0": 0,
 "body-time-25": 0,
 "body-time-50": 0,
 "body-time-75": 0,
 "body-time-99": 0
, "request-total-time-0": 0,
 "request-total-time-25": 0,
 "request-total-time-50": 0,
 "request-total-time-75": 0,
 "request-total-time-99": 0
, "process-time-0": 0,
 "process-time-25": 0,
 "process-time-50": 0,
 "process-time-75": 0,
 "process-time-99": 0
, "response-time-0": 0,
 "response-time-25": 0,
 "response-time-50": 0,
 "response-time-75": 0,
 "response-time-99": 0
, "duration-0": 0,
 "duration-25": 0,
 "duration-50": 0,
 "duration-75": 0,
 "duration-99": 0
}`

	h2oStats := strings.NewReader(stub)

	stat, err := h2o.parseStats(h2oStats)
	fmt.Println(stat)
	assert.Nil(t, err)
	assert.EqualValues(t, 288, stat["uptime"])
	assert.EqualValues(t, 1, stat["requests"])
	assert.EqualValues(t, 1, stat["connections"])
	assert.EqualValues(t, 2, stat["status-errors_404"])
	assert.EqualValues(t, 3, stat["http2_read-closed"])
	assert.EqualValues(t, 0, stat["connect-time-25"])
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"strings"

	"github.com/fsouza/go-dockerclient"
)

func run(c *docker.Client, filename string) error {
	p, err := ParseConfig(filename)
	if err != nil {
		return err
	}

	fmt.Println("Pulling docker images")

	for _, stage := range p.Stages {
		image := stage.Image
		repo, tag := getRepoAndTag(image)
		fmt.Print(repo, ":", tag, "\n")
		pom := docker.PullImageOptions{Repository: repo,
			Tag: tag}

		err = c.PullImage(pom, docker.AuthConfiguration{})
		if err != nil {
			return err
		}

	}

	fmt.Println(p)
	return nil
}

func getRepoAndTag(pipelineImage string) (repo, tag string) {
	repoAndTag := strings.Split(pipelineImage, ":")
	if len(repoAndTag) == 1 {
		tag = "latest"
	} else {
		tag = repoAndTag[1]
	}
	repo = repoAndTag[0]

	return repo, tag
}

func main() {
	var configFilename = flag.String("f", "pipeline.json", "pipeline description file")
	var cmd = flag.String("cmd", "run", "walrus command. available commands: 'run'")

	flag.Parse()

	client, err := docker.NewClientFromEnv()
	if err != nil {
		panic(err)
	}

	switch *cmd {
	case "run":
		err = run(client, *configFilename)
	}

	fmt.Println(err)

}
<commit_msg>pull create rename and run<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/client"
)

func run(c *client.Client, filename string) error {
	p, err := ParseConfig(filename)
	if err != nil {
		return err
	}

	fmt.Println("Pulling docker images")

	for _, stage := range p.Stages {
		repo, tag := getRepoAndTag(stage.Image)
		image := repo + ":" + tag
		fmt.Print(repo, ":", tag, "\n")
		_, err := c.ImagePull(context.Background(), image, types.ImagePullOptions{})
		if err != nil {
			return err
		}

		resp, err := c.ContainerCreate(context.Background(),
			&container.Config{Image: image,
				Env: stage.Env,
				Cmd: stage.Cmd,
			},
			&container.HostConfig{},
			&network.NetworkingConfig{},
			stage.Name)
		if err != nil {
			return err
		}
		containerId := resp.ID
		containerName := stage.Name + "-" + containerId[0:11]
		err = c.ContainerRename(context.Background(), containerId, containerName)
		if err != nil {
			return err
		}

		err = c.ContainerStart(context.Background(), containerId, types.ContainerStartOptions{})
		if err != nil {
			return err
		}
		fmt.Println(containerId, err)

	}

	return nil
}

func getRepoAndTag(pipelineImage string) (repo, tag string) {
	repoAndTag := strings.Split(pipelineImage, ":")
	if len(repoAndTag) == 1 {
		tag = "latest"
	} else {
		tag = repoAndTag[1]
	}
	repo = repoAndTag[0]

	return repo, tag
}

func main() {
	var configFilename = flag.String("f", "pipeline.json", "pipeline description file")
	var cmd = flag.String("cmd", "run", "walrus command. available commands: 'run'")

	flag.Parse()
	client, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}

	switch *cmd {
	case "run":
		err = run(client, *configFilename)
	}

	fmt.Println(err)

}
<|endoftext|>