added readme
This commit is contained in:
parent
5c7143ffd7
commit
0ae5afa452
48
README.md
Normal file
48
README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Vinegar
|
||||
|
||||
### Vinegar is a simple web application framework written in Go.
|
||||
|
||||
## Features
|
||||
Routing with support for static files, templates, APIs
|
||||
Template rendering
|
||||
Caching
|
||||
Gzip compression
|
||||
Custom error pages
|
||||
Getting Started
|
||||
Prerequisites
|
||||
|
||||
Go 1.18+
|
||||
### Installation
|
||||
```go get geniuscartel.xyz/vinegar```
|
||||
|
||||
### Usage
|
||||
|
||||
Create a config.json file to define routes and options
|
||||
|
||||
### Import Vinegar and create a new server instance:
|
||||
```
|
||||
import "geniuscartel.xyz/vinegar"
|
||||
|
||||
func main(){
|
||||
server := vinegar.NewServer(config)
|
||||
Add handlers for API routes:
|
||||
api := server.NewApiRoute("/api")
|
||||
api.Get(handleGet)
|
||||
Start the server:
|
||||
server.Start(":8080")
|
||||
}
|
||||
```
|
||||
|
||||
See the examples folder for more usage examples.
|
||||
|
||||
## Configuration
|
||||
The config.json file defines the routes and options for Vinegar. It supports the following route types:
|
||||
|
||||
* static - Map a URL pattern to a static file or directory
|
||||
* template - Render a Go template on a route
|
||||
* api - Add API routes with custom handlers
|
||||
* See config_example.json for a sample configuration file.
|
||||
|
||||
|
||||
## License
|
||||
Vinegar is closed source. Copyright 2023 David Tookey. All rights reserved
|
||||
@ -1,8 +1,10 @@
|
||||
package servlet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"geniuscartel.xyz/vinegar/vinegarUtil"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
@ -28,12 +30,25 @@ func (r *VinegarWebRouter) RouteRequest(w http.ResponseWriter, req *http.Request
|
||||
path := req.URL.Path
|
||||
for _, route := range r.Routes {
|
||||
if route.Pattern.MatchString(path) {
|
||||
//fmt.Printf("SERVING: [%s]=>{%s}\n", path, route.Pattern.String())
|
||||
log.Printf("SERVING: [%s]=>{%s}\n", path, route.Pattern.String())
|
||||
go route.Handler(w, req)
|
||||
return nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
notFoundHandler(w, req)
|
||||
return errors.New("failed to match route for [" + path + "]")
|
||||
}
|
||||
|
||||
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
|
||||
errorResponse := ErrorResponse{
|
||||
Code: http.StatusNotFound,
|
||||
Message: "The requested resource could not be found.",
|
||||
}
|
||||
|
||||
jsonBytes, _ := json.Marshal(errorResponse)
|
||||
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.Write(jsonBytes)
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"geniuscartel.xyz/vinegar/vinegarUtil"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -150,7 +151,7 @@ func GenerateBlankConfig() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Generating a blank configuration file at ")
|
||||
log.Println("Generating a blank configuration file at ")
|
||||
ioutil.WriteFile(defaultTemplateFileName, content, 0755)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -26,8 +26,32 @@ type ErrorResponse struct {
|
||||
|
||||
type (
|
||||
VinegarWebServlet struct {
|
||||
Port string
|
||||
Router VinegarWebRouter
|
||||
Port string
|
||||
Router VinegarWebRouter
|
||||
|
||||
// ErrorRoutes is a map that stores TemplateRoute pointers
|
||||
// for different HTTP status code error pages.
|
||||
//
|
||||
// It gets populated when custom error routes are defined via AddErrorRoute.
|
||||
// For example:
|
||||
//
|
||||
// err404 := NewTemplateRoute(/*...*/)
|
||||
// srv.AddErrorRoute(404, err404)
|
||||
//
|
||||
// This will add err404 to ErrorRoutes mapped to 404.
|
||||
//
|
||||
// Routes can then be rendered like:
|
||||
//
|
||||
// tmpl, exists := s.ErrorRoutes[404]
|
||||
// if exists {
|
||||
// // render tmpl
|
||||
// }
|
||||
//
|
||||
// So ErrorRoutes provides a lookup from status code
|
||||
// to the associated custom error route.
|
||||
//
|
||||
// It allows easily rendering custom error pages
|
||||
// for different status codes.
|
||||
ErrorRoutes map[int]*TemplateRoute
|
||||
interrupts chan struct{}
|
||||
errors chan error
|
||||
@ -107,9 +131,10 @@ func (r *VinegarWebRoute) Announce() {
|
||||
}
|
||||
|
||||
func (s *VinegarWebServlet) SendError(w http.ResponseWriter, req *http.Request, code int, msg string, aErr error) {
|
||||
fmt.Printf("[%d][%s]. Rendering template for code %d with message: %s\n", code, req.URL.Path, code, msg)
|
||||
log.Printf("[%d][%s]. Rendering template for code %d with message: %s\n", code, req.URL.Path, code, msg)
|
||||
out, _ := json.Marshal(aErr)
|
||||
fmt.Println(string(out))
|
||||
|
||||
log.Println(string(out))
|
||||
tmpl, exists := s.ErrorRoutes[code]
|
||||
if exists {
|
||||
err := tmpl.TemplateManager.AddMixin("code", strconv.Itoa(code))
|
||||
@ -124,6 +149,11 @@ func (s *VinegarWebServlet) SendError(w http.ResponseWriter, req *http.Request,
|
||||
}
|
||||
w.WriteHeader(code)
|
||||
bitties, err := tmpl.TemplateManager.RenderTemplate(fmt.Sprintf("%d.html", code))
|
||||
if err != nil {
|
||||
http.Error(w, msg, code)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(bitties))
|
||||
if err != nil {
|
||||
http.Error(w, msg, code)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package servlet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -38,10 +37,11 @@ func TestServletServeTraffic(t *testing.T) {
|
||||
srv.Router.AddRoute(&VinegarWebRoute{
|
||||
Pattern: regexp.MustCompile("/test"),
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Printf("We got into the handler\n")
|
||||
log.Printf("We got into the handler\n")
|
||||
msg := []byte("hello")
|
||||
l, err := w.Write(msg)
|
||||
fmt.Printf("Wrote %d bytes\n", l)
|
||||
|
||||
log.Printf("Wrote %d bytes\n", l)
|
||||
if err != nil {
|
||||
srv.errors <- err
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package vinegarUtil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
@ -61,7 +60,7 @@ func NewSingleFileCache(pathlike string) (*SingleFileCache, error) {
|
||||
func (l *Lru) Get(key string) (*LruEntry, bool) {
|
||||
entry, exists := (*l.entries)[key]
|
||||
if exists && entry.expires.Before(time.Now()) {
|
||||
fmt.Println("Cache miss due to expired content")
|
||||
log.Println("Cache miss due to expired content")
|
||||
err := entry.Reload()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user