Compare commits

..

6 Commits

4 changed files with 55 additions and 10 deletions

6
api/adapter.go Normal file
View File

@ -0,0 +1,6 @@
package api
import "net/http"
// Adapter to encapsulate incoming requests
type Adapter func(http.HandlerFunc) http.HandlerFunc

View File

@ -5,6 +5,7 @@ import (
"io" "io"
"net/http" "net/http"
"git.xdrm.io/go/aicra/api"
"git.xdrm.io/go/aicra/datatype" "git.xdrm.io/go/aicra/datatype"
"git.xdrm.io/go/aicra/internal/config" "git.xdrm.io/go/aicra/internal/config"
"git.xdrm.io/go/aicra/internal/dynfunc" "git.xdrm.io/go/aicra/internal/dynfunc"
@ -14,6 +15,7 @@ import (
type Builder struct { type Builder struct {
conf *config.Server conf *config.Server
handlers []*apiHandler handlers []*apiHandler
adapters []api.Adapter
} }
// represents an api handler (method-pattern combination) // represents an api handler (method-pattern combination)
@ -31,9 +33,23 @@ func (b *Builder) AddType(t datatype.T) {
if b.conf.Services != nil { if b.conf.Services != nil {
panic(errLateType) panic(errLateType)
} }
if b.conf.Types == nil {
b.conf.Types = make([]datatype.T, 0)
}
b.conf.Types = append(b.conf.Types, t) b.conf.Types = append(b.conf.Types, t)
} }
// Use adds an http adapter (middleware)
func (b *Builder) Use(adapter api.Adapter) {
if b.conf == nil {
b.conf = &config.Server{}
}
if b.adapters == nil {
b.adapters = make([]api.Adapter, 0)
}
b.adapters = append(b.adapters, adapter)
}
// Setup the builder with its api definition file // Setup the builder with its api definition file
// panics if already setup // panics if already setup
func (b *Builder) Setup(r io.Reader) error { func (b *Builder) Setup(r io.Reader) error {

View File

@ -1,7 +1,6 @@
package aicra package aicra
import ( import (
"log"
"net/http" "net/http"
"git.xdrm.io/go/aicra/api" "git.xdrm.io/go/aicra/api"
@ -12,17 +11,17 @@ import (
// Handler wraps the builder to handle requests // Handler wraps the builder to handle requests
type Handler Builder type Handler Builder
// ServeHTTP implements http.Handler // ServeHTTP implements http.Handler and wraps it in middlewares (adapters)
func (s Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer func() { var h = http.HandlerFunc(s.handleRequest)
if rc := recover(); rc != nil {
log.Printf("recovering request: %s\n", rc)
// try to send error response
api.EmptyResponse().WithError(api.ErrUncallableService).ServeHTTP(w, r)
}
}()
defer r.Body.Close()
for _, adapter := range s.adapters {
h = adapter(h)
}
h(w, r)
}
func (s Handler) handleRequest(w http.ResponseWriter, r *http.Request) {
// 1. find a matching service from config // 1. find a matching service from config
var service = s.conf.Find(r) var service = s.conf.Find(r)
if service == nil { if service == nil {

View File

@ -2,6 +2,7 @@ package dynfunc
import ( import (
"fmt" "fmt"
"log"
"reflect" "reflect"
"git.xdrm.io/go/aicra/api" "git.xdrm.io/go/aicra/api"
@ -70,6 +71,29 @@ func (h *Handler) Handle(data map[string]interface{}) (map[string]interface{}, a
if !inData { if !inData {
continue continue
} }
var refvalue = reflect.ValueOf(value)
// T to pointer of T
if field.Kind() == reflect.Ptr {
var ptrType = field.Type().Elem()
if !refvalue.Type().ConvertibleTo(ptrType) {
log.Printf("Cannot convert %v into %v", refvalue.Type(), ptrType)
return nil, api.ErrUncallableService
}
ptr := reflect.New(ptrType)
ptr.Elem().Set(reflect.ValueOf(value).Convert(ptrType))
field.Set(ptr)
continue
}
if !reflect.ValueOf(value).Type().ConvertibleTo(field.Type()) {
log.Printf("Cannot convert %v into %v", reflect.ValueOf(value).Type(), field.Type())
return nil, api.ErrUncallableService
}
field.Set(reflect.ValueOf(value).Convert(field.Type())) field.Set(reflect.ValueOf(value).Convert(field.Type()))
} }
callArgs = append(callArgs, callStruct) callArgs = append(callArgs, callStruct)