Kepler core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

254 lines
6.6 KiB

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)
}