vinegar/servlet/config.go
2023-07-31 17:12:05 -04:00

157 lines
3.9 KiB
Go

package servlet
import (
"encoding/json"
"errors"
"fmt"
"geniuscartel.xyz/vinegar/vinegarUtil"
"io/ioutil"
)
type (
// ConfigType is an enum representing the types of configuration routes.
// There are currently 3 options:
//
// Text - Used for simple text/HTML routes.
// Image - Used for image file routes.
// SingleFile - Used for serving a single file.
//
// These constants define the allowed values for the ConfigType
// field used when loading route configurations from a JSON file.
//
//
// So when loading a JSON config, the "ConfigType" field must be
// set to one of these constant values like "Text" or "Image".
ConfigType string
// ConfigEntry defines a single route configuration entry.
// Used to configure routes from a JSON config file.
ConfigEntry struct {
// ConfigType indicates the type of route - Text, Image etc.
ConfigType ConfigType
// UrlPattern is the URL regex pattern to match for the route.
UrlPattern string
// FileLocation is the file path or directory to serve files from.
FileLocation string
// UseBuiltinCache indicates whether to use the built-in LRU cache.
UseBuiltinCache bool
}
Config struct {
ListeningAddress string
Routes []ConfigEntry
}
)
const (
// defaultTemplateFileName is the default file name for the generated
// blank config template.
defaultTemplateFileName = "servlet.json.example.tmpl"
// defaultListeningPort is the default HTTP listening port.
// Set to ":8080" to listen on port 8080.
defaultListeningPort = ":8080"
// defaultUrlPattern is the default URL pattern route.
// Set to "/*" to match all URLs.
defaultUrlPattern = "/*"
// defaultFileLocation is the default file location to serve static files from.
// Set to "errors/" to serve from a directory called "errors".
defaultFileLocation = "errors/"
)
const (
// Text is a ConfigType constant representing a text/HTML route.
Text ConfigType = "Text"
// Image is a ConfigType constant representing an image file route.
Image = "Image"
// SingleFile is a ConfigType constant representing a route that
// serves a single file.
SingleFile = "SingleFile"
)
func CreateBlankConfig() *Config {
conf := Config{
ListeningAddress: defaultListeningPort,
Routes: make([]ConfigEntry, 0, 10),
}
dummyRoute := ConfigEntry{
ConfigType: Text,
UrlPattern: defaultUrlPattern,
FileLocation: defaultFileLocation,
UseBuiltinCache: false,
}
conf.Routes = append(conf.Routes, dummyRoute)
return &conf
}
func LoadConfig(pathlike string) (*VinegarHttpServlet, error) {
contents, err := vinegarUtil.GetDiskContent(pathlike)
if err != nil {
CreateBlankConfig()
return nil, err
}
conf := Config{}
err = json.Unmarshal(*contents, &conf)
if err != nil {
return nil, err
}
servlet := NewServlet(conf.ListeningAddress)
for _, v := range conf.Routes {
constructor, err := getConstructorFunction(v.ConfigType)
if err != nil {
return nil, err
}
//we don't have to invoke servlet.AddRoute because the static routes already do that for us
constructor(servlet, v.UrlPattern, v.FileLocation, v.UseBuiltinCache)
}
return servlet, nil
}
func (e ConfigEntry) toRoute(serv *VinegarHttpServlet) error {
constructor, err := getConstructorFunction(e.ConfigType)
if err != nil {
return err
}
constructor(serv, e.UrlPattern, e.FileLocation, e.UseBuiltinCache)
return nil
}
func getConstructorFunction(t ConfigType) (RouteConstructor, error) {
switch t {
case Text:
return NewTextRoute, nil
case Image:
return NewImageRoute, nil
case SingleFile:
return NewSingleFileRoute, nil
}
return nil, errors.New(fmt.Sprintf("could not determine constructor for invalid ConfigType: %s", t))
}
func GenerateBlankConfig() error {
conf := CreateBlankConfig()
content, err := json.Marshal(&conf)
if err != nil {
return err
}
fmt.Println("Generating a blank configuration file at ")
ioutil.WriteFile(defaultTemplateFileName, content, 0755)
return nil
}