<commit_before>package ssh

import (
	"fmt"
	"net"
	"time"

	gossh "golang.org/x/crypto/ssh"
)

// Server defines parameters for running an SSH server. The zero value for
// Server is a valid configuration. When both PasswordHandler and
// PublicKeyHandler are nil, no client authentication is performed.
type Server struct {
	Addr        string   // TCP address to listen on, ":22" if empty
	Handler     Handler  // handler to invoke, ssh.DefaultHandler if nil
	HostSigners []Signer // private keys for the host key, must have at least one

	PasswordHandler     PasswordHandler     // password authentication handler
	PublicKeyHandler    PublicKeyHandler    // public key authentication handler
	PtyCallback         PtyCallback         // callback for allowing PTY sessions, allows all if nil
	PermissionsCallback PermissionsCallback // optional callback for setting up permissions
}

func (srv *Server) makeConfig() (*gossh.ServerConfig, error) {
	config := &gossh.ServerConfig{}
	if len(srv.HostSigners) == 0 {
		signer, err := generateSigner()
		if err != nil {
			return nil, err
		}
		srv.HostSigners = append(srv.HostSigners, signer)
	}
	for _, signer := range srv.HostSigners {
		config.AddHostKey(signer)
	}
	if srv.PasswordHandler == nil && srv.PublicKeyHandler == nil {
		config.NoClientAuth = true
	}
	if srv.PasswordHandler != nil {
		config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
			perms := &gossh.Permissions{}
			if ok := srv.PasswordHandler(conn.User(), string(password)); !ok {
				return perms, fmt.Errorf("permission denied")
			}
			if srv.PermissionsCallback != nil {
				srv.PermissionsCallback(conn.User(), &Permissions{perms})
			}
			return perms, nil
		}
	}
	if srv.PublicKeyHandler != nil {
		config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
			perms := &gossh.Permissions{}
			if ok := srv.PublicKeyHandler(conn.User(), key); !ok {
				return perms, fmt.Errorf("permission denied")
			}
			perms.Extensions = map[string]string{
				"_publickey": string(key.Marshal()),
			}
			if srv.PermissionsCallback != nil {
				srv.PermissionsCallback(conn.User(), &Permissions{perms})
			}
			return perms, nil
		}
	}
	return config, nil
}

// Handle sets the Handler for the server.
func (srv *Server) Handle(fn Handler) {
	srv.Handler = fn
}

// Serve accepts incoming connections on the Listener l, creating a new
// connection goroutine for each. The connection goroutines read requests and then
// calls srv.Handler to handle sessions.
//
// Serve always returns a non-nil error.
func (srv *Server) Serve(l net.Listener) error {
	defer l.Close()
	config, err := srv.makeConfig()
	if err != nil {
		return err
	}
	if srv.Handler == nil {
		srv.Handler = DefaultHandler
	}
	var tempDelay time.Duration
	for {
		conn, e := l.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				time.Sleep(tempDelay)
				continue
			}
			return e
		}
		go srv.handleConn(conn, config)
	}
}

func (srv *Server) handleConn(conn net.Conn, conf *gossh.ServerConfig) {
	defer conn.Close()
	sshConn, chans, reqs, err := gossh.NewServerConn(conn, conf)
	if err != nil {
		return
	}
	go gossh.DiscardRequests(reqs)
	for ch := range chans {
		if ch.ChannelType() != "session" {
			ch.Reject(gossh.UnknownChannelType, "unsupported channel type")
			continue
		}
		go srv.handleChannel(sshConn, ch)
	}
}

func (srv *Server) handleChannel(conn *gossh.ServerConn, newChan gossh.NewChannel) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		return
	}
	sess := srv.newSession(conn, ch)
	sess.handleRequests(reqs)
}

func (srv *Server) newSession(conn *gossh.ServerConn, ch gossh.Channel) *session {
	sess := &session{
		Channel: ch,
		conn:    conn,
		handler: srv.Handler,
		ptyCb:   srv.PtyCallback,
	}
	return sess
}

// ListenAndServe listens on the TCP network address srv.Addr and then calls
// Serve to handle incoming connections. If srv.Addr is blank, ":22" is used.
// ListenAndServe always returns a non-nil error.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":22"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(ln)
}

// AddHostKey adds a private key as a host key. If an existing host key exists
// with the same algorithm, it is overwritten. Each server config must have at
// least one host key.
func (srv *Server) AddHostKey(key Signer) {
	// these are later added via AddHostKey on ServerConfig, which performs the
	// check for one of every algorithm.
	srv.HostSigners = append(srv.HostSigners, key)
}

// SetOption runs a functional option against the server.
func (srv *Server) SetOption(option Option) error {
	return option(srv)
}
<commit_msg>Add ServerVersion as an option in the config<commit_after>package ssh

import (
	"fmt"
	"net"
	"time"

	gossh "golang.org/x/crypto/ssh"
)

// Server defines parameters for running an SSH server. The zero value for
// Server is a valid configuration. When both PasswordHandler and
// PublicKeyHandler are nil, no client authentication is performed.
type Server struct {
	Addr        string   // TCP address to listen on, ":22" if empty
	Handler     Handler  // handler to invoke, ssh.DefaultHandler if nil
	HostSigners []Signer // private keys for the host key, must have at least one
	Version     string   // server version to be sent before the initial handshake

	PasswordHandler     PasswordHandler     // password authentication handler
	PublicKeyHandler    PublicKeyHandler    // public key authentication handler
	PtyCallback         PtyCallback         // callback for allowing PTY sessions, allows all if nil
	PermissionsCallback PermissionsCallback // optional callback for setting up permissions
}

func (srv *Server) makeConfig() (*gossh.ServerConfig, error) {
	config := &gossh.ServerConfig{}
	if len(srv.HostSigners) == 0 {
		signer, err := generateSigner()
		if err != nil {
			return nil, err
		}
		srv.HostSigners = append(srv.HostSigners, signer)
	}
	for _, signer := range srv.HostSigners {
		config.AddHostKey(signer)
	}
	if srv.PasswordHandler == nil && srv.PublicKeyHandler == nil {
		config.NoClientAuth = true
	}
	if srv.Version != "" {
		config.ServerVersion = "SSH-2.0-" + srv.Version
	}
	if srv.PasswordHandler != nil {
		config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
			perms := &gossh.Permissions{}
			if ok := srv.PasswordHandler(conn.User(), string(password)); !ok {
				return perms, fmt.Errorf("permission denied")
			}
			if srv.PermissionsCallback != nil {
				srv.PermissionsCallback(conn.User(), &Permissions{perms})
			}
			return perms, nil
		}
	}
	if srv.PublicKeyHandler != nil {
		config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
			perms := &gossh.Permissions{}
			if ok := srv.PublicKeyHandler(conn.User(), key); !ok {
				return perms, fmt.Errorf("permission denied")
			}
			perms.Extensions = map[string]string{
				"_publickey": string(key.Marshal()),
			}
			if srv.PermissionsCallback != nil {
				srv.PermissionsCallback(conn.User(), &Permissions{perms})
			}
			return perms, nil
		}
	}
	return config, nil
}

// Handle sets the Handler for the server.
func (srv *Server) Handle(fn Handler) {
	srv.Handler = fn
}

// Serve accepts incoming connections on the Listener l, creating a new
// connection goroutine for each. The connection goroutines read requests and then
// calls srv.Handler to handle sessions.
//
// Serve always returns a non-nil error.
func (srv *Server) Serve(l net.Listener) error {
	defer l.Close()
	config, err := srv.makeConfig()
	if err != nil {
		return err
	}
	if srv.Handler == nil {
		srv.Handler = DefaultHandler
	}
	var tempDelay time.Duration
	for {
		conn, e := l.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				time.Sleep(tempDelay)
				continue
			}
			return e
		}
		go srv.handleConn(conn, config)
	}
}

func (srv *Server) handleConn(conn net.Conn, conf *gossh.ServerConfig) {
	defer conn.Close()
	sshConn, chans, reqs, err := gossh.NewServerConn(conn, conf)
	if err != nil {
		return
	}
	go gossh.DiscardRequests(reqs)
	for ch := range chans {
		if ch.ChannelType() != "session" {
			ch.Reject(gossh.UnknownChannelType, "unsupported channel type")
			continue
		}
		go srv.handleChannel(sshConn, ch)
	}
}

func (srv *Server) handleChannel(conn *gossh.ServerConn, newChan gossh.NewChannel) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		return
	}
	sess := srv.newSession(conn, ch)
	sess.handleRequests(reqs)
}

func (srv *Server) newSession(conn *gossh.ServerConn, ch gossh.Channel) *session {
	sess := &session{
		Channel: ch,
		conn:    conn,
		handler: srv.Handler,
		ptyCb:   srv.PtyCallback,
	}
	return sess
}

// ListenAndServe listens on the TCP network address srv.Addr and then calls
// Serve to handle incoming connections. If srv.Addr is blank, ":22" is used.
// ListenAndServe always returns a non-nil error.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":22"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(ln)
}

// AddHostKey adds a private key as a host key. If an existing host key exists
// with the same algorithm, it is overwritten. Each server config must have at
// least one host key.
func (srv *Server) AddHostKey(key Signer) {
	// these are later added via AddHostKey on ServerConfig, which performs the
	// check for one of every algorithm.
	srv.HostSigners = append(srv.HostSigners, key)
}

// SetOption runs a functional option against the server.
func (srv *Server) SetOption(option Option) error {
	return option(srv)
}
<|endoftext|>


<commit_before>package falcore

import (
	"bufio"
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
)

type Server struct {
	Addr               string
	Pipeline           *Pipeline
	CompletionCallback RequestCompletionCallback
	listener           net.Listener
	listenerFile       *os.File
	stopAccepting      chan int
	handlerWaitGroup   *sync.WaitGroup
	logPrefix          string
	AcceptReady        chan int
	sendfile           bool
	sockOpt            int
	bufferPool         *bufferPool
}

type RequestCompletionCallback func(req *Request, res *http.Response)

func NewServer(port int, pipeline *Pipeline) *Server {
	s := new(Server)
	s.Addr = fmt.Sprintf(":%v", port)
	s.Pipeline = pipeline
	s.stopAccepting = make(chan int)
	s.AcceptReady = make(chan int, 1)
	s.handlerWaitGroup = new(sync.WaitGroup)
	s.logPrefix = fmt.Sprintf("%d", syscall.Getpid())

	// openbsd/netbsd don't have TCP_NOPUSH so it's likely sendfile will be slower
	// without these socket options, just enable for linux, mac and freebsd.
	// TODO (Graham) windows has TransmitFile zero-copy mechanism, try to use it
	switch runtime.GOOS {
	case "linux":
		s.sendfile = true
		s.sockOpt = 0x3 // syscall.TCP_CORK
	case "freebsd", "darwin":
		s.sendfile = true
		s.sockOpt = 0x4 // syscall.TCP_NOPUSH
	default:
		s.sendfile = false
	}

	// buffer pool for reusing connection bufio.Readers
	s.bufferPool = newBufferPool(100, 8192)

	return s
}

func (srv *Server) FdListen(fd int) error {
	var err error
	srv.listenerFile = os.NewFile(uintptr(fd), "")
	if srv.listener, err = net.FileListener(srv.listenerFile); err != nil {
		return err
	}
	if _, ok := srv.listener.(*net.TCPListener); !ok {
		return errors.New("Broken listener isn't TCP")
	}
	return nil
}

func (srv *Server) socketListen() error {
	var la *net.TCPAddr
	var err error
	if la, err = net.ResolveTCPAddr("tcp", srv.Addr); err != nil {
		return err
	}

	var l *net.TCPListener
	if l, err = net.ListenTCP("tcp", la); err != nil {
		return err
	}
	srv.listener = l
	// setup listener to be non-blocking if we're not on windows.
	// this is required for hot restart to work.
	return srv.setupNonBlockingListener(err, l)
}

func (srv *Server) ListenAndServe() error {
	if srv.Addr == "" {
		srv.Addr = ":http"
	}
	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}
	return srv.serve()
}

func (srv *Server) SocketFd() int {
	return int(srv.listenerFile.Fd())
}

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
	if srv.Addr == "" {
		srv.Addr = ":https"
	}
	config := &tls.Config{
		Rand:       rand.Reader,
		Time:       time.Now,
		NextProtos: []string{"http/1.1"},
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}

	srv.listener = tls.NewListener(srv.listener, config)

	return srv.serve()
}

func (srv *Server) StopAccepting() {
	close(srv.stopAccepting)
}

func (srv *Server) Port() int {
	if l := srv.listener; l != nil {
		a := l.Addr()
		if _, p, e := net.SplitHostPort(a.String()); e == nil && p != "" {
			server_port, _ := strconv.Atoi(p)
			return server_port
		}
	}
	return 0
}

func (srv *Server) serve() (e error) {
	var accept = true
	srv.AcceptReady <- 1
	for accept {
		var c net.Conn
		if l, ok := srv.listener.(*net.TCPListener); ok {
			l.SetDeadline(time.Now().Add(3e9))
		}
		c, e = srv.listener.Accept()
		if e != nil {
			if ope, ok := e.(*net.OpError); ok {
				if !(ope.Timeout() && ope.Temporary()) {
					Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), ope)
				}
			} else {
				Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), e)
			}
		} else {
			//Trace("Handling!")
			srv.handlerWaitGroup.Add(1)
			go srv.handler(c)
		}
		select {
		case <-srv.stopAccepting:
			accept = false
		default:
		}
	}
	Trace("Stopped accepting, waiting for handlers")
	// wait for handlers
	srv.handlerWaitGroup.Wait()
	return nil
}

func (srv *Server) sentinel(c net.Conn, connClosed chan int) {
	select {
	case <-srv.stopAccepting:
		c.SetReadDeadline(time.Now().Add(3 * time.Second))
	case <-connClosed:
	}
}

func (srv *Server) handler(c net.Conn) {
	startTime := time.Now()
	bpe := srv.bufferPool.take(c)
	defer srv.bufferPool.give(bpe)
	var closeSentinelChan = make(chan int)
	go srv.sentinel(c, closeSentinelChan)
	defer srv.connectionFinished(c, closeSentinelChan)
	var err error
	var req *http.Request
	// no keepalive (for now)
	reqCount := 0
	keepAlive := true
	for err == nil && keepAlive {
		if req, err = http.ReadRequest(bpe.br); err == nil {
			if req.Header.Get("Connection") != "Keep-Alive" {
				keepAlive = false
			}
			request := newRequest(req, c, startTime)
			reqCount++
			var res *http.Response

			pssInit := new(PipelineStageStat)
			pssInit.Name = "server.Init"
			pssInit.StartTime = startTime
			pssInit.EndTime = time.Now()
			request.appendPipelineStage(pssInit)
			// execute the pipeline
			if res = srv.Pipeline.execute(request); res == nil {
				res = StringResponse(req, 404, nil, "Not Found")
			}
			// cleanup
			request.startPipelineStage("server.ResponseWrite")
			req.Body.Close()

			// shutting down?
			select {
			case <-srv.stopAccepting:
				keepAlive = false
				res.Close = true
			default:
			}
			// The res.Write omits Content-length on 0 length bodies, and by spec,
			// it SHOULD. While this is not MUST, it's kinda broken.  See sec 4.4
			// of rfc2616 and a 200 with a zero length does not satisfy any of the
			// 5 conditions if Connection: keep-alive is set :(
			// I'm forcing chunked which seems to work because I couldn't get the
			// content length to write if it was 0.
			// Specifically, the android http client waits forever if there's no
			// content-length instead of assuming zero at the end of headers. der.
			if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) {
				res.TransferEncoding = []string{"identity"}
			}
			if res.ContentLength < 0 {
				res.TransferEncoding = []string{"chunked"}
			}

			// write response
			if srv.sendfile {
				res.Write(c)
				srv.cycleNonBlock(c)
			} else {
				wbuf := bufio.NewWriter(c)
				res.Write(wbuf)
				wbuf.Flush()
			}
			if res.Body != nil {
				res.Body.Close()
			}
			request.finishPipelineStage()
			request.finishRequest()
			srv.requestFinished(request, res)

			if res.Close {
				keepAlive = false
			}

			// Reset the startTime
			// this isn't great since there may be lag between requests; but it's the best we've got
			startTime = time.Now()
		} else {
			// EOF is socket closed
			if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) {
				Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err)
			}
		}
	}
	//Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr())
}

func (srv *Server) serverLogPrefix() string {
	return srv.logPrefix
}

func (srv *Server) requestFinished(request *Request, res *http.Response) {
	if srv.CompletionCallback != nil {
		// Don't block the connecion for this
		go srv.CompletionCallback(request, res)
	}
}

func (srv *Server) connectionFinished(c net.Conn, closeChan chan int) {
	c.Close()
	close(closeChan)
	srv.handlerWaitGroup.Done()
}
<commit_msg>wait for bytes to arrive to start the request timer<commit_after>package falcore

import (
	"bufio"
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
)

type Server struct {
	Addr               string
	Pipeline           *Pipeline
	CompletionCallback RequestCompletionCallback
	listener           net.Listener
	listenerFile       *os.File
	stopAccepting      chan int
	handlerWaitGroup   *sync.WaitGroup
	logPrefix          string
	AcceptReady        chan int
	sendfile           bool
	sockOpt            int
	bufferPool         *bufferPool
}

type RequestCompletionCallback func(req *Request, res *http.Response)

func NewServer(port int, pipeline *Pipeline) *Server {
	s := new(Server)
	s.Addr = fmt.Sprintf(":%v", port)
	s.Pipeline = pipeline
	s.stopAccepting = make(chan int)
	s.AcceptReady = make(chan int, 1)
	s.handlerWaitGroup = new(sync.WaitGroup)
	s.logPrefix = fmt.Sprintf("%d", syscall.Getpid())

	// openbsd/netbsd don't have TCP_NOPUSH so it's likely sendfile will be slower
	// without these socket options, just enable for linux, mac and freebsd.
	// TODO (Graham) windows has TransmitFile zero-copy mechanism, try to use it
	switch runtime.GOOS {
	case "linux":
		s.sendfile = true
		s.sockOpt = 0x3 // syscall.TCP_CORK
	case "freebsd", "darwin":
		s.sendfile = true
		s.sockOpt = 0x4 // syscall.TCP_NOPUSH
	default:
		s.sendfile = false
	}

	// buffer pool for reusing connection bufio.Readers
	s.bufferPool = newBufferPool(100, 8192)

	return s
}

func (srv *Server) FdListen(fd int) error {
	var err error
	srv.listenerFile = os.NewFile(uintptr(fd), "")
	if srv.listener, err = net.FileListener(srv.listenerFile); err != nil {
		return err
	}
	if _, ok := srv.listener.(*net.TCPListener); !ok {
		return errors.New("Broken listener isn't TCP")
	}
	return nil
}

func (srv *Server) socketListen() error {
	var la *net.TCPAddr
	var err error
	if la, err = net.ResolveTCPAddr("tcp", srv.Addr); err != nil {
		return err
	}

	var l *net.TCPListener
	if l, err = net.ListenTCP("tcp", la); err != nil {
		return err
	}
	srv.listener = l
	// setup listener to be non-blocking if we're not on windows.
	// this is required for hot restart to work.
	return srv.setupNonBlockingListener(err, l)
}

func (srv *Server) ListenAndServe() error {
	if srv.Addr == "" {
		srv.Addr = ":http"
	}
	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}
	return srv.serve()
}

func (srv *Server) SocketFd() int {
	return int(srv.listenerFile.Fd())
}

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
	if srv.Addr == "" {
		srv.Addr = ":https"
	}
	config := &tls.Config{
		Rand:       rand.Reader,
		Time:       time.Now,
		NextProtos: []string{"http/1.1"},
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}

	srv.listener = tls.NewListener(srv.listener, config)

	return srv.serve()
}

func (srv *Server) StopAccepting() {
	close(srv.stopAccepting)
}

func (srv *Server) Port() int {
	if l := srv.listener; l != nil {
		a := l.Addr()
		if _, p, e := net.SplitHostPort(a.String()); e == nil && p != "" {
			server_port, _ := strconv.Atoi(p)
			return server_port
		}
	}
	return 0
}

func (srv *Server) serve() (e error) {
	var accept = true
	srv.AcceptReady <- 1
	for accept {
		var c net.Conn
		if l, ok := srv.listener.(*net.TCPListener); ok {
			l.SetDeadline(time.Now().Add(3e9))
		}
		c, e = srv.listener.Accept()
		if e != nil {
			if ope, ok := e.(*net.OpError); ok {
				if !(ope.Timeout() && ope.Temporary()) {
					Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), ope)
				}
			} else {
				Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), e)
			}
		} else {
			//Trace("Handling!")
			srv.handlerWaitGroup.Add(1)
			go srv.handler(c)
		}
		select {
		case <-srv.stopAccepting:
			accept = false
		default:
		}
	}
	Trace("Stopped accepting, waiting for handlers")
	// wait for handlers
	srv.handlerWaitGroup.Wait()
	return nil
}

func (srv *Server) sentinel(c net.Conn, connClosed chan int) {
	select {
	case <-srv.stopAccepting:
		c.SetReadDeadline(time.Now().Add(3 * time.Second))
	case <-connClosed:
	}
}

func (srv *Server) handler(c net.Conn) {
	var startTime time.Time
	bpe := srv.bufferPool.take(c)
	defer srv.bufferPool.give(bpe)
	var closeSentinelChan = make(chan int)
	go srv.sentinel(c, closeSentinelChan)
	defer srv.connectionFinished(c, closeSentinelChan)
	var err error
	var req *http.Request
	// no keepalive (for now)
	reqCount := 0
	keepAlive := true
	for err == nil && keepAlive {
		if _, err := bpe.br.Peek(1); err == nil {
			startTime = time.Now()
		}
		if req, err = http.ReadRequest(bpe.br); err == nil {
			if req.Header.Get("Connection") != "Keep-Alive" {
				keepAlive = false
			}
			request := newRequest(req, c, startTime)
			reqCount++
			var res *http.Response

			pssInit := new(PipelineStageStat)
			pssInit.Name = "server.Init"
			pssInit.StartTime = startTime
			pssInit.EndTime = time.Now()
			request.appendPipelineStage(pssInit)
			// execute the pipeline
			if res = srv.Pipeline.execute(request); res == nil {
				res = StringResponse(req, 404, nil, "Not Found")
			}
			// cleanup
			request.startPipelineStage("server.ResponseWrite")
			req.Body.Close()

			// shutting down?
			select {
			case <-srv.stopAccepting:
				keepAlive = false
				res.Close = true
			default:
			}
			// The res.Write omits Content-length on 0 length bodies, and by spec,
			// it SHOULD. While this is not MUST, it's kinda broken.  See sec 4.4
			// of rfc2616 and a 200 with a zero length does not satisfy any of the
			// 5 conditions if Connection: keep-alive is set :(
			// I'm forcing chunked which seems to work because I couldn't get the
			// content length to write if it was 0.
			// Specifically, the android http client waits forever if there's no
			// content-length instead of assuming zero at the end of headers. der.
			if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) {
				res.TransferEncoding = []string{"identity"}
			}
			if res.ContentLength < 0 {
				res.TransferEncoding = []string{"chunked"}
			}

			// write response
			if srv.sendfile {
				res.Write(c)
				srv.cycleNonBlock(c)
			} else {
				wbuf := bufio.NewWriter(c)
				res.Write(wbuf)
				wbuf.Flush()
			}
			if res.Body != nil {
				res.Body.Close()
			}
			request.finishPipelineStage()
			request.finishRequest()
			srv.requestFinished(request, res)

			if res.Close {
				keepAlive = false
			}

			// Reset the startTime
			// this isn't great since there may be lag between requests; but it's the best we've got
			startTime = time.Now()
		} else {
			// EOF is socket closed
			if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) {
				Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err)
			}
		}
	}
	//Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr())
}

func (srv *Server) serverLogPrefix() string {
	return srv.logPrefix
}

func (srv *Server) requestFinished(request *Request, res *http.Response) {
	if srv.CompletionCallback != nil {
		// Don't block the connecion for this
		go srv.CompletionCallback(request, res)
	}
}

func (srv *Server) connectionFinished(c net.Conn, closeChan chan int) {
	c.Close()
	close(closeChan)
	srv.handlerWaitGroup.Done()
}
<|endoftext|>


<commit_before>package main

import (
	//"log"
	"encoding/json"
	"github.com/codegangsta/negroni"
	"github.com/sdboyer/mock_druplatform_api/acquia"
	"net/http"
	"net"
	"time"
)

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
//
// (Copied from net/http, b/c they did not deign to export)
type tcpKeepAliveListener struct {
    *net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
    tc, err := ln.AcceptTCP()
    if err != nil {
        return
    }
    tc.SetKeepAlive(true)
    tc.SetKeepAlivePeriod(3 * time.Minute)
    return tc, nil
}

type ServerInstance struct {
	Listener tcpKeepAliveListener
	HttpServer *http.Server
	MockApp
}

type MockApp interface {
	Version() string
}

var servers = make([]ServerInstance, 0)

type createServerRequest struct {
	ServerType string `json:"server_type"`
	Version string `json:"version"`
}

type createServerResponse struct {
	Port int `json:"port"`
	ServerType string `json:"server_type"`
	Version string `json:"version"`
}

func hhCreateAcquiaServer(w http.ResponseWriter, r *http.Request) {
	j := &createServerRequest{}

	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(j); err != nil {
		panic(err)
	}

	an := negroni.New()
	app := acquia.NewServerInstance("default")
	an.UseHandler(acquia.NewRouter(app))

	laddr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:0") // listen to all the things
	if err != nil {
		panic(err)
	}

	l, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		panic(err)
	}
	kal := tcpKeepAliveListener{l}

	// The Addr prop shouldn't actually be used, but set it to avoid triggering defaults
	srv := &http.Server{Addr: laddr.String(), Handler: an}

	si := ServerInstance{Listener: kal, HttpServer: srv, MockApp: app}
	resp, err := json.Marshal(createServerResponse{
		Port: kal.Addr().(*net.TCPAddr).Port,
		ServerType: "acquia",
		Version: si.Version(),
	})

	if err != nil {
		panic(err)
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(resp) // auto-sends 200 response
	servers = append(servers, si)
	go srv.Serve(kal)
}

func hhListAcquiaServers(w http.ResponseWriter, r *http.Request) {

}

func hhListServerTypes(w http.ResponseWriter, r *http.Request) {

}
<commit_msg>Correctly return 201 with location header on server create<commit_after>package main

import (
	//"log"
	"encoding/json"
	"github.com/codegangsta/negroni"
	"github.com/sdboyer/mock_druplatform_api/acquia"
	"net/http"
	"net"
	"time"
	"strconv"
)

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
//
// (Copied from net/http, b/c they did not deign to export)
type tcpKeepAliveListener struct {
    *net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
    tc, err := ln.AcceptTCP()
    if err != nil {
        return
    }
    tc.SetKeepAlive(true)
    tc.SetKeepAlivePeriod(3 * time.Minute)
    return tc, nil
}

type ServerInstance struct {
	Listener tcpKeepAliveListener
	HttpServer *http.Server
	MockApp
}

type MockApp interface {
	Version() string
}

var servers = make([]ServerInstance, 0)

type createServerRequest struct {
	ServerType string `json:"server_type"`
	Version string `json:"version"`
}

type createServerResponse struct {
	Port int `json:"port"`
	ServerType string `json:"server_type"`
	Version string `json:"version"`
}

func hhCreateAcquiaServer(w http.ResponseWriter, r *http.Request) {
	j := &createServerRequest{}

	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(j); err != nil {
		panic(err)
	}

	an := negroni.New()
	app := acquia.NewServerInstance("default")
	an.UseHandler(acquia.NewRouter(app))

	laddr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:0") // listen to all the things
	if err != nil {
		panic(err)
	}

	l, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		panic(err)
	}
	kal := tcpKeepAliveListener{l}

	// The Addr prop shouldn't actually be used, but set it to avoid triggering defaults
	srv := &http.Server{Addr: laddr.String(), Handler: an}

	si := ServerInstance{Listener: kal, HttpServer: srv, MockApp: app}
	resp, err := json.Marshal(createServerResponse{
		Port: kal.Addr().(*net.TCPAddr).Port,
		ServerType: "acquia",
		Version: si.Version(),
	})

	if err != nil {
		panic(err)
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Location", "acquia/" + strconv.Itoa(kal.Addr().(*net.TCPAddr).Port))
	w.WriteHeader(201)
	w.Write(resp)
	servers = append(servers, si)
	go srv.Serve(kal)
}

func hhListAcquiaServers(w http.ResponseWriter, r *http.Request) {

}

func hhListServerTypes(w http.ResponseWriter, r *http.Request) {

}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All rights reserved.
//
// 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 fmtserver

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type Server struct {
	JavaJar       string
	Buildifier    string
	Gofmt         string
	languageRegex map[string]*regexp.Regexp
	formatterMap  map[string]formatterFunc
}

type formatterFunc func(in []File, out io.Writer) ([]FormattedFile, error)

func NewServer() *Server {
	type formatter struct {
		lang  string
		regex *regexp.Regexp
		fun   formatterFunc
	}

	s := &Server{
		languageRegex: map[string]*regexp.Regexp{},
		formatterMap:  map[string]formatterFunc{},
	}

	formatters := []formatter{
		{"java", regexp.MustCompile(`\.java$`), s.javaFormat},
		{"bazel", regexp.MustCompile(`(\.bzl|/BUILD|^BUILD)$`), s.bazelFormat},
		{"go", regexp.MustCompile(`\.go$`), s.goFormat},
		{"commit-msg", regexp.MustCompile(`^/COMMIT_MSG$`), s.commitCheck},
	}

	for _, l := range formatters {
		s.languageRegex[l.lang] = l.regex
	}
	for _, l := range formatters {
		s.formatterMap[l.lang] = l.fun
	}
	return s
}

func (s *Server) splitByLang(in []File) map[string][]File {
	res := map[string][]File{}
	for _, f := range in {
		for lang, regex := range s.languageRegex {
			if regex.MatchString(f.Name) {
				res[lang] = append(res[lang], f)
				break
			}
		}
	}
	return res
}

func (s *Server) Format(req *FormatRequest, rep *FormatReply) error {
	for lang, files := range s.splitByLang(req.Files) {
		var buf bytes.Buffer
		out, err := s.formatterMap[lang](files, &buf)
		if err != nil {
			return err
		}

		if len(out) > 0 && out[0].Message == "" {
			out[0].Message = buf.String()
		}
		rep.Files = append(rep.Files, out...)
	}
	return nil
}

func (s *Server) commitCheck(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	complaint := s.checkCommitMessage(string(in[0].Content))
	ff := FormattedFile{}
	ff.Name = in[0].Name
	if complaint != "" {
		ff.Message = complaint
	} else {
		ff.Content = in[0].Content
	}
	out = append(out, ff)
	return out, nil
}

func (s *Server) checkCommitMessage(msg string) (complaint string) {
	lines := strings.Split(msg, "\n")
	if len(lines) < 2 {
		return "must have multiple lines"
	}

	if len(lines[1]) > 1 {
		return "subject and body must be separated by blank line"
	}

	if len(lines[0]) > 70 {
		return "subject must be less than 70 chars"
	}

	if strings.HasSuffix(lines[0], ".") {
		return "subject must not end in '.'"
	}

	return ""
}

func (s *Server) javaFormat(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	if _, err := os.Stat(s.JavaJar); err != nil {
		return nil, fmt.Errorf("Stat(%q): %v", s.JavaJar, err)
	}
	cmd := exec.Command(
		"java",
		"-jar",
		s.JavaJar,
		"-i",
	)
	return s.inlineFixTool(cmd, in, outSink)
}

func (s *Server) bazelFormat(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	if _, err := os.Stat(s.Buildifier); err != nil {
		return nil, fmt.Errorf("Stat(%q): %v", s.Buildifier, err)
	}
	cmd := exec.Command(
		s.Buildifier,
		"-mode=fix",
	)
	return s.inlineFixTool(cmd, in, outSink)
}

func (s *Server) goFormat(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	if _, err := os.Stat(s.Buildifier); err != nil {
		return nil, fmt.Errorf("Stat(%q): %v", s.Buildifier, err)
	}
	cmd := exec.Command(
		s.Gofmt,
		"-mode=fix",
	)
	return s.inlineFixTool(cmd, in, outSink)
}

func (s *Server) inlineFixTool(cmd *exec.Cmd, in []File, outSink io.Writer) (out []FormattedFile, err error) {
	tmpDir, err := ioutil.TempDir("", "fmtserver")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tmpDir)

	for _, f := range in {
		dir, base := filepath.Split(f.Name)
		dir = filepath.Join(tmpDir, dir)
		if err := os.MkdirAll(dir, 0755); err != nil {
			return nil, err
		}

		if err := ioutil.WriteFile(filepath.Join(dir, base), f.Content, 0644); err != nil {
			return nil, err
		}

		cmd.Args = append(cmd.Args, f.Name)
	}
	cmd.Dir = tmpDir
	cmd.Stdout = outSink
	cmd.Stderr = outSink
	log.Println("running", cmd.Args, "in", tmpDir)
	if err := cmd.Run(); err != nil {
		return nil, err
	}

	for _, f := range in {
		c, err := ioutil.ReadFile(filepath.Join(tmpDir, f.Name))
		if err != nil {
			return nil, err
		}

		out = append(out, FormattedFile{
			File: File{
				Name:    f.Name,
				Content: c,
			},
		})
	}

	return out, nil
}
<commit_msg>Dump stderr/stdout for failures.<commit_after>// Copyright 2019 Google Inc. All rights reserved.
//
// 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 fmtserver

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type Server struct {
	JavaJar       string
	Buildifier    string
	Gofmt         string
	languageRegex map[string]*regexp.Regexp
	formatterMap  map[string]formatterFunc
}

type formatterFunc func(in []File, out io.Writer) ([]FormattedFile, error)

func NewServer() *Server {
	type formatter struct {
		lang  string
		regex *regexp.Regexp
		fun   formatterFunc
	}

	s := &Server{
		languageRegex: map[string]*regexp.Regexp{},
		formatterMap:  map[string]formatterFunc{},
	}

	formatters := []formatter{
		{"java", regexp.MustCompile(`\.java$`), s.javaFormat},
		{"bazel", regexp.MustCompile(`(\.bzl|/BUILD|^BUILD)$`), s.bazelFormat},
		{"go", regexp.MustCompile(`\.go$`), s.goFormat},
		{"commit-msg", regexp.MustCompile(`^/COMMIT_MSG$`), s.commitCheck},
	}

	for _, l := range formatters {
		s.languageRegex[l.lang] = l.regex
	}
	for _, l := range formatters {
		s.formatterMap[l.lang] = l.fun
	}
	return s
}

func (s *Server) splitByLang(in []File) map[string][]File {
	res := map[string][]File{}
	for _, f := range in {
		for lang, regex := range s.languageRegex {
			if regex.MatchString(f.Name) {
				res[lang] = append(res[lang], f)
				break
			}
		}
	}
	return res
}

func (s *Server) Format(req *FormatRequest, rep *FormatReply) error {
	for lang, files := range s.splitByLang(req.Files) {
		var buf bytes.Buffer
		out, err := s.formatterMap[lang](files, &buf)
		if err != nil {
			return err
		}

		if len(out) > 0 && out[0].Message == "" {
			out[0].Message = buf.String()
		}
		rep.Files = append(rep.Files, out...)
	}
	return nil
}

func (s *Server) commitCheck(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	complaint := s.checkCommitMessage(string(in[0].Content))
	ff := FormattedFile{}
	ff.Name = in[0].Name
	if complaint != "" {
		ff.Message = complaint
	} else {
		ff.Content = in[0].Content
	}
	out = append(out, ff)
	return out, nil
}

func (s *Server) checkCommitMessage(msg string) (complaint string) {
	lines := strings.Split(msg, "\n")
	if len(lines) < 2 {
		return "must have multiple lines"
	}

	if len(lines[1]) > 1 {
		return "subject and body must be separated by blank line"
	}

	if len(lines[0]) > 70 {
		return "subject must be less than 70 chars"
	}

	if strings.HasSuffix(lines[0], ".") {
		return "subject must not end in '.'"
	}

	return ""
}

func (s *Server) javaFormat(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	if _, err := os.Stat(s.JavaJar); err != nil {
		return nil, fmt.Errorf("Stat(%q): %v", s.JavaJar, err)
	}
	cmd := exec.Command(
		"java",
		"-jar",
		s.JavaJar,
		"-i",
	)
	return s.inlineFixTool(cmd, in, outSink)
}

func (s *Server) bazelFormat(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	if _, err := os.Stat(s.Buildifier); err != nil {
		return nil, fmt.Errorf("Stat(%q): %v", s.Buildifier, err)
	}
	cmd := exec.Command(
		s.Buildifier,
		"-mode=fix",
	)
	return s.inlineFixTool(cmd, in, outSink)
}

func (s *Server) goFormat(in []File, outSink io.Writer) (out []FormattedFile, err error) {
	if _, err := os.Stat(s.Buildifier); err != nil {
		return nil, fmt.Errorf("Stat(%q): %v", s.Buildifier, err)
	}
	cmd := exec.Command(
		s.Gofmt,
		"-mode=fix",
	)
	return s.inlineFixTool(cmd, in, outSink)
}

func (s *Server) inlineFixTool(cmd *exec.Cmd, in []File, outSink io.Writer) (out []FormattedFile, err error) {
	tmpDir, err := ioutil.TempDir("", "fmtserver")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tmpDir)

	for _, f := range in {
		dir, base := filepath.Split(f.Name)
		dir = filepath.Join(tmpDir, dir)
		if err := os.MkdirAll(dir, 0755); err != nil {
			return nil, err
		}

		if err := ioutil.WriteFile(filepath.Join(dir, base), f.Content, 0644); err != nil {
			return nil, err
		}

		cmd.Args = append(cmd.Args, f.Name)
	}
	cmd.Dir = tmpDir

	var errBuf, outBuf bytes.Buffer
	cmd.Stdout = &outBuf
	cmd.Stderr = &errBuf
	log.Println("running", cmd.Args, "in", tmpDir)
	if err := cmd.Run(); err != nil {
		log.Println("error %v, stderr %s, stdout %s", err, errBuf.String(),
			outBuf.String())
		return nil, err
	}

	for _, f := range in {
		c, err := ioutil.ReadFile(filepath.Join(tmpDir, f.Name))
		if err != nil {
			return nil, err
		}

		out = append(out, FormattedFile{
			File: File{
				Name:    f.Name,
				Content: c,
			},
		})
	}

	return out, nil
}
<|endoftext|>


<commit_before>package dht

// Deprecated: No longer used
// Pool size is the number of nodes used for group find/set RPC calls
var PoolSize = 6

// Deprecated: This value is still the default, but changing this parameter no longer does anything.
// K is the maximum number of requests to perform before returning failure.
var KValue = 20

// Deprecated: This value is still the default, but changing this parameter no longer does anything.
// Alpha is the concurrency factor for asynchronous requests.
var AlphaValue = 3
<commit_msg>made deprecated util values have comments that satisfy golint<commit_after>package dht

// PoolSize is the number of nodes used for group find/set RPC calls
// Deprecated: No longer used
var PoolSize = 6

// KValue is the maximum number of requests to perform before returning failure.
// Deprecated: This value is still the default, but changing this parameter no longer does anything.
var KValue = 20

// AlphaValue is the concurrency factor for asynchronous requests.
// Deprecated: This value is still the default, but changing this parameter no longer does anything.
var AlphaValue = 3
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "net/http"
    "log"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Hello, Huskydocs ^_^\n")
}

func Projects(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func Project(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func CreateProject(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func DeleteProject(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func Documents(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func Document(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func CreateDocument(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func UpdateDocument(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func DeleteDocument(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)

    router.GET("/project/:subject", Projects)
    router.GET("/project/:subject/:project", Project)
    router.PUT("/project/:subject/:project", CreateProject)
    router.DELETE("/project/:subject/:project", DeleteProject)

    router.GET("/document/:subject/:project", Documents)
    router.GET("/document/:subject/:project/*document", Document)
    router.PUT("/document/:subject/:project/*document", CreateDocument)
    router.POST("/document/:subject/:project/*document", UpdateDocument)
    router.DELETE("/document/:subject/:project/*document", DeleteDocument)

    log.Fatal(http.ListenAndServe(":8080", router))
}
<commit_msg>Adding basic server functionality<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/huskydocs/engine/persistence"
	"github.com/julienschmidt/httprouter"
	"log"
	"net/http"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprint(w, "Hello, Huskydocs ^_^\n")
}

func (ph *PersistenceHandler) CreateSubject(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Printf("Received request to create subject: %s \n", p.ByName("subject"))
	decoder := json.NewDecoder(r.Body)

	var s Subject
	err := decoder.Decode(&s)

	if err != nil {
		fmt.Printf("Error decoding JSON payload: %v", err)
		fmt.Fprint(w, "Error decoding JSON payload")
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	fmt.Printf("Decoded requst body with email: %s \n", s.email)
	subject := &persistence.Subject{Username: p.ByName("subject"), Email: s.email}
	err = ph.PS.CreateSubject(subject)
	if err != nil {
		fmt.Printf("Error persisting new subject: %v", err)
		fmt.Fprint(w, "Error persisting new subject")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprint(w, "Successfully created subject")
	w.WriteHeader(http.StatusCreated)
}

func (ph *PersistenceHandler) Projects(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
}

func (ph *PersistenceHandler) Project(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) CreateProject(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) DeleteProject(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) Documents(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) Document(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) CreateDocument(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) UpdateDocument(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

func (ph *PersistenceHandler) DeleteDocument(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}

type Subject struct {
	email string
}

type PersistenceHandler struct {
	PS *persistence.PersistenceSession
}

func main() {

	persistenceSession := persistence.Init()
	persistenceHandler := &PersistenceHandler{PS: persistenceSession}

	router := httprouter.New()
	router.GET("/", Index)
	router.PUT("/subject/:subject", persistenceHandler.CreateSubject)

	router.GET("/project/:subject", persistenceHandler.Projects)
	router.GET("/project/:subject/:project", persistenceHandler.Project)
	router.PUT("/project/:subject/:project", persistenceHandler.CreateProject)
	router.DELETE("/project/:subject/:project", persistenceHandler.DeleteProject)

	router.GET("/document/:subject/:project", persistenceHandler.Documents)
	router.GET("/document/:subject/:project/*document", persistenceHandler.Document)
	router.PUT("/document/:subject/:project/*document", persistenceHandler.CreateDocument)
	router.POST("/document/:subject/:project/*document", persistenceHandler.UpdateDocument)
	router.DELETE("/document/:subject/:project/*document", persistenceHandler.DeleteDocument)

	log.Fatal(http.ListenAndServe(":8080", router))
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/signal"
	"syscall"

	"github.com/bitly/go-nsq"
	"github.com/dancannon/gorethink"
)

type QueueOpts struct {
	LookupdAddr string
	Topic       string
	Channel     string
	Concurrent  int
	Signals     []os.Signal
}

func QueueOptsFromContext(topic, channel string) QueueOpts {
	return QueueOpts{
		Signals:     []os.Signal{syscall.SIGTERM, syscall.SIGINT},
		LookupdAddr: config.Lookupd,
		Topic:       topic,
		Channel:     channel,
		Concurrent:  1,
	}
}

func ProcessQueue(handler nsq.Handler, opts QueueOpts) error {
	if opts.Concurrent == 0 {
		opts.Concurrent = 1
	}
	s := make(chan os.Signal, 64)
	signal.Notify(s, opts.Signals...)

	consumer, err := nsq.NewConsumer(opts.Topic, opts.Channel, nsq.NewConfig())
	if err != nil {
		return err
	}
	consumer.AddConcurrentHandlers(handler, opts.Concurrent)
	if err := consumer.ConnectToNSQLookupd(opts.LookupdAddr); err != nil {
		return err
	}

	for {
		select {
		case <-consumer.StopChan:
			return nil
		case sig := <-s:
			logger.WithField("signal", sig).Debug("received signal")
			consumer.Stop()
		}
	}
	return nil
}

func NewRethinkdbSession() (*gorethink.Session, error) {
	return gorethink.Connect(gorethink.ConnectOpts{
		Database: config.RethinkdbDatabase,
		AuthKey:  config.RethinkdbKey,
		Address:  config.RethinkdbAddress,
	})
}
<commit_msg>Use connection pool for rethindkb<commit_after>package main

import (
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/bitly/go-nsq"
	"github.com/dancannon/gorethink"
)

type QueueOpts struct {
	LookupdAddr string
	Topic       string
	Channel     string
	Concurrent  int
	Signals     []os.Signal
}

func QueueOptsFromContext(topic, channel string) QueueOpts {
	return QueueOpts{
		Signals:     []os.Signal{syscall.SIGTERM, syscall.SIGINT},
		LookupdAddr: config.Lookupd,
		Topic:       topic,
		Channel:     channel,
		Concurrent:  1,
	}
}

func ProcessQueue(handler nsq.Handler, opts QueueOpts) error {
	if opts.Concurrent == 0 {
		opts.Concurrent = 1
	}
	s := make(chan os.Signal, 64)
	signal.Notify(s, opts.Signals...)

	consumer, err := nsq.NewConsumer(opts.Topic, opts.Channel, nsq.NewConfig())
	if err != nil {
		return err
	}
	consumer.AddConcurrentHandlers(handler, opts.Concurrent)
	if err := consumer.ConnectToNSQLookupd(opts.LookupdAddr); err != nil {
		return err
	}

	for {
		select {
		case <-consumer.StopChan:
			return nil
		case sig := <-s:
			logger.WithField("signal", sig).Debug("received signal")
			consumer.Stop()
		}
	}
	return nil
}

func NewRethinkdbSession() (*gorethink.Session, error) {
	return gorethink.Connect(gorethink.ConnectOpts{
		Database:    config.RethinkdbDatabase,
		AuthKey:     config.RethinkdbKey,
		Address:     config.RethinkdbAddress,
		MaxIdle:     10,
		IdleTimeout: 20 * time.Second,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"fmt"
	"net"
	"regexp"
	"strings"
	"sync"
	"time"

	"code.google.com/p/rog-go/new9p/client"

	"golang.org/x/crypto/ssh"
)

const MAX_NAME_LENGTH = 32
const HISTORY_LEN = 20

var RE_STRIP_NAME = regexp.MustCompile("[^0-9A-Za-z_]")

type Clients map[string]*Client

type Server struct {
	sshConfig *ssh.ServerConfig
	done      chan struct{}
	clients   Clients
	lock      sync.Mutex
	count     int
	history   *History
	admins    map[string]struct{}   // fingerprint lookup
	banned    map[string]*time.Time // fingerprint lookup
}

func NewServer(privateKey []byte) (*Server, error) {
	signer, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}

	server := Server{
		done:    make(chan struct{}),
		clients: Clients{},
		count:   0,
		history: NewHistory(HISTORY_LEN),
		admins:  map[string]struct{}{},
		banned:  map[string]*time.Time{},
	}

	config := ssh.ServerConfig{
		NoClientAuth: false,
		// Auth-related things should be constant-time to avoid timing attacks.
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			fingerprint := Fingerprint(key)
			if server.IsBanned(fingerprint) {
				return nil, fmt.Errorf("Banned.")
			}
			perm := &ssh.Permissions{Extensions: map[string]string{"fingerprint": fingerprint}}
			return perm, nil
		},
	}
	config.AddHostKey(signer)

	server.sshConfig = &config

	return &server, nil
}

func (s *Server) Len() int {
	return len(s.clients)
}

func (s *Server) Broadcast(msg string, except *Client) {
	logger.Debugf("Broadcast to %d: %s", s.Len(), msg)
	s.history.Add(msg)

	for _, client := range s.clients {
		if except != nil && client == except {
			continue
		}
		client.Msg <- msg
	}
}

func (s *Server) Add(client *Client) {
	go func() {
		client.WriteLines(s.history.Get(10))
		client.Write(fmt.Sprintf("-> Welcome to ssh-chat. Enter /help for more."))
	}()

	s.lock.Lock()
	s.count++

	newName, err := s.proposeName(client.Name)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> Your name '%s' is not available, renamed to '%s'. Use /nick <name> to change it.", client.Name, newName)
	}

	client.Rename(newName)
	s.clients[client.Name] = client
	num := len(s.clients)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s joined. (Total connected: %d)", client.Name, num), client)
}

func (s *Server) Remove(client *Client) {
	s.lock.Lock()
	delete(s.clients, client.Name)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s left.", client.Name), nil)
}

func (s *Server) proposeName(name string) (string, error) {
	// Assumes caller holds lock.
	var err error
	name = RE_STRIP_NAME.ReplaceAllString(name, "")

	if len(name) > MAX_NAME_LENGTH {
		name = name[:MAX_NAME_LENGTH]
	} else if len(name) == 0 {
		name = fmt.Sprintf("Guest%d", s.count)
	}

	_, collision := s.clients[name]
	if collision {
		err = fmt.Errorf("%s is not available.", name)
		name = fmt.Sprintf("Guest%d", s.count)
	}

	return name, err
}

func (s *Server) Rename(client *Client, newName string) {
	s.lock.Lock()

	newName, err := s.proposeName(newName)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> %s", err)
		s.lock.Unlock()
		return
	}

	// TODO: Use a channel/goroutine for adding clients, rathern than locks?
	delete(s.clients, client.Name)
	oldName := client.Name
	client.Rename(newName)
	s.clients[client.Name] = client
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s is now known as %s.", oldName, newName), nil)
}

func (s *Server) List(prefix *string) []string {
	r := []string{}

	for name, _ := range s.clients {
		if prefix != nil && !strings.HasPrefix(name, *prefix) {
			continue
		}
		r = append(r, name)
	}

	return r
}

func (s *Server) Who(name string) *Client {
	return s.clients[name]
}

func (s *Server) Op(fingerprint string) {
	logger.Infof("Adding admin: %s", fingerprint)
	s.lock.Lock()
	s.admins[fingerprint] = struct{}{}
	s.lock.Unlock()
}

func (s *Server) IsOp(client *Client) bool {
	_, r := s.admins[client.Fingerprint()]
	return r
}

func (s *Server) IsBanned(fingerprint string) bool {
	ban, hasBan := s.banned[fingerprint]
	if !hasBan {
		return false
	}
	if ban == nil {
		return true
	}
	if ban.Before(time.Now()) {
		s.Unban(fingerprint)
		return false
	}
	return true
}

func (s *Server) Ban(fingerprint string, duration *time.Duration) {
	var until *time.Time
	s.lock.Lock()
	if duration != nil {
		when := time.Now().Add(*duration)
		until = &when
	}
	s.banned[fingerprint] = until
	s.lock.Unlock()
}

func (s *Server) Unban(fingerprint string) {
	s.lock.Lock()
	delete(s.banned, fingerprint)
	s.lock.Unlock()
}

func (s *Server) Start(laddr string) error {
	// Once a ServerConfig has been configured, connections can be
	// accepted.
	socket, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}

	logger.Infof("Listening on %s", laddr)

	go func() {
		for {
			conn, err := socket.Accept()

			if err != nil {
				// TODO: Handle shutdown more gracefully?
				logger.Errorf("Failed to accept connection, aborting loop: %v", err)
				return
			}

			// Goroutineify to resume accepting sockets early.
			go func() {
				// From a standard TCP connection to an encrypted SSH connection
				sshConn, channels, requests, err := ssh.NewServerConn(conn, s.sshConfig)
				if err != nil {
					logger.Errorf("Failed to handshake: %v", err)
					return
				}

				version := client.Conn.ClientVersion()
				if len(version) > 100 {
					version = []byte("Evil Jerk with a superlong string")
				}
				logger.Infof("Connection #%d from: %s, %s, %s", s.count+1, sshConn.RemoteAddr(), sshConn.User(), version)

				go ssh.DiscardRequests(requests)

				client := NewClient(s, sshConn)
				go client.handleChannels(channels)
			}()
		}
	}()

	go func() {
		<-s.done
		socket.Close()
	}()

	return nil
}

func (s *Server) Stop() {
	for _, client := range s.clients {
		client.Conn.Close()
	}

	close(s.done)
}

func Fingerprint(k ssh.PublicKey) string {
	hash := md5.Sum(k.Marshal())
	r := fmt.Sprintf("% x", hash)
	return strings.Replace(r, " ", ":", -1)
}
<commit_msg>More evil inputs.<commit_after>package main

import (
	"crypto/md5"
	"fmt"
	"net"
	"regexp"
	"strings"
	"sync"
	"time"

	"golang.org/x/crypto/ssh"
)

const MAX_NAME_LENGTH = 32
const HISTORY_LEN = 20

var RE_STRIP_NAME = regexp.MustCompile("[^0-9A-Za-z_]")

type Clients map[string]*Client

type Server struct {
	sshConfig *ssh.ServerConfig
	done      chan struct{}
	clients   Clients
	lock      sync.Mutex
	count     int
	history   *History
	admins    map[string]struct{}   // fingerprint lookup
	banned    map[string]*time.Time // fingerprint lookup
}

func NewServer(privateKey []byte) (*Server, error) {
	signer, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}

	server := Server{
		done:    make(chan struct{}),
		clients: Clients{},
		count:   0,
		history: NewHistory(HISTORY_LEN),
		admins:  map[string]struct{}{},
		banned:  map[string]*time.Time{},
	}

	config := ssh.ServerConfig{
		NoClientAuth: false,
		// Auth-related things should be constant-time to avoid timing attacks.
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			fingerprint := Fingerprint(key)
			if server.IsBanned(fingerprint) {
				return nil, fmt.Errorf("Banned.")
			}
			perm := &ssh.Permissions{Extensions: map[string]string{"fingerprint": fingerprint}}
			return perm, nil
		},
	}
	config.AddHostKey(signer)

	server.sshConfig = &config

	return &server, nil
}

func (s *Server) Len() int {
	return len(s.clients)
}

func (s *Server) Broadcast(msg string, except *Client) {
	logger.Debugf("Broadcast to %d: %s", s.Len(), msg)
	s.history.Add(msg)

	for _, client := range s.clients {
		if except != nil && client == except {
			continue
		}
		client.Msg <- msg
	}
}

func (s *Server) Add(client *Client) {
	go func() {
		client.WriteLines(s.history.Get(10))
		client.Write(fmt.Sprintf("-> Welcome to ssh-chat. Enter /help for more."))
	}()

	s.lock.Lock()
	s.count++

	newName, err := s.proposeName(client.Name)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> Your name '%s' is not available, renamed to '%s'. Use /nick <name> to change it.", client.Name, newName)
	}

	client.Rename(newName)
	s.clients[client.Name] = client
	num := len(s.clients)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s joined. (Total connected: %d)", client.Name, num), client)
}

func (s *Server) Remove(client *Client) {
	s.lock.Lock()
	delete(s.clients, client.Name)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s left.", client.Name), nil)
}

func (s *Server) proposeName(name string) (string, error) {
	// Assumes caller holds lock.
	var err error
	name = RE_STRIP_NAME.ReplaceAllString(name, "")

	if len(name) > MAX_NAME_LENGTH {
		name = name[:MAX_NAME_LENGTH]
	} else if len(name) == 0 {
		name = fmt.Sprintf("Guest%d", s.count)
	}

	_, collision := s.clients[name]
	if collision {
		err = fmt.Errorf("%s is not available.", name)
		name = fmt.Sprintf("Guest%d", s.count)
	}

	return name, err
}

func (s *Server) Rename(client *Client, newName string) {
	s.lock.Lock()

	newName, err := s.proposeName(newName)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> %s", err)
		s.lock.Unlock()
		return
	}

	// TODO: Use a channel/goroutine for adding clients, rathern than locks?
	delete(s.clients, client.Name)
	oldName := client.Name
	client.Rename(newName)
	s.clients[client.Name] = client
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s is now known as %s.", oldName, newName), nil)
}

func (s *Server) List(prefix *string) []string {
	r := []string{}

	for name, _ := range s.clients {
		if prefix != nil && !strings.HasPrefix(name, *prefix) {
			continue
		}
		r = append(r, name)
	}

	return r
}

func (s *Server) Who(name string) *Client {
	return s.clients[name]
}

func (s *Server) Op(fingerprint string) {
	logger.Infof("Adding admin: %s", fingerprint)
	s.lock.Lock()
	s.admins[fingerprint] = struct{}{}
	s.lock.Unlock()
}

func (s *Server) IsOp(client *Client) bool {
	_, r := s.admins[client.Fingerprint()]
	return r
}

func (s *Server) IsBanned(fingerprint string) bool {
	ban, hasBan := s.banned[fingerprint]
	if !hasBan {
		return false
	}
	if ban == nil {
		return true
	}
	if ban.Before(time.Now()) {
		s.Unban(fingerprint)
		return false
	}
	return true
}

func (s *Server) Ban(fingerprint string, duration *time.Duration) {
	var until *time.Time
	s.lock.Lock()
	if duration != nil {
		when := time.Now().Add(*duration)
		until = &when
	}
	s.banned[fingerprint] = until
	s.lock.Unlock()
}

func (s *Server) Unban(fingerprint string) {
	s.lock.Lock()
	delete(s.banned, fingerprint)
	s.lock.Unlock()
}

func (s *Server) Start(laddr string) error {
	// Once a ServerConfig has been configured, connections can be
	// accepted.
	socket, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}

	logger.Infof("Listening on %s", laddr)

	go func() {
		for {
			conn, err := socket.Accept()

			if err != nil {
				// TODO: Handle shutdown more gracefully?
				logger.Errorf("Failed to accept connection, aborting loop: %v", err)
				return
			}

			// Goroutineify to resume accepting sockets early.
			go func() {
				// From a standard TCP connection to an encrypted SSH connection
				sshConn, channels, requests, err := ssh.NewServerConn(conn, s.sshConfig)
				if err != nil {
					logger.Errorf("Failed to handshake: %v", err)
					return
				}

				version := sshConn.ClientVersion()
				if len(version) > 100 {
					version = []byte("Evil Jerk with a superlong string")
				}
				logger.Infof("Connection #%d from: %s, %s, %s", s.count+1, sshConn.RemoteAddr(), sshConn.User(), version)

				go ssh.DiscardRequests(requests)

				client := NewClient(s, sshConn)
				go client.handleChannels(channels)
			}()
		}
	}()

	go func() {
		<-s.done
		socket.Close()
	}()

	return nil
}

func (s *Server) Stop() {
	for _, client := range s.clients {
		client.Conn.Close()
	}

	close(s.done)
}

func Fingerprint(k ssh.PublicKey) string {
	hash := md5.Sum(k.Marshal())
	r := fmt.Sprintf("% x", hash)
	return strings.Replace(r, " ", ":", -1)
}
<|endoftext|>


<commit_before>/*
Copyright 2013 Andrew Medworth

This file is part of Gopoker, a set of miscellaneous poker-related functions
written in the Go programming language (http://golang.org).

Gopoker is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Gopoker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Gopoker.  If not, see <http://www.gnu.org/licenses/>.
*/
package poker_http

import (
	"encoding/json"
	"fmt"
	"github.com/amdw/gopoker/poker"
	"io/ioutil"
	"log"
	"net/http"
	"path"
	"strconv"
)

const rank1Key = "rank1"
const rank2Key = "rank2"
const sameSuitKey = "samesuit"
const handsToPlayKey = "handstoplay"

func StartingCards(htmlBaseDir string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		path := path.Join(htmlBaseDir, "starting_cards.html")
		body, err := ioutil.ReadFile(path)
		if err != nil {
			http.Error(w, fmt.Sprintf("Could not load %v: %v", path, err), http.StatusInternalServerError)
			return
		}
		fmt.Fprintln(w, string(body))
	}
}

func getRank(req *http.Request, key string, w http.ResponseWriter) (poker.Rank, bool) {
	var rank poker.Rank
	var err error
	if rstrs, ok := req.Form[key]; ok && len(rstrs) > 0 {
		rank, err = poker.MakeRank(rstrs[0])
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad rank '%v': %v", rstrs[0], err), http.StatusBadRequest)
			return 0, false
		}
	} else {
		http.Error(w, fmt.Sprintf("Missing required %v", key), http.StatusBadRequest)
		return 0, false
	}
	return rank, true
}

type SimParams struct {
	StartingPair poker.StartingPair
	Players      int
	HandsToPlay  int
}

func (params SimParams) RunSimulation() poker.Simulator {
	return params.StartingPair.RunSimulation(params.Players, params.HandsToPlay)
}

func getStartingPair(req *http.Request, w http.ResponseWriter) (SimParams, bool) {
	req.ParseForm()
	rank1, ok := getRank(req, rank1Key, w)
	if !ok {
		return SimParams{}, false
	}
	rank2, ok := getRank(req, rank2Key, w)
	if !ok {
		return SimParams{}, false
	}
	sameSuit := false
	var err error
	if ssstrs, ok := req.Form[sameSuitKey]; ok && len(ssstrs) > 0 {
		sameSuit, err = strconv.ParseBool(ssstrs[0])
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad %v: %v", sameSuitKey, err), http.StatusBadRequest)
			return SimParams{}, false
		}
	}
	players := 7
	if pstrs, ok := req.Form[playersKey]; ok && len(pstrs) > 0 {
		var players64 int64
		players64, err = strconv.ParseInt(pstrs[0], 10, 31)
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad %v: %v", playersKey, err), http.StatusBadRequest)
			return SimParams{}, false
		}
		players = int(players64)
	}
	handsToPlay := 10000
	if htpstrs, ok := req.Form[handsToPlayKey]; ok && len(htpstrs) > 0 {
		var handsToPlay64 int64
		handsToPlay64, err = strconv.ParseInt(htpstrs[0], 10, 31)
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad %v: %v", handsToPlayKey, err), http.StatusBadRequest)
			return SimParams{}, false
		}
		handsToPlay = int(handsToPlay64)
	}
	startingPair := poker.StartingPair{rank1, rank2, sameSuit}
	err = startingPair.Validate()
	if err != nil {
		http.Error(w, fmt.Sprintf("Bad pair: %v", err), http.StatusBadRequest)
		return SimParams{}, false
	}
	return SimParams{startingPair, players, handsToPlay}, true
}

func SimulateStartingCards(w http.ResponseWriter, req *http.Request) {
	simParams, ok := getStartingPair(req, w)
	if !ok {
		return
	}
	log.Println("Simulating", simParams)
	simulator := simParams.RunSimulation()
	log.Println("Simulation", simParams, "complete")
	json.NewEncoder(w).Encode(simulator)
}
<commit_msg>Use io.Copy to render static HTML (closes #15)<commit_after>/*
Copyright 2013 Andrew Medworth

This file is part of Gopoker, a set of miscellaneous poker-related functions
written in the Go programming language (http://golang.org).

Gopoker is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Gopoker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Gopoker.  If not, see <http://www.gnu.org/licenses/>.
*/
package poker_http

import (
	"encoding/json"
	"fmt"
	"github.com/amdw/gopoker/poker"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"strconv"
)

const rank1Key = "rank1"
const rank2Key = "rank2"
const sameSuitKey = "samesuit"
const handsToPlayKey = "handstoplay"

func StartingCards(htmlBaseDir string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		path := path.Join(htmlBaseDir, "starting_cards.html")
		file, err := os.Open(path)
		if err != nil {
			http.Error(w, fmt.Sprintf("Could not load %v: %v", path, err), http.StatusInternalServerError)
			return
		}
		_, err = io.Copy(w, file)
		if err != nil {
			http.Error(w, fmt.Sprintf("Could not write %v: %v", path, err), http.StatusInternalServerError)
			return
		}
	}
}

func getRank(req *http.Request, key string, w http.ResponseWriter) (poker.Rank, bool) {
	var rank poker.Rank
	var err error
	if rstrs, ok := req.Form[key]; ok && len(rstrs) > 0 {
		rank, err = poker.MakeRank(rstrs[0])
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad rank '%v': %v", rstrs[0], err), http.StatusBadRequest)
			return 0, false
		}
	} else {
		http.Error(w, fmt.Sprintf("Missing required %v", key), http.StatusBadRequest)
		return 0, false
	}
	return rank, true
}

type SimParams struct {
	StartingPair poker.StartingPair
	Players      int
	HandsToPlay  int
}

func (params SimParams) RunSimulation() poker.Simulator {
	return params.StartingPair.RunSimulation(params.Players, params.HandsToPlay)
}

func getStartingPair(req *http.Request, w http.ResponseWriter) (SimParams, bool) {
	req.ParseForm()
	rank1, ok := getRank(req, rank1Key, w)
	if !ok {
		return SimParams{}, false
	}
	rank2, ok := getRank(req, rank2Key, w)
	if !ok {
		return SimParams{}, false
	}
	sameSuit := false
	var err error
	if ssstrs, ok := req.Form[sameSuitKey]; ok && len(ssstrs) > 0 {
		sameSuit, err = strconv.ParseBool(ssstrs[0])
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad %v: %v", sameSuitKey, err), http.StatusBadRequest)
			return SimParams{}, false
		}
	}
	players := 7
	if pstrs, ok := req.Form[playersKey]; ok && len(pstrs) > 0 {
		var players64 int64
		players64, err = strconv.ParseInt(pstrs[0], 10, 31)
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad %v: %v", playersKey, err), http.StatusBadRequest)
			return SimParams{}, false
		}
		players = int(players64)
	}
	handsToPlay := 10000
	if htpstrs, ok := req.Form[handsToPlayKey]; ok && len(htpstrs) > 0 {
		var handsToPlay64 int64
		handsToPlay64, err = strconv.ParseInt(htpstrs[0], 10, 31)
		if err != nil {
			http.Error(w, fmt.Sprintf("Bad %v: %v", handsToPlayKey, err), http.StatusBadRequest)
			return SimParams{}, false
		}
		handsToPlay = int(handsToPlay64)
	}
	startingPair := poker.StartingPair{rank1, rank2, sameSuit}
	err = startingPair.Validate()
	if err != nil {
		http.Error(w, fmt.Sprintf("Bad pair: %v", err), http.StatusBadRequest)
		return SimParams{}, false
	}
	return SimParams{startingPair, players, handsToPlay}, true
}

func SimulateStartingCards(w http.ResponseWriter, req *http.Request) {
	simParams, ok := getStartingPair(req, w)
	if !ok {
		return
	}
	log.Println("Simulating", simParams)
	simulator := simParams.RunSimulation()
	log.Println("Simulation", simParams, "complete")
	json.NewEncoder(w).Encode(simulator)
}
<|endoftext|>


<commit_before>// spdy/server.go

package spdy

import (
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// ListenAndServe creates a new Server that serves on the given address.  If
// the handler is nil, then http.DefaultServeMux is used.
func ListenAndServe(addr string, handler http.Handler) error {
	srv := &Server{addr, handler}
	return srv.ListenAndServe()
}

// ListenAndServeTLS acts like ListenAndServe except it uses TLS.
func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) (err error) {
	config := &tls.Config{
		Rand:         rand.Reader,
		Time:         time.Now,
		NextProtos:   []string{"spdy/2", "http/1.1"},
		Certificates: make([]tls.Certificate, 1),
	}
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return
	}
	tlsListener := tls.NewListener(conn, config)
	return (&Server{addr, handler}).Serve(tlsListener)
}

// A Server handles incoming SPDY connections with HTTP handlers.
type Server struct {
	Addr    string
	Handler http.Handler
}

// ListenAndServe services SPDY requests on the given address.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(l)
}

// ListenAndServe services SPDY requests using the given listener.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) Serve(l net.Listener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		s, err := newSession(c, handler)
		if err != nil {
			return err
		}
		go s.serve()
	}
	return nil
}

// A session manages a single TCP connection to a client.
type session struct {
	c         net.Conn
	handler   http.Handler
	out       chan Frame
	streams   map[uint32]*serverStream // all access is done synchronously
	last_good uint32

	headerReader *HeaderReader
	headerWriter *HeaderWriter
}

func newSession(c net.Conn, h http.Handler) (s *session, err error) {
	s = &session{
		c:            c,
		handler:      h,
		headerReader: NewHeaderReader(),
		headerWriter: NewHeaderWriter(-1),
		out:          make(chan Frame),
		streams:      make(map[uint32]*serverStream),
		last_good:    0,
	}
	return
}

func (sess *session) serve() {
	defer sess.c.Close()
	go sess.receiveFrames()

	for frame := range sess.out {

		if frame == nil {
			// EOF, signalling end of session
			// initiated by us (on errors, etc.)
			return
		}

		// TODO: Check for errors
		frame.WriteTo(sess.c)
	}
}

func (sess *session) fail() {
	sess.out <- ControlFrame{
		Type: TypeGoaway,
		Data: []byte{
			byte(sess.last_good & 0x7f000000 >> 24),
			byte(sess.last_good & 0x00ff0000 >> 16),
			byte(sess.last_good & 0x0000ff00 >> 8),
			byte(sess.last_good & 0x000000ff >> 0),
		},
	}
	sess.out <- nil
}

func (sess *session) handleControl(frame ControlFrame) {
	switch frame.Type {
	case TypeSynStream:
		if stream, err := newServerStream(sess, frame); err == nil {
			if _, exists := sess.streams[stream.id]; !exists {
				sess.streams[stream.id] = stream
				sess.last_good = stream.id
				go func() {
					sess.handler.ServeHTTP(stream, stream.Request())
					stream.finish()
				}()
			}
		} else {
			sess.fail()
		}
	case TypeRstStream:
		d := bytes.NewBuffer(frame.Data)
		var streamId, statusCode uint32
		readBinary(d, &streamId, &statusCode)
	case TypePing:
		d := bytes.NewBuffer(frame.Data)
		var pingId uint32
		readBinary(d, &pingId)
		sess.out <- ControlFrame{
			Type: TypePing,
			Data: []byte{
				byte(pingId & 0xff000000 >> 24),
				byte(pingId & 0x00ff0000 >> 16),
				byte(pingId & 0x0000ff00 >> 8),
				byte(pingId & 0x000000ff >> 0),
			},
		}
	}
}

func (sess *session) handleData(frame DataFrame) {
	st, found := sess.streams[frame.StreamID]
	if !found {
		// TODO: Error?
		return
	}
	if st.dataPipe != nil {
		st.dataPipe.write(frame.Data)
		if frame.Flags&FlagFin != 0 {
			st.dataPipe.wclose(nil)
		}
	}
}

func (sess *session) receiveFrames() {
	for {
		f, err := ReadFrame(sess.c)
		if err != nil {
			return
		}

		if f == nil {
			// EOF, signalling end of session
			return
		}
		switch frame := f.(type) {
		case ControlFrame:
			sess.handleControl(frame)
		case DataFrame:
			sess.handleData(frame)
		}
	}
}

// A serverStream is a logical data stream inside a session.  A serverStream
// services a single request.
type serverStream struct {
	id      uint32
	session *session
	closed  bool

	requestHeaders  http.Header
	responseHeaders http.Header
	wroteHeader     bool

	dataPipe *asyncPipe
}

func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err error) {
	if frame.Type != TypeSynStream {
		err = errors.New("Server stream must be created from a SynStream frame")
		return
	}
	st = &serverStream{
		session:         sess,
		responseHeaders: make(http.Header),
	}
	if frame.Flags&FlagFin == 0 {
		// Request body will follow
		st.dataPipe = apipe()
	}
	// Read frame data
	data := bytes.NewBuffer(frame.Data)
	err = binary.Read(data, binary.BigEndian, &st.id)
	if err != nil {
		return
	}
	_, err = io.ReadFull(data, make([]byte, 6)) // skip associated stream ID and priority
	if err != nil {
		return
	}
	st.requestHeaders, err = sess.headerReader.Decode(data.Bytes())
	return
}

// Request returns the request data associated with the serverStream.
func (st *serverStream) Request() (req *http.Request) {
	// TODO: Add more info
	req = &http.Request{
		Method:     st.requestHeaders.Get("method"),
		Proto:      st.requestHeaders.Get("version"),
		Header:     st.requestHeaders,
		Body:       st,
		RemoteAddr: st.session.c.RemoteAddr().String(),
	}
	req.URL, _ = url.ParseRequestURI(st.requestHeaders.Get("url"))
	return
}

func (st *serverStream) Read(p []byte) (n int, err error) {
	return st.dataPipe.read(p)
}

// Header returns the current response headers.
func (st *serverStream) Header() http.Header { return st.responseHeaders }

func (st *serverStream) Write(p []byte) (n int, err error) {
	if st.closed {
		err = errors.New("Write on closed serverStream")
		return
	}
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	for len(p) > 0 {
		frame := DataFrame{
			StreamID: st.id,
		}
		if len(p) < MaxDataLength {
			frame.Data = make([]byte, len(p))
		} else {
			frame.Data = make([]byte, MaxDataLength)
		}
		copy(frame.Data, p)
		p = p[len(frame.Data):]
		st.session.out <- frame
		n += len(frame.Data)
	}
	return
}

// A synReplyFrame defers header compression until the server writes the frame.
// This is necessary to guarantee correctly ordered compression.
type synReplyFrame struct {
	stream *serverStream
	header http.Header
	flags  FrameFlags
}

func (frame synReplyFrame) GetFlags() FrameFlags {
	return frame.flags
}

func (frame synReplyFrame) GetData() []byte {
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, frame.stream.id&0x7fffffff)
	buf.Write([]byte{0, 0})
	frame.stream.session.headerWriter.WriteHeader(buf, frame.stream.responseHeaders)
	return buf.Bytes()
}

func (frame synReplyFrame) WriteTo(w io.Writer) (n int64, err error) {
	cf := ControlFrame{Type: TypeSynReply, Data: frame.GetData()}
	return cf.WriteTo(w)
}

func (st *serverStream) WriteHeader(code int) {
	if st.wroteHeader {
		return
	}
	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
	st.responseHeaders.Set("version", "HTTP/1.1")
	if st.responseHeaders.Get("Content-Type") == "" {
		st.responseHeaders.Set("Content-Type", "text/html; charset=utf-8")
	}
	if st.responseHeaders.Get("Date") == "" {
		st.responseHeaders.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	}
	// Write the frame
	// TODO: Copy headers
	st.session.out <- synReplyFrame{stream: st, header: st.responseHeaders}
	st.wroteHeader = true
}

// Close sends a closing frame, thus preventing the server from sending more
// data over the stream.  The client may still send data.
func (st *serverStream) Close() (err error) {
	if st.closed {
		return
	}
	st.session.out <- DataFrame{
		StreamID: st.id,
		Flags:    FlagFin,
		Data:     []byte{},
	}
	st.closed = true
	return nil
}

func (st *serverStream) finish() (err error) {
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	return st.Close()
}
<commit_msg>Catch obviously malformed SYN_STREAM requests<commit_after>// spdy/server.go

package spdy

import (
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// ListenAndServe creates a new Server that serves on the given address.  If
// the handler is nil, then http.DefaultServeMux is used.
func ListenAndServe(addr string, handler http.Handler) error {
	srv := &Server{addr, handler}
	return srv.ListenAndServe()
}

// ListenAndServeTLS acts like ListenAndServe except it uses TLS.
func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) (err error) {
	config := &tls.Config{
		Rand:         rand.Reader,
		Time:         time.Now,
		NextProtos:   []string{"spdy/2", "http/1.1"},
		Certificates: make([]tls.Certificate, 1),
	}
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return
	}
	tlsListener := tls.NewListener(conn, config)
	return (&Server{addr, handler}).Serve(tlsListener)
}

// A Server handles incoming SPDY connections with HTTP handlers.
type Server struct {
	Addr    string
	Handler http.Handler
}

// ListenAndServe services SPDY requests on the given address.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(l)
}

// ListenAndServe services SPDY requests using the given listener.
// If the handler is nil, then http.DefaultServeMux is used.
func (srv *Server) Serve(l net.Listener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		s, err := newSession(c, handler)
		if err != nil {
			return err
		}
		go s.serve()
	}
	return nil
}

// A session manages a single TCP connection to a client.
type session struct {
	c         net.Conn
	handler   http.Handler
	out       chan Frame
	streams   map[uint32]*serverStream // all access is done synchronously
	last_good uint32

	headerReader *HeaderReader
	headerWriter *HeaderWriter
}

func newSession(c net.Conn, h http.Handler) (s *session, err error) {
	s = &session{
		c:            c,
		handler:      h,
		headerReader: NewHeaderReader(),
		headerWriter: NewHeaderWriter(-1),
		out:          make(chan Frame),
		streams:      make(map[uint32]*serverStream),
		last_good:    0,
	}
	return
}

func (sess *session) serve() {
	defer sess.c.Close()
	go sess.receiveFrames()

	for frame := range sess.out {

		if frame == nil {
			// EOF, signalling end of session
			// initiated by us (on errors, etc.)
			return
		}

		// TODO: Check for errors
		frame.WriteTo(sess.c)
	}
}

func (sess *session) fail() {
	sess.out <- ControlFrame{
		Type: TypeGoaway,
		Data: []byte{
			byte(sess.last_good & 0x7f000000 >> 24),
			byte(sess.last_good & 0x00ff0000 >> 16),
			byte(sess.last_good & 0x0000ff00 >> 8),
			byte(sess.last_good & 0x000000ff >> 0),
		},
	}
	sess.out <- nil
}

func (sess *session) handleControl(frame ControlFrame) {
	switch frame.Type {
	case TypeSynStream:
		if stream, err := newServerStream(sess, frame); err == nil {
			if _, exists := sess.streams[stream.id]; !exists {
				sess.streams[stream.id] = stream
				sess.last_good = stream.id
				go func() {
					sess.handler.ServeHTTP(stream, stream.Request())
					stream.finish()
				}()
			}
		} else {
			sess.fail()
		}
	case TypeRstStream:
		d := bytes.NewBuffer(frame.Data)
		var streamId, statusCode uint32
		readBinary(d, &streamId, &statusCode)
	case TypePing:
		d := bytes.NewBuffer(frame.Data)
		var pingId uint32
		readBinary(d, &pingId)
		sess.out <- ControlFrame{
			Type: TypePing,
			Data: []byte{
				byte(pingId & 0xff000000 >> 24),
				byte(pingId & 0x00ff0000 >> 16),
				byte(pingId & 0x0000ff00 >> 8),
				byte(pingId & 0x000000ff >> 0),
			},
		}
	}
}

func (sess *session) handleData(frame DataFrame) {
	st, found := sess.streams[frame.StreamID]
	if !found {
		// TODO: Error?
		return
	}
	if st.dataPipe != nil {
		st.dataPipe.write(frame.Data)
		if frame.Flags&FlagFin != 0 {
			st.dataPipe.wclose(nil)
		}
	}
}

func (sess *session) receiveFrames() {
	for {
		f, err := ReadFrame(sess.c)
		if err != nil {
			return
		}

		if f == nil {
			// EOF, signalling end of session
			return
		}
		switch frame := f.(type) {
		case ControlFrame:
			sess.handleControl(frame)
		case DataFrame:
			sess.handleData(frame)
		}
	}
}

// A serverStream is a logical data stream inside a session.  A serverStream
// services a single request.
type serverStream struct {
	id      uint32
	session *session
	closed  bool

	requestHeaders  http.Header
	responseHeaders http.Header
	wroteHeader     bool

	dataPipe *asyncPipe
}

func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err error) {
	if frame.Type != TypeSynStream {
		err = errors.New("Server stream must be created from a SynStream frame")
		return
	}
	st = &serverStream{
		session:         sess,
		responseHeaders: make(http.Header),
	}
	if frame.Flags&FlagFin == 0 {
		// Request body will follow
		st.dataPipe = apipe()
	}
	// Read frame data
	data := bytes.NewBuffer(frame.Data)
	err = binary.Read(data, binary.BigEndian, &st.id)
	if err != nil {
		return
	}
	_, err = io.ReadFull(data, make([]byte, 6)) // skip associated stream ID and priority
	if err != nil {
		return
	}
	st.requestHeaders, err = sess.headerReader.Decode(data.Bytes())
	if err != nil {
		return
	}

	if st.requestHeaders.Get("method") == "" {
		err = errors.New("Missing method header")
	} else if st.requestHeaders.Get("version") == "" {
		err = errors.New("Missing version header")
	} else if st.requestHeaders.Get("url") == "" {
		err = errors.New("Missing url header")
	}

	return
}

// Request returns the request data associated with the serverStream.
func (st *serverStream) Request() (req *http.Request) {
	// TODO: Add more info
	req = &http.Request{
		Method:     st.requestHeaders.Get("method"),
		Proto:      st.requestHeaders.Get("version"),
		Header:     st.requestHeaders,
		Body:       st,
		RemoteAddr: st.session.c.RemoteAddr().String(),
	}
	req.URL, _ = url.ParseRequestURI(st.requestHeaders.Get("url"))
	return
}

func (st *serverStream) Read(p []byte) (n int, err error) {
	return st.dataPipe.read(p)
}

// Header returns the current response headers.
func (st *serverStream) Header() http.Header { return st.responseHeaders }

func (st *serverStream) Write(p []byte) (n int, err error) {
	if st.closed {
		err = errors.New("Write on closed serverStream")
		return
	}
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	for len(p) > 0 {
		frame := DataFrame{
			StreamID: st.id,
		}
		if len(p) < MaxDataLength {
			frame.Data = make([]byte, len(p))
		} else {
			frame.Data = make([]byte, MaxDataLength)
		}
		copy(frame.Data, p)
		p = p[len(frame.Data):]
		st.session.out <- frame
		n += len(frame.Data)
	}
	return
}

// A synReplyFrame defers header compression until the server writes the frame.
// This is necessary to guarantee correctly ordered compression.
type synReplyFrame struct {
	stream *serverStream
	header http.Header
	flags  FrameFlags
}

func (frame synReplyFrame) GetFlags() FrameFlags {
	return frame.flags
}

func (frame synReplyFrame) GetData() []byte {
	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, frame.stream.id&0x7fffffff)
	buf.Write([]byte{0, 0})
	frame.stream.session.headerWriter.WriteHeader(buf, frame.stream.responseHeaders)
	return buf.Bytes()
}

func (frame synReplyFrame) WriteTo(w io.Writer) (n int64, err error) {
	cf := ControlFrame{Type: TypeSynReply, Data: frame.GetData()}
	return cf.WriteTo(w)
}

func (st *serverStream) WriteHeader(code int) {
	if st.wroteHeader {
		return
	}
	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
	st.responseHeaders.Set("version", "HTTP/1.1")
	if st.responseHeaders.Get("Content-Type") == "" {
		st.responseHeaders.Set("Content-Type", "text/html; charset=utf-8")
	}
	if st.responseHeaders.Get("Date") == "" {
		st.responseHeaders.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	}
	// Write the frame
	// TODO: Copy headers
	st.session.out <- synReplyFrame{stream: st, header: st.responseHeaders}
	st.wroteHeader = true
}

// Close sends a closing frame, thus preventing the server from sending more
// data over the stream.  The client may still send data.
func (st *serverStream) Close() (err error) {
	if st.closed {
		return
	}
	st.session.out <- DataFrame{
		StreamID: st.id,
		Flags:    FlagFin,
		Data:     []byte{},
	}
	st.closed = true
	return nil
}

func (st *serverStream) finish() (err error) {
	if !st.wroteHeader {
		st.WriteHeader(http.StatusOK)
	}
	return st.Close()
}
<|endoftext|>


<commit_before>package devastator

import (
	"fmt"
	"log"
	"sync"

	"github.com/nbusy/neptulon"
	"github.com/nbusy/neptulon/jsonrpc"
)

// Server wraps a listener instance and registers default connection and message handlers with the listener.
type Server struct {
	neptulon  *neptulon.Server
	jsonrpc   *jsonrpc.Server
	pubRoute  *jsonrpc.Router
	privRoute *jsonrpc.Router

	db      DB
	certMgr *CertMgr
	queue   Queue

	debug    bool
	err      error
	errMutex sync.Mutex
}

// NewServer creates and returns a new server instance with a listener created using given parameters.
// Debug mode dumps raw TCP data to stderr using log.Println().
func NewServer(cert, privKey, clientCACert, clientCAKey []byte, laddr string, debug bool) (*Server, error) {
	nep, err := neptulon.NewServer(cert, privKey, clientCACert, laddr, debug)
	if err != nil {
		return nil, err
	}

	s := Server{
		debug:    debug,
		neptulon: nep,
		db:       NewInMemDB(),
		certMgr:  NewCertMgr(clientCACert, clientCAKey),
		queue:    NewQueue(),
	}

	s.jsonrpc, err = jsonrpc.NewServer(nep)
	if err != nil {
		return nil, err
	}

	s.pubRoute, err = jsonrpc.NewRouter(s.jsonrpc)
	if err != nil {
		return nil, err
	}

	s.pubRoute.Request("auth.google", func(ctx *jsonrpc.ReqCtx) {
		googleAuth(ctx, s.db, s.certMgr)
	})

	s.pubRoute.Notification("conn.close", func(ctx *jsonrpc.NotCtx) {
		ctx.Done = true
		ctx.Conn.Close()
	})

	// pubRoute.NotFound(...)
	// todo: if the first incoming message in public route is not one of close/google.auth,
	// close the connection right away (and maybe wait for client to return ACK then close?)

	_, err = NewCertAuth(s.jsonrpc)
	if err != nil {
		return nil, err
	}

	s.privRoute, err = jsonrpc.NewRouter(s.jsonrpc)
	if err != nil {
		return nil, err
	}

	s.privRoute.Request("msg.echo", func(ctx *jsonrpc.ReqCtx) {
		ctx.Params(&ctx.Res)
		if ctx.Res == nil {
			ctx.Res = ""
		}
	})

	type msgSendRequest struct {
		to      string
		message string
	}

	s.privRoute.Request("msg.send", func(ctx *jsonrpc.ReqCtx) {
		// try to send the incoming message right away
		var r msgSendRequest
		ctx.Params(&r)
		s.queue.AddRequest(r.to, &jsonrpc.Request{ID: "456", Method: "msg.recv", Params: r.message})
	})

	s.privRoute.Request("msg.recv", func(ctx *jsonrpc.ReqCtx) {

	})

	// privRoute.Middleware(NotFoundHandler()) // 404-like handler
	// privRoute/pubRoute.Middleware(Logger()) // request-response logger (the pointer fields in request/response objects will have to change for this to work)

	return &s, nil
}

// UseDB sets the database to be used by the server. If not supplied, in-memory database implementation is used.
func (s *Server) UseDB(db DB) error {
	s.db = db
	return nil
}

// Start starts accepting connections on the internal listener and handles connections with registered onnection and message handlers.
// This function blocks and never returns, unless there was an error while accepting a new connection or the server was closed.
func (s *Server) Start() error {
	err := s.neptulon.Run()
	if err != nil && s.debug {
		log.Fatalln("Listener returned an error while closing:", err)
	}

	s.errMutex.Lock()
	s.err = err
	s.errMutex.Unlock()

	return err
}

// Stop stops the server and closes all of the active connections discarding any read/writes that is going on currently.
// This is not a problem as we always require an ACK but it will also mean that message deliveries will be at-least-once; to-and-from the server.
func (s *Server) Stop() error {
	err := s.neptulon.Stop()

	s.errMutex.Lock()
	if s.err != nil {
		return fmt.Errorf("Past internal error: %v", s.err)
	}
	s.errMutex.Unlock()
	return err
}
<commit_msg>rename msgSendRequest -> sendMsgReq<commit_after>package devastator

import (
	"fmt"
	"log"
	"sync"

	"github.com/nbusy/neptulon"
	"github.com/nbusy/neptulon/jsonrpc"
)

// Server wraps a listener instance and registers default connection and message handlers with the listener.
type Server struct {
	neptulon  *neptulon.Server
	jsonrpc   *jsonrpc.Server
	pubRoute  *jsonrpc.Router
	privRoute *jsonrpc.Router

	db      DB
	certMgr *CertMgr
	queue   Queue

	debug    bool
	err      error
	errMutex sync.Mutex
}

// NewServer creates and returns a new server instance with a listener created using given parameters.
// Debug mode dumps raw TCP data to stderr using log.Println().
func NewServer(cert, privKey, clientCACert, clientCAKey []byte, laddr string, debug bool) (*Server, error) {
	nep, err := neptulon.NewServer(cert, privKey, clientCACert, laddr, debug)
	if err != nil {
		return nil, err
	}

	s := Server{
		debug:    debug,
		neptulon: nep,
		db:       NewInMemDB(),
		certMgr:  NewCertMgr(clientCACert, clientCAKey),
		queue:    NewQueue(),
	}

	s.jsonrpc, err = jsonrpc.NewServer(nep)
	if err != nil {
		return nil, err
	}

	s.pubRoute, err = jsonrpc.NewRouter(s.jsonrpc)
	if err != nil {
		return nil, err
	}

	s.pubRoute.Request("auth.google", func(ctx *jsonrpc.ReqCtx) {
		googleAuth(ctx, s.db, s.certMgr)
	})

	s.pubRoute.Notification("conn.close", func(ctx *jsonrpc.NotCtx) {
		ctx.Done = true
		ctx.Conn.Close()
	})

	// pubRoute.NotFound(...)
	// todo: if the first incoming message in public route is not one of close/google.auth,
	// close the connection right away (and maybe wait for client to return ACK then close?)

	_, err = NewCertAuth(s.jsonrpc)
	if err != nil {
		return nil, err
	}

	s.privRoute, err = jsonrpc.NewRouter(s.jsonrpc)
	if err != nil {
		return nil, err
	}

	s.privRoute.Request("msg.echo", func(ctx *jsonrpc.ReqCtx) {
		ctx.Params(&ctx.Res)
		if ctx.Res == nil {
			ctx.Res = ""
		}
	})

	type sendMsgReq struct {
		to      string
		message string
	}

	s.privRoute.Request("msg.send", func(ctx *jsonrpc.ReqCtx) {
		// try to send the incoming message right away
		var r sendMsgReq
		ctx.Params(&r)
		s.queue.AddRequest(r.to, &jsonrpc.Request{ID: "456", Method: "msg.recv", Params: r.message})
	})

	s.privRoute.Request("msg.recv", func(ctx *jsonrpc.ReqCtx) {

	})

	// privRoute.Middleware(NotFoundHandler()) // 404-like handler
	// privRoute/pubRoute.Middleware(Logger()) // request-response logger (the pointer fields in request/response objects will have to change for this to work)

	return &s, nil
}

// UseDB sets the database to be used by the server. If not supplied, in-memory database implementation is used.
func (s *Server) UseDB(db DB) error {
	s.db = db
	return nil
}

// Start starts accepting connections on the internal listener and handles connections with registered onnection and message handlers.
// This function blocks and never returns, unless there was an error while accepting a new connection or the server was closed.
func (s *Server) Start() error {
	err := s.neptulon.Run()
	if err != nil && s.debug {
		log.Fatalln("Listener returned an error while closing:", err)
	}

	s.errMutex.Lock()
	s.err = err
	s.errMutex.Unlock()

	return err
}

// Stop stops the server and closes all of the active connections discarding any read/writes that is going on currently.
// This is not a problem as we always require an ACK but it will also mean that message deliveries will be at-least-once; to-and-from the server.
func (s *Server) Stop() error {
	err := s.neptulon.Stop()

	s.errMutex.Lock()
	if s.err != nil {
		return fmt.Errorf("Past internal error: %v", s.err)
	}
	s.errMutex.Unlock()
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/codegangsta/martini"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"
)

const DEFAULT_PORT = 5000

func main() {
	port := flag.Int("port", DEFAULT_PORT, "Port to use")
	flag.Parse()

	m := martini.Classic()

	log.Printf("Server: Version=%s/%d", BUILD_GIT_COMMIT, BUILD_NUMBER)

	m.Get("/version", func() string {
		out := fmt.Sprint("This is build ", BUILD_NUMBER, " from commit ", BUILD_GIT_COMMIT)
		log.Println(out)
		return out
	})

	m.Get("/cgo", func() string {
		out := fmt.Sprint("Number of cgo calls: ", runtime.NumGoroutine())
		log.Println(out)
		return out
	})

	m.Get("/logs", func(w http.ResponseWriter, r *http.Request) {
		f, err := os.OpenFile(LOGS_FILE, os.O_RDONLY, 0666)
		if err != nil {
			w.WriteHeader(404)
			log.Println("File could not be opened !")
			return
		}
		defer f.Close()
		reader := bufio.NewReader(f)
		copied, err := io.Copy(w, reader)
		log.Println("Copied", copied, "bytes of logs.")
	})

	m.Get("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(404)
		fmt.Fprintln(w, "There's no favicon.")
	})

	m.Get("/", func(w http.ResponseWriter, r *http.Request) {
		out := fmt.Sprintf("Hi there, I love \"%s\" !", strings.Replace(r.URL.Path[1:], "/", "<SLASH>", -1))
		log.Println(out)
		w.Write([]byte(out))
	})

	log.Printf("Listening on port %d...", *port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", *port), m)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Added some Go environment information.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/codegangsta/martini"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"
)

const DEFAULT_PORT = 5000

func main() {
	port := flag.Int("port", DEFAULT_PORT, "Port to use")
	flag.Parse()

	m := martini.Classic()

	log.Printf("Server: Version=%s/%d", BUILD_GIT_COMMIT, BUILD_NUMBER)

	m.Get("/version", func() string {
		return fmt.Sprint("This is build ", BUILD_NUMBER, " from commit ", BUILD_GIT_COMMIT)
	})

	m.Get("/go", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(fmt.Sprintln("Version:", runtime.Version())))
		w.Write([]byte(fmt.Sprintln("CGO calls:", runtime.NumCgoCall())))
		{
			var mem runtime.MemStats
			runtime.ReadMemStats(&mem)
			w.Write([]byte(fmt.Sprintln("MEM: Footprint: ", mem.Alloc, ", Mallocs: ", mem.Mallocs, ", Frees: ", mem.Frees, ", GCs: ", mem.NumGC, "Next GC in ", (mem.NextGC - mem.HeapAlloc), " bytes")))
		}
	})

	m.Get("/logs", func(w http.ResponseWriter, r *http.Request) {
		f, err := os.OpenFile(LOGS_FILE, os.O_RDONLY, 0666)
		if err != nil {
			w.WriteHeader(404)
			log.Println("File could not be opened !")
			return
		}
		defer f.Close()
		reader := bufio.NewReader(f)
		copied, err := io.Copy(w, reader)
		log.Println("Copied", copied, "bytes of logs.")
	})

	m.Get("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(404)
		fmt.Fprintln(w, "There's no favicon.")
	})

	m.Get("/", func(w http.ResponseWriter, r *http.Request) {
		out := fmt.Sprintf("Hi there, I love \"%s\" !", strings.Replace(r.URL.Path[1:], "/", "<SLASH>", -1))
		log.Println(out)
		w.Write([]byte(out))
	})

	log.Printf("Listening on port %d...", *port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", *port), m)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>