<commit_before>package buffstreams

import ()

import (
	"encoding/binary"
	"errors"
	"log"
	"net"
	"sync"
)

type BuffManager struct {
	dialedConnections map[string]*net.TCPConn
	listeningSockets  map[string]*net.TCPListener
	// TODO find a way to sanely provide this to a Dialer or a Receiver on a per-connection basis
	MaxMessageSizeBitLength int
	EnableLogging           bool
	// TODO I could control access to the maps better if I centralized how they got accessed - less locking code littered around
	sync.RWMutex
}

type BuffManagerConfig struct {
	MaxMessageSize int
	EnableLogging  bool
}

func New(cfg BuffManagerConfig) *BuffManager {
	bm := &BuffManager{
		dialedConnections: make(map[string]*net.TCPConn),
		listeningSockets:  make(map[string]*net.TCPListener),
		EnableLogging:     cfg.EnableLogging,
	}
	maxMessageSize := 4096
	// 0 is the default, and the message must be atleast 1 byte large
	if cfg.MaxMessageSize != 0 {
		maxMessageSize = cfg.MaxMessageSize
	}
	bm.MaxMessageSizeBitLength = MessageSizeToBitLength(maxMessageSize)
	return bm
}

type ListenCallback func([]byte) error

// Incase someone wants a programmtically correct way to format an address/port
// for use with StartListening or WriteTo
func FormatAddress(address string, port string) string {
	return address + ":" + port
}

func (bm *BuffManager) StartListening(port string, cb ListenCallback) error {
	address := FormatAddress("", port)
	tcpAddr, err := net.ResolveTCPAddr("tcp", address)
	receiveSocket, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return err
	}
	bm.startListening(address, receiveSocket, cb)
	return nil
}

func (bm *BuffManager) startListening(address string, socket *net.TCPListener, cb ListenCallback) {
	bm.Lock()
	bm.listeningSockets[address] = socket
	bm.Unlock()

	go func(address string, maxMessageSizeBitLength int, enableLogging bool, listener net.Listener) {
		for {
			// Wait for someone to connect
			conn, err := listener.Accept()
			if err != nil {
				if enableLogging == true {
					log.Print("Error attempting to accept connection")
					log.Print(err)
				}
			} else {
				// Hand this off and immediately listen for more
				go handleListenedConn(address, conn, bm.MaxMessageSizeBitLength, enableLogging, cb)
			}
		}
	}(address, bm.MaxMessageSizeBitLength, bm.EnableLogging, socket)
}

func handleListenedConn(address string, conn net.Conn, maxMessageSize int, enableLogging bool, cb ListenCallback) {
	for {
		// Handle getting the data header
		headerByteSize := maxMessageSize
		headerBuffer := make([]byte, headerByteSize)
		//fullHeaderBuffer := make([]byte, 0)
		var headerReadError error
		var totalHeaderBytesRead = 0
		var bytesRead = 0
		// First, read the number of bytes required to determine the message length
		for totalHeaderBytesRead < headerByteSize && headerReadError == nil {
			// While we haven't read enough yet, pass in the slice that represents where we are in the buffer
			bytesRead, headerReadError = readFromConnection(conn, headerBuffer[totalHeaderBytesRead:])
			totalHeaderBytesRead += bytesRead
		}
		if headerReadError != nil {
			if enableLogging == true {
				if headerReadError.Error() != "EOF" {
					// Log the error we got from the call to read
					log.Print("Error when trying to read from address %s. Tried to read %d, actually read %d", address, headerByteSize, totalHeaderBytesRead)
					log.Print(headerReadError)
				} else {
					// Client closed the conn
					log.Printf("Address %s: Client closed connection", address)
					log.Print(headerReadError)
				}
			}
			conn.Close()
			return
		}

		// Now turn that buffer of bytes into an integer - represnts size of message body
		//msgLength, bytesParsed := binary.Uvarint(fullHeaderBuffer)
		msgLength, bytesParsed := binary.Uvarint(headerBuffer)
		// Not sure what the correct way to handle these errors are. For now, bomb out
		if bytesParsed == 0 {
			// "Buffer too small"
			if enableLogging == true {
				log.Printf("Address %s: 0 Bytes parsed from header", address)
				log.Print(headerReadError)
			}
			conn.Close()
			return
		} else if bytesParsed < 0 {
			// "Buffer overflow"
			if enableLogging == true {
				log.Printf("Address %s: Buffer Less than zero bytes parsed from header", address)
				log.Print(headerReadError)
			}
			conn.Close()
			return
		}
		dataBuffer := make([]byte, msgLength)
		//fullDataBuffer := make([]byte, 0)
		var dataReadError error
		var totalDataBytesRead = 0
		bytesRead = 0
		for totalDataBytesRead < int(msgLength) && dataReadError == nil {
			// While we haven't read enough yet, pass in the slice that represents where we are in the buffer
			bytesRead, dataReadError = readFromConnection(conn, dataBuffer[totalDataBytesRead:])
			totalDataBytesRead += bytesRead
		}

		if dataReadError != nil {
			if enableLogging == true {
				if dataReadError.Error() != "EOF" {
					// log the error from the call to read
					log.Printf("Address %s: Failure to read from connection. Was told to read %d by the header, actually read %d", address, msgLength, totalDataBytesRead)
					log.Print(dataReadError)
				} else {
					// The client wrote the header but closed the connection
					log.Printf("Address %s: Client closed connection", address)
					log.Print(dataReadError)
				}
			}
			conn.Close()
			return
		}

		// If we read bytes, there wasn't an error, or if there was it was only EOF
		// And readbytes + EOF is normal, just as readbytes + no err, next read 0 bytes EOF
		// So... we take action on the actual message data
		if totalDataBytesRead > 0 && (dataReadError == nil || (dataReadError != nil && dataReadError.Error() == "EOF")) {
\			err := cb(dataBuffer)
			if err != nil && enableLogging == true {
				log.Printf("Error in Callback")
				log.Print(err)
				// TODO if it's a protobuffs error, it means we likely had an issue and can't
				// deserialize data? Should we kill the connection and have the client start over?
				// At this point, there isn't a reliable recovery mechanic for the server
			}
		}
	}
}

func readFromConnection(reader net.Conn, buffer []byte) (int, error) {
	// This fills the buffer
	bytesLen, err := reader.Read(buffer)
	// Output the content of the bytes to the queue
	if bytesLen == 0 {
		if err != nil && err.Error() == "EOF" {
			// "End of individual transmission"
			// We're just done reading from that conn
			return bytesLen, err
		}
	}

	if err != nil {
		//"Underlying network failure?"
		// Not sure what this error would be, but it could exist and i've seen it handled
		// as a general case in other networking code. Following in the footsteps of (greatness|madness)
		return bytesLen, err
	}
	// Read some bytes, return the length
	return bytesLen, nil
}

func (bm *BuffManager) dialOut(address string) (*net.TCPConn, error) {
	bm.RLock()
	if _, ok := bm.dialedConnections[address]; ok == true {
		bm.RUnlock()
		// Need to clean it out on any error...
		return nil, errors.New("You have a connection to this ip and port open already")
	}
	bm.RUnlock()
	tcpAddr, err := net.ResolveTCPAddr("tcp", address)
	if err != nil {
		return nil, err
	}
	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		return nil, err
	} else {
		// Store the connection, it's valid
		bm.Lock()
		bm.dialedConnections[address] = conn
		bm.Unlock()
	}
	return conn, nil
}

// closeDialer uses explicit lock semantics vs defers to better control
// when the lock gets released to reduce contention
func (bm *BuffManager) closeDialer(address string) error {
	// Get a read lock to look up that the connection exists
	bm.RLock()
	if conn, ok := bm.dialedConnections[address]; ok == true {
		// Release immediately
		bm.RUnlock()
		err := conn.Close()
		// Grab lock to delete from the map
		bm.Lock()
		delete(bm.dialedConnections, address)
		// Release immediately
		bm.Unlock()
		return err
	}
	// Release the lock incase it didn't exist
	bm.RUnlock()
	return nil
}

// Write data and dial out if the conn isn't open
// TODO throw a fit if they try to write data > maxSize
func (bm *BuffManager) WriteTo(address string, data []byte, persist bool) (int, error) {
	var conn *net.TCPConn
	var err error
	var ok bool

	// Get the connection if it's cached, or open a new one
	bm.RLock()
	conn, ok = bm.dialedConnections[address]
	bm.RUnlock()
	if ok != true {
		conn, err = bm.dialOut(address)
		if err != nil {
			// Error dialing out, cannot write
			// bail
			return 0, err
		}
	}
	// Calculate how big the message is, using a consistent header size.
	msgLenHeader := UInt16ToByteArray(uint16(len(data)), bm.MaxMessageSizeBitLength)
	// Append the size to the message, so now it has a header
	toWrite := append(msgLenHeader, data...)

	toWriteLen := len(toWrite)

	// Three conditions could have occured:
	// 1. There was an error
	// 2. Not all bytes were written
	// 3. Both 1 and 2

	// If there was an error, that should take handling precedence. If the connection
	// was closed, or is otherwise in a bad state, we have to abort and re-open the connection
	// to try again, as we can't realistically finish the write. We have to retry it, or return
	// and error to the user?

	// TODO configurable message retries

	// If there was not an error, and we simply didn't finish the write, we should enter
	// a write-until-complete loop, where we continue to write the data until the server accepts
	// all of it.

	// If both issues occurred, we'll need to find a way to determine if the error
	// is recoverable (is the connection in a bad state) or not

	var writeError error
	var totalBytesWritten = 0
	var bytesWritten = 0
	// First, read the number of bytes required to determine the message length
	for totalBytesWritten < toWriteLen && writeError == nil {
		// While we haven't read enough yet
		// If there are remainder bytes, adjust the contents of toWrite
		// totalBytesWritten will be the index of the nextByte waiting to be read
		bytesWritten, writeError = conn.Write(toWrite[totalBytesWritten:])
		totalBytesWritten += bytesWritten
	}

	if writeError != nil || persist == false {
		if writeError != nil && bm.EnableLogging == true {
			log.Printf("Error while writing data to %s. Expected to write %d, actually wrote %d", address, len(toWrite), totalBytesWritten)
			log.Print(writeError)
		}
		writeError = bm.closeDialer(address)
		conn = nil
		if writeError != nil {
			// TODO ponder the following:
			// What if some bytes written, then failure, then also the close throws an error
			// []error is a better return type, but not sure if thats a thing you're supposed to do...
			// Possibilities for error not as complicated as i'm thinking?
			if bm.EnableLogging == true {
				// The error will get returned up the stack, no need to log it here?
				log.Print("There was a subsequent error cleaning up the connection to %s")
			}
			return totalBytesWritten, writeError
		}
	}

	// Return the bytes written, any error
	return totalBytesWritten, writeError
}
<commit_msg>Fixing typo that miraculously snuck into the codebase<commit_after>package buffstreams

import ()

import (
	"encoding/binary"
	"errors"
	"log"
	"net"
	"sync"
)

type BuffManager struct {
	dialedConnections map[string]*net.TCPConn
	listeningSockets  map[string]*net.TCPListener
	// TODO find a way to sanely provide this to a Dialer or a Receiver on a per-connection basis
	MaxMessageSizeBitLength int
	EnableLogging           bool
	// TODO I could control access to the maps better if I centralized how they got accessed - less locking code littered around
	sync.RWMutex
}

type BuffManagerConfig struct {
	MaxMessageSize int
	EnableLogging  bool
}

func New(cfg BuffManagerConfig) *BuffManager {
	bm := &BuffManager{
		dialedConnections: make(map[string]*net.TCPConn),
		listeningSockets:  make(map[string]*net.TCPListener),
		EnableLogging:     cfg.EnableLogging,
	}
	maxMessageSize := 4096
	// 0 is the default, and the message must be atleast 1 byte large
	if cfg.MaxMessageSize != 0 {
		maxMessageSize = cfg.MaxMessageSize
	}
	bm.MaxMessageSizeBitLength = MessageSizeToBitLength(maxMessageSize)
	return bm
}

type ListenCallback func([]byte) error

// Incase someone wants a programmtically correct way to format an address/port
// for use with StartListening or WriteTo
func FormatAddress(address string, port string) string {
	return address + ":" + port
}

func (bm *BuffManager) StartListening(port string, cb ListenCallback) error {
	address := FormatAddress("", port)
	tcpAddr, err := net.ResolveTCPAddr("tcp", address)
	receiveSocket, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return err
	}
	bm.startListening(address, receiveSocket, cb)
	return nil
}

func (bm *BuffManager) startListening(address string, socket *net.TCPListener, cb ListenCallback) {
	bm.Lock()
	bm.listeningSockets[address] = socket
	bm.Unlock()

	go func(address string, maxMessageSizeBitLength int, enableLogging bool, listener net.Listener) {
		for {
			// Wait for someone to connect
			conn, err := listener.Accept()
			if err != nil {
				if enableLogging == true {
					log.Print("Error attempting to accept connection")
					log.Print(err)
				}
			} else {
				// Hand this off and immediately listen for more
				go handleListenedConn(address, conn, bm.MaxMessageSizeBitLength, enableLogging, cb)
			}
		}
	}(address, bm.MaxMessageSizeBitLength, bm.EnableLogging, socket)
}

func handleListenedConn(address string, conn net.Conn, maxMessageSize int, enableLogging bool, cb ListenCallback) {
	for {
		// Handle getting the data header
		headerByteSize := maxMessageSize
		headerBuffer := make([]byte, headerByteSize)
		//fullHeaderBuffer := make([]byte, 0)
		var headerReadError error
		var totalHeaderBytesRead = 0
		var bytesRead = 0
		// First, read the number of bytes required to determine the message length
		for totalHeaderBytesRead < headerByteSize && headerReadError == nil {
			// While we haven't read enough yet, pass in the slice that represents where we are in the buffer
			bytesRead, headerReadError = readFromConnection(conn, headerBuffer[totalHeaderBytesRead:])
			totalHeaderBytesRead += bytesRead
		}
		if headerReadError != nil {
			if enableLogging == true {
				if headerReadError.Error() != "EOF" {
					// Log the error we got from the call to read
					log.Print("Error when trying to read from address %s. Tried to read %d, actually read %d", address, headerByteSize, totalHeaderBytesRead)
					log.Print(headerReadError)
				} else {
					// Client closed the conn
					log.Printf("Address %s: Client closed connection", address)
					log.Print(headerReadError)
				}
			}
			conn.Close()
			return
		}

		// Now turn that buffer of bytes into an integer - represnts size of message body
		//msgLength, bytesParsed := binary.Uvarint(fullHeaderBuffer)
		msgLength, bytesParsed := binary.Uvarint(headerBuffer)
		// Not sure what the correct way to handle these errors are. For now, bomb out
		if bytesParsed == 0 {
			// "Buffer too small"
			if enableLogging == true {
				log.Printf("Address %s: 0 Bytes parsed from header", address)
				log.Print(headerReadError)
			}
			conn.Close()
			return
		} else if bytesParsed < 0 {
			// "Buffer overflow"
			if enableLogging == true {
				log.Printf("Address %s: Buffer Less than zero bytes parsed from header", address)
				log.Print(headerReadError)
			}
			conn.Close()
			return
		}
		dataBuffer := make([]byte, msgLength)
		//fullDataBuffer := make([]byte, 0)
		var dataReadError error
		var totalDataBytesRead = 0
		bytesRead = 0
		for totalDataBytesRead < int(msgLength) && dataReadError == nil {
			// While we haven't read enough yet, pass in the slice that represents where we are in the buffer
			bytesRead, dataReadError = readFromConnection(conn, dataBuffer[totalDataBytesRead:])
			totalDataBytesRead += bytesRead
		}

		if dataReadError != nil {
			if enableLogging == true {
				if dataReadError.Error() != "EOF" {
					// log the error from the call to read
					log.Printf("Address %s: Failure to read from connection. Was told to read %d by the header, actually read %d", address, msgLength, totalDataBytesRead)
					log.Print(dataReadError)
				} else {
					// The client wrote the header but closed the connection
					log.Printf("Address %s: Client closed connection", address)
					log.Print(dataReadError)
				}
			}
			conn.Close()
			return
		}

		// If we read bytes, there wasn't an error, or if there was it was only EOF
		// And readbytes + EOF is normal, just as readbytes + no err, next read 0 bytes EOF
		// So... we take action on the actual message data
		if totalDataBytesRead > 0 && (dataReadError == nil || (dataReadError != nil && dataReadError.Error() == "EOF")) {
			err := cb(dataBuffer)
			if err != nil && enableLogging == true {
				log.Printf("Error in Callback")
				log.Print(err)
				// TODO if it's a protobuffs error, it means we likely had an issue and can't
				// deserialize data? Should we kill the connection and have the client start over?
				// At this point, there isn't a reliable recovery mechanic for the server
			}
		}
	}
}

func readFromConnection(reader net.Conn, buffer []byte) (int, error) {
	// This fills the buffer
	bytesLen, err := reader.Read(buffer)
	// Output the content of the bytes to the queue
	if bytesLen == 0 {
		if err != nil && err.Error() == "EOF" {
			// "End of individual transmission"
			// We're just done reading from that conn
			return bytesLen, err
		}
	}

	if err != nil {
		//"Underlying network failure?"
		// Not sure what this error would be, but it could exist and i've seen it handled
		// as a general case in other networking code. Following in the footsteps of (greatness|madness)
		return bytesLen, err
	}
	// Read some bytes, return the length
	return bytesLen, nil
}

func (bm *BuffManager) dialOut(address string) (*net.TCPConn, error) {
	bm.RLock()
	if _, ok := bm.dialedConnections[address]; ok == true {
		bm.RUnlock()
		// Need to clean it out on any error...
		return nil, errors.New("You have a connection to this ip and port open already")
	}
	bm.RUnlock()
	tcpAddr, err := net.ResolveTCPAddr("tcp", address)
	if err != nil {
		return nil, err
	}
	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		return nil, err
	} else {
		// Store the connection, it's valid
		bm.Lock()
		bm.dialedConnections[address] = conn
		bm.Unlock()
	}
	return conn, nil
}

// closeDialer uses explicit lock semantics vs defers to better control
// when the lock gets released to reduce contention
func (bm *BuffManager) closeDialer(address string) error {
	// Get a read lock to look up that the connection exists
	bm.RLock()
	if conn, ok := bm.dialedConnections[address]; ok == true {
		// Release immediately
		bm.RUnlock()
		err := conn.Close()
		// Grab lock to delete from the map
		bm.Lock()
		delete(bm.dialedConnections, address)
		// Release immediately
		bm.Unlock()
		return err
	}
	// Release the lock incase it didn't exist
	bm.RUnlock()
	return nil
}

// Write data and dial out if the conn isn't open
// TODO throw a fit if they try to write data > maxSize
func (bm *BuffManager) WriteTo(address string, data []byte, persist bool) (int, error) {
	var conn *net.TCPConn
	var err error
	var ok bool

	// Get the connection if it's cached, or open a new one
	bm.RLock()
	conn, ok = bm.dialedConnections[address]
	bm.RUnlock()
	if ok != true {
		conn, err = bm.dialOut(address)
		if err != nil {
			// Error dialing out, cannot write
			// bail
			return 0, err
		}
	}
	// Calculate how big the message is, using a consistent header size.
	msgLenHeader := UInt16ToByteArray(uint16(len(data)), bm.MaxMessageSizeBitLength)
	// Append the size to the message, so now it has a header
	toWrite := append(msgLenHeader, data...)

	toWriteLen := len(toWrite)

	// Three conditions could have occured:
	// 1. There was an error
	// 2. Not all bytes were written
	// 3. Both 1 and 2

	// If there was an error, that should take handling precedence. If the connection
	// was closed, or is otherwise in a bad state, we have to abort and re-open the connection
	// to try again, as we can't realistically finish the write. We have to retry it, or return
	// and error to the user?

	// TODO configurable message retries

	// If there was not an error, and we simply didn't finish the write, we should enter
	// a write-until-complete loop, where we continue to write the data until the server accepts
	// all of it.

	// If both issues occurred, we'll need to find a way to determine if the error
	// is recoverable (is the connection in a bad state) or not

	var writeError error
	var totalBytesWritten = 0
	var bytesWritten = 0
	// First, read the number of bytes required to determine the message length
	for totalBytesWritten < toWriteLen && writeError == nil {
		// While we haven't read enough yet
		// If there are remainder bytes, adjust the contents of toWrite
		// totalBytesWritten will be the index of the nextByte waiting to be read
		bytesWritten, writeError = conn.Write(toWrite[totalBytesWritten:])
		totalBytesWritten += bytesWritten
	}

	if writeError != nil || persist == false {
		if writeError != nil && bm.EnableLogging == true {
			log.Printf("Error while writing data to %s. Expected to write %d, actually wrote %d", address, len(toWrite), totalBytesWritten)
			log.Print(writeError)
		}
		writeError = bm.closeDialer(address)
		conn = nil
		if writeError != nil {
			// TODO ponder the following:
			// What if some bytes written, then failure, then also the close throws an error
			// []error is a better return type, but not sure if thats a thing you're supposed to do...
			// Possibilities for error not as complicated as i'm thinking?
			if bm.EnableLogging == true {
				// The error will get returned up the stack, no need to log it here?
				log.Print("There was a subsequent error cleaning up the connection to %s")
			}
			return totalBytesWritten, writeError
		}
	}

	// Return the bytes written, any error
	return totalBytesWritten, writeError
}
<|endoftext|>


<commit_before>package cmux

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"testing"
)

const (
	testHTTP1Resp = "http1"
	rpcVal        = 1234
)

func testListener(t *testing.T) (net.Listener, func()) {
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatal(err)
	}
	return l, func() {
		if err := l.Close(); err != nil {
			t.Error(err)
		}
	}
}

type testHTTP1Handler struct{}

func (h *testHTTP1Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, testHTTP1Resp)
}

func runTestHTTPServer(t *testing.T, l net.Listener) {
	s := &http.Server{
		Handler: &testHTTP1Handler{},
	}
	if err := s.Serve(l); err != nil && err != ErrListenerClosed {
		t.Log(err)
	}
}

func runTestHTTP1Client(t *testing.T, addr net.Addr) {
	r, err := http.Get("http://" + addr.String())
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := r.Body.Close(); err != nil {
			t.Log(err)
		}
	}()
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Error(err)
	}

	if string(b) != testHTTP1Resp {
		t.Errorf("invalid response: want=%s got=%s", testHTTP1Resp, b)
	}
}

type TestRPCRcvr struct{}

func (r TestRPCRcvr) Test(i int, j *int) error {
	*j = i
	return nil
}

func runTestRPCServer(t *testing.T, l net.Listener) {
	s := rpc.NewServer()
	if err := s.Register(TestRPCRcvr{}); err != nil {
		t.Fatal(err)
	}
	for {
		c, err := l.Accept()
		if err != nil {
			t.Log(err)
			return
		}
		go s.ServeConn(c)
	}
}

func runTestRPCClient(t *testing.T, addr net.Addr) {
	c, err := rpc.Dial(addr.Network(), addr.String())
	if err != nil {
		t.Error(err)
		return
	}

	var num int
	if err := c.Call("TestRPCRcvr.Test", rpcVal, &num); err != nil {
		t.Error(err)
		return
	}

	if num != rpcVal {
		t.Errorf("wrong rpc response: want=%d got=%v", rpcVal, num)
	}
}

func TestAny(t *testing.T) {
	l, cleanup := testListener(t)
	defer cleanup()

	muxl := New(l)
	httpl := muxl.Match(Any())

	go runTestHTTPServer(t, httpl)
	go func() {
		if err := muxl.Serve(); err != nil {
			t.Log(err)
		}
	}()

	runTestHTTP1Client(t, l.Addr())
}

func TestHTTPGoRPC(t *testing.T) {
	l, cleanup := testListener(t)
	defer cleanup()

	muxl := New(l)
	httpl := muxl.Match(HTTP2(), HTTP1Fast())
	rpcl := muxl.Match(Any())

	go runTestHTTPServer(t, httpl)
	go runTestRPCServer(t, rpcl)
	go func() {
		if err := muxl.Serve(); err != nil {
			t.Log(err)
		}
	}()

	runTestHTTP1Client(t, l.Addr())
	runTestRPCClient(t, l.Addr())
}

func TestErrorHandler(t *testing.T) {
	l, cleanup := testListener(t)
	defer cleanup()

	muxl := New(l)
	httpl := muxl.Match(HTTP2(), HTTP1Fast())

	go runTestHTTPServer(t, httpl)
	go func() {
		if err := muxl.Serve(); err != nil {
			t.Log(err)
		}
	}()

	firstErr := true
	muxl.HandleError(func(err error) bool {
		if !firstErr {
			return true
		}
		if _, ok := err.(ErrNotMatched); !ok {
			t.Errorf("unexpected error: %v", err)
		}
		firstErr = false
		return true
	})

	addr := l.Addr()
	c, err := rpc.Dial(addr.Network(), addr.String())
	if err != nil {
		t.Fatal(err)
	}

	var num int
	if err := c.Call("TestRPCRcvr.Test", rpcVal, &num); err == nil {
		t.Error("rpc got a response")
	}
}

type closerConn struct {
	net.Conn
}

func (c closerConn) Close() error { return nil }

func TestClosed(t *testing.T) {
	mux := &cMux{}
	lis := mux.Match(Any()).(muxListener)
	close(lis.donec)
	mux.serve(closerConn{})
	_, err := lis.Accept()
	if _, ok := err.(errListenerClosed); !ok {
		t.Errorf("expected errListenerClosed got %v", err)
	}
}
<commit_msg>fix test-only goroutine leaks<commit_after>package cmux

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"runtime"
	"sort"
	"strings"
	"sync"
	"testing"
	"time"
)

const (
	testHTTP1Resp = "http1"
	rpcVal        = 1234
)

func safeServe(t *testing.T, muxl CMux) {
	if err := muxl.Serve(); !strings.Contains(err.Error(), "use of closed network connection") {
		t.Fatal(err)
	}
}

func safeDial(t *testing.T, addr net.Addr) (*rpc.Client, func()) {
	c, err := rpc.Dial(addr.Network(), addr.String())
	if err != nil {
		t.Fatal(err)
	}
	return c, func() {
		if err := c.Close(); err != nil {
			t.Fatal(err)
		}
	}
}

func testListener(t *testing.T) (net.Listener, func()) {
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatal(err)
	}
	return l, func() {
		if err := l.Close(); err != nil {
			t.Fatal(err)
		}
	}
}

type testHTTP1Handler struct{}

func (h *testHTTP1Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, testHTTP1Resp)
}

func runTestHTTPServer(t *testing.T, l net.Listener) {
	var mu sync.Mutex
	conns := make(map[net.Conn]struct{})

	defer func() {
		mu.Lock()
		for c := range conns {
			if err := c.Close(); err != nil {
				t.Fatal(err)
			}
		}
		mu.Unlock()
	}()

	s := &http.Server{
		Handler: &testHTTP1Handler{},
		ConnState: func(c net.Conn, state http.ConnState) {
			mu.Lock()
			switch state {
			case http.StateNew:
				conns[c] = struct{}{}
			case http.StateClosed:
				delete(conns, c)
			}
			mu.Unlock()
		},
	}
	if err := s.Serve(l); err != ErrListenerClosed {
		t.Fatal(err)
	}
}

func runTestHTTP1Client(t *testing.T, addr net.Addr) {
	r, err := http.Get("http://" + addr.String())
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := r.Body.Close(); err != nil {
			t.Fatal(err)
		}
	}()
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatal(err)
	}

	if string(b) != testHTTP1Resp {
		t.Errorf("invalid response: want=%s got=%s", testHTTP1Resp, b)
	}
}

type TestRPCRcvr struct{}

func (r TestRPCRcvr) Test(i int, j *int) error {
	*j = i
	return nil
}

func runTestRPCServer(t *testing.T, l net.Listener) {
	s := rpc.NewServer()
	if err := s.Register(TestRPCRcvr{}); err != nil {
		t.Fatal(err)
	}
	for {
		c, err := l.Accept()
		if err != nil {
			if err != ErrListenerClosed {
				t.Fatal(err)
			}
			return
		}
		go s.ServeConn(c)
	}
}

func runTestRPCClient(t *testing.T, addr net.Addr) {
	c, cleanup := safeDial(t, addr)
	defer cleanup()

	var num int
	if err := c.Call("TestRPCRcvr.Test", rpcVal, &num); err != nil {
		t.Fatal(err)
	}

	if num != rpcVal {
		t.Errorf("wrong rpc response: want=%d got=%v", rpcVal, num)
	}
}

func TestAny(t *testing.T) {
	defer leakCheck(t)()
	l, cleanup := testListener(t)
	defer cleanup()

	muxl := New(l)
	httpl := muxl.Match(Any())

	go runTestHTTPServer(t, httpl)
	go safeServe(t, muxl)

	runTestHTTP1Client(t, l.Addr())
}

func TestHTTPGoRPC(t *testing.T) {
	defer leakCheck(t)()
	l, cleanup := testListener(t)
	defer cleanup()

	muxl := New(l)
	httpl := muxl.Match(HTTP2(), HTTP1Fast())
	rpcl := muxl.Match(Any())

	go runTestHTTPServer(t, httpl)
	go runTestRPCServer(t, rpcl)
	go safeServe(t, muxl)

	runTestHTTP1Client(t, l.Addr())
	runTestRPCClient(t, l.Addr())
}

func TestErrorHandler(t *testing.T) {
	defer leakCheck(t)()
	l, cleanup := testListener(t)
	defer cleanup()

	muxl := New(l)
	httpl := muxl.Match(HTTP2(), HTTP1Fast())

	go runTestHTTPServer(t, httpl)
	go safeServe(t, muxl)

	firstErr := true
	muxl.HandleError(func(err error) bool {
		if !firstErr {
			return true
		}
		if _, ok := err.(ErrNotMatched); !ok {
			t.Errorf("unexpected error: %v", err)
		}
		firstErr = false
		return true
	})

	c, cleanup := safeDial(t, l.Addr())
	defer cleanup()

	var num int
	if err := c.Call("TestRPCRcvr.Test", rpcVal, &num); err == nil {
		t.Error("rpc got a response")
	}
}

type closerConn struct {
	net.Conn
}

func (c closerConn) Close() error { return nil }

func TestClosed(t *testing.T) {
	defer leakCheck(t)()
	mux := &cMux{}
	lis := mux.Match(Any()).(muxListener)
	close(lis.donec)
	mux.serve(closerConn{})
	_, err := lis.Accept()
	if _, ok := err.(errListenerClosed); !ok {
		t.Errorf("expected errListenerClosed got %v", err)
	}
}

// Cribbed from google.golang.org/grpc/test/end2end_test.go.

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// leakCheck snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func leakCheck(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := time.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if time.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<|endoftext|>


<commit_before>package raft

import (
	"encoding/binary"
	"fmt"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"log"
	"path/filepath"
)

const logPath = "logs"
const confPath = "conf"
const maxOpenFiles = 128

type levelDBStore struct {
	db *leveldb.DB
}

func (l *levelDBStore) Close() error {
	return l.db.Close()
}

// LevelDBLogStore provides an implementation of LogStore
type LevelDBLogStore struct {
	levelDBStore
}

// LevelDBStableStore provides an implementation of StableStore
type LevelDBStableStore struct {
	levelDBStore
}

// newLevelDBStore is used to initialize a levelDB store
func newLevelDBStore(path string, store *levelDBStore) error {
	// LevelDB options
	opts := &opt.Options{
		Compression:  opt.SnappyCompression,
		MaxOpenFiles: maxOpenFiles,
		Strict:       opt.StrictAll,
	}

	// Open the DBs
	db, err := leveldb.OpenFile(path, opts)
	if err != nil {
		log.Printf("[ERR] Failed to open leveldb at %v: %v", path, err)
		return err
	}
	store.db = db
	return nil
}

// NewLevelDBLogStore returns a new LevelDBLogStore and potential
// error. Requres a base directory from which to operate.
func NewLevelDBLogStore(base string) (*LevelDBLogStore, error) {
	// Get the paths
	logLoc := filepath.Join(base, logPath)

	// Create the struct
	ldb := &LevelDBLogStore{}

	// Initialize the db
	if err := newLevelDBStore(logLoc, &ldb.levelDBStore); err != nil {
		return nil, err
	}
	return ldb, nil
}

func (l *LevelDBLogStore) FirstIndex() (uint64, error) {
	// Get an iterator
	it := l.db.NewIterator(nil)
	defer it.Release()

	// Seek to the first value
	it.First()

	// Check if there is a key
	key := it.Key()
	if key == nil {
		// Nothing written yet
		return 0, it.Error()
	}

	// Convert the key to the index
	return bytesToUint64(key), it.Error()
}

func (l *LevelDBLogStore) LastIndex() (uint64, error) {
	// Get an iterator
	it := l.db.NewIterator(nil)
	defer it.Release()

	// Seek to the last value
	it.Last()

	// Check if there is a key
	key := it.Key()
	if key == nil {
		// Nothing written yet
		return 0, it.Error()
	}

	// Convert the key to the index
	return bytesToUint64(key), it.Error()
}

// Gets a log entry at a given index
func (l *LevelDBLogStore) GetLog(index uint64, logOut *Log) error {
	key := uint64ToBytes(index)

	// Get an iterator
	snap, err := l.db.GetSnapshot()
	if err != nil {
		return err
	}
	defer snap.Release()

	// Look for the key
	val, err := snap.Get(key, nil)
	if err == leveldb.ErrNotFound {
		return fmt.Errorf("log not found")
	} else if err != nil {
		return err
	}

	// Convert the value to a log
	return decodeMsgPack(val, logOut)
}

// Stores a log entry
func (l *LevelDBLogStore) StoreLog(log *Log) error {
	// Convert to an on-disk format
	key := uint64ToBytes(log.Index)
	val, err := encodeMsgPack(log)
	if err != nil {
		return err
	}

	// Write it out
	opts := &opt.WriteOptions{Sync: true}
	return l.db.Put(key, val.Bytes(), opts)
}

// Deletes a range of log entries. The range is inclusive.
func (l *LevelDBLogStore) DeleteRange(min, max uint64) error {
	// Create a batch operation
	batch := &leveldb.Batch{}
	for i := min; i <= max; i++ {
		key := uint64ToBytes(i)
		batch.Delete(key)
	}

	// Apply the batch
	opts := &opt.WriteOptions{Sync: true}
	return l.db.Write(batch, opts)
}

// NewLevelDBStableStore returns a new LevelDBStableStore and potential
// error. Requres a base directory from which to operate.
func NewLevelDBStableStore(base string) (*LevelDBStableStore, error) {
	// Get the paths
	confLoc := filepath.Join(base, confPath)

	// Create the struct
	ldb := &LevelDBStableStore{}

	// Initialize the db
	if err := newLevelDBStore(confLoc, &ldb.levelDBStore); err != nil {
		return nil, err
	}
	return ldb, nil
}

// Set a K/V pair
func (l *LevelDBStableStore) Set(key []byte, val []byte) error {
	opts := &opt.WriteOptions{Sync: true}
	return l.db.Put(key, val, opts)
}

// Get a K/V pair
func (l *LevelDBStableStore) Get(key []byte) ([]byte, error) {
	// Get a snapshot view
	snap, err := l.db.GetSnapshot()
	if err != nil {
		return nil, err
	}
	defer snap.Release()

	// Look for the key
	val, err := snap.Get(key, nil)
	if err == leveldb.ErrNotFound {
		return nil, fmt.Errorf("not found")
	} else if err != nil {
		return nil, err
	}

	// Copy it to a new buffer
	buf := make([]byte, len(val))
	copy(buf, val)
	return buf, nil
}

func (l *LevelDBStableStore) SetUint64(key []byte, val uint64) error {
	return l.Set(key, uint64ToBytes(val))
}

func (l *LevelDBStableStore) GetUint64(key []byte) (uint64, error) {
	buf, err := l.Get(key)
	if err != nil {
		return 0, err
	}
	return bytesToUint64(buf), nil
}

// Converts bytes to an integer
func bytesToUint64(b []byte) uint64 {
	return binary.BigEndian.Uint64(b)
}

// Converts a uint to a byte slice
func uint64ToBytes(u uint64) []byte {
	buf := make([]byte, 8)
	binary.BigEndian.PutUint64(buf, u)
	return buf
}
<commit_msg>Optimize DeleteRange to only handle real index values<commit_after>package raft

import (
	"encoding/binary"
	"fmt"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"log"
	"path/filepath"
)

const logPath = "logs"
const confPath = "conf"
const maxOpenFiles = 128

type levelDBStore struct {
	db *leveldb.DB
}

func (l *levelDBStore) Close() error {
	return l.db.Close()
}

// LevelDBLogStore provides an implementation of LogStore
type LevelDBLogStore struct {
	levelDBStore
}

// LevelDBStableStore provides an implementation of StableStore
type LevelDBStableStore struct {
	levelDBStore
}

// newLevelDBStore is used to initialize a levelDB store
func newLevelDBStore(path string, store *levelDBStore) error {
	// LevelDB options
	opts := &opt.Options{
		Compression:  opt.SnappyCompression,
		MaxOpenFiles: maxOpenFiles,
		Strict:       opt.StrictAll,
	}

	// Open the DBs
	db, err := leveldb.OpenFile(path, opts)
	if err != nil {
		log.Printf("[ERR] Failed to open leveldb at %v: %v", path, err)
		return err
	}
	store.db = db
	return nil
}

// NewLevelDBLogStore returns a new LevelDBLogStore and potential
// error. Requres a base directory from which to operate.
func NewLevelDBLogStore(base string) (*LevelDBLogStore, error) {
	// Get the paths
	logLoc := filepath.Join(base, logPath)

	// Create the struct
	ldb := &LevelDBLogStore{}

	// Initialize the db
	if err := newLevelDBStore(logLoc, &ldb.levelDBStore); err != nil {
		return nil, err
	}
	return ldb, nil
}

func (l *LevelDBLogStore) FirstIndex() (uint64, error) {
	// Get an iterator
	it := l.db.NewIterator(nil)
	defer it.Release()

	// Seek to the first value
	it.First()

	// Check if there is a key
	key := it.Key()
	if key == nil {
		// Nothing written yet
		return 0, it.Error()
	}

	// Convert the key to the index
	return bytesToUint64(key), it.Error()
}

func (l *LevelDBLogStore) LastIndex() (uint64, error) {
	// Get an iterator
	it := l.db.NewIterator(nil)
	defer it.Release()

	// Seek to the last value
	it.Last()

	// Check if there is a key
	key := it.Key()
	if key == nil {
		// Nothing written yet
		return 0, it.Error()
	}

	// Convert the key to the index
	return bytesToUint64(key), it.Error()
}

// Gets a log entry at a given index
func (l *LevelDBLogStore) GetLog(index uint64, logOut *Log) error {
	key := uint64ToBytes(index)

	// Get an iterator
	snap, err := l.db.GetSnapshot()
	if err != nil {
		return err
	}
	defer snap.Release()

	// Look for the key
	val, err := snap.Get(key, nil)
	if err == leveldb.ErrNotFound {
		return fmt.Errorf("log not found")
	} else if err != nil {
		return err
	}

	// Convert the value to a log
	return decodeMsgPack(val, logOut)
}

// Stores a log entry
func (l *LevelDBLogStore) StoreLog(log *Log) error {
	// Convert to an on-disk format
	key := uint64ToBytes(log.Index)
	val, err := encodeMsgPack(log)
	if err != nil {
		return err
	}

	// Write it out
	opts := &opt.WriteOptions{Sync: true}
	return l.db.Put(key, val.Bytes(), opts)
}

// Deletes a range of log entries. The range is inclusive.
func (l *LevelDBLogStore) DeleteRange(minIdx, maxIdx uint64) error {
	// Get lower and upper index bounds
	firstIdx, err := l.FirstIndex()
	if err != nil {
		return err
	}
	lastIdx, err := l.LastIndex()
	if err != nil {
		return err
	}

	// Optimize the index ranges
	minIdx = max(minIdx, firstIdx)
	maxIdx = min(maxIdx, lastIdx)

	// Create a batch operation
	batch := &leveldb.Batch{}
	for i := minIdx; i <= maxIdx; i++ {
		key := uint64ToBytes(i)
		batch.Delete(key)
	}

	// Apply the batch
	opts := &opt.WriteOptions{Sync: true}
	return l.db.Write(batch, opts)
}

// NewLevelDBStableStore returns a new LevelDBStableStore and potential
// error. Requres a base directory from which to operate.
func NewLevelDBStableStore(base string) (*LevelDBStableStore, error) {
	// Get the paths
	confLoc := filepath.Join(base, confPath)

	// Create the struct
	ldb := &LevelDBStableStore{}

	// Initialize the db
	if err := newLevelDBStore(confLoc, &ldb.levelDBStore); err != nil {
		return nil, err
	}
	return ldb, nil
}

// Set a K/V pair
func (l *LevelDBStableStore) Set(key []byte, val []byte) error {
	opts := &opt.WriteOptions{Sync: true}
	return l.db.Put(key, val, opts)
}

// Get a K/V pair
func (l *LevelDBStableStore) Get(key []byte) ([]byte, error) {
	// Get a snapshot view
	snap, err := l.db.GetSnapshot()
	if err != nil {
		return nil, err
	}
	defer snap.Release()

	// Look for the key
	val, err := snap.Get(key, nil)
	if err == leveldb.ErrNotFound {
		return nil, fmt.Errorf("not found")
	} else if err != nil {
		return nil, err
	}

	// Copy it to a new buffer
	buf := make([]byte, len(val))
	copy(buf, val)
	return buf, nil
}

func (l *LevelDBStableStore) SetUint64(key []byte, val uint64) error {
	return l.Set(key, uint64ToBytes(val))
}

func (l *LevelDBStableStore) GetUint64(key []byte) (uint64, error) {
	buf, err := l.Get(key)
	if err != nil {
		return 0, err
	}
	return bytesToUint64(buf), nil
}

// Converts bytes to an integer
func bytesToUint64(b []byte) uint64 {
	return binary.BigEndian.Uint64(b)
}

// Converts a uint to a byte slice
func uint64ToBytes(u uint64) []byte {
	buf := make([]byte, 8)
	binary.BigEndian.PutUint64(buf, u)
	return buf
}
<|endoftext|>


<commit_before>package GoSDK

import (
	"fmt"
	"strings"
)

const (
	_CODE_ADMIN_PREAMBLE    = "/admin/code/v/1"
	_CODE_ADMIN_PREAMBLE_V2 = "/codeadmin/v/2"
)

//Service is a helper struct for grouping facts about a code service
type Service struct {
	Name    string
	Code    string
	Version int
	Params  []string
	System  string
}

//CodeLog provides structure to the code log return value
type CodeLog struct {
	Log  string
	Time string
}

//GetServiceNames retrieves the service names for a particular system
func (d *DevClient) GetServiceNames(systemKey string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting services: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting services: %v", resp.Body)
	}
	code := resp.Body.(map[string]interface{})["code"]
	sliceBody, isSlice := code.([]interface{})
	if !isSlice && code != nil {
		return nil, fmt.Errorf("Error getting services: server returned unexpected response")
	}
	services := make([]string, len(sliceBody))
	for i, service := range sliceBody {
		services[i] = service.(string)
	}
	return services, nil
}

//GetService returns information about a specified service
func (d *DevClient) GetService(systemKey, name string) (*Service, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	paramsSlice := mapBody["params"].([]interface{})
	params := make([]string, len(paramsSlice))
	for i, param := range paramsSlice {
		params[i] = param.(string)
	}
	svc := &Service{
		Name:    name,
		System:  systemKey,
		Code:    mapBody["code"].(string),
		Version: int(mapBody["current_version"].(float64)),
		Params:  params,
	}
	return svc, nil
}

func (d *DevClient) GetServiceRaw(systemKey, name string) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	/*
		paramsSlice := mapBody["params"].([]interface{})
		params := make([]string, len(paramsSlice))
		for i, param := range paramsSlice {
			params[i] = param.(string)
		}
	*/
	return mapBody, nil
}

//SetServiceEffectiveUser allows the developer to set the userid that a service executes under.
func (d *DevClient) SetServiceEffectiveUser(systemKey, name, userid string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, map[string]interface{}{
		"run_user": userid,
	}, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating service: %v\n", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return nil
}

//UpdateService facillitates changes to the service's code
func (d *DevClient) UpdateService(systemKey, name, code string, params []string) (error, map[string]interface{}) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params}
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) UpdateServiceWithLibraries(systemKey, name, code, deps string, params []string) (error, map[string]interface{}) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params, "dependencies": deps}
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) updateService(sysKey, name, code string, extra map[string]interface{}) (error, map[string]interface{}) {
	creds, err := d.credentials()
	if err != nil {
		return err, nil
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+sysKey+"/"+name, extra, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating service: %v\n", err), nil
	}
	body, ok := resp.Body.(map[string]interface{})
	if !ok {
		return fmt.Errorf("Service not created. First create service..."), nil
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating service: %v\n", resp.Body), nil
	}
	return nil, body
}

//NewServiceWithLibraries creates a new service with the specified code, params, and libraries/dependencies.
//Parameters is a slice of strings of parameter names
func (d *DevClient) NewServiceWithLibraries(systemKey, name, code, deps string, params []string) error {
	extra := map[string]interface{}{"parameters": params, "dependencies": deps}
	return d.newService(systemKey, name, code, extra)
}

//NewService creates a new service with a new name, code and params
func (d *DevClient) NewService(systemKey, name, code string, params []string) error {
	extra := map[string]interface{}{"parameters": params}
	return d.newService(systemKey, name, code, extra)
}

//EnableLogsForService activates logging for execution of a service
func (d *DevClient) EnableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": "true"}, creds, nil)
	return err
}

//DisableLogsForService turns logging off for that service
func (d *DevClient) DisableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": false}, creds, nil)
	return err
}

//AreServiceLogsEnabled allows the developer to query the state of logging
func (d *DevClient) AreServiceLogsEnabled(systemKey, name string) (bool, error) {
	creds, err := d.credentials()
	if err != nil {
		return false, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name+"/active", nil, creds, nil)
	if err != nil {
		return false, err
	}
	le := resp.Body.(map[string]interface{})["logging_enabled"]
	if le == nil {
		return false, fmt.Errorf("Improperly formatted json response")
	} else {
		return strings.ToLower(le.(string)) == "true", nil
	}
}

//GetLogsForService retrieves the logs for the service
func (d *DevClient) GetLogsForService(systemKey, name string) ([]CodeLog, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, err
	}
	switch resp.Body.(type) {
	case string:
		return nil, fmt.Errorf("%s", resp.Body.(string))
	case []interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	case []map[string]interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	default:
		return nil, fmt.Errorf("Bad Return Value\n")
	}
}

func (d *DevClient) newService(systemKey, name, code string, extra map[string]interface{}) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	extra["code"] = code
	resp, err := post(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, extra, creds, nil)
	if err != nil {
		return fmt.Errorf("Error creating new service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error creating new service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) DeleteService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := delete(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) GetFailedServices(systemKey string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, "/codeadmin/failed/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not get failed services: %s", err)
	}
	body := resp.Body.(map[string]interface{})[systemKey].([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) RetryFailedServices(systemKey string, ids []string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not retry failed service %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	responses := make([]string, len(body))
	for i, b := range body {
		responses[i] = b.(string)
	}
	return responses, nil
}

func (d *DevClient) DeleteFailedServices(systemKey string, ids []string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := deleteWithBody(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not delete failed services %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func genCodeLog(m map[string]interface{}) CodeLog {
	cl := CodeLog{}
	if tim, ext := m["service_execution_time"]; ext {
		t := tim.(string)
		cl.Time = t
	}
	if logg, ext := m["log"]; ext {
		l := logg.(string)
		cl.Log = l
	}
	return cl
}
<commit_msg>added setLongRunningServiceParams<commit_after>package GoSDK

import (
	"fmt"
	"strings"
)

const (
	_CODE_ADMIN_PREAMBLE    = "/admin/code/v/1"
	_CODE_ADMIN_PREAMBLE_V2 = "/codeadmin/v/2"
)

//Service is a helper struct for grouping facts about a code service
type Service struct {
	Name    string
	Code    string
	Version int
	Params  []string
	System  string
}

//CodeLog provides structure to the code log return value
type CodeLog struct {
	Log  string
	Time string
}

//GetServiceNames retrieves the service names for a particular system
func (d *DevClient) GetServiceNames(systemKey string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting services: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting services: %v", resp.Body)
	}
	code := resp.Body.(map[string]interface{})["code"]
	sliceBody, isSlice := code.([]interface{})
	if !isSlice && code != nil {
		return nil, fmt.Errorf("Error getting services: server returned unexpected response")
	}
	services := make([]string, len(sliceBody))
	for i, service := range sliceBody {
		services[i] = service.(string)
	}
	return services, nil
}

//GetService returns information about a specified service
func (d *DevClient) GetService(systemKey, name string) (*Service, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	paramsSlice := mapBody["params"].([]interface{})
	params := make([]string, len(paramsSlice))
	for i, param := range paramsSlice {
		params[i] = param.(string)
	}
	svc := &Service{
		Name:    name,
		System:  systemKey,
		Code:    mapBody["code"].(string),
		Version: int(mapBody["current_version"].(float64)),
		Params:  params,
	}
	return svc, nil
}

func (d *DevClient) GetServiceRaw(systemKey, name string) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Error getting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Error getting service: %v", resp.Body)
	}
	mapBody := resp.Body.(map[string]interface{})
	/*
		paramsSlice := mapBody["params"].([]interface{})
		params := make([]string, len(paramsSlice))
		for i, param := range paramsSlice {
			params[i] = param.(string)
		}
	*/
	return mapBody, nil
}

//SetServiceEffectiveUser allows the developer to set the userid that a service executes under.
func (d *DevClient) SetServiceEffectiveUser(systemKey, name, userid string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, map[string]interface{}{
		"run_user": userid,
	}, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating service: %v\n", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating service: %v\n", resp.Body)
	}
	return nil
}

//UpdateService facillitates changes to the service's code
func (d *DevClient) UpdateService(systemKey, name, code string, params []string) (error, map[string]interface{}) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params}
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) UpdateServiceWithLibraries(systemKey, name, code, deps string, params []string) (error, map[string]interface{}) {
	extra := map[string]interface{}{"code": code, "name": name, "parameters": params, "dependencies": deps}
	return d.updateService(systemKey, name, code, extra)
}

func (d *DevClient) updateService(sysKey, name, code string, extra map[string]interface{}) (error, map[string]interface{}) {
	creds, err := d.credentials()
	if err != nil {
		return err, nil
	}
	resp, err := put(d, _CODE_ADMIN_PREAMBLE+"/"+sysKey+"/"+name, extra, creds, nil)
	if err != nil {
		return fmt.Errorf("Error updating service: %v\n", err), nil
	}
	body, ok := resp.Body.(map[string]interface{})
	if !ok {
		return fmt.Errorf("Service not created. First create service..."), nil
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error updating service: %v\n", resp.Body), nil
	}
	return nil, body
}

//NewServiceWithLibraries creates a new service with the specified code, params, and libraries/dependencies.
//Parameters is a slice of strings of parameter names
func (d *DevClient) NewServiceWithLibraries(systemKey, name, code, deps string, params []string) error {
	extra := map[string]interface{}{"parameters": params, "dependencies": deps}
	return d.newService(systemKey, name, code, extra)
}

//NewService creates a new service with a new name, code and params
func (d *DevClient) NewService(systemKey, name, code string, params []string) error {
	extra := map[string]interface{}{"parameters": params}
	return d.newService(systemKey, name, code, extra)
}

//EnableLogsForService activates logging for execution of a service
func (d *DevClient) EnableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": "true"}, creds, nil)
	return err
}

//DisableLogsForService turns logging off for that service
func (d *DevClient) DisableLogsForService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	_, err = post(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, map[string]interface{}{"logging": false}, creds, nil)
	return err
}

//AreServiceLogsEnabled allows the developer to query the state of logging
func (d *DevClient) AreServiceLogsEnabled(systemKey, name string) (bool, error) {
	creds, err := d.credentials()
	if err != nil {
		return false, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name+"/active", nil, creds, nil)
	if err != nil {
		return false, err
	}
	le := resp.Body.(map[string]interface{})["logging_enabled"]
	if le == nil {
		return false, fmt.Errorf("Improperly formatted json response")
	} else {
		return strings.ToLower(le.(string)) == "true", nil
	}
}

//GetLogsForService retrieves the logs for the service
func (d *DevClient) GetLogsForService(systemKey, name string) ([]CodeLog, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, _CODE_ADMIN_PREAMBLE_V2+"/logs/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return nil, err
	}
	switch resp.Body.(type) {
	case string:
		return nil, fmt.Errorf("%s", resp.Body.(string))
	case []interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	case []map[string]interface{}:
		r := resp.Body.([]map[string]interface{})
		outgoing := make([]CodeLog, len(r))
		for idx, v := range r {
			cl := genCodeLog(v)
			outgoing[idx] = cl
		}
		return outgoing, nil
	default:
		return nil, fmt.Errorf("Bad Return Value\n")
	}
}

func (d *DevClient) newService(systemKey, name, code string, extra map[string]interface{}) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	extra["code"] = code
	resp, err := post(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, extra, creds, nil)
	if err != nil {
		return fmt.Errorf("Error creating new service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error creating new service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) DeleteService(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := delete(d, _CODE_ADMIN_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	if err != nil {
		return fmt.Errorf("Error deleting service: %v", err)
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("Error deleting service: %v", resp.Body)
	}
	return nil
}

func (d *DevClient) GetFailedServices(systemKey string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(d, "/codeadmin/failed/"+systemKey, nil, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not get failed services: %s", err)
	}
	body := resp.Body.(map[string]interface{})[systemKey].([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) RetryFailedServices(systemKey string, ids []string) ([]string, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not retry failed service %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	responses := make([]string, len(body))
	for i, b := range body {
		responses[i] = b.(string)
	}
	return responses, nil
}

func (d *DevClient) DeleteFailedServices(systemKey string, ids []string) ([]map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := deleteWithBody(d, "/codeadmin/failed/"+systemKey, map[string]interface{}{"id": ids}, creds, nil)
	if err != nil {
		return nil, fmt.Errorf("Could not delete failed services %s/%s: %s", systemKey, ids, err)
	}
	body := resp.Body.([]interface{})
	services := make([]map[string]interface{}, len(body))
	for i, b := range body {
		services[i] = b.(map[string]interface{})
	}
	return services, nil
}

func (d *DevClient) SetLongRunningServiceParams(systemKey, name string, autoRestart bool, concurrency int) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	params := map[string]interface{}{
		"execution_timeout": -1,
		"auto_restart":      autoRestart,
		"concurrency":       concurrency,
	}

	_, err = put(d, _CODE_ADMIN_PREAMBLE_V2+"/"+systemKey+"/"+name, params, creds, nil)
	return err
}

func genCodeLog(m map[string]interface{}) CodeLog {
	cl := CodeLog{}
	if tim, ext := m["service_execution_time"]; ext {
		t := tim.(string)
		cl.Time = t
	}
	if logg, ext := m["log"]; ext {
		l := logg.(string)
		cl.Log = l
	}
	return cl
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package commands

import (
	. "github.com/limetext/lime/backend"
	"io/ioutil"
	"os"
	"testing"
)

var testfile string = "../testdata/Default.sublime-settings"

func TestSave(t *testing.T) {
	hold, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatalf("Couldn't read test file %s", testfile)
	}
	if err := ioutil.WriteFile(testfile, []byte("Before text"), 0644); err != nil {
		t.Fatalf("Couldn't write test file %s", testfile)
	}
	tests := []struct {
		text   string
		expect string
	}{
		{
			" ab\ncd",
			"Before text ab\ncd",
		},
		{
			"\n",
			"Before text\n",
		},
	}
	ed := GetEditor()
	w := ed.NewWindow()

	for i, test := range tests {
		err := ioutil.WriteFile(testfile, []byte("Before text"), 0644)
		if err != nil {
			t.Fatal("Could not write to test file")
		}

		v := w.OpenFile(testfile, 0)
		e := v.BeginEdit()
		v.Insert(e, v.Buffer().Size(), test.text)
		v.EndEdit(e)

		ed.CommandHandler().RunTextCommand(v, "save", nil)
		if data, _ := ioutil.ReadFile(testfile); test.expect != string(data) {
			t.Errorf("Test %d: Expected %s, but got %s", i, test.expect, string(data))
		}
	}
	if err := ioutil.WriteFile(testfile, hold, 0644); err != nil {
		t.Fatalf("Couldn't write back test file %s", testfile)
	}
}

func TestSaveAs(t *testing.T) {
	hold, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatalf("Couldn't read test file %s", testfile)
	}
	if err := ioutil.WriteFile(testfile, []byte(""), 0644); err != nil {
		t.Fatalf("Couldn't write test file %s", testfile)
	}
	ed := GetEditor()
	w := ed.NewWindow()
	v := w.OpenFile(testfile, 0)
	e := v.BeginEdit()
	v.Insert(e, 0, "Testing save_as command")
	v.BeginEdit()

	name := "../testdata/save_as_test.txt"

	ed.CommandHandler().RunTextCommand(v, "save_as", Args{"name": name})
	if _, err := os.Stat(name); os.IsNotExist(err) {
		t.Errorf("The new test file %s wasn't created", name)
	}
	if data, _ := ioutil.ReadFile(name); "Testing save_as command" != string(data) {
		t.Errorf("Expected %s, but got %s", "Testing save_as command", string(data))
	}
	if err := os.Remove(name); err != nil {
		t.Errorf("Couldn't remove test file %s", name)
	}
	if err := ioutil.WriteFile(testfile, hold, 0644); err != nil {
		t.Fatalf("Couldn't write back test file %s", testfile)
	}
}

func TestSaveAll(t *testing.T) {
	var err error
	holds := make(map[int][]byte)
	tests := []struct {
		file   string
		expect string
	}{
		{
			"../testdata/Default.sublime-settings",
			"Testing save all 1",
		},
		{
			"../testdata/Default.sublime-keymap",
			"Testing save all 2",
		},
	}
	ed := GetEditor()
	w := ed.NewWindow()
	for i, test := range tests {
		holds[i], err = ioutil.ReadFile(test.file)
		if err != nil {
			t.Fatalf("Test %d: Couldn't read file %s", i, test.file)
		}
		if err := ioutil.WriteFile(test.file, []byte(""), 0644); err != nil {
			t.Fatalf("Test %d: Couldn't write test file %s", i, test.file)
		}
		v := w.OpenFile(test.file, 0)
		e := v.BeginEdit()
		v.Insert(e, 0, test.expect)
		v.EndEdit(e)
	}
	ed.CommandHandler().RunWindowCommand(w, "save_all", nil)
	for i, test := range tests {
		if data, _ := ioutil.ReadFile(test.file); string(data) != test.expect {
			t.Errorf("Test %d: Expected to get `%s`, but got `%s`", i, test.expect, string(data))
		}
	}
	for i, test := range tests {
		ioutil.WriteFile(test.file, holds[i], 0644)
	}
}
<commit_msg>backend/commands/save_test: make use of DummyFrontend.DefaultAction<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package commands

import (
	. "github.com/limetext/lime/backend"
	"io/ioutil"
	"os"
	"testing"
)

var testfile string = "../testdata/Default.sublime-settings"

func TestSave(t *testing.T) {
	hold, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatalf("Couldn't read test file %s", testfile)
	}
	if err := ioutil.WriteFile(testfile, []byte("Before text"), 0644); err != nil {
		t.Fatalf("Couldn't write test file %s", testfile)
	}
	tests := []struct {
		text   string
		expect string
	}{
		{
			" ab\ncd",
			"Before text ab\ncd",
		},
		{
			"\n",
			"Before text\n",
		},
	}
	ed := GetEditor()
	w := ed.NewWindow()

	for i, test := range tests {
		err := ioutil.WriteFile(testfile, []byte("Before text"), 0644)
		if err != nil {
			t.Fatal("Could not write to test file")
		}

		v := w.OpenFile(testfile, 0)
		e := v.BeginEdit()
		v.Insert(e, v.Buffer().Size(), test.text)
		v.EndEdit(e)

		ed.CommandHandler().RunTextCommand(v, "save", nil)
		if data, _ := ioutil.ReadFile(testfile); test.expect != string(data) {
			t.Errorf("Test %d: Expected %s, but got %s", i, test.expect, string(data))
		}
	}
	if err := ioutil.WriteFile(testfile, hold, 0644); err != nil {
		t.Fatalf("Couldn't write back test file %s", testfile)
	}
}

func TestSaveAs(t *testing.T) {
	hold, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatalf("Couldn't read test file %s", testfile)
	}
	if err := ioutil.WriteFile(testfile, []byte(""), 0644); err != nil {
		t.Fatalf("Couldn't write test file %s", testfile)
	}
	ed := GetEditor()
	w := ed.NewWindow()
	v := w.OpenFile(testfile, 0)
	e := v.BeginEdit()
	v.Insert(e, 0, "Testing save_as command")
	v.BeginEdit()

	name := "../testdata/save_as_test.txt"

	ed.CommandHandler().RunTextCommand(v, "save_as", Args{"name": name})
	if _, err := os.Stat(name); os.IsNotExist(err) {
		t.Errorf("The new test file %s wasn't created", name)
	}
	if data, _ := ioutil.ReadFile(name); "Testing save_as command" != string(data) {
		t.Errorf("Expected %s, but got %s", "Testing save_as command", string(data))
	}
	if err := os.Remove(name); err != nil {
		t.Errorf("Couldn't remove test file %s", name)
	}
	if err := ioutil.WriteFile(testfile, hold, 0644); err != nil {
		t.Fatalf("Couldn't write back test file %s", testfile)
	}
}

func TestSaveAll(t *testing.T) {
	var err error
	holds := make(map[int][]byte)
	tests := []struct {
		file   string
		expect string
	}{
		{
			"../testdata/Default.sublime-settings",
			"Testing save all 1",
		},
		{
			"../testdata/Default.sublime-keymap",
			"Testing save all 2",
		},
	}
	ed := GetEditor()
	fe := ed.Frontend()
	if dfe, ok := fe.(*DummyFrontend); ok {
		// Make it *not* reload the file
		dfe.DefaultAction = false
	}

	w := ed.NewWindow()
	for i, test := range tests {
		holds[i], err = ioutil.ReadFile(test.file)
		if err != nil {
			t.Fatalf("Test %d: Couldn't read file %s", i, test.file)
		}
		if err := ioutil.WriteFile(test.file, []byte(""), 0644); err != nil {
			t.Fatalf("Test %d: Couldn't write test file %s", i, test.file)
		}
		v := w.OpenFile(test.file, 0)
		e := v.BeginEdit()
		v.Insert(e, 0, test.expect)
		v.EndEdit(e)
	}
	if err := ed.CommandHandler().RunWindowCommand(w, "save_all", nil); err != nil {
		t.Errorf("failed to run save_all: %s", err)
	}
	for i, test := range tests {
		if data, err := ioutil.ReadFile(test.file); err != nil {
			t.Errorf("failed to read in file: %s", err)
		} else if s := string(data); s != test.expect {
			t.Errorf("Test %d: Expected to get `%s`, but got `%s`", i, test.expect, s)
		}
	}
	for i, test := range tests {
		ioutil.WriteFile(test.file, holds[i], 0644)
	}
}
<|endoftext|>


<commit_before>package cloudatgost

import(
	"net/http"
	"net/url"
)

type TaskList struct {
	Status string `json:"status"`
	Time int `json:"time"`
	API string `json:"api"`
	Cid string `json:"cid"`
	Action string `json:"action"`
	Data []struct {
		Cid string `json:"cid"`
		Idf string `json:"idf"`
		Serverid string `json:"serverid"`
		Action string `json:"action"`
		Status string `json:"status"`
		Starttime string `json:"starttime"`
		Finishtime string `json:"finishtime"`
	} `json:"data"`
}

func (c *Client) ListTasks() (*TaskList) {
	v := &TaskList{}
	Url, err := url.Parse(c.BaseURL)
	if err != nil {
		panic("boom! Busted :F")
	}
	Url.Path += "listtasks.php"
	parameters := url.Values{}
	parameters.Add("key", c.Token)
	parameters.Add("login", c.Login)
	Url.RawQuery = parameters.Encode()

	request, err := http.NewRequest("GET", Url.String(), nil)
	if err != nil {
		return nil
	}

	c.Do(request, &v)
	return v
}
<commit_msg>listtasks.go properly commented<commit_after>package cloudatgost

import(
	"net/http"
	"net/url"
)

// A TaskList represents an API response that contains a list
// of tasks in operation.
type TaskList struct {
	Status string `json:"status"`
	Time int `json:"time"`
	API string `json:"api"`
	Cid string `json:"cid"`
	Action string `json:"action"`
	Data []struct {
		Cid string `json:"cid"`
		Idf string `json:"idf"`
		Serverid string `json:"serverid"`
		Action string `json:"action"`
		Status string `json:"status"`
		Starttime string `json:"starttime"`
		Finishtime string `json:"finishtime"`
	} `json:"data"`
}

// ListTasks formulates an HTTP request to the listtasks.php
// endpoint and maps the JSON response through Do to a TaskList
// structure.
func (c *Client) ListTasks() (*TaskList) {
	v := &TaskList{}
	Url, err := url.Parse(c.BaseURL)
	if err != nil {
		panic("boom! Busted :F")
	}
	Url.Path += "listtasks.php"
	parameters := url.Values{}
	parameters.Add("key", c.Token)
	parameters.Add("login", c.Login)
	Url.RawQuery = parameters.Encode()

	request, err := http.NewRequest("GET", Url.String(), nil)
	if err != nil {
		return nil
	}

	c.Do(request, &v)
	return v
}
<|endoftext|>


<commit_before>package simulation

import (
	"container/list"
	"log"
	"math"
	"math/rand"
	"superstellar/backend/constants"
	"superstellar/backend/events"
	"superstellar/backend/state"
	"superstellar/backend/types"
	"time"
)

// UpdatePhysics updates world physics for the next simulation step
func UpdatePhysics(space *state.Space, eventDispatcher *events.EventDispatcher) {
	detectProjectileCollisions(space, eventDispatcher)
	updateSpaceships(space, eventDispatcher)
	updateProjectiles(space)
}

func detectProjectileCollisions(space *state.Space, eventDispatcher *events.EventDispatcher) {
	for projectile := range space.Projectiles {
		for clientID, spaceship := range space.Spaceships {
			if projectile.ClientID != clientID && projectile.DetectCollision(spaceship) {
				spaceship.CollideWithProjectile(projectile)
				space.RemoveProjectile(projectile)

				if spaceship.HP <= 0 {
					space.RemoveSpaceship(clientID)

					userDiedMessage := &events.UserDied{ClientID: clientID, KilledBy: projectile.ClientID}
					eventDispatcher.FireUserDied(userDiedMessage)
				}
			}
		}
	}
}

func updateSpaceships(s *state.Space, eventDispatcher *events.EventDispatcher) {
	now := time.Now()

	for _, spaceship := range s.Spaceships {
		if spaceship.Fire {
			timeSinceLastShot := now.Sub(spaceship.LastShotTime)
			if timeSinceLastShot >= constants.MinFireInterval {
				projectile := state.NewProjectile(s.NextProjectileID(),
					s.PhysicsFrameID, spaceship)
				s.AddProjectile(projectile)
				spaceship.LastShotTime = now

				shotEvent := &events.ProjectileFired{
					Projectile: projectile,
				}
				eventDispatcher.FireProjectileFired(shotEvent)
			}
		}

		if spaceship.InputThrust {
			deltaVelocity := spaceship.NormalizedFacing().Multiply(constants.SpaceshipAcceleration)
			spaceship.Velocity = spaceship.Velocity.Add(deltaVelocity)
		} else {
			spaceship.Velocity = spaceship.Velocity.Multiply(1 - constants.FrictionCoefficient)
		}

		if spaceship.Position.Add(spaceship.Velocity).Length() > constants.WorldRadius {
			outreachLength := spaceship.Position.Length() - constants.WorldRadius
			gravityAcceleration := -(outreachLength / constants.BoundaryAnnulusWidth) * constants.SpaceshipAcceleration
			deltaVelocity := spaceship.Position.Normalize().Multiply(gravityAcceleration)
			spaceship.Velocity = spaceship.Velocity.Add(deltaVelocity)
		}

		if spaceship.Velocity.Length() > constants.SpaceshipMaxSpeed {
			spaceship.Velocity = spaceship.Velocity.Normalize().Multiply(constants.SpaceshipMaxSpeed)
		}

		spaceship.Position = spaceship.Position.Add(spaceship.Velocity)

		angle := math.Atan2(spaceship.Facing.Y, spaceship.Facing.X)
		switch spaceship.InputDirection {
		case state.LEFT:
			angle += constants.SpaceshipAngularVelocity
		case state.RIGHT:
			angle -= constants.SpaceshipAngularVelocity
		}

		spaceship.Facing = types.NewVector(math.Cos(angle), math.Sin(angle))
	}

	collided := make(map[*state.Spaceship]bool)
	oldVelocity := make(map[*state.Spaceship]*types.Vector)

	for _, spaceship := range s.Spaceships {

		collided[spaceship] = true

		for _, otherSpaceship := range s.Spaceships {
			if !collided[otherSpaceship] && spaceship.DetectCollision(otherSpaceship) {
				if _, exists := oldVelocity[spaceship]; !exists {
					oldVelocity[spaceship] = spaceship.Velocity.Multiply(-1.0)
				}

				if _, exists := oldVelocity[otherSpaceship]; !exists {
					oldVelocity[otherSpaceship] = otherSpaceship.Velocity.Multiply(-1.0)
				}

				spaceship.Collide(otherSpaceship)
			}
		}
	}

	queue := list.New()
	collidedThisTurn := make(map[*state.Spaceship]bool)
	visited := make(map[*state.Spaceship]bool)

	for spaceship := range oldVelocity {
		queue.PushBack(spaceship)
		collidedThisTurn[spaceship] = true
		visited[spaceship] = true
	}

	for e := queue.Front(); e != nil; e = e.Next() {
		spaceship := e.Value.(*state.Spaceship)
		collidedThisTurn[spaceship] = true
		spaceship.Position = spaceship.Position.Add(oldVelocity[spaceship])

		for _, otherSpaceship := range s.Spaceships {
			if !collidedThisTurn[otherSpaceship] && spaceship.DetectCollision(otherSpaceship) {
				oldVelocity[otherSpaceship] = otherSpaceship.Velocity.Multiply(-1.0)
				if !visited[otherSpaceship] {
					visited[otherSpaceship] = true
					queue.PushBack(otherSpaceship)
				}

				spaceship.Collide(otherSpaceship)
			}
		}
	}

	// TODO kod przeciwzakrzepowy - wywalic jak zrobimy losowe spawnowanie
	collided2 := make(map[*state.Spaceship]bool)

	for _, spaceship := range s.Spaceships {
		collided2[spaceship] = true
		for _, otherSpaceship := range s.Spaceships {
			if !collided2[otherSpaceship] && spaceship.DetectCollision(otherSpaceship) {
				log.Printf("COLLISON")
				if val, exists := oldVelocity[spaceship]; exists {
					log.Printf("ov1: %f %f", val.X, val.Y)
				}
				if val, exists := oldVelocity[otherSpaceship]; exists {
					log.Printf("ov2: %f %f", val.X, val.Y)
				}
				log.Printf("v1: %f %f", spaceship.Velocity.X, spaceship.Velocity.Y)
				log.Printf("v2: %f %f", otherSpaceship.Velocity.X, otherSpaceship.Velocity.Y)
				log.Printf("p1: %d %d", spaceship.Position.X, spaceship.Position.Y)
				log.Printf("p2: %d %d", otherSpaceship.Position.X, otherSpaceship.Position.Y)

				randAngle := rand.Float64() * 2 * math.Pi
				randMove := types.NewVector(5000, 0).Rotate(randAngle)
				spaceship.Position = spaceship.Position.Add(randMove)
			}
		}
	}
	// koniec kodu przeciwzakrzepowego

	s.PhysicsFrameID++
}

func updateProjectiles(space *state.Space) {
	for projectile := range space.Projectiles {
		projectile.TTL--
		if projectile.TTL > 0 {
			projectile.Position = projectile.Position.Add(projectile.Velocity)
		} else {
			space.RemoveProjectile(projectile)
		}
	}
}
<commit_msg>Prevent using friction when we dont have to<commit_after>package simulation

import (
	"container/list"
	"log"
	"math"
	"math/rand"
	"superstellar/backend/constants"
	"superstellar/backend/events"
	"superstellar/backend/state"
	"superstellar/backend/types"
	"time"
)

// UpdatePhysics updates world physics for the next simulation step
func UpdatePhysics(space *state.Space, eventDispatcher *events.EventDispatcher) {
	detectProjectileCollisions(space, eventDispatcher)
	updateSpaceships(space, eventDispatcher)
	updateProjectiles(space)
}

func detectProjectileCollisions(space *state.Space, eventDispatcher *events.EventDispatcher) {
	for projectile := range space.Projectiles {
		for clientID, spaceship := range space.Spaceships {
			if projectile.ClientID != clientID && projectile.DetectCollision(spaceship) {
				spaceship.CollideWithProjectile(projectile)
				space.RemoveProjectile(projectile)

				if spaceship.HP <= 0 {
					space.RemoveSpaceship(clientID)

					userDiedMessage := &events.UserDied{ClientID: clientID, KilledBy: projectile.ClientID}
					eventDispatcher.FireUserDied(userDiedMessage)
				}
			}
		}
	}
}

func updateSpaceships(s *state.Space, eventDispatcher *events.EventDispatcher) {
	now := time.Now()

	for _, spaceship := range s.Spaceships {
		if spaceship.Fire {
			timeSinceLastShot := now.Sub(spaceship.LastShotTime)
			if timeSinceLastShot >= constants.MinFireInterval {
				projectile := state.NewProjectile(s.NextProjectileID(),
					s.PhysicsFrameID, spaceship)
				s.AddProjectile(projectile)
				spaceship.LastShotTime = now

				shotEvent := &events.ProjectileFired{
					Projectile: projectile,
				}
				eventDispatcher.FireProjectileFired(shotEvent)
			}
		}

		if spaceship.InputThrust {
			deltaVelocity := spaceship.NormalizedFacing().Multiply(constants.SpaceshipAcceleration)
			spaceship.Velocity = spaceship.Velocity.Add(deltaVelocity)
		} else {
			if spaceship.Velocity.Length() != 0 {
				spaceship.Velocity = spaceship.Velocity.Multiply(1 - constants.FrictionCoefficient)

				if spaceship.Velocity.Length() < 1 {
					spaceship.Velocity = types.ZeroVector()
				}
			}
		}

		if spaceship.Position.Add(spaceship.Velocity).Length() > constants.WorldRadius {
			outreachLength := spaceship.Position.Length() - constants.WorldRadius
			gravityAcceleration := -(outreachLength / constants.BoundaryAnnulusWidth) * constants.SpaceshipAcceleration
			deltaVelocity := spaceship.Position.Normalize().Multiply(gravityAcceleration)
			spaceship.Velocity = spaceship.Velocity.Add(deltaVelocity)
		}

		if spaceship.Velocity.Length() > constants.SpaceshipMaxSpeed {
			spaceship.Velocity = spaceship.Velocity.Normalize().Multiply(constants.SpaceshipMaxSpeed)
		}

		spaceship.Position = spaceship.Position.Add(spaceship.Velocity)

		angle := math.Atan2(spaceship.Facing.Y, spaceship.Facing.X)
		switch spaceship.InputDirection {
		case state.LEFT:
			angle += constants.SpaceshipAngularVelocity
		case state.RIGHT:
			angle -= constants.SpaceshipAngularVelocity
		}

		spaceship.Facing = types.NewVector(math.Cos(angle), math.Sin(angle))
	}

	collided := make(map[*state.Spaceship]bool)
	oldVelocity := make(map[*state.Spaceship]*types.Vector)

	for _, spaceship := range s.Spaceships {

		collided[spaceship] = true

		for _, otherSpaceship := range s.Spaceships {
			if !collided[otherSpaceship] && spaceship.DetectCollision(otherSpaceship) {
				if _, exists := oldVelocity[spaceship]; !exists {
					oldVelocity[spaceship] = spaceship.Velocity.Multiply(-1.0)
				}

				if _, exists := oldVelocity[otherSpaceship]; !exists {
					oldVelocity[otherSpaceship] = otherSpaceship.Velocity.Multiply(-1.0)
				}

				spaceship.Collide(otherSpaceship)
			}
		}
	}

	queue := list.New()
	collidedThisTurn := make(map[*state.Spaceship]bool)
	visited := make(map[*state.Spaceship]bool)

	for spaceship := range oldVelocity {
		queue.PushBack(spaceship)
		collidedThisTurn[spaceship] = true
		visited[spaceship] = true
	}

	for e := queue.Front(); e != nil; e = e.Next() {
		spaceship := e.Value.(*state.Spaceship)
		collidedThisTurn[spaceship] = true
		spaceship.Position = spaceship.Position.Add(oldVelocity[spaceship])

		for _, otherSpaceship := range s.Spaceships {
			if !collidedThisTurn[otherSpaceship] && spaceship.DetectCollision(otherSpaceship) {
				oldVelocity[otherSpaceship] = otherSpaceship.Velocity.Multiply(-1.0)
				if !visited[otherSpaceship] {
					visited[otherSpaceship] = true
					queue.PushBack(otherSpaceship)
				}

				spaceship.Collide(otherSpaceship)
			}
		}
	}

	// TODO kod przeciwzakrzepowy - wywalic jak zrobimy losowe spawnowanie
	collided2 := make(map[*state.Spaceship]bool)

	for _, spaceship := range s.Spaceships {
		collided2[spaceship] = true
		for _, otherSpaceship := range s.Spaceships {
			if !collided2[otherSpaceship] && spaceship.DetectCollision(otherSpaceship) {
				log.Printf("COLLISON")
				if val, exists := oldVelocity[spaceship]; exists {
					log.Printf("ov1: %f %f", val.X, val.Y)
				}
				if val, exists := oldVelocity[otherSpaceship]; exists {
					log.Printf("ov2: %f %f", val.X, val.Y)
				}
				log.Printf("v1: %f %f", spaceship.Velocity.X, spaceship.Velocity.Y)
				log.Printf("v2: %f %f", otherSpaceship.Velocity.X, otherSpaceship.Velocity.Y)
				log.Printf("p1: %d %d", spaceship.Position.X, spaceship.Position.Y)
				log.Printf("p2: %d %d", otherSpaceship.Position.X, otherSpaceship.Position.Y)

				randAngle := rand.Float64() * 2 * math.Pi
				randMove := types.NewVector(5000, 0).Rotate(randAngle)
				spaceship.Position = spaceship.Position.Add(randMove)
			}
		}
	}
	// koniec kodu przeciwzakrzepowego

	s.PhysicsFrameID++
}

func updateProjectiles(space *state.Space) {
	for projectile := range space.Projectiles {
		projectile.TTL--
		if projectile.TTL > 0 {
			projectile.Position = projectile.Position.Add(projectile.Velocity)
		} else {
			space.RemoveProjectile(projectile)
		}
	}
}
<|endoftext|>