rewrite api package

This commit is contained in:
Asim Aslam
2020-10-17 15:33:56 +01:00
parent f2728a7fee
commit 975da990a9
13 changed files with 44 additions and 164 deletions

View File

@@ -7,7 +7,7 @@ import (
"net"
"os"
"github.com/micro/go-micro/v3/api/server/acme"
"github.com/micro/go-micro/v3/api/acme"
"github.com/micro/go-micro/v3/logger"
"golang.org/x/crypto/acme/autocert"
)

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/caddyserver/certmagic"
"github.com/micro/go-micro/v3/api/server/acme"
"github.com/micro/go-micro/v3/api/acme"
"github.com/micro/go-micro/v3/logger"
)

View File

@@ -2,6 +2,7 @@ package api
import (
"errors"
"net/http"
"regexp"
"strings"
@@ -9,23 +10,24 @@ import (
"github.com/micro/go-micro/v3/server"
)
type Api interface {
// Gateway is an api gateway interface
type Gateway interface {
// Initialise options
Init(...Option) error
// Get the options
Options() Options
// Register a http handler
// Register an endpoint
Register(*Endpoint) error
// Register a route
// Deregister a route
Deregister(*Endpoint) error
// Register http handler
Handle(path string, hd http.Handler)
// Start serving requests
Serve() error
// Implementation of api
String() string
}
type Options struct{}
type Option func(*Options) error
// Endpoint is a mapping between an RPC method and HTTP endpoint
type Endpoint struct {
// RPC Method e.g. Greeter.Hello

View File

@@ -5,70 +5,62 @@ import (
"crypto/tls"
"net"
"net/http"
"os"
"sync"
"github.com/gorilla/handlers"
"github.com/micro/go-micro/v3/api/server"
"github.com/micro/go-micro/v3/api/server/cors"
"github.com/micro/go-micro/v3/api"
"github.com/micro/go-micro/v3/logger"
)
type httpServer struct {
mux *http.ServeMux
opts server.Options
opts api.Options
mtx sync.RWMutex
address string
exit chan chan error
}
func NewServer(address string, opts ...server.Option) server.Server {
var options server.Options
// NewGateway returns a new HTTP api gateway
func NewGateway(opts ...api.Option) api.Gateway {
var options api.Options
for _, o := range opts {
o(&options)
}
return &httpServer{
opts: options,
mux: http.NewServeMux(),
address: address,
exit: make(chan chan error),
opts: options,
mux: http.NewServeMux(),
exit: make(chan chan error),
}
}
func (s *httpServer) Address() string {
s.mtx.RLock()
defer s.mtx.RUnlock()
return s.address
}
func (s *httpServer) Init(opts ...server.Option) error {
func (s *httpServer) Init(opts ...api.Option) error {
for _, o := range opts {
o(&s.opts)
}
return nil
}
func (s *httpServer) Options() api.Options {
return s.opts
}
func (s *httpServer) Register(ep *api.Endpoint) error { return nil }
func (s *httpServer) Deregister(ep *api.Endpoint) error { return nil }
func (s *httpServer) Handle(path string, handler http.Handler) {
// TODO: move this stuff out to one place with ServeHTTP
// apply the wrappers, e.g. auth
for _, wrapper := range s.opts.Wrappers {
handler = wrapper(handler)
}
// wrap with cors
if s.opts.EnableCORS {
handler = cors.CombinedCORSHandler(handler)
}
// wrap with logger
handler = handlers.CombinedLoggingHandler(os.Stdout, handler)
s.mux.Handle(path, handler)
}
func (s *httpServer) Serve() error {
if err := s.Start(); err != nil {
return err
}
<-s.exit
return nil
}
func (s *httpServer) Start() error {
var l net.Listener
var err error
@@ -77,10 +69,10 @@ func (s *httpServer) Start() error {
// should we check the address to make sure its using :443?
l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
} else if s.opts.EnableTLS && s.opts.TLSConfig != nil {
l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig)
l, err = tls.Listen("tcp", s.opts.Address, s.opts.TLSConfig)
} else {
// otherwise plain listen
l, err = net.Listen("tcp", s.address)
l, err = net.Listen("tcp", s.opts.Address)
}
if err != nil {
return err
@@ -90,10 +82,6 @@ func (s *httpServer) Start() error {
logger.Infof("HTTP API Listening on %s", l.Addr().String())
}
s.mtx.Lock()
s.address = l.Addr().String()
s.mtx.Unlock()
go func() {
if err := http.Serve(l, s.mux); err != nil {
// temporary fix

View File

@@ -1,37 +1,27 @@
package server
package api
import (
"crypto/tls"
"net/http"
"github.com/micro/go-micro/v3/api/acme"
"github.com/micro/go-micro/v3/api/resolver"
"github.com/micro/go-micro/v3/api/server/acme"
)
type Option func(o *Options)
type Options struct {
Address string
EnableACME bool
EnableCORS bool
ACMEProvider acme.Provider
EnableTLS bool
ACMEHosts []string
TLSConfig *tls.Config
Resolver resolver.Resolver
Wrappers []Wrapper
}
type Wrapper func(h http.Handler) http.Handler
type Option func(o *Options)
func WrapHandler(w ...Wrapper) Option {
func Address(a string) Option {
return func(o *Options) {
o.Wrappers = append(o.Wrappers, w...)
}
}
func EnableCORS(b bool) Option {
return func(o *Options) {
o.EnableCORS = b
o.Address = a
}
}

View File

@@ -1,44 +0,0 @@
package cors
import (
"net/http"
)
// CombinedCORSHandler wraps a server and provides CORS headers
func CombinedCORSHandler(h http.Handler) http.Handler {
return corsHandler{h}
}
type corsHandler struct {
handler http.Handler
}
func (c corsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
SetHeaders(w, r)
if r.Method == "OPTIONS" {
return
}
c.handler.ServeHTTP(w, r)
}
// SetHeaders sets the CORS headers
func SetHeaders(w http.ResponseWriter, r *http.Request) {
set := func(w http.ResponseWriter, k, v string) {
if v := w.Header().Get(k); len(v) > 0 {
return
}
w.Header().Set(k, v)
}
if origin := r.Header.Get("Origin"); len(origin) > 0 {
set(w, "Access-Control-Allow-Origin", origin)
} else {
set(w, "Access-Control-Allow-Origin", "*")
}
set(w, "Access-Control-Allow-Credentials", "true")
set(w, "Access-Control-Allow-Methods", "POST, PATCH, GET, OPTIONS, PUT, DELETE")
set(w, "Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, Namespace")
}

View File

@@ -1,41 +0,0 @@
package http
import (
"fmt"
"io/ioutil"
"net/http"
"testing"
)
func TestHTTPServer(t *testing.T) {
testResponse := "hello world"
s := NewServer("localhost:0")
s.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, testResponse)
}))
if err := s.Start(); err != nil {
t.Fatal(err)
}
rsp, err := http.Get(fmt.Sprintf("http://%s/", s.Address()))
if err != nil {
t.Fatal(err)
}
defer rsp.Body.Close()
b, err := ioutil.ReadAll(rsp.Body)
if err != nil {
t.Fatal(err)
}
if string(b) != testResponse {
t.Fatalf("Unexpected response, got %s, expected %s", string(b), testResponse)
}
if err := s.Stop(); err != nil {
t.Fatal(err)
}
}

View File

@@ -1,15 +0,0 @@
// Package server provides an API gateway server which handles inbound requests
package server
import (
"net/http"
)
// Server serves api requests
type Server interface {
Address() string
Init(opts ...Option) error
Handle(path string, handler http.Handler)
Start() error
Stop() error
}