feat: the new architucture basing on the context.
This commit is contained in:
parent
9209039b32
commit
893a53c482
16 changed files with 291 additions and 211 deletions
107
api.go
107
api.go
|
@ -1,107 +1,24 @@
|
||||||
package bond
|
package bond
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"fmt"
|
|
||||||
"vultras.su/core/bond/contents"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Decoder interface {
|
type Handler interface {
|
||||||
Decode(any) error
|
Handle(c *Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The type is used for custom-one-place implementation
|
||||||
|
// of handling.
|
||||||
type Func func(*Context)
|
type Func func(*Context)
|
||||||
|
func (fn Func) Handle(c *Context) {
|
||||||
func (fn Func) ServeHTTP(w ResponseWriter, r *Request) {
|
fn(c)
|
||||||
fn(&Context{
|
|
||||||
R: r,
|
|
||||||
W: w,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context struct {
|
// The wrapper for the standard http.Handler(s).
|
||||||
R *Request
|
type Wrap struct {
|
||||||
W ResponseWriter
|
HttpHandler
|
||||||
// Custom data to store stuff.
|
}
|
||||||
Data any
|
func (w Wrap) Handle(c *Context) {
|
||||||
|
w.ServeHTTP(c.W, c.R)
|
||||||
scanErr error
|
|
||||||
dec Decoder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) SetContentType(typ contents.Type) {
|
|
||||||
c.SetHeader("Content-Type", string(typ))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) ContentType() contents.Type {
|
|
||||||
ret, ok := c.Header("Content-Type")
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if len(ret) < 1 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return contents.Type(ret[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) SetHeader(k, v string) {
|
|
||||||
c.W.Header().Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) Header(name string) ([]string, bool) {
|
|
||||||
ret, ok := c.R.Header[name]
|
|
||||||
return ret, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Closes the requests body after finishes scaning.
|
|
||||||
func (c *Context) Close() {
|
|
||||||
c.R.Body.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan the incoming value from body depending
|
|
||||||
// on the content type of the request.
|
|
||||||
func (c *Context) Scan(v any) bool {
|
|
||||||
if c.dec == nil {
|
|
||||||
typ := c.ContentType()
|
|
||||||
switch typ {
|
|
||||||
case contents.Json:
|
|
||||||
c.dec = json.NewDecoder(c.R.Body)
|
|
||||||
//case contents.UrlEncoded:
|
|
||||||
// return false
|
|
||||||
default:
|
|
||||||
c.scanErr = UnknownContentTypeErr
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := c.dec.Decode(v)
|
|
||||||
if err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
c.scanErr = err
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) ScanErr() error {
|
|
||||||
return c.scanErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) Path() string {
|
|
||||||
return c.R.URL.Path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) NotFound() {
|
|
||||||
http.NotFound(c.W, c.R)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) Printf(format string, v ...any) (int, error) {
|
|
||||||
return fmt.Fprintf(c.W, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) Query() url.Values {
|
|
||||||
return c.R.URL.Query()
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,17 +14,15 @@ type GetNotesOptions struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var root = bond.Mux().
|
var root = bond.Root(bond.Path().
|
||||||
Def(
|
Def(
|
||||||
"",
|
"", bond.Func(func(c *bond.Context) {
|
||||||
bond.Func(func(c *bond.Context) {
|
|
||||||
c.W.Write([]byte("This is the index page"))
|
c.W.Write([]byte("This is the index page"))
|
||||||
}),
|
}),
|
||||||
).Def(
|
).Def(
|
||||||
"hello",
|
"hello",
|
||||||
bond.Mux().Def(
|
bond.Path().Def(
|
||||||
"en",
|
"en", bond.Func(func(c *bond.Context) {
|
||||||
bond.Func(func(c *bond.Context) {
|
|
||||||
c.Printf("Hello, World!")
|
c.Printf("Hello, World!")
|
||||||
}),
|
}),
|
||||||
).Def(
|
).Def(
|
||||||
|
@ -34,11 +32,9 @@ var root = bond.Mux().
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
).Def(
|
).Def(
|
||||||
"web",
|
"web", bond.Static("./static"),
|
||||||
bond.Static("./static"),
|
|
||||||
).Def(
|
).Def(
|
||||||
"test",
|
"test", bond.Func(func(c *bond.Context) {
|
||||||
bond.Func(func(c *bond.Context) {
|
|
||||||
c.SetContentType(contents.Plain)
|
c.SetContentType(contents.Plain)
|
||||||
c.Printf(
|
c.Printf(
|
||||||
"Path: %q\n"+
|
"Path: %q\n"+
|
||||||
|
@ -82,7 +78,7 @@ var root = bond.Mux().
|
||||||
fmt.Printf("values: %q", values)
|
fmt.Printf("values: %q", values)
|
||||||
}),
|
}),
|
||||||
//),
|
//),
|
||||||
)
|
))
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
srv := bond.Server{
|
srv := bond.Server{
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"vultras.su/core/bond"
|
"vultras.su/core/bond"
|
||||||
"vultras.su/core/bond/methods"
|
"vultras.su/core/bond/methods"
|
||||||
"vultras.su/core/bond/contents"
|
"vultras.su/core/bond/contents"
|
||||||
|
"vultras.su/core/bond/statuses"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetNotesOptions struct {
|
type GetNotesOptions struct {
|
||||||
|
@ -11,31 +12,30 @@ type GetNotesOptions struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var root = bond.Mux().
|
var root = bond.Root(bond.Path().
|
||||||
Def(
|
Def(
|
||||||
"",
|
"",
|
||||||
bond.Func(func(c *bond.Context) {
|
bond.Func(func(c *bond.Context) {
|
||||||
c.W.Write([]byte("This is the index page"))
|
c.W.Write([]byte("This is the index page"))
|
||||||
}),
|
}),
|
||||||
).Def(
|
).Def(
|
||||||
"hello",
|
"hello",
|
||||||
bond.Mux().Def(
|
bond.Path().Def(
|
||||||
"en",
|
// Using the relative redirect to force us to the en.
|
||||||
bond.Func(func(c *bond.Context) {
|
"", bond.Redirect("/hello/en", statuses.SeeOther),
|
||||||
|
).Def(
|
||||||
|
"en", bond.Func(func(c *bond.Context) {
|
||||||
c.Printf("Hello, World!")
|
c.Printf("Hello, World!")
|
||||||
}),
|
}),
|
||||||
).Def(
|
).Def(
|
||||||
"ru",
|
"ru", bond.Func(func(c *bond.Context) {
|
||||||
bond.Func(func(c *bond.Context) {
|
|
||||||
c.Printf("Привет, Мир!")
|
c.Printf("Привет, Мир!")
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
).Def(
|
).Def(
|
||||||
"web",
|
"web", bond.Static("./static"),
|
||||||
bond.Static("./static"),
|
|
||||||
).Def(
|
).Def(
|
||||||
"test",
|
"test", bond.Func(func(c *bond.Context) {
|
||||||
bond.Func(func(c *bond.Context) {
|
|
||||||
c.SetContentType(contents.Plain)
|
c.SetContentType(contents.Plain)
|
||||||
c.Printf(
|
c.Printf(
|
||||||
"Path: %q\n"+
|
"Path: %q\n"+
|
||||||
|
@ -60,7 +60,7 @@ var root = bond.Mux().
|
||||||
c.Printf("%v", opts)
|
c.Printf("%v", opts)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
))
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
srv := bond.Server{
|
srv := bond.Server{
|
||||||
|
|
|
@ -13,7 +13,7 @@ const (
|
||||||
// Using the UTF-8 by default.
|
// Using the UTF-8 by default.
|
||||||
Unknown Type = "application/octet-stream"
|
Unknown Type = "application/octet-stream"
|
||||||
Binary
|
Binary
|
||||||
Plain Type = "text/plain; charset=utf-8"
|
Plain Type = "text/plain"
|
||||||
Css Type = "text/css"
|
Css Type = "text/css"
|
||||||
Html Type = "text/html"
|
Html Type = "text/html"
|
||||||
Json Type = "application/json"
|
Json Type = "application/json"
|
||||||
|
|
108
context.go
Normal file
108
context.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package bond
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"fmt"
|
||||||
|
"vultras.su/core/bond/contents"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
R *Request
|
||||||
|
W ResponseWriter
|
||||||
|
// Custom data to store stuff.
|
||||||
|
Data any
|
||||||
|
|
||||||
|
scanErr error
|
||||||
|
dec Decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Method() ReqMethod {
|
||||||
|
return ReqMethod(c.R.Method)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the reply status code.
|
||||||
|
func (c *Context) SetStatus(status Status) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the reply content type.
|
||||||
|
func (c *Context) SetContentType(typ contents.Type) {
|
||||||
|
c.SetHeader("Content-Type", string(typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the request content type.
|
||||||
|
func (c *Context) ContentType() ContentType {
|
||||||
|
ret, ok := c.Header("Content-Type")
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(ret) < 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return contents.Type(ret[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) SetHeader(k, v string) {
|
||||||
|
c.W.Header().Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Header(name string) ([]string, bool) {
|
||||||
|
ret, ok := c.R.Header[name]
|
||||||
|
return ret, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closes the requests body after finishes scaning.
|
||||||
|
func (c *Context) Close() {
|
||||||
|
c.R.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan the incoming value from body depending
|
||||||
|
// on the content type of the request.
|
||||||
|
func (c *Context) Scan(v any) bool {
|
||||||
|
if c.dec == nil {
|
||||||
|
typ := c.ContentType()
|
||||||
|
switch typ {
|
||||||
|
case contents.Json:
|
||||||
|
c.dec = json.NewDecoder(c.R.Body)
|
||||||
|
//case contents.UrlEncoded:
|
||||||
|
// return false
|
||||||
|
default:
|
||||||
|
c.scanErr = UnknownContentTypeErr
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := c.dec.Decode(v)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
c.scanErr = err
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) ScanErr() error {
|
||||||
|
return c.scanErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Path() string {
|
||||||
|
return c.R.URL.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) NotFound() {
|
||||||
|
http.NotFound(c.W, c.R)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Printf(format string, v ...any) (int, error) {
|
||||||
|
return fmt.Fprintf(c.W, format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Query() url.Values {
|
||||||
|
return c.R.URL.Query()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Redirect(u string, status Status) {
|
||||||
|
http.Redirect(c.W, c.R, u, int(status))
|
||||||
|
}
|
5
decoder.go
Normal file
5
decoder.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package bond
|
||||||
|
|
||||||
|
type Decoder interface {
|
||||||
|
Decode(any) error
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -1,3 +1,4 @@
|
||||||
module vultras.su/core/bond
|
module vultras.su/core/bond
|
||||||
|
|
||||||
go 1.21.3
|
go 1.21.3
|
||||||
|
|
||||||
|
|
15
handler.go
15
handler.go
|
@ -1,15 +0,0 @@
|
||||||
package bond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Request = http.Request
|
|
||||||
type ResponseWriter = http.ResponseWriter
|
|
||||||
type HandlerFunc = http.HandlerFunc
|
|
||||||
type Handler = http.Handler
|
|
||||||
type Server = http.Server
|
|
||||||
|
|
||||||
func Static(pth string) Handler {
|
|
||||||
return http.FileServer(http.Dir(pth))
|
|
||||||
}
|
|
17
http.go
Normal file
17
http.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package bond
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"vultras.su/core/bond/contents"
|
||||||
|
"vultras.su/core/bond/statuses"
|
||||||
|
"vultras.su/core/bond/methods"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Request = http.Request
|
||||||
|
type ResponseWriter = http.ResponseWriter
|
||||||
|
type HttpHandlerFunc = http.HandlerFunc
|
||||||
|
type HttpHandler = http.Handler
|
||||||
|
type Server = http.Server
|
||||||
|
|
||||||
|
type ContentType = contents.Type
|
||||||
|
type Status = statuses.Code
|
||||||
|
type ReqMethod = methods.Method
|
25
method.go
25
method.go
|
@ -1,24 +1,20 @@
|
||||||
package bond
|
package bond
|
||||||
|
|
||||||
import (
|
// The type implements method routing.
|
||||||
"net/http"
|
|
||||||
"vultras.su/core/bond/methods"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The type implements functionality for multiplexing
|
|
||||||
// the methods.
|
|
||||||
type MethodRouter struct {
|
type MethodRouter struct {
|
||||||
methodMap map[methods.Method]Handler
|
methodMap map[ReqMethod]Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns new empty MethodRouter.
|
||||||
func Method() *MethodRouter {
|
func Method() *MethodRouter {
|
||||||
ret := &MethodRouter{}
|
ret := &MethodRouter{}
|
||||||
ret.methodMap = make(map[methods.Method]Handler)
|
ret.methodMap = make(map[ReqMethod]Handler)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define new handler for the specified method.
|
||||||
func (mr *MethodRouter) Def(
|
func (mr *MethodRouter) Def(
|
||||||
method methods.Method,
|
method ReqMethod,
|
||||||
handler Handler,
|
handler Handler,
|
||||||
) *MethodRouter {
|
) *MethodRouter {
|
||||||
_, dup := mr.methodMap[method]
|
_, dup := mr.methodMap[method]
|
||||||
|
@ -30,11 +26,12 @@ func (mr *MethodRouter) Def(
|
||||||
return mr
|
return mr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mr *MethodRouter) ServeHTTP(w ResponseWriter, r *Request) {
|
// Implementing the Handler.
|
||||||
handler, ok := mr.methodMap[methods.Method(r.Method)]
|
func (mr *MethodRouter) Handle(c *Context) {
|
||||||
|
handler, ok := mr.methodMap[c.Method()]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(w, r)
|
c.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
handler.ServeHTTP(w, r)
|
handler.Handle(c)
|
||||||
}
|
}
|
||||||
|
|
65
path.go
Normal file
65
path.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package bond
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
//"fmt"
|
||||||
|
//"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The type implements path routing for requests.
|
||||||
|
type PathRouter struct {
|
||||||
|
pathMap map[string] Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns new empty PathRouter.
|
||||||
|
func Path() *PathRouter {
|
||||||
|
ret := &PathRouter{}
|
||||||
|
ret.pathMap = map[string] Handler{}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define new handler for the specified path.
|
||||||
|
// The defined path must not contain slashes and will panic otherwise.
|
||||||
|
func (router *PathRouter) Def(pth string, handler Handler) *PathRouter {
|
||||||
|
_, dup := router.pathMap[pth]
|
||||||
|
if dup {
|
||||||
|
panic(DupDefErr)
|
||||||
|
}
|
||||||
|
router.pathMap[pth] = handler
|
||||||
|
return router
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementing the Handler.
|
||||||
|
func (router *PathRouter) Handle(c *Context) {
|
||||||
|
pth := c.Path()
|
||||||
|
var splits []string
|
||||||
|
var name, rest string
|
||||||
|
|
||||||
|
if len(pth)>0 && pth[0] == '/' { // Handling the root path.
|
||||||
|
splits = strings.SplitN(pth, "/", 3)
|
||||||
|
if len(splits) > 1 {
|
||||||
|
name = splits[1]
|
||||||
|
}
|
||||||
|
if len(splits) > 2 {
|
||||||
|
rest = splits[2]
|
||||||
|
}
|
||||||
|
} else { // Handling the relative path. (second or n-th call)
|
||||||
|
splits = strings.SplitN(pth, "/", 2)
|
||||||
|
if len(splits) > 0 {
|
||||||
|
name = splits[0]
|
||||||
|
}
|
||||||
|
if len(splits) > 1 {
|
||||||
|
rest = splits[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler, ok := router.pathMap[name]
|
||||||
|
if !ok {
|
||||||
|
c.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.R.URL.Path = rest
|
||||||
|
handler.Handle(c)
|
||||||
|
}
|
||||||
|
|
27
root.go
Normal file
27
root.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package bond
|
||||||
|
|
||||||
|
// The type implements the entry point
|
||||||
|
// for all the request for the server.
|
||||||
|
type RootRouter struct {
|
||||||
|
handler Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the new RootRouter with the specified
|
||||||
|
// handler.
|
||||||
|
func Root(handler Handler) *RootRouter {
|
||||||
|
if handler == nil {
|
||||||
|
panic("the root handler is nil")
|
||||||
|
}
|
||||||
|
ret := &RootRouter{}
|
||||||
|
ret.handler = handler
|
||||||
|
return ret
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementing the http.Handler .
|
||||||
|
func (router *RootRouter) ServeHTTP(w ResponseWriter, r *Request) {
|
||||||
|
ctx := Context{}
|
||||||
|
ctx.W = w
|
||||||
|
ctx.R = r
|
||||||
|
router.handler.Handle(&ctx)
|
||||||
|
}
|
56
router.go
56
router.go
|
@ -1,56 +0,0 @@
|
||||||
package bond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
//"fmt"
|
|
||||||
"path"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Router struct {
|
|
||||||
pathMap map[string] Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func Mux() *Router {
|
|
||||||
ret := &Router{}
|
|
||||||
ret.pathMap = map[string] Handler{}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router *Router) Def(pth string, handler Handler) *Router {
|
|
||||||
_, dup := router.pathMap[pth]
|
|
||||||
if dup {
|
|
||||||
panic(DupDefErr)
|
|
||||||
}
|
|
||||||
router.pathMap[pth] = handler
|
|
||||||
return router
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router *Router) ServeHTTP(w ResponseWriter, r *Request) {
|
|
||||||
pth := r.URL.Path
|
|
||||||
pth = path.Clean(pth)
|
|
||||||
pths := strings.SplitN(pth, "/", 3)
|
|
||||||
|
|
||||||
var name string
|
|
||||||
if len(pths) > 1 {
|
|
||||||
name = pths[1]
|
|
||||||
}
|
|
||||||
name, _ = strings.CutSuffix(name, "/")
|
|
||||||
|
|
||||||
prefix := "/"
|
|
||||||
if pth != "/" {
|
|
||||||
prefix = path.Clean("/" + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("Path: %q\n", r.URL.Path)
|
|
||||||
//fmt.Printf("%q %q %q %q\n", pth, prefix, pths, name)
|
|
||||||
handler, ok := router.pathMap[name]
|
|
||||||
if !ok {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
r.URL.Path = pth
|
|
||||||
http.StripPrefix(prefix, handler).ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
8
short.go
Normal file
8
short.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package bond
|
||||||
|
|
||||||
|
type RedirectRouter string
|
||||||
|
func Redirect(u string, status Status) Handler {
|
||||||
|
return Func(func(c *Context){
|
||||||
|
c.Redirect(u, status)
|
||||||
|
})
|
||||||
|
}
|
10
static.go
Normal file
10
static.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package bond
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Static(pth string) Handler {
|
||||||
|
return Wrap{http.FileServer(http.Dir(pth))}
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status int
|
type Code int
|
||||||
const (
|
const (
|
||||||
Continue Status = http.StatusContinue
|
Continue Code = http.StatusContinue
|
||||||
SwitchingProtocols = http.StatusSwitchingProtocols // RFC 9110, 15.2.2
|
SwitchingProtocols = http.StatusSwitchingProtocols // RFC 9110, 15.2.2
|
||||||
Processing = http.StatusProcessing // RFC 2518, 10.1
|
Processing = http.StatusProcessing // RFC 2518, 10.1
|
||||||
EarlyHints = http.StatusEarlyHints // RFC 8297
|
EarlyHints = http.StatusEarlyHints // RFC 8297
|
||||||
|
|
Loading…
Reference in a new issue