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) (*VinegarWebServlet, 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 *VinegarWebServlet) 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 }