<commit_before>package main

import (
	"os"

	"net/http"

	"github.com/codegangsta/negroni"
	"github.com/julienschmidt/httprouter"
)

func main() {
	// Setup Routes
	router := httprouter.New()
	router.RedirectTrailingSlash = false
	router.RedirectFixedPath = false

	router.GET("/", func(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.Write([]byte("{ \"code\":3.14159265359, \"description\":\"HI!\" }"))
	})

	// Setup Server
	n := negroni.New()
	n.Use(negroni.NewRecovery())
	n.UseHandler(router)

	// start server
	port := os.Getenv("PORT")

	if port == "" {
		port = "8080"
	}

	n.Run(":" + port)
}
<commit_msg>added POST at /<commit_after>package main

import (
	"os"

	"net/http"

	"github.com/codegangsta/negroni"
	"github.com/julienschmidt/httprouter"
)

func main() {
	// Setup Routes
	router := httprouter.New()
	router.RedirectTrailingSlash = false
	router.RedirectFixedPath = false

	router.GET("/", func(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.Write([]byte("{ \"code\":3.14159265359, \"description\":\"HI!\" }"))
	})

	router.POST("/", func(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.Write([]byte("{ \"code\":3.14159265359, \"description\":\"HI!\" }"))
	})

	// Setup Server
	n := negroni.New()
	n.Use(negroni.NewRecovery())
	n.UseHandler(router)

	// start server
	port := os.Getenv("PORT")

	if port == "" {
		port = "8080"
	}

	n.Run(":" + port)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Joshua Elliott
// Released under the MIT License
// http://opensource.org/licenses/MIT

package turnpike

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"fmt"
	"github.com/nu7hatch/gouuid"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
	"time"
)

var (
	// The amount of messages to buffer before sending to client.
	serverBacklog = 20
)

const (
	clientConnTimeout = 6
	clientMaxFailures = 3
)

// Server represents a WAMP server that handles RPC and pub/sub.
type Server struct {
	// Client ID -> send channel
	clients map[string]chan string
	// Client ID -> prefix mapping
	prefixes map[string]prefixMap
	// Proc URI -> handler
	rpcHandlers map[string]RPCHandler
	// Topic URI -> subscribed clients
	subscriptions       map[string]listenerMap
	subLock             *sync.Mutex
	sessionOpenCallback func(string)
	websocket.Server
}

// RPCHandler is an interface that handlers to RPC calls should implement.
// The first parameter is the call ID, the second is the proc URI. Last comes
// all optional arguments to the RPC call. The return can be of any type that
// can be marshaled to JSON, or a error (preferably RPCError but any error works.)
// NOTE: this may be broken in v2 if multiple-return is implemented
type RPCHandler func(clientID string, topicURI string, args ...interface{}) (interface{}, error)

// RPCError represents a call error and is the recommended way to return an
// error from a RPC handler.
type RPCError struct {
	URI         string
	Description string
	Details     interface{}
}

// Error returns an error description.
func (e RPCError) Error() string {
	return fmt.Sprintf("turnpike: RPC error with URI %s: %s", e.URI, e.Description)
}

// NewServer creates a new WAMP server.
func NewServer() *Server {
	s := &Server{
		clients:       make(map[string]chan string),
		subscriptions: make(map[string]listenerMap),
		prefixes:      make(map[string]prefixMap),
		rpcHandlers:   make(map[string]RPCHandler),
		subLock:       new(sync.Mutex),
	}
	s.Server = websocket.Server{
		Handshake: checkWAMPHandshake,
		Handler:   websocket.Handler(s.HandleWebsocket),
	}
	return s
}

// SetSessionOpenCallback adds a callback function that is run when a new session begins.
// The callback function must accept a string argument that is the session ID.
func (t *Server) SetSessionOpenCallback(f func(string)) {
	t.sessionOpenCallback = f
}

// RegisterRPC adds a handler for the RPC named uri.
func (t *Server) RegisterRPC(uri string, f RPCHandler) {
	if f != nil {
		t.rpcHandlers[uri] = f
	}
}

// UnregisterRPC removes a handler for the RPC named uri.
func (t *Server) UnregisterRPC(uri string) {
	delete(t.rpcHandlers, uri)
}

// SendEvent sends an event with topic directly (not via Client.Publish())
func (t *Server) SendEvent(topic string, event interface{}) {
	t.handlePublish(topic, publishMsg{
		TopicURI: topic,
		Event:    event,
	})
}

// HandleWebsocket implements the go.net/websocket.Handler interface.
func (t *Server) HandleWebsocket(conn *websocket.Conn) {
	defer conn.Close()

	if debug {
		log.Print("turnpike: received websocket connection")
	}

	tid, err := uuid.NewV4()
	if err != nil {
		if debug {
			log.Print("turnpike: could not create unique id, refusing client connection")
		}
		return
	}
	id := tid.String()
	if debug {
		log.Printf("turnpike: client connected: %s", id)
	}

	arr, err := createWelcome(id, turnpikeServerIdent)
	if err != nil {
		if debug {
			log.Print("turnpike: error encoding welcome message")
		}
		return
	}
	if debug {
		log.Printf("turnpike: sending welcome message: %s", arr)
	}
	err = websocket.Message.Send(conn, string(arr))
	if err != nil {
		if debug {
			log.Printf("turnpike: error sending welcome message, aborting connection: %s", err)
		}
		return
	}

	c := make(chan string, serverBacklog)
	t.clients[id] = c

	if t.sessionOpenCallback != nil {
		t.sessionOpenCallback(id)
	}

	failures := 0
	go func() {
		for msg := range c {
			if debug {
				log.Printf("turnpike: sending message: %s", msg)
			}
			conn.SetWriteDeadline(time.Now().Add(clientConnTimeout * time.Second))
			err := websocket.Message.Send(conn, msg)
			if err != nil {
				if nErr, ok := err.(net.Error); ok && (nErr.Timeout() || nErr.Temporary()) {
					log.Printf("Network error: %s", nErr)
					failures++
					if failures > clientMaxFailures {
						break
					}
				} else {
					if debug {
						log.Printf("turnpike: error sending message: %s", err)
					}
					break
				}
			}
		}
		if debug {
			log.Printf("Client %s disconnected", id)
		}
		conn.Close()
	}()

	for {
		var rec string
		err := websocket.Message.Receive(conn, &rec)
		if err != nil {
			if err != io.EOF {
				if debug {
					log.Printf("turnpike: error receiving message, aborting connection: %s", err)
				}
			}
			break
		}
		if debug {
			log.Printf("turnpike: message received: %s", rec)
		}

		data := []byte(rec)

		switch typ := parseMessageType(rec); typ {
		case msgPrefix:
			var msg prefixMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling prefix message: %s", err)
				}
				continue
			}
			t.handlePrefix(id, msg)
		case msgCall:
			var msg callMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling call message: %s", err)
				}
				continue
			}
			t.handleCall(id, msg)
		case msgSubscribe:
			var msg subscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling subscribe message: %s", err)
				}
				continue
			}
			t.handleSubscribe(id, msg)
		case msgUnsubscribe:
			var msg unsubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling unsubscribe message: %s", err)
				}
				continue
			}
			t.handleUnsubscribe(id, msg)
		case msgPublish:
			var msg publishMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling publish message: %s", err)
				}
				continue
			}
			t.handlePublish(id, msg)
		case msgWelcome, msgCallResult, msgCallError, msgEvent:
			if debug {
				log.Printf("turnpike: server -> client message received, ignored: %s", messageTypeString(typ))
			}
		default:
			if debug {
				log.Printf("turnpike: invalid message format, message dropped: %s", data)
			}
		}
	}

	delete(t.clients, id)
	close(c)
}

func (t *Server) handlePrefix(id string, msg prefixMsg) {
	if debug {
		log.Print("turnpike: handling prefix message")
	}
	if _, ok := t.prefixes[id]; !ok {
		t.prefixes[id] = make(prefixMap)
	}
	if err := t.prefixes[id].registerPrefix(msg.Prefix, msg.URI); err != nil {
		if debug {
			log.Printf("turnpike: error registering prefix: %s", err)
		}
	}
	if debug {
		log.Printf("turnpike: client %s registered prefix '%s' for URI: %s", id, msg.Prefix, msg.URI)
	}
}

func (t *Server) handleCall(id string, msg callMsg) {
	if debug {
		log.Print("turnpike: handling call message")
	}

	var out string
	var err error

	if f, ok := t.rpcHandlers[msg.ProcURI]; ok && f != nil {
		var res interface{}
		res, err = f(id, msg.ProcURI, msg.CallArgs...)
		if err != nil {
			var errorURI, desc string
			var details interface{}
			if er, ok := err.(RPCError); ok {
				errorURI = er.URI
				desc = er.Description
				details = er.Details
			} else {
				errorURI = msg.ProcURI + "#generic-error"
				desc = err.Error()
			}

			if details != nil {
				out, err = createCallError(msg.CallID, errorURI, desc, details)
			} else {
				out, err = createCallError(msg.CallID, errorURI, desc)
			}
		} else {
			out, err = createCallResult(msg.CallID, res)
		}
	} else {
		if debug {
			log.Printf("turnpike: RPC call not registered: %s", msg.ProcURI)
		}
		out, err = createCallError(msg.CallID, "error:notimplemented", "RPC call '%s' not implemented", msg.ProcURI)
	}

	if err != nil {
		// whatever, let the client hang...
		if debug {
			log.Printf("turnpike: error creating callError message: %s", err)
		}
		return
	}
	if client, ok := t.clients[id]; ok {
		client <- out
	}
}

func (t *Server) handleSubscribe(id string, msg subscribeMsg) {
	if debug {
		log.Print("turnpike: handling subscribe message")
	}
	t.subLock.Lock()
	topic := checkCurie(t.prefixes[id], msg.TopicURI)
	if _, ok := t.subscriptions[topic]; !ok {
		t.subscriptions[topic] = make(map[string]bool)
	}
	t.subscriptions[topic].add(id)
	t.subLock.Unlock()
	if debug {
		log.Printf("turnpike: client %s subscribed to topic: %s", id, topic)
	}
}

func (t *Server) handleUnsubscribe(id string, msg unsubscribeMsg) {
	if debug {
		log.Print("turnpike: handling unsubscribe message")
	}
	t.subLock.Lock()
	topic := checkCurie(t.prefixes[id], msg.TopicURI)
	if lm, ok := t.subscriptions[topic]; ok {
		lm.remove(id)
	}
	t.subLock.Unlock()
	if debug {
		log.Printf("turnpike: client %s unsubscribed from topic: %s", id, topic)
	}
}

func (t *Server) handlePublish(id string, msg publishMsg) {
	if debug {
		log.Print("turnpike: handling publish message")
	}
	topic := checkCurie(t.prefixes[id], msg.TopicURI)
	lm, ok := t.subscriptions[topic]
	if !ok {
		return
	}

	out, err := createEvent(topic, msg.Event)
	if err != nil {
		if debug {
			log.Printf("turnpike: error creating event message: %s", err)
		}
		return
	}

	var sendTo []string
	if len(msg.ExcludeList) > 0 || len(msg.EligibleList) > 0 {
		// this is super ugly, but I couldn't think of a better way...
		for tid := range lm {
			include := true
			for _, _tid := range msg.ExcludeList {
				if tid == _tid {
					include = false
					break
				}
			}
			if include {
				sendTo = append(sendTo, tid)
			}
		}

		for _, tid := range msg.EligibleList {
			include := true
			for _, _tid := range sendTo {
				if _tid == tid {
					include = false
					break
				}
			}
			if include {
				sendTo = append(sendTo, tid)
			}
		}
	} else {
		for tid := range lm {
			if tid == id && msg.ExcludeMe {
				continue
			}
			sendTo = append(sendTo, tid)
		}
	}

	for _, tid := range sendTo {
		// we're not locking anything, so we need
		// to make sure the client didn't disconnecct in the
		// last few nanoseconds...
		if client, ok := t.clients[tid]; ok {
			if len(client) == cap(client) {
				<-client
			}
			client <- string(out)
		}
	}
}

type listenerMap map[string]bool

func (lm listenerMap) add(id string) {
	lm[id] = true
}
func (lm listenerMap) contains(id string) bool {
	return lm[id]
}
func (lm listenerMap) remove(id string) {
	delete(lm, id)
}

func checkWAMPHandshake(config *websocket.Config, req *http.Request) error {
	for _, protocol := range config.Protocol {
		if protocol == "wamp" {
			config.Protocol = []string{protocol}
			return nil
		}
	}
	return websocket.ErrBadWebSocketProtocol
}
<commit_msg>Add pub/sub handlers<commit_after>// Copyright (c) 2013 Joshua Elliott
// Released under the MIT License
// http://opensource.org/licenses/MIT

package turnpike

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"fmt"
	"github.com/nu7hatch/gouuid"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
	"time"
)

var (
	// The amount of messages to buffer before sending to client.
	serverBacklog = 20
)

const (
	clientConnTimeout = 6
	clientMaxFailures = 3
)

// Server represents a WAMP server that handles RPC and pub/sub.
type Server struct {
	// Client ID -> send channel
	clients map[string]chan string
	// Client ID -> prefix mapping
	prefixes map[string]prefixMap
	// Proc URI -> handler
	rpcHandlers map[string]RPCHandler
	subHandlers map[string]SubHandler
	pubHandlers map[string]PubHandler
	// Topic URI -> subscribed clients
	subscriptions       map[string]listenerMap
	subLock             *sync.Mutex
	sessionOpenCallback func(string)
	websocket.Server
}

// RPCHandler is an interface that handlers to RPC calls should implement.
// The first parameter is the call ID, the second is the proc URI. Last comes
// all optional arguments to the RPC call. The return can be of any type that
// can be marshaled to JSON, or a error (preferably RPCError but any error works.)
// NOTE: this may be broken in v2 if multiple-return is implemented
type RPCHandler func(clientID string, topicURI string, args ...interface{}) (interface{}, error)

// RPCError represents a call error and is the recommended way to return an
// error from a RPC handler.
type RPCError struct {
	URI         string
	Description string
	Details     interface{}
}

// Error returns an error description.
func (e RPCError) Error() string {
	return fmt.Sprintf("turnpike: RPC error with URI %s: %s", e.URI, e.Description)
}

// SubHandler is an interface that handlers for subscriptions should implement to
// control with subscriptions are valid. A subscription is allowed by returning
// true or denied by returning false.
type SubHandler func(clientID string, topicURI string) bool

// PubHandler is an interface that handlers for publishes should implement to
// get notified on a client publish with the possibility to modify the event.
// The event that will be published should be returned.
type PubHandler func(topicURI string, event interface{}) interface{}

// NewServer creates a new WAMP server.
func NewServer() *Server {
	s := &Server{
		clients:       make(map[string]chan string),
		prefixes:      make(map[string]prefixMap),
		rpcHandlers:   make(map[string]RPCHandler),
		subHandlers:   make(map[string]SubHandler),
		pubHandlers:   make(map[string]PubHandler),
		subscriptions: make(map[string]listenerMap),
		subLock:       new(sync.Mutex),
	}
	s.Server = websocket.Server{
		Handshake: checkWAMPHandshake,
		Handler:   websocket.Handler(s.HandleWebsocket),
	}
	return s
}

// SetSessionOpenCallback adds a callback function that is run when a new session begins.
// The callback function must accept a string argument that is the session ID.
func (t *Server) SetSessionOpenCallback(f func(string)) {
	t.sessionOpenCallback = f
}

// RegisterRPC adds a handler for the RPC named uri.
func (t *Server) RegisterRPC(uri string, f RPCHandler) {
	if f != nil {
		t.rpcHandlers[uri] = f
	}
}

// UnregisterRPC removes a handler for the RPC named uri.
func (t *Server) UnregisterRPC(uri string) {
	delete(t.rpcHandlers, uri)
}

// RegisterSubHandler adds a handler called when a client subscribes to URI.
// The subscription can be canceled in the handler by returning false, or
// approved by returning true.
func (t *Server) RegisterSubHandler(uri string, f SubHandler) {
	if f != nil {
		t.subHandlers[uri] = f
	}
}

// UnregisterSubHandler removes a subscription handler for the URI.
func (t *Server) UnregisterSubHandler(uri string) {
	delete(t.subHandlers, uri)
}

// RegisterPubHandler adds a handler called when a client publishes to URI.
// The event can be modified in the handler and the returned event is what is
// published to the other clients.
func (t *Server) RegisterPubHandler(uri string, f PubHandler) {
	if f != nil {
		t.pubHandlers[uri] = f
	}
}

// UnregisterPubHandler removes a publish handler for the URI.
func (t *Server) UnregisterPubHandler(uri string) {
	delete(t.pubHandlers, uri)
}

// SendEvent sends an event with topic directly (not via Client.Publish())
func (t *Server) SendEvent(topic string, event interface{}) {
	t.handlePublish(topic, publishMsg{
		TopicURI: topic,
		Event:    event,
	})
}

// HandleWebsocket implements the go.net/websocket.Handler interface.
func (t *Server) HandleWebsocket(conn *websocket.Conn) {
	defer conn.Close()

	if debug {
		log.Print("turnpike: received websocket connection")
	}

	tid, err := uuid.NewV4()
	if err != nil {
		if debug {
			log.Print("turnpike: could not create unique id, refusing client connection")
		}
		return
	}
	id := tid.String()
	if debug {
		log.Printf("turnpike: client connected: %s", id)
	}

	arr, err := createWelcome(id, turnpikeServerIdent)
	if err != nil {
		if debug {
			log.Print("turnpike: error encoding welcome message")
		}
		return
	}
	if debug {
		log.Printf("turnpike: sending welcome message: %s", arr)
	}
	err = websocket.Message.Send(conn, string(arr))
	if err != nil {
		if debug {
			log.Printf("turnpike: error sending welcome message, aborting connection: %s", err)
		}
		return
	}

	c := make(chan string, serverBacklog)
	t.clients[id] = c

	if t.sessionOpenCallback != nil {
		t.sessionOpenCallback(id)
	}

	failures := 0
	go func() {
		for msg := range c {
			if debug {
				log.Printf("turnpike: sending message: %s", msg)
			}
			conn.SetWriteDeadline(time.Now().Add(clientConnTimeout * time.Second))
			err := websocket.Message.Send(conn, msg)
			if err != nil {
				if nErr, ok := err.(net.Error); ok && (nErr.Timeout() || nErr.Temporary()) {
					log.Printf("Network error: %s", nErr)
					failures++
					if failures > clientMaxFailures {
						break
					}
				} else {
					if debug {
						log.Printf("turnpike: error sending message: %s", err)
					}
					break
				}
			}
		}
		if debug {
			log.Printf("Client %s disconnected", id)
		}
		conn.Close()
	}()

	for {
		var rec string
		err := websocket.Message.Receive(conn, &rec)
		if err != nil {
			if err != io.EOF {
				if debug {
					log.Printf("turnpike: error receiving message, aborting connection: %s", err)
				}
			}
			break
		}
		if debug {
			log.Printf("turnpike: message received: %s", rec)
		}

		data := []byte(rec)

		switch typ := parseMessageType(rec); typ {
		case msgPrefix:
			var msg prefixMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling prefix message: %s", err)
				}
				continue
			}
			t.handlePrefix(id, msg)
		case msgCall:
			var msg callMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling call message: %s", err)
				}
				continue
			}
			t.handleCall(id, msg)
		case msgSubscribe:
			var msg subscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling subscribe message: %s", err)
				}
				continue
			}
			t.handleSubscribe(id, msg)
		case msgUnsubscribe:
			var msg unsubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling unsubscribe message: %s", err)
				}
				continue
			}
			t.handleUnsubscribe(id, msg)
		case msgPublish:
			var msg publishMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling publish message: %s", err)
				}
				continue
			}
			t.handlePublish(id, msg)
		case msgWelcome, msgCallResult, msgCallError, msgEvent:
			if debug {
				log.Printf("turnpike: server -> client message received, ignored: %s", messageTypeString(typ))
			}
		default:
			if debug {
				log.Printf("turnpike: invalid message format, message dropped: %s", data)
			}
		}
	}

	delete(t.clients, id)
	close(c)
}

func (t *Server) handlePrefix(id string, msg prefixMsg) {
	if debug {
		log.Print("turnpike: handling prefix message")
	}
	if _, ok := t.prefixes[id]; !ok {
		t.prefixes[id] = make(prefixMap)
	}
	if err := t.prefixes[id].registerPrefix(msg.Prefix, msg.URI); err != nil {
		if debug {
			log.Printf("turnpike: error registering prefix: %s", err)
		}
	}
	if debug {
		log.Printf("turnpike: client %s registered prefix '%s' for URI: %s", id, msg.Prefix, msg.URI)
	}
}

func (t *Server) handleCall(id string, msg callMsg) {
	if debug {
		log.Print("turnpike: handling call message")
	}

	var out string
	var err error

	if f, ok := t.rpcHandlers[msg.ProcURI]; ok && f != nil {
		var res interface{}
		res, err = f(id, msg.ProcURI, msg.CallArgs...)
		if err != nil {
			var errorURI, desc string
			var details interface{}
			if er, ok := err.(RPCError); ok {
				errorURI = er.URI
				desc = er.Description
				details = er.Details
			} else {
				errorURI = msg.ProcURI + "#generic-error"
				desc = err.Error()
			}

			if details != nil {
				out, err = createCallError(msg.CallID, errorURI, desc, details)
			} else {
				out, err = createCallError(msg.CallID, errorURI, desc)
			}
		} else {
			out, err = createCallResult(msg.CallID, res)
		}
	} else {
		if debug {
			log.Printf("turnpike: RPC call not registered: %s", msg.ProcURI)
		}
		out, err = createCallError(msg.CallID, "error:notimplemented", "RPC call '%s' not implemented", msg.ProcURI)
	}

	if err != nil {
		// whatever, let the client hang...
		if debug {
			log.Printf("turnpike: error creating callError message: %s", err)
		}
		return
	}
	if client, ok := t.clients[id]; ok {
		client <- out
	}
}

func (t *Server) handleSubscribe(id string, msg subscribeMsg) {
	if debug {
		log.Print("turnpike: handling subscribe message")
	}

	uri := checkCurie(t.prefixes[id], msg.TopicURI)
	h := t.getSubHandler(uri)
	if !h(id, uri) {
		if debug {
			log.Printf("turnpike: client %s denied subscription of topic: %s", id, uri)
		}
		return
	}

	t.subLock.Lock()
	defer t.subLock.Unlock()
	if _, ok := t.subscriptions[uri]; !ok {
		t.subscriptions[uri] = make(map[string]bool)
	}
	t.subscriptions[uri].add(id)
	if debug {
		log.Printf("turnpike: client %s subscribed to topic: %s", id, uri)
	}
}

func (t *Server) handleUnsubscribe(id string, msg unsubscribeMsg) {
	if debug {
		log.Print("turnpike: handling unsubscribe message")
	}
	t.subLock.Lock()
	topic := checkCurie(t.prefixes[id], msg.TopicURI)
	if lm, ok := t.subscriptions[topic]; ok {
		lm.remove(id)
	}
	t.subLock.Unlock()
	if debug {
		log.Printf("turnpike: client %s unsubscribed from topic: %s", id, topic)
	}
}

func (t *Server) handlePublish(id string, msg publishMsg) {
	if debug {
		log.Print("turnpike: handling publish message")
	}
	topic := checkCurie(t.prefixes[id], msg.TopicURI)
	lm, ok := t.subscriptions[topic]
	if !ok {
		return
	}

	out, err := createEvent(topic, msg.Event)
	if err != nil {
		if debug {
			log.Printf("turnpike: error creating event message: %s", err)
		}
		return
	}

	var sendTo []string
	if len(msg.ExcludeList) > 0 || len(msg.EligibleList) > 0 {
		// this is super ugly, but I couldn't think of a better way...
		for tid := range lm {
			include := true
			for _, _tid := range msg.ExcludeList {
				if tid == _tid {
					include = false
					break
				}
			}
			if include {
				sendTo = append(sendTo, tid)
			}
		}

		for _, tid := range msg.EligibleList {
			include := true
			for _, _tid := range sendTo {
				if _tid == tid {
					include = false
					break
				}
			}
			if include {
				sendTo = append(sendTo, tid)
			}
		}
	} else {
		for tid := range lm {
			if tid == id && msg.ExcludeMe {
				continue
			}
			sendTo = append(sendTo, tid)
		}
	}

	for _, tid := range sendTo {
		// we're not locking anything, so we need
		// to make sure the client didn't disconnecct in the
		// last few nanoseconds...
		if client, ok := t.clients[tid]; ok {
			if len(client) == cap(client) {
				<-client
			}
			client <- string(out)
		}
	}
}

func (t *Server) getSubHandler(uri string) SubHandler {
	for i := len(uri); i >= 0; i-- {
		u := uri[:i]
		if h, ok := t.subHandlers[u]; ok {
			return h
		}
	}
	return nil
}

func (t *Server) getPubHandler(uri string) PubHandler {
	for i := len(uri); i >= 0; i-- {
		u := uri[:i]
		if h, ok := t.pubHandlers[u]; ok {
			return h
		}
	}
	return nil
}

type listenerMap map[string]bool

func (lm listenerMap) add(id string) {
	lm[id] = true
}
func (lm listenerMap) contains(id string) bool {
	return lm[id]
}
func (lm listenerMap) remove(id string) {
	delete(lm, id)
}

func checkWAMPHandshake(config *websocket.Config, req *http.Request) error {
	for _, protocol := range config.Protocol {
		if protocol == "wamp" {
			config.Protocol = []string{protocol}
			return nil
		}
	}
	return websocket.ErrBadWebSocketProtocol
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/UniversityRadioYork/2016-site/controllers"
	"github.com/UniversityRadioYork/2016-site/structs"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Server is the type of the main 2016site web application.
type Server struct {
	*negroni.Negroni
}

// NewServer creates a 2016site server based on the config c.
func NewServer(c *structs.Config) (*Server, error) {

	s := Server{negroni.Classic()}

	session, err := myradio.NewSessionFromKeyFile()

	if err != nil {
		return &s, err
	}

	router := mux.NewRouter().StrictSlash(true)

	getRouter := router.Methods("GET").Subrouter()
	postRouter := router.Methods("POST").Subrouter()

	// Routes go in here
	nfc := controllers.NewNotFoundController(c)
	router.NotFoundHandler = http.HandlerFunc(nfc.Get)

	ic := controllers.NewIndexController(session, c)
	getRouter.HandleFunc("/", ic.Get)
	postRouter.HandleFunc("/", ic.Post)

	sc := controllers.NewSearchController(session, c)
	getRouter.HandleFunc("/search/", sc.Get)

	showC := controllers.NewShowController(session, c)
	getRouter.HandleFunc("/schedule/shows/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	getRouter.HandleFunc("/schedule/shows/{id:[0-9]+}/", showC.GetShow).Name("show")
	getRouter.HandleFunc("/schedule/shows/timeslots/{id:[0-9]+}/", showC.GetTimeslot).Name("timeslot")
	getRouter.HandleFunc("/schedule/shows/seasons/{id:[0-9]+}/", showC.GetSeason).Name("season")

	getRouter.HandleFunc("/schedule/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	// NOTE: NewScheduleWeekController assumes 'timeslot' is installed BEFORE it is called.
	schedWeekC := controllers.NewScheduleWeekController(session, getRouter, c)
	getRouter.HandleFunc("/schedule/thisweek/", schedWeekC.GetThisWeek).Name("schedule-thisweek")

	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/", schedWeekC.GetByYearWeek).Name("schedule-week")
	// This route exists so that day schedule links from the previous website aren't broken.
	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/{day:[1-7]}/", schedWeekC.GetByYearWeek).Name("schedule-week-day-compat")

	onDemandC := controllers.NewOnDemandController(session, c)
	getRouter.HandleFunc("/ontap/", onDemandC.Get)

	podcastsC := controllers.NewPodcastController(session, c)
	getRouter.HandleFunc("/podcasts/", podcastsC.GetAllPodcasts)
	getRouter.HandleFunc("/podcasts/page/{page:[0-9]+}", podcastsC.GetAllPodcasts)
	getRouter.HandleFunc("/podcasts/{id:[0-9]+}/", podcastsC.Get)
	getRouter.HandleFunc("/podcasts/{id:[0-9]+}/player/", podcastsC.GetEmbed)
	// Redirect old podcast URLs
	getRouter.HandleFunc("/uryplayer/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/ontap/", 301)
	})
	getRouter.HandleFunc("/listen/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/about/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/podcasts/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		http.Redirect(w, r, fmt.Sprintf("/podcasts/%d/", id), 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/player/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		http.Redirect(w, r, fmt.Sprintf("/podcasts/%d/player/", id), 301)
	})

	pc := controllers.NewPeopleController(session, c)
	getRouter.HandleFunc("/people/{id:[0-9]+}/", pc.Get)

	teamC := controllers.NewTeamController(session, c)
	getRouter.HandleFunc("/teams/", teamC.GetAll)
	getRouter.HandleFunc("/teams/{alias}/", teamC.Get)

	getinvolvedC := controllers.NewGetInvolvedController(session, c)
	getRouter.HandleFunc("/getinvolved/", getinvolvedC.Get)

	signupC := controllers.NewSignUpController(session, c)
	postRouter.HandleFunc("/signup/", signupC.Post)

	staticC := controllers.NewStaticController(c)
	getRouter.HandleFunc("/about/", staticC.GetAbout)
	getRouter.HandleFunc("/contact/", staticC.GetContact)
	getRouter.HandleFunc("/competitions/", staticC.GetCompetitions)
	getRouter.HandleFunc("/cin/", staticC.GetCIN)

	// End routes

	s.UseHandler(router)

	return &s, nil

}
<commit_msg>Added conditional to routing<commit_after>package main

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/UniversityRadioYork/2016-site/controllers"
	"github.com/UniversityRadioYork/2016-site/structs"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Server is the type of the main 2016site web application.
type Server struct {
	*negroni.Negroni
}

// NewServer creates a 2016site server based on the config c.
func NewServer(c *structs.Config) (*Server, error) {

	s := Server{negroni.Classic()}

	session, err := myradio.NewSessionFromKeyFile()

	if err != nil {
		return &s, err
	}

	router := mux.NewRouter().StrictSlash(true)

	getRouter := router.Methods("GET").Subrouter()
	postRouter := router.Methods("POST").Subrouter()

	// Routes go in here
	nfc := controllers.NewNotFoundController(c)
	router.NotFoundHandler = http.HandlerFunc(nfc.Get)

	ic := controllers.NewIndexController(session, c)
	getRouter.HandleFunc("/", ic.Get)
	postRouter.HandleFunc("/", ic.Post)

	sc := controllers.NewSearchController(session, c)
	getRouter.HandleFunc("/search/", sc.Get)

	showC := controllers.NewShowController(session, c)
	getRouter.HandleFunc("/schedule/shows/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	getRouter.HandleFunc("/schedule/shows/{id:[0-9]+}/", showC.GetShow).Name("show")
	getRouter.HandleFunc("/schedule/shows/timeslots/{id:[0-9]+}/", showC.GetTimeslot).Name("timeslot")
	getRouter.HandleFunc("/schedule/shows/seasons/{id:[0-9]+}/", showC.GetSeason).Name("season")

	getRouter.HandleFunc("/schedule/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	// NOTE: NewScheduleWeekController assumes 'timeslot' is installed BEFORE it is called.
	schedWeekC := controllers.NewScheduleWeekController(session, getRouter, c)
	getRouter.HandleFunc("/schedule/thisweek/", schedWeekC.GetThisWeek).Name("schedule-thisweek")

	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/", schedWeekC.GetByYearWeek).Name("schedule-week")
	// This route exists so that day schedule links from the previous website aren't broken.
	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/{day:[1-7]}/", schedWeekC.GetByYearWeek).Name("schedule-week-day-compat")

	onDemandC := controllers.NewOnDemandController(session, c)
	getRouter.HandleFunc("/ontap/", onDemandC.Get)

	podcastsC := controllers.NewPodcastController(session, c)
	getRouter.HandleFunc("/podcasts/", podcastsC.GetAllPodcasts)
	getRouter.HandleFunc("/podcasts/page/{page:[0-9]+}", podcastsC.GetAllPodcasts)
	getRouter.HandleFunc("/podcasts/{id:[0-9]+}/", podcastsC.Get)
	getRouter.HandleFunc("/podcasts/{id:[0-9]+}/player/", podcastsC.GetEmbed)
	// Redirect old podcast URLs
	getRouter.HandleFunc("/uryplayer/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/ontap/", 301)
	})
	getRouter.HandleFunc("/listen/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/about/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/podcasts/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		http.Redirect(w, r, fmt.Sprintf("/podcasts/%d/", id), 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/player/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		http.Redirect(w, r, fmt.Sprintf("/podcasts/%d/player/", id), 301)
	})

	pc := controllers.NewPeopleController(session, c)
	getRouter.HandleFunc("/people/{id:[0-9]+}/", pc.Get)

	teamC := controllers.NewTeamController(session, c)
	getRouter.HandleFunc("/teams/", teamC.GetAll)
	getRouter.HandleFunc("/teams/{alias}/", teamC.Get)

	getinvolvedC := controllers.NewGetInvolvedController(session, c)
	getRouter.HandleFunc("/getinvolved/", getinvolvedC.Get)

	signupC := controllers.NewSignUpController(session, c)
	postRouter.HandleFunc("/signup/", signupC.Post)

	staticC := controllers.NewStaticController(c)
	getRouter.HandleFunc("/about/", staticC.GetAbout)
	getRouter.HandleFunc("/contact/", staticC.GetContact)
	getRouter.HandleFunc("/competitions/", staticC.GetCompetitions)
	if(c.PageContext.CIN) {
		getRouter.HandleFunc("/cin/", staticC.GetCIN)
	}
	// End routes

	s.UseHandler(router)

	return &s, nil

}
<|endoftext|>


<commit_before>package main

import (
    "net/http"
    "log"
    "encoding/json"
    "crypto/md5"
    "time"
    "io"
    "fmt"
    "sync"
    _ "net/http/pprof"

    "code.google.com/p/go.net/websocket"
)

var DEBUG bool
var CLIENT_BROAD bool

type Server struct {
    ID      string
    Config  *Configuration
    Store   *Storage
}

func createServer(conf *Configuration, store *Storage) *Server{
    hash := md5.New()
    io.WriteString(hash, time.Now().String())
    id := string(hash.Sum(nil))

    return &Server{id, conf, store}
}

func main() {
    defer func() {
        if err := recover(); err != nil {
            log.Println("FATAL: ", err)

            log.Println("clearing redis memory")
            log.Println("Shutting down")
        }
    }()

    conf  := initConfig()
    store := initStore(&conf)
    initLogger(conf)

    go func() {
        for {
            log.Println(store.memory.clientCount)
            time.Sleep(20 * time.Second)
        }
    }()

    CLIENT_BROAD = conf.GetBool("client_broadcasts")
    server := createServer(&conf, &store)

    go server.initAppListner()
    go server.initSocketListener()

    listenAddr := fmt.Sprintf(":%s", conf.Get("listening_port"))

    http.HandleFunc("/ping", pingHandler)
    err := http.ListenAndServe(listenAddr, nil)
    if err != nil {
        log.Fatal(err)
    }
}

func (this *Server) initSocketListener() {
    Connect := func(ws *websocket.Conn) {
        sock := newSocket(ws, this, "")

        if DEBUG { log.Printf("Socket connected via %s\n", ws.RemoteAddr()) }
        if err := sock.Authenticate(); err != nil {
            if DEBUG { log.Printf("Error: %s\n", err.Error()) }
            return
        }

        var wg sync.WaitGroup
        wg.Add(2)

        go sock.listenForMessages(&wg)
        go sock.listenForWrites(&wg)

        wg.Wait()
        if DEBUG { log.Println("Socket Closed") }
    }

    http.Handle("/socket", websocket.Handler(Connect))
}

func (this *Server) initAppListner() {
    rec := make(chan []string)

    consumer, err := this.Store.redis.Subscribe(rec, "Message")
    if err != nil {
        log.Fatal("Couldn't subscribe to redis channel")
    }
    defer consumer.Quit()

    if DEBUG { log.Println("LISENING FOR REDIS MESSAGE") }
    var ms []string
    for {
        var msg Message
        ms = <- rec
        json.Unmarshal([]byte(ms[2]), &msg)
        go msg.FromRedis(this)

        if DEBUG { log.Printf("Received %v\n", msg.Event) }
    }
}

func pingHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "OK")
}

<commit_msg>added signal handlers<commit_after>package main

import (
    "net/http"
    "log"
    "encoding/json"
    "crypto/md5"
    "time"
    "io"
    "fmt"
    "sync"
    "os"
    "os/signal"
    "syscall"
    _ "net/http/pprof"

    "code.google.com/p/go.net/websocket"
)

var DEBUG bool
var CLIENT_BROAD bool

type Server struct {
    ID      string
    Config  *Configuration
    Store   *Storage
}

func createServer(conf *Configuration, store *Storage) *Server{
    hash := md5.New()
    io.WriteString(hash, time.Now().String())
    id := string(hash.Sum(nil))

    return &Server{id, conf, store}
}

func main() {
    defer func() {
        if err := recover(); err != nil {
            log.Println("FATAL: ", err)

            log.Println("clearing redis memory...")
            log.Println("Shutting down...")
        }
    }()

    conf  := initConfig()
    store := initStore(&conf)
    initLogger(conf)

    go func() {
        for {
            log.Println(store.memory.clientCount)
            time.Sleep(20 * time.Second)
        }
    }()

    signals := make(chan os.Signal, 1)
    signal.Notify(signals, syscall.SIGINT, syscall.SIGUSR1)
    InstallSignalHandlers(signals)

    CLIENT_BROAD = conf.GetBool("client_broadcasts")
    server := createServer(&conf, &store)

    go server.initAppListner()
    go server.initSocketListener()

    listenAddr := fmt.Sprintf(":%s", conf.Get("listening_port"))

    http.HandleFunc("/ping", pingHandler)
    err := http.ListenAndServe(listenAddr, nil)
    if err != nil {
        log.Fatal(err)
    }
}

func (this *Server) initSocketListener() {
    Connect := func(ws *websocket.Conn) {
        sock := newSocket(ws, this, "")

        if DEBUG { log.Printf("Socket connected via %s\n", ws.RemoteAddr()) }
        if err := sock.Authenticate(); err != nil {
            if DEBUG { log.Printf("Error: %s\n", err.Error()) }
            return
        }

        var wg sync.WaitGroup
        wg.Add(2)

        go sock.listenForMessages(&wg)
        go sock.listenForWrites(&wg)

        wg.Wait()
        if DEBUG { log.Println("Socket Closed") }
    }

    http.Handle("/socket", websocket.Handler(Connect))
}

func (this *Server) initAppListner() {
    rec := make(chan []string)

    consumer, err := this.Store.redis.Subscribe(rec, "Message")
    if err != nil {
        log.Fatal("Couldn't subscribe to redis channel")
    }
    defer consumer.Quit()

    if DEBUG { log.Println("LISENING FOR REDIS MESSAGE") }
    var ms []string
    for {
        var msg Message
        ms = <- rec
        json.Unmarshal([]byte(ms[2]), &msg)
        go msg.FromRedis(this)

        if DEBUG { log.Printf("Received %v\n", msg.Event) }
    }
}

func pingHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "OK")
}

func InstallSignalHandlers(signals chan os.Signal) {
    go func() {
        sig := <-signals
        switch sig {
        case syscall.SIGINT:
            log.Println("\nCtrl-C signalled\n")
            os.Exit(0)
        }
    }()
}

<|endoftext|>


<commit_before>package main

import (
	"github.com/cenkalti/backoff"
	"github.com/golang/groupcache/lru"
	"github.com/mitchellh/colorstring"
	"log"
	"time"
)

type SyncServer struct {
	Spotify   *Spotify
	Radio     *Radio
	Interval  time.Duration
	Adaptive  bool
	CacheSize int
	playlist  *Playlist
	cache     *lru.Cache
}

func logColorf(format string, v ...interface{}) {
	log.Printf(colorstring.Color(format), v...)
}

func (sync *SyncServer) isCached(track *Track) bool {
	_, exists := sync.cache.Get(track.Id)
	return exists
}

func (sync *SyncServer) addTrack(track *Track) {
	if !sync.isCached(track) {
		sync.cache.Add(track.Id, track)
	}
}

func (sync *SyncServer) initPlaylist() error {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(5 * time.Minute)
	ticker := backoff.NewTicker(b)
	var playlist *Playlist
	var err error
	for _ = range ticker.C {
		playlist, err = sync.Spotify.GetOrCreatePlaylist(
			sync.Radio.Name)
		if err != nil {
			log.Printf("Failed to get playlist: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	if err != nil {
		return err
	}
	sync.playlist = playlist
	return nil
}

func (sync *SyncServer) initCache() error {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(5 * time.Minute)
	ticker := backoff.NewTicker(b)
	var tracks []PlaylistTrack
	var err error
	for _ = range ticker.C {
		tracks, err = sync.Spotify.RecentTracks(sync.playlist)
		if err != nil {
			log.Printf("Failed to get recent tracks: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	if err != nil {
		return err
	}
	sync.cache = lru.New(sync.CacheSize)
	for _, t := range tracks {
		sync.addTrack(&t.Track)
	}
	return nil
}

func (sync *SyncServer) Serve() {
	log.Printf("Server started")

	log.Print("Initializing Spotify playlist")
	if err := sync.initPlaylist(); err != nil {
		log.Fatalf("Failed to initialize playlist: %s", err)
	}
	log.Printf("Playlist: %s", sync.playlist.String())

	log.Print("Initializing cache")
	if err := sync.initCache(); err != nil {
		log.Fatalf("Failed to init cache: %s", err)
	}
	log.Printf("Size: %d/%d", sync.cache.Len(), sync.cache.MaxEntries)

	if sync.Adaptive {
		log.Print("Automatically determining interval")
	} else {
		log.Printf("Syncing every %s", sync.Interval)
	}
	for {
		select {
		case <-sync.scheduleRun():
		}
	}
}

func (sync *SyncServer) scheduleRun() <-chan time.Time {
	duration, err := sync.run()
	if err != nil {
		log.Printf("Sync failed: %s\n", err)
		log.Print("Retrying in 1 minute")
		return time.After(1 * time.Minute)
	}
	log.Printf("Next sync in %s", duration)
	return time.After(duration)
}

func (sync *SyncServer) retryPlaylist() (*RadioPlaylist, error) {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(1 * time.Minute)
	ticker := backoff.NewTicker(b)
	var playlist *RadioPlaylist
	var err error
	for _ = range ticker.C {
		playlist, err = sync.Radio.Playlist()
		if err != nil {
			log.Printf("Retrieving radio playlist failed: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	return playlist, err
}

func (sync *SyncServer) retrySearch(track *RadioTrack) ([]Track, error) {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(1 * time.Minute)
	ticker := backoff.NewTicker(b)
	var tracks []Track
	var err error
	for _ = range ticker.C {
		tracks, err = sync.Spotify.SearchArtistTrack(track.Artist,
			track.Track)
		if err != nil {
			log.Printf("Search failed: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	return tracks, err
}

func (sync *SyncServer) retryAddTrack(track *Track) error {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(1 * time.Minute)
	ticker := backoff.NewTicker(b)
	var err error
	for _ = range ticker.C {
		err = sync.Spotify.AddTrack(sync.playlist, track)
		if err != nil {
			log.Printf("Add track failed: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	return err
}

func (sync *SyncServer) logCurrentTrack(playlist *RadioPlaylist) {
	current, err := playlist.Current()
	if err != nil {
		logColorf("[red]Failed to get current track: %s[reset]", err)
		return
	}
	position, err := current.Position()
	if err != nil {
		logColorf("[red]Failed to parse metadata: %s[reset]", err)
		return
	}
	logColorf("[cyan]%s is currently playing: %s - %s[reset] (%s) [%s]",
		sync.Radio.Name, current.Artist, current.Track,
		position.String(), position.Symbol(10, true))
}

func (sync *SyncServer) run() (time.Duration, error) {
	logColorf("[light_magenta]Running sync[reset]")

	radioPlaylist, err := sync.retryPlaylist()
	if err != nil {
		return time.Duration(0), err
	}
	sync.logCurrentTrack(radioPlaylist)

	radioTracks, err := radioPlaylist.CurrentAndNext()
	if err != nil {
		return time.Duration(0), err
	}
	added := 0
	for _, t := range radioTracks {
		logColorf("Searching for: %s", t.String())
		if !t.IsMusic() {
			logColorf("[yellow]Not music, skipping: %s[reset]",
				t.String())
			continue
		}
		tracks, err := sync.retrySearch(&t)
		if err != nil {
			logColorf("[red]Search failed: %s (%s)[reset]",
				t.String(), err)
			continue
		}
		if len(tracks) == 0 {
			logColorf("[yellow]Track not found: %s[reset]",
				t.String())
			continue
		}
		track := &tracks[0]
		if sync.isCached(track) {
			logColorf("[blue]Already added: %s[reset]",
				track.String())
			added++
			continue
		}
		if err = sync.retryAddTrack(track); err != nil {
			logColorf("[red]Failed to add: %s (%s)[reset]",
				track.String(), err)
			continue
		}
		sync.addTrack(track)
		added++
		logColorf("[green]Added track: %s[reset]", track.String())
	}
	log.Printf("Cache size: %d/%d", sync.cache.Len(),
		sync.cache.MaxEntries)
	if !sync.Adaptive {
		return sync.Interval, nil
	}
	if added != len(radioTracks) {
		log.Printf("%d/%d tracks were added. Falling back to "+
			" regular interval", added, len(radioTracks))
		return sync.Interval, nil
	}
	return radioPlaylist.NextSync()
}
<commit_msg>Use interval when sync fails completely<commit_after>package main

import (
	"github.com/cenkalti/backoff"
	"github.com/golang/groupcache/lru"
	"github.com/mitchellh/colorstring"
	"log"
	"time"
)

type SyncServer struct {
	Spotify   *Spotify
	Radio     *Radio
	Interval  time.Duration
	Adaptive  bool
	CacheSize int
	playlist  *Playlist
	cache     *lru.Cache
}

func logColorf(format string, v ...interface{}) {
	log.Printf(colorstring.Color(format), v...)
}

func (sync *SyncServer) isCached(track *Track) bool {
	_, exists := sync.cache.Get(track.Id)
	return exists
}

func (sync *SyncServer) addTrack(track *Track) {
	if !sync.isCached(track) {
		sync.cache.Add(track.Id, track)
	}
}

func (sync *SyncServer) initPlaylist() error {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(5 * time.Minute)
	ticker := backoff.NewTicker(b)
	var playlist *Playlist
	var err error
	for _ = range ticker.C {
		playlist, err = sync.Spotify.GetOrCreatePlaylist(
			sync.Radio.Name)
		if err != nil {
			log.Printf("Failed to get playlist: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	if err != nil {
		return err
	}
	sync.playlist = playlist
	return nil
}

func (sync *SyncServer) initCache() error {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(5 * time.Minute)
	ticker := backoff.NewTicker(b)
	var tracks []PlaylistTrack
	var err error
	for _ = range ticker.C {
		tracks, err = sync.Spotify.RecentTracks(sync.playlist)
		if err != nil {
			log.Printf("Failed to get recent tracks: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	if err != nil {
		return err
	}
	sync.cache = lru.New(sync.CacheSize)
	for _, t := range tracks {
		sync.addTrack(&t.Track)
	}
	return nil
}

func (sync *SyncServer) Serve() {
	log.Printf("Server started")

	log.Print("Initializing Spotify playlist")
	if err := sync.initPlaylist(); err != nil {
		log.Fatalf("Failed to initialize playlist: %s", err)
	}
	log.Printf("Playlist: %s", sync.playlist.String())

	log.Print("Initializing cache")
	if err := sync.initCache(); err != nil {
		log.Fatalf("Failed to init cache: %s", err)
	}
	log.Printf("Size: %d/%d", sync.cache.Len(), sync.cache.MaxEntries)

	if sync.Adaptive {
		log.Print("Using adaptive interval")
	} else {
		log.Printf("Syncing every %s", sync.Interval)
	}
	for {
		select {
		case <-sync.runForever():
		}
	}
}

func (sync *SyncServer) runForever() <-chan time.Time {
	duration, err := sync.run()
	if err != nil {
		log.Printf("Sync failed: %s", err)
		duration = sync.Interval
	}
	log.Printf("Next sync in %s", duration)
	return time.After(duration)
}

func (sync *SyncServer) retryPlaylist() (*RadioPlaylist, error) {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(1 * time.Minute)
	ticker := backoff.NewTicker(b)
	var playlist *RadioPlaylist
	var err error
	for _ = range ticker.C {
		playlist, err = sync.Radio.Playlist()
		if err != nil {
			log.Printf("Retrieving radio playlist failed: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	return playlist, err
}

func (sync *SyncServer) retrySearch(track *RadioTrack) ([]Track, error) {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(1 * time.Minute)
	ticker := backoff.NewTicker(b)
	var tracks []Track
	var err error
	for _ = range ticker.C {
		tracks, err = sync.Spotify.SearchArtistTrack(track.Artist,
			track.Track)
		if err != nil {
			log.Printf("Search failed: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	return tracks, err
}

func (sync *SyncServer) retryAddTrack(track *Track) error {
	b := backoff.NewExponentialBackOff()
	b.MaxElapsedTime = time.Duration(1 * time.Minute)
	ticker := backoff.NewTicker(b)
	var err error
	for _ = range ticker.C {
		err = sync.Spotify.AddTrack(sync.playlist, track)
		if err != nil {
			log.Printf("Add track failed: %s", err)
			log.Println("Retrying...")
			continue
		}
		break
	}
	return err
}

func (sync *SyncServer) logCurrentTrack(playlist *RadioPlaylist) {
	current, err := playlist.Current()
	if err != nil {
		logColorf("[red]Failed to get current track: %s[reset]", err)
		return
	}
	position, err := current.Position()
	if err != nil {
		logColorf("[red]Failed to parse metadata: %s[reset]", err)
		return
	}
	logColorf("[cyan]%s is currently playing: %s - %s[reset] (%s) [%s]",
		sync.Radio.Name, current.Artist, current.Track,
		position.String(), position.Symbol(10, true))
}

func (sync *SyncServer) run() (time.Duration, error) {
	logColorf("[light_magenta]Running sync[reset]")

	radioPlaylist, err := sync.retryPlaylist()
	if err != nil {
		return time.Duration(0), err
	}
	sync.logCurrentTrack(radioPlaylist)

	radioTracks, err := radioPlaylist.CurrentAndNext()
	if err != nil {
		return time.Duration(0), err
	}
	added := 0
	for _, t := range radioTracks {
		logColorf("Searching for: %s", t.String())
		if !t.IsMusic() {
			logColorf("[yellow]Not music, skipping: %s[reset]",
				t.String())
			continue
		}
		tracks, err := sync.retrySearch(&t)
		if err != nil {
			logColorf("[red]Search failed: %s (%s)[reset]",
				t.String(), err)
			continue
		}
		if len(tracks) == 0 {
			logColorf("[yellow]Track not found: %s[reset]",
				t.String())
			continue
		}
		track := &tracks[0]
		if sync.isCached(track) {
			logColorf("[yellow]Already added: %s[reset]",
				track.String())
			added++
			continue
		}
		if err = sync.retryAddTrack(track); err != nil {
			logColorf("[red]Failed to add: %s (%s)[reset]",
				track.String(), err)
			continue
		}
		sync.addTrack(track)
		added++
		logColorf("[green]Added track: %s[reset]", track.String())
	}
	log.Printf("Cache size: %d/%d", sync.cache.Len(),
		sync.cache.MaxEntries)
	if !sync.Adaptive {
		return sync.Interval, nil
	}
	if added != len(radioTracks) {
		log.Printf("%d/%d tracks were added. Falling back to "+
			" regular interval", added, len(radioTracks))
		return sync.Interval, nil
	}
	return radioPlaylist.NextSync()
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.crypto/ssh"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

// Write a simple http server
// response to the client is only wether or not his request was successfull or what error caused it to fail
// want to maintain state

// first, increment a global variable on every request
// can execute a get to get the variable.

// later: specify which public key to sign, and other parameters, username, permissions, restrictions, etc.
// probably a json object that's marshalled and sent over the wire as an http request.

// server processes that request, creates a certificate, upates the global datastructure

//from the user's computer, periodically execute a get method on your key in the data structure to receive updated copies of stuff.

type CertificateCollection map[string][]*ssh.Certificate

type CertificateParameters struct {
	Username       string
	Permissions    []string // no reason for it to be a map at this stage.
	PrivateKeyPath string
	Key            string // for now it points to the path of the public key to be signed.
}

var Certificates CertificateCollection

func init() {
	Certificates = make(CertificateCollection)
}

func (c CertificateCollection) New(params CertificateParameters) {
	// read private key
	privateKeyBytes, err := ioutil.ReadFile(params.PrivateKeyPath)
	check(err)
	authority, err := ssh.ParsePrivateKey(privateKeyBytes) // the private key used to sign the certificate.
	check(err)
	fmt.Printf("associated public key is: %v ", authority.PublicKey())
	// for now, read in public key to be signed.

	keyToSignBytes, err := ioutil.ReadFile(params.Key)
	check(err)
	keyToSign, comment, _, _, err := ssh.ParseAuthorizedKey(keyToSignBytes)
	check(err)

	if keyToSign == nil {
		panic("public key is nil")
		fmt.Println("comment is ", comment)
	}
	// from the params set the permissions and username
	// valid till infinity for now.

	cert := &ssh.Certificate{
		Nonce:       []byte{},
		Key:         keyToSign, // the public key that will be signed
		CertType:    ssh.UserCert,
		KeyId:       "user_" + params.Username,
		ValidBefore: ssh.CertTimeInfinity,
		Permissions: ssh.Permissions{
			CriticalOptions: map[string]string{},
			Extensions:      map[string]string{},
		},
		ValidPrincipals: []string{params.Username},
	}

	fmt.Println("public key is : ", keyToSign.Type())

	// setting the permissions
	for _, v := range params.Permissions {
		cert.Permissions.Extensions[v] = ""
	}

	err = cert.SignCert(rand.Reader, authority)
	check(err)

	//add newly created cert to the file.

	certs, ok := c[params.Username]

	if !ok {
		// key does not exits
		c[params.Username] = []*ssh.Certificate{cert}
	} else {

		c[params.Username] = append(certs, cert)
	}

	// write signed cert to a file:
	err = ioutil.WriteFile("/Users/shantanu/.ssh/id_rsa-cert-server.pub", ssh.MarshalAuthorizedKey(cert), 0600)

	check(err)

	//once created add it to the map.
	// but for now, also write it to file, so that I can use it to connect to the remote server.

}

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

	decoder := json.NewDecoder(r.Body)
	var params CertificateParameters
	err := decoder.Decode(&params)
	check(err)
	Certificates.New(params)
	fmt.Println(Certificates)
	fmt.Fprintf(w, "%d", 200)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	http.HandleFunc("/inc/", incrementHandler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>comment cheat sheet<commit_after>package main

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"

	"code.google.com/p/go.crypto/ssh"
)

// Write a simple http server
// response to the client is only wether or not his request was successfull or what error caused it to fail
// want to maintain state

// first, increment a global variable on every request
// can execute a get to get the variable.

// later: specify which public key to sign, and other parameters, username, permissions, restrictions, etc.
// probably a json object that's marshalled and sent over the wire as an http request.

// server processes that request, creates a certificate, upates the global datastructure

//from the user's computer, periodically execute a get method on your key in the data structure to receive updated copies of stuff.

type CertificateCollection map[string][]*ssh.Certificate

type CertificateParameters struct {
	Username       string
	Permissions    []string // no reason for it to be a map at this stage.
	PrivateKeyPath string
	Key            string // for now it points to the path of the public key to be signed.
}

var Certificates CertificateCollection

func init() {
	Certificates = make(CertificateCollection)
}

func (c CertificateCollection) New(params CertificateParameters) {
	// read private key
	privateKeyBytes, err := ioutil.ReadFile(params.PrivateKeyPath)
	check(err)
	authority, err := ssh.ParsePrivateKey(privateKeyBytes) // the private key used to sign the certificate.
	check(err)
	fmt.Printf("associated public key is: %v ", authority.PublicKey())
	// for now, read in public key to be signed.

	keyToSignBytes, err := ioutil.ReadFile(params.Key)
	check(err)
	keyToSign, comment, _, _, err := ssh.ParseAuthorizedKey(keyToSignBytes)
	check(err)

	if keyToSign == nil {
		panic("public key is nil")
		fmt.Println("comment is ", comment)
	}
	// from the params set the permissions and username
	// valid till infinity for now.

	cert := &ssh.Certificate{
		Nonce:       []byte{},
		Key:         keyToSign, // the public key that will be signed
		CertType:    ssh.UserCert,
		KeyId:       "user_" + params.Username,
		ValidBefore: ssh.CertTimeInfinity,
		Permissions: ssh.Permissions{
			CriticalOptions: map[string]string{},
			Extensions:      map[string]string{},
		},
		ValidPrincipals: []string{params.Username},
	}

	fmt.Println("public key is : ", keyToSign.Type())

	// setting the permissions
	for _, v := range params.Permissions {
		cert.Permissions.Extensions[v] = ""
	}

	err = cert.SignCert(rand.Reader, authority)
	check(err)

	//add newly created cert to the file.

	certs, ok := c[params.Username]

	if !ok {
		// key does not exits
		c[params.Username] = []*ssh.Certificate{cert}
	} else {

		c[params.Username] = append(certs, cert)
	}

	// write signed cert to a file:
	err = ioutil.WriteFile("/Users/shantanu/.ssh/id_rsa-cert-server.pub", ssh.MarshalAuthorizedKey(cert), 0600)

	check(err)

	//once created add it to the map.
	// but for now, also write it to file, so that I can use it to connect to the remote server.

}

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

	decoder := json.NewDecoder(r.Body)
	var params CertificateParameters
	err := decoder.Decode(&params)
	check(err)
	Certificates.New(params)
	fmt.Println(Certificates)
	fmt.Fprintf(w, "%d", 200)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	http.HandleFunc("/inc/", incrementHandler)
	http.ListenAndServe(":8080", nil)
}

// curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"Username": "shantanu", "Permissions": ["permit-pty"], "PrivateKeyPath": "/Users/shantanu/.ssh/users_ca","Key": "/Users/shantanu/.ssh/id_rsa.pub" } '  http://localhost:8080/inc/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/Toorop/govh"
	"github.com/Toorop/govh/server"
	"github.com/codegangsta/cli"
	"strconv"
)

// getFwCmds return commands for firewall subsection
func getServerCmds(client *govh.OvhClient) (serverCmds []cli.Command) {
	sr, err := server.New(client)
	if err != nil {
		return
	}

	serverCmds = []cli.Command{
		{
			Name:        "list",
			Usage:       "Return a list of server ",
			Description: "ovh server list" + NLTAB + "Example: ovh server list",
			Action: func(c *cli.Context) {
				servers, err := sr.List()
				handleErrFromOvh(err)
				for _, server := range servers {
					fmt.Println(server)
				}
				dieOk()
			},
		},
		{
			Name:        "getProperties",
			Usage:       "Return properties of a server ",
			Description: "ovh server getProperties SERVER" + NLTAB + "Example: ovh server getProperties ks323462.kimsufi.com",
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 1)
				properties, err := sr.GetProperties(c.Args().First())
				handleErrFromOvh(err)
				fmt.Printf("ID: %d%s", properties.Id, NL)
				fmt.Printf("Name: %s%s", properties.Name, NL)
				fmt.Printf("Ip: %s%s", properties.Ip, NL)
				fmt.Printf("Datacenter: %s%s", properties.Datacenter, NL)
				fmt.Printf("SupportLevel: %s%s", properties.SupportLevel, NL)
				fmt.Printf("ProfessionalUse: %t%s", properties.ProfessionalUse, NL)
				fmt.Printf("CommercialRange: %s%s", properties.CommercialRange, NL)
				fmt.Printf("Os: %s%s", properties.Os, NL)
				fmt.Printf("State: %s%s", properties.State, NL)
				fmt.Printf("Reverse: %s%s", properties.Reverse, NL)
				fmt.Printf("Monitored: %t%s", properties.Monitored, NL)
				fmt.Printf("Rack: %s%s", properties.Rack, NL)
				fmt.Printf("RootDevice: %s%s", properties.RootDevice, NL)
				fmt.Printf("LinkSpeed: %d%s", properties.LinkSpeed, NL)
				fmt.Printf("Bootid: %d%s", properties.BootId, NL)
				dieOk()
			},
		},
		{
			Name:        "getTasks",
			Usage:       "Return a list of tasks for a server ",
			Description: "ovh server getTasks SERVER [--function, --status]" + NLTAB + "Example: ovh server getTasks ns309865.ovh.net --function hardReboot --status done",
			Flags: []cli.Flag{
				cli.StringFlag{"function", "", "(optional) - filter by function. See https://api.ovh.com/console/#/dedicated/server/%7BserviceName%%7D/task#GET for availables functions.)"},
				cli.StringFlag{"status", "", "(optional) : filter by status. See [OVH doc](https://api.ovh.com/console/#/dedicated/server/%7BserviceName%%7D/task#GET) for availables status."},
			},
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 1)
				function := c.String("function")
				status := c.String("status")
				tasks, err := sr.GetTasks(c.Args().First(), function, status)
				handleErrFromOvh(err)
				for _, task := range tasks {
					fmt.Println(task)
				}
				dieOk()
			},
		},
		{
			Name:        "getTaskProperties",
			Usage:       "Return properties of a server task",
			Description: "ovh server getTaskProperties SERVER TASKID" + NLTAB + "Example: ovh server getTaskProperties ns309865.ovh.net 456",
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 2)
				taskId, err := strconv.ParseUint(c.Args().Get(1), 10, 64)
				if err != nil {
					dieError(err)
				}
				task, err := sr.GetTaskProperties(c.Args().First(), taskId)
				handleErrFromOvh(err)
				fmt.Printf("Task ID: %d%s", task.Id, NL)
				fmt.Printf("Function: %s%s", task.Function, NL)
				fmt.Printf("Status: %s%s", task.Status, NL)
				fmt.Printf("Comment: %s%s", task.Comment, NL)
				fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
				fmt.Printf("Start Date: %s%s", task.StartDate, NL)
				fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
				dieOk()
			},
		},
		{
			Name:        "cancelTask",
			Usage:       "Cancel a server task",
			Description: "ovh server cancelTask SERVER TASKID" + NLTAB + "Example: ovh server cancelTask ks323462.kimsufi.com 4319579",
			Action: func(c *cli.Context) {
				taskId, err := strconv.ParseUint(c.Args().Get(1), 10, 64)
				if err != nil {
					dieError(err)
				}
				err = sr.CancelTask(c.Args().Get(0), taskId)
				handleErrFromOvh(err)
				dieOk()
			},
		},
		{
			Name:        "reboot",
			Usage:       "Create a new reboot task",
			Description: "ovh server reboot SERVER" + NLTAB + "Example: ovh server reboot ks323462.kimsufi.com",
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 1)
				task, err := sr.Reboot(c.Args().First())
				handleErrFromOvh(err)
				fmt.Printf("Task ID: %d%s", task.Id, NL)
				fmt.Printf("Function: %s%s", task.Function, NL)
				fmt.Printf("Status: %s%s", task.Status, NL)
				fmt.Printf("Comment: %s%s", task.Comment, NL)
				fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
				fmt.Printf("Start Date: %s%s", task.StartDate, NL)
				fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
				dieOk()
			},
		},
	}

	switch cmd.Action {
	// List
	case "list":
		servers, err := serverR.List()
		if err != nil {
			return err
		}
		for _, s := range servers {
			resp = fmt.Sprintf("%s%s\r\n", resp, s)
		}
		if len(resp) > 2 {
			resp = resp[0 : len(resp)-2]
		}
		dieOk(resp)
		break
	// get server properties
	// ./ovh server getTasks SERVER_NAME FUNCTION STATUS
	case "properties":
		if len(cmd.Args) != 3 {
			return errors.New("\"server properties\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}

		properties, err := serverR.GetProperties(strings.ToLower(cmd.Args[2]))
		if err != nil {
			return err
		}
		fmt.Printf("ID: %d%s", properties.Id, NL)
		fmt.Printf("Name: %s%s", properties.Name, NL)
		fmt.Printf("Ip: %s%s", properties.Ip, NL)
		fmt.Printf("Datacenter: %s%s", properties.Datacenter, NL)
		fmt.Printf("ProfessionalUse: %t%s", properties.ProfessionalUse, NL)
		fmt.Printf("CommercialRange: %s%s", properties.CommercialRange, NL)
		fmt.Printf("Os: %s%s", properties.Os, NL)
		fmt.Printf("State: %s%s", properties.State, NL)
		fmt.Printf("Reverse: %s%s", properties.Reverse, NL)
		fmt.Printf("Monitored: %t%s", properties.Monitored, NL)
		fmt.Printf("Rack: %s%s", properties.Rack, NL)
		fmt.Printf("RootDevice: %s%s", properties.RootDevice, NL)
		fmt.Printf("LinkSpeed: %d%s", properties.LinkSpeed, NL)
		fmt.Printf("Bootid: %d%s", properties.BootId, NL)
		dieOk("")
		break

	// Get available netboots ID for this server
	case "availableNetboots":
		if len(cmd.Args) < 3 {
			return errors.New("\"server availableNetboots\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}
		var netbootIds []int
		if len(cmd.Args) == 3 {
			netbootIds, err = serverR.GetNetboots(strings.ToLower(cmd.Args[2]))
		} else {
			netbootIds, err = serverR.GetNetboots(strings.ToLower(cmd.Args[2]), cmd.Args[3])
		}
		if err != nil {
			return
		}
		for _, id := range netbootIds {
			fmt.Println(id)
		}
		break

	// Get server tasks
	case "getTasks":
		function := "all"
		status := "all"

		if len(cmd.Args) < 3 {
			return errors.New("\"server getTasks\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}

		if len(cmd.Args) > 5 {
			return errors.New("\"server getTasks\" too many arguments - see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}

		// serverName
		serverName := strings.ToLower(cmd.Args[2])

		// function
		if len(cmd.Args) > 3 {
			function = cmd.Args[3]
			if len(cmd.Args) > 4 {
				status = cmd.Args[4]
			}
		}

		tasks, err := serverR.GetTasks(serverName, function, status)
		if err != nil {
			return err
		}
		resp := ""
		for _, task := range tasks {
			resp = fmt.Sprintf("%s%d\r\n", resp, task)
		}
		if len(resp) > 2 {
			resp = resp[0 : len(resp)-2]
		}
		dieOk(resp)
		break

	// Get task properties
	// ./ovh server getTaskProperties SERVER_NAME TASK_ID
	case "getTaskProperties":
		if len(cmd.Args) != 4 {
			return errors.New("\"server getTaskProperties\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}

		serverName := strings.ToLower(cmd.Args[2])
		taskId, err := strconv.ParseUint(cmd.Args[3], 10, 64)
		if err != nil {
			return err
		}
		task, err := serverR.GetTaskProperties(serverName, taskId)
		if err != nil {
			return err
		}
		fmt.Printf("Task ID: %d%s", task.Id, NL)
		fmt.Printf("Function: %s%s", task.Function, NL)
		fmt.Printf("Status: %s%s", task.Status, NL)
		fmt.Printf("Comment: %s%s", task.Comment, NL)
		fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
		fmt.Printf("Start Date: %s%s", task.StartDate, NL)
		fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
		dieOk("")
		break

	// Cancel task (if possible)
	// ./ovh server cancelTask SERVER_NAME TASK_ID
	case "cancelTask":
		if len(cmd.Args) != 4 {
			return errors.New("\"server cancel Task\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}
		serverName := strings.ToLower(cmd.Args[2])
		taskId, err := strconv.ParseUint(cmd.Args[3], 10, 64)
		if err != nil {
			return err
		}
		err = serverR.CancelTask(serverName, taskId)
		if err != nil {
			return err
		}
		dieOk("Success task " + cmd.Args[3] + "cancelled")
		break

	// Reboot
	case "reboot":
		if len(cmd.Args) != 3 {
			return errors.New("\"server reboot\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
		}
		task, err := serverR.Reboot(strings.ToLower(cmd.Args[2]))
		if err != nil {
			return err
		}
		fmt.Printf("Task ID: %d%s", task.Id, NL)
		fmt.Printf("Function: %s%s", task.Function, NL)
		fmt.Printf("Status: %s%s", task.Status, NL)
		fmt.Printf("Comment: %s%s", task.Comment, NL)
		fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
		fmt.Printf("Start Date: %s%s", task.StartDate, NL)
		fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
		dieOk("")
		break

	default:
		return errors.New(fmt.Sprintf("This action : '%s' is not valid or not implemented yet !", strings.Join(cmd.Args, " ")))
	}
	return
}
<commit_msg>clean<commit_after>package main

import (
	"fmt"
	"github.com/Toorop/govh"
	"github.com/Toorop/govh/server"
	"github.com/codegangsta/cli"
	"strconv"
)

// getFwCmds return commands for firewall subsection
func getServerCmds(client *govh.OvhClient) (serverCmds []cli.Command) {
	sr, err := server.New(client)
	if err != nil {
		return
	}

	serverCmds = []cli.Command{
		{
			Name:        "list",
			Usage:       "Return a list of server ",
			Description: "ovh server list" + NLTAB + "Example: ovh server list",
			Action: func(c *cli.Context) {
				servers, err := sr.List()
				handleErrFromOvh(err)
				for _, server := range servers {
					fmt.Println(server)
				}
				dieOk()
			},
		},
		{
			Name:        "getProperties",
			Usage:       "Return properties of a server ",
			Description: "ovh server getProperties SERVER" + NLTAB + "Example: ovh server getProperties ks323462.kimsufi.com",
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 1)
				properties, err := sr.GetProperties(c.Args().First())
				handleErrFromOvh(err)
				fmt.Printf("ID: %d%s", properties.Id, NL)
				fmt.Printf("Name: %s%s", properties.Name, NL)
				fmt.Printf("Ip: %s%s", properties.Ip, NL)
				fmt.Printf("Datacenter: %s%s", properties.Datacenter, NL)
				fmt.Printf("SupportLevel: %s%s", properties.SupportLevel, NL)
				fmt.Printf("ProfessionalUse: %t%s", properties.ProfessionalUse, NL)
				fmt.Printf("CommercialRange: %s%s", properties.CommercialRange, NL)
				fmt.Printf("Os: %s%s", properties.Os, NL)
				fmt.Printf("State: %s%s", properties.State, NL)
				fmt.Printf("Reverse: %s%s", properties.Reverse, NL)
				fmt.Printf("Monitored: %t%s", properties.Monitored, NL)
				fmt.Printf("Rack: %s%s", properties.Rack, NL)
				fmt.Printf("RootDevice: %s%s", properties.RootDevice, NL)
				fmt.Printf("LinkSpeed: %d%s", properties.LinkSpeed, NL)
				fmt.Printf("Bootid: %d%s", properties.BootId, NL)
				dieOk()
			},
		},
		{
			Name:        "getTasks",
			Usage:       "Return a list of tasks for a server ",
			Description: "ovh server getTasks SERVER [--function, --status]" + NLTAB + "Example: ovh server getTasks ns309865.ovh.net --function hardReboot --status done",
			Flags: []cli.Flag{
				cli.StringFlag{"function", "", "(optional) - filter by function. See https://api.ovh.com/console/#/dedicated/server/%7BserviceName%%7D/task#GET for availables functions.)"},
				cli.StringFlag{"status", "", "(optional) : filter by status. See [OVH doc](https://api.ovh.com/console/#/dedicated/server/%7BserviceName%%7D/task#GET) for availables status."},
			},
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 1)
				function := c.String("function")
				status := c.String("status")
				tasks, err := sr.GetTasks(c.Args().First(), function, status)
				handleErrFromOvh(err)
				for _, task := range tasks {
					fmt.Println(task)
				}
				dieOk()
			},
		},
		{
			Name:        "getTaskProperties",
			Usage:       "Return properties of a server task",
			Description: "ovh server getTaskProperties SERVER TASKID" + NLTAB + "Example: ovh server getTaskProperties ns309865.ovh.net 456",
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 2)
				taskId, err := strconv.ParseUint(c.Args().Get(1), 10, 64)
				if err != nil {
					dieError(err)
				}
				task, err := sr.GetTaskProperties(c.Args().First(), taskId)
				handleErrFromOvh(err)
				fmt.Printf("Task ID: %d%s", task.Id, NL)
				fmt.Printf("Function: %s%s", task.Function, NL)
				fmt.Printf("Status: %s%s", task.Status, NL)
				fmt.Printf("Comment: %s%s", task.Comment, NL)
				fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
				fmt.Printf("Start Date: %s%s", task.StartDate, NL)
				fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
				dieOk()
			},
		},
		{
			Name:        "cancelTask",
			Usage:       "Cancel a server task",
			Description: "ovh server cancelTask SERVER TASKID" + NLTAB + "Example: ovh server cancelTask ks323462.kimsufi.com 4319579",
			Action: func(c *cli.Context) {
				taskId, err := strconv.ParseUint(c.Args().Get(1), 10, 64)
				if err != nil {
					dieError(err)
				}
				err = sr.CancelTask(c.Args().Get(0), taskId)
				handleErrFromOvh(err)
				dieOk()
			},
		},
		{
			Name:        "reboot",
			Usage:       "Create a new reboot task",
			Description: "ovh server reboot SERVER" + NLTAB + "Example: ovh server reboot ks323462.kimsufi.com",
			Action: func(c *cli.Context) {
				dieIfArgsMiss(len(c.Args()), 1)
				task, err := sr.Reboot(c.Args().First())
				handleErrFromOvh(err)
				fmt.Printf("Task ID: %d%s", task.Id, NL)
				fmt.Printf("Function: %s%s", task.Function, NL)
				fmt.Printf("Status: %s%s", task.Status, NL)
				fmt.Printf("Comment: %s%s", task.Comment, NL)
				fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
				fmt.Printf("Start Date: %s%s", task.StartDate, NL)
				fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
				dieOk()
			},
		},
	}

	/*
		switch cmd.Action {
		// List
		case "list":
			servers, err := serverR.List()
			if err != nil {
				return err
			}
			for _, s := range servers {
				resp = fmt.Sprintf("%s%s\r\n", resp, s)
			}
			if len(resp) > 2 {
				resp = resp[0 : len(resp)-2]
			}
			dieOk(resp)
			break
		// get server properties
		// ./ovh server getTasks SERVER_NAME FUNCTION STATUS
		case "properties":
			if len(cmd.Args) != 3 {
				return errors.New("\"server properties\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}

			properties, err := serverR.GetProperties(strings.ToLower(cmd.Args[2]))
			if err != nil {
				return err
			}
			fmt.Printf("ID: %d%s", properties.Id, NL)
			fmt.Printf("Name: %s%s", properties.Name, NL)
			fmt.Printf("Ip: %s%s", properties.Ip, NL)
			fmt.Printf("Datacenter: %s%s", properties.Datacenter, NL)
			fmt.Printf("ProfessionalUse: %t%s", properties.ProfessionalUse, NL)
			fmt.Printf("CommercialRange: %s%s", properties.CommercialRange, NL)
			fmt.Printf("Os: %s%s", properties.Os, NL)
			fmt.Printf("State: %s%s", properties.State, NL)
			fmt.Printf("Reverse: %s%s", properties.Reverse, NL)
			fmt.Printf("Monitored: %t%s", properties.Monitored, NL)
			fmt.Printf("Rack: %s%s", properties.Rack, NL)
			fmt.Printf("RootDevice: %s%s", properties.RootDevice, NL)
			fmt.Printf("LinkSpeed: %d%s", properties.LinkSpeed, NL)
			fmt.Printf("Bootid: %d%s", properties.BootId, NL)
			dieOk("")
			break

		// Get available netboots ID for this server
		case "availableNetboots":
			if len(cmd.Args) < 3 {
				return errors.New("\"server availableNetboots\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}
			var netbootIds []int
			if len(cmd.Args) == 3 {
				netbootIds, err = serverR.GetNetboots(strings.ToLower(cmd.Args[2]))
			} else {
				netbootIds, err = serverR.GetNetboots(strings.ToLower(cmd.Args[2]), cmd.Args[3])
			}
			if err != nil {
				return
			}
			for _, id := range netbootIds {
				fmt.Println(id)
			}
			break

		// Get server tasks
		case "getTasks":
			function := "all"
			status := "all"

			if len(cmd.Args) < 3 {
				return errors.New("\"server getTasks\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}

			if len(cmd.Args) > 5 {
				return errors.New("\"server getTasks\" too many arguments - see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}

			// serverName
			serverName := strings.ToLower(cmd.Args[2])

			// function
			if len(cmd.Args) > 3 {
				function = cmd.Args[3]
				if len(cmd.Args) > 4 {
					status = cmd.Args[4]
				}
			}

			tasks, err := serverR.GetTasks(serverName, function, status)
			if err != nil {
				return err
			}
			resp := ""
			for _, task := range tasks {
				resp = fmt.Sprintf("%s%d\r\n", resp, task)
			}
			if len(resp) > 2 {
				resp = resp[0 : len(resp)-2]
			}
			dieOk(resp)
			break

		// Get task properties
		// ./ovh server getTaskProperties SERVER_NAME TASK_ID
		case "getTaskProperties":
			if len(cmd.Args) != 4 {
				return errors.New("\"server getTaskProperties\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}

			serverName := strings.ToLower(cmd.Args[2])
			taskId, err := strconv.ParseUint(cmd.Args[3], 10, 64)
			if err != nil {
				return err
			}
			task, err := serverR.GetTaskProperties(serverName, taskId)
			if err != nil {
				return err
			}
			fmt.Printf("Task ID: %d%s", task.Id, NL)
			fmt.Printf("Function: %s%s", task.Function, NL)
			fmt.Printf("Status: %s%s", task.Status, NL)
			fmt.Printf("Comment: %s%s", task.Comment, NL)
			fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
			fmt.Printf("Start Date: %s%s", task.StartDate, NL)
			fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
			dieOk("")
			break

		// Cancel task (if possible)
		// ./ovh server cancelTask SERVER_NAME TASK_ID
		case "cancelTask":
			if len(cmd.Args) != 4 {
				return errors.New("\"server cancel Task\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}
			serverName := strings.ToLower(cmd.Args[2])
			taskId, err := strconv.ParseUint(cmd.Args[3], 10, 64)
			if err != nil {
				return err
			}
			err = serverR.CancelTask(serverName, taskId)
			if err != nil {
				return err
			}
			dieOk("Success task " + cmd.Args[3] + "cancelled")
			break

		// Reboot
		case "reboot":
			if len(cmd.Args) != 3 {
				return errors.New("\"server reboot\" needs an argument see doc at https://github.com/Toorop/govh/blob/master/cli/README.md")
			}
			task, err := serverR.Reboot(strings.ToLower(cmd.Args[2]))
			if err != nil {
				return err
			}
			fmt.Printf("Task ID: %d%s", task.Id, NL)
			fmt.Printf("Function: %s%s", task.Function, NL)
			fmt.Printf("Status: %s%s", task.Status, NL)
			fmt.Printf("Comment: %s%s", task.Comment, NL)
			fmt.Printf("Last Upadte: %s%s", task.LastUpdate, NL)
			fmt.Printf("Start Date: %s%s", task.StartDate, NL)
			fmt.Printf("Done Date: %s%s", task.DoneDate, NL)
			dieOk("")
			break

		default:
			return errors.New(fmt.Sprintf("This action : '%s' is not valid or not implemented yet !", strings.Join(cmd.Args, " ")))
		}*/
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

/*
package main

import (
	"fmt"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/go-ozzo/ozzo-dbx"
	"github.com/go-ozzo/ozzo-routing"
	"github.com/go-ozzo/ozzo-routing/auth"
	"github.com/go-ozzo/ozzo-routing/content"
	"github.com/go-ozzo/ozzo-routing/cors"
	_ "github.com/lib/pq"
	"github.com/Zhanat87/go/apis"
	"github.com/Zhanat87/go/app"
	"github.com/Zhanat87/go/daos"
	"github.com/Zhanat87/go/errors"
	"github.com/Zhanat87/go/services"
)

func main() {
	// load application configurations
	if err := app.LoadConfig("./config"); err != nil {
		panic(fmt.Errorf("Invalid application configuration: %s", err))
	}

	// load error messages
	if err := errors.LoadMessages(app.Config.ErrorFile); err != nil {
		panic(fmt.Errorf("Failed to read the error message file: %s", err))
	}

	// create the logger
	logger := logrus.New()

	// connect to the database
	db, err := dbx.MustOpen("postgres", app.Config.DSN)
	if err != nil {
		panic(err)
	}
	db.LogFunc = logger.Infof

	// wire up API routing
	http.Handle("/", buildRouter(logger, db))

	// start the server
	address := fmt.Sprintf(":%v", app.Config.ServerPort)
	logger.Infof("server %v is started at %v\n", app.Version, address)
	panic(http.ListenAndServe(address, nil))
}

func buildRouter(logger *logrus.Logger, db *dbx.DB) *routing.Router {
	router := routing.New()

	router.To("GET,HEAD", "/ping", func(c *routing.Context) error {
		c.Abort()  // skip all other middlewares/handlers
		return c.Write("OK " + app.Version)
	})

	router.Use(
		app.Init(logger),
		content.TypeNegotiator(content.JSON),
		cors.Handler(cors.Options{
			AllowOrigins: "*",
			AllowHeaders: "*",
			AllowMethods: "*",
		}),
		app.Transactional(db),
	)

	rg := router.Group("/v1")

	rg.Post("/auth", apis.Auth(app.Config.JWTSigningKey))
	rg.Use(auth.JWT(app.Config.JWTVerificationKey, auth.JWTOptions{
		SigningMethod: app.Config.JWTSigningMethod,
		TokenHandler:  apis.JWTHandler,
	}))

	artistDAO := daos.NewArtistDAO()
	apis.ServeArtistResource(rg, services.NewArtistService(artistDAO))

	albumDAO := daos.NewAlbumDAO()
	apis.ServeAlbumResource(rg, services.NewAlbumService(albumDAO))

	// wire up more resource APIs here

	return router
}
*/
<commit_msg>updates<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
)

func handler(w http.ResponseWriter, r *http.Request) {
	var variables string
	for _, e := range os.Environ() {
		variables += e + "\r\n"
	}
	fmt.Fprintf(w, variables)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

/*
package main

import (
	"fmt"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/go-ozzo/ozzo-dbx"
	"github.com/go-ozzo/ozzo-routing"
	"github.com/go-ozzo/ozzo-routing/auth"
	"github.com/go-ozzo/ozzo-routing/content"
	"github.com/go-ozzo/ozzo-routing/cors"
	_ "github.com/lib/pq"
	"github.com/Zhanat87/go/apis"
	"github.com/Zhanat87/go/app"
	"github.com/Zhanat87/go/daos"
	"github.com/Zhanat87/go/errors"
	"github.com/Zhanat87/go/services"
)

func main() {
	// load application configurations
	if err := app.LoadConfig("./config"); err != nil {
		panic(fmt.Errorf("Invalid application configuration: %s", err))
	}

	// load error messages
	if err := errors.LoadMessages(app.Config.ErrorFile); err != nil {
		panic(fmt.Errorf("Failed to read the error message file: %s", err))
	}

	// create the logger
	logger := logrus.New()

	// connect to the database
	db, err := dbx.MustOpen("postgres", app.Config.DSN)
	if err != nil {
		panic(err)
	}
	db.LogFunc = logger.Infof

	// wire up API routing
	http.Handle("/", buildRouter(logger, db))

	// start the server
	address := fmt.Sprintf(":%v", app.Config.ServerPort)
	logger.Infof("server %v is started at %v\n", app.Version, address)
	panic(http.ListenAndServe(address, nil))
}

func buildRouter(logger *logrus.Logger, db *dbx.DB) *routing.Router {
	router := routing.New()

	router.To("GET,HEAD", "/ping", func(c *routing.Context) error {
		c.Abort()  // skip all other middlewares/handlers
		return c.Write("OK " + app.Version)
	})

	router.Use(
		app.Init(logger),
		content.TypeNegotiator(content.JSON),
		cors.Handler(cors.Options{
			AllowOrigins: "*",
			AllowHeaders: "*",
			AllowMethods: "*",
		}),
		app.Transactional(db),
	)

	rg := router.Group("/v1")

	rg.Post("/auth", apis.Auth(app.Config.JWTSigningKey))
	rg.Use(auth.JWT(app.Config.JWTVerificationKey, auth.JWTOptions{
		SigningMethod: app.Config.JWTSigningMethod,
		TokenHandler:  apis.JWTHandler,
	}))

	artistDAO := daos.NewArtistDAO()
	apis.ServeArtistResource(rg, services.NewArtistService(artistDAO))

	albumDAO := daos.NewAlbumDAO()
	apis.ServeAlbumResource(rg, services.NewAlbumService(albumDAO))

	// wire up more resource APIs here

	return router
}
*/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"net"

	"github.com/ttaylorr/minecraft/protocol"
)

func main() {
	conn, _ := net.Listen("tcp", "0.0.0.0:25565")
	for {
		client, _ := conn.Accept()
		go handleConnection(protocol.NewConnection(client))
	}
}

func handleConnection(c *protocol.Connection) {
	for {
		p, err := c.Next()
		if err == io.EOF {
			return
		}

		fmt.Println(p)
	}
}
<commit_msg>Teach server to ping the client<commit_after>package main

import (
	"io"
	"math/rand"
	"net"

	"github.com/ttaylorr/minecraft/protocol"
	"github.com/ttaylorr/minecraft/protocol/packet"
)

func main() {
	conn, _ := net.Listen("tcp", "0.0.0.0:25565")
	for {
		client, _ := conn.Accept()
		go handleConnection(protocol.NewConnection(client))
	}
}

func handleConnection(c *protocol.Connection) {
	for {
		p, err := c.Next()
		if err == io.EOF {
			return
		}

		switch t := p.(type) {
		case packet.Handshake:
			state := protocol.State(uint8(t.NextState))
			c.SetState(state)
		case packet.StatusRequest:
			resp := packet.StatusResponse{}
			resp.Status.Version.Name = "1.8.8"
			resp.Status.Version.Protocol = 47
			resp.Status.Players.Max = rand.Intn(100)
			resp.Status.Players.Online = rand.Intn(101)
			resp.Status.Description.Text = "Hello from Golang!"

			c.Write(resp)
		case packet.StatusPing:
			pong := packet.StatusPong{}
			pong.Payload = t.Payload

			c.Write(pong)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-uuid/uuid"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
)

type Message struct {
	Y   int    // current Y position
	X   int    // as above
	Id  string // the id of the player that sent the message
	New bool   // true if this player just connected so we know when to
	// spawn a new sprite on the screens of the other players. for all subsequent
	// messages it's false
	Online bool // true if the player is no longer connected so the frontend
	// will remove it's sprite
}

type Player struct {
	Y      int             // Y position of the player
	X      int             // X position
	Id     string          // a unique id to identify the player by the frontend
	Socket *websocket.Conn // websocket connection of the player
}

func (p *Player) position(new bool) Message {
	return Message{X: p.X, Y: p.Y, Id: p.Id, New: new, Online: true}
}

// a slice of *Players which will store the list of connected players
var Players = make([]*Player, 0)

func remoteHandler(res http.ResponseWriter, req *http.Request) {
	var err error

	//when someone requires a ws connection we create a new player and store a
	// pointer to the connection inside player.Socket
	ws, err := websocket.Upgrade(res, req, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(res, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		log.Println(err)
		return
	}

	log.Printf("got websocket conn from %v\n", ws.RemoteAddr())
	player := new(Player)
	player.Id = uuid.New()
	player.Socket = ws

	// we broadcast the position of the new player to alredy connected
	// players (if any) and viceversa, we tell the player where to spawn already
	// existing players
	log.Println("Publishing positions")

	go func() {
		for _, p := range Players {
			if p.Socket.RemoteAddr() != player.Socket.RemoteAddr() {
				if err = player.Socket.WriteJSON(p.position(true)); err != nil {
					log.Println(err)
				}
				if err = p.Socket.WriteJSON(player.position(true)); err != nil {
					log.Println(err)
				}
			}
		}
	}()

	// we append the new player to Players slice
	Players = append(Players, player)
	for {
		// if a network error occurs (aka someone closed the game) we let
		// the other players know to despawn his sprite (Online: false) and
		// remove him from the slice so no further updates will be sent
		if err = player.Socket.ReadJSON(&player); err != nil {
			log.Println("Player Disconnected waiting", err)
			for i, p := range Players {
				if p.Socket.RemoteAddr() == player.Socket.RemoteAddr() {
					Players = append(Players[:i], Players[i+1:]...)
				} else {
					log.Println("destroy player", player)
					if err = p.Socket.WriteJSON(Message{Online: false, Id: player.Id}); err != nil {
						log.Println(err)
					}
				}
			}
			log.Println("Number of players still connected ...", len(Players))
			return
		}

		// a regular broadcast to inform all the players about a player's
		// position update
		go func() {
			for _, p := range Players {
				if p.Socket.RemoteAddr() != player.Socket.RemoteAddr() {
					if err = p.Socket.WriteJSON(player.position(false)); err != nil {
						log.Println(err)
					}
				}

			}
		}()
	}
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/ws", remoteHandler)

	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public/")))
	http.ListenAndServe(":3000", r)
}
<commit_msg>Update dependencies<commit_after>package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/pborman/uuid"
)

type Message struct {
	Y   int    // current Y position
	X   int    // as above
	Id  string // the id of the player that sent the message
	New bool   // true if this player just connected so we know when to
	// spawn a new sprite on the screens of the other players. for all subsequent
	// messages it's false
	Online bool // true if the player is no longer connected so the frontend
	// will remove it's sprite
}

type Player struct {
	Y      int             // Y position of the player
	X      int             // X position
	Id     string          // a unique id to identify the player by the frontend
	Socket *websocket.Conn // websocket connection of the player
}

func (p *Player) position(new bool) Message {
	return Message{X: p.X, Y: p.Y, Id: p.Id, New: new, Online: true}
}

// a slice of *Players which will store the list of connected players
var Players = make([]*Player, 0)

func remoteHandler(res http.ResponseWriter, req *http.Request) {
	var err error

	//when someone requires a ws connection we create a new player and store a
	// pointer to the connection inside player.Socket
	ws, err := websocket.Upgrade(res, req, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(res, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		log.Println(err)
		return
	}

	log.Printf("got websocket conn from %v\n", ws.RemoteAddr())
	player := new(Player)
	player.Id = uuid.New()
	player.Socket = ws

	// we broadcast the position of the new player to alredy connected
	// players (if any) and viceversa, we tell the player where to spawn already
	// existing players
	log.Println("Publishing positions")

	go func() {
		for _, p := range Players {
			if p.Socket.RemoteAddr() != player.Socket.RemoteAddr() {
				if err = player.Socket.WriteJSON(p.position(true)); err != nil {
					log.Println(err)
				}
				if err = p.Socket.WriteJSON(player.position(true)); err != nil {
					log.Println(err)
				}
			}
		}
	}()

	// we append the new player to Players slice
	Players = append(Players, player)
	for {
		// if a network error occurs (aka someone closed the game) we let
		// the other players know to despawn his sprite (Online: false) and
		// remove him from the slice so no further updates will be sent
		if err = player.Socket.ReadJSON(&player); err != nil {
			log.Println("Player Disconnected waiting", err)
			for i, p := range Players {
				if p.Socket.RemoteAddr() == player.Socket.RemoteAddr() {
					Players = append(Players[:i], Players[i+1:]...)
				} else {
					log.Println("destroy player", player)
					if err = p.Socket.WriteJSON(Message{Online: false, Id: player.Id}); err != nil {
						log.Println(err)
					}
				}
			}
			log.Println("Number of players still connected ...", len(Players))
			return
		}

		// a regular broadcast to inform all the players about a player's
		// position update
		go func() {
			for _, p := range Players {
				if p.Socket.RemoteAddr() != player.Socket.RemoteAddr() {
					if err = p.Socket.WriteJSON(player.position(false)); err != nil {
						log.Println(err)
					}
				}

			}
		}()
	}
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/ws", remoteHandler)

	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public/")))
	http.ListenAndServe(":3000", r)
}
<|endoftext|>