<commit_before>package main

import (
  "github.com/codegangsta/martini"
  "encoding/json"
  "net/http"
  "os"
  "github.com/jinzhu/gorm"
  _ "github.com/go-sql-driver/mysql"
)

func main() {
  m := martini.Classic()

  dbPassword := os.Getenv("OOPS_DB_PASS")
  db, err := gorm.Open("mysql", "oops:" + dbPassword + "@tcp(15.126.247.23:3306)/oops")
  if err != nil { panic(err) }
  //defer db.Close() //TODO what should this be?

  //db.SetPool(10)

  db.LogMode(true)

  m.Map(db)

  //These are all the years of active school data. We could also derive it from the DB, possibly
  years := []string{"20022003", "20032004", "20042005", "20052006", "20062007", "20072008", "20082009", "20092010", "20102011", "20112012", "20122013"}

  m.Get("/schools", func(res http.ResponseWriter) string {
    var allSchools = []School{}
    db.Find(&allSchools)
    return render(res, allSchools)
  })

  //TODO need to also return stats by year -- needs to return []DistrictsByYear - district level stats for each year and each district
  m.Get("/districts", func(res http.ResponseWriter) string {
    allDistricts := []District{}
    db.Find(&allDistricts)

    districtsByYear := []DistrictsByYear{}
    for _, year := range years {
      districtByYear := DistrictsByYear{
        Year: year,
      }

      allDistrictsWithYears := []DistrictYear{}
      for _, district := range allDistricts {

        //FIXME hardcoded
        district.Latitude = 41.31027811
        district.Longitude = -96.146874

        districtWithYear := DistrictYear {
          EnrollmentSize: 2555,
          District: district,
        }
        allDistrictsWithYears = append(allDistrictsWithYears, districtWithYear)
      }

      districtByYear.Districts = allDistrictsWithYears
      districtsByYear = append(districtsByYear, districtByYear)
    }

    return render(res, districtsByYear)
  })

  //TODO need to also return stats by year for each school in the district
  m.Get("/district/:id", func(res http.ResponseWriter, params martini.Params) string {
    schoolsByYear := []SchoolsByYear{}

    schoolsInDistrict := []School{}
    db.Where("district_id = ?", params["id"]).Find(&schoolsInDistrict)

    for _, year := range years {

      //calculate school enrollment & append it
      schoolsInYear := []SchoolYear{}
      for _, school := range schoolsInDistrict {
        schoolsInYear = append(schoolsInYear, SchoolYear {
          //FIXME hardcoded
          EnrollmentSize: 552,
          School: school,
        })
      }

      schoolsByYear = append(schoolsByYear, SchoolsByYear{
        Year: year,
        Schools: schoolsInYear,
      })
    }

    var testDistrict = District{}
    db.Where("id = ?", params["id"]).First(&testDistrict)
    return render(res, schoolsByYear)

  })

  //TODO Possible clean-up opportunities here
  //TODO Still need total teacher count per year
  m.Get("/school/:id", func(res http.ResponseWriter, params martini.Params) string {
    var school = School{
      //FIXME hardcoded data
      Latitude : 41.31027811,
      Longitude : -96.146874,
    }
    schoolId := params["id"]
    db.Where("id = ?", schoolId).First(&school)
    var classStats = []ClassStat{}
    db.Where("school_id = ?", params["id"]).Find(&classStats)

    var yearsToEnrollments = map[string][]GradeEnrollment{}
    for _, row := range classStats {
      if row.EnrollmentSize > 0 {
        yearsToEnrollments[row.Years] = append(yearsToEnrollments[row.Years], GradeEnrollment{
          Grade: row.Grade,
          EnrollmentSize:    row.EnrollmentSize,
        })
      }
    }

    var enrollmentData = []EnrollmentByYear{}
    for year, enrollment := range yearsToEnrollments{

      //calculate Students field
      var classSize int64 = 0
      for _, i := range enrollment { classSize += i.EnrollmentSize }

      type TeacherAmount struct {
        TeacherSize float64
      }
      teacherAmount := TeacherAmount{}

      db.Table("school_stats").Where("school_id = ? and years = ?", schoolId, year).Select("teacher_size").First(&teacherAmount)

      enrollmentData = append(enrollmentData, EnrollmentByYear{
        Year: year,
        GradeEnrollment: enrollment,
        Students: classSize,

        //FIXME hardcoded data
        Teachers: int64(teacherAmount.TeacherSize),
      })
    }

    //put it all together
    var allData = SchoolWithEnrollment {
      School: school,
      EnrollmentByYear: enrollmentData,
    }

    return render(res, allData)
  })

  m.Run()
}

func render(res http.ResponseWriter, data interface{}) string {
  thing, err := json.Marshal(data)
  if err != nil { panic(err) }
  return asJson(res, thing)
}

func asJson(res http.ResponseWriter, data []byte) string {
  res.Header().Set("Content-Type", "application/json")
  res.Header().Set("Access-Control-Allow-Origin", "*")
  return string(data[:])
}

<commit_msg>Update server.go<commit_after>package main

import (
  "github.com/codegangsta/martini"
  "encoding/json"
  "net/http"
  "os"
  "github.com/jinzhu/gorm"
  _ "github.com/go-sql-driver/mysql"
)

func main() {
  m := martini.Classic()

  dbPassword := os.Getenv("OOPS_DB_PASS")
  db, err := gorm.Open("mysql", "oops:" + dbPassword + "@tcp(15.126.247.23:3306)/oops")
  if err != nil { panic(err) }
  //defer db.Close() //TODO what should this be?

  //db.SetPool(10)

  db.LogMode(true)

  m.Map(db)

  //These are all the years of active school data. We could also derive it from the DB, possibly
  years := []string{"20022003", "20032004", "20042005", "20052006", "20062007", "20072008", "20082009", "20092010", "20102011", "20112012", "20122013"}

  m.Get("/schools", func(res http.ResponseWriter) string {
    var allSchools = []School{}
    db.Find(&allSchools)
    return render(res, allSchools)
  })

  //TODO need to also return stats by year -- needs to return []DistrictsByYear - district level stats for each year and each district
  m.Get("/districts", func(res http.ResponseWriter) string {
    allDistricts := []District{}
    db.Find(&allDistricts)

    districtsByYear := []DistrictsByYear{}
    for _, year := range years {
      districtByYear := DistrictsByYear{
        Year: year,
      }

      allDistrictsWithYears := []DistrictYear{}
      for _, district := range allDistricts {

        //FIXME hardcoded
        district.Latitude = 41.31027811
        district.Longitude = -96.146874

        districtWithYear := DistrictYear {
          EnrollmentSize: 2555,
          District: district,
        }
        allDistrictsWithYears = append(allDistrictsWithYears, districtWithYear)
      }

      districtByYear.Districts = allDistrictsWithYears
      districtsByYear = append(districtsByYear, districtByYear)
    }

    return render(res, districtsByYear)
  })

  //TODO need to also return stats by year for each school in the district
  m.Get("/district/:id", func(res http.ResponseWriter, params martini.Params) string {
    schoolsByYear := []SchoolsByYear{}

    schoolsInDistrict := []School{}
    db.Where("district_id = ?", params["id"]).Find(&schoolsInDistrict)

    //db.Where("school_id = ? and years = ?", schoolId, year).Select("teacher_size").First(&teacherAmount)

    for _, year := range years {

      //calculate school enrollment & append it
      schoolsInYear := []SchoolYear{}
      for _, school := range schoolsInDistrict {
        schoolsInYear = append(schoolsInYear, SchoolYear {
          //FIXME hardcoded
          EnrollmentSize: 552,
          School: school,
        })
      }

      schoolsByYear = append(schoolsByYear, SchoolsByYear{
        Year: year,
        Schools: schoolsInYear,
      })
    }

    var testDistrict = District{}
    db.Where("id = ?", params["id"]).First(&testDistrict)
    return render(res, schoolsByYear)

  })

  //TODO Possible clean-up opportunities here, but it's looking pretty decent
  m.Get("/school/:id", func(res http.ResponseWriter, params martini.Params) string {
    var school = School{
      //FIXME hardcoded data
      Latitude : 41.31027811,
      Longitude : -96.146874,
    }
    schoolId := params["id"]
    db.Where("id = ?", schoolId).First(&school)

    var classStats = []ClassStat{}
    db.Where("school_id = ?", params["id"]).Find(&classStats)

    var yearsToEnrollments = map[string][]GradeEnrollment{}
    for _, row := range classStats {
      if row.EnrollmentSize > 0 {
        yearsToEnrollments[row.Years] = append(yearsToEnrollments[row.Years], GradeEnrollment{
          Grade: row.Grade,
          EnrollmentSize:    row.EnrollmentSize,
        })
      }
    }

    var schoolStats = []SchoolStat{}
    db.Where("school_id = ? and teacher_size is not null", params["id"]).Find(&schoolStats)

    var yearsToTotalStats = map[string]SchoolStat{}
    for _, row := range schoolStats {
    	yearsToTotalStats[row.Years] = row
    }

    var enrollmentData = []EnrollmentByYear{}
    for year, enrollment := range yearsToEnrollments{

      //calculate Students field
      //Could pull from SchoolStat, but will want to change
      //query above and deal properly with teacher_size being null
      var classSize int64 = 0
      for _, i := range enrollment { classSize += i.EnrollmentSize }

      enrollmentData = append(enrollmentData, EnrollmentByYear{
        Year: year,
        GradeEnrollment: enrollment,
        Students: classSize,
        Teachers: int64(yearsToTotalStats[year].TeacherSize),
      })
    }

    //put it all together
    var allData = SchoolWithEnrollment {
      School: school,
      EnrollmentByYear: enrollmentData,
    }

    return render(res, allData)
  })

  m.Run()
}

func render(res http.ResponseWriter, data interface{}) string {
  thing, err := json.Marshal(data)
  if err != nil { panic(err) }
  return asJson(res, thing)
}

func asJson(res http.ResponseWriter, data []byte) string {
  res.Header().Set("Content-Type", "application/json")
  res.Header().Set("Access-Control-Allow-Origin", "*")
  return string(data[:])
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"

	"github.com/hoisie/web"
	"github.com/nfleet/via/geo"
	"github.com/nfleet/via/geotypes"
	"github.com/nfleet/via/postgeodb"

	// register this postgres driver with the SQL module
	_ "github.com/bmizerany/pq"
)

type (
	Server struct {
		Geo              *geo.Geo
		AllowedCountries map[string]bool
		Port             int
	}
)

const (
	expiry int = 3600
)

var (
	Debug    bool
	Parallel bool
)

func Splash(ctx *web.Context) {
	ctx.ContentType("image/jpeg")
	http.ServeFile(ctx, ctx.Request, "./splash.jpg")
}

func parse_flags() {
	flag.BoolVar(&Debug, "debug", false, "toggle debugging on/off")
	flag.BoolVar(&Parallel, "par", false, "turn on parallel execution")
	flag.Parse()
}

func test_connection() {
	// redis
	fmt.Printf("loading services")

}

func Options(ctx *web.Context, route string) string {
	ctx.SetHeader("Access-Control-Allow-Origin", "*", false)
	ctx.SetHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, If-None-Match", false)
	ctx.SetHeader("Access-control-Allow-Methods", "GET, PUT, POST, DELETE", false)
	ctx.ContentType("application/json")
	return "{}"
}

func main() {
	parse_flags()

	var config geotypes.Config
	var configFile string
	var geoDB *postgeodb.GeoPostgresDB

	// Handle SIGINT and SIGKILL
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	go func() {
		for sig := range c {
			log.Printf("received %v, closing database connections and exiting...", sig)
			geoDB.DB.Close()
			os.Exit(1)
		}
	}()

	args := flag.Args()
	if len(args) < 1 {
		configFile = "production.json"
	} else {
		configFile = args[0]
	}

	log.Print("loading config from " + configFile + "... ")
	config, err := geo.LoadConfig(configFile)
	if err != nil {
		log.Printf("failed: %s\n", configFile, err.Error())
		return
	}

	log.Print("establishing database connection... ")
	geoDB, err = postgeodb.NewGeoPostgresDB(config)
	if err != nil {
		log.Println("error: " + err.Error())
		return
	}

	log.Println("starting server...")

	geo := geo.NewGeo(Debug, geoDB, expiry)

	server := Server{Geo: geo, Port: config.Port, AllowedCountries: config.AllowedCountries}

	// Basic
	web.Get("/", Splash)
	web.Get("/status", server.GetServerStatus)

	// Dmatrix
	web.Get("/dm/(.*)/result", server.GetMatrixResult)
	web.Get("/dm/(.*)$", server.GetMatrix)
	web.Post("/dm/", server.PostMatrix)
	web.Get("/spp/(.*)/result", server.GetMatrixResult)
	web.Get("/spp/(.*)$", server.GetMatrix)
	web.Post("/spp/", server.PostMatrix)

	// Path
	web.Post("/paths", server.PostCoordinatePaths)
	web.Post("/cpaths", server.PostCoordinatePaths)

	// Address/Coordinate
	web.Post("/resolve", server.PostResolve)

	web.Match("OPTIONS", "/(.*)", Options)

	web.Run(fmt.Sprintf("127.0.0.1:%d", config.Port))
}
<commit_msg>Add multicore support.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime"

	"github.com/hoisie/web"
	"github.com/nfleet/via/geo"
	"github.com/nfleet/via/geotypes"
	"github.com/nfleet/via/postgeodb"

	// register this postgres driver with the SQL module
	_ "github.com/bmizerany/pq"
)

type (
	Server struct {
		Geo              *geo.Geo
		AllowedCountries map[string]bool
		Port             int
	}
)

const (
	expiry int = 3600
)

var (
	Debug    bool
	Parallel bool
)

func Splash(ctx *web.Context) {
	ctx.ContentType("image/jpeg")
	http.ServeFile(ctx, ctx.Request, "./splash.jpg")
}

func parse_flags() {
	flag.BoolVar(&Debug, "debug", false, "toggle debugging on/off")
	flag.BoolVar(&Parallel, "par", false, "turn on parallel execution")
	flag.Parse()
}

func test_connection() {
	// redis
	fmt.Printf("loading services")

}

func Options(ctx *web.Context, route string) string {
	ctx.SetHeader("Access-Control-Allow-Origin", "*", false)
	ctx.SetHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, If-None-Match", false)
	ctx.SetHeader("Access-control-Allow-Methods", "GET, PUT, POST, DELETE", false)
	ctx.ContentType("application/json")
	return "{}"
}

func main() {
	parse_flags()

	var config geotypes.Config
	var configFile string
	var geoDB *postgeodb.GeoPostgresDB

	args := flag.Args()
	if len(args) < 1 {
		configFile = "production.json"
	} else {
		configFile = args[0]
	}

	log.Print("loading config from " + configFile + "... ")
	config, err := geo.LoadConfig(configFile)
	if err != nil {
		log.Printf("failed: %s\n", configFile, err.Error())
		return
	}

	log.Print("establishing database connection... ")
	geoDB, err = postgeodb.NewGeoPostgresDB(config)
	if err != nil {
		log.Println("error: " + err.Error())
		return
	}

	// Handle SIGINT and SIGKILL
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	go func() {
		for sig := range c {
			log.Printf("received %v, closing database connections and exiting...", sig)
			geoDB.DB.Close()
			os.Exit(1)
		}
	}()

	procs := runtime.NumCPU()
	runtime.GOMAXPROCS(procs)

	log.Printf("starting server, running on %d cores...", procs)

	geo := geo.NewGeo(Debug, geoDB, expiry)
	server := Server{Geo: geo, Port: config.Port, AllowedCountries: config.AllowedCountries}

	// Basic
	web.Get("/", Splash)
	web.Get("/status", server.GetServerStatus)

	// Dmatrix
	web.Get("/dm/(.*)/result", server.GetMatrixResult)
	web.Get("/dm/(.*)$", server.GetMatrix)
	web.Post("/dm/", server.PostMatrix)
	web.Get("/spp/(.*)/result", server.GetMatrixResult)
	web.Get("/spp/(.*)$", server.GetMatrix)
	web.Post("/spp/", server.PostMatrix)

	// Path
	web.Post("/paths", server.PostCoordinatePaths)
	web.Post("/cpaths", server.PostCoordinatePaths)

	// Address/Coordinate
	web.Post("/resolve", server.PostResolve)

	web.Match("OPTIONS", "/(.*)", Options)

	web.Run(fmt.Sprintf("127.0.0.1:%d", config.Port))
}
<|endoftext|>


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

package httputils

import (
	"crypto/tls"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

// Provide a HTTP server implementation which can listen on TPC
// and Unix Domain sockets.
type Server struct {
	http.Server
	*log.Logger
}

// ListenAndServe binds sockets according to the configuration of srv and blocks
// until the socket closes or an exit signal is received.
func (srv *Server) ListenAndServe() error {

	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}

	var closing = false
	var err error
	var l net.Listener
	if l, err = srv.socketListen(addr); err != nil {
		return err
	}

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-sig
		msg := "Received exit signal %d - Closing ..."
		if srv.Logger != nil {
			srv.Logger.Printf(msg, s)
		} else {
			log.Printf(msg, s)
		}
		closing = true
		l.Close()
	}()

	err = srv.Serve(l)
	if err != nil {
		if closing {
			return nil
		}
	}
	return err

}

// ListenAndServeTLS binds sockets according to the configuration of srv and blocks
// until the socket closes or an exit signal is received.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {

	config := &tls.Config{}
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}

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

	return srv.ListenAndServeTLSWithConfig(config)

}

// ListenAndServeTLSAdvanced binds sockets according to the configuration
// of srv and blocks until the socket closes or an exit signal is received. A
// TLSConfig needs to be available at the server.
func (srv *Server) ListenAndServeTLSWithConfig(config *tls.Config) error {

	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}

	if config == nil {
		return errors.New("TLSConfig required")
	}
	if len(config.Certificates) == 0 {
		return errors.New("TLSConfig has no certificate")
	}

	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	var closing = false
	var l net.Listener
	if l, err = srv.socketListen(addr); err != nil {
		return err
	}

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-sig
		msg := "Received exit signal %d - Closing ..."
		if srv.Logger != nil {
			srv.Logger.Printf(msg, s)
		} else {
			log.Printf(msg, s)
		}
		closing = true
		l.Close()
	}()

	tlsListener := tls.NewListener(l, config)

	err = srv.Serve(tlsListener)
	if err != nil {
		if closing {
			return nil
		}
	}
	return err

}

func (srv *Server) socketListen(addr string) (net.Listener, error) {

	var err error
	var l net.Listener

	if strings.HasPrefix(addr, "/") {
		var laddr *net.UnixAddr
		if laddr, err = net.ResolveUnixAddr("unix", addr); err != nil {
			return nil, err
		}
		if l, err = createUnixSocket(laddr); err != nil {
			// Unix-domain-socket already exists, try to connect to it to
			// see if it still is usedb by another process
			if _, err = net.Dial("unix", addr); err != nil {
				if err = os.Remove(addr); err != nil {
					return nil, err
				}
				if l, err = createUnixSocket(laddr); err != nil {
					return nil, err
				}
			} else {
				return nil, fmt.Errorf("another process seems to be listening on %s already", addr)
			}
		}
	} else {
		var laddr *net.TCPAddr
		if laddr, err = net.ResolveTCPAddr("tcp", addr); err != nil {
			return nil, err
		}
		if l, err = net.ListenTCP("tcp", laddr); err != nil {
			return nil, err
		}
	}

	return l, nil

}

func createUnixSocket(addr *net.UnixAddr) (l net.Listener, err error) {
	l, err = net.ListenUnix("unix", addr)

	if err != nil {
		return
	}

	// TODO(lcooper): Not sure if this sequence is completely safe.
	// It would be better if we could get the underlying FD of the socket
	// and stat() + chmod() that instead.
	fi, err := os.Stat(addr.String())
	if err != nil {
		return
	}

	// NOTE(lcooper): This only ensures g+w other then on Linux,
	// BSD systems only use parent directory permissions.
	// See http://stackoverflow.com/questions/5977556 .
	err = os.Chmod(addr.String(), fi.Mode()|0060)
	return
}
<commit_msg>Make sure sha512 is supported.<commit_after>// Copyright 2014 struktur AG. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httputils

import (
	_ "crypto/sha512" // Make sure to link in SHA512 (see https://codereview.appspot.com/84700045/).
	"crypto/tls"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

// Provide a HTTP server implementation which can listen on TPC
// and Unix Domain sockets.
type Server struct {
	http.Server
	*log.Logger
}

// ListenAndServe binds sockets according to the configuration of srv and blocks
// until the socket closes or an exit signal is received.
func (srv *Server) ListenAndServe() error {

	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}

	var closing = false
	var err error
	var l net.Listener
	if l, err = srv.socketListen(addr); err != nil {
		return err
	}

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-sig
		msg := "Received exit signal %d - Closing ..."
		if srv.Logger != nil {
			srv.Logger.Printf(msg, s)
		} else {
			log.Printf(msg, s)
		}
		closing = true
		l.Close()
	}()

	err = srv.Serve(l)
	if err != nil {
		if closing {
			return nil
		}
	}
	return err

}

// ListenAndServeTLS binds sockets according to the configuration of srv and blocks
// until the socket closes or an exit signal is received.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {

	config := &tls.Config{}
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}

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

	return srv.ListenAndServeTLSWithConfig(config)

}

// ListenAndServeTLSAdvanced binds sockets according to the configuration
// of srv and blocks until the socket closes or an exit signal is received. A
// TLSConfig needs to be available at the server.
func (srv *Server) ListenAndServeTLSWithConfig(config *tls.Config) error {

	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}

	if config == nil {
		return errors.New("TLSConfig required")
	}
	if len(config.Certificates) == 0 {
		return errors.New("TLSConfig has no certificate")
	}

	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	var closing = false
	var l net.Listener
	if l, err = srv.socketListen(addr); err != nil {
		return err
	}

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-sig
		msg := "Received exit signal %d - Closing ..."
		if srv.Logger != nil {
			srv.Logger.Printf(msg, s)
		} else {
			log.Printf(msg, s)
		}
		closing = true
		l.Close()
	}()

	tlsListener := tls.NewListener(l, config)

	err = srv.Serve(tlsListener)
	if err != nil {
		if closing {
			return nil
		}
	}
	return err

}

func (srv *Server) socketListen(addr string) (net.Listener, error) {

	var err error
	var l net.Listener

	if strings.HasPrefix(addr, "/") {
		var laddr *net.UnixAddr
		if laddr, err = net.ResolveUnixAddr("unix", addr); err != nil {
			return nil, err
		}
		if l, err = createUnixSocket(laddr); err != nil {
			// Unix-domain-socket already exists, try to connect to it to
			// see if it still is usedb by another process
			if _, err = net.Dial("unix", addr); err != nil {
				if err = os.Remove(addr); err != nil {
					return nil, err
				}
				if l, err = createUnixSocket(laddr); err != nil {
					return nil, err
				}
			} else {
				return nil, fmt.Errorf("another process seems to be listening on %s already", addr)
			}
		}
	} else {
		var laddr *net.TCPAddr
		if laddr, err = net.ResolveTCPAddr("tcp", addr); err != nil {
			return nil, err
		}
		if l, err = net.ListenTCP("tcp", laddr); err != nil {
			return nil, err
		}
	}

	return l, nil

}

func createUnixSocket(addr *net.UnixAddr) (l net.Listener, err error) {
	l, err = net.ListenUnix("unix", addr)

	if err != nil {
		return
	}

	// TODO(lcooper): Not sure if this sequence is completely safe.
	// It would be better if we could get the underlying FD of the socket
	// and stat() + chmod() that instead.
	fi, err := os.Stat(addr.String())
	if err != nil {
		return
	}

	// NOTE(lcooper): This only ensures g+w other then on Linux,
	// BSD systems only use parent directory permissions.
	// See http://stackoverflow.com/questions/5977556 .
	err = os.Chmod(addr.String(), fi.Mode()|0060)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"golang.org/x/net/websocket"
)

var signalChannel chan string

// startServer will start a webserver on the given address and open the default
// browser on the given address
func startServer(address string) {

	server := echo.New()
	// server.Use(middleware.Logger())
	server.Use(middleware.Recover())

	// server static files
	server.Index("website/index.html")
	server.ServeFile("/websocket.min.js", "website/websocket.min.js")
	server.ServeFile("/lodash.min.js", "website/lodash.min.js")
	server.ServeFile("/style.css", "website/style.css")
	server.ServeFile("/style.css.map", "website/style.css.map")
	server.ServeFile("/style.scss", "website/style.scss")

	// handle websocket connections
	server.WebSocket("/ws", handleSocketConnection)

	// run the server (blocking)
	server.Run(address)
}

// showIndexPage will display the main page showing an interactive page
func showIndexPage(c *echo.Context) error {
	return c.String(http.StatusOK, "This is the start-page")
}

// handleSocketConnection will handle the live connection between the webpage
// and our game
func handleSocketConnection(c *echo.Context) error {

	// upgrade the connection to a socket
	ws := c.Socket()

	for {
		// send signals if something is put on the signalChannel
		signal := <-signalChannel
		websocket.Message.Send(ws, signal)

	}

}
<commit_msg>open a webpage in the default browser<commit_after>package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/skratchdot/open-golang/open"
	"golang.org/x/net/websocket"
)

var signalChannel chan string

// startServer will start a webserver on the given address and open the default
// browser on the given address
func startServer(address string) {

	server := echo.New()
	// server.Use(middleware.Logger())
	server.Use(middleware.Recover())

	// server static files
	server.Index("website/index.html")
	server.ServeFile("/websocket.min.js", "website/websocket.min.js")
	server.ServeFile("/lodash.min.js", "website/lodash.min.js")
	server.ServeFile("/style.css", "website/style.css")
	server.ServeFile("/style.css.map", "website/style.css.map")
	server.ServeFile("/style.scss", "website/style.scss")

	// handle websocket connections
	server.WebSocket("/ws", handleSocketConnection)

	// open the page in the default browser
	go openInDefaultBrowser(address)

	// run the server (blocking)
	server.Run(address)
}

// showIndexPage will display the main page showing an interactive page
func showIndexPage(c *echo.Context) error {
	return c.String(http.StatusOK, "This is the start-page")
}

// handleSocketConnection will handle the live connection between the webpage
// and our game
func handleSocketConnection(c *echo.Context) error {

	// upgrade the connection to a socket
	ws := c.Socket()

	for {
		// send signals if something is put on the signalChannel
		signal := <-signalChannel
		websocket.Message.Send(ws, signal)

	}

}

// openInDefaultBrowser will open the given address in the users default browser
// (after a short timeout)
func openInDefaultBrowser(address string) {
	<-time.After(100 * time.Millisecond)
	err := open.Start("http://" + address + "/")
	if err != nil {
		fmt.Println("Bitte öffnen Sie Ihren Browser auf der Adresse", address)
	}
}
<|endoftext|>


<commit_before>package torrent_center

import (
	"net/http"
	"github.com/bamboV/torrent"
	"encoding/json"
	"strconv"
	"strings"
)

type Server struct{
	center Center
}

func NewServer(center Center) Server {
	return Server{
		center: center,
	}
}

func (s *Server) Start () {
	mux := http.NewServeMux()
	mux.HandleFunc("/trackers", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			s.write(s.center.GetTrackers(), w)
			break
		case http.MethodPost:
			name := r.PostForm.Get("name")
			url := r.PostForm.Get("url")
			if name == "" || url == "" {
				w.WriteHeader(400)
				return
			}
			tracker := Tracker{
				Name: name,
				Url: url,
			}
			s.write(s.center.AddTracker(tracker), w)
			break
		}
	})
	mux.HandleFunc("/trackers/", func(w http.ResponseWriter, r *http.Request) {
		name := strings.Trim(r.URL.Path, "/trackers/")
		switch r.Method {
		case http.MethodGet:
			s.write(s.center.GetTracker(name), w)
			break
		case http.MethodDelete:
			s.center.DeleteTracker(Tracker{Name: name})
			break
		case http.MethodPut:
			name := r.Form.Get("name")
			url := r.Form.Get("url")
			if name == "" || url == "" {
				w.WriteHeader(400)
				return
			}
			tracker := Tracker{
				Name: name,
				Url: url,
			}
			s.write(s.center.UpdateTracker(tracker), w)
			break
		}
	})

	mux.HandleFunc("/distributions", func(w http.ResponseWriter, r *http.Request) {
		phrase := r.URL.Query().Get("phrase")

		if phrase == "" {
			w.WriteHeader(400)
			return
		}

		s.write(s.searchInAllTrackers(phrase),w)
	})

	mux.HandleFunc("/distributions/", func(w http.ResponseWriter, r *http.Request) {
		params := strings.Trim(r.URL.Path, "/distributions/")

		split := strings.Split(params, "/")

		trackerName := split[0]

		tracker := s.center.GetTracker(trackerName)

		if tracker.Url == "" {
			w.WriteHeader(404)
			return
		}

		if len(split) > 1 {
			id, err := strconv.Atoi(split[1])

			if err != nil {
				w.WriteHeader(400)
				return
			}

			s.write(tracker.Get(id), w)
		} else {
			phrase := r.URL.Query().Get("phrase")
			if phrase == "" {
				w.WriteHeader(400)
				return
			}
			s.write(tracker.Search(phrase), w)
		}
	})

	mux.HandleFunc("/magnet", func(w http.ResponseWriter, r *http.Request) {
		magnet := r.PostForm.Get("magnet")
		if magnet == ""  {
			w.WriteHeader(500)
			return
		}

		if s.center.Download(magnet) {
			w.WriteHeader(200)
		} else {
			w.WriteHeader(500)
		}
	})

	http.ListenAndServe(":80", mux)
}

func (s *Server) write(object interface{}, w http.ResponseWriter) {
	str, _ := json.Marshal(object)
	w.Write(str)
}

func (s *Server) getDistribution(trackerName string, id int) torrent.Distribution {
	tracker := s.center.GetTracker(trackerName)

	return tracker.Get(id)
}

func (s *Server) search(trackerName string, phrase string) []torrent.Distribution {
	tracker := s.center.GetTracker(trackerName)

	return tracker.Search(phrase)
}

func (s *Server) searchInAllTrackers(phrase string) []TrackerSearchResult {
	trackers := s.center.GetTrackers()

	result := []TrackerSearchResult{}

	for _, value := range trackers {
		search := value.Search(phrase)
		if len(search) > 0 {
			result = append(result, TrackerSearchResult{
				Name: value.Name,
				Items: search,
			})
		}
	}

	return result
}

<commit_msg>Added error handling<commit_after>package torrent_center

import (
	"net/http"
	"github.com/bamboV/torrent"
	"encoding/json"
	"strconv"
	"strings"
)

type Server struct{
	center Center
}

func NewServer(center Center) Server {
	return Server{
		center: center,
	}
}

func (s *Server) Start () {
	mux := http.NewServeMux()
	mux.HandleFunc("/trackers", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			s.write(s.center.GetTrackers(), w)
			break
		case http.MethodPost:
			name := r.PostForm.Get("name")
			url := r.PostForm.Get("url")
			if name == "" || url == "" {
				w.WriteHeader(400)
				return
			}
			tracker := Tracker{
				Name: name,
				Url: url,
			}
			s.write(s.center.AddTracker(tracker), w)
			break
		}
	})
	mux.HandleFunc("/trackers/", func(w http.ResponseWriter, r *http.Request) {
		name := strings.Trim(r.URL.Path, "/trackers/")
		switch r.Method {
		case http.MethodGet:
			s.write(s.center.GetTracker(name), w)
			break
		case http.MethodDelete:
			s.center.DeleteTracker(Tracker{Name: name})
			break
		case http.MethodPut:
			name := r.Form.Get("name")
			url := r.Form.Get("url")
			if name == "" || url == "" {
				w.WriteHeader(400)
				return
			}
			tracker := Tracker{
				Name: name,
				Url: url,
			}
			s.write(s.center.UpdateTracker(tracker), w)
			break
		}
	})

	mux.HandleFunc("/distributions", func(w http.ResponseWriter, r *http.Request) {
		phrase := r.URL.Query().Get("phrase")

		if phrase == "" {
			w.WriteHeader(400)
			return
		}

		s.write(s.searchInAllTrackers(phrase),w)
	})

	mux.HandleFunc("/distributions/", func(w http.ResponseWriter, r *http.Request) {
		params := strings.Trim(r.URL.Path, "/distributions/")

		split := strings.Split(params, "/")

		trackerName := split[0]

		tracker := s.center.GetTracker(trackerName)

		if tracker.Url == "" {
			w.WriteHeader(404)
			return
		}

		if len(split) > 1 {
			id, err := strconv.Atoi(split[1])

			if err != nil {
				w.WriteHeader(400)
				return
			}

			s.write(tracker.Get(id), w)
		} else {
			phrase := r.URL.Query().Get("phrase")
			if phrase == "" {
				w.WriteHeader(400)
				return
			}
			s.write(tracker.Search(phrase), w)
		}
	})

	mux.HandleFunc("/magnet", func(w http.ResponseWriter, r *http.Request) {
		magnet := r.PostForm.Get("magnet")
		if magnet == ""  {
			w.WriteHeader(500)
			return
		}

		if s.center.Download(magnet) {
			w.WriteHeader(200)
		} else {
			w.WriteHeader(500)
		}
	})

	err := http.ListenAndServe(":80", mux)

	if err != nil {
		panic(err)
	}
}

func (s *Server) write(object interface{}, w http.ResponseWriter) {
	str, _ := json.Marshal(object)
	w.Write(str)
}

func (s *Server) getDistribution(trackerName string, id int) torrent.Distribution {
	tracker := s.center.GetTracker(trackerName)

	return tracker.Get(id)
}

func (s *Server) search(trackerName string, phrase string) []torrent.Distribution {
	tracker := s.center.GetTracker(trackerName)

	return tracker.Search(phrase)
}

func (s *Server) searchInAllTrackers(phrase string) []TrackerSearchResult {
	trackers := s.center.GetTrackers()

	result := []TrackerSearchResult{}

	for _, value := range trackers {
		search := value.Search(phrase)
		if len(search) > 0 {
			result = append(result, TrackerSearchResult{
				Name: value.Name,
				Items: search,
			})
		}
	}

	return result
}

<|endoftext|>


<commit_before>package webrpc

import (
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  4096,
	WriteBufferSize: 4096,
	EnableCompression: true,
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

// Server implements an RPC server.
type Server struct {
	chans     map[string]*channel
	onConnect func(c *Conn)
}

// NewServer creates a new server instance.
func NewServer() *Server {
	return &Server{
		chans: map[string]*channel{},
	}
}

func (s *Server) getChannel(name string) *channel {
	ch, ok := s.chans[name]
	if !ok {
		ch = newChannel(name)
		s.chans[name] = ch
	}
	return ch
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	c := newConn(s, ws)
	go c.writeLoop()
	if s.onConnect != nil {
		s.onConnect(c)
	}
	c.readLoop()
}

// OnConnect sets the connection handler for this server.
func (s *Server) OnConnect(handler func(c *Conn)) {
	s.onConnect = handler
}

// Broadcast sends a message on a given channel.
func (s *Server) Broadcast(chname, name string, args ...interface{}) error {
	msg, err := NewEvent(name, args...)
	if err != nil {
		return err
	}

	s.getChannel(chname).broadcast(msg, nil)
	return nil
}
<commit_msg>Add a means to configure the underlying websocket.<commit_after>package webrpc

import (
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

// Server implements an RPC server.
type Server struct {
	chans     map[string]*channel
	onConnect func(c *Conn)
	upgrader  websocket.Upgrader
}

// Config specifies a configuration for the server.
type Config struct {
	ReadBufferSize, WriteBufferSize int
	EnableCompression               bool
}

// NewServer creates a new server instance.
func NewServer() *Server {
	return NewServerWithConfig(Config{
		ReadBufferSize:    4096,
		WriteBufferSize:   4096,
		EnableCompression: true,
	})
}

// NewServerWithConfig creates a new server with config.
func NewServerWithConfig(c Config) *Server {
	return &Server{
		chans: map[string]*channel{},
		upgrader: websocket.Upgrader{
			ReadBufferSize:    c.ReadBufferSize,
			WriteBufferSize:   c.WriteBufferSize,
			EnableCompression: c.EnableCompression,
			CheckOrigin: func(r *http.Request) bool {
				return true
			},
		},
	}
}

func (s *Server) getChannel(name string) *channel {
	ch, ok := s.chans[name]
	if !ok {
		ch = newChannel(name)
		s.chans[name] = ch
	}
	return ch
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	ws, err := s.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	c := newConn(s, ws)
	go c.writeLoop()
	if s.onConnect != nil {
		s.onConnect(c)
	}
	c.readLoop()
}

// OnConnect sets the connection handler for this server.
func (s *Server) OnConnect(handler func(c *Conn)) {
	s.onConnect = handler
}

// Broadcast sends a message on a given channel.
func (s *Server) Broadcast(chname, name string, args ...interface{}) error {
	msg, err := NewEvent(name, args...)
	if err != nil {
		return err
	}

	s.getChannel(chname).broadcast(msg, nil)
	return nil
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package grpc

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"reflect"
	"strings"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/transport"
)

type methodHandler func(srv interface{}, ctx context.Context, codec Codec, buf []byte) (interface{}, error)

// MethodDesc represents an RPC service's method specification.
type MethodDesc struct {
	MethodName string
	Handler    methodHandler
}

// ServiceDesc represents an RPC service's specification.
type ServiceDesc struct {
	ServiceName string
	// The pointer to the service interface. Used to check whether the user
	// provided implementation satisfies the interface requirements.
	HandlerType interface{}
	Methods     []MethodDesc
	Streams     []StreamDesc
}

// service consists of the information of the server serving this service and
// the methods in this service.
type service struct {
	server interface{} // the server for service methods
	md     map[string]*MethodDesc
	sd     map[string]*StreamDesc
}

// Server is a gRPC server to serve RPC requests.
type Server struct {
	opts  options
	mu    sync.Mutex
	lis   map[net.Listener]bool
	conns map[transport.ServerTransport]bool
	m     map[string]*service // service name -> service info
}

type options struct {
	handshaker           func(net.Conn) error
	codec                Codec
	maxConcurrentStreams uint32
}

// A ServerOption sets options.
type ServerOption func(*options)

func Handshaker(f func(net.Conn) error) ServerOption {
	return func(o *options) {
		o.handshaker = f
	}
}

func CustomCodec(codec Codec) ServerOption {
	return func(o *options) {
		o.codec = codec
	}
}

// MaxConcurrentStreams returns an Option that will apply a limit on the number
// of concurrent streams to each ServerTransport.
func MaxConcurrentStreams(n uint32) ServerOption {
	return func(o *options) {
		o.maxConcurrentStreams = n
	}
}

// NewServer creates a gRPC server which has no service registered and has not
// started to accept requests yet.
func NewServer(opt ...ServerOption) *Server {
	var opts options
	for _, o := range opt {
		o(&opts)
	}
	if opts.codec == nil {
		// Set the default codec.
		opts.codec = protoCodec{}
	}
	return &Server{
		lis:   make(map[net.Listener]bool),
		opts:  opts,
		conns: make(map[transport.ServerTransport]bool),
		m:     make(map[string]*service),
	}
}

// RegisterService register a service and its implementation to the gRPC
// server. Called from the IDL generated code. This must be called before
// invoking Serve.
func (s *Server) RegisterService(sd *ServiceDesc, ss interface{}) {
	s.mu.Lock()
	defer s.mu.Unlock()
	// Does some sanity checks.
	if _, ok := s.m[sd.ServiceName]; ok {
		log.Fatalf("grpc: Server.RegisterService found duplicate service registration for %q", sd.ServiceName)
	}
	ht := reflect.TypeOf(sd.HandlerType).Elem()
	st := reflect.TypeOf(ss)
	if !st.Implements(ht) {
		log.Fatalf("grpc: Server.RegisterService found the handler of type %v that does not satisfy %v", st, ht)
	}
	srv := &service{
		server: ss,
		md:     make(map[string]*MethodDesc),
		sd:     make(map[string]*StreamDesc),
	}
	for i := range sd.Methods {
		d := &sd.Methods[i]
		srv.md[d.MethodName] = d
	}
	for i := range sd.Streams {
		d := &sd.Streams[i]
		srv.sd[d.StreamName] = d
	}
	s.m[sd.ServiceName] = srv
}

var (
	// ErrServerStopped indicates that the operation is now illegal because of
	// the server being stopped.
	ErrServerStopped = errors.New("grpc: the server has been stopped")
)

// Serve accepts incoming connections on the listener lis, creating a new
// ServerTransport and service goroutine for each. The service goroutines
// read gRPC request and then call the registered handlers to reply to them.
// Service returns when lis.Accept fails.
func (s *Server) Serve(lis net.Listener) error {
	s.mu.Lock()
	if s.lis == nil {
		s.mu.Unlock()
		return ErrServerStopped
	}
	s.lis[lis] = true
	s.mu.Unlock()
	defer func() {
		lis.Close()
		s.mu.Lock()
		delete(s.lis, lis)
		s.mu.Unlock()
	}()
	for {
		c, err := lis.Accept()
		if err != nil {
			return err
		}
		// Perform handshaking if it is required.
		if s.opts.handshaker != nil {
			if err := s.opts.handshaker(c); err != nil {
				log.Println("grpc: Server.Serve failed to complete handshake.")
				c.Close()
				continue
			}
		}
		s.mu.Lock()
		if s.conns == nil {
			s.mu.Unlock()
			c.Close()
			return nil
		}
		st, err := transport.NewServerTransport("http2", c, s.opts.maxConcurrentStreams)
		if err != nil {
			s.mu.Unlock()
			c.Close()
			log.Println("grpc: Server.Serve failed to create ServerTransport: ", err)
			continue
		}
		s.conns[st] = true
		s.mu.Unlock()

		go func() {
			st.HandleStreams(func(stream *transport.Stream) {
				s.handleStream(st, stream)
			})
			s.mu.Lock()
			delete(s.conns, st)
			s.mu.Unlock()
		}()
	}
}

func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, pf payloadFormat, opts *transport.Options) error {
	p, err := encode(s.opts.codec, msg, pf)
	if err != nil {
		// This typically indicates a fatal issue (e.g., memory
		// corruption or hardware faults) the application program
		// cannot handle.
		//
		// TODO(zhaoq): There exist other options also such as only closing the
		// faulty stream locally and remotely (Other streams can keep going). Find
		// the optimal option.
		log.Fatalf("grpc: Server failed to encode response %v", err)
	}
	return t.Write(stream, p, opts)
}

func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, md *MethodDesc) {
	p := &parser{s: stream}
	for {
		pf, req, err := p.recvMsg()
		if err == io.EOF {
			// The entire stream is done (for unary RPC only).
			return
		}
		if err != nil {
			switch err := err.(type) {
			case transport.ConnectionError:
				// Nothing to do here.
			case transport.StreamError:
				if err := t.WriteStatus(stream, err.Code, err.Desc); err != nil {
					log.Printf("grpc: Server.processUnaryRPC failed to write status: %v", err)
				}
			default:
				panic(fmt.Sprintf("grpc: Unexpected error (%T) from recvMsg: %v", err, err))
			}
			return
		}
		switch pf {
		case compressionNone:
			statusCode := codes.OK
			statusDesc := ""
			reply, appErr := md.Handler(srv.server, stream.Context(), s.opts.codec, req)
			if appErr != nil {
				if err, ok := appErr.(rpcError); ok {
					statusCode = err.code
					statusDesc = err.desc
				} else {
					statusCode = convertCode(appErr)
					statusDesc = appErr.Error()
				}
				if err := t.WriteStatus(stream, statusCode, statusDesc); err != nil {
					log.Printf("grpc: Server.processUnaryRPC failed to write status: %v", err)
				}
				return
			}
			opts := &transport.Options{
				Last:  true,
				Delay: false,
			}
			if err := s.sendResponse(t, stream, reply, compressionNone, opts); err != nil {
				if _, ok := err.(transport.ConnectionError); ok {
					return
				}
				if e, ok := err.(transport.StreamError); ok {
					statusCode = e.Code
					statusDesc = e.Desc
				} else {
					statusCode = codes.Unknown
					statusDesc = err.Error()
				}
			}
			t.WriteStatus(stream, statusCode, statusDesc)
		default:
			panic(fmt.Sprintf("payload format to be supported: %d", pf))
		}
	}
}

func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc) {
	ss := &serverStream{
		t:     t,
		s:     stream,
		p:     &parser{s: stream},
		codec: s.opts.codec,
	}
	if appErr := sd.Handler(srv.server, ss); appErr != nil {
		if err, ok := appErr.(rpcError); ok {
			ss.statusCode = err.code
			ss.statusDesc = err.desc
		} else {
			ss.statusCode = convertCode(appErr)
			ss.statusDesc = appErr.Error()
		}
	}
	t.WriteStatus(ss.s, ss.statusCode, ss.statusDesc)
}

func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream) {
	sm := stream.Method()
	if sm != "" && sm[0] == '/' {
		sm = sm[1:]
	}
	pos := strings.LastIndex(sm, "/")
	if pos == -1 {
		if err := t.WriteStatus(stream, codes.InvalidArgument, fmt.Sprintf("malformed method name: %q", stream.Method())); err != nil {
			log.Printf("grpc: Server.handleStream failed to write status: %v", err)
		}
		return
	}
	service := sm[:pos]
	method := sm[pos+1:]
	srv, ok := s.m[service]
	if !ok {
		if err := t.WriteStatus(stream, codes.Unimplemented, fmt.Sprintf("unknown service %v", service)); err != nil {
			log.Printf("grpc: Server.handleStream failed to write status: %v", err)
		}
		return
	}
	// Unary RPC or Streaming RPC?
	if md, ok := srv.md[method]; ok {
		s.processUnaryRPC(t, stream, srv, md)
		return
	}
	if sd, ok := srv.sd[method]; ok {
		s.processStreamingRPC(t, stream, srv, sd)
		return
	}
	if err := t.WriteStatus(stream, codes.Unimplemented, fmt.Sprintf("unknown method %v", method)); err != nil {
		log.Printf("grpc: Server.handleStream failed to write status: %v", err)
	}
}

// Stop stops the gRPC server. Once Stop returns, the server stops accepting
// connection requests and closes all the connected connections.
func (s *Server) Stop() {
	s.mu.Lock()
	listeners := s.lis
	s.lis = nil
	cs := s.conns
	s.conns = nil
	s.mu.Unlock()
	for lis := range listeners {
		lis.Close()
	}
	for c := range cs {
		c.Close()
	}
}

// TestingCloseConns closes all exiting transports but keeps s.lis accepting new
// connections. This is for test only now.
func (s *Server) TestingCloseConns() {
	s.mu.Lock()
	for c := range s.conns {
		c.Close()
	}
	s.conns = make(map[transport.ServerTransport]bool)
	s.mu.Unlock()
}

// SendHeader sends header metadata. It may be called at most once from a unary
// RPC handler. The ctx is the RPC handler's Context or one derived from it.
func SendHeader(ctx context.Context, md metadata.MD) error {
	if md.Len() == 0 {
		return nil
	}
	stream, ok := transport.StreamFromContext(ctx)
	if !ok {
		return fmt.Errorf("grpc: failed to fetch the stream from the context %v", ctx)
	}
	t := stream.ServerTransport()
	if t == nil {
		log.Fatalf("grpc: SendHeader: %v has no ServerTransport to send header metadata.", stream)
	}
	return t.WriteHeader(stream, md)
}

// SetTrailer sets the trailer metadata that will be sent when an RPC returns.
// It may be called at most once from a unary RPC handler. The ctx is the RPC
// handler's Context or one derived from it.
func SetTrailer(ctx context.Context, md metadata.MD) error {
	if md.Len() == 0 {
		return nil
	}
	stream, ok := transport.StreamFromContext(ctx)
	if !ok {
		return fmt.Errorf("grpc: failed to fetch the stream from the context %v", ctx)
	}
	return stream.SetTrailer(md)
}
<commit_msg>gofmt -w<commit_after>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package grpc

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"reflect"
	"strings"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/transport"
)

type methodHandler func(srv interface{}, ctx context.Context, codec Codec, buf []byte) (interface{}, error)

// MethodDesc represents an RPC service's method specification.
type MethodDesc struct {
	MethodName string
	Handler    methodHandler
}

// ServiceDesc represents an RPC service's specification.
type ServiceDesc struct {
	ServiceName string
	// The pointer to the service interface. Used to check whether the user
	// provided implementation satisfies the interface requirements.
	HandlerType interface{}
	Methods     []MethodDesc
	Streams     []StreamDesc
}

// service consists of the information of the server serving this service and
// the methods in this service.
type service struct {
	server interface{} // the server for service methods
	md     map[string]*MethodDesc
	sd     map[string]*StreamDesc
}

// Server is a gRPC server to serve RPC requests.
type Server struct {
	opts  options
	mu    sync.Mutex
	lis   map[net.Listener]bool
	conns map[transport.ServerTransport]bool
	m     map[string]*service // service name -> service info
}

type options struct {
	handshaker           func(net.Conn) error
	codec                Codec
	maxConcurrentStreams uint32
}

// A ServerOption sets options.
type ServerOption func(*options)

// Handshaker returns a ServerOption that specifies a function to perform user-specified
// handshaking on the connection before it becomes usable for gRPC.
func Handshaker(f func(net.Conn) error) ServerOption {
	return func(o *options) {
		o.handshaker = f
	}
}

// CustomeCodec returns a ServerOption that sets a codec for message marshaling and unmarshaling.
func CustomCodec(codec Codec) ServerOption {
	return func(o *options) {
		o.codec = codec
	}
}

// MaxConcurrentStreams returns a ServerOption that will apply a limit on the number
// of concurrent streams to each ServerTransport.
func MaxConcurrentStreams(n uint32) ServerOption {
	return func(o *options) {
		o.maxConcurrentStreams = n
	}
}

// NewServer creates a gRPC server which has no service registered and has not
// started to accept requests yet.
func NewServer(opt ...ServerOption) *Server {
	var opts options
	for _, o := range opt {
		o(&opts)
	}
	if opts.codec == nil {
		// Set the default codec.
		opts.codec = protoCodec{}
	}
	return &Server{
		lis:   make(map[net.Listener]bool),
		opts:  opts,
		conns: make(map[transport.ServerTransport]bool),
		m:     make(map[string]*service),
	}
}

// RegisterService register a service and its implementation to the gRPC
// server. Called from the IDL generated code. This must be called before
// invoking Serve.
func (s *Server) RegisterService(sd *ServiceDesc, ss interface{}) {
	s.mu.Lock()
	defer s.mu.Unlock()
	// Does some sanity checks.
	if _, ok := s.m[sd.ServiceName]; ok {
		log.Fatalf("grpc: Server.RegisterService found duplicate service registration for %q", sd.ServiceName)
	}
	ht := reflect.TypeOf(sd.HandlerType).Elem()
	st := reflect.TypeOf(ss)
	if !st.Implements(ht) {
		log.Fatalf("grpc: Server.RegisterService found the handler of type %v that does not satisfy %v", st, ht)
	}
	srv := &service{
		server: ss,
		md:     make(map[string]*MethodDesc),
		sd:     make(map[string]*StreamDesc),
	}
	for i := range sd.Methods {
		d := &sd.Methods[i]
		srv.md[d.MethodName] = d
	}
	for i := range sd.Streams {
		d := &sd.Streams[i]
		srv.sd[d.StreamName] = d
	}
	s.m[sd.ServiceName] = srv
}

var (
	// ErrServerStopped indicates that the operation is now illegal because of
	// the server being stopped.
	ErrServerStopped = errors.New("grpc: the server has been stopped")
)

// Serve accepts incoming connections on the listener lis, creating a new
// ServerTransport and service goroutine for each. The service goroutines
// read gRPC request and then call the registered handlers to reply to them.
// Service returns when lis.Accept fails.
func (s *Server) Serve(lis net.Listener) error {
	s.mu.Lock()
	if s.lis == nil {
		s.mu.Unlock()
		return ErrServerStopped
	}
	s.lis[lis] = true
	s.mu.Unlock()
	defer func() {
		lis.Close()
		s.mu.Lock()
		delete(s.lis, lis)
		s.mu.Unlock()
	}()
	for {
		c, err := lis.Accept()
		if err != nil {
			return err
		}
		// Perform handshaking if it is required.
		if s.opts.handshaker != nil {
			if err := s.opts.handshaker(c); err != nil {
				log.Println("grpc: Server.Serve failed to complete handshake.")
				c.Close()
				continue
			}
		}
		s.mu.Lock()
		if s.conns == nil {
			s.mu.Unlock()
			c.Close()
			return nil
		}
		st, err := transport.NewServerTransport("http2", c, s.opts.maxConcurrentStreams)
		if err != nil {
			s.mu.Unlock()
			c.Close()
			log.Println("grpc: Server.Serve failed to create ServerTransport: ", err)
			continue
		}
		s.conns[st] = true
		s.mu.Unlock()

		go func() {
			st.HandleStreams(func(stream *transport.Stream) {
				s.handleStream(st, stream)
			})
			s.mu.Lock()
			delete(s.conns, st)
			s.mu.Unlock()
		}()
	}
}

func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, pf payloadFormat, opts *transport.Options) error {
	p, err := encode(s.opts.codec, msg, pf)
	if err != nil {
		// This typically indicates a fatal issue (e.g., memory
		// corruption or hardware faults) the application program
		// cannot handle.
		//
		// TODO(zhaoq): There exist other options also such as only closing the
		// faulty stream locally and remotely (Other streams can keep going). Find
		// the optimal option.
		log.Fatalf("grpc: Server failed to encode response %v", err)
	}
	return t.Write(stream, p, opts)
}

func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, md *MethodDesc) {
	p := &parser{s: stream}
	for {
		pf, req, err := p.recvMsg()
		if err == io.EOF {
			// The entire stream is done (for unary RPC only).
			return
		}
		if err != nil {
			switch err := err.(type) {
			case transport.ConnectionError:
				// Nothing to do here.
			case transport.StreamError:
				if err := t.WriteStatus(stream, err.Code, err.Desc); err != nil {
					log.Printf("grpc: Server.processUnaryRPC failed to write status: %v", err)
				}
			default:
				panic(fmt.Sprintf("grpc: Unexpected error (%T) from recvMsg: %v", err, err))
			}
			return
		}
		switch pf {
		case compressionNone:
			statusCode := codes.OK
			statusDesc := ""
			reply, appErr := md.Handler(srv.server, stream.Context(), s.opts.codec, req)
			if appErr != nil {
				if err, ok := appErr.(rpcError); ok {
					statusCode = err.code
					statusDesc = err.desc
				} else {
					statusCode = convertCode(appErr)
					statusDesc = appErr.Error()
				}
				if err := t.WriteStatus(stream, statusCode, statusDesc); err != nil {
					log.Printf("grpc: Server.processUnaryRPC failed to write status: %v", err)
				}
				return
			}
			opts := &transport.Options{
				Last:  true,
				Delay: false,
			}
			if err := s.sendResponse(t, stream, reply, compressionNone, opts); err != nil {
				if _, ok := err.(transport.ConnectionError); ok {
					return
				}
				if e, ok := err.(transport.StreamError); ok {
					statusCode = e.Code
					statusDesc = e.Desc
				} else {
					statusCode = codes.Unknown
					statusDesc = err.Error()
				}
			}
			t.WriteStatus(stream, statusCode, statusDesc)
		default:
			panic(fmt.Sprintf("payload format to be supported: %d", pf))
		}
	}
}

func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc) {
	ss := &serverStream{
		t:     t,
		s:     stream,
		p:     &parser{s: stream},
		codec: s.opts.codec,
	}
	if appErr := sd.Handler(srv.server, ss); appErr != nil {
		if err, ok := appErr.(rpcError); ok {
			ss.statusCode = err.code
			ss.statusDesc = err.desc
		} else {
			ss.statusCode = convertCode(appErr)
			ss.statusDesc = appErr.Error()
		}
	}
	t.WriteStatus(ss.s, ss.statusCode, ss.statusDesc)
}

func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream) {
	sm := stream.Method()
	if sm != "" && sm[0] == '/' {
		sm = sm[1:]
	}
	pos := strings.LastIndex(sm, "/")
	if pos == -1 {
		if err := t.WriteStatus(stream, codes.InvalidArgument, fmt.Sprintf("malformed method name: %q", stream.Method())); err != nil {
			log.Printf("grpc: Server.handleStream failed to write status: %v", err)
		}
		return
	}
	service := sm[:pos]
	method := sm[pos+1:]
	srv, ok := s.m[service]
	if !ok {
		if err := t.WriteStatus(stream, codes.Unimplemented, fmt.Sprintf("unknown service %v", service)); err != nil {
			log.Printf("grpc: Server.handleStream failed to write status: %v", err)
		}
		return
	}
	// Unary RPC or Streaming RPC?
	if md, ok := srv.md[method]; ok {
		s.processUnaryRPC(t, stream, srv, md)
		return
	}
	if sd, ok := srv.sd[method]; ok {
		s.processStreamingRPC(t, stream, srv, sd)
		return
	}
	if err := t.WriteStatus(stream, codes.Unimplemented, fmt.Sprintf("unknown method %v", method)); err != nil {
		log.Printf("grpc: Server.handleStream failed to write status: %v", err)
	}
}

// Stop stops the gRPC server. Once Stop returns, the server stops accepting
// connection requests and closes all the connected connections.
func (s *Server) Stop() {
	s.mu.Lock()
	listeners := s.lis
	s.lis = nil
	cs := s.conns
	s.conns = nil
	s.mu.Unlock()
	for lis := range listeners {
		lis.Close()
	}
	for c := range cs {
		c.Close()
	}
}

// TestingCloseConns closes all exiting transports but keeps s.lis accepting new
// connections. This is for test only now.
func (s *Server) TestingCloseConns() {
	s.mu.Lock()
	for c := range s.conns {
		c.Close()
	}
	s.conns = make(map[transport.ServerTransport]bool)
	s.mu.Unlock()
}

// SendHeader sends header metadata. It may be called at most once from a unary
// RPC handler. The ctx is the RPC handler's Context or one derived from it.
func SendHeader(ctx context.Context, md metadata.MD) error {
	if md.Len() == 0 {
		return nil
	}
	stream, ok := transport.StreamFromContext(ctx)
	if !ok {
		return fmt.Errorf("grpc: failed to fetch the stream from the context %v", ctx)
	}
	t := stream.ServerTransport()
	if t == nil {
		log.Fatalf("grpc: SendHeader: %v has no ServerTransport to send header metadata.", stream)
	}
	return t.WriteHeader(stream, md)
}

// SetTrailer sets the trailer metadata that will be sent when an RPC returns.
// It may be called at most once from a unary RPC handler. The ctx is the RPC
// handler's Context or one derived from it.
func SetTrailer(ctx context.Context, md metadata.MD) error {
	if md.Len() == 0 {
		return nil
	}
	stream, ok := transport.StreamFromContext(ctx)
	if !ok {
		return fmt.Errorf("grpc: failed to fetch the stream from the context %v", ctx)
	}
	return stream.SetTrailer(md)
}
<|endoftext|>


<commit_before>package synapse

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"github.com/philhofer/msgp/enc"
	"io"
	"log"
	"math"
	"net"
	"time"
)

// maxFRAMESIZE is the maximum size of a message
const maxFRAMESIZE = math.MaxUint16

// FRAMING EXPLANATION:
//
// Request:
//   |   seq#  |   len   |   name  |  msg  |
//   | uint64  |  uint32 |  string | (bts) |
//
// Response:
//   |   seq#  |   len   |   code  |  msg  |
//   | uint64  |  uint32 |  int64  | (bts) |
//
// - 'seq' should increase monotonically per request
// - 'len' should be the number of bytes *remaining* to be read
// - 'name' is a messagepack-encoded string
// - 'code' is a messagepack-encoded signed integer (up to 64 bits)
// - 'msg' is any messagepack-encoded message
//
// Clients and servers do asynchronous writes and synchronous reads.
//
// All writes (on either side) need to be atomic; conn.Write() is called exactly once and
// (should) contain the entirety of the request (client-side) or response (server-side).
//
// Clients ignore requests with bad sequence numbers.
//
// Both clients and servers force-close connections if they
// detect a frame larger than maxFRAMESIZE. This is to make it
// impossible for one side to ask the other (for whatever reason)
// to allocate an unreasonable amount of memory. Also, the maximum
// frame size is the default size of the TCP window, which keeps
// latency reasonable. (No more than one ACK per write.)
//
// In principle, the client can operate on any net.Conn, and the
// server can operate on any net.Listener. However, the protocol
// was designed with TCP in mind.

// Serve starts a server on 'l' that serves
// the supplied handler.
func Serve(l net.Listener, h Handler) error {
	s := server{l, h}
	return s.serve()
}

type server struct {
	l net.Listener
	h Handler
}

func (s *server) serve() error {
	for {
		conn, err := s.l.Accept()
		if err != nil {
			return err
		}
		ch := &connHandler{conn: conn, h: s.h}
		go ch.connLoop()
	}
}

// connHandler handles network
// connections and multiplexes requests
// to connWrappers
type connHandler struct {
	h    Handler
	conn net.Conn
}

// connLoop continuously polls the connection.
// requests are read synchronously; the responses
// are written in a spawned goroutine
func (c *connHandler) connLoop() {
	brd := bufio.NewReader(c.conn)

	var lead [12]byte
	var seq uint64
	var sz uint32
	for {
		// loop:
		//  - read seq and sz
		//  - call handler asynchronously

		_, err := io.ReadFull(brd, lead[:])
		if err != nil {
			if err != io.EOF {
				log.Printf("server: fatal: %s", err)
			}
			c.conn.Close()
			break
		}
		seq = binary.BigEndian.Uint64(lead[0:8])
		sz = binary.BigEndian.Uint32(lead[8:12])

		// reject frames
		// larger than 65kB
		if sz > maxFRAMESIZE {
			log.Printf("synapse server: client at %s sent a %d-byte frame; force-closing connection...",
				c.conn.RemoteAddr().String(), sz)
			c.conn.Close()
			break
		}

		isz := int(sz)
		w := popWrapper(c)

		if cap(w.in) >= isz {
			w.in = w.in[0:isz]
		} else {
			w.in = make([]byte, isz)
		}

		// don't block forever here
		c.conn.SetReadDeadline(time.Now().Add(1 * time.Second))
		_, err = io.ReadFull(brd, w.in)
		if err != nil {
			log.Printf("synapse server: fatal error: %s", err)
			c.conn.Close()
			break
		}
		// clear read deadline
		c.conn.SetReadDeadline(time.Time{})

		// trigger handler
		w.seq = seq
		w.dc.Reset(bytes.NewReader(w.in))
		go handleConn(w, c.h) // must write atomically
	}
}

// connWrapper contains all the resources
// necessary to execute a Handler on a request
type connWrapper struct {
	seq    uint64
	lead   [12]byte
	in     []byte       // incoming message
	out    bytes.Buffer // we need to write to parent.conn atomically, so buffer the whole message
	req    request
	res    response
	en     *enc.MsgWriter // wraps bytes.Buffer
	dc     *enc.MsgReader // wraps 'in'
	parent *connHandler
}

// handleconn sets up the Request and ResponseWriter
// interfaces and calls the handler.
// output is written to cw.parent.conn
func handleConn(cw *connWrapper, h Handler) {
	// clear/reset everything
	cw.out.Reset()
	cw.req.dc = cw.dc
	cw.req.addr = cw.parent.conn.RemoteAddr()
	cw.res.en = cw.en
	cw.res.err = nil
	cw.res.wrote = false
	cw.res.status = Invalid

	// reserve 12 bytes at the beginning
	cw.out.Write(cw.lead[:])

	var err error
	cw.req.name, _, err = cw.dc.ReadString()
	if err != nil {
		cw.res.WriteHeader(BadRequest)
	} else {
		h.ServeCall(&cw.req, &cw.res)
	}

	if !cw.res.wrote {
		cw.res.WriteHeader(OK)
		cw.res.Send(nil)
	}

	bts := cw.out.Bytes()
	blen := len(bts) - 12 // length minus frame length
	binary.BigEndian.PutUint64(bts[0:8], cw.seq)
	binary.BigEndian.PutUint32(bts[8:12], uint32(blen))

	// net.Conn takes care of the
	// locking for us
	_, err = cw.parent.conn.Write(bts)
	if err != nil {
		// TODO: print something more usefull...?
		log.Printf("synapse server: error writing response: %s", err)
	}
	pushWrapper(cw)
}
<commit_msg>don't deadline unnecessarily<commit_after>package synapse

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"github.com/philhofer/msgp/enc"
	"io"
	"log"
	"math"
	"net"
	"time"
)

// maxFRAMESIZE is the maximum size of a message
const maxFRAMESIZE = math.MaxUint16

// FRAMING EXPLANATION:
//
// Request:
//   |   seq#  |   len   |   name  |  msg  |
//   | uint64  |  uint32 |  string | (bts) |
//
// Response:
//   |   seq#  |   len   |   code  |  msg  |
//   | uint64  |  uint32 |  int64  | (bts) |
//
// - 'seq' should increase monotonically per request
// - 'len' should be the number of bytes *remaining* to be read
// - 'name' is a messagepack-encoded string
// - 'code' is a messagepack-encoded signed integer (up to 64 bits)
// - 'msg' is any messagepack-encoded message
//
// Clients and servers do asynchronous writes and synchronous reads.
//
// All writes (on either side) need to be atomic; conn.Write() is called exactly once and
// (should) contain the entirety of the request (client-side) or response (server-side).
//
// Clients ignore requests with bad sequence numbers.
//
// Both clients and servers force-close connections if they
// detect a frame larger than maxFRAMESIZE. This is to make it
// impossible for one side to ask the other (for whatever reason)
// to allocate an unreasonable amount of memory. Also, the maximum
// frame size is the default size of the TCP window, which keeps
// latency reasonable. (No more than one ACK per write.)
//
// In principle, the client can operate on any net.Conn, and the
// server can operate on any net.Listener. However, the protocol
// was designed with TCP in mind.

// Serve starts a server on 'l' that serves
// the supplied handler.
func Serve(l net.Listener, h Handler) error {
	s := server{l, h}
	return s.serve()
}

type server struct {
	l net.Listener
	h Handler
}

func (s *server) serve() error {
	for {
		conn, err := s.l.Accept()
		if err != nil {
			return err
		}
		ch := &connHandler{conn: conn, h: s.h}
		go ch.connLoop()
	}
}

// connHandler handles network
// connections and multiplexes requests
// to connWrappers
type connHandler struct {
	h    Handler
	conn net.Conn
}

// connLoop continuously polls the connection.
// requests are read synchronously; the responses
// are written in a spawned goroutine
func (c *connHandler) connLoop() {
	brd := bufio.NewReader(c.conn)

	var lead [12]byte
	var seq uint64
	var sz uint32
	for {
		// loop:
		//  - read seq and sz
		//  - call handler asynchronously

		_, err := io.ReadFull(brd, lead[:])
		if err != nil {
			if err != io.EOF {
				log.Printf("server: fatal: %s", err)
			}
			c.conn.Close()
			break
		}
		seq = binary.BigEndian.Uint64(lead[0:8])
		sz = binary.BigEndian.Uint32(lead[8:12])

		// reject frames
		// larger than 65kB
		if sz > maxFRAMESIZE {
			log.Printf("synapse server: client at %s sent a %d-byte frame; force-closing connection...",
				c.conn.RemoteAddr().String(), sz)
			c.conn.Close()
			break
		}

		isz := int(sz)
		w := popWrapper(c)

		if cap(w.in) >= isz {
			w.in = w.in[0:isz]
		} else {
			w.in = make([]byte, isz)
		}

		// don't block forever here,
		// deadline if we haven't already
		// buffered the connection data
		deadline := false
		if brd.Buffered() < isz {
			c.conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))

		}
		_, err = io.ReadFull(brd, w.in)
		if err != nil {
			log.Printf("synapse server: fatal error: %s", err)
			c.conn.Close()
			break
		}
		// clear read deadline
		if deadline {
			c.conn.SetReadDeadline(time.Time{})

		}

		// trigger handler
		w.seq = seq
		w.dc.Reset(bytes.NewReader(w.in))
		go handleConn(w, c.h) // must write atomically
	}
}

// connWrapper contains all the resources
// necessary to execute a Handler on a request
type connWrapper struct {
	seq    uint64
	lead   [12]byte
	in     []byte       // incoming message
	out    bytes.Buffer // we need to write to parent.conn atomically, so buffer the whole message
	req    request
	res    response
	en     *enc.MsgWriter // wraps bytes.Buffer
	dc     *enc.MsgReader // wraps 'in'
	parent *connHandler
}

// handleconn sets up the Request and ResponseWriter
// interfaces and calls the handler.
// output is written to cw.parent.conn
func handleConn(cw *connWrapper, h Handler) {
	// clear/reset everything
	cw.out.Reset()
	cw.req.dc = cw.dc
	cw.req.addr = cw.parent.conn.RemoteAddr()
	cw.res.en = cw.en
	cw.res.err = nil
	cw.res.wrote = false
	cw.res.status = Invalid

	// reserve 12 bytes at the beginning
	cw.out.Write(cw.lead[:])

	var err error
	cw.req.name, _, err = cw.dc.ReadString()
	if err != nil {
		cw.res.WriteHeader(BadRequest)
	} else {
		h.ServeCall(&cw.req, &cw.res)
	}

	if !cw.res.wrote {
		cw.res.WriteHeader(OK)
		cw.res.Send(nil)
	}

	bts := cw.out.Bytes()
	blen := len(bts) - 12 // length minus frame length
	binary.BigEndian.PutUint64(bts[0:8], cw.seq)
	binary.BigEndian.PutUint32(bts[8:12], uint32(blen))

	// TODO: timeout?
	// net.Conn takes care of the
	// locking for us
	_, err = cw.parent.conn.Write(bts)
	if err != nil {
		// TODO: print something more usefull...?
		log.Printf("synapse server: error writing response: %s", err)
	}
	pushWrapper(cw)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"time"
	"math/rand"
	"github.com/gocodo/bloomdb"
)

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")

func randSeq(n int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func Create() error {
	key := randSeq(32)

	bdb := bloomdb.CreateDB()
	conn, err := bdb.SqlConnection()
	if err != nil {
		return err
	}

	createdAt := time.Now().UTC()
	key_id := bloomdb.MakeKey(key)

	_, err = conn.Exec("INSERT INTO api_keys (id, key, created_at) VALUES ($1, $2, $3)", key_id, key, createdAt)
	if err != nil {
		return err
	}

	fmt.Printf("Created Key '%s' at '%s'\n", key, createdAt.String())

	return nil
}<commit_msg>updating api tool<commit_after>package cmd

import (
	"fmt"
	"time"
	"math/rand"
	"github.com/gocodo/bloomdb"
)

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")

func randSeq(n int) string {
	rand.Seed(time.Now().UTC().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func Create() error {
	key := randSeq(32)

	bdb := bloomdb.CreateDB()
	conn, err := bdb.SqlConnection()
	if err != nil {
		return err
	}

	createdAt := time.Now().UTC()
	key_id := bloomdb.MakeKey(key)

	_, err = conn.Exec("INSERT INTO api_keys (id, key, created_at, updated_at) VALUES ($1, $2, $3, $3)", key_id, key, createdAt)
	if err != nil {
		return err
	}

	fmt.Printf("Created Key '%s' at '%s'\n", key, createdAt.String())

	return nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"github.com/arschles/gbs/log"
	docker "github.com/fsouza/go-dockerclient"
	"github.com/gorilla/mux"
)

const (
	containerBinDir = "/gobin"
	containerGoPath = "/go"
)

func BuildURL() string {
	return fmt.Sprintf("/{%s}/{%s}/{%s}", site, org, repo)
}

func Build(workdir string, dockerCl *docker.Client) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		flusher, ok := w.(http.Flusher)
		if !ok {
			httpErrf(w, http.StatusInternalServerError, "server doesn't support flushing output")
			return
		}

		site, ok := mux.Vars(r)[site]
		if !ok {
			httpErrf(w, http.StatusBadRequest, "missing site in path")
			return
		}

		org, ok := mux.Vars(r)[org]
		if !ok {
			httpErrf(w, http.StatusBadRequest, "missing org in path")
			return
		}

		repo, ok := mux.Vars(r)[repo]
		if !ok {
			httpErrf(w, http.StatusBadRequest, "missing repo in path")
			return
		}

		req := newBuildReq()
		if err := json.NewDecoder(r.Body).Decode(req); err != nil {
			log.Errf("decoding request body [%s]", err)
			http.Error(w, fmt.Sprintf("Error decoding request body [%s]", err), http.StatusBadRequest)
			return
		}
		defer r.Body.Close()

		env := []string{
			"GO15VENDOREXPERIMENT=1",
			"SITE=" + site,
			"ORG=" + org,
			"REPO=" + repo,
			"BIN_NAME=" + repo,
			"BIN_DIR=" + containerBinDir,
			"GOPATH=" + containerGoPath,
		}

		createContainerOpts, hostConfig := createAndStartContainerOpts(
			req.buildImage(),
			containerName(site, org, repo),
			nil,
			append(env, req.envs()...),
			"/",
			[]docker.Mount{
				docker.Mount{Name: "bin", Source: workdir, Destination: containerBinDir, Mode: "rx"},
			},
		)

		container, err := dockerCl.CreateContainer(*createContainerOpts)

		if err != nil {
			log.Errf("creating container [%s]", err)
			httpErrf(w, http.StatusInternalServerError, "error creating container [%s]", err)
			return
		}

		if err := dockerCl.StartContainer(container.ID, hostConfig); err != nil {
			log.Errf("starting container [%s]", err)
			httpErrf(w, http.StatusInternalServerError, "error starting container [%s]", err)
			return
		}

		attachOpts, outputReader := attachToContainerOpts(container.ID)
		errCh := make(chan error)
		go func() {
			if err := dockerCl.AttachToContainer(attachOpts); err != nil {
				errCh <- err
			}
		}()

		w.WriteHeader(http.StatusCreated)
		go func(reader io.Reader) {
			scanner := bufio.NewScanner(reader)
			for scanner.Scan() {
				fmt.Fprintf(w, "%s\n", scanner.Text())
				flusher.Flush()
			}
			if err := scanner.Err(); err != nil {
				fmt.Fprintf(w, "error with scanner in attached container [%s]\n", err)
			}
		}(outputReader)

		code, err := dockerCl.WaitContainer(container.ID)
		if err != nil {
			log.Errf("waiting for container %s [%s]", container.ID, err)
			return
		}
		w.Write([]byte(fmt.Sprintf("exited with error code %d\n", code)))

		removeOpts := docker.RemoveContainerOptions{
			ID:            container.ID,
			RemoveVolumes: true,
			Force:         true,
		}
		if err := dockerCl.RemoveContainer(removeOpts); err != nil {
			log.Errf("removing container %s [%s]", container.ID, err)
		}
	})
}
<commit_msg>allow for empty request bodies<commit_after>package handlers

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"github.com/arschles/gbs/log"
	docker "github.com/fsouza/go-dockerclient"
	"github.com/gorilla/mux"
)

const (
	containerBinDir = "/gobin"
	containerGoPath = "/go"
)

func BuildURL() string {
	return fmt.Sprintf("/{%s}/{%s}/{%s}", site, org, repo)
}

func Build(workdir string, dockerCl *docker.Client) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		flusher, ok := w.(http.Flusher)
		if !ok {
			httpErrf(w, http.StatusInternalServerError, "server doesn't support flushing output")
			return
		}

		site, ok := mux.Vars(r)[site]
		if !ok {
			httpErrf(w, http.StatusBadRequest, "missing site in path")
			return
		}

		org, ok := mux.Vars(r)[org]
		if !ok {
			httpErrf(w, http.StatusBadRequest, "missing org in path")
			return
		}

		repo, ok := mux.Vars(r)[repo]
		if !ok {
			httpErrf(w, http.StatusBadRequest, "missing repo in path")
			return
		}

		req := newBuildReq()
		if err := json.NewDecoder(r.Body).Decode(req); err != nil {
			// allow for empty request bodies
			if err != io.EOF {
				log.Errf("decoding request body [%s]", err)
				http.Error(w, fmt.Sprintf("Error decoding request body [%s]", err), http.StatusBadRequest)
				return
			}
		}
		defer r.Body.Close()

		env := []string{
			"GO15VENDOREXPERIMENT=1",
			"SITE=" + site,
			"ORG=" + org,
			"REPO=" + repo,
			"BIN_NAME=" + repo,
			"BIN_DIR=" + containerBinDir,
			"GOPATH=" + containerGoPath,
		}

		createContainerOpts, hostConfig := createAndStartContainerOpts(
			req.buildImage(),
			containerName(site, org, repo),
			nil,
			append(env, req.envs()...),
			"/",
			[]docker.Mount{
				docker.Mount{Name: "bin", Source: workdir, Destination: containerBinDir, Mode: "rx"},
			},
		)

		container, err := dockerCl.CreateContainer(*createContainerOpts)

		if err != nil {
			log.Errf("creating container [%s]", err)
			httpErrf(w, http.StatusInternalServerError, "error creating container [%s]", err)
			return
		}

		if err := dockerCl.StartContainer(container.ID, hostConfig); err != nil {
			log.Errf("starting container [%s]", err)
			httpErrf(w, http.StatusInternalServerError, "error starting container [%s]", err)
			return
		}

		attachOpts, outputReader := attachToContainerOpts(container.ID)
		errCh := make(chan error)
		go func() {
			if err := dockerCl.AttachToContainer(attachOpts); err != nil {
				errCh <- err
			}
		}()

		w.WriteHeader(http.StatusCreated)
		go func(reader io.Reader) {
			scanner := bufio.NewScanner(reader)
			for scanner.Scan() {
				fmt.Fprintf(w, "%s\n", scanner.Text())
				flusher.Flush()
			}
			if err := scanner.Err(); err != nil {
				fmt.Fprintf(w, "error with scanner in attached container [%s]\n", err)
			}
		}(outputReader)

		code, err := dockerCl.WaitContainer(container.ID)
		if err != nil {
			log.Errf("waiting for container %s [%s]", container.ID, err)
			return
		}
		w.Write([]byte(fmt.Sprintf("exited with error code %d\n", code)))

		removeOpts := docker.RemoveContainerOptions{
			ID:            container.ID,
			RemoveVolumes: true,
			Force:         true,
		}
		if err := dockerCl.RemoveContainer(removeOpts); err != nil {
			log.Errf("removing container %s [%s]", container.ID, err)
		}
	})
}
<|endoftext|>


<commit_before>package handlers

import (
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"strings"

	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/jmoiron/sqlx"

	"github.com/resourced/resourced-master/dal"
	"github.com/resourced/resourced-master/libhttp"
	"github.com/resourced/resourced-master/mailer"
)

func GetSignup(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	qParams := r.URL.Query()
	email := qParams.Get("email")
	token := qParams.Get("token")

	data := struct {
		Email                  string
		EmailVerificationToken string
	}{
		email,
		token,
	}

	tmpl, err := template.ParseFiles("templates/users/login-signup.html.tmpl", "templates/users/signup.html.tmpl")
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	tmpl.Execute(w, data)
}

func PostSignup(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	db := context.Get(r, "db.Core").(*sqlx.DB)

	email := r.FormValue("Email")
	password := r.FormValue("Password")
	passwordAgain := r.FormValue("PasswordAgain")
	emailVerificationToken := r.FormValue("EmailVerificationToken")

	emailValidated := false

	userRow, err := dal.NewUser(db).GetByEmail(nil, email)

	if err != nil && err.Error() == "sql: no rows in result set" {
		// There's no existing user in the database, create a new one.
		userRow, err = dal.NewUser(db).Signup(nil, email, password, passwordAgain)
		if err != nil {
			libhttp.HandleErrorJson(w, err)
			return
		}

		// Create a default cluster
		clusterRow, err := dal.NewCluster(db).Create(nil, userRow, "Default")
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

		// Create a default access-token
		_, err = dal.NewAccessToken(db).Create(nil, userRow.ID, clusterRow.ID, "execute")
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

	} else if userRow != nil {
		if userRow.EmailVerificationToken.String != emailVerificationToken {
			libhttp.HandleErrorHTML(w, errors.New("Mismatch token"), 500)
			return
		}

		emailValidated = true

		// There's an existing user in the database, update email and password info.
		userRow, err = dal.NewUser(db).UpdateEmailAndPasswordById(nil, userRow.ID, email, password, passwordAgain)
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

		// Verified that emailVerificationToken works.
		_, err = dal.NewUser(db).UpdateEmailVerification(nil, emailVerificationToken)
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}
	}

	// Send email verification if needed
	if !emailValidated {
		go func(userRow *dal.UserRow) {
			if userRow.EmailVerificationToken.String != "" {
				mailer := context.Get(r, "mailer.GeneralConfig").(*mailer.Mailer)

				vipAddr := context.Get(r, "vipAddr").(string)
				vipProtocol := context.Get(r, "vipProtocol").(string)

				url := fmt.Sprintf("%v://%v/users/email-verification/%v", vipProtocol, vipAddr, userRow.EmailVerificationToken.String)

				body := fmt.Sprintf("Click the following link to verify your email address:\n\n%v", url)

				mailer.Send(userRow.Email, "Email Verification", body)
			}
		}(userRow)
	}

	// Perform login
	PostLogin(w, r)
}

func GetLoginWithoutSession(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	tmpl, err := template.ParseFiles("templates/users/login-signup.html.tmpl", "templates/users/login.html.tmpl")
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	tmpl.Execute(w, nil)
}

// GetLogin get login page.
func GetLogin(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	cookieStore := context.Get(r, "cookieStore").(*sessions.CookieStore)

	session, _ := cookieStore.Get(r, "resourcedmaster-session")

	currentUserInterface := session.Values["user"]
	if currentUserInterface != nil {
		http.Redirect(w, r, "/", 301)
		return
	}

	GetLoginWithoutSession(w, r)
}

// PostLogin performs login.
func PostLogin(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	db := context.Get(r, "db.Core").(*sqlx.DB)
	cookieStore := context.Get(r, "cookieStore").(*sessions.CookieStore)

	email := r.FormValue("Email")
	password := r.FormValue("Password")

	u := dal.NewUser(db)

	user, err := u.GetUserByEmailAndPassword(nil, email, password)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	session, _ := cookieStore.Get(r, "resourcedmaster-session")
	session.Values["user"] = user

	err = session.Save(r, w)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	http.Redirect(w, r, "/", 301)
}

func PostPutDeleteUsersID(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	method := r.FormValue("_method")
	if method == "" || strings.ToLower(method) == "post" || strings.ToLower(method) == "put" {
		PutUsersID(w, r)
	} else if strings.ToLower(method) == "delete" {
		DeleteUsersID(w, r)
	}
}

func PutUsersID(w http.ResponseWriter, r *http.Request) {
	userId, err := getInt64SlugFromPath(w, r, "id")
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	db := context.Get(r, "db.Core").(*sqlx.DB)

	cookieStore := context.Get(r, "cookieStore").(*sessions.CookieStore)

	session, _ := cookieStore.Get(r, "resourcedmaster-session")

	currentUser := session.Values["user"].(*dal.UserRow)

	if currentUser.ID != userId {
		err := errors.New("Modifying other user is not allowed.")
		libhttp.HandleErrorJson(w, err)
		return
	}

	email := r.FormValue("Email")
	password := r.FormValue("Password")
	passwordAgain := r.FormValue("PasswordAgain")

	u := dal.NewUser(db)

	currentUser, err = u.UpdateEmailAndPasswordById(nil, currentUser.ID, email, password, passwordAgain)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	// Update currentUser stored in session.
	session.Values["user"] = currentUser
	err = session.Save(r, w)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	http.Redirect(w, r, "/", 301)
}

func DeleteUsersID(w http.ResponseWriter, r *http.Request) {
	err := errors.New("DELETE method is not implemented.")
	libhttp.HandleErrorJson(w, err)
	return
}

// GetUsersEmailVerificationToken verifies user email.
func GetUsersEmailVerificationToken(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	db := context.Get(r, "db.Core").(*sqlx.DB)

	emailVerificationToken := mux.Vars(r)["token"]

	_, err := dal.NewUser(db).UpdateEmailVerification(nil, emailVerificationToken)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	http.Redirect(w, r, "/login", 301)
}
<commit_msg>on signup and login, returns error in html mode.<commit_after>package handlers

import (
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"strings"

	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/jmoiron/sqlx"

	"github.com/resourced/resourced-master/dal"
	"github.com/resourced/resourced-master/libhttp"
	"github.com/resourced/resourced-master/mailer"
)

func GetSignup(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	qParams := r.URL.Query()
	email := qParams.Get("email")
	token := qParams.Get("token")

	data := struct {
		Email                  string
		EmailVerificationToken string
	}{
		email,
		token,
	}

	tmpl, err := template.ParseFiles("templates/users/login-signup.html.tmpl", "templates/users/signup.html.tmpl")
	if err != nil {
		libhttp.HandleErrorHTML(w, err, 500)
		return
	}

	tmpl.Execute(w, data)
}

func PostSignup(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	db := context.Get(r, "db.Core").(*sqlx.DB)

	email := r.FormValue("Email")
	password := r.FormValue("Password")
	passwordAgain := r.FormValue("PasswordAgain")
	emailVerificationToken := r.FormValue("EmailVerificationToken")

	emailValidated := false

	userRow, err := dal.NewUser(db).GetByEmail(nil, email)

	if err != nil && err.Error() == "sql: no rows in result set" {
		// There's no existing user in the database, create a new one.
		userRow, err = dal.NewUser(db).Signup(nil, email, password, passwordAgain)
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

		// Create a default cluster
		clusterRow, err := dal.NewCluster(db).Create(nil, userRow, "Default")
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

		// Create a default access-token
		_, err = dal.NewAccessToken(db).Create(nil, userRow.ID, clusterRow.ID, "execute")
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

	} else if userRow != nil {
		if userRow.EmailVerificationToken.String != emailVerificationToken {
			libhttp.HandleErrorHTML(w, errors.New("Mismatch token"), 500)
			return
		}

		emailValidated = true

		// There's an existing user in the database, update email and password info.
		userRow, err = dal.NewUser(db).UpdateEmailAndPasswordById(nil, userRow.ID, email, password, passwordAgain)
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}

		// Verified that emailVerificationToken works.
		_, err = dal.NewUser(db).UpdateEmailVerification(nil, emailVerificationToken)
		if err != nil {
			libhttp.HandleErrorHTML(w, err, 500)
			return
		}
	}

	// Send email verification if needed
	if !emailValidated {
		go func(userRow *dal.UserRow) {
			if userRow.EmailVerificationToken.String != "" {
				mailer := context.Get(r, "mailer.GeneralConfig").(*mailer.Mailer)

				vipAddr := context.Get(r, "vipAddr").(string)
				vipProtocol := context.Get(r, "vipProtocol").(string)

				url := fmt.Sprintf("%v://%v/users/email-verification/%v", vipProtocol, vipAddr, userRow.EmailVerificationToken.String)

				body := fmt.Sprintf("Click the following link to verify your email address:\n\n%v", url)

				mailer.Send(userRow.Email, "Email Verification", body)
			}
		}(userRow)
	}

	// Perform login
	PostLogin(w, r)
}

func GetLoginWithoutSession(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	tmpl, err := template.ParseFiles("templates/users/login-signup.html.tmpl", "templates/users/login.html.tmpl")
	if err != nil {
		libhttp.HandleErrorHTML(w, err, 500)
		return
	}

	tmpl.Execute(w, nil)
}

// GetLogin get login page.
func GetLogin(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	cookieStore := context.Get(r, "cookieStore").(*sessions.CookieStore)

	session, _ := cookieStore.Get(r, "resourcedmaster-session")

	currentUserInterface := session.Values["user"]
	if currentUserInterface != nil {
		http.Redirect(w, r, "/", 301)
		return
	}

	GetLoginWithoutSession(w, r)
}

// PostLogin performs login.
func PostLogin(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	db := context.Get(r, "db.Core").(*sqlx.DB)
	cookieStore := context.Get(r, "cookieStore").(*sessions.CookieStore)

	email := r.FormValue("Email")
	password := r.FormValue("Password")

	u := dal.NewUser(db)

	user, err := u.GetUserByEmailAndPassword(nil, email, password)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	session, _ := cookieStore.Get(r, "resourcedmaster-session")
	session.Values["user"] = user

	err = session.Save(r, w)
	if err != nil {
		libhttp.HandleErrorHTML(w, err, 500)
		return
	}

	http.Redirect(w, r, "/", 301)
}

func PostPutDeleteUsersID(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	method := r.FormValue("_method")
	if method == "" || strings.ToLower(method) == "post" || strings.ToLower(method) == "put" {
		PutUsersID(w, r)
	} else if strings.ToLower(method) == "delete" {
		DeleteUsersID(w, r)
	}
}

func PutUsersID(w http.ResponseWriter, r *http.Request) {
	userId, err := getInt64SlugFromPath(w, r, "id")
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	db := context.Get(r, "db.Core").(*sqlx.DB)

	cookieStore := context.Get(r, "cookieStore").(*sessions.CookieStore)

	session, _ := cookieStore.Get(r, "resourcedmaster-session")

	currentUser := session.Values["user"].(*dal.UserRow)

	if currentUser.ID != userId {
		err := errors.New("Modifying other user is not allowed.")
		libhttp.HandleErrorJson(w, err)
		return
	}

	email := r.FormValue("Email")
	password := r.FormValue("Password")
	passwordAgain := r.FormValue("PasswordAgain")

	u := dal.NewUser(db)

	currentUser, err = u.UpdateEmailAndPasswordById(nil, currentUser.ID, email, password, passwordAgain)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	// Update currentUser stored in session.
	session.Values["user"] = currentUser
	err = session.Save(r, w)
	if err != nil {
		libhttp.HandleErrorJson(w, err)
		return
	}

	http.Redirect(w, r, "/", 301)
}

func DeleteUsersID(w http.ResponseWriter, r *http.Request) {
	err := errors.New("DELETE method is not implemented.")
	libhttp.HandleErrorJson(w, err)
	return
}

// GetUsersEmailVerificationToken verifies user email.
func GetUsersEmailVerificationToken(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	db := context.Get(r, "db.Core").(*sqlx.DB)

	emailVerificationToken := mux.Vars(r)["token"]

	_, err := dal.NewUser(db).UpdateEmailVerification(nil, emailVerificationToken)
	if err != nil {
		libhttp.HandleErrorHTML(w, err, 500)
		return
	}

	http.Redirect(w, r, "/login", 301)
}
<|endoftext|>


<commit_before>// Package snaker provides methods to convert CamelCase names to snake_case and back.
// It considers the list of allowed initialsms used by github.com/golang/lint/golint (e.g. ID or HTTP)
package snaker

import (
	"strings"
	"unicode"
)

// CamelToSnake converts a given string to snake case
func CamelToSnake(s string) string {
	var result string
	var words []string
	var lastPos int
	rs := []rune(s)

	for i := 0; i < len(rs); i++ {
		if i > 0 && unicode.IsUpper(rs[i]) {
			if initialism := startsWithInitialism(s[lastPos:]); initialism != "" {
				words = append(words, initialism)

				i += len(initialism) - 1
				lastPos = i
				continue
			}

			words = append(words, s[lastPos:i])
			lastPos = i
		}
	}

	// append the last word
	if s[lastPos:] != "" {
		words = append(words, s[lastPos:])
	}

	for k, word := range words {
		if k > 0 {
			result += "_"
		}

		result += strings.ToLower(word)
	}

	return result
}

// SnakeToCamel returns a string converted from snake case to uppercase
func SnakeToCamel(s string) string {
	var result string

	words := strings.Split(s, "_")

	for _, word := range words {
		if upper := strings.ToUpper(word); commonInitialisms[upper] {
			result += upper
			continue
		}

		if len(word) > 0 {
			w := []rune(word)
			w[0] = unicode.ToUpper(w[0])
			result += string(w)
		}
	}

	return result
}

// startsWithInitialism returns the initialism if the given string begins with it
func startsWithInitialism(s string) string {
	var initialism string
	// the longest initialism is 5 char, the shortest 2
	for i := 1; i <= 5; i++ {
		if len(s) > i-1 && commonInitialisms[s[:i]] {
			initialism = s[:i]
		}
	}
	return initialism
}

// commonInitialisms, taken from
// https://github.com/golang/lint/blob/3d26dc39376c307203d3a221bada26816b3073cf/lint.go#L482
var commonInitialisms = map[string]bool{
	"API":   true,
	"ASCII": true,
	"CPU":   true,
	"CSS":   true,
	"DNS":   true,
	"EOF":   true,
	"GUID":  true,
	"HTML":  true,
	"HTTP":  true,
	"HTTPS": true,
	"ID":    true,
	"IP":    true,
	"JSON":  true,
	"LHS":   true,
	"QPS":   true,
	"RAM":   true,
	"RHS":   true,
	"RPC":   true,
	"SLA":   true,
	"SMTP":  true,
	"SSH":   true,
	"TLS":   true,
	"TTL":   true,
	"UI":    true,
	"UID":   true,
	"UUID":  true,
	"URI":   true,
	"URL":   true,
	"UTF8":  true,
	"VM":    true,
	"XML":   true,
}
<commit_msg>Updating commonInitialisms found in golint<commit_after>// Package snaker provides methods to convert CamelCase names to snake_case and back.
// It considers the list of allowed initialsms used by github.com/golang/lint/golint (e.g. ID or HTTP)
package snaker

import (
	"strings"
	"unicode"
)

// CamelToSnake converts a given string to snake case
func CamelToSnake(s string) string {
	var result string
	var words []string
	var lastPos int
	rs := []rune(s)

	for i := 0; i < len(rs); i++ {
		if i > 0 && unicode.IsUpper(rs[i]) {
			if initialism := startsWithInitialism(s[lastPos:]); initialism != "" {
				words = append(words, initialism)

				i += len(initialism) - 1
				lastPos = i
				continue
			}

			words = append(words, s[lastPos:i])
			lastPos = i
		}
	}

	// append the last word
	if s[lastPos:] != "" {
		words = append(words, s[lastPos:])
	}

	for k, word := range words {
		if k > 0 {
			result += "_"
		}

		result += strings.ToLower(word)
	}

	return result
}

// SnakeToCamel returns a string converted from snake case to uppercase
func SnakeToCamel(s string) string {
	var result string

	words := strings.Split(s, "_")

	for _, word := range words {
		if upper := strings.ToUpper(word); commonInitialisms[upper] {
			result += upper
			continue
		}

		if len(word) > 0 {
			w := []rune(word)
			w[0] = unicode.ToUpper(w[0])
			result += string(w)
		}
	}

	return result
}

// startsWithInitialism returns the initialism if the given string begins with it
func startsWithInitialism(s string) string {
	var initialism string
	// the longest initialism is 5 char, the shortest 2
	for i := 1; i <= 5; i++ {
		if len(s) > i-1 && commonInitialisms[s[:i]] {
			initialism = s[:i]
		}
	}
	return initialism
}

// commonInitialisms, taken from
// https://github.com/golang/lint/blob/32a87160691b3c96046c0c678fe57c5bef761456/lint.go#L702
var commonInitialisms = map[string]bool{
	"API":   true,
	"ASCII": true,
	"CPU":   true,
	"CSS":   true,
	"DNS":   true,
	"EOF":   true,
	"GUID":  true,
	"HTML":  true,
	"HTTP":  true,
	"HTTPS": true,
	"ID":    true,
	"IP":    true,
	"JSON":  true,
	"LHS":   true,
	"QPS":   true,
	"RAM":   true,
	"RHS":   true,
	"RPC":   true,
	"SLA":   true,
	"SMTP":  true,
	"SQL":   true,
	"SSH":   true,
	"TCP":   true,
	"TLS":   true,
	"TTL":   true,
	"UDP":   true,
	"UI":    true,
	"UID":   true,
	"UUID":  true,
	"URI":   true,
	"URL":   true,
	"UTF8":  true,
	"VM":    true,
	"XML":   true,
	"XSRF":  true,
	"XSS":   true,
}
<|endoftext|>