<commit_before>package rest

import (
	"fmt"
	"http"
	"strings"
)

var resources = make(map[string]interface{})

// Lists all the items in the resource
// GET /resource/
type Index interface {
	Index(http.ResponseWriter)
}

// Creates a new resource item
// POST /resource/
type Create interface {
	Create(http.ResponseWriter, *http.Request)
}

// Views a resource item
// GET /resource/id
type Find interface {
	Find(http.ResponseWriter, string)
}

// PUT /resource/id
type Update interface {
	Update(http.ResponseWriter, string, *http.Request)
}

// DELETE /resource/id
type Delete interface {
	Delete(http.ResponseWriter, string)
}

// Return options to use the service. If string is nil, then it is the base URL
// OPTIONS /resource/id
// OPTIONS /resource/
type Options interface {
	Options(http.ResponseWriter, string)
}

// Generic resource handler
func resourceHandler(c http.ResponseWriter, req *http.Request) {
	// Parse request URI to resource URI and (potential) ID
	var resourceEnd = strings.Index(req.URL.Path[1:], "/") + 1
	var resourceName string
	if resourceEnd == -1 {
		resourceName = req.URL.Path[1:]
	} else {
		resourceName = req.URL.Path[1:resourceEnd]
	}
	var id = req.URL.Path[resourceEnd+1:]

	resource, ok := resources[resourceName]
	if !ok {
		fmt.Fprintf(c, "resource %s not found\n", resourceName)
	}

	if len(id) == 0 {
		switch req.Method {
		case "GET":
			// Index
			if resIndex, ok := resource.(Index); ok {
				resIndex.Index(c)
			} else {
				NotImplemented(c)
			}
		case "POST":
			// Create
			if resCreate, ok := resource.(Create); ok {
				resCreate.Create(c, req)
			} else {
				NotImplemented(c)
			}
		case "OPTIONS":
			// automatic options listing
			if resOptions, ok := resource.(Options); ok {
				resOptions.Options(c, id)
			} else {
				NotImplemented(c)
			}
		default:
			NotImplemented(c)
		}
	} else { // ID was passed
		switch req.Method {
		case "GET":
			// Find
			if resFind, ok := resource.(Find); ok {
				resFind.Find(c, id)
			} else {
				NotImplemented(c)
			}
		case "PUT":
			// Update
			if resUpdate, ok := resource.(Update); ok {
				resUpdate.Update(c, id, req)
			} else {
				NotImplemented(c)
			}
		case "DELETE":
			// Delete
			if resDelete, ok := resource.(Delete); ok {
				resDelete.Delete(c, id)
			} else {
				NotImplemented(c)
			}
		case "OPTIONS":
			// automatic options
			if resOptions, ok := resource.(Options); ok {
				resOptions.Options(c, id)
			} else {
				NotImplemented(c)
			}
		default:
			NotImplemented(c)
		}
	}
}

// Add a resource route to http
func Resource(name string, res interface{}) {
	resources[name] = res
	http.Handle("/"+name+"/", http.HandlerFunc(resourceHandler))
}

// Emits a 404 Not Found
func NotFound(c http.ResponseWriter) {
	http.Error(c, "404 Not Found", http.StatusNotFound)
}

// Emits a 501 Not Implemented
func NotImplemented(c http.ResponseWriter) {
	http.Error(c, "501 Not Implemented", http.StatusNotImplemented)
}

// Emits a 201 Created with the URI for the new location
func Created(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "201 Created", http.StatusCreated)
}

// Emits a 200 OK with a location. Used when after a PUT
func Updated(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "200 OK", http.StatusOK)
}

// Emits a bad request with the specified instructions
func BadRequest(c http.ResponseWriter, instructions string) {
	c.WriteHeader(http.StatusBadRequest)
	c.Write([]byte(instructions))
}

// Emits a 204 No Content
func NoContent(c http.ResponseWriter) {
	http.Error(c, "204 No Content", http.StatusNoContent)
}
<commit_msg>Changed server interfaces used for method calls from public to private. See issue #6<commit_after>package rest

import (
	"fmt"
	"http"
	"strings"
)

var resources = make(map[string]interface{})

// Lists all the items in the resource
// GET /resource/
type index interface {
	Index(http.ResponseWriter)
}

// Creates a new resource item
// POST /resource/
type create interface {
	Create(http.ResponseWriter, *http.Request)
}

// Views a resource item
// GET /resource/id
type find interface {
	Find(http.ResponseWriter, string)
}

// PUT /resource/id
type update interface {
	Update(http.ResponseWriter, string, *http.Request)
}

// DELETE /resource/id
type delete interface {
	Delete(http.ResponseWriter, string)
}

// Return options to use the service. If string is nil, then it is the base URL
// OPTIONS /resource/id
// OPTIONS /resource/
type options interface {
	Options(http.ResponseWriter, string)
}

// Generic resource handler
func resourceHandler(c http.ResponseWriter, req *http.Request) {
	// Parse request URI to resource URI and (potential) ID
	var resourceEnd = strings.Index(req.URL.Path[1:], "/") + 1
	var resourceName string
	if resourceEnd == -1 {
		resourceName = req.URL.Path[1:]
	} else {
		resourceName = req.URL.Path[1:resourceEnd]
	}
	var id = req.URL.Path[resourceEnd+1:]

	resource, ok := resources[resourceName]
	if !ok {
		fmt.Fprintf(c, "resource %s not found\n", resourceName)
	}

	if len(id) == 0 {
		switch req.Method {
		case "GET":
			// Index
			if resIndex, ok := resource.(index); ok {
				resIndex.Index(c)
			} else {
				NotImplemented(c)
			}
		case "POST":
			// Create
			if resCreate, ok := resource.(create); ok {
				resCreate.Create(c, req)
			} else {
				NotImplemented(c)
			}
		case "OPTIONS":
			// automatic options listing
			if resOptions, ok := resource.(options); ok {
				resOptions.Options(c, id)
			} else {
				NotImplemented(c)
			}
		default:
			NotImplemented(c)
		}
	} else { // ID was passed
		switch req.Method {
		case "GET":
			// Find
			if resFind, ok := resource.(find); ok {
				resFind.Find(c, id)
			} else {
				NotImplemented(c)
			}
		case "PUT":
			// Update
			if resUpdate, ok := resource.(update); ok {
				resUpdate.Update(c, id, req)
			} else {
				NotImplemented(c)
			}
		case "DELETE":
			// Delete
			if resDelete, ok := resource.(delete); ok {
				resDelete.Delete(c, id)
			} else {
				NotImplemented(c)
			}
		case "OPTIONS":
			// automatic options
			if resOptions, ok := resource.(options); ok {
				resOptions.Options(c, id)
			} else {
				NotImplemented(c)
			}
		default:
			NotImplemented(c)
		}
	}
}

// Add a resource route to http
func Resource(name string, res interface{}) {
	resources[name] = res
	http.Handle("/"+name+"/", http.HandlerFunc(resourceHandler))
}

// Emits a 404 Not Found
func NotFound(c http.ResponseWriter) {
	http.Error(c, "404 Not Found", http.StatusNotFound)
}

// Emits a 501 Not Implemented
func NotImplemented(c http.ResponseWriter) {
	http.Error(c, "501 Not Implemented", http.StatusNotImplemented)
}

// Emits a 201 Created with the URI for the new location
func Created(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "201 Created", http.StatusCreated)
}

// Emits a 200 OK with a location. Used when after a PUT
func Updated(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "200 OK", http.StatusOK)
}

// Emits a bad request with the specified instructions
func BadRequest(c http.ResponseWriter, instructions string) {
	c.WriteHeader(http.StatusBadRequest)
	c.Write([]byte(instructions))
}

// Emits a 204 No Content
func NoContent(c http.ResponseWriter) {
	http.Error(c, "204 No Content", http.StatusNoContent)
}
<|endoftext|>


<commit_before>package rest

import (
	"log"
	"fmt"
	"http"
	"strings"
)

var resources = make(map[string]interface{})

// Generic resource handler
func resourceHandler(c http.ResponseWriter, req *http.Request) {
	uriPath := req.URL.Path

	// try to get resource with full uri path
	resource, ok := resources[uriPath]
	var id string
	if !ok {
		// no resource found, thus check if the path is a resource + ID
		i := strings.LastIndex(uriPath, "/")
		if i == -1 {
			log.Println("Invalid URI-path ", uriPath)
			NotFound(c)
			return
		}
		id = uriPath[i+1:]
		uriPathParent := uriPath[:i]
		resource, ok = resources[uriPathParent]
		if !ok {
			log.Println("Invalid URI-path ", uriPath)
			NotFound(c)
			return
		}
	}

	var hasAccess bool = false
	if accesschecker, ok := resource.(accessChecker); ok {
		hasAccess, _ = accesschecker.HasAccess(req)
	} else {
		// no checker for resource, so always give access
		log.Println("Resource ", uriPath, " has no accessChecker. Giving access …")
		hasAccess = true
	}
	if hasAccess {
		// call method on resource corresponding to the HTTP method
		switch req.Method {
		case "GET":
			if len(id) == 0 {
				// no ID -> Index
				if resIndex, ok := resource.(indexer); ok {
					resIndex.Index(c)
				} else {
					NotImplemented(c)
				}
			} else {
				// Find by ID
				if resFind, ok := resource.(finder); ok {
					resFind.Find(c, id)
				} else {
					NotImplemented(c)
				}
			}
		case "POST":
			// Create
			if resCreate, ok := resource.(creater); ok {
				resCreate.Create(c, req)
			} else {
				NotImplemented(c)
			}
		case "PUT":
			// Update
			if resUpdate, ok := resource.(updater); ok {
				resUpdate.Update(c, id, req)
			} else {
				NotImplemented(c)
			}
		case "DELETE":
			// Delete
			if resDelete, ok := resource.(deleter); ok {
				resDelete.Delete(c, id)
			} else {
				NotImplemented(c)
			}
		case "OPTIONS":
			// List usable HTTP methods
			if resOptions, ok := resource.(optioner); ok {
				resOptions.Options(c, id)
			} else {
				NotImplemented(c)
			}
		default:
			NotImplemented(c)
		}
	}
	return
}

// Add a resource route
func Resource(path string, res interface{}) {
	// check and warn for missing leading slash
	if fmt.Sprint(path[0]) == "/" {
		log.Println("Resource was added with a path no leading slash. Did you mean to add /", path, " ?")
	}
	// add potentially missing trailing slash (resource always ends with slash)
	pathLen := len(path)
	if len(path) > 1 && path[pathLen-1:pathLen] != "/" {
		log.Println("adding trailing slash to ", path)
		path = fmt.Sprint(path, "/")
	}
	log.Println("Adding resource ", *res, " at ", path)
	resources[path] = res
	http.Handle(path, http.HandlerFunc(resourceHandler))
}

// Emits a 404 Not Found
func NotFound(c http.ResponseWriter) {
	http.Error(c, "404 Not Found", http.StatusNotFound)
}

// Emits a 501 Not Implemented
func NotImplemented(c http.ResponseWriter) {
	http.Error(c, "501 Not Implemented", http.StatusNotImplemented)
}

// Emits a 201 Created with the URI for the new location
func Created(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "201 Created", http.StatusCreated)
}

// Emits a 200 OK with a location. Used when after a PUT
func Updated(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "200 OK", http.StatusOK)
}

// Emits a bad request with the specified instructions
func BadRequest(c http.ResponseWriter, instructions string) {
	c.WriteHeader(http.StatusBadRequest)
	c.Write([]byte(instructions))
}

// Emits a 204 No Content
func NoContent(c http.ResponseWriter) {
	http.Error(c, "204 No Content", http.StatusNoContent)
}
<commit_msg>fix log call; fix compilation<commit_after>package rest

import (
	"log"
	"fmt"
	"http"
	"strings"
)

var resources = make(map[string]interface{})

// Generic resource handler
func resourceHandler(c http.ResponseWriter, req *http.Request) {
	uriPath := req.URL.Path

	// try to get resource with full uri path
	resource, ok := resources[uriPath]
	var id string
	if !ok {
		// no resource found, thus check if the path is a resource + ID
		i := strings.LastIndex(uriPath, "/")
		if i == -1 {
			log.Println("Invalid URI-path ", uriPath)
			NotFound(c)
			return
		}
		id = uriPath[i+1:]
		uriPathParent := uriPath[:i]
		resource, ok = resources[uriPathParent]
		if !ok {
			log.Println("Invalid URI-path ", uriPath)
			NotFound(c)
			return
		}
	}

	var hasAccess bool = false
	if accesschecker, ok := resource.(accessChecker); ok {
		hasAccess, _ = accesschecker.HasAccess(req)
	} else {
		// no checker for resource, so always give access
		log.Println("Resource ", uriPath, " has no accessChecker. Giving access …")
		hasAccess = true
	}
	if hasAccess {
		// call method on resource corresponding to the HTTP method
		switch req.Method {
		case "GET":
			if len(id) == 0 {
				// no ID -> Index
				if resIndex, ok := resource.(indexer); ok {
					resIndex.Index(c)
				} else {
					NotImplemented(c)
				}
			} else {
				// Find by ID
				if resFind, ok := resource.(finder); ok {
					resFind.Find(c, id)
				} else {
					NotImplemented(c)
				}
			}
		case "POST":
			// Create
			if resCreate, ok := resource.(creater); ok {
				resCreate.Create(c, req)
			} else {
				NotImplemented(c)
			}
		case "PUT":
			// Update
			if resUpdate, ok := resource.(updater); ok {
				resUpdate.Update(c, id, req)
			} else {
				NotImplemented(c)
			}
		case "DELETE":
			// Delete
			if resDelete, ok := resource.(deleter); ok {
				resDelete.Delete(c, id)
			} else {
				NotImplemented(c)
			}
		case "OPTIONS":
			// List usable HTTP methods
			if resOptions, ok := resource.(optioner); ok {
				resOptions.Options(c, id)
			} else {
				NotImplemented(c)
			}
		default:
			NotImplemented(c)
		}
	}
	return
}

// Add a resource route
func Resource(path string, res interface{}) {
	// check and warn for missing leading slash
	if fmt.Sprint(path[0]) == "/" {
		log.Println("Resource was added with a path no leading slash. Did you mean to add /", path, " ?")
	}
	// add potentially missing trailing slash (resource always ends with slash)
	pathLen := len(path)
	if len(path) > 1 && path[pathLen-1:pathLen] != "/" {
		log.Println("adding trailing slash to ", path)
		path = fmt.Sprint(path, "/")
	}
	log.Println("Adding resource ", res, " at ", path)
	resources[path] = res
	http.Handle(path, http.HandlerFunc(resourceHandler))
}

// Emits a 404 Not Found
func NotFound(c http.ResponseWriter) {
	http.Error(c, "404 Not Found", http.StatusNotFound)
}

// Emits a 501 Not Implemented
func NotImplemented(c http.ResponseWriter) {
	http.Error(c, "501 Not Implemented", http.StatusNotImplemented)
}

// Emits a 201 Created with the URI for the new location
func Created(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "201 Created", http.StatusCreated)
}

// Emits a 200 OK with a location. Used when after a PUT
func Updated(c http.ResponseWriter, location string) {
	c.Header().Set("Location", location)
	http.Error(c, "200 OK", http.StatusOK)
}

// Emits a bad request with the specified instructions
func BadRequest(c http.ResponseWriter, instructions string) {
	c.WriteHeader(http.StatusBadRequest)
	c.Write([]byte(instructions))
}

// Emits a 204 No Content
func NoContent(c http.ResponseWriter) {
	http.Error(c, "204 No Content", http.StatusNoContent)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"

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

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

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

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

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

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

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

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

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

	router.To("GET,HEAD", "/test", func(c *routing.Context) error {
		c.Abort()  // skip all other middlewares/handlers
		return c.Write("test3")
	})

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

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

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

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

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

	// wire up more resource APIs here

	return router
}
<commit_msg>change in local<commit_after>package main

import (
	"fmt"
	"net/http"

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

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

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

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

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

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

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

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

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

	router.To("GET,HEAD", "/test", func(c *routing.Context) error {
		c.Abort()  // skip all other middlewares/handlers
		return c.Write("test4")
	})

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

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

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

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

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

	// wire up more resource APIs here

	return router
}
<|endoftext|>


<commit_before>package gunfish

import (
	"encoding/json"
	"fmt"
	"math"
	"net"
	"net/http"
	"os"
	"os/signal"
	"reflect"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/fukata/golang-stats-api-handler"
	"github.com/kayac/Gunfish/apns"
	"github.com/kayac/Gunfish/config"
	"github.com/kayac/Gunfish/fcm"
	"github.com/lestrrat/go-server-starter/listener"
	"github.com/shogo82148/go-gracedown"
	"github.com/sirupsen/logrus"
	"golang.org/x/net/netutil"
)

// Provider defines Gunfish httpHandler and has a state
// of queue which is shared by the supervisor.
type Provider struct {
	Sup Supervisor
}

// ResponseHandler provides you to implement handling on success or on error response from apns.
// Therefore, you can specifies hook command which is set at toml file.
type ResponseHandler interface {
	OnResponse(Result)
	HookCmd() string
}

// DefaultResponseHandler is the default ResponseHandler if not specified.
type DefaultResponseHandler struct {
	Hook string
}

// OnResponse is performed when to receive result from APNs or FCM.
func (rh DefaultResponseHandler) OnResponse(result Result) {
}

// HookCmd returns hook command to execute after getting response from APNS
// only when to get error response.
func (rh DefaultResponseHandler) HookCmd() string {
	return rh.Hook
}

// StartServer starts an apns provider server on http.
func StartServer(conf config.Config, env Environment) {
	// Initialize DefaultResponseHandler if response handlers are not defined.
	if successResponseHandler == nil {
		InitSuccessResponseHandler(DefaultResponseHandler{})
	}

	if errorResponseHandler == nil {
		InitErrorResponseHandler(DefaultResponseHandler{Hook: conf.Provider.ErrorHook})
	}

	// Init Provider
	srvStats = NewStats(conf)
	prov := &Provider{}

	srvStats.DebugPort = conf.Provider.DebugPort
	LogWithFields(logrus.Fields{
		"type": "provider",
	}).Infof("Size of POST request queue is %d", conf.Provider.QueueSize)

	// Set APNS host addr according of environment
	if env == Production {
		conf.Apns.Host = ProdServer
	} else if env == Development {
		conf.Apns.Host = DevServer
	} else if env == Test {
		conf.Apns.Host = MockServer
	}

	// start supervisor
	sup, err := StartSupervisor(&conf)
	if err != nil {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Fatalf("Failed to start Gunfish: %s", err.Error())
	}
	prov.Sup = sup

	LogWithFields(logrus.Fields{
		"type": "supervisor",
	}).Infof("Starts supervisor at %s", Production.String())

	// StartServer listener
	listeners, err := listener.ListenAll()
	if err != nil {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Infof("%s. If you want graceful to restart Gunfish, you should use 'starter_server' (github.com/lestrrat/go-server-starter).", err)
	}

	// Start gunfish provider server
	var lis net.Listener
	if err == listener.ErrNoListeningTarget {
		// Fallback if not running under ServerStarter
		service := fmt.Sprintf(":%d", conf.Provider.Port)
		lis, err = net.Listen("tcp", service)
		if err != nil {
			LogWithFields(logrus.Fields{
				"type": "provider",
			}).Error(err)
			sup.Shutdown()
			return
		}
	} else {
		if l, ok := listeners[0].Addr().(*net.TCPAddr); ok && l.Port != conf.Provider.Port {
			LogWithFields(logrus.Fields{
				"type": "provider",
			}).Infof("'start_server' starts on :%d", l.Port)
		}
		// Starts Gunfish under ServerStarter.
		conf.Provider.Port = listeners[0].Addr().(*net.TCPAddr).Port
		lis = listeners[0]
	}

	// If many connections establishs between Gunfish provider and your application,
	// Gunfish provider would be overload, and decrease performance.
	llis := netutil.LimitListener(lis, conf.Provider.MaxConnections)

	// signal handling
	go startSignalReciever(lis)

	// Start Gunfish provider
	LogWithFields(logrus.Fields{
		"type": "provider",
	}).Infof("Starts provider on :%d ...", conf.Provider.Port)

	mux := http.NewServeMux()
	if conf.Apns.Enabled {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Infof("Enable endpoint /push/apns")
		mux.HandleFunc("/push/apns", prov.PushAPNsHandler())
	}
	if conf.FCM.Enabled {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Infof("Enable endpoint /push/fcm")
		mux.HandleFunc("/push/fcm", prov.PushFCMHandler())
	}
	mux.HandleFunc("/stats/app", prov.StatsHandler())
	mux.HandleFunc("/stats/profile", stats_api.Handler)

	if err := gracedown.Serve(llis, mux); err != nil {
		LogWithFields(logrus.Fields{}).Error(err)
	}

	// if Gunfish server stop, Close queue
	LogWithFields(logrus.Fields{
		"type": "provider",
	}).Info("Stopping server")

	// if Gunfish server stop, Close queue
	sup.Shutdown()
}

func (prov *Provider) PushAPNsHandler() http.HandlerFunc {
	return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		atomic.AddInt64(&(srvStats.RequestCount), 1)

		// Method Not Alllowed
		if err := validateMethod(res, req); err != nil {
			logrus.Warn(err)
			return
		}

		// Parse request body
		c := req.Header.Get("Content-Type")
		var ps []PostedData
		switch c {
		case ApplicationXW3FormURLEncoded:
			body := req.FormValue("json")
			if err := json.Unmarshal([]byte(body), &ps); err != nil {
				LogWithFields(logrus.Fields{}).Warnf("%s: %s", err, body)
				res.WriteHeader(http.StatusBadRequest)
				fmt.Fprintf(res, `{"reason": "%s"}`, err.Error())
				return
			}
		case ApplicationJSON:
			decoder := json.NewDecoder(req.Body)
			if err := decoder.Decode(&ps); err != nil {
				LogWithFields(logrus.Fields{}).Warnf("%s: %v", err, ps)
				res.WriteHeader(http.StatusBadRequest)
				fmt.Fprintf(res, `{"reason": "%s"}`, err.Error())
				return
			}
		default:
			// Unsupported Media Type
			logrus.Warnf("Unsupported Media Type: %s", c)
			res.WriteHeader(http.StatusUnsupportedMediaType)
			fmt.Fprintf(res, `{"reason":"Unsupported Media Type"}`)
			return
		}

		// Validates posted data
		if err := validatePostedData(ps); err != nil {
			res.WriteHeader(http.StatusBadRequest)
			fmt.Fprintf(res, `{"reason":"%s"}`, err.Error())
			return
		}

		// Create requests
		reqs := make([]Request, len(ps))
		for i, p := range ps {
			switch t := p.Payload.Alert.(type) {
			case map[string]interface{}:
				var alert apns.Alert
				mapToAlert(t, &alert)
				p.Payload.Alert = alert
			}

			req := Request{
				Notification: apns.Notification{
					Header:  p.Header,
					Token:   p.Token,
					Payload: p.Payload,
				},
				Tries: 0,
			}

			reqs[i] = req
		}

		// enqueues one request into supervisor's queue.
		if err := prov.Sup.EnqueueClientRequest(&reqs); err != nil {
			setRetryAfter(res, req, err.Error())
			return
		}

		// success
		res.WriteHeader(http.StatusOK)
		fmt.Fprint(res, "{\"result\": \"ok\"}")
	})
}

func (prov *Provider) PushFCMHandler() http.HandlerFunc {
	return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		atomic.AddInt64(&(srvStats.RequestCount), 1)

		// Method Not Alllowed
		if err := validateMethod(res, req); err != nil {
			logrus.Warn(err)
			return
		}

		// only Content-Type application/json
		c := req.Header.Get("Content-Type")
		if c != ApplicationJSON {
			// Unsupported Media Type
			logrus.Warnf("Unsupported Media Type: %s", c)
			res.WriteHeader(http.StatusUnsupportedMediaType)
			fmt.Fprintf(res, `{"reason":"Unsupported Media Type"}`)
			return
		}

		// create request for fcm
		var payload fcm.Payload
		dec := json.NewDecoder(req.Body)
		if err := dec.Decode(&payload); err != nil {
			logrus.Warnf("Internal Server Error: %s", err)
			res.WriteHeader(http.StatusInternalServerError)
			fmt.Fprintf(res, "{\"reason\":\"%s\"}", err.Error())
			return
		}
		grs := []Request{
			Request{
				Notification: payload,
				Tries:        0,
			},
		}

		// enqueues one request into supervisor's queue.
		if err := prov.Sup.EnqueueClientRequest(&grs); err != nil {
			setRetryAfter(res, req, err.Error())
			return
		}

		// success
		res.WriteHeader(http.StatusOK)
		fmt.Fprint(res, "{\"result\": \"ok\"}")
	})
}

func validateMethod(res http.ResponseWriter, req *http.Request) error {
	if req.Method != "POST" {
		res.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(res, "{\"reason\":\"Method Not Allowed.\"}")
		return fmt.Errorf("Method Not Allowed: %s", req.Method)
	}
	return nil
}

func setRetryAfter(res http.ResponseWriter, req *http.Request, reason string) {
	now := time.Now().Unix()
	atomic.StoreInt64(&(srvStats.ServiceUnavailableAt), now)
	updateRetryAfterStat(now - srvStats.ServiceUnavailableAt)
	// Retry-After is set seconds
	res.Header().Set("Retry-After", fmt.Sprintf("%d", srvStats.RetryAfter))
	res.WriteHeader(http.StatusServiceUnavailable)
	fmt.Fprintf(res, fmt.Sprintf(`{"reason":"%s"}`, reason))
}

func (prov *Provider) StatsHandler() http.HandlerFunc {
	return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if ok := validateStatsHandler(res, req); ok != true {
			return
		}

		wqs := 0
		for _, w := range prov.Sup.workers {
			wqs += len(w.queue)
		}

		atomic.StoreInt64(&(srvStats.QueueSize), int64(len(prov.Sup.queue)))
		atomic.StoreInt64(&(srvStats.RetryQueueSize), int64(len(prov.Sup.retryq)))
		atomic.StoreInt64(&(srvStats.WorkersQueueSize), int64(wqs))
		atomic.StoreInt64(&(srvStats.CommandQueueSize), int64(len(prov.Sup.cmdq)))
		res.WriteHeader(http.StatusOK)
		encoder := json.NewEncoder(res)
		err := encoder.Encode(srvStats.GetStats())
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			fmt.Fprintf(res, `{"reason":"Internal Server Error"}`)
			return
		}
	})
}

func validatePostedData(ps []PostedData) error {
	if len(ps) == 0 {
		return fmt.Errorf("PostedData must not be empty: %v", ps)
	}

	if len(ps) > config.MaxRequestSize {
		return fmt.Errorf("PostedData was too long. Be less than %d: %v", config.MaxRequestSize, len(ps))
	}

	for _, p := range ps {
		if p.Payload.APS == nil || p.Token == "" {
			return fmt.Errorf("Payload format was malformed: %v", p.Payload)
		}
	}
	return nil
}

func validateStatsHandler(res http.ResponseWriter, req *http.Request) bool {
	// Method Not Alllowed
	if req.Method != "GET" {
		res.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(res, `{"reason":"Method Not Allowed."}`)
		logrus.Warnf("Method Not Allowed: %s", req.Method)
		return false
	}

	return true
}

func mapToAlert(mapVal map[string]interface{}, alert *apns.Alert) {
	a := reflect.ValueOf(alert).Elem()
	for k, v := range mapVal {
		newk, ok := AlertKeyToField[k]
		if ok == true {
			a.FieldByName(newk).Set(reflect.ValueOf(v))
		} else {
			logrus.Warnf("\"%s\" is not supported key for Alert struct.", k)
		}
	}
}

func startSignalReciever(lis net.Listener) {
	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, syscall.SIGTERM)
	s := <-sigChan
	switch s {
	case syscall.SIGHUP:
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Info("Gunfish recieved SIGHUP signal.")
		gracedown.Close()
	case syscall.SIGTERM:
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Info("Gunfish recieved SIGTERM signal.")
		gracedown.Close()
	case syscall.SIGINT:
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Info("Gunfish recieved SIGINT signal. Stopping server now...")
		gracedown.Close()
	}
}

func updateRetryAfterStat(x int64) {
	var nxtRA int64
	if x > int64(ResetRetryAfterSecond/time.Second) {
		nxtRA = int64(RetryAfterSecond / time.Second)
	} else {
		a := int64(math.Log(float64(10/(x+1) + 1)))
		if srvStats.RetryAfter+2*a < int64(ResetRetryAfterSecond/time.Second) {
			nxtRA = srvStats.RetryAfter + 2*a
		} else {
			nxtRA = int64(ResetRetryAfterSecond / time.Second)
		}
	}

	atomic.StoreInt64(&(srvStats.RetryAfter), nxtRA)
}
<commit_msg>remove github.com/shogo82148/go-gracedown and lestrrat/go-server-starter.<commit_after>package gunfish

import (
	"context"
	"encoding/json"
	"fmt"
	"math"
	"net"
	"net/http"
	"os"
	"os/signal"
	"reflect"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/fukata/golang-stats-api-handler"
	"github.com/kayac/Gunfish/apns"
	"github.com/kayac/Gunfish/config"
	"github.com/kayac/Gunfish/fcm"
	"github.com/lestrrat-go/server-starter/listener"
	"github.com/sirupsen/logrus"
	"golang.org/x/net/netutil"
)

// Provider defines Gunfish httpHandler and has a state
// of queue which is shared by the supervisor.
type Provider struct {
	Sup Supervisor
}

// ResponseHandler provides you to implement handling on success or on error response from apns.
// Therefore, you can specifies hook command which is set at toml file.
type ResponseHandler interface {
	OnResponse(Result)
	HookCmd() string
}

// DefaultResponseHandler is the default ResponseHandler if not specified.
type DefaultResponseHandler struct {
	Hook string
}

// OnResponse is performed when to receive result from APNs or FCM.
func (rh DefaultResponseHandler) OnResponse(result Result) {
}

// HookCmd returns hook command to execute after getting response from APNS
// only when to get error response.
func (rh DefaultResponseHandler) HookCmd() string {
	return rh.Hook
}

// StartServer starts an apns provider server on http.
func StartServer(conf config.Config, env Environment) {
	// Initialize DefaultResponseHandler if response handlers are not defined.
	if successResponseHandler == nil {
		InitSuccessResponseHandler(DefaultResponseHandler{})
	}

	if errorResponseHandler == nil {
		InitErrorResponseHandler(DefaultResponseHandler{Hook: conf.Provider.ErrorHook})
	}

	// Init Provider
	srvStats = NewStats(conf)
	prov := &Provider{}

	srvStats.DebugPort = conf.Provider.DebugPort
	LogWithFields(logrus.Fields{
		"type": "provider",
	}).Infof("Size of POST request queue is %d", conf.Provider.QueueSize)

	// Set APNS host addr according of environment
	if env == Production {
		conf.Apns.Host = ProdServer
	} else if env == Development {
		conf.Apns.Host = DevServer
	} else if env == Test {
		conf.Apns.Host = MockServer
	}

	// start supervisor
	sup, err := StartSupervisor(&conf)
	if err != nil {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Fatalf("Failed to start Gunfish: %s", err.Error())
	}
	prov.Sup = sup

	LogWithFields(logrus.Fields{
		"type": "supervisor",
	}).Infof("Starts supervisor at %s", Production.String())

	// StartServer listener
	listeners, err := listener.ListenAll()
	if err != nil {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Infof("%s. If you want graceful to restart Gunfish, you should use 'starter_server' (github.com/lestrrat/go-server-starter).", err)
	}

	// Start gunfish provider server
	var lis net.Listener
	if err == listener.ErrNoListeningTarget {
		// Fallback if not running under ServerStarter
		service := fmt.Sprintf(":%d", conf.Provider.Port)
		lis, err = net.Listen("tcp", service)
		if err != nil {
			LogWithFields(logrus.Fields{
				"type": "provider",
			}).Error(err)
			sup.Shutdown()
			return
		}
	} else {
		if l, ok := listeners[0].Addr().(*net.TCPAddr); ok && l.Port != conf.Provider.Port {
			LogWithFields(logrus.Fields{
				"type": "provider",
			}).Infof("'start_server' starts on :%d", l.Port)
		}
		// Starts Gunfish under ServerStarter.
		conf.Provider.Port = listeners[0].Addr().(*net.TCPAddr).Port
		lis = listeners[0]
	}

	// If many connections establishs between Gunfish provider and your application,
	// Gunfish provider would be overload, and decrease performance.
	llis := netutil.LimitListener(lis, conf.Provider.MaxConnections)

	// Start Gunfish provider
	LogWithFields(logrus.Fields{
		"type": "provider",
	}).Infof("Starts provider on :%d ...", conf.Provider.Port)

	mux := http.NewServeMux()
	if conf.Apns.Enabled {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Infof("Enable endpoint /push/apns")
		mux.HandleFunc("/push/apns", prov.PushAPNsHandler())
	}
	if conf.FCM.Enabled {
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Infof("Enable endpoint /push/fcm")
		mux.HandleFunc("/push/fcm", prov.PushFCMHandler())
	}
	mux.HandleFunc("/stats/app", prov.StatsHandler())
	mux.HandleFunc("/stats/profile", stats_api.Handler)

	srv := &http.Server{Handler: mux}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		if err := srv.Serve(llis); err != nil {
			LogWithFields(logrus.Fields{}).Error(err)
		}
		wg.Done()
	}()

	// signal handling
	wg.Add(1)
	go startSignalReciever(&wg, srv)

	// wait for server shutdown complete
	wg.Wait()

	// if Gunfish server stop, Close queue
	LogWithFields(logrus.Fields{
		"type": "provider",
	}).Info("Stopping server")

	// if Gunfish server stop, Close queue
	sup.Shutdown()
}

func (prov *Provider) PushAPNsHandler() http.HandlerFunc {
	return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		atomic.AddInt64(&(srvStats.RequestCount), 1)

		// Method Not Alllowed
		if err := validateMethod(res, req); err != nil {
			logrus.Warn(err)
			return
		}

		// Parse request body
		c := req.Header.Get("Content-Type")
		var ps []PostedData
		switch c {
		case ApplicationXW3FormURLEncoded:
			body := req.FormValue("json")
			if err := json.Unmarshal([]byte(body), &ps); err != nil {
				LogWithFields(logrus.Fields{}).Warnf("%s: %s", err, body)
				res.WriteHeader(http.StatusBadRequest)
				fmt.Fprintf(res, `{"reason": "%s"}`, err.Error())
				return
			}
		case ApplicationJSON:
			decoder := json.NewDecoder(req.Body)
			if err := decoder.Decode(&ps); err != nil {
				LogWithFields(logrus.Fields{}).Warnf("%s: %v", err, ps)
				res.WriteHeader(http.StatusBadRequest)
				fmt.Fprintf(res, `{"reason": "%s"}`, err.Error())
				return
			}
		default:
			// Unsupported Media Type
			logrus.Warnf("Unsupported Media Type: %s", c)
			res.WriteHeader(http.StatusUnsupportedMediaType)
			fmt.Fprintf(res, `{"reason":"Unsupported Media Type"}`)
			return
		}

		// Validates posted data
		if err := validatePostedData(ps); err != nil {
			res.WriteHeader(http.StatusBadRequest)
			fmt.Fprintf(res, `{"reason":"%s"}`, err.Error())
			return
		}

		// Create requests
		reqs := make([]Request, len(ps))
		for i, p := range ps {
			switch t := p.Payload.Alert.(type) {
			case map[string]interface{}:
				var alert apns.Alert
				mapToAlert(t, &alert)
				p.Payload.Alert = alert
			}

			req := Request{
				Notification: apns.Notification{
					Header:  p.Header,
					Token:   p.Token,
					Payload: p.Payload,
				},
				Tries: 0,
			}

			reqs[i] = req
		}

		// enqueues one request into supervisor's queue.
		if err := prov.Sup.EnqueueClientRequest(&reqs); err != nil {
			setRetryAfter(res, req, err.Error())
			return
		}

		// success
		res.WriteHeader(http.StatusOK)
		fmt.Fprint(res, "{\"result\": \"ok\"}")
	})
}

func (prov *Provider) PushFCMHandler() http.HandlerFunc {
	return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		atomic.AddInt64(&(srvStats.RequestCount), 1)

		// Method Not Alllowed
		if err := validateMethod(res, req); err != nil {
			logrus.Warn(err)
			return
		}

		// only Content-Type application/json
		c := req.Header.Get("Content-Type")
		if c != ApplicationJSON {
			// Unsupported Media Type
			logrus.Warnf("Unsupported Media Type: %s", c)
			res.WriteHeader(http.StatusUnsupportedMediaType)
			fmt.Fprintf(res, `{"reason":"Unsupported Media Type"}`)
			return
		}

		// create request for fcm
		var payload fcm.Payload
		dec := json.NewDecoder(req.Body)
		if err := dec.Decode(&payload); err != nil {
			logrus.Warnf("Internal Server Error: %s", err)
			res.WriteHeader(http.StatusInternalServerError)
			fmt.Fprintf(res, "{\"reason\":\"%s\"}", err.Error())
			return
		}
		grs := []Request{
			Request{
				Notification: payload,
				Tries:        0,
			},
		}

		// enqueues one request into supervisor's queue.
		if err := prov.Sup.EnqueueClientRequest(&grs); err != nil {
			setRetryAfter(res, req, err.Error())
			return
		}

		// success
		res.WriteHeader(http.StatusOK)
		fmt.Fprint(res, "{\"result\": \"ok\"}")
	})
}

func validateMethod(res http.ResponseWriter, req *http.Request) error {
	if req.Method != "POST" {
		res.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(res, "{\"reason\":\"Method Not Allowed.\"}")
		return fmt.Errorf("Method Not Allowed: %s", req.Method)
	}
	return nil
}

func setRetryAfter(res http.ResponseWriter, req *http.Request, reason string) {
	now := time.Now().Unix()
	atomic.StoreInt64(&(srvStats.ServiceUnavailableAt), now)
	updateRetryAfterStat(now - srvStats.ServiceUnavailableAt)
	// Retry-After is set seconds
	res.Header().Set("Retry-After", fmt.Sprintf("%d", srvStats.RetryAfter))
	res.WriteHeader(http.StatusServiceUnavailable)
	fmt.Fprintf(res, fmt.Sprintf(`{"reason":"%s"}`, reason))
}

func (prov *Provider) StatsHandler() http.HandlerFunc {
	return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if ok := validateStatsHandler(res, req); ok != true {
			return
		}

		wqs := 0
		for _, w := range prov.Sup.workers {
			wqs += len(w.queue)
		}

		atomic.StoreInt64(&(srvStats.QueueSize), int64(len(prov.Sup.queue)))
		atomic.StoreInt64(&(srvStats.RetryQueueSize), int64(len(prov.Sup.retryq)))
		atomic.StoreInt64(&(srvStats.WorkersQueueSize), int64(wqs))
		atomic.StoreInt64(&(srvStats.CommandQueueSize), int64(len(prov.Sup.cmdq)))
		res.WriteHeader(http.StatusOK)
		encoder := json.NewEncoder(res)
		err := encoder.Encode(srvStats.GetStats())
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			fmt.Fprintf(res, `{"reason":"Internal Server Error"}`)
			return
		}
	})
}

func validatePostedData(ps []PostedData) error {
	if len(ps) == 0 {
		return fmt.Errorf("PostedData must not be empty: %v", ps)
	}

	if len(ps) > config.MaxRequestSize {
		return fmt.Errorf("PostedData was too long. Be less than %d: %v", config.MaxRequestSize, len(ps))
	}

	for _, p := range ps {
		if p.Payload.APS == nil || p.Token == "" {
			return fmt.Errorf("Payload format was malformed: %v", p.Payload)
		}
	}
	return nil
}

func validateStatsHandler(res http.ResponseWriter, req *http.Request) bool {
	// Method Not Alllowed
	if req.Method != "GET" {
		res.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(res, `{"reason":"Method Not Allowed."}`)
		logrus.Warnf("Method Not Allowed: %s", req.Method)
		return false
	}

	return true
}

func mapToAlert(mapVal map[string]interface{}, alert *apns.Alert) {
	a := reflect.ValueOf(alert).Elem()
	for k, v := range mapVal {
		newk, ok := AlertKeyToField[k]
		if ok == true {
			a.FieldByName(newk).Set(reflect.ValueOf(v))
		} else {
			logrus.Warnf("\"%s\" is not supported key for Alert struct.", k)
		}
	}
}

func startSignalReciever(wg *sync.WaitGroup, srv *http.Server) {
	defer wg.Done()

	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT)
	s := <-sigChan
	switch s {
	case syscall.SIGHUP:
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Info("Gunfish recieved SIGHUP signal.")
		srv.Shutdown(context.Background())
	case syscall.SIGTERM:
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Info("Gunfish recieved SIGTERM signal.")
		srv.Shutdown(context.Background())
	case syscall.SIGINT:
		LogWithFields(logrus.Fields{
			"type": "provider",
		}).Info("Gunfish recieved SIGINT signal. Stopping server now...")
		srv.Shutdown(context.Background())
	}
}

func updateRetryAfterStat(x int64) {
	var nxtRA int64
	if x > int64(ResetRetryAfterSecond/time.Second) {
		nxtRA = int64(RetryAfterSecond / time.Second)
	} else {
		a := int64(math.Log(float64(10/(x+1) + 1)))
		if srvStats.RetryAfter+2*a < int64(ResetRetryAfterSecond/time.Second) {
			nxtRA = srvStats.RetryAfter + 2*a
		} else {
			nxtRA = int64(ResetRetryAfterSecond / time.Second)
		}
	}

	atomic.StoreInt64(&(srvStats.RetryAfter), nxtRA)
}
<|endoftext|>


<commit_before>package main

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

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

// Big picture:

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

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

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

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

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

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

var Certificates CertificateCollection

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

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

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

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

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

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

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

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

	//add newly created cert to the file.

	certs, ok := c[params.Username]

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

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

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

	check(err)

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

}

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

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

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

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

// curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"Username": "shantanu", "Permissions": ["permit-pty"], "PrivateKeyPath": "/Users/shantanu/.ssh/users_ca","Key": "/Users/shantanu/.ssh/id_rsa.pub" } '  http://localhost:8080/sign/
<commit_msg>reflecting changes made to the discovery json format<commit_after>package main

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

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

// Big picture:

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

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

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

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

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

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

var Certificates CertificateCollection

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

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

	keyToSignBytes := []byte(params.Key)
	keyToSign, comment, _, _, err := ssh.ParseAuthorizedKey(keyToSignBytes)
	check(err)

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

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

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

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

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

	//add newly created cert to the file.

	certs, ok := c[params.User]

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

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

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

	check(err)

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

}

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

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

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

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

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


<commit_before>package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"sync"
)

var errsNotDir = errors.New("Given path is not a dir")
var validGhEvent = regexp.MustCompile(`^[a-z_]{1,30}$`)

// HookServer implements net/http.Handler
type HookServer struct {
	RootDir string
	secret  string
	sync.Mutex
}

// NewHookServer instantiates a new HookServer with some basic validation
// on the root directory
func NewHookServer(rootdir string, secret string) (*HookServer, error) {
	f, err := os.Open(rootdir)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

	if !fi.IsDir() {
		return nil, errsNotDir
	}

	return &HookServer{
		RootDir: rootdir,
		secret:  secret,
	}, nil
}

func (h *HookServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ghEvent := r.Header.Get("X-Github-Event")

	if !validGhEvent.MatchString(ghEvent) {
		http.Error(w, "Request requires valid X-Github-Event", http.StatusBadRequest)
		return
	}

	if ghEvent == "ping" {
		fmt.Fprintln(w, "pong")
		return
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Println(err)
		return
	}
	buff := bytes.NewReader(b)

	if h.secret != "" {
		xSig := r.Header.Get("X-Hub-Signature")

		if xSig == "" {
			http.Error(w, "Missing required X-Hub-Signature for HMAC verification", http.StatusForbidden)
			log.Println("missing X-Hub-Signature")
			return
		}

		hash := hmac.New(sha1.New, []byte(h.secret))
		hash.Write(b)

		ehash := hash.Sum(nil)
		esig := "sha1=" + hex.EncodeToString(ehash)
		if !hmac.Equal([]byte(esig), []byte(xSig)) {
			http.Error(w, "HMAC verification failed", http.StatusForbidden)
			log.Println("HMAC verification failed")
			return
		}
	}

	basicHook := &HookJSON{}

	decoder := json.NewDecoder(buff)
	err = decoder.Decode(basicHook)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		log.Println(err)
		return
	}

	login := basicHook.Repository.Owner.GetLogin()
	repo := basicHook.Repository.Name

	fmt.Fprintf(w, "%s/%s", login, repo)

	if repo == "" || login == "" {
		http.Error(w, "Failed parsing JSON HTTP Body", http.StatusBadRequest)
		log.Println(err)
		return
	}

	hook := HookExec{
		RootDir: h.RootDir,

		Owner: login,
		Repo:  repo,

		Event: ghEvent,
		Data:  buff,

		HookServer: h,
	}

	go hook.Exec()
}

// HookUserJSON exists because some hooks use Login, some use Name
// - it's horribly inconsistant
type HookUserJSON struct {
	Login string `json:"login"`
	Name  string `json:"name"`
}

// GetLogin is used to get the login from the data github decided to pass today
func (h *HookUserJSON) GetLogin() string {
	if h.Login != "" {
		return h.Login
	}

	return h.Name
}

// HookJSON represents the minimum body we need to parse
type HookJSON struct {
	Repository struct {
		Name  string       `json:"name"`
		Owner HookUserJSON `json:"owner"`
	} `json:"repository"`
	Sender HookUserJSON `json:"sender"`
}
<commit_msg>spacing<commit_after>package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"sync"
)

var errsNotDir = errors.New("Given path is not a dir")
var validGhEvent = regexp.MustCompile(`^[a-z_]{1,30}$`)

// HookServer implements net/http.Handler
type HookServer struct {
	RootDir string
	secret  string
	sync.Mutex
}

// NewHookServer instantiates a new HookServer with some basic validation
// on the root directory
func NewHookServer(rootdir string, secret string) (*HookServer, error) {
	f, err := os.Open(rootdir)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

	if !fi.IsDir() {
		return nil, errsNotDir
	}

	return &HookServer{
		RootDir: rootdir,
		secret:  secret,
	}, nil
}

func (h *HookServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ghEvent := r.Header.Get("X-Github-Event")

	if !validGhEvent.MatchString(ghEvent) {
		http.Error(w, "Request requires valid X-Github-Event", http.StatusBadRequest)
		return
	}

	if ghEvent == "ping" {
		fmt.Fprintln(w, "pong")
		return
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Println(err)
		return
	}
	buff := bytes.NewReader(b)

	if h.secret != "" {
		xSig := r.Header.Get("X-Hub-Signature")

		if xSig == "" {
			http.Error(w, "Missing required X-Hub-Signature for HMAC verification", http.StatusForbidden)
			log.Println("missing X-Hub-Signature")
			return
		}

		hash := hmac.New(sha1.New, []byte(h.secret))
		hash.Write(b)

		ehash := hash.Sum(nil)
		esig := "sha1=" + hex.EncodeToString(ehash)

		if !hmac.Equal([]byte(esig), []byte(xSig)) {
			http.Error(w, "HMAC verification failed", http.StatusForbidden)
			log.Println("HMAC verification failed")
			return
		}
	}

	basicHook := &HookJSON{}

	decoder := json.NewDecoder(buff)
	err = decoder.Decode(basicHook)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		log.Println(err)
		return
	}

	login := basicHook.Repository.Owner.GetLogin()
	repo := basicHook.Repository.Name

	fmt.Fprintf(w, "%s/%s", login, repo)

	if repo == "" || login == "" {
		http.Error(w, "Failed parsing JSON HTTP Body", http.StatusBadRequest)
		log.Println(err)
		return
	}

	hook := HookExec{
		RootDir: h.RootDir,

		Owner: login,
		Repo:  repo,

		Event: ghEvent,
		Data:  buff,

		HookServer: h,
	}

	go hook.Exec()
}

// HookUserJSON exists because some hooks use Login, some use Name
// - it's horribly inconsistant
type HookUserJSON struct {
	Login string `json:"login"`
	Name  string `json:"name"`
}

// GetLogin is used to get the login from the data github decided to pass today
func (h *HookUserJSON) GetLogin() string {
	if h.Login != "" {
		return h.Login
	}

	return h.Name
}

// HookJSON represents the minimum body we need to parse
type HookJSON struct {
	Repository struct {
		Name  string       `json:"name"`
		Owner HookUserJSON `json:"owner"`
	} `json:"repository"`
	Sender HookUserJSON `json:"sender"`
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"

	"github.com/coreos/go-etcd/etcd"
	"github.com/flynn/go-discoverd"
	rpc "github.com/flynn/rpcplus/comborpc"
)

type Server struct {
	*HTTPFrontend
}

func (s *Server) ListenAndServe(quit <-chan struct{}) {
	go s.HTTPFrontend.serve()
	go s.HTTPFrontend.syncDatabase()
	<-quit
	// TODO: unregister from service discovery
	// TODO: stop frontends gracefully
}

func main() {
	rpcAddr := flag.String("rpcaddr", ":1115", "rpc listen address")
	httpAddr := flag.String("httpaddr", ":8080", "http frontend listen address")
	flag.Parse()

	d, err := discoverd.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	var s Server
	s.HTTPFrontend = NewHTTPFrontend(*httpAddr, etcd.NewClient(nil), d)
	rpc.Register(&Router{s})
	rpc.HandleHTTP()
	go http.ListenAndServe(*rpcAddr, nil)

	if err = d.Register("flynn-strowger-rpc", *rpcAddr); err != nil {
		log.Fatal(err)
	}

	s.ListenAndServe(nil)
}
<commit_msg>router: Merge pull request #15 from miracle2k/etcd-env<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/coreos/go-etcd/etcd"
	"github.com/flynn/go-discoverd"
	rpc "github.com/flynn/rpcplus/comborpc"
)

type Server struct {
	*HTTPFrontend
}

func (s *Server) ListenAndServe(quit <-chan struct{}) {
	go s.HTTPFrontend.serve()
	go s.HTTPFrontend.syncDatabase()
	<-quit
	// TODO: unregister from service discovery
	// TODO: stop frontends gracefully
}

func main() {
	rpcAddr := flag.String("rpcaddr", ":1115", "rpc listen address")
	httpAddr := flag.String("httpaddr", ":8080", "http frontend listen address")
	flag.Parse()

	// Will use DISCOVERD environment variable
	d, err := discoverd.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	// Read etcd address from ETCD
	etcdAddr := strings.Split(os.Getenv("ETCD"), ",")
	if len(etcdAddr) == 1 && etcdAddr[0] == "" {
		etcdAddr = nil
	}

	var s Server
	s.HTTPFrontend = NewHTTPFrontend(*httpAddr, etcd.NewClient(etcdAddr), d)
	rpc.Register(&Router{s})
	rpc.HandleHTTP()
	go http.ListenAndServe(*rpcAddr, nil)

	if err = d.Register("flynn-strowger-rpc", *rpcAddr); err != nil {
		log.Fatal(err)
	}

	s.ListenAndServe(nil)
}
<|endoftext|>


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

// DNS server implementation.

package dns

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

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

// A ResponseWriter interface is used by an DNS handler to
// construct an DNS response.
type ResponseWriter interface {
	// RemoteAddr returns the net.Addr of the client that sent the current request.
	RemoteAddr() net.Addr
	// Return the status of the Tsig (TsigNone, TsigVerified or TsigBad)
	TsigStatus() error
	// Write writes a reply back to the client.
	Write(*Msg) error
}

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

type response struct {
	conn           *conn
	req            *Msg
	tsigStatus     error
	tsigTimersOnly bool
	tsigRequestMAC string
}

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

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

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

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

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

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

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

// Start a server on addresss and network speficied. Invoke handler
// for any incoming queries.
func ListenAndServe(addr string, network string, handler Handler) error {
	server := &Server{Addr: addr, Net: network, Handler: handler}
	return server.ListenAndServe()
}

// Start a server on addresss and network speficied. Use the tsig
// secrets for Tsig validation.
// Invoke handler for any incoming queries.
func ListenAndServeTsig(addr string, network string, handler Handler, tsig map[string]string) error {
	server := &Server{Addr: addr, Net: network, Handler: handler, TsigSecret: tsig}
	return server.ListenAndServe()
}

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

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	if pattern == "" {
		panic("dns: invalid pattern " + pattern)
	}
	mux.m[pattern] = handler
}

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

func (mux *ServeMux) HandleRemove(pattern string) {
	if pattern == "" {
		panic("dns: invalid pattern " + pattern)
	}
	// if its there, its gone
	delete(mux.m, pattern)
}

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

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

// HandleRemove deregisters the handle with the given pattern
// in the DefaultServeMux.
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }

// HandleFunc registers the handler function with te given pattern
// in the DefaultServeMux.
func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

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

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

// ServeTCP starts a TCP listener for the server.
// Each request is handled in a seperate goroutine.
// with the Handler set in ....
func (srv *Server) ServeTCP(l *net.TCPListener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
forever:
	for {
		rw, e := l.AcceptTCP()
		if e != nil {
			return e
		}
		if srv.ReadTimeout != 0 {
			rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
		}
		if srv.WriteTimeout != 0 {
			rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
		}
		l := make([]byte, 2)
		n, err := rw.Read(l)
		if err != nil || n != 2 {
			continue
		}
		length, _ := unpackUint16(l, 0)
		if length == 0 {
			continue
		}
		m := make([]byte, int(length))
		n, err = rw.Read(m[:int(length)])
		if err != nil {
			continue
		}
		i := n
		for i < int(length) {
			j, err := rw.Read(m[i:int(length)])
			if err != nil {
				continue forever
			}
			i += j
		}
		n = i
		d, err := newConn(rw, nil, rw.RemoteAddr(), m, handler, srv.TsigSecret)
		if err != nil {
			continue
		}
		go d.serve()
	}
	panic("not reached")
}

// ServeUDP starts a UDP listener for the server.
// Each request is handled in a seperate goroutine,
// with the Handler set in ....
func (srv *Server) ServeUDP(l *net.UDPConn) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if srv.UDPSize == 0 {
		srv.UDPSize = UDPMsgSize
	}
	for {
		m := make([]byte, srv.UDPSize)
		n, a, e := l.ReadFromUDP(m)
		if e != nil {
			return e
		}
		m = m[:n]

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

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

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

// Serve a new connection.
func (c *conn) serve() {
	for {
		// Request has been read in ServeUDP or ServeTCP
		w := new(response)
		w.conn = c
		req := new(Msg)
		if !req.Unpack(c.request) {
			// Send a format error back
			x := new(Msg)
			x.SetRcodeFormatError(req)
			w.Write(x)
			break
		}

		w.tsigStatus = nil
		if req.IsTsig() {
			secret := req.Extra[len(req.Extra)-1].(*RR_TSIG).Hdr.Name
			if _, ok := w.conn.tsigSecret[secret]; !ok {
				w.tsigStatus = ErrKeyAlg
			}
			w.tsigStatus = TsigVerify(c.request, w.conn.tsigSecret[secret], "", false)
			w.tsigTimersOnly = false // Will this ever be true?
			w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*RR_TSIG).MAC
		}
		w.req = req
		c.handler.ServeDNS(w, w.req) // this does the writing back to the client
		if c.hijacked {
			return
		}
		break // TODO(mg) Why is this a loop anyway?
	}
	if c._TCP != nil {
		c.close() // Listen and Serve is closed then
	}
}

func (w *response) Write(m *Msg) (err error) {
	var (
		data []byte
		ok   bool
	)
	if m.IsTsig() {
		data, w.tsigRequestMAC, err = TsigGenerate(m, w.conn.tsigSecret[m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
		if err != nil {
			return err
		}
	} else {
		data, ok = m.Pack()
		if !ok {
			return ErrPack
		}
	}
	switch {
	case w.conn._UDP != nil:
		_, err := w.conn._UDP.WriteTo(data, w.conn.remoteAddr)
		if err != nil {
			return err
		}
	case w.conn._TCP != nil:
		if len(data) > MaxMsgSize {
			return ErrBuf
		}
		l := make([]byte, 2)
		l[0], l[1] = packUint16(uint16(len(data)))
		n, err := w.conn._TCP.Write(l)
		if err != nil {
			return err
		}
		if n != 2 {
			return io.ErrShortWrite
		}
		n, err = w.conn._TCP.Write(data)
		if err != nil {
			return err
		}
		i := n
		if i < len(data) {
			j, err := w.conn._TCP.Write(data[i:len(data)])
			if err != nil {
				return err
			}
			i += j
		}
		n = i
	}
	return nil
}

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

// TsigStatus implements the ResponseWriter.TsigStatus method
func (w *response) TsigStatus() error {
	return w.tsigStatus
}
<commit_msg>Fix panic<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// DNS server implementation.

package dns

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

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

// A ResponseWriter interface is used by an DNS handler to
// construct an DNS response.
type ResponseWriter interface {
	// RemoteAddr returns the net.Addr of the client that sent the current request.
	RemoteAddr() net.Addr
	// Return the status of the Tsig (TsigNone, TsigVerified or TsigBad)
	TsigStatus() error
	// Write writes a reply back to the client.
	Write(*Msg) error
}

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

type response struct {
	conn           *conn
	req            *Msg
	tsigStatus     error
	tsigTimersOnly bool
	tsigRequestMAC string
}

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

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

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

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

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

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

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

// Start a server on addresss and network speficied. Invoke handler
// for any incoming queries.
func ListenAndServe(addr string, network string, handler Handler) error {
	server := &Server{Addr: addr, Net: network, Handler: handler}
	return server.ListenAndServe()
}

// Start a server on addresss and network speficied. Use the tsig
// secrets for Tsig validation.
// Invoke handler for any incoming queries.
func ListenAndServeTsig(addr string, network string, handler Handler, tsig map[string]string) error {
	server := &Server{Addr: addr, Net: network, Handler: handler, TsigSecret: tsig}
	return server.ListenAndServe()
}

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

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	if pattern == "" {
		panic("dns: invalid pattern " + pattern)
	}
	mux.m[pattern] = handler
}

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

func (mux *ServeMux) HandleRemove(pattern string) {
	if pattern == "" {
		panic("dns: invalid pattern " + pattern)
	}
	// if its there, its gone
	delete(mux.m, pattern)
}

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

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

// HandleRemove deregisters the handle with the given pattern
// in the DefaultServeMux.
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }

// HandleFunc registers the handler function with te given pattern
// in the DefaultServeMux.
func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

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

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

// ServeTCP starts a TCP listener for the server.
// Each request is handled in a seperate goroutine.
// with the Handler set in ....
func (srv *Server) ServeTCP(l *net.TCPListener) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
forever:
	for {
		rw, e := l.AcceptTCP()
		if e != nil {
			return e
		}
		if srv.ReadTimeout != 0 {
			rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
		}
		if srv.WriteTimeout != 0 {
			rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
		}
		l := make([]byte, 2)
		n, err := rw.Read(l)
		if err != nil || n != 2 {
			continue
		}
		length, _ := unpackUint16(l, 0)
		if length == 0 {
			continue
		}
		m := make([]byte, int(length))
		n, err = rw.Read(m[:int(length)])
		if err != nil || n == 0 {
			continue
		}
		i := n
		for i < int(length) {
			j, err := rw.Read(m[i:int(length)])
			if err != nil {
				continue forever
			}
			i += j
		}
		n = i
		d, err := newConn(rw, nil, rw.RemoteAddr(), m, handler, srv.TsigSecret)
		if err != nil {
			continue
		}
		go d.serve()
	}
	panic("not reached")
}

// ServeUDP starts a UDP listener for the server.
// Each request is handled in a seperate goroutine,
// with the Handler set in ....
func (srv *Server) ServeUDP(l *net.UDPConn) error {
	defer l.Close()
	handler := srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if srv.UDPSize == 0 {
		srv.UDPSize = UDPMsgSize
	}
	for {
		m := make([]byte, srv.UDPSize)
		n, a, e := l.ReadFromUDP(m)
		if e != nil || n == 0 {
			return e
		}
		m = m[:n]

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

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

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

// Serve a new connection.
func (c *conn) serve() {
	for {
		// Request has been read in ServeUDP or ServeTCP
		w := new(response)
		w.conn = c
		req := new(Msg)
		if !req.Unpack(c.request) {
			// Send a format error back
			x := new(Msg)
			x.SetRcodeFormatError(req)
			w.Write(x)
			break
		}

		w.tsigStatus = nil
		if req.IsTsig() {
			secret := req.Extra[len(req.Extra)-1].(*RR_TSIG).Hdr.Name
			if _, ok := w.conn.tsigSecret[secret]; !ok {
				w.tsigStatus = ErrKeyAlg
			}
			w.tsigStatus = TsigVerify(c.request, w.conn.tsigSecret[secret], "", false)
			w.tsigTimersOnly = false // Will this ever be true?
			w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*RR_TSIG).MAC
		}
		w.req = req
		c.handler.ServeDNS(w, w.req) // this does the writing back to the client
		if c.hijacked {
			return
		}
		break // TODO(mg) Why is this a loop anyway?
	}
	if c._TCP != nil {
		c.close() // Listen and Serve is closed then
	}
}

func (w *response) Write(m *Msg) (err error) {
	var (
		data []byte
		ok   bool
	)
	if m.IsTsig() {
		data, w.tsigRequestMAC, err = TsigGenerate(m, w.conn.tsigSecret[m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
		if err != nil {
			return err
		}
	} else {
		data, ok = m.Pack()
		if !ok {
			return ErrPack
		}
	}
	switch {
	case w.conn._UDP != nil:
		_, err := w.conn._UDP.WriteTo(data, w.conn.remoteAddr)
		if err != nil {
			return err
		}
	case w.conn._TCP != nil:
		if len(data) > MaxMsgSize {
			return ErrBuf
		}
		l := make([]byte, 2)
		l[0], l[1] = packUint16(uint16(len(data)))
		n, err := w.conn._TCP.Write(l)
		if err != nil {
			return err
		}
		if n != 2 {
			return io.ErrShortWrite
		}
		n, err = w.conn._TCP.Write(data)
		if err != nil {
			return err
		}
		i := n
		if i < len(data) {
			j, err := w.conn._TCP.Write(data[i:len(data)])
			if err != nil {
				return err
			}
			i += j
		}
		n = i
	}
	return nil
}

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

// TsigStatus implements the ResponseWriter.TsigStatus method
func (w *response) TsigStatus() error {
	return w.tsigStatus
}
<|endoftext|>


<commit_before>package tensor3
import "fmt"

// component type
type BaseType int

const scaleShift=10
const scale = 1<<scaleShift

func Base64(f float64) BaseType{
	return BaseType(f*float64(scale))
}

func Base32(f float32) BaseType{
	return BaseType(f*float32(scale))
}

func baseScale(v BaseType) BaseType{
	return v<<scaleShift
}

func baseUnscale(v BaseType) BaseType{
	return v>>scaleShift
}

func vectorScale(v *Vector){
	v.x<<=scaleShift
	v.y<<=scaleShift
	v.z<<=scaleShift
	return
}

func vectorUnscale(v *Vector){
	v.x>>=scaleShift
	v.y>>=scaleShift
	v.z>>=scaleShift
	return
}

func (v BaseType) String()string{
	return fmt.Sprint(float32(v)/float32(scale))
}

func (v Vector) String()string{
	return fmt.Sprintf("{%s %s %s}",v.x,v.y,v.z)
}

// TODO scan scaled?

// new vector reference from float64's
func New(x,y,z float64) *Vector{
	return &Vector{Base64(x),Base64(y),Base64(z)}
}

<commit_msg>comment<commit_after><|endoftext|>


<commit_before>package data

import (
	"errors"
	"fmt"
	"reflect"
)

// ReadWire parses types received via the peer network
func ReadWire(r Reader, typ NodeType, ledgerSequence uint32) (Hashable, error) {
	version, err := readHashPrefix(r)
	if err != nil {
		return nil, err
	}
	switch version {
	case HP_LEAF_NODE:
		return readLedgerEntry(r)
	case HP_TRANSACTION_NODE:
		return readTransactionWithMetadata(r, ledgerSequence)
	case HP_INNER_NODE:
		return readCompressedInnerNode(r, typ)
	default:
		return nil, fmt.Errorf("Unknown hash prefix: %s", version.String())
	}
}

// ReadPrefix parses types received from the nodestore
func ReadPrefix(r Reader) (Storer, error) {
	header, err := readHeader(r)
	if err != nil {
		return nil, err
	}
	version, err := readHashPrefix(r)
	if err != nil {
		return nil, err
	}
	switch {
	case version == HP_INNER_NODE:
		return readInnerNode(r, header.NodeType)
	case header.NodeType == NT_LEDGER:
		return ReadLedger(r)
	case header.NodeType == NT_TRANSACTION_NODE:
		return readTransactionWithMetadata(r, header.LedgerSequence)
	case header.NodeType == NT_ACCOUNT_NODE:
		return readLedgerEntry(r)
	default:
		return nil, fmt.Errorf("Unknown node type")
	}
}

func ReadLedger(r Reader) (*Ledger, error) {
	ledger := new(Ledger)
	return ledger, read(r, &ledger.LedgerHeader)
}

func ReadValidation(r Reader) (*Validation, error) {
	validation := new(Validation)
	v := reflect.ValueOf(validation)
	if err := readObject(r, &v); err != nil {
		return nil, err
	}
	return validation, nil
}

func ReadTransaction(r Reader) (Transaction, error) {
	txType, err := expectType(r, "TransactionType")
	if err != nil {
		return nil, err
	}
	tx := TxFactory[txType]()
	v := reflect.ValueOf(tx)
	if err := readObject(r, &v); err != nil {
		return nil, err
	}
	return tx, nil
}

// ReadTransactionAndMetadata combines the inputs from the two
// readers into a TransactionWithMetaData
func ReadTransactionAndMetadata(tx, meta Reader, hash Hash256, ledger uint32) (*TransactionWithMetaData, error) {
	t, err := ReadTransaction(tx)
	if err != nil {
		return nil, err
	}
	txm := &TransactionWithMetaData{
		Transaction:    t,
		LedgerSequence: ledger,
	}
	m := reflect.ValueOf(&txm.MetaData)
	if err := readObject(meta, &m); err != nil {
		return nil, err
	}
	txm.Transaction.GetBase().Hash = hash
	return txm, nil
}

// For internal use when reading Prefix format
func readTransactionWithMetadata(r Reader, ledger uint32) (*TransactionWithMetaData, error) {
	br, err := NewVariableByteReader(r)
	if err != nil {
		return nil, err
	}
	tx, err := ReadTransaction(br)
	if err != nil {
		return nil, err
	}
	txm := &TransactionWithMetaData{
		Transaction:    tx,
		LedgerSequence: ledger,
	}
	br, err = NewVariableByteReader(r)
	if err != nil {
		return nil, err
	}
	meta := reflect.ValueOf(&txm.MetaData)
	if err := readObject(br, &meta); err != nil {
		return nil, err
	}
	hash, err := readHash(r)
	if err != nil {
		return nil, err
	}
	txm.Transaction.GetBase().Hash = *hash
	return txm, nil
}

func readHashPrefix(r Reader) (HashPrefix, error) {
	var version HashPrefix
	return version, read(r, &version)
}

func readHeader(r Reader) (*NodeHeader, error) {
	header := new(NodeHeader)
	return header, read(r, header)
}

func readHash(r Reader) (*Hash256, error) {
	var h Hash256
	n, err := r.Read(h[:])
	switch {
	case err != nil:
		return nil, err
	case n != len(h):
		return nil, fmt.Errorf("Bad hash")
	default:
		return &h, nil
	}
}

func readInnerNode(r Reader, typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	for i := range inner.Children {
		if _, err := r.Read(inner.Children[i][:]); err != nil {
			return nil, err
		}
	}
	return &inner, nil
}

func readCompressedInnerNode(r Reader, typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	var entry CompressedNodeEntry
	for read(r, &entry) == nil {
		inner.Children[entry.Pos] = entry.Hash
	}
	return &inner, nil
}

func readLedgerEntry(r Reader) (LedgerEntry, error) {
	leType, err := expectType(r, "LedgerEntryType")
	if err != nil {
		return nil, err
	}
	le := LedgerEntryFactory[leType]()
	v := reflect.ValueOf(le)
	// LedgerEntries have 32 bytes of index suffixed
	// but don't have a variable bytes indicator
	lr := LimitedByteReader(r, int64(r.Len()-32))
	if err := readObject(lr, &v); err != nil {
		return nil, err
	}
	return le, nil
}

func expectType(r Reader, expected string) (uint16, error) {
	enc, err := readEncoding(r)
	if err != nil {
		return 0, err
	}
	name := encodings[*enc]
	if name != expected {
		return 0, fmt.Errorf("Unexpected type: %s expected: %s", name, expected)
	}
	var typ uint16
	return typ, read(r, &typ)
}

var (
	errorEndOfObject = errors.New("EndOfObject")
	errorEndOfArray  = errors.New("EndOfArray")
)

func readObject(r Reader, v *reflect.Value) error {
	var err error
	for enc, err := readEncoding(r); err == nil; enc, err = readEncoding(r) {
		name := encodings[*enc]
		// fmt.Println(name, v, v.IsValid(), enc.typ, enc.field)
		switch enc.typ {
		case ST_ARRAY:
			if name == "EndOfArray" {
				return errorEndOfArray
			}
			array := getField(v, enc)
		loop:
			for {
				child := reflect.New(array.Type().Elem()).Elem()
				err := readObject(r, &child)
				switch err {
				case errorEndOfArray:
					break loop
				case errorEndOfObject:
					array.Set(reflect.Append(*array, child))
				default:
					return err
				}
			}
		case ST_OBJECT:
			switch name {
			case "EndOfObject":
				return errorEndOfObject
			case "PreviousFields", "NewFields", "FinalFields":
				var fields Fields
				f := reflect.ValueOf(&fields)
				v.Elem().FieldByName(name).Set(f)
				if readObject(r, &f); err != nil && err != errorEndOfObject {
					return err
				}
			case "ModifiedNode", "DeletedNode", "CreatedNode":
				var node AffectedNode
				n := reflect.ValueOf(&node)
				var effect NodeEffect
				e := reflect.ValueOf(&effect)
				e.Elem().FieldByName(name).Set(n)
				v.Set(e.Elem())
				return readObject(r, &n)
			case "Memo":
				var memo Memo
				m := reflect.ValueOf(&memo)
				inner := reflect.ValueOf(&memo.Memo)
				err := readObject(r, &inner)
				v.Set(m.Elem())
				return err
			default:
				panic(fmt.Sprintf("Unknown object: %+v", enc))
			}
		default:
			if v.Kind() == reflect.Struct {
				return fmt.Errorf("Unexpected object: %s for field: %s", v.Type(), name)
			}
			field := getField(v, enc)
			if !field.CanAddr() {
				return fmt.Errorf("Missing field: %s", name)
			}
			switch v := field.Addr().Interface().(type) {
			case Wire:
				if err := v.Unmarshal(r); err != nil {
					return err
				}
			default:
				if err := read(r, v); err != nil {
					return err
				}
			}
		}
	}
	return err
}

func getField(v *reflect.Value, e *enc) *reflect.Value {
	name := encodings[*e]
	field := v.Elem().FieldByName(name)
	if field.Kind() == reflect.Ptr {
		field.Set(reflect.New(field.Type().Elem()))
		field = field.Elem()
	}
	return &field
}
<commit_msg>Set hash for TransactionWithMetadata<commit_after>package data

import (
	"errors"
	"fmt"
	"reflect"
)

// ReadWire parses types received via the peer network
func ReadWire(r Reader, typ NodeType, ledgerSequence uint32) (Hashable, error) {
	version, err := readHashPrefix(r)
	if err != nil {
		return nil, err
	}
	switch version {
	case HP_LEAF_NODE:
		return readLedgerEntry(r)
	case HP_TRANSACTION_NODE:
		return readTransactionWithMetadata(r, ledgerSequence)
	case HP_INNER_NODE:
		return readCompressedInnerNode(r, typ)
	default:
		return nil, fmt.Errorf("Unknown hash prefix: %s", version.String())
	}
}

// ReadPrefix parses types received from the nodestore
func ReadPrefix(r Reader) (Storer, error) {
	header, err := readHeader(r)
	if err != nil {
		return nil, err
	}
	version, err := readHashPrefix(r)
	if err != nil {
		return nil, err
	}
	switch {
	case version == HP_INNER_NODE:
		return readInnerNode(r, header.NodeType)
	case header.NodeType == NT_LEDGER:
		return ReadLedger(r)
	case header.NodeType == NT_TRANSACTION_NODE:
		return readTransactionWithMetadata(r, header.LedgerSequence)
	case header.NodeType == NT_ACCOUNT_NODE:
		return readLedgerEntry(r)
	default:
		return nil, fmt.Errorf("Unknown node type")
	}
}

func ReadLedger(r Reader) (*Ledger, error) {
	ledger := new(Ledger)
	return ledger, read(r, &ledger.LedgerHeader)
}

func ReadValidation(r Reader) (*Validation, error) {
	validation := new(Validation)
	v := reflect.ValueOf(validation)
	if err := readObject(r, &v); err != nil {
		return nil, err
	}
	return validation, nil
}

func ReadTransaction(r Reader) (Transaction, error) {
	txType, err := expectType(r, "TransactionType")
	if err != nil {
		return nil, err
	}
	tx := TxFactory[txType]()
	v := reflect.ValueOf(tx)
	if err := readObject(r, &v); err != nil {
		return nil, err
	}
	return tx, nil
}

// ReadTransactionAndMetadata combines the inputs from the two
// readers into a TransactionWithMetaData
func ReadTransactionAndMetadata(tx, meta Reader, hash Hash256, ledger uint32) (*TransactionWithMetaData, error) {
	t, err := ReadTransaction(tx)
	if err != nil {
		return nil, err
	}
	txm := &TransactionWithMetaData{
		Transaction:    t,
		LedgerSequence: ledger,
	}
	m := reflect.ValueOf(&txm.MetaData)
	if err := readObject(meta, &m); err != nil {
		return nil, err
	}
	*txm.GetHash() = hash
	return txm, nil
}

// For internal use when reading Prefix format
func readTransactionWithMetadata(r Reader, ledger uint32) (*TransactionWithMetaData, error) {
	br, err := NewVariableByteReader(r)
	if err != nil {
		return nil, err
	}
	tx, err := ReadTransaction(br)
	if err != nil {
		return nil, err
	}
	txm := &TransactionWithMetaData{
		Transaction:    tx,
		LedgerSequence: ledger,
	}
	br, err = NewVariableByteReader(r)
	if err != nil {
		return nil, err
	}
	meta := reflect.ValueOf(&txm.MetaData)
	if err := readObject(br, &meta); err != nil {
		return nil, err
	}
	hash, err := readHash(r)
	if err != nil {
		return nil, err
	}
	txm.Transaction.GetBase().Hash = *hash
	return txm, nil
}

func readHashPrefix(r Reader) (HashPrefix, error) {
	var version HashPrefix
	return version, read(r, &version)
}

func readHeader(r Reader) (*NodeHeader, error) {
	header := new(NodeHeader)
	return header, read(r, header)
}

func readHash(r Reader) (*Hash256, error) {
	var h Hash256
	n, err := r.Read(h[:])
	switch {
	case err != nil:
		return nil, err
	case n != len(h):
		return nil, fmt.Errorf("Bad hash")
	default:
		return &h, nil
	}
}

func readInnerNode(r Reader, typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	for i := range inner.Children {
		if _, err := r.Read(inner.Children[i][:]); err != nil {
			return nil, err
		}
	}
	return &inner, nil
}

func readCompressedInnerNode(r Reader, typ NodeType) (*InnerNode, error) {
	var inner InnerNode
	inner.Type = typ
	var entry CompressedNodeEntry
	for read(r, &entry) == nil {
		inner.Children[entry.Pos] = entry.Hash
	}
	return &inner, nil
}

func readLedgerEntry(r Reader) (LedgerEntry, error) {
	leType, err := expectType(r, "LedgerEntryType")
	if err != nil {
		return nil, err
	}
	le := LedgerEntryFactory[leType]()
	v := reflect.ValueOf(le)
	// LedgerEntries have 32 bytes of index suffixed
	// but don't have a variable bytes indicator
	lr := LimitedByteReader(r, int64(r.Len()-32))
	if err := readObject(lr, &v); err != nil {
		return nil, err
	}
	return le, nil
}

func expectType(r Reader, expected string) (uint16, error) {
	enc, err := readEncoding(r)
	if err != nil {
		return 0, err
	}
	name := encodings[*enc]
	if name != expected {
		return 0, fmt.Errorf("Unexpected type: %s expected: %s", name, expected)
	}
	var typ uint16
	return typ, read(r, &typ)
}

var (
	errorEndOfObject = errors.New("EndOfObject")
	errorEndOfArray  = errors.New("EndOfArray")
)

func readObject(r Reader, v *reflect.Value) error {
	var err error
	for enc, err := readEncoding(r); err == nil; enc, err = readEncoding(r) {
		name := encodings[*enc]
		// fmt.Println(name, v, v.IsValid(), enc.typ, enc.field)
		switch enc.typ {
		case ST_ARRAY:
			if name == "EndOfArray" {
				return errorEndOfArray
			}
			array := getField(v, enc)
		loop:
			for {
				child := reflect.New(array.Type().Elem()).Elem()
				err := readObject(r, &child)
				switch err {
				case errorEndOfArray:
					break loop
				case errorEndOfObject:
					array.Set(reflect.Append(*array, child))
				default:
					return err
				}
			}
		case ST_OBJECT:
			switch name {
			case "EndOfObject":
				return errorEndOfObject
			case "PreviousFields", "NewFields", "FinalFields":
				var fields Fields
				f := reflect.ValueOf(&fields)
				v.Elem().FieldByName(name).Set(f)
				if readObject(r, &f); err != nil && err != errorEndOfObject {
					return err
				}
			case "ModifiedNode", "DeletedNode", "CreatedNode":
				var node AffectedNode
				n := reflect.ValueOf(&node)
				var effect NodeEffect
				e := reflect.ValueOf(&effect)
				e.Elem().FieldByName(name).Set(n)
				v.Set(e.Elem())
				return readObject(r, &n)
			case "Memo":
				var memo Memo
				m := reflect.ValueOf(&memo)
				inner := reflect.ValueOf(&memo.Memo)
				err := readObject(r, &inner)
				v.Set(m.Elem())
				return err
			default:
				panic(fmt.Sprintf("Unknown object: %+v", enc))
			}
		default:
			if v.Kind() == reflect.Struct {
				return fmt.Errorf("Unexpected object: %s for field: %s", v.Type(), name)
			}
			field := getField(v, enc)
			if !field.CanAddr() {
				return fmt.Errorf("Missing field: %s", name)
			}
			switch v := field.Addr().Interface().(type) {
			case Wire:
				if err := v.Unmarshal(r); err != nil {
					return err
				}
			default:
				if err := read(r, v); err != nil {
					return err
				}
			}
		}
	}
	return err
}

func getField(v *reflect.Value, e *enc) *reflect.Value {
	name := encodings[*e]
	field := v.Elem().FieldByName(name)
	if field.Kind() == reflect.Ptr {
		field.Set(reflect.New(field.Type().Elem()))
		field = field.Elem()
	}
	return &field
}
<|endoftext|>