package restlet
|
|
|
|
import (
|
|
"database/sql"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/archsh/go.xql"
|
|
|
|
"cygnux.net/kepler/bucket"
|
|
"cygnux.net/kepler/cache"
|
|
"cygnux.net/kepler/config"
|
|
"cygnux.net/kepler/database"
|
|
"cygnux.net/kepler/kv"
|
|
)
|
|
|
|
type Parameters map[string]string
|
|
|
|
type ControlResult struct {
|
|
Total int64 `json:"total"`
|
|
Count int64 `json:"count"`
|
|
Offset int64 `json:"offset"`
|
|
Limit int64 `json:"limit"`
|
|
ProgressURL string `json:"progressUrl,omitempty"`
|
|
}
|
|
|
|
type DebugInfo struct {
|
|
Start int64
|
|
Finish int64
|
|
}
|
|
|
|
type Progress struct {
|
|
ID string `json:"id"`
|
|
Finished int `json:"finished"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
type Result struct {
|
|
Code uint `json:"code"`
|
|
Message string `json:"message,omitempty"`
|
|
ContentType string `json:"-"`
|
|
DataOnly bool `json:"-"`
|
|
RawBytes bool `json:"-"`
|
|
Cacheable bool `json:"-"`
|
|
Headers http.Header `json:"-"`
|
|
Cookies []*http.Cookie `json:"-"`
|
|
ETag string `json:"__eTag,omitempty"`
|
|
Debug *DebugInfo `json:"__debug,omitempty"`
|
|
Model string `json:"__model,omitempty"`
|
|
IsList bool `json:"__is_list,omitempty"`
|
|
Control *ControlResult `json:"__control,omitempty"`
|
|
Data interface{} `json:"data"`
|
|
}
|
|
|
|
type QueryController struct {
|
|
Offset int64
|
|
Limit int64
|
|
Debug bool
|
|
Includes []interface{}
|
|
Excludes []interface{}
|
|
OrderBy []interface{}
|
|
GroupBy []interface{}
|
|
Filters []interface{}
|
|
Params map[string]interface{}
|
|
}
|
|
|
|
//type MessageHandleFunc func ([]byte) error
|
|
//
|
|
//type MessageQueue interface {
|
|
// Chan(channel string, body []byte) error
|
|
// Subscribe(channel string, queue string, handle MessageHandleFunc) error
|
|
//}
|
|
|
|
type Context interface {
|
|
Schema(name ...string) string
|
|
SQL(name ...string) *sql.DB
|
|
DBI(name ...string) database.DBI
|
|
Config() config.Config
|
|
Cache(name ...string) cache.Cache
|
|
KV(name ...string) kv.KV
|
|
Publish(string, ...interface{}) error
|
|
Set(string, interface{}) error
|
|
Get(string) (interface{}, bool)
|
|
Bucket(string) bucket.Bucket
|
|
}
|
|
|
|
type RequestContext interface {
|
|
Context
|
|
Request() *http.Request
|
|
NewProgress(total int, prefixes ...interface{}) (string, string, error) // Return ID and progress URL
|
|
UpdateProgress(id string, finished int)
|
|
}
|
|
|
|
type ContextProvider interface {
|
|
NewContext(*http.Request) RequestContext
|
|
}
|
|
|
|
type RequestPredictor interface {
|
|
Predicate(ctx RequestContext) (string, error)
|
|
Next(handler interface{}) RequestHandler
|
|
}
|
|
|
|
type CacheController struct {
|
|
KeyPrefix string
|
|
CacheMethods []string
|
|
CacheStatus []int
|
|
Expires int64
|
|
}
|
|
|
|
/**
|
|
* HTTP Handling
|
|
* Global Handler: RequestHandler
|
|
* SimpleHandlerFunc: -> RequestHandler
|
|
* RestletFunc: -> RequestHandler
|
|
* RestletFuncEx: -> RequestHandler (with result.DataOnly = true)
|
|
*/
|
|
|
|
type RequestHandler interface {
|
|
Handle(ctx RequestContext, w http.ResponseWriter, r *http.Request) error
|
|
}
|
|
|
|
type RequestHandleFunc func(ctx RequestContext, w http.ResponseWriter, r *http.Request) error
|
|
|
|
func (f RequestHandleFunc) Handle(ctx RequestContext, w http.ResponseWriter, r *http.Request) error {
|
|
return f(ctx, w, r)
|
|
}
|
|
|
|
type SimpleHandleFunc func(w http.ResponseWriter, r *http.Request)
|
|
|
|
func (f SimpleHandleFunc) Handle(ctx RequestContext, w http.ResponseWriter, r *http.Request) error {
|
|
f(w, r)
|
|
return nil
|
|
}
|
|
|
|
type RestletHandler interface {
|
|
Handle(ctx RequestContext, params Parameters, queries Parameters, data []byte) (Result, error)
|
|
}
|
|
|
|
type RestletFunc func(ctx RequestContext, params Parameters, queries Parameters, data []byte) (Result, error)
|
|
|
|
func (f RestletFunc) Handle(ctx RequestContext, w http.ResponseWriter, r *http.Request) error {
|
|
var params = GetUrlParams(r)
|
|
var queries = GetUrlQueries(r)
|
|
var data []byte
|
|
var format string
|
|
if f, b := queries.GetString("__restlet_format", "JSON"); b {
|
|
format = f
|
|
delete(queries, "__restlet_format")
|
|
}
|
|
if r.Body != nil {
|
|
if bs, e := ioutil.ReadAll(r.Body); nil != e {
|
|
return FailureResponse(w, http.StatusBadRequest, e.Error())
|
|
} else {
|
|
data = bs
|
|
_ = r.Body.Close()
|
|
}
|
|
}
|
|
if ret, e := f(ctx, params, queries, data); nil != e {
|
|
if ee, b := e.(Error); b {
|
|
return FailureResponse(w, ee.Code(), ee.Error())
|
|
} else {
|
|
return FailureResponse(w, http.StatusInternalServerError, e.Error())
|
|
}
|
|
} else if 0 != ret.Code {
|
|
var retCode int
|
|
var data interface{}
|
|
if ret.Code >= 100*100 {
|
|
retCode = int(ret.Code / 100)
|
|
} else {
|
|
retCode = int(ret.Code)
|
|
}
|
|
data = ret
|
|
if ret.DataOnly {
|
|
data = ret.Data
|
|
}
|
|
if ret.RawBytes {
|
|
if bs, b := ret.Data.([]byte); b {
|
|
if ret.ContentType != "" {
|
|
return StandardResponse(bs, retCode, ret.ContentType, w, ret.Cookies...)
|
|
}
|
|
return StandardResponse(bs, retCode, "text/plain", w, ret.Cookies...)
|
|
}
|
|
}
|
|
//if len(ret.Cookies) > 0 {
|
|
// for _, c := range ret.Cookies {
|
|
// http.SetCookie(w, c)
|
|
// }
|
|
//}
|
|
switch strings.ToLower(format) {
|
|
case "xml":
|
|
return XmlResponse(data, retCode, w, ret.Cookies...)
|
|
case "yaml":
|
|
return YamlResponse(data, retCode, w, ret.Cookies...)
|
|
case "bson":
|
|
return BsonResponse(data, retCode, w, ret.Cookies...)
|
|
default:
|
|
return JsonResponse(data, retCode, w, ret.Cookies...)
|
|
}
|
|
} else {
|
|
return FailureResponse(w, http.StatusInternalServerError, "nil return")
|
|
}
|
|
}
|
|
|
|
type RestletFuncEx func(ctx RequestContext, params Parameters, queries Parameters, data []byte) (int, interface{}, error)
|
|
|
|
func (f RestletFuncEx) Handle(ctx RequestContext, w http.ResponseWriter, r *http.Request) error {
|
|
return RestletFunc(func(ctx RequestContext, params Parameters, queries Parameters, data []byte) (Result, error) {
|
|
var ret Result
|
|
if c, d, e := f(ctx, params, queries, data); nil != e {
|
|
return ret, e
|
|
} else {
|
|
ret.Code = uint(c)
|
|
ret.Data = d
|
|
ret.DataOnly = true
|
|
return ret, nil
|
|
}
|
|
}).Handle(ctx, w, r)
|
|
}
|
|
|
|
type RawletFunc func(ctx RequestContext, params Parameters, queries Parameters, w http.ResponseWriter, r *http.Request) error
|
|
|
|
func (f RawletFunc) Handle(ctx RequestContext, w http.ResponseWriter, r *http.Request) error {
|
|
var params = GetUrlParams(r)
|
|
var queries = GetUrlQueries(r)
|
|
return f(ctx, params, queries, w, r)
|
|
}
|
|
|
|
type TaskContext interface {
|
|
Context
|
|
}
|
|
|
|
type TaskContextProvider interface {
|
|
NewContext() TaskContext
|
|
}
|
|
|
|
type TaskObject struct {
|
|
Queue string
|
|
Params []interface{}
|
|
}
|
|
|
|
type TaskletHandler interface {
|
|
Handle(TaskContext, ...interface{}) error
|
|
}
|
|
|
|
type TaskletFunc func(TaskContext, ...interface{}) error
|
|
|
|
func (f TaskletFunc) Handle(ctx TaskContext, params ...interface{}) error {
|
|
return f(ctx, params...)
|
|
}
|
|
|
|
type QueryMaker interface {
|
|
Query(k, v string) (xql.QueryFilter, bool)
|
|
}
|