aboutsummaryrefslogtreecommitdiffstats
path: root/golang/restapi
diff options
context:
space:
mode:
Diffstat (limited to 'golang/restapi')
-rw-r--r--golang/restapi/configure_fatcat.go71
-rw-r--r--golang/restapi/doc.go23
-rw-r--r--golang/restapi/embedded_spec.go250
-rw-r--r--golang/restapi/operations/fatcat_api.go288
-rw-r--r--golang/restapi/operations/get_creator_id.go58
-rw-r--r--golang/restapi/operations/get_creator_id_parameters.go72
-rw-r--r--golang/restapi/operations/get_creator_id_responses.go116
-rw-r--r--golang/restapi/operations/get_creator_id_urlbuilder.go99
-rw-r--r--golang/restapi/operations/post_creator.go58
-rw-r--r--golang/restapi/operations/post_creator_parameters.go70
-rw-r--r--golang/restapi/operations/post_creator_responses.go116
-rw-r--r--golang/restapi/operations/post_creator_urlbuilder.go87
-rw-r--r--golang/restapi/server.go448
13 files changed, 1756 insertions, 0 deletions
diff --git a/golang/restapi/configure_fatcat.go b/golang/restapi/configure_fatcat.go
new file mode 100644
index 00000000..1b8d2e7c
--- /dev/null
+++ b/golang/restapi/configure_fatcat.go
@@ -0,0 +1,71 @@
+// This file is safe to edit. Once it exists it will not be overwritten
+
+package restapi
+
+import (
+ "crypto/tls"
+ "net/http"
+
+ errors "github.com/go-openapi/errors"
+ runtime "github.com/go-openapi/runtime"
+ middleware "github.com/go-openapi/runtime/middleware"
+ graceful "github.com/tylerb/graceful"
+
+ "git.archive.org/bnewbold/fatcat/restapi/operations"
+)
+
+//go:generate swagger generate server --target .. --name Fatcat --spec ../fatcat-openapi2.yml
+
+func configureFlags(api *operations.FatcatAPI) {
+ // api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ ... }
+}
+
+func configureAPI(api *operations.FatcatAPI) http.Handler {
+ // configure the api here
+ api.ServeError = errors.ServeError
+
+ // Set your custom logger if needed. Default one is log.Printf
+ // Expected interface func(string, ...interface{})
+ //
+ // Example:
+ // api.Logger = log.Printf
+
+ api.JSONConsumer = runtime.JSONConsumer()
+
+ api.JSONProducer = runtime.JSONProducer()
+
+ api.GetCreatorIDHandler = operations.GetCreatorIDHandlerFunc(func(params operations.GetCreatorIDParams) middleware.Responder {
+ return middleware.NotImplemented("operation .GetCreatorID has not yet been implemented")
+ })
+ api.PostCreatorHandler = operations.PostCreatorHandlerFunc(func(params operations.PostCreatorParams) middleware.Responder {
+ return middleware.NotImplemented("operation .PostCreator has not yet been implemented")
+ })
+
+ api.ServerShutdown = func() {}
+
+ return setupGlobalMiddleware(api.Serve(setupMiddlewares))
+}
+
+// The TLS configuration before HTTPS server starts.
+func configureTLS(tlsConfig *tls.Config) {
+ // Make all necessary changes to the TLS configuration here.
+}
+
+// As soon as server is initialized but not run yet, this function will be called.
+// If you need to modify a config, store server instance to stop it individually later, this is the place.
+// This function can be called multiple times, depending on the number of serving schemes.
+// scheme value will be set accordingly: "http", "https" or "unix"
+func configureServer(s *graceful.Server, scheme, addr string) {
+}
+
+// The middleware configuration is for the handler executors. These do not apply to the swagger.json document.
+// The middleware executes after routing but before authentication, binding and validation
+func setupMiddlewares(handler http.Handler) http.Handler {
+ return handler
+}
+
+// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
+// So this is a good place to plug in a panic handling middleware, logging and metrics
+func setupGlobalMiddleware(handler http.Handler) http.Handler {
+ return handler
+}
diff --git a/golang/restapi/doc.go b/golang/restapi/doc.go
new file mode 100644
index 00000000..9896c2da
--- /dev/null
+++ b/golang/restapi/doc.go
@@ -0,0 +1,23 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+/*
+Package restapi fatcat
+A scalable, versioned, API-oriented catalog of bibliographic entities and file metadata
+
+
+ Schemes:
+ http
+ https
+ Host: api.fatcat.wiki
+ BasePath: /v0
+ Version: 0.1.0
+
+ Consumes:
+ - application/json
+
+ Produces:
+ - application/json
+
+swagger:meta
+*/
+package restapi
diff --git a/golang/restapi/embedded_spec.go b/golang/restapi/embedded_spec.go
new file mode 100644
index 00000000..1b193eb9
--- /dev/null
+++ b/golang/restapi/embedded_spec.go
@@ -0,0 +1,250 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package restapi
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "encoding/json"
+)
+
+var (
+ // SwaggerJSON embedded version of the swagger document used at generation time
+ SwaggerJSON json.RawMessage
+ // FlatSwaggerJSON embedded flattened version of the swagger document used at generation time
+ FlatSwaggerJSON json.RawMessage
+)
+
+func init() {
+ SwaggerJSON = json.RawMessage([]byte(`{
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "schemes": [
+ "http",
+ "https"
+ ],
+ "swagger": "2.0",
+ "info": {
+ "description": "A scalable, versioned, API-oriented catalog of bibliographic entities and file metadata",
+ "title": "fatcat",
+ "version": "0.1.0"
+ },
+ "host": "api.fatcat.wiki",
+ "basePath": "/v0",
+ "paths": {
+ "/creator": {
+ "post": {
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/creator_entity"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "created",
+ "schema": {
+ "$ref": "#/definitions/creator_entity"
+ }
+ },
+ "default": {
+ "description": "generic error response",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
+ "/creator/{id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "fetch a single creator by id",
+ "schema": {
+ "$ref": "#/definitions/creator_entity"
+ }
+ },
+ "default": {
+ "description": "generic error response",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "type": "string",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ]
+ }
+ },
+ "definitions": {
+ "creator_entity": {
+ "type": "object",
+ "required": [
+ "ident",
+ "state"
+ ],
+ "properties": {
+ "ident": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "orcid": {
+ "type": "string"
+ },
+ "redirect": {
+ "type": "string"
+ },
+ "revision": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ }
+ }
+ },
+ "error": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+}`))
+ FlatSwaggerJSON = json.RawMessage([]byte(`{
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "schemes": [
+ "http",
+ "https"
+ ],
+ "swagger": "2.0",
+ "info": {
+ "description": "A scalable, versioned, API-oriented catalog of bibliographic entities and file metadata",
+ "title": "fatcat",
+ "version": "0.1.0"
+ },
+ "host": "api.fatcat.wiki",
+ "basePath": "/v0",
+ "paths": {
+ "/creator": {
+ "post": {
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "schema": {
+ "$ref": "#/definitions/creator_entity"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "created",
+ "schema": {
+ "$ref": "#/definitions/creator_entity"
+ }
+ },
+ "default": {
+ "description": "generic error response",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
+ "/creator/{id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "fetch a single creator by id",
+ "schema": {
+ "$ref": "#/definitions/creator_entity"
+ }
+ },
+ "default": {
+ "description": "generic error response",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "type": "string",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ]
+ }
+ },
+ "definitions": {
+ "creator_entity": {
+ "type": "object",
+ "required": [
+ "ident",
+ "state"
+ ],
+ "properties": {
+ "ident": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "orcid": {
+ "type": "string"
+ },
+ "redirect": {
+ "type": "string"
+ },
+ "revision": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ }
+ }
+ },
+ "error": {
+ "type": "object",
+ "required": [
+ "message"
+ ],
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ }
+ }
+}`))
+}
diff --git a/golang/restapi/operations/fatcat_api.go b/golang/restapi/operations/fatcat_api.go
new file mode 100644
index 00000000..7b60b34f
--- /dev/null
+++ b/golang/restapi/operations/fatcat_api.go
@@ -0,0 +1,288 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ errors "github.com/go-openapi/errors"
+ loads "github.com/go-openapi/loads"
+ runtime "github.com/go-openapi/runtime"
+ middleware "github.com/go-openapi/runtime/middleware"
+ security "github.com/go-openapi/runtime/security"
+ spec "github.com/go-openapi/spec"
+ strfmt "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+)
+
+// NewFatcatAPI creates a new Fatcat instance
+func NewFatcatAPI(spec *loads.Document) *FatcatAPI {
+ return &FatcatAPI{
+ handlers: make(map[string]map[string]http.Handler),
+ formats: strfmt.Default,
+ defaultConsumes: "application/json",
+ defaultProduces: "application/json",
+ customConsumers: make(map[string]runtime.Consumer),
+ customProducers: make(map[string]runtime.Producer),
+ ServerShutdown: func() {},
+ spec: spec,
+ ServeError: errors.ServeError,
+ BasicAuthenticator: security.BasicAuth,
+ APIKeyAuthenticator: security.APIKeyAuth,
+ BearerAuthenticator: security.BearerAuth,
+ JSONConsumer: runtime.JSONConsumer(),
+ JSONProducer: runtime.JSONProducer(),
+ GetCreatorIDHandler: GetCreatorIDHandlerFunc(func(params GetCreatorIDParams) middleware.Responder {
+ return middleware.NotImplemented("operation GetCreatorID has not yet been implemented")
+ }),
+ PostCreatorHandler: PostCreatorHandlerFunc(func(params PostCreatorParams) middleware.Responder {
+ return middleware.NotImplemented("operation PostCreator has not yet been implemented")
+ }),
+ }
+}
+
+/*FatcatAPI A scalable, versioned, API-oriented catalog of bibliographic entities and file metadata */
+type FatcatAPI struct {
+ spec *loads.Document
+ context *middleware.Context
+ handlers map[string]map[string]http.Handler
+ formats strfmt.Registry
+ customConsumers map[string]runtime.Consumer
+ customProducers map[string]runtime.Producer
+ defaultConsumes string
+ defaultProduces string
+ Middleware func(middleware.Builder) http.Handler
+
+ // BasicAuthenticator generates a runtime.Authenticator from the supplied basic auth function.
+ // It has a default implemention in the security package, however you can replace it for your particular usage.
+ BasicAuthenticator func(security.UserPassAuthentication) runtime.Authenticator
+ // APIKeyAuthenticator generates a runtime.Authenticator from the supplied token auth function.
+ // It has a default implemention in the security package, however you can replace it for your particular usage.
+ APIKeyAuthenticator func(string, string, security.TokenAuthentication) runtime.Authenticator
+ // BearerAuthenticator generates a runtime.Authenticator from the supplied bearer token auth function.
+ // It has a default implemention in the security package, however you can replace it for your particular usage.
+ BearerAuthenticator func(string, security.ScopedTokenAuthentication) runtime.Authenticator
+
+ // JSONConsumer registers a consumer for a "application/json" mime type
+ JSONConsumer runtime.Consumer
+
+ // JSONProducer registers a producer for a "application/json" mime type
+ JSONProducer runtime.Producer
+
+ // GetCreatorIDHandler sets the operation handler for the get creator ID operation
+ GetCreatorIDHandler GetCreatorIDHandler
+ // PostCreatorHandler sets the operation handler for the post creator operation
+ PostCreatorHandler PostCreatorHandler
+
+ // ServeError is called when an error is received, there is a default handler
+ // but you can set your own with this
+ ServeError func(http.ResponseWriter, *http.Request, error)
+
+ // ServerShutdown is called when the HTTP(S) server is shut down and done
+ // handling all active connections and does not accept connections any more
+ ServerShutdown func()
+
+ // Custom command line argument groups with their descriptions
+ CommandLineOptionsGroups []swag.CommandLineOptionsGroup
+
+ // User defined logger function.
+ Logger func(string, ...interface{})
+}
+
+// SetDefaultProduces sets the default produces media type
+func (o *FatcatAPI) SetDefaultProduces(mediaType string) {
+ o.defaultProduces = mediaType
+}
+
+// SetDefaultConsumes returns the default consumes media type
+func (o *FatcatAPI) SetDefaultConsumes(mediaType string) {
+ o.defaultConsumes = mediaType
+}
+
+// SetSpec sets a spec that will be served for the clients.
+func (o *FatcatAPI) SetSpec(spec *loads.Document) {
+ o.spec = spec
+}
+
+// DefaultProduces returns the default produces media type
+func (o *FatcatAPI) DefaultProduces() string {
+ return o.defaultProduces
+}
+
+// DefaultConsumes returns the default consumes media type
+func (o *FatcatAPI) DefaultConsumes() string {
+ return o.defaultConsumes
+}
+
+// Formats returns the registered string formats
+func (o *FatcatAPI) Formats() strfmt.Registry {
+ return o.formats
+}
+
+// RegisterFormat registers a custom format validator
+func (o *FatcatAPI) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) {
+ o.formats.Add(name, format, validator)
+}
+
+// Validate validates the registrations in the FatcatAPI
+func (o *FatcatAPI) Validate() error {
+ var unregistered []string
+
+ if o.JSONConsumer == nil {
+ unregistered = append(unregistered, "JSONConsumer")
+ }
+
+ if o.JSONProducer == nil {
+ unregistered = append(unregistered, "JSONProducer")
+ }
+
+ if o.GetCreatorIDHandler == nil {
+ unregistered = append(unregistered, "GetCreatorIDHandler")
+ }
+
+ if o.PostCreatorHandler == nil {
+ unregistered = append(unregistered, "PostCreatorHandler")
+ }
+
+ if len(unregistered) > 0 {
+ return fmt.Errorf("missing registration: %s", strings.Join(unregistered, ", "))
+ }
+
+ return nil
+}
+
+// ServeErrorFor gets a error handler for a given operation id
+func (o *FatcatAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) {
+ return o.ServeError
+}
+
+// AuthenticatorsFor gets the authenticators for the specified security schemes
+func (o *FatcatAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
+
+ return nil
+
+}
+
+// Authorizer returns the registered authorizer
+func (o *FatcatAPI) Authorizer() runtime.Authorizer {
+
+ return nil
+
+}
+
+// ConsumersFor gets the consumers for the specified media types
+func (o *FatcatAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
+
+ result := make(map[string]runtime.Consumer)
+ for _, mt := range mediaTypes {
+ switch mt {
+
+ case "application/json":
+ result["application/json"] = o.JSONConsumer
+
+ }
+
+ if c, ok := o.customConsumers[mt]; ok {
+ result[mt] = c
+ }
+ }
+ return result
+
+}
+
+// ProducersFor gets the producers for the specified media types
+func (o *FatcatAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
+
+ result := make(map[string]runtime.Producer)
+ for _, mt := range mediaTypes {
+ switch mt {
+
+ case "application/json":
+ result["application/json"] = o.JSONProducer
+
+ }
+
+ if p, ok := o.customProducers[mt]; ok {
+ result[mt] = p
+ }
+ }
+ return result
+
+}
+
+// HandlerFor gets a http.Handler for the provided operation method and path
+func (o *FatcatAPI) HandlerFor(method, path string) (http.Handler, bool) {
+ if o.handlers == nil {
+ return nil, false
+ }
+ um := strings.ToUpper(method)
+ if _, ok := o.handlers[um]; !ok {
+ return nil, false
+ }
+ if path == "/" {
+ path = ""
+ }
+ h, ok := o.handlers[um][path]
+ return h, ok
+}
+
+// Context returns the middleware context for the fatcat API
+func (o *FatcatAPI) Context() *middleware.Context {
+ if o.context == nil {
+ o.context = middleware.NewRoutableContext(o.spec, o, nil)
+ }
+
+ return o.context
+}
+
+func (o *FatcatAPI) initHandlerCache() {
+ o.Context() // don't care about the result, just that the initialization happened
+
+ if o.handlers == nil {
+ o.handlers = make(map[string]map[string]http.Handler)
+ }
+
+ if o.handlers["GET"] == nil {
+ o.handlers["GET"] = make(map[string]http.Handler)
+ }
+ o.handlers["GET"]["/creator/{id}"] = NewGetCreatorID(o.context, o.GetCreatorIDHandler)
+
+ if o.handlers["POST"] == nil {
+ o.handlers["POST"] = make(map[string]http.Handler)
+ }
+ o.handlers["POST"]["/creator"] = NewPostCreator(o.context, o.PostCreatorHandler)
+
+}
+
+// Serve creates a http handler to serve the API over HTTP
+// can be used directly in http.ListenAndServe(":8000", api.Serve(nil))
+func (o *FatcatAPI) Serve(builder middleware.Builder) http.Handler {
+ o.Init()
+
+ if o.Middleware != nil {
+ return o.Middleware(builder)
+ }
+ return o.context.APIHandler(builder)
+}
+
+// Init allows you to just initialize the handler cache, you can then recompose the middleware as you see fit
+func (o *FatcatAPI) Init() {
+ if len(o.handlers) == 0 {
+ o.initHandlerCache()
+ }
+}
+
+// RegisterConsumer allows you to add (or override) a consumer for a media type.
+func (o *FatcatAPI) RegisterConsumer(mediaType string, consumer runtime.Consumer) {
+ o.customConsumers[mediaType] = consumer
+}
+
+// RegisterProducer allows you to add (or override) a producer for a media type.
+func (o *FatcatAPI) RegisterProducer(mediaType string, producer runtime.Producer) {
+ o.customProducers[mediaType] = producer
+}
diff --git a/golang/restapi/operations/get_creator_id.go b/golang/restapi/operations/get_creator_id.go
new file mode 100644
index 00000000..90185374
--- /dev/null
+++ b/golang/restapi/operations/get_creator_id.go
@@ -0,0 +1,58 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "net/http"
+
+ middleware "github.com/go-openapi/runtime/middleware"
+)
+
+// GetCreatorIDHandlerFunc turns a function with the right signature into a get creator ID handler
+type GetCreatorIDHandlerFunc func(GetCreatorIDParams) middleware.Responder
+
+// Handle executing the request and returning a response
+func (fn GetCreatorIDHandlerFunc) Handle(params GetCreatorIDParams) middleware.Responder {
+ return fn(params)
+}
+
+// GetCreatorIDHandler interface for that can handle valid get creator ID params
+type GetCreatorIDHandler interface {
+ Handle(GetCreatorIDParams) middleware.Responder
+}
+
+// NewGetCreatorID creates a new http.Handler for the get creator ID operation
+func NewGetCreatorID(ctx *middleware.Context, handler GetCreatorIDHandler) *GetCreatorID {
+ return &GetCreatorID{Context: ctx, Handler: handler}
+}
+
+/*GetCreatorID swagger:route GET /creator/{id} getCreatorId
+
+GetCreatorID get creator ID API
+
+*/
+type GetCreatorID struct {
+ Context *middleware.Context
+ Handler GetCreatorIDHandler
+}
+
+func (o *GetCreatorID) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ route, rCtx, _ := o.Context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
+ }
+ var Params = NewGetCreatorIDParams()
+
+ if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+
+ res := o.Handler.Handle(Params) // actually handle the request
+
+ o.Context.Respond(rw, r, route.Produces, route, res)
+
+}
diff --git a/golang/restapi/operations/get_creator_id_parameters.go b/golang/restapi/operations/get_creator_id_parameters.go
new file mode 100644
index 00000000..f1e338b6
--- /dev/null
+++ b/golang/restapi/operations/get_creator_id_parameters.go
@@ -0,0 +1,72 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime/middleware"
+
+ strfmt "github.com/go-openapi/strfmt"
+)
+
+// NewGetCreatorIDParams creates a new GetCreatorIDParams object
+// no default values defined in spec.
+func NewGetCreatorIDParams() GetCreatorIDParams {
+
+ return GetCreatorIDParams{}
+}
+
+// GetCreatorIDParams contains all the bound params for the get creator ID operation
+// typically these are obtained from a http.Request
+//
+// swagger:parameters GetCreatorID
+type GetCreatorIDParams struct {
+
+ // HTTP Request Object
+ HTTPRequest *http.Request `json:"-"`
+
+ /*
+ Required: true
+ In: path
+ */
+ ID string
+}
+
+// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
+// for simple values it will use straight method calls.
+//
+// To ensure default values, the struct must have been initialized with NewGetCreatorIDParams() beforehand.
+func (o *GetCreatorIDParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
+ var res []error
+
+ o.HTTPRequest = r
+
+ rID, rhkID, _ := route.Params.GetOK("id")
+ if err := o.bindID(rID, rhkID, route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
+
+func (o *GetCreatorIDParams) bindID(rawData []string, hasKey bool, formats strfmt.Registry) error {
+ var raw string
+ if len(rawData) > 0 {
+ raw = rawData[len(rawData)-1]
+ }
+
+ // Required: true
+ // Parameter is provided by construction from the route
+
+ o.ID = raw
+
+ return nil
+}
diff --git a/golang/restapi/operations/get_creator_id_responses.go b/golang/restapi/operations/get_creator_id_responses.go
new file mode 100644
index 00000000..42fe1de6
--- /dev/null
+++ b/golang/restapi/operations/get_creator_id_responses.go
@@ -0,0 +1,116 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime"
+
+ models "git.archive.org/bnewbold/fatcat/models"
+)
+
+// GetCreatorIDOKCode is the HTTP code returned for type GetCreatorIDOK
+const GetCreatorIDOKCode int = 200
+
+/*GetCreatorIDOK fetch a single creator by id
+
+swagger:response getCreatorIdOK
+*/
+type GetCreatorIDOK struct {
+
+ /*
+ In: Body
+ */
+ Payload *models.CreatorEntity `json:"body,omitempty"`
+}
+
+// NewGetCreatorIDOK creates GetCreatorIDOK with default headers values
+func NewGetCreatorIDOK() *GetCreatorIDOK {
+
+ return &GetCreatorIDOK{}
+}
+
+// WithPayload adds the payload to the get creator Id o k response
+func (o *GetCreatorIDOK) WithPayload(payload *models.CreatorEntity) *GetCreatorIDOK {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the get creator Id o k response
+func (o *GetCreatorIDOK) SetPayload(payload *models.CreatorEntity) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *GetCreatorIDOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(200)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
+
+/*GetCreatorIDDefault generic error response
+
+swagger:response getCreatorIdDefault
+*/
+type GetCreatorIDDefault struct {
+ _statusCode int
+
+ /*
+ In: Body
+ */
+ Payload *models.Error `json:"body,omitempty"`
+}
+
+// NewGetCreatorIDDefault creates GetCreatorIDDefault with default headers values
+func NewGetCreatorIDDefault(code int) *GetCreatorIDDefault {
+ if code <= 0 {
+ code = 500
+ }
+
+ return &GetCreatorIDDefault{
+ _statusCode: code,
+ }
+}
+
+// WithStatusCode adds the status to the get creator ID default response
+func (o *GetCreatorIDDefault) WithStatusCode(code int) *GetCreatorIDDefault {
+ o._statusCode = code
+ return o
+}
+
+// SetStatusCode sets the status to the get creator ID default response
+func (o *GetCreatorIDDefault) SetStatusCode(code int) {
+ o._statusCode = code
+}
+
+// WithPayload adds the payload to the get creator ID default response
+func (o *GetCreatorIDDefault) WithPayload(payload *models.Error) *GetCreatorIDDefault {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the get creator ID default response
+func (o *GetCreatorIDDefault) SetPayload(payload *models.Error) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *GetCreatorIDDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(o._statusCode)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
diff --git a/golang/restapi/operations/get_creator_id_urlbuilder.go b/golang/restapi/operations/get_creator_id_urlbuilder.go
new file mode 100644
index 00000000..8f23373f
--- /dev/null
+++ b/golang/restapi/operations/get_creator_id_urlbuilder.go
@@ -0,0 +1,99 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "errors"
+ "net/url"
+ golangswaggerpaths "path"
+ "strings"
+)
+
+// GetCreatorIDURL generates an URL for the get creator ID operation
+type GetCreatorIDURL struct {
+ ID string
+
+ _basePath string
+ // avoid unkeyed usage
+ _ struct{}
+}
+
+// WithBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *GetCreatorIDURL) WithBasePath(bp string) *GetCreatorIDURL {
+ o.SetBasePath(bp)
+ return o
+}
+
+// SetBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *GetCreatorIDURL) SetBasePath(bp string) {
+ o._basePath = bp
+}
+
+// Build a url path and query string
+func (o *GetCreatorIDURL) Build() (*url.URL, error) {
+ var result url.URL
+
+ var _path = "/creator/{id}"
+
+ id := o.ID
+ if id != "" {
+ _path = strings.Replace(_path, "{id}", id, -1)
+ } else {
+ return nil, errors.New("ID is required on GetCreatorIDURL")
+ }
+
+ _basePath := o._basePath
+ if _basePath == "" {
+ _basePath = "/v0"
+ }
+ result.Path = golangswaggerpaths.Join(_basePath, _path)
+
+ return &result, nil
+}
+
+// Must is a helper function to panic when the url builder returns an error
+func (o *GetCreatorIDURL) Must(u *url.URL, err error) *url.URL {
+ if err != nil {
+ panic(err)
+ }
+ if u == nil {
+ panic("url can't be nil")
+ }
+ return u
+}
+
+// String returns the string representation of the path with query string
+func (o *GetCreatorIDURL) String() string {
+ return o.Must(o.Build()).String()
+}
+
+// BuildFull builds a full url with scheme, host, path and query string
+func (o *GetCreatorIDURL) BuildFull(scheme, host string) (*url.URL, error) {
+ if scheme == "" {
+ return nil, errors.New("scheme is required for a full url on GetCreatorIDURL")
+ }
+ if host == "" {
+ return nil, errors.New("host is required for a full url on GetCreatorIDURL")
+ }
+
+ base, err := o.Build()
+ if err != nil {
+ return nil, err
+ }
+
+ base.Scheme = scheme
+ base.Host = host
+ return base, nil
+}
+
+// StringFull returns the string representation of a complete url
+func (o *GetCreatorIDURL) StringFull(scheme, host string) string {
+ return o.Must(o.BuildFull(scheme, host)).String()
+}
diff --git a/golang/restapi/operations/post_creator.go b/golang/restapi/operations/post_creator.go
new file mode 100644
index 00000000..b33694f1
--- /dev/null
+++ b/golang/restapi/operations/post_creator.go
@@ -0,0 +1,58 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "net/http"
+
+ middleware "github.com/go-openapi/runtime/middleware"
+)
+
+// PostCreatorHandlerFunc turns a function with the right signature into a post creator handler
+type PostCreatorHandlerFunc func(PostCreatorParams) middleware.Responder
+
+// Handle executing the request and returning a response
+func (fn PostCreatorHandlerFunc) Handle(params PostCreatorParams) middleware.Responder {
+ return fn(params)
+}
+
+// PostCreatorHandler interface for that can handle valid post creator params
+type PostCreatorHandler interface {
+ Handle(PostCreatorParams) middleware.Responder
+}
+
+// NewPostCreator creates a new http.Handler for the post creator operation
+func NewPostCreator(ctx *middleware.Context, handler PostCreatorHandler) *PostCreator {
+ return &PostCreator{Context: ctx, Handler: handler}
+}
+
+/*PostCreator swagger:route POST /creator postCreator
+
+PostCreator post creator API
+
+*/
+type PostCreator struct {
+ Context *middleware.Context
+ Handler PostCreatorHandler
+}
+
+func (o *PostCreator) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ route, rCtx, _ := o.Context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
+ }
+ var Params = NewPostCreatorParams()
+
+ if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+
+ res := o.Handler.Handle(Params) // actually handle the request
+
+ o.Context.Respond(rw, r, route.Produces, route, res)
+
+}
diff --git a/golang/restapi/operations/post_creator_parameters.go b/golang/restapi/operations/post_creator_parameters.go
new file mode 100644
index 00000000..68fcf1a2
--- /dev/null
+++ b/golang/restapi/operations/post_creator_parameters.go
@@ -0,0 +1,70 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/middleware"
+
+ models "git.archive.org/bnewbold/fatcat/models"
+)
+
+// NewPostCreatorParams creates a new PostCreatorParams object
+// no default values defined in spec.
+func NewPostCreatorParams() PostCreatorParams {
+
+ return PostCreatorParams{}
+}
+
+// PostCreatorParams contains all the bound params for the post creator operation
+// typically these are obtained from a http.Request
+//
+// swagger:parameters PostCreator
+type PostCreatorParams struct {
+
+ // HTTP Request Object
+ HTTPRequest *http.Request `json:"-"`
+
+ /*
+ In: body
+ */
+ Body *models.CreatorEntity
+}
+
+// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
+// for simple values it will use straight method calls.
+//
+// To ensure default values, the struct must have been initialized with NewPostCreatorParams() beforehand.
+func (o *PostCreatorParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
+ var res []error
+
+ o.HTTPRequest = r
+
+ if runtime.HasBody(r) {
+ defer r.Body.Close()
+ var body models.CreatorEntity
+ if err := route.Consumer.Consume(r.Body, &body); err != nil {
+ res = append(res, errors.NewParseError("body", "body", "", err))
+ } else {
+
+ // validate body object
+ if err := body.Validate(route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) == 0 {
+ o.Body = &body
+ }
+ }
+ }
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
diff --git a/golang/restapi/operations/post_creator_responses.go b/golang/restapi/operations/post_creator_responses.go
new file mode 100644
index 00000000..08014441
--- /dev/null
+++ b/golang/restapi/operations/post_creator_responses.go
@@ -0,0 +1,116 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime"
+
+ models "git.archive.org/bnewbold/fatcat/models"
+)
+
+// PostCreatorCreatedCode is the HTTP code returned for type PostCreatorCreated
+const PostCreatorCreatedCode int = 201
+
+/*PostCreatorCreated created
+
+swagger:response postCreatorCreated
+*/
+type PostCreatorCreated struct {
+
+ /*
+ In: Body
+ */
+ Payload *models.CreatorEntity `json:"body,omitempty"`
+}
+
+// NewPostCreatorCreated creates PostCreatorCreated with default headers values
+func NewPostCreatorCreated() *PostCreatorCreated {
+
+ return &PostCreatorCreated{}
+}
+
+// WithPayload adds the payload to the post creator created response
+func (o *PostCreatorCreated) WithPayload(payload *models.CreatorEntity) *PostCreatorCreated {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the post creator created response
+func (o *PostCreatorCreated) SetPayload(payload *models.CreatorEntity) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *PostCreatorCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(201)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
+
+/*PostCreatorDefault generic error response
+
+swagger:response postCreatorDefault
+*/
+type PostCreatorDefault struct {
+ _statusCode int
+
+ /*
+ In: Body
+ */
+ Payload *models.Error `json:"body,omitempty"`
+}
+
+// NewPostCreatorDefault creates PostCreatorDefault with default headers values
+func NewPostCreatorDefault(code int) *PostCreatorDefault {
+ if code <= 0 {
+ code = 500
+ }
+
+ return &PostCreatorDefault{
+ _statusCode: code,
+ }
+}
+
+// WithStatusCode adds the status to the post creator default response
+func (o *PostCreatorDefault) WithStatusCode(code int) *PostCreatorDefault {
+ o._statusCode = code
+ return o
+}
+
+// SetStatusCode sets the status to the post creator default response
+func (o *PostCreatorDefault) SetStatusCode(code int) {
+ o._statusCode = code
+}
+
+// WithPayload adds the payload to the post creator default response
+func (o *PostCreatorDefault) WithPayload(payload *models.Error) *PostCreatorDefault {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the post creator default response
+func (o *PostCreatorDefault) SetPayload(payload *models.Error) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *PostCreatorDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(o._statusCode)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
diff --git a/golang/restapi/operations/post_creator_urlbuilder.go b/golang/restapi/operations/post_creator_urlbuilder.go
new file mode 100644
index 00000000..901edeb6
--- /dev/null
+++ b/golang/restapi/operations/post_creator_urlbuilder.go
@@ -0,0 +1,87 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package operations
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "errors"
+ "net/url"
+ golangswaggerpaths "path"
+)
+
+// PostCreatorURL generates an URL for the post creator operation
+type PostCreatorURL struct {
+ _basePath string
+}
+
+// WithBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *PostCreatorURL) WithBasePath(bp string) *PostCreatorURL {
+ o.SetBasePath(bp)
+ return o
+}
+
+// SetBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *PostCreatorURL) SetBasePath(bp string) {
+ o._basePath = bp
+}
+
+// Build a url path and query string
+func (o *PostCreatorURL) Build() (*url.URL, error) {
+ var result url.URL
+
+ var _path = "/creator"
+
+ _basePath := o._basePath
+ if _basePath == "" {
+ _basePath = "/v0"
+ }
+ result.Path = golangswaggerpaths.Join(_basePath, _path)
+
+ return &result, nil
+}
+
+// Must is a helper function to panic when the url builder returns an error
+func (o *PostCreatorURL) Must(u *url.URL, err error) *url.URL {
+ if err != nil {
+ panic(err)
+ }
+ if u == nil {
+ panic("url can't be nil")
+ }
+ return u
+}
+
+// String returns the string representation of the path with query string
+func (o *PostCreatorURL) String() string {
+ return o.Must(o.Build()).String()
+}
+
+// BuildFull builds a full url with scheme, host, path and query string
+func (o *PostCreatorURL) BuildFull(scheme, host string) (*url.URL, error) {
+ if scheme == "" {
+ return nil, errors.New("scheme is required for a full url on PostCreatorURL")
+ }
+ if host == "" {
+ return nil, errors.New("host is required for a full url on PostCreatorURL")
+ }
+
+ base, err := o.Build()
+ if err != nil {
+ return nil, err
+ }
+
+ base.Scheme = scheme
+ base.Host = host
+ return base, nil
+}
+
+// StringFull returns the string representation of a complete url
+func (o *PostCreatorURL) StringFull(scheme, host string) string {
+ return o.Must(o.BuildFull(scheme, host)).String()
+}
diff --git a/golang/restapi/server.go b/golang/restapi/server.go
new file mode 100644
index 00000000..4a5f51f1
--- /dev/null
+++ b/golang/restapi/server.go
@@ -0,0 +1,448 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package restapi
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-openapi/runtime/flagext"
+ "github.com/go-openapi/swag"
+ flags "github.com/jessevdk/go-flags"
+ graceful "github.com/tylerb/graceful"
+
+ "git.archive.org/bnewbold/fatcat/restapi/operations"
+)
+
+const (
+ schemeHTTP = "http"
+ schemeHTTPS = "https"
+ schemeUnix = "unix"
+)
+
+var defaultSchemes []string
+
+func init() {
+ defaultSchemes = []string{
+ schemeHTTP,
+ schemeHTTPS,
+ }
+}
+
+// NewServer creates a new api fatcat server but does not configure it
+func NewServer(api *operations.FatcatAPI) *Server {
+ s := new(Server)
+
+ s.shutdown = make(chan struct{})
+ s.api = api
+ return s
+}
+
+// ConfigureAPI configures the API and handlers.
+func (s *Server) ConfigureAPI() {
+ if s.api != nil {
+ s.handler = configureAPI(s.api)
+ }
+}
+
+// ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
+func (s *Server) ConfigureFlags() {
+ if s.api != nil {
+ configureFlags(s.api)
+ }
+}
+
+// Server for the fatcat API
+type Server struct {
+ EnabledListeners []string `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`
+ CleanupTimeout time.Duration `long:"cleanup-timeout" description:"grace period for which to wait before shutting down the server" default:"10s"`
+ MaxHeaderSize flagext.ByteSize `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`
+
+ SocketPath flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/fatcat.sock"`
+ domainSocketL net.Listener
+
+ Host string `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`
+ Port int `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`
+ ListenLimit int `long:"listen-limit" description:"limit the number of outstanding requests"`
+ KeepAlive time.Duration `long:"keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)" default:"3m"`
+ ReadTimeout time.Duration `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`
+ WriteTimeout time.Duration `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`
+ httpServerL net.Listener
+
+ TLSHost string `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`
+ TLSPort int `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`
+ TLSCertificate flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`
+ TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure conections" env:"TLS_PRIVATE_KEY"`
+ TLSCACertificate flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`
+ TLSListenLimit int `long:"tls-listen-limit" description:"limit the number of outstanding requests"`
+ TLSKeepAlive time.Duration `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`
+ TLSReadTimeout time.Duration `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`
+ TLSWriteTimeout time.Duration `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`
+ httpsServerL net.Listener
+
+ api *operations.FatcatAPI
+ handler http.Handler
+ hasListeners bool
+ shutdown chan struct{}
+ shuttingDown int32
+}
+
+// Logf logs message either via defined user logger or via system one if no user logger is defined.
+func (s *Server) Logf(f string, args ...interface{}) {
+ if s.api != nil && s.api.Logger != nil {
+ s.api.Logger(f, args...)
+ } else {
+ log.Printf(f, args...)
+ }
+}
+
+// Fatalf logs message either via defined user logger or via system one if no user logger is defined.
+// Exits with non-zero status after printing
+func (s *Server) Fatalf(f string, args ...interface{}) {
+ if s.api != nil && s.api.Logger != nil {
+ s.api.Logger(f, args...)
+ os.Exit(1)
+ } else {
+ log.Fatalf(f, args...)
+ }
+}
+
+// SetAPI configures the server with the specified API. Needs to be called before Serve
+func (s *Server) SetAPI(api *operations.FatcatAPI) {
+ if api == nil {
+ s.api = nil
+ s.handler = nil
+ return
+ }
+
+ s.api = api
+ s.api.Logger = log.Printf
+ s.handler = configureAPI(api)
+}
+
+func (s *Server) hasScheme(scheme string) bool {
+ schemes := s.EnabledListeners
+ if len(schemes) == 0 {
+ schemes = defaultSchemes
+ }
+
+ for _, v := range schemes {
+ if v == scheme {
+ return true
+ }
+ }
+ return false
+}
+
+// Serve the api
+func (s *Server) Serve() (err error) {
+ if !s.hasListeners {
+ if err = s.Listen(); err != nil {
+ return err
+ }
+ }
+
+ // set default handler, if none is set
+ if s.handler == nil {
+ if s.api == nil {
+ return errors.New("can't create the default handler, as no api is set")
+ }
+
+ s.SetHandler(s.api.Serve(nil))
+ }
+
+ var wg sync.WaitGroup
+
+ if s.hasScheme(schemeUnix) {
+ domainSocket := &graceful.Server{Server: new(http.Server)}
+ domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
+ domainSocket.Handler = s.handler
+ domainSocket.LogFunc = s.Logf
+ if int64(s.CleanupTimeout) > 0 {
+ domainSocket.Timeout = s.CleanupTimeout
+ }
+
+ configureServer(domainSocket, "unix", string(s.SocketPath))
+
+ wg.Add(2)
+ s.Logf("Serving fatcat at unix://%s", s.SocketPath)
+ go func(l net.Listener) {
+ defer wg.Done()
+ if err := domainSocket.Serve(l); err != nil {
+ s.Fatalf("%v", err)
+ }
+ s.Logf("Stopped serving fatcat at unix://%s", s.SocketPath)
+ }(s.domainSocketL)
+ go s.handleShutdown(&wg, domainSocket)
+ }
+
+ if s.hasScheme(schemeHTTP) {
+ httpServer := &graceful.Server{Server: new(http.Server)}
+ httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
+ httpServer.ReadTimeout = s.ReadTimeout
+ httpServer.WriteTimeout = s.WriteTimeout
+ httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
+ httpServer.TCPKeepAlive = s.KeepAlive
+ if s.ListenLimit > 0 {
+ httpServer.ListenLimit = s.ListenLimit
+ }
+
+ if int64(s.CleanupTimeout) > 0 {
+ httpServer.Timeout = s.CleanupTimeout
+ }
+
+ httpServer.Handler = s.handler
+ httpServer.LogFunc = s.Logf
+
+ configureServer(httpServer, "http", s.httpServerL.Addr().String())
+
+ wg.Add(2)
+ s.Logf("Serving fatcat at http://%s", s.httpServerL.Addr())
+ go func(l net.Listener) {
+ defer wg.Done()
+ if err := httpServer.Serve(l); err != nil {
+ s.Fatalf("%v", err)
+ }
+ s.Logf("Stopped serving fatcat at http://%s", l.Addr())
+ }(s.httpServerL)
+ go s.handleShutdown(&wg, httpServer)
+ }
+
+ if s.hasScheme(schemeHTTPS) {
+ httpsServer := &graceful.Server{Server: new(http.Server)}
+ httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
+ httpsServer.ReadTimeout = s.TLSReadTimeout
+ httpsServer.WriteTimeout = s.TLSWriteTimeout
+ httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
+ httpsServer.TCPKeepAlive = s.TLSKeepAlive
+ if s.TLSListenLimit > 0 {
+ httpsServer.ListenLimit = s.TLSListenLimit
+ }
+ if int64(s.CleanupTimeout) > 0 {
+ httpsServer.Timeout = s.CleanupTimeout
+ }
+ httpsServer.Handler = s.handler
+ httpsServer.LogFunc = s.Logf
+
+ // Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
+ httpsServer.TLSConfig = &tls.Config{
+ // Causes servers to use Go's default ciphersuite preferences,
+ // which are tuned to avoid attacks. Does nothing on clients.
+ PreferServerCipherSuites: true,
+ // Only use curves which have assembly implementations
+ // https://github.com/golang/go/tree/master/src/crypto/elliptic
+ CurvePreferences: []tls.CurveID{tls.CurveP256},
+ // Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
+ NextProtos: []string{"http/1.1", "h2"},
+ // https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
+ MinVersion: tls.VersionTLS12,
+ // These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
+ CipherSuites: []uint16{
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ }
+
+ if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
+ httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
+ httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(string(s.TLSCertificate), string(s.TLSCertificateKey))
+ }
+
+ if s.TLSCACertificate != "" {
+ caCert, caCertErr := ioutil.ReadFile(string(s.TLSCACertificate))
+ if caCertErr != nil {
+ log.Fatal(caCertErr)
+ }
+ caCertPool := x509.NewCertPool()
+ caCertPool.AppendCertsFromPEM(caCert)
+ httpsServer.TLSConfig.ClientCAs = caCertPool
+ httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
+ }
+
+ configureTLS(httpsServer.TLSConfig)
+ httpsServer.TLSConfig.BuildNameToCertificate()
+
+ if err != nil {
+ return err
+ }
+
+ if len(httpsServer.TLSConfig.Certificates) == 0 {
+ if s.TLSCertificate == "" {
+ if s.TLSCertificateKey == "" {
+ s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
+ }
+ s.Fatalf("the required flag `--tls-certificate` was not specified")
+ }
+ if s.TLSCertificateKey == "" {
+ s.Fatalf("the required flag `--tls-key` was not specified")
+ }
+ }
+
+ configureServer(httpsServer, "https", s.httpsServerL.Addr().String())
+
+ wg.Add(2)
+ s.Logf("Serving fatcat at https://%s", s.httpsServerL.Addr())
+ go func(l net.Listener) {
+ defer wg.Done()
+ if err := httpsServer.Serve(l); err != nil {
+ s.Fatalf("%v", err)
+ }
+ s.Logf("Stopped serving fatcat at https://%s", l.Addr())
+ }(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig))
+ go s.handleShutdown(&wg, httpsServer)
+ }
+
+ wg.Wait()
+ return nil
+}
+
+// Listen creates the listeners for the server
+func (s *Server) Listen() error {
+ if s.hasListeners { // already done this
+ return nil
+ }
+
+ if s.hasScheme(schemeHTTPS) {
+ // Use http host if https host wasn't defined
+ if s.TLSHost == "" {
+ s.TLSHost = s.Host
+ }
+ // Use http listen limit if https listen limit wasn't defined
+ if s.TLSListenLimit == 0 {
+ s.TLSListenLimit = s.ListenLimit
+ }
+ // Use http tcp keep alive if https tcp keep alive wasn't defined
+ if int64(s.TLSKeepAlive) == 0 {
+ s.TLSKeepAlive = s.KeepAlive
+ }
+ // Use http read timeout if https read timeout wasn't defined
+ if int64(s.TLSReadTimeout) == 0 {
+ s.TLSReadTimeout = s.ReadTimeout
+ }
+ // Use http write timeout if https write timeout wasn't defined
+ if int64(s.TLSWriteTimeout) == 0 {
+ s.TLSWriteTimeout = s.WriteTimeout
+ }
+ }
+
+ if s.hasScheme(schemeUnix) {
+ domSockListener, err := net.Listen("unix", string(s.SocketPath))
+ if err != nil {
+ return err
+ }
+ s.domainSocketL = domSockListener
+ }
+
+ if s.hasScheme(schemeHTTP) {
+ listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)))
+ if err != nil {
+ return err
+ }
+
+ h, p, err := swag.SplitHostPort(listener.Addr().String())
+ if err != nil {
+ return err
+ }
+ s.Host = h
+ s.Port = p
+ s.httpServerL = listener
+ }
+
+ if s.hasScheme(schemeHTTPS) {
+ tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort)))
+ if err != nil {
+ return err
+ }
+
+ sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
+ if err != nil {
+ return err
+ }
+ s.TLSHost = sh
+ s.TLSPort = sp
+ s.httpsServerL = tlsListener
+ }
+
+ s.hasListeners = true
+ return nil
+}
+
+// Shutdown server and clean up resources
+func (s *Server) Shutdown() error {
+ if atomic.LoadInt32(&s.shuttingDown) != 0 {
+ s.Logf("already shutting down")
+ return nil
+ }
+ s.shutdown <- struct{}{}
+ return nil
+}
+
+func (s *Server) handleShutdown(wg *sync.WaitGroup, server *graceful.Server) {
+ defer wg.Done()
+ for {
+ select {
+ case <-s.shutdown:
+ atomic.AddInt32(&s.shuttingDown, 1)
+ server.Stop(s.CleanupTimeout)
+ <-server.StopChan()
+ s.api.ServerShutdown()
+ return
+ case <-server.StopChan():
+ atomic.AddInt32(&s.shuttingDown, 1)
+ s.api.ServerShutdown()
+ return
+ }
+ }
+}
+
+// GetHandler returns a handler useful for testing
+func (s *Server) GetHandler() http.Handler {
+ return s.handler
+}
+
+// SetHandler allows for setting a http handler on this server
+func (s *Server) SetHandler(handler http.Handler) {
+ s.handler = handler
+}
+
+// UnixListener returns the domain socket listener
+func (s *Server) UnixListener() (net.Listener, error) {
+ if !s.hasListeners {
+ if err := s.Listen(); err != nil {
+ return nil, err
+ }
+ }
+ return s.domainSocketL, nil
+}
+
+// HTTPListener returns the http listener
+func (s *Server) HTTPListener() (net.Listener, error) {
+ if !s.hasListeners {
+ if err := s.Listen(); err != nil {
+ return nil, err
+ }
+ }
+ return s.httpServerL, nil
+}
+
+// TLSListener returns the https listener
+func (s *Server) TLSListener() (net.Listener, error) {
+ if !s.hasListeners {
+ if err := s.Listen(); err != nil {
+ return nil, err
+ }
+ }
+ return s.httpsServerL, nil
+}