make params an any slice to support automatic int conversion, add readme
This commit is contained in:
parent
8944c20394
commit
e100f2d56b
421
README.md
Normal file
421
README.md
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
# 🍣 Sushi
|
||||||
|
|
||||||
|
A fast, raw, tasty framework for simplifying basic web apps!
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.sharkk.net/Sharkk/Sushi"
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := sushi.New()
|
||||||
|
|
||||||
|
// Initialize sessions
|
||||||
|
session.InitSessions("sessions.json")
|
||||||
|
|
||||||
|
app.Get("/", func(ctx sushi.Ctx, params []any) {
|
||||||
|
sushi.SendHTML(ctx, "<h1>Hello Sushi!</h1>")
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Listen(":8080")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Routing
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Basic routes
|
||||||
|
app.Get("/users/:id", getUserHandler)
|
||||||
|
app.Post("/users", createUserHandler)
|
||||||
|
app.Put("/users/:id", updateUserHandler)
|
||||||
|
app.Delete("/users/:id", deleteUserHandler)
|
||||||
|
|
||||||
|
// Wildcards
|
||||||
|
app.Get("/files/*path", serveFilesHandler)
|
||||||
|
|
||||||
|
// Route groups
|
||||||
|
api := app.Group("/api/v1")
|
||||||
|
api.Get("/users", listUsersHandler)
|
||||||
|
api.Post("/users", createUserHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
URL parameters are automatically converted to the appropriate type:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Numeric parameters become integers
|
||||||
|
app.Get("/users/:id", func(ctx sushi.Ctx, params []any) {
|
||||||
|
userID := params[0].(int) // /users/123 -> 123
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
|
||||||
|
// String parameters stay strings
|
||||||
|
app.Get("/users/:name", func(ctx sushi.Ctx, params []any) {
|
||||||
|
name := params[0].(string) // /users/john -> "john"
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
|
||||||
|
// Mixed types
|
||||||
|
app.Get("/users/:id/posts/:slug", func(ctx sushi.Ctx, params []any) {
|
||||||
|
userID := params[0].(int) // 123
|
||||||
|
slug := params[1].(string) // "my-post"
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Helpers
|
||||||
|
|
||||||
|
```go
|
||||||
|
func myHandler(ctx sushi.Ctx, params []any) {
|
||||||
|
// JSON responses
|
||||||
|
sushi.SendJSON(ctx, map[string]string{"message": "success"})
|
||||||
|
|
||||||
|
// HTML responses
|
||||||
|
sushi.SendHTML(ctx, "<h1>Welcome</h1>")
|
||||||
|
|
||||||
|
// Text responses
|
||||||
|
sushi.SendText(ctx, "Plain text")
|
||||||
|
|
||||||
|
// Error responses
|
||||||
|
sushi.SendError(ctx, 404, "Not Found")
|
||||||
|
|
||||||
|
// Redirects
|
||||||
|
sushi.SendRedirect(ctx, "/login")
|
||||||
|
|
||||||
|
// Status only
|
||||||
|
sushi.SendStatus(ctx, 204)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Middleware
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Custom middleware
|
||||||
|
func loggingMiddleware() sushi.Middleware {
|
||||||
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
|
println("Request:", string(ctx.Method()), string(ctx.Path()))
|
||||||
|
next()
|
||||||
|
println("Status:", ctx.Response.StatusCode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Use(loggingMiddleware())
|
||||||
|
|
||||||
|
// Group middleware
|
||||||
|
admin := app.Group("/admin")
|
||||||
|
admin.Use(auth.RequireAuth("/login"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication Workflow
|
||||||
|
|
||||||
|
### 1. Setup Password Hashing
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "git.sharkk.net/Sharkk/Sushi/password"
|
||||||
|
|
||||||
|
// Hash password for storage
|
||||||
|
hashedPassword := password.HashPassword("userpassword123")
|
||||||
|
|
||||||
|
// Verify password during login
|
||||||
|
isValid, err := password.VerifyPassword("userpassword123", hashedPassword)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. User Structure
|
||||||
|
|
||||||
|
```go
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"` // Store hashed password
|
||||||
|
}
|
||||||
|
|
||||||
|
// User lookup function for auth middleware
|
||||||
|
func getUserByID(userID int) any {
|
||||||
|
// Query your database for user by ID
|
||||||
|
// Return nil if not found
|
||||||
|
return &User{ID: userID, Email: "user@example.com"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Session & Auth Middleware
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/session"
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := sushi.New()
|
||||||
|
|
||||||
|
// Initialize sessions
|
||||||
|
session.InitSessions("sessions.json")
|
||||||
|
|
||||||
|
// Add session middleware
|
||||||
|
app.Use(session.Middleware())
|
||||||
|
|
||||||
|
// Add auth middleware with user lookup
|
||||||
|
app.Use(auth.Middleware(getUserByID))
|
||||||
|
|
||||||
|
// Public routes
|
||||||
|
app.Get("/login", loginPageHandler)
|
||||||
|
app.Post("/login", loginHandler)
|
||||||
|
app.Post("/logout", logoutHandler)
|
||||||
|
|
||||||
|
// Protected routes
|
||||||
|
protected := app.Group("/dashboard")
|
||||||
|
protected.Use(auth.RequireAuth("/login"))
|
||||||
|
protected.Get("/", dashboardHandler)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Login Handler
|
||||||
|
|
||||||
|
```go
|
||||||
|
func loginHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
email := string(ctx.PostArgs().Peek("email"))
|
||||||
|
password := string(ctx.PostArgs().Peek("password"))
|
||||||
|
|
||||||
|
// Find user by email/username
|
||||||
|
user := findUserByEmail(email)
|
||||||
|
if user == nil {
|
||||||
|
sushi.SendError(ctx, 401, "Invalid credentials")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify password
|
||||||
|
isValid, err := password.VerifyPassword(password, user.Password)
|
||||||
|
if err != nil || !isValid {
|
||||||
|
sushi.SendError(ctx, 401, "Invalid credentials")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the user in
|
||||||
|
auth.Login(ctx, user.ID, user)
|
||||||
|
|
||||||
|
sushi.SendRedirect(ctx, "/dashboard")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Logout Handler
|
||||||
|
|
||||||
|
```go
|
||||||
|
func logoutHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
auth.Logout(ctx)
|
||||||
|
sushi.SendRedirect(ctx, "/")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Getting Current User
|
||||||
|
|
||||||
|
```go
|
||||||
|
func dashboardHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
user := auth.GetCurrentUser(ctx).(*User)
|
||||||
|
|
||||||
|
html := fmt.Sprintf("<h1>Welcome, %s!</h1>", user.Username)
|
||||||
|
sushi.SendHTML(ctx, html)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSRF Protection
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "git.sharkk.net/Sharkk/Sushi/csrf"
|
||||||
|
|
||||||
|
// Add CSRF middleware to forms
|
||||||
|
app.Use(csrf.Middleware())
|
||||||
|
|
||||||
|
// In your form template
|
||||||
|
func loginPageHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
csrfField := csrf.CSRFHiddenField(ctx)
|
||||||
|
|
||||||
|
html := fmt.Sprintf(`
|
||||||
|
<form method="POST" action="/login">
|
||||||
|
%s
|
||||||
|
<input type="email" name="email" required>
|
||||||
|
<input type="password" name="password" required>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
`, csrfField)
|
||||||
|
|
||||||
|
sushi.SendHTML(ctx, html)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Static Files
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Serve static files
|
||||||
|
app.Get("/static/*path", sushi.Static("./public"))
|
||||||
|
|
||||||
|
// Serve single file
|
||||||
|
app.Get("/favicon.ico", sushi.StaticFile("./public/favicon.ico"))
|
||||||
|
|
||||||
|
// Embedded files
|
||||||
|
files := map[string][]byte{
|
||||||
|
"/style.css": cssData,
|
||||||
|
"/app.js": jsData,
|
||||||
|
}
|
||||||
|
app.Get("/assets/*path", sushi.StaticEmbed(files))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sessions
|
||||||
|
|
||||||
|
```go
|
||||||
|
func someHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
sess := session.GetCurrentSession(ctx)
|
||||||
|
|
||||||
|
// Set session data
|
||||||
|
sess.Set("user_preference", "dark_mode")
|
||||||
|
|
||||||
|
// Get session data
|
||||||
|
if pref, exists := sess.Get("user_preference"); exists {
|
||||||
|
preference := pref.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flash messages (one-time)
|
||||||
|
sess.SetFlash("success", "Profile updated!")
|
||||||
|
|
||||||
|
// Get flash message
|
||||||
|
message := sess.GetFlashMessage("success")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server Configuration
|
||||||
|
|
||||||
|
```go
|
||||||
|
app := sushi.New(sushi.ServerOptions{
|
||||||
|
ReadTimeout: 30 * time.Second,
|
||||||
|
WriteTimeout: 30 * time.Second,
|
||||||
|
MaxRequestBodySize: 10 * 1024 * 1024, // 10MB
|
||||||
|
})
|
||||||
|
|
||||||
|
// TLS
|
||||||
|
app.ListenTLS(":443", "cert.pem", "key.pem")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Auth Example
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
sushi "git.sharkk.net/Sharkk/Sushi"
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/auth"
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/csrf"
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/password"
|
||||||
|
"git.sharkk.net/Sharkk/Sushi/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int
|
||||||
|
Email string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
var users = map[int]*User{
|
||||||
|
1: {ID: 1, Email: "admin@example.com", Password: password.HashPassword("admin123")},
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserByID(userID int) any {
|
||||||
|
return users[userID]
|
||||||
|
}
|
||||||
|
|
||||||
|
func findUserByEmail(email string) *User {
|
||||||
|
for _, user := range users {
|
||||||
|
if user.Email == email {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := sushi.New()
|
||||||
|
|
||||||
|
session.InitSessions("sessions.json")
|
||||||
|
app.Use(session.Middleware())
|
||||||
|
app.Use(auth.Middleware(getUserByID))
|
||||||
|
|
||||||
|
// Public routes
|
||||||
|
app.Get("/", homeHandler)
|
||||||
|
app.Get("/login", loginPageHandler)
|
||||||
|
app.Post("/login", loginHandler)
|
||||||
|
|
||||||
|
// Protected routes
|
||||||
|
protected := app.Group("/dashboard")
|
||||||
|
protected.Use(auth.RequireAuth("/login"))
|
||||||
|
protected.Use(csrf.Middleware())
|
||||||
|
protected.Get("/", dashboardHandler)
|
||||||
|
protected.Post("/logout", logoutHandler)
|
||||||
|
|
||||||
|
app.Listen(":8080")
|
||||||
|
}
|
||||||
|
|
||||||
|
func homeHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
if auth.IsAuthenticated(ctx) {
|
||||||
|
sushi.SendRedirect(ctx, "/dashboard")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sushi.SendHTML(ctx, `<a href="/login">Login</a>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loginPageHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
html := fmt.Sprintf(`
|
||||||
|
<form method="POST" action="/login">
|
||||||
|
%s
|
||||||
|
<input type="email" name="email" placeholder="Email" required><br>
|
||||||
|
<input type="password" name="password" placeholder="Password" required><br>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
`, csrf.CSRFHiddenField(ctx))
|
||||||
|
|
||||||
|
sushi.SendHTML(ctx, html)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loginHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
email := string(ctx.PostArgs().Peek("email"))
|
||||||
|
pass := string(ctx.PostArgs().Peek("password"))
|
||||||
|
|
||||||
|
user := findUserByEmail(email)
|
||||||
|
if user == nil {
|
||||||
|
sushi.SendError(ctx, 401, "Invalid credentials")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid, _ := password.VerifyPassword(pass, user.Password); !valid {
|
||||||
|
sushi.SendError(ctx, 401, "Invalid credentials")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auth.Login(ctx, user.ID, user)
|
||||||
|
sushi.SendRedirect(ctx, "/dashboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
func dashboardHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
user := auth.GetCurrentUser(ctx).(*User)
|
||||||
|
|
||||||
|
html := fmt.Sprintf(`
|
||||||
|
<h1>Welcome, %s!</h1>
|
||||||
|
<form method="POST" action="/logout">
|
||||||
|
%s
|
||||||
|
<button type="submit">Logout</button>
|
||||||
|
</form>
|
||||||
|
`, user.Email, csrf.CSRFHiddenField(ctx))
|
||||||
|
|
||||||
|
sushi.SendHTML(ctx, html)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logoutHandler(ctx sushi.Ctx, params []string) {
|
||||||
|
auth.Logout(ctx)
|
||||||
|
sushi.SendRedirect(ctx, "/")
|
||||||
|
}
|
||||||
|
```
|
@ -10,7 +10,7 @@ const UserCtxKey = "user"
|
|||||||
|
|
||||||
// Middleware adds authentication handling
|
// Middleware adds authentication handling
|
||||||
func Middleware(userLookup func(int) any) sushi.Middleware {
|
func Middleware(userLookup func(int) any) sushi.Middleware {
|
||||||
return func(ctx sushi.Ctx, params []string, next func()) {
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
sess := session.GetCurrentSession(ctx)
|
sess := session.GetCurrentSession(ctx)
|
||||||
if sess != nil && sess.UserID > 0 && userLookup != nil {
|
if sess != nil && sess.UserID > 0 && userLookup != nil {
|
||||||
user := userLookup(sess.UserID)
|
user := userLookup(sess.UserID)
|
||||||
@ -32,7 +32,7 @@ func RequireAuth(redirectPath ...string) sushi.Middleware {
|
|||||||
redirect = redirectPath[0]
|
redirect = redirectPath[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ctx sushi.Ctx, params []string, next func()) {
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
if !IsAuthenticated(ctx) {
|
if !IsAuthenticated(ctx) {
|
||||||
ctx.Redirect(redirect, fasthttp.StatusFound)
|
ctx.Redirect(redirect, fasthttp.StatusFound)
|
||||||
return
|
return
|
||||||
@ -48,7 +48,7 @@ func RequireGuest(redirectPath ...string) sushi.Middleware {
|
|||||||
redirect = redirectPath[0]
|
redirect = redirectPath[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ctx sushi.Ctx, params []string, next func()) {
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
if IsAuthenticated(ctx) {
|
if IsAuthenticated(ctx) {
|
||||||
ctx.Redirect(redirect, fasthttp.StatusFound)
|
ctx.Redirect(redirect, fasthttp.StatusFound)
|
||||||
return
|
return
|
||||||
|
@ -119,7 +119,7 @@ func ValidateFormCSRFToken(ctx sushi.Ctx) bool {
|
|||||||
|
|
||||||
// Middleware returns middleware that automatically validates CSRF tokens
|
// Middleware returns middleware that automatically validates CSRF tokens
|
||||||
func Middleware() sushi.Middleware {
|
func Middleware() sushi.Middleware {
|
||||||
return func(ctx sushi.Ctx, params []string, next func()) {
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
method := string(ctx.Method())
|
method := string(ctx.Method())
|
||||||
|
|
||||||
if method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE" {
|
if method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE" {
|
||||||
|
6
fs.go
6
fs.go
@ -50,7 +50,7 @@ func StaticFS(fsOptions StaticOptions) Handler {
|
|||||||
|
|
||||||
fsHandler := fs.NewRequestHandler()
|
fsHandler := fs.NewRequestHandler()
|
||||||
|
|
||||||
return func(ctx Ctx, params []string) {
|
return func(ctx Ctx, params []any) {
|
||||||
fsHandler(ctx)
|
fsHandler(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,14 +62,14 @@ func Static(root string) Handler {
|
|||||||
|
|
||||||
// StaticFile serves a single file
|
// StaticFile serves a single file
|
||||||
func StaticFile(filePath string) Handler {
|
func StaticFile(filePath string) Handler {
|
||||||
return func(ctx Ctx, params []string) {
|
return func(ctx Ctx, params []any) {
|
||||||
fasthttp.ServeFile(ctx, filePath)
|
fasthttp.ServeFile(ctx, filePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticEmbed creates a handler for embedded files
|
// StaticEmbed creates a handler for embedded files
|
||||||
func StaticEmbed(files map[string][]byte) Handler {
|
func StaticEmbed(files map[string][]byte) Handler {
|
||||||
return func(ctx Ctx, params []string) {
|
return func(ctx Ctx, params []any) {
|
||||||
requestPath := string(ctx.Path())
|
requestPath := string(ctx.Path())
|
||||||
|
|
||||||
// Try to find the file
|
// Try to find the file
|
||||||
|
12
router.go
12
router.go
@ -22,7 +22,7 @@ type Router struct {
|
|||||||
patch *node
|
patch *node
|
||||||
delete *node
|
delete *node
|
||||||
middleware []Middleware
|
middleware []Middleware
|
||||||
paramsBuffer []string
|
paramsBuffer []any
|
||||||
}
|
}
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
@ -40,7 +40,7 @@ func NewRouter() *Router {
|
|||||||
patch: &node{},
|
patch: &node{},
|
||||||
delete: &node{},
|
delete: &node{},
|
||||||
middleware: []Middleware{},
|
middleware: []Middleware{},
|
||||||
paramsBuffer: make([]string, 64),
|
paramsBuffer: make([]any, 64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ func applyMiddleware(h Handler, mw []Middleware) Handler {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ctx Ctx, params []string) {
|
return func(ctx Ctx, params []any) {
|
||||||
var index int
|
var index int
|
||||||
var next func()
|
var next func()
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ func (r *Router) addRoute(root *node, path string, h Handler, mw []Middleware) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lookup finds a handler matching method and path
|
// Lookup finds a handler matching method and path
|
||||||
func (r *Router) Lookup(method, path string) (Handler, []string, bool) {
|
func (r *Router) Lookup(method, path string) (Handler, []any, bool) {
|
||||||
root := r.methodNode(method)
|
root := r.methodNode(method)
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
@ -240,7 +240,7 @@ func (r *Router) Lookup(method, path string) (Handler, []string, bool) {
|
|||||||
|
|
||||||
buffer := r.paramsBuffer
|
buffer := r.paramsBuffer
|
||||||
if cap(buffer) < int(root.maxParams) {
|
if cap(buffer) < int(root.maxParams) {
|
||||||
buffer = make([]string, root.maxParams)
|
buffer = make([]any, root.maxParams)
|
||||||
r.paramsBuffer = buffer
|
r.paramsBuffer = buffer
|
||||||
}
|
}
|
||||||
buffer = buffer[:0]
|
buffer = buffer[:0]
|
||||||
@ -253,7 +253,7 @@ func (r *Router) Lookup(method, path string) (Handler, []string, bool) {
|
|||||||
return h, buffer[:paramCount], true
|
return h, buffer[:paramCount], true
|
||||||
}
|
}
|
||||||
|
|
||||||
func match(current *node, path string, start int, params *[]string) (Handler, int, bool) {
|
func match(current *node, path string, start int, params *[]any) (Handler, int, bool) {
|
||||||
paramCount := 0
|
paramCount := 0
|
||||||
|
|
||||||
for _, c := range current.children {
|
for _, c := range current.children {
|
||||||
|
@ -4,7 +4,7 @@ import sushi "git.sharkk.net/Sharkk/Sushi"
|
|||||||
|
|
||||||
// Middleware provides session handling
|
// Middleware provides session handling
|
||||||
func Middleware() sushi.Middleware {
|
func Middleware() sushi.Middleware {
|
||||||
return func(ctx sushi.Ctx, params []string, next func()) {
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
sessionID := sushi.GetCookie(ctx, SessionCookieName)
|
sessionID := sushi.GetCookie(ctx, SessionCookieName)
|
||||||
var sess *Session
|
var sess *Session
|
||||||
|
|
||||||
|
4
sushi.go
4
sushi.go
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h Handler) Serve(ctx Ctx, params []string) {
|
func (h Handler) Serve(ctx Ctx, params []any) {
|
||||||
h(ctx, params)
|
h(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ func IsHTTPS(ctx Ctx) bool {
|
|||||||
|
|
||||||
// StandardHandler adapts a standard fasthttp.RequestHandler to the router's Handler
|
// StandardHandler adapts a standard fasthttp.RequestHandler to the router's Handler
|
||||||
func StandardHandler(handler fasthttp.RequestHandler) Handler {
|
func StandardHandler(handler fasthttp.RequestHandler) Handler {
|
||||||
return func(ctx Ctx, _ []string) {
|
return func(ctx Ctx, _ []any) {
|
||||||
handler(ctx)
|
handler(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ const RequestTimerKey = "request_start_time"
|
|||||||
|
|
||||||
// Middleware adds request timing functionality
|
// Middleware adds request timing functionality
|
||||||
func Middleware() sushi.Middleware {
|
func Middleware() sushi.Middleware {
|
||||||
return func(ctx sushi.Ctx, params []string, next func()) {
|
return func(ctx sushi.Ctx, params []any, next func()) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
ctx.SetUserValue(RequestTimerKey, startTime)
|
ctx.SetUserValue(RequestTimerKey, startTime)
|
||||||
next()
|
next()
|
||||||
|
4
types.go
4
types.go
@ -3,5 +3,5 @@ package sushi
|
|||||||
import "github.com/valyala/fasthttp"
|
import "github.com/valyala/fasthttp"
|
||||||
|
|
||||||
type Ctx = *fasthttp.RequestCtx
|
type Ctx = *fasthttp.RequestCtx
|
||||||
type Handler func(ctx Ctx, params []string)
|
type Handler func(ctx Ctx, params []any)
|
||||||
type Middleware func(ctx Ctx, params []string, next func())
|
type Middleware func(ctx Ctx, params []any, next func())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user