<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	_ "github.com/go-sql-driver/mysql"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

type Stock struct {
	Change           float64 `json:"Change"`
	ChangePercent    float64 `json:"ChangePercent"`
	ChangePercentYTD float64 `json:"ChangePercentYTD"`
	ChangeYTD        float64 `json:"ChangeYTD"`
	High             float64 `json:"High"`
	Price            float64 `json:"LastPrice"`
	Low              float64 `json:"Low"`
	MSDate           float64 `json:"MSDate"`
	MarketCap        int     `json:"MarketCap"`
	Name             string  `json:"Name"`
	Open             float64 `json:"Open"`
	Status           string  `json:"Status"`
	Symbol           string  `json:"Symbol"`
	Timestamp        string  `json:"Timestamp"`
	Volume           int     `json:"Volume"`
}

func health(c web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Uh, we had a slight weapons malfunction, but uh... everything's perfectly all right now. We're fine. We're all fine here now, thank you. How are you?")
}

func testPost(c web.C, w http.ResponseWriter, r *http.Request) {
	db, err := sql.Open("mysql", "root:"+os.Getenv("STALKS_DB_PASS")+"@tcp("+os.Getenv("STALKS_DB_HOST")+":"+os.Getenv("STALKS_DB_PORT"))
	if err != nil { // Die if there was an error
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	defer db.Close()

	fmt.Fprintf(w, "%s", "Post response")
}

func check(c web.C, w http.ResponseWriter, r *http.Request) {
	client := new(http.Client)
	res, err := client.Get("http://dev.markitondemand.com/Api/v2/Quote/jsonp?symbol=" + c.URLParams["stock"])
	if err != nil { // Die if there was an error
		fmt.Fprintf(w, "Error: %s", err)
		return
	}

	// Super ghetto method of removing unnecessary callback garbage from the API response
	body, err := ioutil.ReadAll(res.Body)
	if err != nil { // Die if there was an error
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	body = append(body[:0], body[18:]...) // Kill the leading function() bit
	body = body[:len(body)-1]             // Remove the last character so we just have naked JSON
	// End of ghetto code

	var stock = new(Stock)            // Make a new instance of the Stock struct
	err = json.Unmarshal(body, stock) // Populate it with our JSON data
	if err != nil {                   // Die if there was an error
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	fmt.Fprintf(w, "%s is currently worth %d turnips\n", stock.Name, int(stock.Price*100)) // Return the price through the API endpoint
}

func main() {
	goji.Get("/health", health)
	// goji.Get("/portfolio/:user", portfolio)
	goji.Get("/check/:stock", check)
	goji.Post("/post", testPost)
	// goji.Post("/buy/:stock/:quantity", buy)
	// goji.Post("/sell/:stock/:quantity", sell)
	goji.Serve()
}
<commit_msg>Fixed dsn issue in mysql connect<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	_ "github.com/go-sql-driver/mysql"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

type Stock struct {
	Change           float64 `json:"Change"`
	ChangePercent    float64 `json:"ChangePercent"`
	ChangePercentYTD float64 `json:"ChangePercentYTD"`
	ChangeYTD        float64 `json:"ChangeYTD"`
	High             float64 `json:"High"`
	Price            float64 `json:"LastPrice"`
	Low              float64 `json:"Low"`
	MSDate           float64 `json:"MSDate"`
	MarketCap        int     `json:"MarketCap"`
	Name             string  `json:"Name"`
	Open             float64 `json:"Open"`
	Status           string  `json:"Status"`
	Symbol           string  `json:"Symbol"`
	Timestamp        string  `json:"Timestamp"`
	Volume           int     `json:"Volume"`
}

func health(c web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Uh, we had a slight weapons malfunction, but uh... everything's perfectly all right now. We're fine. We're all fine here now, thank you. How are you?")
}

func testPost(c web.C, w http.ResponseWriter, r *http.Request) {
	db, err := sql.Open("mysql", "root:"+os.Getenv("STALKS_DB_PASS")+"@tcp("+os.Getenv("STALKS_DB_HOST")+":"+os.Getenv("STALKS_DB_PORT")+")/"+os.Getenv("STALKS_DB_NAME"))
	if err != nil { // Die if there was an error
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	defer db.Close()

	fmt.Fprintf(w, "%s", "Post response")
}

func check(c web.C, w http.ResponseWriter, r *http.Request) {
	client := new(http.Client)
	res, err := client.Get("http://dev.markitondemand.com/Api/v2/Quote/jsonp?symbol=" + c.URLParams["stock"])
	if err != nil { // Die if there was an error
		fmt.Fprintf(w, "Error: %s", err)
		return
	}

	// Super ghetto method of removing unnecessary callback garbage from the API response
	body, err := ioutil.ReadAll(res.Body)
	if err != nil { // Die if there was an error
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	body = append(body[:0], body[18:]...) // Kill the leading function() bit
	body = body[:len(body)-1]             // Remove the last character so we just have naked JSON
	// End of ghetto code

	var stock = new(Stock)            // Make a new instance of the Stock struct
	err = json.Unmarshal(body, stock) // Populate it with our JSON data
	if err != nil {                   // Die if there was an error
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	fmt.Fprintf(w, "%s is currently worth %d turnips\n", stock.Name, int(stock.Price*100)) // Return the price through the API endpoint
}

func main() {
	goji.Get("/health", health)
	// goji.Get("/portfolio/:user", portfolio)
	goji.Get("/check/:stock", check)
	goji.Post("/post", testPost)
	// goji.Post("/buy/:stock/:quantity", buy)
	// goji.Post("/sell/:stock/:quantity", sell)
	goji.Serve()
}
<|endoftext|>


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

// DNS server implementation.

package dns

import (
	"io"
	"net"
)

// how to do Tsig here?? TODO(mg)

type Handler interface {
	ServeDNS(w ResponseWriter, r *Msg)
	// IP based ACL mapping. The contains the string representation
	// of the IP address and a boolean saying it may connect (true) or not.
}

// A ResponseWriter interface is used by an DNS handler to
// construct an DNS response.
type ResponseWriter interface {
	// RemoteAddr returns the net.Addr of the client that sent the current request.
	RemoteAddr() net.Addr
	// Write a reply back to the client.
	Write([]byte) (int, error)
}

// port?
type conn struct {
	remoteAddr net.Addr     // address of remote side (sans port)
	handler    Handler      // request handler
	request    []byte       // bytes read
	_UDP       *net.UDPConn // i/o connection if UDP was used
	_TCP       *net.TCPConn // i/o connection if TCP was used
	hijacked   bool         // connection has been hijacked by hander TODO(mg)
}

type response struct {
	conn *conn
	req  *Msg
}

// ServeMux is an DNS request multiplexer. It matches the
// zone name of each incoming request against a list of
// registered patterns add calls the handler for the pattern
// that most closely matches the zone name.
type ServeMux struct {
	m map[string]Handler
}

// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as DNS handlers.  If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)

// ServerDNS calls f(w, r)
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
	f(w, r)
}

// Helper handler that returns an answer with
// RCODE = refused for every request.
func Refused(w ResponseWriter, r *Msg) {
	m := new(Msg)
	m.SetRcode(r, RcodeRefused)
	buf, _ := m.Pack()
	w.Write(buf)
}

// RefusedHandler returns HandlerFunc with Refused.
func RefusedHandler() Handler { return HandlerFunc(Refused) }

// ...
func ListenAndServe(addr string, network string, handler Handler, size int) error {
	server := &Server{Addr: addr, Net: network, Handler: handler, UDPSize: size}
	return server.ListenAndServe()
}

func (mux *ServeMux) match(zone string) Handler {
	var h Handler
	var n = 0
	for k, v := range mux.m {
		if !zoneMatch(k, zone) {
			continue
		}
		if h == nil || len(k) > n {
			n = len(k)
			h = v
		}
	}
	return h
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	if pattern == "" {
		panic("dns: invalid pattern " + pattern)
	}
	// Should this go
	//if pattern[len(pattern)-1] != '.' { // no ending .
	//	mux.m[pattern+"."] = handler
	//} else {
	mux.m[pattern] = handler
}

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
	mux.Handle(pattern, HandlerFunc(handler))
}

// ServeDNS dispatches the request to the handler whose
// pattern most closely matches the request message.
func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
	h := mux.match(request.Question[0].Name)
	if h == nil {
		h = RefusedHandler()
	}
	h.ServeDNS(w, request)
}

// Handle register the handler the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patters are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

// A Server defines parameters for running an DNS server.
// Note how much it starts to look like 'Client struct'
type Server struct {
	Addr         string            // address to listen on, ":dns" if empty
	Net          string            // if "tcp" it will invoke a TCP listener, otherwise an UDP one
	Handler      Handler           // handler to invoke, dns.DefaultServeMux if nil
	UDPSize      int               // default buffer to use to read incoming UDP messages
	ReadTimeout  int64             // the net.Conn.SetReadTimeout value for new connections
	WriteTimeout int64             // the net.Conn.SetWriteTimeout value for new connections
	TsigSecret   map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>
}

// ListenAndServe starts a nameserver on the configured address.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":domain"
	}
	switch srv.Net {
	case "tcp", "tcp4", "tcp6":
		a, e := net.ResolveTCPAddr(srv.Net, addr)
		if e != nil {
			return e
		}
		l, e := net.ListenTCP(srv.Net, a)
		if e != nil {
			return e
		}
		return srv.ServeTCP(l)
	case "udp", "udp4", "udp6":
		a, e := net.ResolveUDPAddr(srv.Net, addr)
		if e != nil {
			return e
		}
		l, e := net.ListenUDP(srv.Net, a)
		if e != nil {
			return e
		}
		return srv.ServeUDP(l)
	}
	return nil // os.Error with wrong network
}

func (srv *Server) ServeTCP(l *net.TCPListener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
forever:
	for {
		rw, e := l.AcceptTCP()
		if e != nil {
			return e
		}
		if srv.ReadTimeout != 0 {
			rw.SetReadTimeout(srv.ReadTimeout)
		}
		if srv.WriteTimeout != 0 {
			rw.SetWriteTimeout(srv.WriteTimeout)
		}
		l := make([]byte, 2)
		n, err := rw.Read(l)
		if err != nil || n != 2 {
			continue
		}
		length, _ := unpackUint16(l, 0)
		if length == 0 {
			continue
		}
		m := make([]byte, int(length))
		n, err = rw.Read(m[:int(length)])
		if err != nil {
			continue
		}
		i := n
		for i < int(length) {
			j, err := rw.Read(m[i:int(length)])
			if err != nil {
				continue forever
			}
			i += j
		}
		n = i
		d, err := newConn(rw, nil, rw.RemoteAddr(), m, handler)
		if err != nil {
			continue
		}
		go d.serve()
	}
	panic("not reached")
}

func (srv *Server) ServeUDP(l *net.UDPConn) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if srv.UDPSize == 0 {
		srv.UDPSize = UDPReceiveMsgSize
	}
	for {
		m := make([]byte, srv.UDPSize)
		n, a, e := l.ReadFromUDP(m)
		if e != nil {
			return e
		}
		m = m[:n]

		if srv.ReadTimeout != 0 {
			l.SetReadTimeout(srv.ReadTimeout)
		}
		if srv.WriteTimeout != 0 {
			l.SetWriteTimeout(srv.WriteTimeout)
		}
		d, err := newConn(nil, l, a, m, handler)
		if err != nil {
			continue
		}
		go d.serve()
	}
	panic("not reached")
}

func newConn(t *net.TCPConn, u *net.UDPConn, a net.Addr, buf []byte, handler Handler) (*conn, error) {
	c := new(conn)
	c.handler = handler
	c._TCP = t
	c._UDP = u
	c.remoteAddr = a
	c.request = buf
	return c, nil
}

// Close the connection.
func (c *conn) close() {
	switch {
	case c._UDP != nil:
		c._UDP.Close()
		c._UDP = nil
	case c._TCP != nil:
		c._TCP.Close()
		c._TCP = nil
	}
}

// Serve a new connection.
func (c *conn) serve() {
	for {
		// Request has been read in ServeUDP or ServeTCP
		w := new(response)
		w.conn = c
		req := new(Msg)
		if !req.Unpack(c.request) {
			// Send a format error back
			x := new(Msg)
			x.SetRcodeFormatError(req)
			buf, _ := x.Pack()
			w.Write(buf)
			break
		}
		w.req = req
		c.handler.ServeDNS(w, w.req) // this does the writing back to the client
		if c.hijacked {
			return
		}
		break // TODO(mg) Why is this a loop anyway
	}
	if c._TCP != nil {
		c.close() // Listen and Serve is closed then
	}
}

func (w *response) Write(data []byte) (n int, err error) {
	switch {
	case w.conn._UDP != nil:
		n, err = w.conn._UDP.WriteTo(data, w.conn.remoteAddr)
		if err != nil {
			return 0, err
		}
	case w.conn._TCP != nil:
		// TODO(mg) len(data) > 64K
		l := make([]byte, 2)
		l[0], l[1] = packUint16(uint16(len(data)))
		n, err = w.conn._TCP.Write(l)
		if err != nil {
			return n, err
		}
		if n != 2 {
			return n, io.ErrShortWrite
		}
		n, err = w.conn._TCP.Write(data)
		if err != nil {
			return n, err
		}
		i := n
		if i < len(data) {
			j, err := w.conn._TCP.Write(data[i:len(data)])
			if err != nil {
				return i, err
			}
			i += j
		}
		n = i
	}
	return n, nil
}

// RemoteAddr implements the ResponseWriter.RemoteAddr method
func (w *response) RemoteAddr() net.Addr { return w.conn.remoteAddr }
<commit_msg>Fixes for weekly.2012-01-20<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// DNS server implementation.

package dns

import (
	"io"
	"net"
	"time"
)

// how to do Tsig here?? TODO(mg)

type Handler interface {
	ServeDNS(w ResponseWriter, r *Msg)
	// IP based ACL mapping. The contains the string representation
	// of the IP address and a boolean saying it may connect (true) or not.
}

// A ResponseWriter interface is used by an DNS handler to
// construct an DNS response.
type ResponseWriter interface {
	// RemoteAddr returns the net.Addr of the client that sent the current request.
	RemoteAddr() net.Addr
	// Write a reply back to the client.
	Write([]byte) (int, error)
}

// port?
type conn struct {
	remoteAddr net.Addr     // address of remote side (sans port)
	handler    Handler      // request handler
	request    []byte       // bytes read
	_UDP       *net.UDPConn // i/o connection if UDP was used
	_TCP       *net.TCPConn // i/o connection if TCP was used
	hijacked   bool         // connection has been hijacked by hander TODO(mg)
}

type response struct {
	conn *conn
	req  *Msg
}

// ServeMux is an DNS request multiplexer. It matches the
// zone name of each incoming request against a list of
// registered patterns add calls the handler for the pattern
// that most closely matches the zone name.
type ServeMux struct {
	m map[string]Handler
}

// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as DNS handlers.  If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Msg)

// ServerDNS calls f(w, r)
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
	f(w, r)
}

// Helper handler that returns an answer with
// RCODE = refused for every request.
func Refused(w ResponseWriter, r *Msg) {
	m := new(Msg)
	m.SetRcode(r, RcodeRefused)
	buf, _ := m.Pack()
	w.Write(buf)
}

// RefusedHandler returns HandlerFunc with Refused.
func RefusedHandler() Handler { return HandlerFunc(Refused) }

// ...
func ListenAndServe(addr string, network string, handler Handler, size int) error {
	server := &Server{Addr: addr, Net: network, Handler: handler, UDPSize: size}
	return server.ListenAndServe()
}

func (mux *ServeMux) match(zone string) Handler {
	var h Handler
	var n = 0
	for k, v := range mux.m {
		if !zoneMatch(k, zone) {
			continue
		}
		if h == nil || len(k) > n {
			n = len(k)
			h = v
		}
	}
	return h
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	if pattern == "" {
		panic("dns: invalid pattern " + pattern)
	}
	// Should this go
	//if pattern[len(pattern)-1] != '.' { // no ending .
	//	mux.m[pattern+"."] = handler
	//} else {
	mux.m[pattern] = handler
}

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
	mux.Handle(pattern, HandlerFunc(handler))
}

// ServeDNS dispatches the request to the handler whose
// pattern most closely matches the request message.
func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
	h := mux.match(request.Question[0].Name)
	if h == nil {
		h = RefusedHandler()
	}
	h.ServeDNS(w, request)
}

// Handle register the handler the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patters are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

// A Server defines parameters for running an DNS server.
// Note how much it starts to look like 'Client struct'
type Server struct {
	Addr         string            // address to listen on, ":dns" if empty
	Net          string            // if "tcp" it will invoke a TCP listener, otherwise an UDP one
	Handler      Handler           // handler to invoke, dns.DefaultServeMux if nil
	UDPSize      int               // default buffer to use to read incoming UDP messages
	ReadTimeout  time.Duration             // the net.Conn.SetReadTimeout value for new connections
	WriteTimeout time.Duration             // the net.Conn.SetWriteTimeout value for new connections
	TsigSecret   map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>
}

// ListenAndServe starts a nameserver on the configured address.
func (srv *Server) ListenAndServe() error {
	addr := srv.Addr
	if addr == "" {
		addr = ":domain"
	}
	switch srv.Net {
	case "tcp", "tcp4", "tcp6":
		a, e := net.ResolveTCPAddr(srv.Net, addr)
		if e != nil {
			return e
		}
		l, e := net.ListenTCP(srv.Net, a)
		if e != nil {
			return e
		}
		return srv.ServeTCP(l)
	case "udp", "udp4", "udp6":
		a, e := net.ResolveUDPAddr(srv.Net, addr)
		if e != nil {
			return e
		}
		l, e := net.ListenUDP(srv.Net, a)
		if e != nil {
			return e
		}
		return srv.ServeUDP(l)
	}
	return nil // os.Error with wrong network
}

func (srv *Server) ServeTCP(l *net.TCPListener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
forever:
	for {
		rw, e := l.AcceptTCP()
		if e != nil {
			return e
		}
		if srv.ReadTimeout != 0 {
			rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
		}
		if srv.WriteTimeout != 0 {
			rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
		}
		l := make([]byte, 2)
		n, err := rw.Read(l)
		if err != nil || n != 2 {
			continue
		}
		length, _ := unpackUint16(l, 0)
		if length == 0 {
			continue
		}
		m := make([]byte, int(length))
		n, err = rw.Read(m[:int(length)])
		if err != nil {
			continue
		}
		i := n
		for i < int(length) {
			j, err := rw.Read(m[i:int(length)])
			if err != nil {
				continue forever
			}
			i += j
		}
		n = i
		d, err := newConn(rw, nil, rw.RemoteAddr(), m, handler)
		if err != nil {
			continue
		}
		go d.serve()
	}
	panic("not reached")
}

func (srv *Server) ServeUDP(l *net.UDPConn) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if srv.UDPSize == 0 {
		srv.UDPSize = UDPReceiveMsgSize
	}
	for {
		m := make([]byte, srv.UDPSize)
		n, a, e := l.ReadFromUDP(m)
		if e != nil {
			return e
		}
		m = m[:n]

		if srv.ReadTimeout != 0 {
			l.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
		}
		if srv.WriteTimeout != 0 {
			l.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
		}
		d, err := newConn(nil, l, a, m, handler)
		if err != nil {
			continue
		}
		go d.serve()
	}
	panic("not reached")
}

func newConn(t *net.TCPConn, u *net.UDPConn, a net.Addr, buf []byte, handler Handler) (*conn, error) {
	c := new(conn)
	c.handler = handler
	c._TCP = t
	c._UDP = u
	c.remoteAddr = a
	c.request = buf
	return c, nil
}

// Close the connection.
func (c *conn) close() {
	switch {
	case c._UDP != nil:
		c._UDP.Close()
		c._UDP = nil
	case c._TCP != nil:
		c._TCP.Close()
		c._TCP = nil
	}
}

// Serve a new connection.
func (c *conn) serve() {
	for {
		// Request has been read in ServeUDP or ServeTCP
		w := new(response)
		w.conn = c
		req := new(Msg)
		if !req.Unpack(c.request) {
			// Send a format error back
			x := new(Msg)
			x.SetRcodeFormatError(req)
			buf, _ := x.Pack()
			w.Write(buf)
			break
		}
		w.req = req
		c.handler.ServeDNS(w, w.req) // this does the writing back to the client
		if c.hijacked {
			return
		}
		break // TODO(mg) Why is this a loop anyway
	}
	if c._TCP != nil {
		c.close() // Listen and Serve is closed then
	}
}

func (w *response) Write(data []byte) (n int, err error) {
	switch {
	case w.conn._UDP != nil:
		n, err = w.conn._UDP.WriteTo(data, w.conn.remoteAddr)
		if err != nil {
			return 0, err
		}
	case w.conn._TCP != nil:
		// TODO(mg) len(data) > 64K
		l := make([]byte, 2)
		l[0], l[1] = packUint16(uint16(len(data)))
		n, err = w.conn._TCP.Write(l)
		if err != nil {
			return n, err
		}
		if n != 2 {
			return n, io.ErrShortWrite
		}
		n, err = w.conn._TCP.Write(data)
		if err != nil {
			return n, err
		}
		i := n
		if i < len(data) {
			j, err := w.conn._TCP.Write(data[i:len(data)])
			if err != nil {
				return i, err
			}
			i += j
		}
		n = i
	}
	return n, nil
}

// RemoteAddr implements the ResponseWriter.RemoteAddr method
func (w *response) RemoteAddr() net.Addr { return w.conn.remoteAddr }
<|endoftext|>


<commit_before>// https://devcenter.heroku.com/articles/deploy-hooks#http-post-hook
// The parameters included in the request are the same as the variables available in the hook message: app, user, url, head, head_long, git_log and release. See below for their descriptions.
// This is an example payload:
// curl -X POST http://localhost:8080/$SECRET -d app=secure-woodland-9775 -d user=example%40example.com -d url=http://secure-woodland-9775.herokuapp.com -d head=4f20bdd -d head_long=4f20bdd -d prev_head= -d git_log=%20%20*%20Michael%20Friis%3A%20add%20bar -d release=v7

package main

import (
	"fmt"
	"github.com/gorilla/schema"
	"net/http"
	"regexp"
)

var (
	decoder          = schema.NewDecoder()
	stagingRegexp    = regexp.MustCompile(`staging`)
	productionRegexp = regexp.MustCompile(`production|\bprod\b`)
	heads            = make(map[string]string)
)

func init() {
	decoder.IgnoreUnknownKeys(true)
}

type HerokuWebhookPayload struct {
	App      string `schema:"app"`
	User     string `schema:"user"`
	Url      string `schema:"url"`
	Head     string `schema:"head"`
	HeadLong string `schema:"head_long"`
	PrevHead string `schema:"prev_head"`
	GitLog   string `schema:"git_log"`
	Release  string `schema:"release"`
	AppUUID  string `schema:"app_uuid"`
}

func ParseWebhook(r *http.Request) (payload *HerokuWebhookPayload, err error) {
	payload = new(HerokuWebhookPayload)
	err = decoder.Decode(payload, r.PostForm)
	if err != nil {
		fmt.Printf("Recieved Heroku Deploy Webhook: %+v\n", payload)
	}
	if payload.PrevHead == "" {
		payload.PrevHead = heads[payload.App]
		heads[payload.App] = payload.Head
	}
	return payload, err
}

func (payload *HerokuWebhookPayload) Environment() string {
	switch {
	case stagingRegexp.MatchString(payload.App):
		return "staging"
	case productionRegexp.MatchString(payload.App):
		return "production"
	default:
		return "development"
	}
}

// Return a GitHub compare URL if the repository is configured, otherwise just return the plain URL.
func (payload *HerokuWebhookPayload) URL() (url string) {
	repo := GitHubRepo(payload.App)
	if repo == "" {
		url = payload.Url
	} else {
		url = fmt.Sprint("https://github.com/", repo)
		if payload.PrevHead != "" {
			url = fmt.Sprint(url, "/compare", payload.PrevHead, "...", payload.Head)
		}
	}
	return url
}
<commit_msg>Fix Github compare URL<commit_after>// https://devcenter.heroku.com/articles/deploy-hooks#http-post-hook
// The parameters included in the request are the same as the variables available in the hook message: app, user, url, head, head_long, git_log and release. See below for their descriptions.
// This is an example payload:
// curl -X POST http://localhost:8080/$SECRET -d app=secure-woodland-9775 -d user=example%40example.com -d url=http://secure-woodland-9775.herokuapp.com -d head=4f20bdd -d head_long=4f20bdd -d prev_head= -d git_log=%20%20*%20Michael%20Friis%3A%20add%20bar -d release=v7

package main

import (
	"fmt"
	"github.com/gorilla/schema"
	"net/http"
	"regexp"
)

var (
	decoder          = schema.NewDecoder()
	stagingRegexp    = regexp.MustCompile(`staging`)
	productionRegexp = regexp.MustCompile(`production|\bprod\b`)
	heads            = make(map[string]string)
)

func init() {
	decoder.IgnoreUnknownKeys(true)
}

type HerokuWebhookPayload struct {
	App      string `schema:"app"`
	User     string `schema:"user"`
	Url      string `schema:"url"`
	Head     string `schema:"head"`
	HeadLong string `schema:"head_long"`
	PrevHead string `schema:"prev_head"`
	GitLog   string `schema:"git_log"`
	Release  string `schema:"release"`
	AppUUID  string `schema:"app_uuid"`
}

func ParseWebhook(r *http.Request) (payload *HerokuWebhookPayload, err error) {
	payload = new(HerokuWebhookPayload)
	err = decoder.Decode(payload, r.PostForm)
	if err != nil {
		fmt.Printf("Recieved Heroku Deploy Webhook: %+v\n", payload)
	}
	if payload.PrevHead == "" {
		payload.PrevHead = heads[payload.App]
		heads[payload.App] = payload.Head
	}
	return payload, err
}

func (payload *HerokuWebhookPayload) Environment() string {
	switch {
	case stagingRegexp.MatchString(payload.App):
		return "staging"
	case productionRegexp.MatchString(payload.App):
		return "production"
	default:
		return "development"
	}
}

// Return a GitHub compare URL if the repository is configured, otherwise just return the plain URL.
func (payload *HerokuWebhookPayload) URL() (url string) {
	repo := GitHubRepo(payload.App)
	if repo == "" {
		url = payload.Url
	} else {
		url = fmt.Sprint("https://github.com/", repo)
		if payload.PrevHead != "" {
			url = fmt.Sprint(url, "/compare/", payload.PrevHead, "...", payload.HeadLong)
		}
	}
	return url
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/jmcvetta/neoism"
)

//DB stock the Database variable
var DB *neoism.Database

//APIGetAllLines return All lines of bus
func APIGetAllLines(c *gin.Context) {
	content, err := GetAllLines()
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}
	c.JSON(200, content)
}

//APIGetStopsForLine return all stops for lineID
func APIGetStopsForLine(c *gin.Context) {
	lineID := c.Params.ByName("lineID")
	content, err := GetStopsFromLineID(lineID)
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}
	c.JSON(200, content)

}

func init() {
	var err error

	protocol := os.Getenv("NEO4J_PROT")
	user := os.Getenv("NEO4J_USER")
	password := os.Getenv("NEO4J_PASSWD")
	host := os.Getenv("NEO4J_HOST")
	port := os.Getenv("NEO4J_PORT")
	DB, err = neoism.Connect(fmt.Sprintf("%s://%s:%s@%s:%s", protocol, user, password, host, port))
	if err != nil {
		return
	}
}

func main() {
	app := gin.Default()

	app.GET("/", APIGetAllLines)
	app.GET("/:lineID", APIGetStopsForLine)
	app.Run(fmt.Sprintf(":%s", os.Getenv("API_PORT")))
	app.NoRoute(func(c *gin.Context) {
		c.JSON(404, gin.H{"code": "404", "message": "Page not found"})
	})
}
<commit_msg>try to catch json format<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/jmcvetta/neoism"
)

//DB stock the Database variable
var DB *neoism.Database

//APIGetAllLines return All lines of bus
func APIGetAllLines(c *gin.Context) {
	content, err := GetAllLines()
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}
	c.JSON(200, content)
}

//APIGetStopsForLine return all stops for lineID
func APIGetStopsForLine(c *gin.Context) {
	lineID := c.Params.ByName("lineID")
	format, get := c.Get("format")
	if get != true {
		return
	}
	fmt.Printf("%s\n", format)
	content, err := GetStopsFromLineID(lineID)
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}
	c.JSON(200, content)

}

func init() {
	var err error

	protocol := os.Getenv("NEO4J_PROT")
	user := os.Getenv("NEO4J_USER")
	password := os.Getenv("NEO4J_PASSWD")
	host := os.Getenv("NEO4J_HOST")
	port := os.Getenv("NEO4J_PORT")
	DB, err = neoism.Connect(fmt.Sprintf("%s://%s:%s@%s:%s", protocol, user, password, host, port))
	if err != nil {
		return
	}
}

func main() {
	app := gin.Default()

	app.GET("/", APIGetAllLines)
	app.GET("/:lineID", APIGetStopsForLine)
	app.Run(fmt.Sprintf(":%s", os.Getenv("API_PORT")))
	app.NoRoute(func(c *gin.Context) {
		c.JSON(404, gin.H{"code": "404", "message": "Page not found"})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"image"
	"image/jpeg"
	"log"
	"net/http"
	"regexp"
	"strconv"
)

var e = regexp.MustCompile(`/images/tiles/(?P<path>.+)/image_(?P<width>\d+)x(?P<height>\d+)_from_(?P<x1>\d+),(?P<y1>\d+)_to_(?P<x2>\d+),(?P<y2>\d+).jpg`)

func TileHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "image/jpeg")
	parts := e.FindStringSubmatch(req.URL.Path)
	d := map[string]string{}
	for i, name := range e.SubexpNames() {
		d[name] = parts[i]
	}
	path := d["path"]
	x1, _ := strconv.Atoi(d["x1"])
	y1, _ := strconv.Atoi(d["y1"])
	x2, _ := strconv.Atoi(d["x2"])
	y2, _ := strconv.Atoi(d["y2"])
	r := image.Rect(x1, y1, x2, y2)
	width, _ := strconv.Atoi(d["width"])
	height, _ := strconv.Atoi(d["height"])
	if err, i := NewImageTile(path, r, width, height); err == nil {
		if err = jpeg.Encode(w, i, nil); err != nil {
			log.Println(err)
		}
	} else {
		log.Println(err)
	}
}

func main() {
	Address := flag.String("address", ":8888", "http service address")
	flag.Parse()

	http.Handle("/", http.HandlerFunc(TileHandler))

	if err := http.ListenAndServe(*Address, nil); err != nil {
		log.Print("ListenAndServe:", err)
	}
}
<commit_msg>Set maximum processes to number of CPUs.<commit_after>package main

import (
	"flag"
	"image"
	"image/jpeg"
	"log"
	"net/http"
	"regexp"
	"runtime"
	"strconv"
)

var e = regexp.MustCompile(`/images/tiles/(?P<path>.+)/image_(?P<width>\d+)x(?P<height>\d+)_from_(?P<x1>\d+),(?P<y1>\d+)_to_(?P<x2>\d+),(?P<y2>\d+).jpg`)

func TileHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "image/jpeg")
	parts := e.FindStringSubmatch(req.URL.Path)
	d := map[string]string{}
	for i, name := range e.SubexpNames() {
		d[name] = parts[i]
	}
	path := d["path"]
	x1, _ := strconv.Atoi(d["x1"])
	y1, _ := strconv.Atoi(d["y1"])
	x2, _ := strconv.Atoi(d["x2"])
	y2, _ := strconv.Atoi(d["y2"])
	r := image.Rect(x1, y1, x2, y2)
	width, _ := strconv.Atoi(d["width"])
	height, _ := strconv.Atoi(d["height"])
	if err, i := NewImageTile(path, r, width, height); err == nil {
		if err = jpeg.Encode(w, i, nil); err != nil {
			log.Println(err)
		}
	} else {
		log.Println(err)
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	Address := flag.String("address", ":8888", "http service address")
	flag.Parse()

	http.Handle("/", http.HandlerFunc(TileHandler))

	if err := http.ListenAndServe(*Address, nil); err != nil {
		log.Print("ListenAndServe:", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"fmt"
	"errors"
	"strconv"
	"os"
	"encoding/json"
)

const (
	PROTOCOL_VERSION = "3.8"
	CONFIG_FILE_NAME = "config.json"
)

type Settings struct {
	Ip_address string
	Port string
	Max_connections string
}

// The parameter protocol_version is meant to be a string that is the protocol version you would like to get the message of.
// It returns the message and then an error if one is present.
func getProtocolVersionMessage(protocol_version string) (string, error) {
	if protocol_version == "" {
		return "", errors.New("The protocol version was an empty string")
	}

	if strings.Count(protocol_version, ".") > 1 {
		return "", errors.New("Too many (.) period characters! Expected just one")
	}

	if !strings.Contains(protocol_version, ".") {
		return "", errors.New("Protocol version invalid. Does not contain a period (.) Expected one")
	}

	const (
		MAX_PADDING = 3
	)

	splitString := strings.Split(protocol_version, ".")

	majorVersion := splitString[0]
	// It is needed to check if the major version and minor version are indeed integers.
	if _, err := strconv.Atoi(majorVersion); err != nil {
		// If err is not nil, strconv is not an integer.
		return "", errors.New("Version number to the left of the period (.) is not a valid integer")
	}
	if len(majorVersion) > MAX_PADDING {
		return "", errors.New("The version number to the left of the (.) had more than the max padding of characters!")
	}

	minorVersion := splitString[1]
	if _, err := strconv.Atoi(majorVersion); err != nil {
		// If err is not nil, strconv is not an integer.
		return "", errors.New("Version number to the right of the period (.) is not a valid integer")
	}
	if len(minorVersion) > MAX_PADDING {
		return "", errors.New("The version number to the right of the (.) had more than the max padding 3 characters!")
	}

	minorPaddingLength := MAX_PADDING - len(minorVersion)
	majorPaddingLength := MAX_PADDING - len(majorVersion)

	minorPadding := strings.Repeat("0", minorPaddingLength)
	majorPadding := strings.Repeat("0", majorPaddingLength)

	return fmt.Sprintf("RFB %s%s.%s%s\n", majorPadding, majorVersion, minorPadding, minorVersion), nil
}

func doProtocolVersionHandshake() string {
	// Nothing for right now...
	return "nothing #yoloswag.. soon this will be awesome..!"
}

func doSecurityHandshake() {

	const (
		INVALID = 0
		NONE = 1
		VNC_AUTH = 2
		RA2 = 5
		RA2ne = 6
		Tight = 16
		Ultra = 17
		TLS = 18
		VENCRYPT = 19
		GTK_VNC_SASL = 20
		MD5_HASH = 21
		COLIN_DEAN_XVP = 22
	)

	type securityResult struct {
		message uint32 // can be either 0 or 1.
			       // 0 = OK
			       // 1 = Failed
	}

	type reasonForFailure struct {
		reasonLength uint32
		reasonString []byte
	}

}

func loadConfigFromFile(file *os.File) (settings *Settings, err error) {
	if file == nil {
		return nil, errors.New("loadConfigFromFile: file is nil!")
	}
	jsonParser := json.NewDecoder(file)
	if err := jsonParser.Decode(&settings); err != nil {
		errorMessage := fmt.Sprintf("Could not decode file %s, check if it is valid JSON. Error message: %q\n", CONFIG_FILE_NAME, err)
		return nil, errors.New(errorMessage)
	}
	return settings, nil
}

// Sets up the default settings. To be used as a fallback for when settings cannot be obtained from the CONFIG_FILE_NAME file
// error is there in case it is needed in the future.
func loadDefaultConfig() (settings *Settings, err error) {
	const (
		DEFAULT_IP_ADDRESS = "127.0.0.1"
		DEFAULT_PORT = ":8000"
		DEFAULT_MAX_CONNECTIONS = "50"
	)
	settings = &Settings{DEFAULT_IP_ADDRESS, DEFAULT_PORT, DEFAULT_MAX_CONNECTIONS}
	return settings, nil
}

func main() {
	configFile, err := os.Open(CONFIG_FILE_NAME)
	var settings *Settings
	if err != nil {
		fmt.Errorf("Could not open the file %s. Are you sure it's really there? Reason: %q\n", CONFIG_FILE_NAME)
		fmt.Errorf("Going to be using the default config, instead...\n")
		settings, _ = loadDefaultConfig()
	} else {
		settings, _ = loadConfigFromFile(configFile)
	}
	fmt.Printf("Settings loaded! They are: %q", *settings)
}
<commit_msg>Add Gotem library<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/ColdSauce/Gotem"
	"os"
	"strconv"
	"strings"
)

const (
	PROTOCOL_VERSION = "3.8"
	CONFIG_FILE_NAME = "config.json"
)

type Settings struct {
	Ip_address      string
	Port            string
	Max_connections string
}

// The parameter protocol_version is meant to be a string that is the protocol version you would like to get the message of.
// It returns the message and then an error if one is present.
func getProtocolVersionMessage(protocol_version string) (string, error) {
	if protocol_version == "" {
		return "", errors.New("The protocol version was an empty string")
	}

	if strings.Count(protocol_version, ".") > 1 {
		return "", errors.New("Too many (.) period characters! Expected just one")
	}

	if !strings.Contains(protocol_version, ".") {
		return "", errors.New("Protocol version invalid. Does not contain a period (.) Expected one")
	}

	const (
		MAX_PADDING = 3
	)

	splitString := strings.Split(protocol_version, ".")

	majorVersion := splitString[0]
	// It is needed to check if the major version and minor version are indeed integers.
	if _, err := strconv.Atoi(majorVersion); err != nil {
		// If err is not nil, strconv is not an integer.
		return "", errors.New("Version number to the left of the period (.) is not a valid integer")
	}
	if len(majorVersion) > MAX_PADDING {
		return "", errors.New("The version number to the left of the (.) had more than the max padding of characters!")
	}

	minorVersion := splitString[1]
	if _, err := strconv.Atoi(majorVersion); err != nil {
		// If err is not nil, strconv is not an integer.
		return "", errors.New("Version number to the right of the period (.) is not a valid integer")
	}
	if len(minorVersion) > MAX_PADDING {
		return "", errors.New("The version number to the right of the (.) had more than the max padding 3 characters!")
	}

	minorPaddingLength := MAX_PADDING - len(minorVersion)
	majorPaddingLength := MAX_PADDING - len(majorVersion)

	minorPadding := strings.Repeat("0", minorPaddingLength)
	majorPadding := strings.Repeat("0", majorPaddingLength)

	return fmt.Sprintf("RFB %s%s.%s%s\n", majorPadding, majorVersion, minorPadding, minorVersion), nil
}

func doProtocolVersionHandshake() string {
	// Nothing for right now...
	return "nothing #yoloswag.. soon this will be awesome..!"
}

func doSecurityHandshake() {

	const (
		INVALID        = 0
		NONE           = 1
		VNC_AUTH       = 2
		RA2            = 5
		RA2ne          = 6
		Tight          = 16
		Ultra          = 17
		TLS            = 18
		VENCRYPT       = 19
		GTK_VNC_SASL   = 20
		MD5_HASH       = 21
		COLIN_DEAN_XVP = 22
	)

	type securityResult struct {
		message uint32 // can be either 0 or 1.
		// 0 = OK
		// 1 = Failed
	}

	type reasonForFailure struct {
		reasonLength uint32
		reasonString []byte
	}

}

func loadConfigFromFile(file *os.File) (settings *Settings, err error) {
	if file == nil {
		return nil, errors.New("loadConfigFromFile: file is nil!")
	}
	jsonParser := json.NewDecoder(file)
	if err := jsonParser.Decode(&settings); err != nil {
		errorMessage := fmt.Sprintf("Could not decode file %s, check if it is valid JSON. Error message: %q\n", CONFIG_FILE_NAME, err)
		return nil, errors.New(errorMessage)
	}
	return settings, nil
}

// Sets up the default settings. To be used as a fallback for when settings cannot be obtained from the CONFIG_FILE_NAME file
// error is there in case it is needed in the future.
func loadDefaultConfig() (settings *Settings, err error) {
	const (
		DEFAULT_IP_ADDRESS      = "127.0.0.1"
		DEFAULT_PORT            = ":8000"
		DEFAULT_MAX_CONNECTIONS = "50"
	)
	settings = &Settings{DEFAULT_IP_ADDRESS, DEFAULT_PORT, DEFAULT_MAX_CONNECTIONS}
	return settings, nil
}

func main() {
	// configFile, err := os.Open(CONFIG_FILE_NAME)
	// var settings *Settings
	// if err != nil {
	// 	fmt.Errorf("Could not open the file %s. Are you sure it's really there? Reason: %q\n", CONFIG_FILE_NAME)
	// 	fmt.Errorf("Going to be using the default config, instead...\n")
	// 	settings, _ = loadDefaultConfig()
	// } else {
	// 	settings, _ = loadConfigFromFile(configFile)
	// }
	// fmt.Printf("Settings loaded! They are: %q", *settings)
	Gotem.MoveMouseTo(&Gotem.Point{1230, 30})
}
<|endoftext|>


<commit_before>package copper

import (
	"math/rand"
	"net"
	"net/http"
	"sync"
	"sync/atomic"
	"time"
)

type lowLevelServer interface {
	subscribe(settings SubscribeSettings) (int64, error)
	getEndpoints(targetID int64) ([]Endpoint, error)
	streamEndpoints(targetID int64) (EndpointChangesStream, error)
	unsubscribe(targetID int64) error
	publish(targetID int64, name string, settings PublishSettings) error
	unpublish(targetID int64) error
	setRoute(name string, routes ...Route) error
	listRoutes() ([]string, error)
	lookupRoute(name string) ([]Route, error)
	streamServices() (ServiceChangesStream, error)
}

type handleRequestStatus int

const (
	// Request was handled and the stream consumed
	handleRequestStatusDone handleRequestStatus = iota
	// There was an attempt to handle the request, but it was impossible, and
	// future requests are unlikely to succeed. While the stream was not
	// consumed this status implies that locks had been unlocked and
	// configuration has changed.
	handleRequestStatusImpossible
	// There was not enough capacity to handle the request
	handleRequestStatusOverCapacity
	// There was no route to send the request to
	handleRequestStatusNoRoute
)

type handleRequestCallback func(remote Stream) handleRequestStatus

type endpointReference interface {
	getEndpointsLocked() []Endpoint
	handleRequestLocked(callback handleRequestCallback) handleRequestStatus
}

type server struct {
	lock   sync.Mutex
	random *rand.Rand

	lastTargetID int64

	peers map[serverPeerKey]*serverPeer

	subsByName map[string]map[*serverSubscription]struct{}

	pubByTarget map[int64]*serverPublication
	pubsByName  map[string]map[uint32]*serverPublication
	pubWatchers map[*serverServiceChangesStream]struct{}

	routeByName map[string]*serverRoute

	failure    error
	closedchan chan struct{}
	finishchan chan struct{}
	listenwg   sync.WaitGroup
	clientwg   sync.WaitGroup
	listeners  []net.Listener

	clients map[*serverClient]struct{}
}

// NewServer returns a new local server
func NewServer() Server {
	s := &server{
		random: rand.New(rand.NewSource(time.Now().UnixNano())),

		peers: make(map[serverPeerKey]*serverPeer),

		subsByName: make(map[string]map[*serverSubscription]struct{}),

		pubByTarget: make(map[int64]*serverPublication),
		pubsByName:  make(map[string]map[uint32]*serverPublication),
		pubWatchers: make(map[*serverServiceChangesStream]struct{}),

		routeByName: make(map[string]*serverRoute),

		closedchan: make(chan struct{}),

		clients: make(map[*serverClient]struct{}),
	}
	return s
}

func (s *server) allocateTargetID() int64 {
	return atomic.AddInt64(&s.lastTargetID, 1)
}

func (s *server) closeWithError(err error) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if err == nil {
		err = ECONNCLOSED
	}
	preverror := s.failure
	if s.failure == nil {
		s.failure = err
		listeners := s.listeners
		s.listeners = nil
		for _, listener := range listeners {
			listener.Close()
		}
		for _, peer := range s.peers {
			peer.closeWithErrorLocked(err)
		}
		for client := range s.clients {
			client.closeWithErrorLocked(err)
		}
		for cs := range s.pubWatchers {
			cs.stopLocked()
		}
	}
	return preverror
}

func (s *server) addClient(conn net.Conn, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		conn.Close()
		return s.failure
	}
	client := newServerClient(s, conn, allowChanges)
	s.clients[client] = struct{}{}
	return nil
}

func (s *server) acceptor(listener net.Listener, allowChanges bool) {
	defer s.listenwg.Done()
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			s.closeWithError(err)
			return
		}
		err = s.addClient(conn, allowChanges)
		if err != nil {
			s.closeWithError(err)
			return
		}
	}
}

func (s *server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// TODO
	// Find where to forward this request, using the longest part of the uri.
	// First routes should be checked, then local/remote depending on priority
}

func (s *server) httpacceptor(listener net.Listener) {
	defer s.listenwg.Done()
	defer listener.Close()
	httpserver := &http.Server{
		Handler: s,
	}
	err := httpserver.Serve(listener)
	if err != nil {
		s.closeWithError(err)
		return
	}
}

func (s *server) AddPeer(network, address string, distance uint32) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	return s.addPeerLocked(network, address, distance)
}

func (s *server) AddListener(listener net.Listener, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.acceptor(listener, allowChanges)
	return nil
}

func (s *server) AddHTTPListener(listener net.Listener) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.httpacceptor(listener)
	return nil
}

func (s *server) SetUpstream(upstream Client) error {
	return EUNSUPPORTED
}

func (s *server) Err() error {
	s.lock.Lock()
	defer s.lock.Unlock()
	return s.failure
}

func (s *server) Close() error {
	return s.closeWithError(ECONNSHUTDOWN)
}

func (s *server) Done() <-chan struct{} {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.finishchan == nil {
		s.finishchan = make(chan struct{})
		go func() {
			defer close(s.finishchan)
			s.listenwg.Wait()
			s.clientwg.Wait()
		}()
	}
	return s.finishchan
}

func (s *server) Closed() <-chan struct{} {
	return s.closedchan
}
<commit_msg>Implement http forwarding<commit_after>package copper

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/http"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type lowLevelServer interface {
	subscribe(settings SubscribeSettings) (int64, error)
	getEndpoints(targetID int64) ([]Endpoint, error)
	streamEndpoints(targetID int64) (EndpointChangesStream, error)
	unsubscribe(targetID int64) error
	publish(targetID int64, name string, settings PublishSettings) error
	unpublish(targetID int64) error
	setRoute(name string, routes ...Route) error
	listRoutes() ([]string, error)
	lookupRoute(name string) ([]Route, error)
	streamServices() (ServiceChangesStream, error)
}

type handleRequestStatus int

const (
	// Request was handled and the stream consumed
	handleRequestStatusDone handleRequestStatus = iota
	// There was an attempt to handle the request, but it was impossible, and
	// future requests are unlikely to succeed. While the stream was not
	// consumed this status implies that locks had been unlocked and
	// configuration has changed.
	handleRequestStatusImpossible
	// There was not enough capacity to handle the request
	handleRequestStatusOverCapacity
	// There was no route to send the request to
	handleRequestStatusNoRoute
)

type handleRequestCallback func(remote Stream) handleRequestStatus

type endpointReference interface {
	getEndpointsLocked() []Endpoint
	handleRequestLocked(callback handleRequestCallback) handleRequestStatus
}

type server struct {
	lock   sync.Mutex
	random *rand.Rand

	lastTargetID int64

	peers map[serverPeerKey]*serverPeer

	subsByName map[string]map[*serverSubscription]struct{}

	pubByTarget map[int64]*serverPublication
	pubsByName  map[string]map[uint32]*serverPublication
	pubWatchers map[*serverServiceChangesStream]struct{}

	routeByName map[string]*serverRoute

	failure    error
	closedchan chan struct{}
	finishchan chan struct{}
	listenwg   sync.WaitGroup
	clientwg   sync.WaitGroup
	listeners  []net.Listener

	clients map[*serverClient]struct{}
}

// NewServer returns a new local server
func NewServer() Server {
	s := &server{
		random: rand.New(rand.NewSource(time.Now().UnixNano())),

		peers: make(map[serverPeerKey]*serverPeer),

		subsByName: make(map[string]map[*serverSubscription]struct{}),

		pubByTarget: make(map[int64]*serverPublication),
		pubsByName:  make(map[string]map[uint32]*serverPublication),
		pubWatchers: make(map[*serverServiceChangesStream]struct{}),

		routeByName: make(map[string]*serverRoute),

		closedchan: make(chan struct{}),

		clients: make(map[*serverClient]struct{}),
	}
	return s
}

func (s *server) allocateTargetID() int64 {
	return atomic.AddInt64(&s.lastTargetID, 1)
}

func (s *server) closeWithError(err error) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if err == nil {
		err = ECONNCLOSED
	}
	preverror := s.failure
	if s.failure == nil {
		s.failure = err
		listeners := s.listeners
		s.listeners = nil
		for _, listener := range listeners {
			listener.Close()
		}
		for _, peer := range s.peers {
			peer.closeWithErrorLocked(err)
		}
		for client := range s.clients {
			client.closeWithErrorLocked(err)
		}
		for cs := range s.pubWatchers {
			cs.stopLocked()
		}
	}
	return preverror
}

func (s *server) addClient(conn net.Conn, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		conn.Close()
		return s.failure
	}
	client := newServerClient(s, conn, allowChanges)
	s.clients[client] = struct{}{}
	return nil
}

func (s *server) acceptor(listener net.Listener, allowChanges bool) {
	defer s.listenwg.Done()
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			s.closeWithError(err)
			return
		}
		err = s.addClient(conn, allowChanges)
		if err != nil {
			s.closeWithError(err)
			return
		}
	}
}

func (s *server) findEndpointLocked(name string, minDistance, maxDistance uint32) (endpoint endpointReference) {
	var minPriority uint32
	route := s.routeByName[name]
	if route != nil {
		return route
	}
	pubs := s.pubsByName[name]
	if len(pubs) > 0 {
		for _, pub := range pubs {
			if pub.settings.Distance < minDistance || pub.settings.Distance > maxDistance {
				continue
			}
			if endpoint == nil || pub.settings.Priority < minPriority {
				if pub.settings.Priority == 0 {
					return pub
				}
				endpoint = pub
				minPriority = pub.settings.Priority
			}
		}
		if endpoint != nil {
			return endpoint
		}
	}
	for _, peer := range s.peers {
		remotes := peer.remotesByName[name]
		if len(remotes) > 0 {
			for _, remote := range remotes {
				if remote.settings.Distance < minDistance || remote.settings.Distance > maxDistance {
					continue
				}
				if endpoint == nil || remote.settings.Priority < minPriority {
					if remote.settings.Priority == 0 {
						return remote
					}
					endpoint = remote
					minPriority = remote.settings.Priority
				}
			}
		}
	}
	return endpoint
}

func (s *server) findEndpointHTTPLocked(path string) (endpoint endpointReference) {
	if len(path) == 0 {
		path = "/"
	} else if path[0] != '/' {
		path = "/" + path
	}
	for len(path) > 0 {
		endpoint = s.findEndpointLocked("http:"+path, 0, 1)
		if endpoint != nil {
			return endpoint
		}
		endpoint = s.findEndpointLocked("http:"+path, 2, 2)
		if endpoint != nil {
			return endpoint
		}
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		}
		index := strings.LastIndex(path, "/")
		if index == -1 {
			break
		}
		path = path[:index+1]
	}
	return nil
}

// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

func copyHeaders(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func (s *server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	status := func() handleRequestStatus {
		s.lock.Lock()
		defer s.lock.Unlock()
		var endpoint endpointReference
		service := req.Header.Get("X-Copper-Service")
		if len(service) != 0 {
			endpoint = s.findEndpointLocked("http:"+service, 0, 1)
			if endpoint == nil {
				endpoint = s.findEndpointLocked("http:"+service, 2, 2)
			}
		} else {
			endpoint = s.findEndpointHTTPLocked(req.URL.Path)
		}
		if endpoint == nil {
			return handleRequestStatusNoRoute
		}
		return endpoint.handleRequestLocked(func(remote Stream) handleRequestStatus {
			outreq := new(http.Request)
			*outreq = *req
			modified := false
			for _, h := range hopHeaders {
				if len(outreq.Header[h]) > 0 {
					if !modified {
						outreq.Header = make(http.Header)
						copyHeaders(outreq.Header, req.Header)
					}
					delete(outreq.Header, h)
				}
			}
			go func() {
				err := outreq.Write(remote)
				if err != nil {
					remote.CloseWithError(err)
				}
			}()
			r := bufio.NewReader(remote)
			res, err := http.ReadResponse(r, outreq)
			if err == nil && res.StatusCode == 100 {
				// Skip 100-continue
				res, err = http.ReadResponse(r, outreq)
			}
			if err != nil {
				remote.CloseWithError(err)
				text := err.Error()
				rw.Header().Set("Content-Length", fmt.Sprintf("%d", len(text)))
				rw.WriteHeader(502)
				rw.Write([]byte(text))
			} else {
				defer res.Body.Close()
				copyHeaders(rw.Header(), res.Header)
				rw.WriteHeader(res.StatusCode)
				io.Copy(rw, res.Body)
			}
			return handleRequestStatusDone
		})
	}()
	if status != handleRequestStatusDone {
		rw.WriteHeader(404)
	}
}

func (s *server) httpacceptor(listener net.Listener) {
	defer s.listenwg.Done()
	defer listener.Close()
	httpserver := &http.Server{
		Handler: s,
	}
	err := httpserver.Serve(listener)
	if err != nil {
		s.closeWithError(err)
		return
	}
}

func (s *server) AddPeer(network, address string, distance uint32) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	return s.addPeerLocked(network, address, distance)
}

func (s *server) AddListener(listener net.Listener, allowChanges bool) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.acceptor(listener, allowChanges)
	return nil
}

func (s *server) AddHTTPListener(listener net.Listener) error {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.failure != nil {
		return s.failure
	}
	s.listeners = append(s.listeners, listener)
	s.listenwg.Add(1)
	go s.httpacceptor(listener)
	return nil
}

func (s *server) SetUpstream(upstream Client) error {
	return EUNSUPPORTED
}

func (s *server) Err() error {
	s.lock.Lock()
	defer s.lock.Unlock()
	return s.failure
}

func (s *server) Close() error {
	return s.closeWithError(ECONNSHUTDOWN)
}

func (s *server) Done() <-chan struct{} {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.finishchan == nil {
		s.finishchan = make(chan struct{})
		go func() {
			defer close(s.finishchan)
			s.listenwg.Wait()
			s.clientwg.Wait()
		}()
	}
	return s.finishchan
}

func (s *server) Closed() <-chan struct{} {
	return s.closedchan
}
<|endoftext|>


<commit_before>package uic

import (
	"time"
)

type User struct {
	Id      int64     `json:"id"`
	Name    string    `json:"name"`
	Cnname  string    `json:"cnname"`
	Passwd  string    `json:"-"`
	Email   string    `json:"email"`
	Phone   string    `json:"phone"`
	IM      string    `json:"im" orm:"column(im)"`
	QQ      string    `json:"qq" orm:"column(qq)"`
	Role    int       `json:"role"`
	Created time.Time `json:"-"`
}

type Team struct {
	Id      int64     `json:"id"`
	Name    string    `json:"name"`
	Resume  string    `json:"resume"`
	Creator int64     `json:"creator"`
	Created time.Time `json:"-"`
}

type RelTeamUser struct {
	Id  int64
	Tid int64
	Uid int64
}

type Session struct {
	Id      int64
	Uid     int64
	Sig     string
	Expired int
}
<commit_msg>Fixed field "Created".<commit_after>package uic

import (
	"time"
)

type User struct {
	Id      int64     `json:"id"`
	Name    string    `json:"name"`
	Cnname  string    `json:"cnname"`
	Passwd  string    `json:"-"`
	Email   string    `json:"email"`
	Phone   string    `json:"phone"`
	IM      string    `json:"im" orm:"column(im)"`
	QQ      string    `json:"qq" orm:"column(qq)"`
	Role    int       `json:"role"`
	Created time.Time `orm:"auto_now_add;type(datetime)"`
}

type Team struct {
	Id      int64     `json:"id"`
	Name    string    `json:"name"`
	Resume  string    `json:"resume"`
	Creator int64     `json:"creator"`
	Created time.Time `orm:"auto_now_add;type(datetime)"`
}

type RelTeamUser struct {
	Id  int64
	Tid int64
	Uid int64
}

type Session struct {
	Id      int64
	Uid     int64
	Sig     string
	Expired int
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/clawio/service.auth/lib"
	pb "github.com/clawio/service.localstore.meta/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"mime"
	"os"
	"path"
)

const (
	dirPerm = 0755
)

var (
	unauthenticatedError = grpc.Errorf(codes.Unauthenticated, "identity not found")
	permissionDenied     = grpc.Errorf(codes.PermissionDenied, "access denied")
)

type newServerParams struct {
	dataDir      string
	tmpDir       string
	sharedSecret string
}

func newServer(p *newServerParams) *server {
	return &server{p}
}

type server struct {
	p *newServerParams
}

func (s *server) Home(ctx context.Context, req *pb.HomeReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	home := getHome(idt)

	log.Infof("home is %s", home)

	pp := s.getPhysicalPath(home)

	log.Infof("physical path is %s", pp)

	_, err = os.Stat(pp)

	// Create home dir if not exists
	if os.IsNotExist(err) {

		log.Infof("home does not exist")

		err = os.MkdirAll(pp, dirPerm)
		if err != nil {
			log.Error(err)
			return nil, err
		}

		log.Infof("home created")

		return &pb.Void{}, nil
	}

	if err != nil {
		log.Error(err)
		return nil, err
	}

	log.Infof("home already created")

	return &pb.Void{}, nil
}

func (s *server) Mkdir(ctx context.Context, req *pb.MkdirReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	if !isUnderHome(p, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if p == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot create directory")
	}

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	err = os.Mkdir(pp, dirPerm)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("created dir %s", pp)

	return &pb.Void{}, nil
}

func (s *server) Stat(ctx context.Context, req *pb.StatReq) (*pb.Metadata, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, unauthenticatedError
	}

	log.Infof("%s", s)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	if !isUnderHome(p, idt) {
		log.Error(permissionDenied)
		return &pb.Metadata{}, permissionDenied
	}

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	parentMeta, err := s.getMeta(pp)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, err
	}

	log.Infof("stated %s", pp)

	if !parentMeta.IsContainer || req.Children == false {
		return parentMeta, nil
	}

	dir, err := os.Open(pp)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, err
	}

	log.Infof("opened dir %s", pp)

	defer dir.Close()

	names, err := dir.Readdirnames(0)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, err
	}

	log.Infof("dir %s has %d entries", pp, len(names))

	for _, n := range names {

		m, err := s.getMeta(path.Join(parentMeta.Path, path.Clean(n)))
		if err != nil {
			log.Error(err)
		}

		parentMeta.Children = append(parentMeta.Children, m)
	}

	log.Infof("added %d entries to parent", len(parentMeta.Children))

	return parentMeta, nil
}

func (s *server) Cp(ctx context.Context, req *pb.CpReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	src := path.Clean(req.Src)
	dst := path.Clean(req.Dst)

	log.Infof("src is %s", src)
	log.Info("dst is %s", dst)

	if !isUnderHome(src, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if !isUnderHome(dst, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if src == getHome(idt) || dst == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot copy from/to home directory")
	}

	psrc := s.getPhysicalPath(src)
	pdst := s.getPhysicalPath(dst)

	log.Infof("physical src is %s", psrc)
	log.Infof("physical dst is %s", pdst)

	statReq := &pb.StatReq{}
	statReq.AccessToken = req.AccessToken
	statReq.Path = req.Src

	meta, err := s.Stat(ctx, statReq)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("stated %s", src)

	if meta.IsContainer {
		err = copyDir(psrc, pdst)
		if err != nil {
			return &pb.Void{}, err
		}

		log.Infof("copied from dir %s to dir %s", psrc, pdst)
	}

	err = copyFile(psrc, pdst, int64(meta.Size))
	if err != nil {
		return &pb.Void{}, err
	}

	log.Infof("copied from file %s to file %s", psrc, pdst)

	return &pb.Void{}, nil
}

func (s *server) Mv(ctx context.Context, req *pb.MvReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	src := path.Clean(req.Src)
	dst := path.Clean(req.Dst)

	log.Infof("src is %s", src)
	log.Info("dst is %s", dst)

	if isUnderHome(src, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if !isUnderHome(dst, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if src == getHome(idt) || dst == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot rename from/to home directory")
	}

	psrc := s.getPhysicalPath(src)
	pdst := s.getPhysicalPath(dst)

	log.Infof("physical src is %s", psrc)
	log.Infof("physical dst is %s", pdst)

	err = os.Rename(psrc, pdst)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("renamed from %s to %s", psrc, pdst)

	return &pb.Void{}, nil
}

func (s *server) Rm(ctx context.Context, req *pb.RmReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	if !isUnderHome(p, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if p == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot remove home directory")
	}

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	err = os.Remove(pp)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("removed %s", pp)

	return &pb.Void{}, nil
}

// getMeta return the metadata of path p. p is the physical path.
func (s *server) getMeta(p string) (*pb.Metadata, error) {

	finfo, err := os.Stat(p)
	if err != nil {
		return &pb.Metadata{}, err
	}

	m := &pb.Metadata{}
	m.Id = "TODO"
	m.Path = path.Clean(p) // TODO return logical path
	m.Size = uint32(finfo.Size())
	m.IsContainer = finfo.IsDir()
	m.Modified = uint32(finfo.ModTime().Unix())
	m.Etag = "TODO"
	m.Permissions = 0
	m.MimeType = mime.TypeByExtension(path.Ext(m.Path))

	if m.MimeType == "" {
		m.MimeType = "application/octet-stream"
	}

	if m.IsContainer {
		m.MimeType = "inode/container"
	}

	return m, nil
}

func (s *server) getPhysicalPath(p string) string {
	return path.Join(s.p.dataDir, path.Clean(p))
}
<commit_msg>Fixed metadata path.<commit_after>package main

import (
	"github.com/clawio/service.auth/lib"
	pb "github.com/clawio/service.localstore.meta/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"mime"
	"os"
	"path"
	"strings"
)

const (
	dirPerm = 0755
)

var (
	unauthenticatedError = grpc.Errorf(codes.Unauthenticated, "identity not found")
	permissionDenied     = grpc.Errorf(codes.PermissionDenied, "access denied")
)

type newServerParams struct {
	dataDir      string
	tmpDir       string
	sharedSecret string
}

func newServer(p *newServerParams) *server {
	return &server{p}
}

type server struct {
	p *newServerParams
}

func (s *server) Home(ctx context.Context, req *pb.HomeReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	home := getHome(idt)

	log.Infof("home is %s", home)

	pp := s.getPhysicalPath(home)

	log.Infof("physical path is %s", pp)

	_, err = os.Stat(pp)

	// Create home dir if not exists
	if os.IsNotExist(err) {

		log.Infof("home does not exist")

		err = os.MkdirAll(pp, dirPerm)
		if err != nil {
			log.Error(err)
			return nil, err
		}

		log.Infof("home created")

		return &pb.Void{}, nil
	}

	if err != nil {
		log.Error(err)
		return nil, err
	}

	log.Infof("home already created")

	return &pb.Void{}, nil
}

func (s *server) Mkdir(ctx context.Context, req *pb.MkdirReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	if !isUnderHome(p, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if p == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot create directory")
	}

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	err = os.Mkdir(pp, dirPerm)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("created dir %s", pp)

	return &pb.Void{}, nil
}

func (s *server) Stat(ctx context.Context, req *pb.StatReq) (*pb.Metadata, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, unauthenticatedError
	}

	log.Infof("%s", s)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	if !isUnderHome(p, idt) {
		log.Error(permissionDenied)
		return &pb.Metadata{}, permissionDenied
	}

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	parentMeta, err := s.getMeta(pp)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, err
	}

	log.Infof("stated %s", pp)

	if !parentMeta.IsContainer || req.Children == false {
		return parentMeta, nil
	}

	dir, err := os.Open(pp)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, err
	}

	log.Infof("opened dir %s", pp)

	defer dir.Close()

	names, err := dir.Readdirnames(0)
	if err != nil {
		log.Error(err)
		return &pb.Metadata{}, err
	}

	log.Infof("dir %s has %d entries", pp, len(names))

	for _, n := range names {

		m, err := s.getMeta(path.Join(parentMeta.Path, path.Clean(n)))
		if err != nil {
			log.Error(err)
		}

		parentMeta.Children = append(parentMeta.Children, m)
	}

	log.Infof("added %d entries to parent", len(parentMeta.Children))

	return parentMeta, nil
}

func (s *server) Cp(ctx context.Context, req *pb.CpReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	src := path.Clean(req.Src)
	dst := path.Clean(req.Dst)

	log.Infof("src is %s", src)
	log.Info("dst is %s", dst)

	if !isUnderHome(src, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if !isUnderHome(dst, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if src == getHome(idt) || dst == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot copy from/to home directory")
	}

	psrc := s.getPhysicalPath(src)
	pdst := s.getPhysicalPath(dst)

	log.Infof("physical src is %s", psrc)
	log.Infof("physical dst is %s", pdst)

	statReq := &pb.StatReq{}
	statReq.AccessToken = req.AccessToken
	statReq.Path = req.Src

	meta, err := s.Stat(ctx, statReq)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("stated %s", src)

	if meta.IsContainer {
		err = copyDir(psrc, pdst)
		if err != nil {
			return &pb.Void{}, err
		}

		log.Infof("copied from dir %s to dir %s", psrc, pdst)
	}

	err = copyFile(psrc, pdst, int64(meta.Size))
	if err != nil {
		return &pb.Void{}, err
	}

	log.Infof("copied from file %s to file %s", psrc, pdst)

	return &pb.Void{}, nil
}

func (s *server) Mv(ctx context.Context, req *pb.MvReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	src := path.Clean(req.Src)
	dst := path.Clean(req.Dst)

	log.Infof("src is %s", src)
	log.Info("dst is %s", dst)

	if isUnderHome(src, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if !isUnderHome(dst, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if src == getHome(idt) || dst == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot rename from/to home directory")
	}

	psrc := s.getPhysicalPath(src)
	pdst := s.getPhysicalPath(dst)

	log.Infof("physical src is %s", psrc)
	log.Infof("physical dst is %s", pdst)

	err = os.Rename(psrc, pdst)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("renamed from %s to %s", psrc, pdst)

	return &pb.Void{}, nil
}

func (s *server) Rm(ctx context.Context, req *pb.RmReq) (*pb.Void, error) {

	idt, err := lib.ParseToken(req.AccessToken, s.p.sharedSecret)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, unauthenticatedError
	}

	log.Infof("%s", idt)

	p := path.Clean(req.Path)

	log.Infof("path is %s", p)

	if !isUnderHome(p, idt) {
		log.Error(permissionDenied)
		return &pb.Void{}, permissionDenied
	}

	if p == getHome(idt) {
		return &pb.Void{}, grpc.Errorf(codes.PermissionDenied, "cannot remove home directory")
	}

	pp := s.getPhysicalPath(p)

	log.Infof("physical path is %s", pp)

	err = os.Remove(pp)
	if err != nil {
		log.Error(err)
		return &pb.Void{}, err
	}

	log.Infof("removed %s", pp)

	return &pb.Void{}, nil
}

// getMeta return the metadata of path pp.
// p is the physical path and should never be exposed to clients.
func (s *server) getMeta(pp string) (*pb.Metadata, error) {

	finfo, err := os.Stat(pp)
	if err != nil {
		return &pb.Metadata{}, err
	}

	logicalPath := s.getLogicalPath(pp)

	m := &pb.Metadata{}
	m.Id = "TODO"
	m.Path = logicalPath
	m.Size = uint32(finfo.Size())
	m.IsContainer = finfo.IsDir()
	m.Modified = uint32(finfo.ModTime().Unix())
	m.Etag = "TODO"
	m.Permissions = 0
	m.MimeType = mime.TypeByExtension(path.Ext(m.Path))

	if m.MimeType == "" {
		m.MimeType = "application/octet-stream"
	}

	if m.IsContainer {
		m.MimeType = "inode/container"
	}

	return m, nil
}

func (s *server) getPhysicalPath(p string) string {
	return path.Join(s.p.dataDir, path.Clean(p))
}

func (s *server) getLogicalPath(pp string) string {
	return path.Clean(strings.TrimPrefix(pp, s.p.dataDir))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"math/rand"
	"net/http"
	"strconv"

	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
	"time"
)

// Upgrader specifies parameters for upgrading an HTTP connection to a WebSocket connection.
// Without parameters, default options will be applied (ReadBufferSize WriteBufferSize are set to 4096
var upgrader = websocket.Upgrader{} // use default options

type Hub struct {
	token      string
	connection *websocket.Conn
	toSend     chan []byte
    actionMap  map[string] chan *Action
}

var hubs []*Hub

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

	t := r.URL.Query().Get("token")

	// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
	// c (i.e. Conn type) represents a WebSocket connection.
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}

	defer c.Close()

	h := &Hub{token: t, connection: c, toSend: make(chan []byte), actionMap: make(map[string] chan *Action)}
	hubs = append(hubs, h)

	go h.sendRequest()

	go h.receiveResponse()

	h.run()
}

func (h *Hub) receiveResponse() {
	defer h.connection.Close()

	for {
		messageType, message, err := h.connection.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			continue
		}

		if messageType != websocket.TextMessage {
			log.Println("received a non text message")
			continue
		}

		var action Action
		json.Unmarshal(message, &action)

		h.actionMap[action.ID] <- &action
	}
}

func (h *Hub) createRequest() {
	id := strconv.Itoa(rand.Intn(4))

	var parameters []ActionParameter

	switch id {
	case "1":
		parameters = []ActionParameter{{Name: "param", Value: int(1)}}

	case "2":
		parameters = []ActionParameter{{Name: "param", Value: "2"}}

	case "3":
		parameters = []ActionParameter{{Name: "param1", Value: 3.3}, {Name: "param2", Value: true}}
	}

	actionID := uuid.NewV4().String()

	actionChan := make(chan *Action)
	h.actionMap[actionID] = actionChan

	action := Action{
		ID:         actionID,
		Name:       "action" + id,
		Parameters: parameters,
	}

	jsonAction, err := json.Marshal(action)
	if err != nil {
		log.Println("marshal:", err)
		return
	}

	h.toSend <- []byte(jsonAction)

	log.Printf("sent: %s", jsonAction)

	responseAction := <- actionChan

	log.Printf("recv: action[%s] name=%s  result=%s\n", responseAction.ID, responseAction.Name, responseAction.Result)

}

func (h *Hub) run() {

	for {

		go h.createRequest()

		time.Sleep(time.Duration(rand.Int63n(50))*time.Millisecond)
	}
}

func (h *Hub) sendRequest() {
	defer h.connection.Close()

	for {
		select {
		case msg, ok := <-h.toSend:
			// The boolean variable ok returned by a receive operator indicates whether the received value was sent
			// on the channel (true) or is a zero value returned because the channel is closed and empty (false).
			if ok == false {
				// TODO: what to do here ?
			}
			err := h.connection.WriteMessage(websocket.TextMessage, msg)
			if err != nil {
				log.Println("write:", err)
			}
		}
	}
}

func startServer() {
	/*
		clients = make([]WebSocketStore, 0)
		actionMap = make(map[string]chan Action)
		go func() {
			reader := bufio.NewReader(os.Stdin)

			for {

				for {
					if len(clients) > 0 {
						break
					}
					fmt.Println("No client for now. Press [enter] to refresh")
					reader.ReadString('\n')
				}

				fmt.Println("List of the clients:")
				for i, v := range clients {
					fmt.Printf("%d- %s\n", i, v.token)
				}
				fmt.Print("Choose a client: ")
				var choice int
				fmt.Scanf("%d", &choice)

				go sendAction(clients[choice].socket)
			}
		}()
	*/
	http.HandleFunc("/action", handleActionFunc)
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>Add mutext to the action map<commit_after>package main

import (
	"encoding/json"
	"log"
	"math/rand"
	"net/http"
	"strconv"

	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
	"sync"
	"time"
)

// Upgrader specifies parameters for upgrading an HTTP connection to a WebSocket connection.
// Without parameters, default options will be applied (ReadBufferSize WriteBufferSize are set to 4096
var upgrader = websocket.Upgrader{} // use default options

type Hub struct {
	token      string
	connection *websocket.Conn
	toSend     chan []byte
	actions    actionMap
}
type actionMap struct {
	sync.RWMutex
	m map[string]chan *Action
}

var hubs []*Hub

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

	t := r.URL.Query().Get("token")

	// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
	// c (i.e. Conn type) represents a WebSocket connection.
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}

	defer c.Close()

	h := &Hub{token: t, connection: c, toSend: make(chan []byte), actions: actionMap{m: make(map[string]chan *Action)}}
	hubs = append(hubs, h)

	go h.sendRequest()

	go h.receiveResponse()

	h.run()
}

func (h *Hub) receiveResponse() {
	defer h.connection.Close()

	for {
		messageType, message, err := h.connection.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			continue
		}

		if messageType != websocket.TextMessage {
			log.Println("received a non text message")
			continue
		}

		var action Action
		json.Unmarshal(message, &action)

		h.actions.Lock()
		h.actions.m[action.ID] <- &action
		h.actions.Unlock()
	}
}

func (h *Hub) createRequest() {
	id := strconv.Itoa(rand.Intn(4))

	var parameters []ActionParameter

	switch id {
	case "1":
		parameters = []ActionParameter{{Name: "param", Value: int(1)}}

	case "2":
		parameters = []ActionParameter{{Name: "param", Value: "2"}}

	case "3":
		parameters = []ActionParameter{{Name: "param1", Value: 3.3}, {Name: "param2", Value: true}}
	}

	actionID := uuid.NewV4().String()

	actionChan := make(chan *Action)
	h.actions.Lock()
	h.actions.m[actionID] = actionChan
	h.actions.Unlock()

	action := Action{
		ID:         actionID,
		Name:       "action" + id,
		Parameters: parameters,
	}

	jsonAction, err := json.Marshal(action)
	if err != nil {
		log.Println("marshal:", err)
		return
	}

	h.toSend <- []byte(jsonAction)

	log.Printf("sent: %s", jsonAction)

	responseAction := <-actionChan

	log.Printf("recv: action[%s] name=%s  result=%s\n", responseAction.ID, responseAction.Name, responseAction.Result)

}

func (h *Hub) run() {

	for {

		go h.createRequest()

		time.Sleep(time.Duration(rand.Int63n(50)) * time.Millisecond)
	}
}

func (h *Hub) sendRequest() {
	defer h.connection.Close()

	for {
		select {
		case msg, ok := <-h.toSend:
			// The boolean variable ok returned by a receive operator indicates whether the received value was sent
			// on the channel (true) or is a zero value returned because the channel is closed and empty (false).
			if ok == false {
				// TODO: what to do here ?
			}
			err := h.connection.WriteMessage(websocket.TextMessage, msg)
			if err != nil {
				log.Println("write:", err)
			}
		}
	}
}

func startServer() {
	/*
		clients = make([]WebSocketStore, 0)
		actionMap = make(map[string]chan Action)
		go func() {
			reader := bufio.NewReader(os.Stdin)

			for {

				for {
					if len(clients) > 0 {
						break
					}
					fmt.Println("No client for now. Press [enter] to refresh")
					reader.ReadString('\n')
				}

				fmt.Println("List of the clients:")
				for i, v := range clients {
					fmt.Printf("%d- %s\n", i, v.token)
				}
				fmt.Print("Choose a client: ")
				var choice int
				fmt.Scanf("%d", &choice)

				go sendAction(clients[choice].socket)
			}
		}()
	*/
	http.HandleFunc("/action", handleActionFunc)
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/martini"
	"github.com/wm/go-flowdock/flowdock"
	"net/http"
	"net/url"
	"fmt"
	"syscall"
	"text/template"
	"bytes"
)

type Build struct {
	BuildStatusPrevious   string   `json:"buildStatusPrevious,omitempty"`
	BuildId               string   `json:"buildId,omitempty"`
	TriggeredBy           string   `json:"triggeredBy,omitempty"`
	BuildStatus           string   `json:"buildStatus,omitempty"`
	AgentHostname         string   `json:"agentHostname,omitempty"`
	BuildFullName         string   `json:"buildFullName,omitempty"`
	BuildTypeId           string   `json:"buildTypeId,omitempty"`
	Message               string   `json:"message,omitempty"`
	Text                  string   `json:"text,omitempty"`
	NotifyType            string   `json:"notifyType,omitempty"`
	AgentName             string   `json:"agentName,omitempty"`
	BuildResult           string   `json:"buildResult,omitempty"`
	BuildRunner           string   `json:"buildRunner,omitempty"`
	ProjectId             string   `json:"projectId,omitempty"`
	ProjectName           string   `json:"projectName,omitempty"`
	AgentOs               string   `json:"agentOs,omitempty"`
	BuildNumber           string   `json:"buildNumber,omitempty"`
	BuildName             string   `json:"buildName,omitempty"`
}

//TODO: use const for uri's etc.
var flowClient *flowdock.Client //TODO pass this into the context or martini
var lastActionErr error
var lastBuild = Build{}
var lastForm = url.Values{} //map[string]string{}
var lastAction = "No action yet taken"

func main() {
	flowClient = flowdock.NewClient(nil)
	m := martini.New()

	// Setup middleware
	m.Use(martini.Recovery())
	m.Use(martini.Logger())

	// Setup routes
	r := martini.NewRouter()
	r.Get(`/`, Welcome)
	r.Post(`/status`, Status)
	r.Get(`/status`, Status)
	r.Get(`/last_status`, LastStatus)

	// Add the router action
	m.Action(r.Handle)
	m.Run()
}

func Welcome() string {
	return `Welcome to TeamDock, your TeamCity Flowdock connector`
}

func LastStatus() string {
	return fmt.Sprintf("Build: %+v, %+v, %+v, %+v", lastBuild, lastForm, lastAction, lastActionErr)
}

func Status(r *http.Request, w http.ResponseWriter) (result string) {
	build := encodeBuild(r)
	apiToken, ok := syscall.Getenv("FLOW_API_TOKEN")
	if ok {
		lastAction = "sending to Flow"
		lastActionErr = sendBuildToFlow(flowClient, build, apiToken)
	} else {
		lastActionErr = nil
		lastAction = "FLOW_API_TOKEN is not set"
	}

	lastForm = r.Form
	lastBuild = *build
	return "ok"
}

// TODO: do it similar to json Encode method in the future
func encodeBuild(r *http.Request) *Build {
	currentBuild := Build{
		BuildStatusPrevious: r.FormValue("buildStatusPrevious"),
		BuildId:             r.FormValue("buildId"),
		TriggeredBy:         r.FormValue("triggeredBy"),
		BuildStatus:         r.FormValue("buildStatus"),
		AgentHostname:       r.FormValue("agentHostname"),
		BuildFullName:       r.FormValue("buildFullName"),
		BuildTypeId:         r.FormValue("buildTypeId"),
		Message:             r.FormValue("message"),
		Text:                r.FormValue("text"),
		NotifyType:          r.FormValue("notifyType"),
		AgentName:           r.FormValue("agentName"),
		BuildResult:         r.FormValue("buildResult"),
		BuildRunner:         r.FormValue("buildRunner"),
		ProjectId:           r.FormValue("projectId"),
		ProjectName:         r.FormValue("projectName"),
		AgentOs:             r.FormValue("agentOs"),
		BuildNumber:         r.FormValue("buildNumber"),
		BuildName:           r.FormValue("buildName"),
	}

	return &currentBuild
}

func sendBuildToFlow(client *flowdock.Client, build *Build, flowApiToken string) error {
	var fromAddress string

	switch build.BuildResult {
	case "success":  fromAddress = "build+ok@flowdock.com"
	case "running":  fromAddress = "build+started@flowdock.com"
	case "canceled": fromAddress = "build+canceled@flowdock.com"
	default:         fromAddress = "build+fail@flowdock.com"
	}

	body := statusBody(build)
	opt := &flowdock.InboxCreateOptions{
		Source:       "go-flowdock",
		FromAddress:  fromAddress,
		Subject:     fmt.Sprintf("%v build %v - %v", build.ProjectName, build.BuildNumber, build.BuildResult),
		Tags:        []string{build.BuildResult, "CI", build.BuildNumber, build.ProjectName},
		Project:     build.ProjectName,
		FromName:    "TeamCity CI",
		Content:      body,
	}

	_, _, err := client.Inbox.Create(flowApiToken, opt)

	return err
}

func statusBody(build *Build) string {
	var body bytes.Buffer

	bodyTmpl, err  := template.New("body").Parse(`

	IoraHealth/{{.ProjectName}}
	build #{{.BuildNumber}}: {{.BuildResult}}!

		Branch: {{.BuildName}}

	Build details

    {{.Message}}

`)

	if err != nil { panic(err) }
	err = bodyTmpl.Execute(&body, build)
	if err != nil { panic(err) }

    return body.String()
}
<commit_msg>Add Link and name it<commit_after>package main

import (
	"github.com/codegangsta/martini"
	"github.com/wm/go-flowdock/flowdock"
	"net/http"
	"net/url"
	"fmt"
	"syscall"
	"text/template"
	"bytes"
)

type Build struct {
	BuildStatusPrevious   string   `json:"buildStatusPrevious,omitempty"`
	BuildId               string   `json:"buildId,omitempty"`
	TriggeredBy           string   `json:"triggeredBy,omitempty"`
	BuildStatus           string   `json:"buildStatus,omitempty"`
	AgentHostname         string   `json:"agentHostname,omitempty"`
	BuildFullName         string   `json:"buildFullName,omitempty"`
	BuildTypeId           string   `json:"buildTypeId,omitempty"`
	Message               string   `json:"message,omitempty"`
	Text                  string   `json:"text,omitempty"`
	NotifyType            string   `json:"notifyType,omitempty"`
	AgentName             string   `json:"agentName,omitempty"`
	BuildResult           string   `json:"buildResult,omitempty"`
	BuildRunner           string   `json:"buildRunner,omitempty"`
	ProjectId             string   `json:"projectId,omitempty"`
	ProjectName           string   `json:"projectName,omitempty"`
	AgentOs               string   `json:"agentOs,omitempty"`
	BuildNumber           string   `json:"buildNumber,omitempty"`
	BuildName             string   `json:"buildName,omitempty"`
}

//TODO: use const for uri's etc.
var flowClient *flowdock.Client //TODO pass this into the context or martini
var lastActionErr error
var lastBuild = Build{}
var lastForm = url.Values{} //map[string]string{}
var lastAction = "No action yet taken"

func main() {
	flowClient = flowdock.NewClient(nil)
	m := martini.New()

	// Setup middleware
	m.Use(martini.Recovery())
	m.Use(martini.Logger())

	// Setup routes
	r := martini.NewRouter()
	r.Get(`/`, Welcome)
	r.Post(`/status`, Status)
	r.Get(`/status`, Status)
	r.Get(`/last_status`, LastStatus)

	// Add the router action
	m.Action(r.Handle)
	m.Run()
}

func Welcome() string {
	return `Welcome to TeamDock, your TeamCity Flowdock connector`
}

func LastStatus() string {
	return fmt.Sprintf("Build: %+v, %+v, %+v, %+v", lastBuild, lastForm, lastAction, lastActionErr)
}

func Status(r *http.Request, w http.ResponseWriter) (result string) {
	build := encodeBuild(r)
	apiToken, ok := syscall.Getenv("FLOW_API_TOKEN")
	if ok {
		lastAction = "sending to Flow"
		lastActionErr = sendBuildToFlow(flowClient, build, apiToken)
	} else {
		lastActionErr = nil
		lastAction = "FLOW_API_TOKEN is not set"
	}

	lastForm = r.Form
	lastBuild = *build
	return "ok"
}

// TODO: do it similar to json Encode method in the future
func encodeBuild(r *http.Request) *Build {
	currentBuild := Build{
		BuildStatusPrevious: r.FormValue("buildStatusPrevious"),
		BuildId:             r.FormValue("buildId"),
		TriggeredBy:         r.FormValue("triggeredBy"),
		BuildStatus:         r.FormValue("buildStatus"),
		AgentHostname:       r.FormValue("agentHostname"),
		BuildFullName:       r.FormValue("buildFullName"),
		BuildTypeId:         r.FormValue("buildTypeId"),
		Message:             r.FormValue("message"),
		Text:                r.FormValue("text"),
		NotifyType:          r.FormValue("notifyType"),
		AgentName:           r.FormValue("agentName"),
		BuildResult:         r.FormValue("buildResult"),
		BuildRunner:         r.FormValue("buildRunner"),
		ProjectId:           r.FormValue("projectId"),
		ProjectName:         r.FormValue("projectName"),
		AgentOs:             r.FormValue("agentOs"),
		BuildNumber:         r.FormValue("buildNumber"),
		BuildName:           r.FormValue("buildName"),
	}

	return &currentBuild
}

func sendBuildToFlow(client *flowdock.Client, build *Build, flowApiToken string) error {
	var fromAddress string

	switch build.BuildResult {
	case "success":  fromAddress = "build+ok@flowdock.com"
	case "running":  fromAddress = "build+started@flowdock.com"
	case "canceled": fromAddress = "build+canceled@flowdock.com"
	default:         fromAddress = "build+fail@flowdock.com"
	}

	body := statusBody(build)
	url := fmt.Sprintf("http://nest.icisapp.com/viewLog.html?buildId=%v&tab=buildLog&buildTypeId=%v", build.BuildId, build.BuildTypeId)
	opt := &flowdock.InboxCreateOptions{
		Source:      "TeamCity CI (nest)",
		FromAddress: fromAddress,
		Subject:     fmt.Sprintf("%v build %v - %v", build.ProjectName, build.BuildNumber, build.BuildResult),
		Tags:        []string{build.BuildResult, "CI", build.BuildNumber, build.ProjectName},
		Project:     build.ProjectName,
		FromName:    "TeamCity CI",
		Link:        url,
		Content:     body,
	}

	_, _, err := client.Inbox.Create(flowApiToken, opt)

	return err
}

func statusBody(build *Build) string {
	var body bytes.Buffer

	bodyTmpl, err  := template.New("body").Parse(`

	IoraHealth/{{.ProjectName}}
	build #{{.BuildNumber}}: {{.BuildResult}}!

		Branch: {{.BuildName}}

	Build details

    {{.Message}}

`)

	if err != nil { panic(err) }
	err = bodyTmpl.Execute(&body, build)
	if err != nil { panic(err) }

    return body.String()
}
<|endoftext|>